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) {
throwindex = nod(ONAME, N, N);
throwindex->sym = pkglookup("throwindex", "sys");
}
}
+ hasdefer = 0;
walk(curfn);
if(nerrors != 0)
goto ret;
gins(ACALL, N, throwreturn);
}
+ if(hasdefer)
+ gins(ACALL, N, deferreturn);
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
break;
case OPROC:
- cgen_proc(n);
+ cgen_proc(n, 1);
+ break;
+
+ case ODEFER:
+ cgen_proc(n, 2);
break;
case ORETURN:
/*
* generate:
* call f
- * if proc, generate:
- * push f
- * push argsize
- * call newproc
- * pop
- * pop
+ * proc=0 normal call
+ * proc=1 goroutine run in new proc
+ * proc=2 defer call save away stack
*/
void
ginscall(Node *f, int proc)
{
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(®, types[TINT64], D_AX);
if(f->op != OREGISTER) {
gins(ALEAQ, f, ®);
gins(APUSHQ, f, N);
nodconst(&con, types[TINT32], argsize(f->type));
gins(APUSHQ, &con, N);
- gins(ACALL, N, newproc);
+ if(proc == 1)
+ gins(ACALL, N, newproc);
+ else
+ gins(ACALL, N, deferproc);
gins(APOPQ, N, ®);
gins(APOPQ, N, ®);
- return;
+ break;
}
- gins(ACALL, N, f);
}
/*
/*
* 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
cgen_callmeth(Node *n, int proc)
/*
* 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
cgen_call(Node *n, int proc)
* generate code to start new proc running call n.
*/
void
-cgen_proc(Node *n)
+cgen_proc(Node *n, int proc)
{
switch(n->left->op) {
default:
fatal("cgen_proc: unknown call %O", n->left->op);
case OCALLMETH:
- cgen_callmeth(n->left, 1);
+ cgen_callmeth(n->left, proc);
break;
case OCALLINTER:
- cgen_callinter(n->left, N, 1);
+ cgen_callinter(n->left, N, proc);
break;
case OCALL:
- cgen_call(n->left, 1);
+ cgen_call(n->left, proc);
break;
}
cgen_ret(Node *n)
{
gen(n->left, L); // copy out args
+ if(hasdefer)
+ gins(ACALL, N, deferreturn);
gins(ARET, N, N);
}
EXTERN Label* findlab(Sym*);
EXTERN Node* curfn;
EXTERN Node* newproc;
+EXTERN Node* deferproc;
+EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwreturn;
void cgen_call(Node*, int);
void cgen_callmeth(Node*, int);
void cgen_callinter(Node*, Node*, int);
-void cgen_proc(Node*);
+void cgen_proc(Node*, int);
void cgen_callret(Node*, Node*);
void cgen_div(int, Node*, Node*, Node*);
void cgen_bmul(int, Node*, Node*, Node*);
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODCLFUNC, ODCLFIELD, ODCLARG,
OLIST, OCMP, OPTR, OARRAY, ORANGE,
- ORETURN, OFOR, OIF, OSWITCH,
+ ORETURN, OFOR, OIF, OSWITCH, ODEFER,
OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
OGOTO, OPROC, OMAKE, ONEW, OEMPTY, OSELECT,
OLEN, OCAP, OPANIC, OPANICN, OPRINT, OPRINTN, OTYPEOF,
EXTERN int32 initstksize; // stack size for init function
EXTERN ushort blockgen; // max block number
EXTERN ushort block; // current block number
+EXTERN int hasdefer; // flag that curfn has defer statetment
EXTERN Node* retnil;
EXTERN Node* fskel;
%token <val> LLITERAL
%token <lint> LASOP
%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> LCOLAS LFALL LRETURN LDDD
%token <sym> LLEN LCAP LTYPEOF LPANIC LPANICN LPRINT LPRINTN
$$ = nod(OCALL, $2, $4);
$$ = nod(OPROC, $$, N);
}
+| LDEFER pexpr '(' oexpr_list ')'
+ {
+ $$ = nod(OCALL, $2, $4);
+ $$ = nod(ODEFER, $$, N);
+ }
| LGOTO new_name
{
$$ = nod(OGOTO, $2, N);
"continue", LCONTINUE, Txxx,
"default", LDEFAULT, Txxx,
"else", LELSE, Txxx,
- "export", LEXPORT, Txxx,
+ "defer", LDEFER, Txxx,
"fallthrough", LFALL, Txxx,
"false", LFALSE, Txxx,
"for", LFOR, Txxx,
LPRINT, "PRINT",
LPACKAGE, "PACKAGE",
LIMPORT, "IMPORT",
- LEXPORT, "EXPORT",
+ LDEFER, "DEFER",
LPANIC, "PANIC",
};
[ODCLARG] = "DCLARG",
[ODCLFIELD] = "DCLFIELD",
[ODCLFUNC] = "DCLFUNC",
+ [ODEFER] = "DEFER",
[ODIV] = "DIV",
- [ODOT] = "DOT",
- [ODOTPTR] = "DOTPTR",
- [ODOTMETH] = "DOTMETH",
[ODOTINTER] = "DOTINTER",
+ [ODOTMETH] = "DOTMETH",
+ [ODOTPTR] = "DOTPTR",
+ [ODOT] = "DOT",
[OEMPTY] = "EMPTY",
[OEND] = "END",
[OEQ] = "EQ",
case OXFALL:
case ORETURN:
case OPROC:
+ case ODEFER:
walktype(n, Etop);
break;
}
walkstate(n->nelse);
goto ret;
+ case ODEFER:
+ hasdefer = 1;
case OPROC:
if(top != Etop)
goto nottop;
if((newg = gfget()) != nil){
newg->status = Gwaiting;
- }else{
+ } else {
newg = malg(4096);
newg->status = Gwaiting;
newg->alllink = allg;
//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
tracebackothers(G *me)
{
// if(*val == old){
// *val = new;
// return 1;
-// }else
+// } else
// return 0;
TEXT cas(SB), 7, $0
MOVQ 8(SP), BX
RET
MOVL $1, AX
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
typedef struct MCache MCache;
typedef struct Iface Iface;
typedef struct Itype Itype;
+typedef struct Defer Defer;
/*
* per cpu declaration
{
byte* stackguard; // must not move
byte* stackbase; // must not move
+ Defer* defer; // must not move
byte* stack0; // first stack segment
Gobuf sched;
G* alllink; // on allg
int32 goid;
int32 selgen; // valid sudog pointer
G* schedlink;
- bool readyonstop;
- M* m; // for debuggers
+ bool readyonstop;
+ M* m; // for debuggers
};
struct Mem
{
G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move
uint64 cret; // return value from C - must not move
- uint64 procid; // for debuggers - must not move
- G* gsignal; // signal-handling G - must not move
+ uint64 procid; // for debuggers - must not move
+ G* gsignal; // signal-handling G - must not move
G* curg; // current running goroutine
G* lastg; // last running goroutine - to emulate fifo
Gobuf sched;
Amax
};
+/*
+ * defered subroutine calls
+ */
+struct Defer
+{
+ int32 siz;
+ byte* sp;
+ byte* fn;
+ Defer* link;
+ byte args[8]; // padded to actual size
+};
+
/*
* external data
*/
void close(int32);
int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32);
+void jmpdefer(byte*);
void exit1(int32);
void ready(G*);
byte* getenv(int8*);