From 48769bf546ba7ad830c2edc05656e217d15a20c8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Jul 2013 16:04:09 -0400 Subject: runtime: use funcdata to supply garbage collection information This CL introduces a FUNCDATA number for runtime-specific garbage collection metadata, changes the C and Go compilers to emit that metadata, and changes the runtime to expect it. The old pseudo-instructions that carried this information are gone, as is the linker code to process them. R=golang-dev, dvyukov, cshapiro CC=golang-dev https://golang.org/cl/11406044 --- src/pkg/runtime/funcdata.h | 4 +++- src/pkg/runtime/mgc0.c | 36 ++++++++++++++++++++++++++++-------- src/pkg/runtime/runtime.h | 10 +++++----- src/pkg/runtime/symtab.c | 8 ++++---- src/pkg/runtime/traceback_arm.c | 27 ++++----------------------- src/pkg/runtime/traceback_x86.c | 22 ++-------------------- 6 files changed, 46 insertions(+), 61 deletions(-) (limited to 'src/pkg/runtime') diff --git a/src/pkg/runtime/funcdata.h b/src/pkg/runtime/funcdata.h index 850288bf64..f12bf49fb1 100644 --- a/src/pkg/runtime/funcdata.h +++ b/src/pkg/runtime/funcdata.h @@ -7,7 +7,9 @@ // be written using #defines. It is included by the runtime package // as well as the compilers. -#define PCDATA_ArgSize 0 +#define PCDATA_ArgSize 0 /* argument size at CALL instruction */ + +#define FUNCDATA_GC 0 /* garbage collector block */ // To be used in assembly. #define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index abf93e425b..8654e38544 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -13,6 +13,7 @@ #include "type.h" #include "typekind.h" #include "hashmap.h" +#include "funcdata.h" enum { Debug = 0, @@ -1385,6 +1386,14 @@ addroot(Obj obj) extern byte pclntab[]; // base for f->ptrsoff +typedef struct GCFunc GCFunc; +struct GCFunc +{ + uint32 locals; // size of local variables in bytes + uint32 nptrs; // number of words that follow + uint32 ptrs[1]; // bitmap of pointers in arguments +}; + // Scan a stack frame: local variables and function arguments/results. static void addframeroots(Stkframe *frame, void*) @@ -1392,21 +1401,28 @@ addframeroots(Stkframe *frame, void*) Func *f; byte *ap; int32 i, j, nuintptr; - uint32 w, b, *ptrs; + uint32 w, b; + GCFunc *gcf; + f = frame->fn; + gcf = runtime·funcdata(f, FUNCDATA_GC); + // Scan local variables if stack frame has been allocated. - if(frame->varlen > 0) - addroot((Obj){frame->varp, frame->varlen, 0}); + i = frame->varp - (byte*)frame->sp; + if(i > 0) { + if(gcf == nil) + addroot((Obj){frame->varp - i, i, 0}); + else if(i >= gcf->locals) + addroot((Obj){frame->varp - gcf->locals, gcf->locals, 0}); + } // Scan arguments. // Use pointer information if known. - f = frame->fn; - if(f->args > 0 && f->ptrslen > 0) { + if(f->args > 0 && gcf != nil && gcf->nptrs > 0) { ap = frame->argp; nuintptr = f->args / sizeof(uintptr); - ptrs = (uint32*)(pclntab + f->ptrsoff); - for(i = 0; i < f->ptrslen; i++) { - w = ptrs[i]; + for(i = 0; i < gcf->nptrs; i++) { + w = gcf->ptrs[i]; b = 1; j = nuintptr; if(j > 32) @@ -2017,8 +2033,10 @@ runtime·gc(int32 force) // all done m->gcing = 0; + m->locks++; runtime·semrelease(&runtime·worldsema); runtime·starttheworld(); + m->locks--; // now that gc is done and we're back on g stack, kick off finalizer thread if needed if(finq != nil) { @@ -2185,8 +2203,10 @@ runtime·ReadMemStats(MStats *stats) updatememstats(nil); *stats = mstats; m->gcing = 0; + m->locks++; runtime·semrelease(&runtime·worldsema); runtime·starttheworld(); + m->locks--; } void diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 811ec76653..f405287aa8 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -407,10 +407,10 @@ struct Func // TODO: Remove these fields. int32 args; // in/out args size - int32 locals; // locals size + int32 x1; // locals size int32 frame; // legacy frame size; use pcsp if possible - int32 ptrsoff; - int32 ptrslen; + int32 x2; + int32 x3; int32 pcsp; int32 pcfile; @@ -677,10 +677,9 @@ struct Stkframe uintptr lr; // program counter at caller aka link register uintptr sp; // stack pointer at pc uintptr fp; // stack pointer at caller aka frame pointer + byte* varp; // top of local variables byte* argp; // pointer to function arguments uintptr arglen; // number of bytes at argp - byte* varp; // pointer to local variables - uintptr varlen; // number of bytes at varp }; int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool); @@ -856,6 +855,7 @@ void runtime·netpollready(G**, PollDesc*, int32); void runtime·crash(void); void runtime·parsedebugvars(void); void _rt0_go(void); +void* runtime·funcdata(Func*, int32); #pragma varargck argpos runtime·printf 1 #pragma varargck type "c" int32 diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c index e877a60cd9..053e255079 100644 --- a/src/pkg/runtime/symtab.c +++ b/src/pkg/runtime/symtab.c @@ -78,17 +78,17 @@ readvarint(byte **pp) return v; } -static uintptr -funcdata(Func *f, int32 i) +void* +runtime·funcdata(Func *f, int32 i) { byte *p; if(i < 0 || i >= f->nfuncdata) - return 0; + return nil; p = (byte*)&f->nfuncdata + 4 + f->npcdata*4; if(sizeof(void*) == 8 && ((uintptr)p & 4)) p += 4; - return ((uintptr*)p)[i]; + return ((void**)p)[i]; } static bool diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c index 5aea699e34..563ba28c94 100644 --- a/src/pkg/runtime/traceback_arm.c +++ b/src/pkg/runtime/traceback_arm.c @@ -95,7 +95,9 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, runtime·throw("unknown caller pc"); } } - + + frame.varp = (byte*)frame.fp; + // Derive size of arguments. // Most functions have a fixed-size argument block, // so we can use metadata about the function f. @@ -121,27 +123,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, } } - // Derive location and size of local variables. - if(frame.fp == frame.sp) { - // Function has not created a frame for itself yet. - frame.varp = nil; - frame.varlen = 0; - } else if(f->locals == 0) { - // Assume no information, so use whole frame. - // TODO: Distinguish local==0 from local==unknown. - frame.varp = (byte*)frame.sp; - frame.varlen = frame.fp - frame.sp; - } else { - if(f->locals > frame.fp - frame.sp) { - runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f)); - if(callback != nil) - runtime·throw("invalid stack"); - } - frame.varp = (byte*)frame.fp - f->locals; - frame.varlen = f->locals; - } - - if(skip > 0) { skip--; goto skipped; @@ -203,7 +184,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, frame.fn = f = runtime·findfunc(frame.pc); if(f == nil) frame.pc = x; - else if (f->frame == 0) + else if(f->frame == 0) frame.lr = x; } } diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c index 3153103d34..b88797210e 100644 --- a/src/pkg/runtime/traceback_x86.c +++ b/src/pkg/runtime/traceback_x86.c @@ -111,6 +111,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, runtime·throw("unknown caller pc"); } } + + frame.varp = (byte*)frame.fp - sizeof(uintptr); // Derive size of arguments. // Most functions have a fixed-size argument block, @@ -137,26 +139,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, } } - // Derive location and size of local variables. - if(frame.fp == frame.sp + sizeof(uintptr)) { - // Function has not created a frame for itself yet. - frame.varp = nil; - frame.varlen = 0; - } else if(f->locals == 0) { - // Assume no information, so use whole frame. - // TODO: Distinguish local==0 from local==unknown. - frame.varp = (byte*)frame.sp; - frame.varlen = frame.fp - sizeof(uintptr) - frame.sp; - } else { - if(f->locals > frame.fp - sizeof(uintptr) - frame.sp) { - runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f)); - if(callback != nil) - runtime·throw("invalid stack"); - } - frame.varp = (byte*)frame.fp - sizeof(uintptr) - f->locals; - frame.varlen = f->locals; - } - if(skip > 0) { skip--; goto skipped; -- cgit v1.3