Commit 1e1cc4eb authored by Ken Thompson's avatar Ken Thompson

defer

R=r
OCL=23592
CL=23592
parent 4a903e0b
...@@ -26,6 +26,22 @@ if(newproc == N) { ...@@ -26,6 +26,22 @@ if(newproc == N) {
newproc->ullman = 1; newproc->ullman = 1;
} }
if(deferproc == N) {
deferproc = nod(ONAME, N, N);
deferproc->sym = pkglookup("deferproc", "sys");
deferproc->class = PEXTERN;
deferproc->addable = 1;
deferproc->ullman = 1;
}
if(deferreturn == N) {
deferreturn = nod(ONAME, N, N);
deferreturn->sym = pkglookup("deferreturn", "sys");
deferreturn->class = PEXTERN;
deferreturn->addable = 1;
deferreturn->ullman = 1;
}
if(throwindex == N) { if(throwindex == N) {
throwindex = nod(ONAME, N, N); throwindex = nod(ONAME, N, N);
throwindex->sym = pkglookup("throwindex", "sys"); throwindex->sym = pkglookup("throwindex", "sys");
...@@ -63,6 +79,7 @@ if(throwreturn == N) { ...@@ -63,6 +79,7 @@ if(throwreturn == N) {
} }
} }
hasdefer = 0;
walk(curfn); walk(curfn);
if(nerrors != 0) if(nerrors != 0)
goto ret; goto ret;
...@@ -90,6 +107,8 @@ if(throwreturn == N) { ...@@ -90,6 +107,8 @@ if(throwreturn == N) {
gins(ACALL, N, throwreturn); gins(ACALL, N, throwreturn);
} }
if(hasdefer)
gins(ACALL, N, deferreturn);
pc->as = ARET; // overwrite AEND pc->as = ARET; // overwrite AEND
pc->lineno = lineno; pc->lineno = lineno;
...@@ -343,7 +362,11 @@ loop: ...@@ -343,7 +362,11 @@ loop:
break; break;
case OPROC: case OPROC:
cgen_proc(n); cgen_proc(n, 1);
break;
case ODEFER:
cgen_proc(n, 2);
break; break;
case ORETURN: case ORETURN:
...@@ -683,19 +706,26 @@ argsize(Type *t) ...@@ -683,19 +706,26 @@ argsize(Type *t)
/* /*
* generate: * generate:
* call f * call f
* if proc, generate: * proc=0 normal call
* push f * proc=1 goroutine run in new proc
* push argsize * proc=2 defer call save away stack
* call newproc
* pop
* pop
*/ */
void void
ginscall(Node *f, int proc) ginscall(Node *f, int proc)
{ {
Node reg, con; Node reg, con;
if(proc) { switch(proc) {
default:
fatal("ginscall: bad proc %d", proc);
break;
case 0: // normal call
gins(ACALL, N, f);
break;
case 1: // call in new proc (go)
case 2: // defered call (defer)
nodreg(&reg, types[TINT64], D_AX); nodreg(&reg, types[TINT64], D_AX);
if(f->op != OREGISTER) { if(f->op != OREGISTER) {
gins(ALEAQ, f, &reg); gins(ALEAQ, f, &reg);
...@@ -704,12 +734,14 @@ ginscall(Node *f, int proc) ...@@ -704,12 +734,14 @@ ginscall(Node *f, int proc)
gins(APUSHQ, f, N); gins(APUSHQ, f, N);
nodconst(&con, types[TINT32], argsize(f->type)); nodconst(&con, types[TINT32], argsize(f->type));
gins(APUSHQ, &con, N); gins(APUSHQ, &con, N);
if(proc == 1)
gins(ACALL, N, newproc); gins(ACALL, N, newproc);
else
gins(ACALL, N, deferproc);
gins(APOPQ, N, &reg); gins(APOPQ, N, &reg);
gins(APOPQ, N, &reg); gins(APOPQ, N, &reg);
return; break;
} }
gins(ACALL, N, f);
} }
/* /*
...@@ -767,6 +799,9 @@ cgen_callinter(Node *n, Node *res, int proc) ...@@ -767,6 +799,9 @@ cgen_callinter(Node *n, Node *res, int proc)
/* /*
* generate call to non-interface method * generate call to non-interface method
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/ */
void void
cgen_callmeth(Node *n, int proc) cgen_callmeth(Node *n, int proc)
...@@ -791,7 +826,9 @@ cgen_callmeth(Node *n, int proc) ...@@ -791,7 +826,9 @@ cgen_callmeth(Node *n, int proc)
/* /*
* generate function call; * generate function call;
* if proc, run call in new proc. * proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/ */
void void
cgen_call(Node *n, int proc) cgen_call(Node *n, int proc)
...@@ -851,22 +888,22 @@ ret: ...@@ -851,22 +888,22 @@ ret:
* generate code to start new proc running call n. * generate code to start new proc running call n.
*/ */
void void
cgen_proc(Node *n) cgen_proc(Node *n, int proc)
{ {
switch(n->left->op) { switch(n->left->op) {
default: default:
fatal("cgen_proc: unknown call %O", n->left->op); fatal("cgen_proc: unknown call %O", n->left->op);
case OCALLMETH: case OCALLMETH:
cgen_callmeth(n->left, 1); cgen_callmeth(n->left, proc);
break; break;
case OCALLINTER: case OCALLINTER:
cgen_callinter(n->left, N, 1); cgen_callinter(n->left, N, proc);
break; break;
case OCALL: case OCALL:
cgen_call(n->left, 1); cgen_call(n->left, proc);
break; break;
} }
...@@ -947,6 +984,8 @@ void ...@@ -947,6 +984,8 @@ void
cgen_ret(Node *n) cgen_ret(Node *n)
{ {
gen(n->left, L); // copy out args gen(n->left, L); // copy out args
if(hasdefer)
gins(ACALL, N, deferreturn);
gins(ARET, N, N); gins(ARET, N, N);
} }
......
...@@ -116,6 +116,8 @@ EXTERN Label* labellist; ...@@ -116,6 +116,8 @@ EXTERN Label* labellist;
EXTERN Label* findlab(Sym*); EXTERN Label* findlab(Sym*);
EXTERN Node* curfn; EXTERN Node* curfn;
EXTERN Node* newproc; EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex; EXTERN Node* throwindex;
EXTERN Node* throwreturn; EXTERN Node* throwreturn;
...@@ -151,7 +153,7 @@ void cgen_ret(Node*); ...@@ -151,7 +153,7 @@ void cgen_ret(Node*);
void cgen_call(Node*, int); void cgen_call(Node*, int);
void cgen_callmeth(Node*, int); void cgen_callmeth(Node*, int);
void cgen_callinter(Node*, Node*, int); void cgen_callinter(Node*, Node*, int);
void cgen_proc(Node*); void cgen_proc(Node*, int);
void cgen_callret(Node*, Node*); void cgen_callret(Node*, Node*);
void cgen_div(int, Node*, Node*, Node*); void cgen_div(int, Node*, Node*, Node*);
void cgen_bmul(int, Node*, Node*, Node*); void cgen_bmul(int, Node*, Node*, Node*);
......
...@@ -291,7 +291,7 @@ enum ...@@ -291,7 +291,7 @@ enum
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODCLFUNC, ODCLFIELD, ODCLARG, ODCLFUNC, ODCLFIELD, ODCLARG,
OLIST, OCMP, OPTR, OARRAY, ORANGE, OLIST, OCMP, OPTR, OARRAY, ORANGE,
ORETURN, OFOR, OIF, OSWITCH, ORETURN, OFOR, OIF, OSWITCH, ODEFER,
OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
OGOTO, OPROC, OMAKE, ONEW, OEMPTY, OSELECT, OGOTO, OPROC, OMAKE, ONEW, OEMPTY, OSELECT,
OLEN, OCAP, OPANIC, OPANICN, OPRINT, OPRINTN, OTYPEOF, OLEN, OCAP, OPANIC, OPANICN, OPRINT, OPRINTN, OTYPEOF,
...@@ -498,6 +498,7 @@ EXTERN int32 stksize; // stack size for current frame ...@@ -498,6 +498,7 @@ EXTERN int32 stksize; // stack size for current frame
EXTERN int32 initstksize; // stack size for init function EXTERN int32 initstksize; // stack size for init function
EXTERN ushort blockgen; // max block number EXTERN ushort blockgen; // max block number
EXTERN ushort block; // current block number EXTERN ushort block; // current block number
EXTERN int hasdefer; // flag that curfn has defer statetment
EXTERN Node* retnil; EXTERN Node* retnil;
EXTERN Node* fskel; EXTERN Node* fskel;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%token <val> LLITERAL %token <val> LLITERAL
%token <lint> LASOP %token <lint> LASOP
%token <sym> LNAME LBASETYPE LATYPE LPACK LACONST %token <sym> LNAME LBASETYPE LATYPE LPACK LACONST
%token <sym> LPACKAGE LIMPORT LEXPORT %token <sym> LPACKAGE LIMPORT LDEFER
%token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT %token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT
%token <sym> LCOLAS LFALL LRETURN LDDD %token <sym> LCOLAS LFALL LRETURN LDDD
%token <sym> LLEN LCAP LTYPEOF LPANIC LPANICN LPRINT LPRINTN %token <sym> LLEN LCAP LTYPEOF LPANIC LPANICN LPRINT LPRINTN
...@@ -504,6 +504,11 @@ semi_stmt: ...@@ -504,6 +504,11 @@ semi_stmt:
$$ = nod(OCALL, $2, $4); $$ = nod(OCALL, $2, $4);
$$ = nod(OPROC, $$, N); $$ = nod(OPROC, $$, N);
} }
| LDEFER pexpr '(' oexpr_list ')'
{
$$ = nod(OCALL, $2, $4);
$$ = nod(ODEFER, $$, N);
}
| LGOTO new_name | LGOTO new_name
{ {
$$ = nod(OGOTO, $2, N); $$ = nod(OGOTO, $2, N);
......
...@@ -1056,7 +1056,7 @@ static struct ...@@ -1056,7 +1056,7 @@ static struct
"continue", LCONTINUE, Txxx, "continue", LCONTINUE, Txxx,
"default", LDEFAULT, Txxx, "default", LDEFAULT, Txxx,
"else", LELSE, Txxx, "else", LELSE, Txxx,
"export", LEXPORT, Txxx, "defer", LDEFER, Txxx,
"fallthrough", LFALL, Txxx, "fallthrough", LFALL, Txxx,
"false", LFALSE, Txxx, "false", LFALSE, Txxx,
"for", LFOR, Txxx, "for", LFOR, Txxx,
...@@ -1275,7 +1275,7 @@ struct ...@@ -1275,7 +1275,7 @@ struct
LPRINT, "PRINT", LPRINT, "PRINT",
LPACKAGE, "PACKAGE", LPACKAGE, "PACKAGE",
LIMPORT, "IMPORT", LIMPORT, "IMPORT",
LEXPORT, "EXPORT", LDEFER, "DEFER",
LPANIC, "PANIC", LPANIC, "PANIC",
}; };
......
...@@ -641,11 +641,12 @@ opnames[] = ...@@ -641,11 +641,12 @@ opnames[] =
[ODCLARG] = "DCLARG", [ODCLARG] = "DCLARG",
[ODCLFIELD] = "DCLFIELD", [ODCLFIELD] = "DCLFIELD",
[ODCLFUNC] = "DCLFUNC", [ODCLFUNC] = "DCLFUNC",
[ODEFER] = "DEFER",
[ODIV] = "DIV", [ODIV] = "DIV",
[ODOT] = "DOT",
[ODOTPTR] = "DOTPTR",
[ODOTMETH] = "DOTMETH",
[ODOTINTER] = "DOTINTER", [ODOTINTER] = "DOTINTER",
[ODOTMETH] = "DOTMETH",
[ODOTPTR] = "DOTPTR",
[ODOT] = "DOT",
[OEMPTY] = "EMPTY", [OEMPTY] = "EMPTY",
[OEND] = "END", [OEND] = "END",
[OEQ] = "EQ", [OEQ] = "EQ",
......
...@@ -145,6 +145,7 @@ loop: ...@@ -145,6 +145,7 @@ loop:
case OXFALL: case OXFALL:
case ORETURN: case ORETURN:
case OPROC: case OPROC:
case ODEFER:
walktype(n, Etop); walktype(n, Etop);
break; break;
} }
...@@ -342,6 +343,8 @@ loop: ...@@ -342,6 +343,8 @@ loop:
walkstate(n->nelse); walkstate(n->nelse);
goto ret; goto ret;
case ODEFER:
hasdefer = 1;
case OPROC: case OPROC:
if(top != Etop) if(top != Etop)
goto nottop; goto nottop;
......
...@@ -171,7 +171,7 @@ sys·newproc(int32 siz, byte* fn, byte* arg0) ...@@ -171,7 +171,7 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
if((newg = gfget()) != nil){ if((newg = gfget()) != nil){
newg->status = Gwaiting; newg->status = Gwaiting;
}else{ } else {
newg = malg(4096); newg = malg(4096);
newg->status = Gwaiting; newg->status = Gwaiting;
newg->alllink = allg; newg->alllink = allg;
...@@ -204,6 +204,41 @@ sys·newproc(int32 siz, byte* fn, byte* arg0) ...@@ -204,6 +204,41 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
//printf(" goid=%d\n", newg->goid); //printf(" goid=%d\n", newg->goid);
} }
void
sys·deferproc(int32 siz, byte* fn, byte* arg0)
{
Defer *d;
d = mal(sizeof(*d) + siz - sizeof(d->args));
d->fn = fn;
d->sp = (byte*)&arg0;
d->siz = siz;
mcpy(d->args, d->sp, d->siz);
d->link = g->defer;
g->defer = d;
}
void
sys·deferreturn(int32 arg0)
{
// warning: jmpdefer knows the frame size
// of this routine. dont change anything
// that might change the frame size
Defer *d;
byte *sp;
d = g->defer;
if(d == nil)
return;
sp = (byte*)&arg0;
if(d->sp != sp)
return;
mcpy(d->sp, d->args, d->siz);
g->defer = d->link;
jmpdefer(d->fn);
}
void void
tracebackothers(G *me) tracebackothers(G *me)
{ {
......
...@@ -120,7 +120,7 @@ TEXT setspgoto(SB), 7, $0 ...@@ -120,7 +120,7 @@ TEXT setspgoto(SB), 7, $0
// if(*val == old){ // if(*val == old){
// *val = new; // *val = new;
// return 1; // return 1;
// }else // } else
// return 0; // return 0;
TEXT cas(SB), 7, $0 TEXT cas(SB), 7, $0
MOVQ 8(SP), BX MOVQ 8(SP), BX
...@@ -133,3 +133,13 @@ TEXT cas(SB), 7, $0 ...@@ -133,3 +133,13 @@ TEXT cas(SB), 7, $0
RET RET
MOVL $1, AX MOVL $1, AX
RET RET
// void jmpdefer(byte*);
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
TEXT jmpdefer(SB), 7, $0
MOVQ 8(SP), AX // function
ADDQ $(8+56), SP // pop saved PC and callers frame
SUBQ $5, (SP) // reposition his return address
JMP AX // and goto function
...@@ -52,6 +52,7 @@ typedef struct SigTab SigTab; ...@@ -52,6 +52,7 @@ typedef struct SigTab SigTab;
typedef struct MCache MCache; typedef struct MCache MCache;
typedef struct Iface Iface; typedef struct Iface Iface;
typedef struct Itype Itype; typedef struct Itype Itype;
typedef struct Defer Defer;
/* /*
* per cpu declaration * per cpu declaration
...@@ -128,6 +129,7 @@ struct G ...@@ -128,6 +129,7 @@ struct G
{ {
byte* stackguard; // must not move byte* stackguard; // must not move
byte* stackbase; // must not move byte* stackbase; // must not move
Defer* defer; // must not move
byte* stack0; // first stack segment byte* stack0; // first stack segment
Gobuf sched; Gobuf sched;
G* alllink; // on allg G* alllink; // on allg
...@@ -235,6 +237,18 @@ enum ...@@ -235,6 +237,18 @@ enum
Amax Amax
}; };
/*
* defered subroutine calls
*/
struct Defer
{
int32 siz;
byte* sp;
byte* fn;
Defer* link;
byte args[8]; // padded to actual size
};
/* /*
* external data * external data
*/ */
...@@ -286,6 +300,7 @@ int32 write(int32, void*, int32); ...@@ -286,6 +300,7 @@ int32 write(int32, void*, int32);
void close(int32); void close(int32);
int32 fstat(int32, void*); int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32); bool cas(uint32*, uint32, uint32);
void jmpdefer(byte*);
void exit1(int32); void exit1(int32);
void ready(G*); void ready(G*);
byte* getenv(int8*); byte* getenv(int8*);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment