Skip to content

Commit 1903ad7

Browse files
committed
cmd/gc, reflect, runtime: switch to indirect func value representation
Step 1 of http://golang.org/s/go11func. R=golang-dev, r, daniel.morsing, remyoudompheng CC=golang-dev https://golang.org/cl/7393045
1 parent 4335e69 commit 1903ad7

38 files changed

+316
-89
lines changed

src/cmd/5g/gg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ int isfat(Type*);
141141
int dotaddable(Node*, Node*);
142142
void sudoclean(void);
143143
int sudoaddable(int, Node*, Addr*, int*);
144-
void afunclit(Addr*);
144+
void afunclit(Addr*, Node*);
145145
void datagostring(Strlit*, Addr*);
146146
void split64(Node*, Node*, Node*);
147147
void splitclean(void);

src/cmd/5g/ggen.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,17 @@ fixautoused(Prog* p)
5252
/*
5353
* generate:
5454
* call f
55+
* proc=-1 normal call but no return
5556
* proc=0 normal call
5657
* proc=1 goroutine run in new proc
5758
* proc=2 defer call save away stack
59+
* proc=3 normal call to C pointer (not Go func value)
5860
*/
5961
void
6062
ginscall(Node *f, int proc)
6163
{
6264
Prog *p;
63-
Node n1, r, con;
65+
Node n1, r, r1, con;
6466

6567
switch(proc) {
6668
default:
@@ -69,10 +71,24 @@ ginscall(Node *f, int proc)
6971

7072
case 0: // normal call
7173
case -1: // normal call but no return
72-
p = gins(ABL, N, f);
73-
afunclit(&p->to);
74-
if(proc == -1 || noreturn(p))
75-
gins(AUNDEF, N, N);
74+
if(f->op == ONAME && f->class == PFUNC) {
75+
p = gins(ABL, N, f);
76+
afunclit(&p->to, f);
77+
if(proc == -1 || noreturn(p))
78+
gins(AUNDEF, N, N);
79+
break;
80+
}
81+
nodreg(&r, types[tptr], 0);
82+
nodreg(&r1, types[tptr], 1);
83+
gmove(f, &r);
84+
r.op = OINDREG;
85+
gmove(&r, &r1);
86+
r1.op = OINDREG;
87+
gins(ABL, N, &r1);
88+
break;
89+
90+
case 3: // normal call of c function pointer
91+
gins(ABL, N, f);
7692
break;
7793

7894
case 1: // call in new proc (go)
@@ -139,6 +155,7 @@ cgen_callinter(Node *n, Node *res, int proc)
139155
int r;
140156
Node *i, *f;
141157
Node tmpi, nodo, nodr, nodsp;
158+
Prog *p;
142159

143160
i = n->left;
144161
if(i->op != ODOTINTER)
@@ -183,7 +200,17 @@ cgen_callinter(Node *n, Node *res, int proc)
183200
cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
184201

185202
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
186-
cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
203+
204+
if(proc == 0) {
205+
// plain call: use direct c function pointer - more efficient
206+
cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
207+
nodr.op = OINDREG;
208+
proc = 3;
209+
} else {
210+
// go/defer. generate go func value.
211+
p = gins(AMOVW, &nodo, &nodr);
212+
p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f]
213+
}
187214

188215
// BOTCH nodr.type = fntype;
189216
nodr.type = n->left->type;

src/cmd/5g/gsubr.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,12 @@ isfat(Type *t)
257257
* also fix up direct register references to be D_OREG.
258258
*/
259259
void
260-
afunclit(Addr *a)
260+
afunclit(Addr *a, Node *n)
261261
{
262262
if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
263263
a->type = D_OREG;
264+
if(n->op == ONAME)
265+
a->sym = n->sym;
264266
}
265267
}
266268

@@ -1315,6 +1317,7 @@ naddr(Node *n, Addr *a, int canemitcode)
13151317
case PFUNC:
13161318
a->name = D_EXTERN;
13171319
a->type = D_CONST;
1320+
a->sym = funcsym(a->sym);
13181321
break;
13191322
}
13201323
break;

src/cmd/6g/gg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ Plist* newplist(void);
130130
int isfat(Type*);
131131
void sudoclean(void);
132132
int sudoaddable(int, Node*, Addr*);
133-
void afunclit(Addr*);
133+
void afunclit(Addr*, Node*);
134134
void nodfconst(Node*, Type*, Mpflt*);
135135
void gtrack(Sym*);
136136

