aboutsummaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
authorCarl Shapiro <cshapiro@google.com>2013-05-28 17:59:10 -0700
committerCarl Shapiro <cshapiro@google.com>2013-05-28 17:59:10 -0700
commit4e0a51c210ededa82809756ca1cc72b1fb1def8d (patch)
tree73e39d7d22cc17088ea10bcd2bc0ce165b45ef0d /src/pkg
parent8bbb08533dab0dcf627db0b76ba65c3fb9b1d682 (diff)
downloadgo-4e0a51c210ededa82809756ca1cc72b1fb1def8d.tar.xz
cmd/5l, cmd/6l, cmd/8l, cmd/gc, runtime: generate and use bitmaps of argument pointer locations
With this change the compiler emits a bitmap for each function covering its stack frame arguments area. If an argument word is known to contain a pointer, a bit is set. The garbage collector reads this information when scanning the stack by frames and uses it to ignores locations known to not contain a pointer. R=golang-dev, bradfitz, daniel.morsing, dvyukov, khr, khr, iant, cshapiro CC=golang-dev https://golang.org/cl/9223046
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/runtime/extern.go7
-rw-r--r--src/pkg/runtime/mgc0.c42
-rw-r--r--src/pkg/runtime/runtime.h2
-rw-r--r--src/pkg/runtime/symtab.c21
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;