Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
a6ba5ec5
Commit
a6ba5ec5
authored
May 06, 2009
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
6g: new interface rules (code got simpler!)
R=ken OCL=28374 CL=28378
parent
d76f0957
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
121 additions
and
178 deletions
+121
-178
src/cmd/gc/dcl.c
src/cmd/gc/dcl.c
+1
-2
src/cmd/gc/go.h
src/cmd/gc/go.h
+1
-6
src/cmd/gc/obj.c
src/cmd/gc/obj.c
+38
-43
src/cmd/gc/subr.c
src/cmd/gc/subr.c
+73
-119
src/cmd/gc/walk.c
src/cmd/gc/walk.c
+8
-8
No files found.
src/cmd/gc/dcl.c
View file @
a6ba5ec5
...
...
@@ -129,7 +129,6 @@ updatetype(Type *n, Type *t)
n
->
sym
=
s
;
n
->
local
=
local
;
n
->
siggen
=
0
;
n
->
methptr
=
0
;
n
->
printed
=
0
;
n
->
method
=
nil
;
n
->
vargen
=
0
;
...
...
@@ -293,7 +292,7 @@ addmethod(Node *n, Type *t, int local)
if
(
pa
==
T
)
goto
bad
;
f
=
dclmethod
(
pa
);
f
=
methtype
(
pa
);
if
(
f
==
T
)
goto
bad
;
...
...
src/cmd/gc/go.h
View file @
a6ba5ec5
...
...
@@ -137,7 +137,6 @@ struct Type
uchar
chan
;
uchar
recur
;
// to detect loops
uchar
trecur
;
// to detect loops
uchar
methptr
;
// 1=direct 2=pointer
uchar
printed
;
uchar
embedded
;
// TFIELD embedded type
uchar
siggen
;
...
...
@@ -725,9 +724,7 @@ int isinter(Type*);
int
isnilinter
(
Type
*
);
int
isddd
(
Type
*
);
Type
*
maptype
(
Type
*
,
Type
*
);
Type
*
dclmethod
(
Type
*
);
Type
*
methtype
(
Type
*
);
int
methconv
(
Type
*
);
Sym
*
signame
(
Type
*
);
int
eqtype
(
Type
*
,
Type
*
,
int
);
int
eqtypenoname
(
Type
*
,
Type
*
);
...
...
@@ -787,10 +784,8 @@ int lookdot0(Sym*, Type*, Type**);
Type
*
lookdot1
(
Sym
*
,
Type
*
,
Type
*
);
int
adddot1
(
Sym
*
,
Type
*
,
int
,
Type
**
);
Node
*
adddot
(
Node
*
);
void
expand0
(
Type
*
);
void
expand1
(
Type
*
,
int
);
void
expandmeth
(
Sym
*
,
Type
*
);
void
gen
ptrtramp
(
Sym
*
,
Sym
*
,
Type
*
,
Type
*
,
Sym
*
,
Type
*
);
void
gen
wrapper
(
Type
*
,
Type
*
,
Sym
*
);
/*
* dcl.c
...
...
src/cmd/gc/obj.c
View file @
a6ba5ec5
...
...
@@ -140,6 +140,12 @@ ieeedtod(uint64 *ieee, double native)
*
ieee
=
((
uint64
)
h
<<
32
)
|
l
;
}
static
int
sigcmp
(
Sig
*
a
,
Sig
*
b
)
{
return
strcmp
(
a
->
name
,
b
->
name
);
}
/*
* Add DATA for signature s.
* progt - type in program
...
...
@@ -165,13 +171,6 @@ ieeedtod(uint64 *ieee, double native)
* } meth[1]; // one or more - last name is nil
* };
*/
static
int
sigcmp
(
Sig
*
a
,
Sig
*
b
)
{
return
strcmp
(
a
->
name
,
b
->
name
);
}
void
dumpsigt
(
Type
*
progt
,
Type
*
ifacet
,
Type
*
rcvrt
,
Type
*
methodt
,
Sym
*
s
)
{
...
...
@@ -180,12 +179,16 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
Sig
*
a
,
*
b
;
char
buf
[
NSYMB
];
Type
*
this
;
Iter
savet
;
Prog
*
oldlist
;
Sym
*
method
;
uint32
sighash
;
int
ot
;
if
(
debug
[
'r'
])
{
print
(
"dumpsigt progt=%T ifacet=%T rcvrt=%T methodt=%T s=%S
\n
"
,
progt
,
ifacet
,
rcvrt
,
methodt
,
s
);
}
a
=
nil
;
o
=
0
;
oldlist
=
nil
;
...
...
@@ -201,6 +204,16 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
if
(
method
==
nil
)
continue
;
// get receiver type for this particular method.
this
=
getthisx
(
f
->
type
)
->
type
->
type
;
if
(
f
->
embedded
!=
2
&&
isptr
[
this
->
etype
]
&&
!
isptr
[
progt
->
etype
])
{
// pointer receiver method but value method set.
// ignore.
if
(
debug
[
'r'
])
print
(
"ignore %T for %T
\n
"
,
f
,
progt
);
continue
;
}
b
=
mal
(
sizeof
(
*
b
));
b
->
link
=
a
;
a
=
b
;
...
...
@@ -216,31 +229,19 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
if
(
!
a
->
sym
->
siggen
)
{
a
->
sym
->
siggen
=
1
;
// TODO(rsc): This test is still not quite right.
this
=
structfirst
(
&
savet
,
getthis
(
f
->
type
))
->
type
;
if
(
isptr
[
this
->
etype
]
!=
isptr
[
ifacet
->
etype
])
{
if
(
!
eqtype
(
this
,
ifacet
,
0
))
{
if
(
oldlist
==
nil
)
oldlist
=
pc
;
// indirect vs direct mismatch
Sym
*
oldname
,
*
newname
;
Type
*
oldthis
,
*
newthis
;
newthis
=
ifacet
;
if
(
isptr
[
newthis
->
etype
])
oldthis
=
ifacet
->
type
;
// It would be okay to call genwrapper here always,
// but we can generate more efficient code
// using genembedtramp if all that is necessary
// is a pointer adjustment and a JMP.
if
(
f
->
embedded
&&
isptr
[
ifacet
->
etype
])
genembedtramp
(
ifacet
,
a
);
else
oldthis
=
ptrto
(
ifacet
);
newname
=
a
->
sym
;
oldname
=
methodsym
(
method
,
oldthis
);
genptrtramp
(
method
,
oldname
,
oldthis
,
f
->
type
,
newname
,
newthis
);
}
else
if
(
f
->
embedded
)
{
// TODO(rsc): only works for pointer receivers
if
(
oldlist
==
nil
)
oldlist
=
pc
;
genembedtramp
(
ifacet
,
a
);
genwrapper
(
ifacet
,
f
,
a
->
sym
);
}
}
o
++
;
...
...
@@ -449,23 +450,17 @@ dumpsignatures(void)
rcvrt
=
t
;
// if there's a pointer, methods are on base.
if
(
isptr
[
methodt
->
etype
]
&&
methodt
->
type
->
sym
!=
S
)
{
methodt
=
methodt
->
type
;
methodt
=
methtype
(
progt
);
if
(
methodt
==
T
)
{
// if that failed, go back to progt,
// assuming we're writing out a signature
// for a type with no methods
methodt
=
progt
;
}
else
{
expandmeth
(
methodt
->
sym
,
methodt
);
// if methodt had a name, we don't want to see
// it in the method names that go into the sigt.
// e.g., if
// type item *rat
// then item needs its own sigt distinct from *rat,
// but it needs to have all of *rat's methods, using
// the *rat (not item) in the method names.
if
(
rcvrt
->
sym
!=
S
)
rcvrt
=
ptrto
(
methodt
);
}
// and if ifacet is too wide, the methods
// will see a pointer anyway.
// if ifacet is too wide, the methods will see a pointer.
if
(
ifacet
->
width
>
8
)
{
ifacet
=
ptrto
(
progt
);
rcvrt
=
ptrto
(
progt
);
...
...
@@ -473,7 +468,7 @@ dumpsignatures(void)
// don't emit non-trivial signatures for types defined outside this file.
// non-trivial signatures might also drag in generated trampolines,
// and ar can't handle duplicate
s of the trampoline
s.
// and ar can't handle duplicate
function
s.
// only pay attention to types with symbols, because
// the ... structs and maybe other internal structs
// don't get marked as local.
...
...
src/cmd/gc/subr.c
View file @
a6ba5ec5
...
...
@@ -1495,7 +1495,7 @@ isddd(Type *t)
* return type to hang methods off (r).
*/
Type
*
dclmethod
(
Type
*
t
)
methtype
(
Type
*
t
)
{
int
ptr
;
...
...
@@ -1517,15 +1517,6 @@ dclmethod(Type *t)
if
(
t
->
sym
==
S
)
return
T
;
// check that all method receivers are consistent
if
(
t
->
methptr
!=
0
&&
t
->
methptr
!=
(
1
<<
ptr
))
{
if
(
t
->
methptr
!=
3
)
{
t
->
methptr
=
3
;
yyerror
(
"methods on both %T and *%T"
,
t
,
t
);
}
}
t
->
methptr
|=
1
<<
ptr
;
// check types
if
(
!
issimple
[
t
->
etype
])
switch
(
t
->
etype
)
{
...
...
@@ -1543,50 +1534,6 @@ dclmethod(Type *t)
return
t
;
}
/*
* this is dclmethod() without side effects.
*/
Type
*
methtype
(
Type
*
t
)
{
if
(
t
==
T
)
return
T
;
if
(
isptr
[
t
->
etype
])
{
if
(
t
->
sym
!=
S
)
return
T
;
t
=
t
->
type
;
}
if
(
t
==
T
||
t
->
etype
==
TINTER
||
t
->
sym
==
S
)
return
T
;
return
t
;
}
/*
* given type t in a method call, returns op
* to convert t into appropriate receiver.
* returns OADDR if t==x and method takes *x
* returns OIND if t==*x and method takes x
*/
int
methconv
(
Type
*
t
)
{
Type
*
m
;
m
=
methtype
(
t
);
if
(
m
==
T
)
return
0
;
if
(
m
->
methptr
&
2
)
{
// want pointer
if
(
t
==
m
)
return
OADDR
;
return
0
;
}
// want non-pointer
if
(
t
!=
m
)
return
OIND
;
return
0
;
}
int
iscomposite
(
Type
*
t
)
{
...
...
@@ -2604,19 +2551,22 @@ struct Symlink
{
Type
*
field
;
uchar
good
;
uchar
followptr
;
Symlink
*
link
;
};
static
Symlink
*
slist
;
void
expand0
(
Type
*
t
)
static
void
expand0
(
Type
*
t
,
int
followptr
)
{
Type
*
f
,
*
u
;
Symlink
*
sl
;
u
=
t
;
if
(
isptr
[
u
->
etype
])
if
(
isptr
[
u
->
etype
])
{
followptr
=
1
;
u
=
u
->
type
;
}
u
=
methtype
(
t
);
if
(
u
!=
T
)
{
...
...
@@ -2629,13 +2579,14 @@ expand0(Type *t)
sl
=
mal
(
sizeof
(
*
sl
));
sl
->
field
=
f
;
sl
->
link
=
slist
;
sl
->
followptr
=
followptr
;
slist
=
sl
;
}
}
}
void
expand1
(
Type
*
t
,
int
d
)
static
void
expand1
(
Type
*
t
,
int
d
,
int
followptr
)
{
Type
*
f
,
*
u
;
...
...
@@ -2646,11 +2597,13 @@ expand1(Type *t, int d)
t
->
trecur
=
1
;
if
(
d
!=
nelem
(
dotlist
)
-
1
)
expand0
(
t
);
expand0
(
t
,
followptr
);
u
=
t
;
if
(
isptr
[
u
->
etype
])
if
(
isptr
[
u
->
etype
])
{
followptr
=
1
;
u
=
u
->
type
;
}
if
(
u
->
etype
!=
TSTRUCT
&&
u
->
etype
!=
TINTER
)
goto
out
;
...
...
@@ -2659,7 +2612,7 @@ expand1(Type *t, int d)
continue
;
if
(
f
->
sym
==
S
)
continue
;
expand1
(
f
->
type
,
d
-
1
);
expand1
(
f
->
type
,
d
-
1
,
followptr
);
}
out:
...
...
@@ -2682,7 +2635,7 @@ expandmeth(Sym *s, Type *t)
// generate all reachable methods
slist
=
nil
;
expand1
(
t
,
nelem
(
dotlist
)
-
1
);
expand1
(
t
,
nelem
(
dotlist
)
-
1
,
0
);
// check each method to be uniquely reachable
for
(
sl
=
slist
;
sl
!=
nil
;
sl
=
sl
->
link
)
{
...
...
@@ -2704,7 +2657,8 @@ expandmeth(Sym *s, Type *t)
f
=
typ
(
TFIELD
);
*
f
=
*
sl
->
field
;
f
->
embedded
=
1
;
// needs a trampoline
if
(
sl
->
followptr
)
f
->
embedded
=
2
;
f
->
down
=
t
->
method
;
t
->
method
=
f
;
...
...
@@ -2742,43 +2696,46 @@ structargs(Type **tl, int mustname)
}
/*
* Generate a trampoline to convert
* from an indirect receiver to a direct receiver
* or vice versa.
* Generate a wrapper function to convert from
* a receiver of type T to a receiver of type U.
* That is,
*
* func (t T) M() {
* ...
* }
*
* already exists; this function generates
*
* func (u U) M() {
* u.M()
* }
*
* where the types T and U are such that u.M() is valid
* and calls the T.M method.
* The resulting function is for use in method tables.
*
* method - short name of method (Len)
* oldname - old mangled method name (x·y·Len)
* oldthis - old this type (y)
* oldtype - type of method being called;
* only in and out params are known okay,
* receiver might be != oldthis.
* newnam [sic] - new mangled method name (x·*y·Len)
* newthis - new this type (*y)
* rcvrtype - U
* method - M func (t T)(), a TFIELD type struct
* newnam - the eventual mangled name of this function
*/
void
gen
ptrtramp
(
Sym
*
method
,
Sym
*
oldname
,
Type
*
oldthis
,
Type
*
oldtype
,
Sym
*
newnam
,
Type
*
newthis
)
gen
wrapper
(
Type
*
rcvrtype
,
Type
*
method
,
Sym
*
newnam
)
{
Node
*
fn
,
*
args
,
*
l
,
*
in
,
*
call
,
*
out
,
*
this
,
*
rcvr
,
*
meth
;
Node
*
this
,
*
in
,
*
out
,
*
fn
,
*
args
,
*
call
;
Node
*
l
;
Iter
savel
;
if
(
debug
[
'r'
])
{
print
(
"
\n
genptrtramp method=%S oldname=%S oldthis=%T
\n
"
,
method
,
oldname
,
oldthis
);
print
(
"
\t
oldtype=%T newnam=%S newthis=%T
\n
"
,
oldtype
,
newnam
,
newthis
);
print
(
"genwrapper rcvrtype=%T method=%T newnam=%S
\n
"
,
rcvrtype
,
method
,
newnam
);
}
dclcontext
=
PEXTERN
;
markdcl
();
this
=
nametodcl
(
newname
(
lookup
(
".this"
)),
newthis
);
in
=
structargs
(
getinarg
(
oldtype
),
1
);
out
=
structargs
(
getoutarg
(
oldtype
),
0
);
// fix up oldtype
markdcl
();
oldtype
=
functype
(
nametodcl
(
newname
(
lookup
(
".this"
)),
oldthis
),
in
,
out
);
popdcl
();
this
=
nametodcl
(
newname
(
lookup
(
".this"
)),
rcvrtype
);
in
=
structargs
(
getinarg
(
method
->
type
),
1
);
out
=
structargs
(
getoutarg
(
method
->
type
),
0
);
fn
=
nod
(
ODCLFUNC
,
N
,
N
);
fn
->
nname
=
newname
(
newnam
);
...
...
@@ -2791,19 +2748,10 @@ genptrtramp(Sym *method, Sym *oldname, Type *oldthis, Type *oldtype, Sym *newnam
args
=
list
(
args
,
l
->
left
);
args
=
rev
(
args
);
// method to call
if
(
isptr
[
oldthis
->
etype
])
rcvr
=
nod
(
OADDR
,
this
->
left
,
N
);
else
rcvr
=
nod
(
OIND
,
this
->
left
,
N
);
gettype
(
rcvr
,
N
);
meth
=
nod
(
ODOTMETH
,
rcvr
,
newname
(
oldname
));
meth
->
xoffset
=
BADWIDTH
;
// TODO(rsc): necessary?
meth
->
type
=
oldtype
;
call
=
nod
(
OCALL
,
meth
,
args
);
// generate call
call
=
nod
(
OCALL
,
adddot
(
nod
(
ODOT
,
this
->
left
,
newname
(
method
->
sym
))),
args
);
fn
->
nbody
=
call
;
if
(
old
type
->
outtuple
>
0
)
if
(
method
->
type
->
outtuple
>
0
)
fn
->
nbody
=
nod
(
ORETURN
,
call
,
N
);
if
(
debug
[
'r'
])
...
...
@@ -2850,11 +2798,13 @@ ifacecheck(Type *dst, Type *src, int lineno, int explicit)
}
Type
*
ifacelookdot
(
Sym
*
s
,
Type
*
t
)
ifacelookdot
(
Sym
*
s
,
Type
*
t
,
int
*
followptr
)
{
int
c
,
d
;
int
i
,
c
,
d
;
Type
*
m
;
*
followptr
=
0
;
if
(
t
==
T
)
return
T
;
...
...
@@ -2864,8 +2814,15 @@ ifacelookdot(Sym *s, Type *t)
yyerror
(
"%T.%S is ambiguous"
,
t
,
s
);
return
T
;
}
if
(
c
==
1
)
if
(
c
==
1
)
{
for
(
i
=
0
;
i
<
d
;
i
++
)
{
if
(
isptr
[
dotlist
[
i
].
field
->
type
->
etype
])
{
*
followptr
=
1
;
break
;
}
}
return
m
;
}
}
return
T
;
}
...
...
@@ -2875,23 +2832,11 @@ ifacelookdot(Sym *s, Type *t)
int
ifaceokT2I
(
Type
*
t0
,
Type
*
iface
,
Type
**
m
)
{
Type
*
t
,
*
im
,
*
tm
;
int
imhash
;
Type
*
t
,
*
im
,
*
tm
,
*
rcvr
;
int
imhash
,
followptr
;
t
=
methtype
(
t0
);
// stopgap: check for
// non-pointer type in T2I, methods want pointers.
// supposed to do something better eventually
// but this will catch errors while we decide the
// details of the "better" solution.
// only warn if iface is not interface{}.
if
(
t
==
t0
&&
t
->
methptr
==
2
&&
iface
->
type
!=
T
)
{
yyerror
(
"probably wanted *%T not %T"
,
t
,
t
);
*
m
=
iface
->
type
;
return
0
;
}
// if this is too slow,
// could sort these first
// and then do one loop.
...
...
@@ -2905,11 +2850,20 @@ ifaceokT2I(Type *t0, Type *iface, Type **m)
for
(
im
=
iface
->
type
;
im
;
im
=
im
->
down
)
{
imhash
=
typehash
(
im
,
0
,
0
);
tm
=
ifacelookdot
(
im
->
sym
,
t
);
tm
=
ifacelookdot
(
im
->
sym
,
t
,
&
followptr
);
if
(
tm
==
T
||
typehash
(
tm
,
0
,
0
)
!=
imhash
)
{
*
m
=
im
;
return
0
;
}
// if pointer receiver in method,
// the method does not exist for value types.
rcvr
=
getthisx
(
tm
->
type
)
->
type
->
type
;
if
(
isptr
[
rcvr
->
etype
]
&&
!
isptr
[
t0
->
etype
]
&&
!
followptr
)
{
if
(
debug
[
'r'
])
yyerror
(
"interface pointer mismatch"
);
*
m
=
im
;
return
0
;
}
}
return
1
;
}
...
...
src/cmd/gc/walk.c
View file @
a6ba5ec5
...
...
@@ -1590,8 +1590,7 @@ lookdot1(Sym *s, Type *t, Type *f)
int
lookdot
(
Node
*
n
,
Type
*
t
)
{
Type
*
f1
,
*
f2
,
*
tt
;
int
op
;
Type
*
f1
,
*
f2
,
*
tt
,
*
rcvr
;
Sym
*
s
;
s
=
n
->
right
->
sym
;
...
...
@@ -1618,18 +1617,19 @@ lookdot(Node *n, Type *t)
if
(
f2
!=
T
)
{
tt
=
n
->
left
->
type
;
if
((
op
=
methconv
(
tt
))
!=
0
)
{
switch
(
op
)
{
case
OADDR
:
rcvr
=
getthisx
(
f2
->
type
)
->
type
->
type
;
if
(
!
eqtype
(
rcvr
,
tt
,
0
)
)
{
if
(
rcvr
->
etype
==
tptr
&&
eqtype
(
rcvr
->
type
,
tt
,
0
))
{
walktype
(
n
->
left
,
Elv
);
addrescapes
(
n
->
left
);
n
->
left
=
nod
(
OADDR
,
n
->
left
,
N
);
n
->
left
->
type
=
ptrto
(
tt
);
break
;
case
OIND
:
}
else
if
(
tt
->
etype
==
tptr
&&
eqtype
(
tt
->
type
,
rcvr
,
0
))
{
n
->
left
=
nod
(
OIND
,
n
->
left
,
N
);
n
->
left
->
type
=
tt
->
type
;
break
;
}
else
{
// method is attached to wrong type?
fatal
(
"method mismatch: %T for %T"
,
rcvr
,
tt
);
}
}
n
->
right
=
methodname
(
n
->
right
,
n
->
left
->
type
);
...
...
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