src/cmd/6g/ggen.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ fixautoused(Prog* p)
5050
/*
5151
* generate:
5252
* call f
53+
* proc=-1 normal call but no return
5354
* proc=0 normal call
5455
* proc=1 goroutine run in new proc
5556
* proc=2 defer call save away stack
57+
* proc=3 normal call to C pointer (not Go func value)
5658
*/
5759
void
5860
ginscall(Node *f, int proc)
@@ -68,10 +70,23 @@ ginscall(Node *f, int proc)
6870

6971
case 0: // normal call
7072
case -1: // normal call but no return
71-
p = gins(ACALL, N, f);
72-
afunclit(&p->to);
73-
if(proc == -1 || noreturn(p))
74-
gins(AUNDEF, N, N);
73+
if(f->op == ONAME && f->class == PFUNC) {
74+
p = gins(ACALL, N, f);
75+
afunclit(&p->to, f);
76+
if(proc == -1 || noreturn(p))
77+
gins(AUNDEF, N, N);
78+
break;
79+
}
80+
nodreg(&reg, types[tptr], D_AX);
81+
nodreg(&r1, types[tptr], D_BX);
82+
gmove(f, &reg);
83+
reg.op = OINDREG;
84+
gmove(&reg, &r1);
85+
gins(ACALL, N, &r1);
86+
break;
87+
88+
case 3: // normal call of c function pointer
89+
gins(ACALL, N, f);
7590
break;
7691

7792
case 1: // call in new proc (go)
@@ -153,7 +168,14 @@ cgen_callinter(Node *n, Node *res, int proc)
153168
fatal("cgen_callinter: badwidth");
154169
nodo.op = OINDREG;
155170
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
156-
cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
171+
if(proc == 0) {
172+
// plain call: use direct c function pointer - more efficient
173+
cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
174+
proc = 3;
175+
} else {
176+
// go/defer. generate go func value.
177+
gins(ALEAQ, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.tab->fun[f]
178+
}
157179

158180
// BOTCH nodr.type = fntype;
159181
nodr.type = n->left->type;

src/cmd/6g/gsubr.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,12 @@ isfat(Type *t)
254254
* call afunclit to fix up the argument.
255255
*/
256256
void
257-
afunclit(Addr *a)
257+
afunclit(Addr *a, Node *n)
258258
{
259259
if(a->type == D_ADDR && a->index == D_EXTERN) {
260260
a->type = D_EXTERN;
261261
a->index = D_NONE;
262+
a->sym = n->sym;
262263
}
263264
}
264265

@@ -1195,6 +1196,7 @@ naddr(Node *n, Addr *a, int canemitcode)
11951196
a->index = D_EXTERN;
11961197
a->type = D_ADDR;
11971198
a->width = widthptr;
1199+
a->sym = funcsym(a->sym);
11981200
break;
11991201
}
12001202
break;

src/cmd/8g/gg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ int isfat(Type*);
148148
void sudoclean(void);
149149
int sudoaddable(int, Node*, Addr*);
150150
int dotaddable(Node*, Node*);
151-
void afunclit(Addr*);
151+
void afunclit(Addr*, Node*);
152152
void split64(Node*, Node*, Node*);
153153
void splitclean(void);
154154
void nswap(Node*, Node*);

