1
0
mirror of https://github.com/golang/go synced 2024-11-26 03:57:57 -07:00
R=r
OCL=23592
CL=23592
This commit is contained in:
Ken Thompson 2009-01-27 12:03:53 -08:00
parent 4a903e0b32
commit 1e1cc4eb57
10 changed files with 141 additions and 30 deletions

View File

@ -26,6 +26,22 @@ if(newproc == N) {
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");
@ -63,6 +79,7 @@ if(throwreturn == N) {
}
}
hasdefer = 0;
walk(curfn);
if(nerrors != 0)
goto ret;
@ -90,6 +107,8 @@ if(throwreturn == N) {
gins(ACALL, N, throwreturn);
}
if(hasdefer)
gins(ACALL, N, deferreturn);
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
@ -343,7 +362,11 @@ loop:
break;
case OPROC:
cgen_proc(n);
cgen_proc(n, 1);
break;
case ODEFER:
cgen_proc(n, 2);
break;
case ORETURN:
@ -683,19 +706,26 @@ argsize(Type *t)
/*
* 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(&reg, types[TINT64], D_AX);
if(f->op != OREGISTER) {
gins(ALEAQ, f, &reg);
@ -704,12 +734,14 @@ ginscall(Node *f, int proc)
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, &reg);
gins(APOPQ, N, &reg);
return;
break;
}
gins(ACALL, N, f);
}
/*
@ -767,6 +799,9 @@ cgen_callinter(Node *n, Node *res, int proc)
/*
* 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)
@ -791,7 +826,9 @@ 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)
@ -851,22 +888,22 @@ ret:
* 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;
}
@ -947,6 +984,8 @@ void
cgen_ret(Node *n)
{
gen(n->left, L); // copy out args
if(hasdefer)
gins(ACALL, N, deferreturn);
gins(ARET, N, N);
}

View File

@ -116,6 +116,8 @@ EXTERN Label* labellist;
EXTERN Label* findlab(Sym*);
EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwreturn;
@ -151,7 +153,7 @@ void cgen_ret(Node*);
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*);

View File

@ -291,7 +291,7 @@ enum
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,
@ -498,6 +498,7 @@ EXTERN int32 stksize; // stack size for current frame
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;

View File

@ -15,7 +15,7 @@
%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
@ -504,6 +504,11 @@ semi_stmt:
$$ = 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);

View File

@ -1056,7 +1056,7 @@ static struct
"continue", LCONTINUE, Txxx,
"default", LDEFAULT, Txxx,
"else", LELSE, Txxx,
"export", LEXPORT, Txxx,
"defer", LDEFER, Txxx,
"fallthrough", LFALL, Txxx,
"false", LFALSE, Txxx,
"for", LFOR, Txxx,
@ -1275,7 +1275,7 @@ struct
LPRINT, "PRINT",
LPACKAGE, "PACKAGE",
LIMPORT, "IMPORT",
LEXPORT, "EXPORT",
LDEFER, "DEFER",
LPANIC, "PANIC",
};

View File

@ -641,11 +641,12 @@ opnames[] =
[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",

View File

@ -145,6 +145,7 @@ loop:
case OXFALL:
case ORETURN:
case OPROC:
case ODEFER:
walktype(n, Etop);
break;
}
@ -342,6 +343,8 @@ loop:
walkstate(n->nelse);
goto ret;
case ODEFER:
hasdefer = 1;
case OPROC:
if(top != Etop)
goto nottop;

View File

@ -171,7 +171,7 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
if((newg = gfget()) != nil){
newg->status = Gwaiting;
}else{
} else {
newg = malg(4096);
newg->status = Gwaiting;
newg->alllink = allg;
@ -204,6 +204,41 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
//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)
{

View File

@ -120,7 +120,7 @@ TEXT setspgoto(SB), 7, $0
// if(*val == old){
// *val = new;
// return 1;
// }else
// } else
// return 0;
TEXT cas(SB), 7, $0
MOVQ 8(SP), BX
@ -133,3 +133,13 @@ TEXT cas(SB), 7, $0
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

View File

@ -52,6 +52,7 @@ typedef struct SigTab SigTab;
typedef struct MCache MCache;
typedef struct Iface Iface;
typedef struct Itype Itype;
typedef struct Defer Defer;
/*
* per cpu declaration
@ -128,6 +129,7 @@ struct G
{
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
@ -136,8 +138,8 @@ struct G
int32 goid;
int32 selgen; // valid sudog pointer
G* schedlink;
bool readyonstop;
M* m; // for debuggers
bool readyonstop;
M* m; // for debuggers
};
struct Mem
{
@ -151,8 +153,8 @@ struct M
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;
@ -235,6 +237,18 @@ enum
Amax
};
/*
* defered subroutine calls
*/
struct Defer
{
int32 siz;
byte* sp;
byte* fn;
Defer* link;
byte args[8]; // padded to actual size
};
/*
* external data
*/
@ -286,6 +300,7 @@ int32 write(int32, void*, int32);
void close(int32);
int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32);
void jmpdefer(byte*);
void exit1(int32);
void ready(G*);
byte* getenv(int8*);