Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
547a4168
Commit
547a4168
authored
Dec 12, 2013
by
Ian Lance Taylor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiler, reflect, runtime: Implement method values in reflect.
From-SVN: r205913
parent
24fd676a
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
155 additions
and
64 deletions
+155
-64
gcc/go/gofrontend/types.cc
+29
-20
gcc/go/gofrontend/types.h
+6
-0
libgo/go/reflect/all_test.go
+12
-8
libgo/go/reflect/makefunc.go
+87
-3
libgo/go/reflect/makefuncgo_386.go
+1
-1
libgo/go/reflect/makefuncgo_amd64.go
+1
-1
libgo/go/reflect/type.go
+1
-1
libgo/go/reflect/value.go
+13
-30
libgo/runtime/go-recover.c
+5
-0
No files found.
gcc/go/gofrontend/types.cc
View file @
547a4168
...
...
@@ -2261,26 +2261,9 @@ Type::method_constructor(Gogo*, Type* method_type,
++
p
;
go_assert
(
p
->
is_field_name
(
"typ"
));
if
(
!
only_value_methods
&&
m
->
is_value_method
())
{
// This is a value method on a pointer type. Change the type of
// the method to use a pointer receiver. The implementation
// always uses a pointer receiver anyhow.
Type
*
rtype
=
mtype
->
receiver
()
->
type
();
Type
*
prtype
=
Type
::
make_pointer_type
(
rtype
);
Typed_identifier
*
receiver
=
new
Typed_identifier
(
mtype
->
receiver
()
->
name
(),
prtype
,
mtype
->
receiver
()
->
location
());
mtype
=
Type
::
make_function_type
(
receiver
,
(
mtype
->
parameters
()
==
NULL
?
NULL
:
mtype
->
parameters
()
->
copy
()),
(
mtype
->
results
()
==
NULL
?
NULL
:
mtype
->
results
()
->
copy
()),
mtype
->
location
());
}
vals
->
push_back
(
Expression
::
make_type_descriptor
(
mtype
,
bloc
));
bool
want_pointer_receiver
=
!
only_value_methods
&&
m
->
is_value_method
();
nonmethod_type
=
mtype
->
copy_with_receiver_as_param
(
want_pointer_receiver
);
vals
->
push_back
(
Expression
::
make_type_descriptor
(
nonmethod_type
,
bloc
));
++
p
;
go_assert
(
p
->
is_field_name
(
"tfn"
));
...
...
@@ -4008,6 +3991,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const
return
ret
;
}
// Make a copy of a function type with the receiver as the first
// parameter.
Function_type
*
Function_type
::
copy_with_receiver_as_param
(
bool
want_pointer_receiver
)
const
{
go_assert
(
this
->
is_method
());
Typed_identifier_list
*
new_params
=
new
Typed_identifier_list
();
Type
*
rtype
=
this
->
receiver_
->
type
();
if
(
want_pointer_receiver
)
rtype
=
Type
::
make_pointer_type
(
rtype
);
Typed_identifier
receiver
(
this
->
receiver_
->
name
(),
rtype
,
this
->
receiver_
->
location
());
new_params
->
push_back
(
receiver
);
const
Typed_identifier_list
*
orig_params
=
this
->
parameters_
;
if
(
orig_params
!=
NULL
&&
!
orig_params
->
empty
())
{
for
(
Typed_identifier_list
::
const_iterator
p
=
orig_params
->
begin
();
p
!=
orig_params
->
end
();
++
p
)
new_params
->
push_back
(
*
p
);
}
return
Type
::
make_function_type
(
NULL
,
new_params
,
this
->
results_
,
this
->
location_
);
}
// Make a copy of a function type ignoring any receiver and adding a
// closure parameter.
...
...
gcc/go/gofrontend/types.h
View file @
547a4168
...
...
@@ -1797,6 +1797,12 @@ class Function_type : public Type
Function_type
*
copy_with_receiver
(
Type
*
)
const
;
// Return a copy of this type with the receiver treated as the first
// parameter. If WANT_POINTER_RECEIVER is true, the receiver is
// forced to be a pointer.
Function_type
*
copy_with_receiver_as_param
(
bool
want_pointer_receiver
)
const
;
// Return a copy of this type ignoring any receiver and using dummy
// names for all parameters. This is used for thunks for method
// values.
...
...
libgo/go/reflect/all_test.go
View file @
547a4168
...
...
@@ -1631,9 +1631,13 @@ func TestMethod(t *testing.T) {
}
}
/* Not yet implemented for gccgo
func
TestMethodValue
(
t
*
testing
.
T
)
{
switch
runtime
.
GOARCH
{
case
"amd64"
,
"386"
:
default
:
t
.
Skip
(
"reflect method values not implemented for "
+
runtime
.
GOARCH
)
}
p
:=
Point
{
3
,
4
}
var
i
int64
...
...
@@ -1721,8 +1725,6 @@ func TestMethodValue(t *testing.T) {
}
}
*/
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
...
...
@@ -1807,14 +1809,18 @@ type Tm4 struct {
func
(
t4
Tm4
)
M
(
x
int
,
b
byte
)
(
byte
,
int
)
{
return
b
,
x
+
40
}
func
TestMethod5
(
t
*
testing
.
T
)
{
/* Not yet used for gccgo
switch
runtime
.
GOARCH
{
case
"amd64"
,
"386"
:
default
:
t
.
Skip
(
"reflect method values not implemented for "
+
runtime
.
GOARCH
)
}
CheckF
:=
func
(
name
string
,
f
func
(
int
,
byte
)
(
byte
,
int
),
inc
int
)
{
b
,
x
:=
f
(
1000
,
99
)
if
b
!=
99
||
x
!=
1000
+
inc
{
t
.
Errorf
(
"%s(1000, 99) = %v, %v, want 99, %v"
,
name
,
b
,
x
,
1000
+
inc
)
}
}
*/
CheckV
:=
func
(
name
string
,
i
Value
,
inc
int
)
{
bx
:=
i
.
Method
(
0
)
.
Call
([]
Value
{
ValueOf
(
1000
),
ValueOf
(
byte
(
99
))})
...
...
@@ -1824,9 +1830,7 @@ func TestMethod5(t *testing.T) {
t
.
Errorf
(
"direct %s.M(1000, 99) = %v, %v, want 99, %v"
,
name
,
b
,
x
,
1000
+
inc
)
}
/* Not yet implemented for gccgo
CheckF
(
name
+
".M"
,
i
.
Method
(
0
)
.
Interface
()
.
(
func
(
int
,
byte
)
(
byte
,
int
)),
inc
)
*/
}
var
TinterType
=
TypeOf
(
new
(
Tinter
))
.
Elem
()
...
...
libgo/go/reflect/makefunc.go
View file @
547a4168
...
...
@@ -17,6 +17,11 @@ type makeFuncImpl struct {
code
uintptr
typ
*
funcType
fn
func
([]
Value
)
[]
Value
// For gccgo we use the same entry point for functions and for
// method values.
method
int
rcvr
Value
}
// MakeFunc returns a new function of the given Type
...
...
@@ -61,7 +66,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
dummy
:=
makeFuncStub
code
:=
**
(
**
uintptr
)(
unsafe
.
Pointer
(
&
dummy
))
impl
:=
&
makeFuncImpl
{
code
:
code
,
typ
:
ftyp
,
fn
:
fn
}
impl
:=
&
makeFuncImpl
{
code
:
code
,
typ
:
ftyp
,
fn
:
fn
,
method
:
-
1
}
return
Value
{
t
,
unsafe
.
Pointer
(
&
impl
),
flag
(
Func
<<
flagKindShift
)
|
flagIndir
}
}
...
...
@@ -85,15 +90,94 @@ func makeMethodValue(op string, v Value) Value {
panic
(
"reflect: internal error: invalid use of makePartialFunc"
)
}
switch
runtime
.
GOARCH
{
case
"amd64"
,
"386"
:
default
:
panic
(
"reflect.makeMethodValue not implemented for "
+
runtime
.
GOARCH
)
}
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
fl
:=
v
.
flag
&
(
flagRO
|
flagAddr
|
flagIndir
)
fl
|=
flag
(
v
.
typ
.
Kind
())
<<
flagKindShift
rcvr
:=
Value
{
v
.
typ
,
v
.
val
,
fl
}
// v.Type returns the actual type of the method value.
ft
:=
v
.
Type
()
.
(
*
rtype
)
// Indirect Go func value (dummy) to obtain
// actual code address. (A Go func value is a pointer
// to a C function pointer. http://golang.org/s/go11func.)
dummy
:=
makeFuncStub
code
:=
**
(
**
uintptr
)(
unsafe
.
Pointer
(
&
dummy
))
// Cause panic if method is not appropriate.
// The panic would still happen during the call if we omit this,
// but we want Interface() and other operations to fail early.
methodReceiver
(
op
,
rcvr
,
int
(
v
.
flag
)
>>
flagMethodShift
)
t
,
_
,
_
:=
methodReceiver
(
op
,
rcvr
,
int
(
v
.
flag
)
>>
flagMethodShift
)
fv
:=
&
makeFuncImpl
{
code
:
code
,
typ
:
(
*
funcType
)(
unsafe
.
Pointer
(
t
)),
method
:
int
(
v
.
flag
)
>>
flagMethodShift
,
rcvr
:
rcvr
,
}
return
Value
{
ft
,
unsafe
.
Pointer
(
&
fv
),
v
.
flag
&
flagRO
|
flag
(
Func
)
<<
flagKindShift
|
flagIndir
}
}
panic
(
"reflect makeMethodValue not implemented"
)
// makeValueMethod takes a method function and returns a function that
// takes a value receiver and calls the real method with a pointer to
// it.
func
makeValueMethod
(
v
Value
)
Value
{
typ
:=
v
.
typ
if
typ
.
Kind
()
!=
Func
{
panic
(
"reflect: call of makeValueMethod with non-Func type"
)
}
if
v
.
flag
&
flagMethodFn
==
0
{
panic
(
"reflect: call of makeValueMethod with non-MethodFn"
)
}
switch
runtime
.
GOARCH
{
case
"amd64"
,
"386"
:
default
:
panic
(
"reflect.makeValueMethod not implemented for "
+
runtime
.
GOARCH
)
}
t
:=
typ
.
common
()
ftyp
:=
(
*
funcType
)(
unsafe
.
Pointer
(
t
))
// Indirect Go func value (dummy) to obtain
// actual code address. (A Go func value is a pointer
// to a C function pointer. http://golang.org/s/go11func.)
dummy
:=
makeFuncStub
code
:=
**
(
**
uintptr
)(
unsafe
.
Pointer
(
&
dummy
))
impl
:=
&
makeFuncImpl
{
code
:
code
,
typ
:
ftyp
,
method
:
-
2
,
rcvr
:
v
,
}
return
Value
{
t
,
unsafe
.
Pointer
(
&
impl
),
flag
(
Func
<<
flagKindShift
)
|
flagIndir
}
}
// Call the function represented by a makeFuncImpl.
func
(
c
*
makeFuncImpl
)
call
(
in
[]
Value
)
[]
Value
{
if
c
.
method
==
-
1
{
return
c
.
fn
(
in
)
}
else
if
c
.
method
==
-
2
{
if
c
.
typ
.
IsVariadic
()
{
return
c
.
rcvr
.
CallSlice
(
in
)
}
else
{
return
c
.
rcvr
.
Call
(
in
)
}
}
else
{
m
:=
c
.
rcvr
.
Method
(
c
.
method
)
if
c
.
typ
.
IsVariadic
()
{
return
m
.
CallSlice
(
in
)
}
else
{
return
m
.
Call
(
in
)
}
}
}
libgo/go/reflect/makefuncgo_386.go
View file @
547a4168
...
...
@@ -80,7 +80,7 @@ func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
// Call the real function.
out
:=
c
.
fn
(
in
)
out
:=
c
.
call
(
in
)
if
len
(
out
)
!=
len
(
ftyp
.
out
)
{
panic
(
"reflect: wrong return count from function created by MakeFunc"
)
...
...
libgo/go/reflect/makefuncgo_amd64.go
View file @
547a4168
...
...
@@ -319,7 +319,7 @@ argloop:
// All the real arguments have been found and turned into
// Value's. Call the real function.
out
:=
c
.
fn
(
in
)
out
:=
c
.
call
(
in
)
if
len
(
out
)
!=
len
(
ftyp
.
out
)
{
panic
(
"reflect: wrong return count from function created by MakeFunc"
)
...
...
libgo/go/reflect/type.go
View file @
547a4168
...
...
@@ -517,7 +517,7 @@ func (t *uncommonType) Method(i int) (m Method) {
m
.
Type
=
toType
(
mt
)
x
:=
new
(
unsafe
.
Pointer
)
*
x
=
unsafe
.
Pointer
(
&
p
.
tfn
)
m
.
Func
=
Value
{
mt
,
unsafe
.
Pointer
(
x
),
fl
|
flagIndir
}
m
.
Func
=
Value
{
mt
,
unsafe
.
Pointer
(
x
),
fl
|
flagIndir
|
flagMethodFn
}
m
.
Index
=
i
return
}
...
...
libgo/go/reflect/value.go
View file @
547a4168
...
...
@@ -98,6 +98,7 @@ const (
flagIndir
flagAddr
flagMethod
flagMethodFn
// gccgo: first fn parameter is always pointer
flagKindShift
=
iota
flagKindWidth
=
5
// there are 27 kinds
flagKindMask
flag
=
1
<<
flagKindWidth
-
1
...
...
@@ -433,7 +434,7 @@ func (v Value) call(op string, in []Value) []Value {
if
v
.
flag
&
flagMethod
!=
0
{
nin
++
}
firstPointer
:=
len
(
in
)
>
0
&&
t
.
In
(
0
)
.
Kind
()
!=
Ptr
&&
v
.
flag
&
flagMethod
==
0
&&
isMethod
(
v
.
typ
)
firstPointer
:=
len
(
in
)
>
0
&&
t
.
In
(
0
)
.
Kind
()
!=
Ptr
&&
v
.
flag
&
flagMethod
Fn
!=
0
params
:=
make
([]
unsafe
.
Pointer
,
nin
)
off
:=
0
if
v
.
flag
&
flagMethod
!=
0
{
...
...
@@ -484,33 +485,6 @@ func (v Value) call(op string, in []Value) []Value {
return
ret
}
// gccgo specific test to see if typ is a method. We can tell by
// looking at the string to see if there is a receiver. We need this
// because for gccgo all methods take pointer receivers.
func
isMethod
(
t
*
rtype
)
bool
{
if
Kind
(
t
.
kind
)
!=
Func
{
return
false
}
s
:=
*
t
.
string
parens
:=
0
params
:=
0
sawRet
:=
false
for
i
,
c
:=
range
s
{
if
c
==
'('
{
if
parens
==
0
{
params
++
}
parens
++
}
else
if
c
==
')'
{
parens
--
}
else
if
parens
==
0
&&
c
==
' '
&&
s
[
i
+
1
]
!=
'('
&&
!
sawRet
{
params
++
sawRet
=
true
}
}
return
params
>
2
}
// methodReceiver returns information about the receiver
// described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should
...
...
@@ -873,6 +847,16 @@ func valueInterface(v Value, safe bool) interface{} {
v
=
makeMethodValue
(
"Interface"
,
v
)
}
if
v
.
flag
&
flagMethodFn
!=
0
{
if
v
.
typ
.
Kind
()
!=
Func
{
panic
(
"reflect: MethodFn of non-Func"
)
}
ft
:=
(
*
funcType
)(
unsafe
.
Pointer
(
v
.
typ
))
if
ft
.
in
[
0
]
.
Kind
()
!=
Ptr
{
v
=
makeValueMethod
(
v
)
}
}
k
:=
v
.
kind
()
if
k
==
Interface
{
// Special case: return the element inside the interface.
...
...
@@ -1187,8 +1171,7 @@ func (v Value) Pointer() uintptr {
// created via reflect have the same underlying code pointer,
// so their Pointers are equal. The function used here must
// match the one used in makeMethodValue.
// This is not properly implemented for gccgo.
f
:=
Zero
f
:=
makeFuncStub
return
**
(
**
uintptr
)(
unsafe
.
Pointer
(
&
f
))
}
p
:=
v
.
val
...
...
libgo/runtime/go-recover.c
View file @
547a4168
...
...
@@ -84,6 +84,11 @@ __go_can_recover (const void *retaddr)
if
(
name
[
0
]
==
'f'
&&
name
[
1
]
==
'f'
&&
name
[
2
]
==
'i'
&&
name
[
3
]
==
'_'
)
return
1
;
/* We may also be called by reflect.makeFuncImpl.call, for a
function created by reflect.MakeFunc. */
if
(
__builtin_strstr
((
const
char
*
)
name
,
"makeFuncImpl"
)
!=
NULL
)
return
1
;
return
0
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment