diff options
Diffstat (limited to 'src/pkg/runtime')
| -rw-r--r-- | src/pkg/runtime/extern.go | 7 | ||||
| -rw-r--r-- | src/pkg/runtime/mgc0.c | 42 | ||||
| -rw-r--r-- | src/pkg/runtime/runtime.h | 2 | ||||
| -rw-r--r-- | src/pkg/runtime/symtab.c | 21 |
4 files changed, 60 insertions, 12 deletions
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go index 20f2342530..7c5eb5317b 100644 --- a/src/pkg/runtime/extern.go +++ b/src/pkg/runtime/extern.go @@ -85,9 +85,10 @@ type Func struct { // Keep in sync with runtime.h:struct Func entry uintptr // entry pc pc0 uintptr // starting pc, ln for table ln0 int32 - frame int32 // stack frame size - args int32 // in/out args size - locals int32 // locals size + frame int32 // stack frame size + args int32 // in/out args size + locals int32 // locals size + ptrs []int32 // pointer map } // FuncForPC returns a *Func describing the function that contains the diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 9ea45d48c6..2dbb5868cc 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -1391,25 +1391,53 @@ addroot(Obj obj) work.nroot++; } -// Scan a stack frame. The doframe parameter is a signal that the previously -// scanned activation has an unknown argument size. When *doframe is true the -// current activation must have its entire frame scanned. Otherwise, only the -// locals need to be scanned. +// Scan a stack frame. Normally, this scans the locals area, +// belonging to the current frame, and the arguments area, belonging +// to the calling frame. When the arguments area size is unknown, the +// arguments area scanning is delayed and the doframe parameter +// signals that the previously scanned activation has an unknown +// argument size. When *doframe is true, the possible arguments area +// for the callee, located between the stack pointer and the bottom of +// the locals area, is additionally scanned. Otherwise, this area is +// ignored, as it must have been scanned when the callee was scanned. static void addframeroots(Func *f, byte*, byte *sp, void *doframe) { + byte *fp, *ap; uintptr outs; + int32 i, j, rem; + uint32 w, b; if(thechar == '5') sp += sizeof(uintptr); + fp = sp + f->frame; if(f->locals == 0 || *(bool*)doframe == true) + // Scan the entire stack frame. addroot((Obj){sp, f->frame - sizeof(uintptr), 0}); else if(f->locals > 0) { + // Scan the locals area. outs = f->frame - sizeof(uintptr) - f->locals; addroot((Obj){sp + outs, f->locals, 0}); } - if(f->args > 0) - addroot((Obj){sp + f->frame, f->args, 0}); + if(f->args > 0) { + // Scan the arguments area. + if(f->ptrs.array != nil) { + ap = fp; + rem = f->args / sizeof(uintptr); + for(i = 0; i < f->ptrs.len; i++) { + w = ((uint32*)f->ptrs.array)[i]; + b = 1; + for((j = (rem < 32) ? rem : 32); j > 0; j--) { + if(w & b) + addroot((Obj){ap, sizeof(uintptr), 0}); + b <<= 1; + ap += sizeof(uintptr); + } + rem -= 32; + } + } else + addroot((Obj){fp, f->args, 0}); + } *(bool*)doframe = (f->args == ArgsSizeUnknown); } @@ -1469,7 +1497,7 @@ addstackroots(G *gp) return; } } - if (ScanStackByFrames) { + if(ScanStackByFrames) { USED(stk); USED(guard); doframe = false; diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 44cc0138c0..c7ade2beb5 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -412,6 +412,7 @@ struct Func int32 frame; // stack frame size int32 args; // in/out args size int32 locals; // locals size + Slice ptrs; // pointer map }; // layout of Itab known to compilers @@ -811,6 +812,7 @@ void runtime·netpollready(G**, PollDesc*, int32); void runtime·crash(void); #pragma varargck argpos runtime·printf 1 +#pragma varargck type "c" int32 #pragma varargck type "d" int32 #pragma varargck type "d" uint32 #pragma varargck type "D" int64 diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c index 597fa49b7c..be06d578d4 100644 --- a/src/pkg/runtime/symtab.c +++ b/src/pkg/runtime/symtab.c @@ -199,6 +199,7 @@ static void dofunc(Sym *sym) { Func *f; + uintgo cap; switch(sym->symtype) { case 't': @@ -231,8 +232,24 @@ dofunc(Sym *sym) func[nfunc-1].locals = sym->value; else if(runtime·strcmp(sym->name, (byte*)".args") == 0) func[nfunc-1].args = sym->value; - else { - runtime·printf("invalid 'm' symbol named '%s'\n", sym->name); + else if(runtime·strcmp(sym->name, (byte*)".nptrs") == 0) { + // TODO(cshapiro): use a dense representation for gc information + if(sym->value > func[nfunc-1].args/sizeof(uintptr)) { + runtime·printf("more pointer map entries than argument words\n"); + runtime·throw("mangled symbol table"); + } + cap = ROUND(sym->value, 32) / 32; + func[nfunc-1].ptrs.array = runtime·mallocgc(cap*sizeof(uint32), FlagNoPointers|FlagNoGC, 0, 1); + func[nfunc-1].ptrs.len = 0; + func[nfunc-1].ptrs.cap = cap; + } else if(runtime·strcmp(sym->name, (byte*)".ptrs") == 0) { + if(func[nfunc-1].ptrs.len >= func[nfunc-1].ptrs.cap) { + runtime·printf("more pointer map entries read than argument words\n"); + runtime·throw("mangled symbol table"); + } + ((uint32*)func[nfunc-1].ptrs.array)[func[nfunc-1].ptrs.len++] = sym->value; + } else { + runtime·printf("invalid '%c' symbol named '%s'\n", (int8)sym->symtype, sym->name); runtime·throw("mangled symbol table"); } break; |