src/cmd/8g/ggen.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,17 @@ clearfat(Node *nl)
9494
/*
9595
* generate:
9696
* call f
97+
* proc=-1 normal call but no return
9798
* proc=0 normal call
9899
* proc=1 goroutine run in new proc
99100
* proc=2 defer call save away stack
101+
* proc=3 normal call to C pointer (not Go func value)
100102
*/
101103
void
102104
ginscall(Node *f, int proc)
103105
{
104106
Prog *p;
105-
Node reg, con;
107+
Node reg, r1, con;
106108

107109
switch(proc) {
108110
default:
@@ -111,10 +113,23 @@ ginscall(Node *f, int proc)
111113

112114
case 0: // normal call
113115
case -1: // normal call but no return
114-
p = gins(ACALL, N, f);
115-
afunclit(&p->to);
116-
if(proc == -1 || noreturn(p))
117-
gins(AUNDEF, N, N);
116+
if(f->op == ONAME && f->class == PFUNC) {
117+
p = gins(ACALL, N, f);
118+
afunclit(&p->to, f);
119+
if(proc == -1 || noreturn(p))
120+
gins(AUNDEF, N, N);
121+
break;
122+
}
123+
nodreg(&reg, types[tptr], D_AX);
124+
nodreg(&r1, types[tptr], D_BX);
125+
gmove(f, &reg);
126+
reg.op = OINDREG;
127+
gmove(&reg, &r1);
128+
gins(ACALL, N, &r1);
129+
break;
130+
131+
case 3: // normal call of c function pointer
132+
gins(ACALL, N, f);
118133
break;
119134

120135
case 1: // call in new proc (go)
@@ -186,7 +201,15 @@ cgen_callinter(Node *n, Node *res, int proc)
186201
fatal("cgen_callinter: badwidth");
187202
nodo.op = OINDREG;
188203
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
189-
cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
204+
205+
if(proc == 0) {
206+
// plain call: use direct c function pointer - more efficient
207+
cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
208+
proc = 3;
209+
} else {
210+
// go/defer. generate go func value.
211+
gins(ALEAL, &nodo, &nodr); // REG = &(20+offset(REG)) -- i.tab->fun[f]
212+
}
190213

191214
// BOTCH nodr.type = fntype;
192215
nodr.type = n->left->type;

src/cmd/8g/gsubr.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,12 @@ isfat(Type *t)
255255
* call afunclit to fix up the argument.
256256
*/
257257
void
258-
afunclit(Addr *a)
258+
afunclit(Addr *a, Node *n)
259259
{
260260
if(a->type == D_ADDR && a->index == D_EXTERN) {
261261
a->type = D_EXTERN;
262262
a->index = D_NONE;
263+
a->sym = n->sym;
263264
}
264265
}
265266

@@ -2273,6 +2274,7 @@ naddr(Node *n, Addr *a, int canemitcode)
22732274
case PFUNC:
22742275
a->index = D_EXTERN;
22752276
a->type = D_ADDR;
2277+
a->sym = funcsym(a->sym);
22762278
break;
22772279
}
22782280
break;

src/cmd/gc/dcl.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,3 +1436,21 @@ funccompile(Node *n, int isclosure)
14361436
funcdepth = 0;
14371437
dclcontext = PEXTERN;
14381438
}
1439+
1440+
Sym*
1441+
funcsym(Sym *s)
1442+
{
1443+
char *p;
1444+
Sym *s1;
1445+
1446+
p = smprint("%s·f", s->name);
1447+
s1 = pkglookup(p, s->pkg);
1448+
free(p);
1449+
if(s1->def == N) {
1450+
s1->def = newname(s1);
1451+
s1->def->shortname = newname(s);
1452+
funcsyms = list(funcsyms, s1->def);
1453+
}
1454+
return s1;
1455+
}
1456+

src/cmd/gc/gen.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ gen(Node *n)
281281

282282
switch(n->op) {
283283
default:
284-
fatal("gen: unknown op %N", n);
284+
fatal("gen: unknown op %+hN", n);
285285
break;
286286

287287
case OCASE:

src/cmd/gc/go.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ EXTERN NodeList* externdcl;
907907
EXTERN NodeList* closures;
908908
EXTERN NodeList* exportlist;
909909
EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies
910+
EXTERN NodeList* funcsyms;
910911
EXTERN int dclcontext; // PEXTERN/PAUTO
911912
EXTERN int incannedimport;
912913
EXTERN int statuniqgen; // name generator for static temps
@@ -1058,6 +1059,7 @@ Node* typedcl0(Sym *s);
10581059
Node* typedcl1(Node *n, Node *t, int local);
10591060
Node* typenod(Type *t);
10601061
NodeList* variter(NodeList *vl, Node *t, NodeList *el);
1062+
Sym* funcsym(Sym*);
10611063

10621064
/*
10631065
* esc.c

src/cmd/gc/obj.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ dumpglobls(void)
6161

6262
ggloblnod(n, n->type->width);
6363
}
64+
65+
for(l=funcsyms; l; l=l->next) {
66+
n = l->n;
67+
dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
68+
ggloblsym(n->sym, widthptr, 1, 1);
69+
}
6470
}
6571

6672
void

src/cmd/gc/pgen.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ compile(Node *fn)
8383
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
8484
if(fn->dupok)
8585
ptxt->TEXTFLAG = DUPOK;
86-
afunclit(&ptxt->from);
86+
afunclit(&ptxt->from, curfn->nname);
8787

8888
ginit();
8989

src/cmd/gc/walk.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ walkexpr(Node **np, NodeList **init)
416416
switch(n->op) {
417417
default:
418418
dump("walk", n);
419-
fatal("walkexpr: switch 1 unknown op %N", n);
419+
fatal("walkexpr: switch 1 unknown op %+hN", n);
420420
break;
421421

422422
case OTYPE:
@@ -442,7 +442,6 @@ walkexpr(Node **np, NodeList **init)
442442
usefield(n);
443443
walkexpr(&n->left, init);
444444
goto ret;
445-
446445

447446
case OEFACE:
448447
walkexpr(&n->left, init);

0 commit comments

Comments
 (0)