diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-09-03 22:56:09 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-09-03 22:56:09 +0000 |
commit | aa5ae5757ffe8a3efa80a966801a73f6e534f046 (patch) | |
tree | ba1dd2b0b5d5bd16e9bc5c7dce503f320e8a896a /libgo | |
parent | a3f448f02f99dd76c2e2ce51fa04e2d58878d1ac (diff) | |
download | gcc-aa5ae5757ffe8a3efa80a966801a73f6e534f046.tar.gz |
compiler: Add precise type information on the heap.
* go-gcc.cc (Gcc_backend::implicit_variable): Remove init
parameter. Add is_hidden parameter.
(Gcc_backend::implicit_variable_set_init): New method.
(Gcc_backend::implicit_variable_reference): New method.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@214894 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r-- | libgo/go/reflect/type.go | 45 | ||||
-rw-r--r-- | libgo/go/runtime/type.go | 3 | ||||
-rw-r--r-- | libgo/runtime/go-type.h | 5 | ||||
-rw-r--r-- | libgo/runtime/go-unsafe-pointer.c | 10 | ||||
-rw-r--r-- | libgo/runtime/mgc0.c | 79 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 2 |
6 files changed, 84 insertions, 60 deletions
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 74cf2946a01..91697c4b56b 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -255,6 +255,7 @@ type rtype struct { hashfn uintptr // hash function code equalfn uintptr // equality function code + gc unsafe.Pointer // garbage collection data string *string // string form; unnecessary but undeniably useful *uncommonType // (relatively) uncommon fields ptrToThis *rtype // type for pointer to this type, if used in binary or has methods @@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype { p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) p.elem = t + if t.kind&kindNoPointers != 0 { + p.gc = unsafe.Pointer(&ptrDataGCProg) + } else { + p.gc = unsafe.Pointer(&ptrGC{ + width: p.size, + op: _GC_PTR, + off: 0, + elemgc: t.gc, + end: _GC_END, + }) + } + q := canonicalize(&p.rtype) p = (*ptrType)(unsafe.Pointer(q.(*rtype))) @@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type { ch.ptrToThis = nil ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) + ch.gc = unsafe.Pointer(&chanGC{ + width: ch.size, + op: _GC_CHAN_PTR, + off: 0, + typ: &ch.rtype, + end: _GC_END, + }) + // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong. - //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END}) + // ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END}) return cachePut(ckey, &ch.rtype) } @@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type { // width: unsafe.Sizeof(uintptr(0)), // op: _GC_PTR, // off: 0, - // elemgc: mt.hmap.gc, + // elemgc: nil, // end: _GC_END, // }) + // TODO(cmang): Generate GC data for Map elements. + mt.gc = unsafe.Pointer(&ptrDataGCProg) + // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues // fail when mt.gc is wrong. //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END}) @@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype { // Take the GC program for "t" and append it to the GC program "gc". func appendGCProgram(gc []uintptr, t *rtype) []uintptr { - // p := t.gc - var p unsafe.Pointer + p := t.gc p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size loop: for { @@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type { slice.ptrToThis = nil slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) + if typ.size == 0 { + slice.gc = unsafe.Pointer(&sliceEmptyGCProg) + } else { + slice.gc = unsafe.Pointer(&sliceGC{ + width: slice.size, + op: _GC_SLICE, + off: 0, + elemgc: typ.gc, + end: _GC_END, + }) + } + // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong. - //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END}) + // slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END}) return cachePut(ckey, &slice.rtype) } diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go index 1211f222575..a5ed8af7a85 100644 --- a/libgo/go/runtime/type.go +++ b/libgo/go/runtime/type.go @@ -15,7 +15,7 @@ package runtime import "unsafe" type rtype struct { - Kind uint8 + kind uint8 align uint8 fieldAlign uint8 size uintptr @@ -24,6 +24,7 @@ type rtype struct { hashfn func(unsafe.Pointer, uintptr) uintptr equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool + gc unsafe.Pointer string *string *uncommonType ptrToThis *rtype diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h index 51c2355772d..74e83400598 100644 --- a/libgo/runtime/go-type.h +++ b/libgo/runtime/go-type.h @@ -59,7 +59,7 @@ struct String; #define GO_CODE_MASK 0x7f /* For each Go type the compiler constructs one of these structures. - This is used for type reflectin, interfaces, maps, and reference + This is used for type reflection, interfaces, maps, and reference counting. */ struct __go_type_descriptor @@ -93,6 +93,9 @@ struct __go_type_descriptor size of this type, and returns whether the values are equal. */ _Bool (*__equalfn) (const void *, const void *, uintptr_t); + /* The garbage collection data. */ + const uintptr *__gc; + /* A string describing this type. This is only used for debugging. */ const struct String *__reflection; diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c index b71804ac741..67b2999df5d 100644 --- a/libgo/runtime/go-unsafe-pointer.c +++ b/libgo/runtime/go-unsafe-pointer.c @@ -8,6 +8,7 @@ #include "runtime.h" #include "go-type.h" +#include "mgc0.h" /* A pointer with a zero value. */ static void *zero_pointer; @@ -20,6 +21,9 @@ static void *zero_pointer; extern const struct __go_type_descriptor unsafe_Pointer __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer"); +extern const uintptr unsafe_Pointer_gc[] + __asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc"); + /* Used to determine the field alignment. */ struct field_align { @@ -35,6 +39,8 @@ static const String reflection_string = sizeof REFLECTION - 1 }; +const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END}; + const struct __go_type_descriptor unsafe_Pointer = { /* __code */ @@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer = __go_type_hash_identity, /* __equalfn */ __go_type_equal_identity, + /* __gc */ + unsafe_Pointer_gc, /* __reflection */ &reflection_string, /* __uncommon */ @@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer = __go_type_hash_identity, /* __equalfn */ __go_type_equal_identity, + /* __gc */ + unsafe_Pointer_gc, /* __reflection */ &preflection_string, /* __uncommon */ diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 2d6328fbac3..6864a833dc4 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -181,7 +181,7 @@ struct Finalizer FuncVal *fn; void *arg; const struct __go_func_type *ft; - const struct __go_ptr_type *ot; + const PtrType *ot; }; typedef struct FinBlock FinBlock; @@ -403,8 +403,6 @@ struct BufferList }; static BufferList bufferList[MaxGcproc]; -static Type *itabtype; - static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj); // flushptrbuf moves data from the PtrTarget buffer to the work buffer. @@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf) // Program that scans the whole block and treats every block element as a potential pointer static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; -#if 0 // Hchan program static uintptr chanProg[2] = {0, GC_CHAN}; -#endif // Local variables of a program fragment or loop typedef struct Frame Frame; struct Frame { uintptr count, elemsize, b; - uintptr *loop_or_ret; + const uintptr *loop_or_ret; }; // Sanity check for the derived type info objti. static void checkptr(void *obj, uintptr objti) { - uintptr type, tisize, i, x; + uintptr *pc1, type, tisize, i, j, x; + const uintptr *pc2; byte *objstart; Type *t; MSpan *s; @@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti) (runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") && // Runtime and gc think differently about closures. runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) { -#if 0 pc1 = (uintptr*)objti; - pc2 = (uintptr*)t->gc; + pc2 = (const uintptr*)t->__gc; // A simple best-effort check until first GC_END. for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) { if(pc1[j] != pc2[j]) { @@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti) runtime_throw("invalid gc type info"); } } -#endif } } @@ -728,11 +723,10 @@ static void scanblock(Workbuf *wbuf, bool keepworking) { byte *b, *arena_start, *arena_used; - uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj; - uintptr *pc, precise_type, nominal_size; -#if 0 - uintptr *chan_ret, chancap; -#endif + uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj; + uintptr precise_type, nominal_size; + const uintptr *pc, *chan_ret; + uintptr chancap; void *obj; const Type *t, *et; Slice *sliceptr; @@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking) Scanbuf sbuf; Eface *eface; Iface *iface; -#if 0 Hchan *chan; - ChanType *chantype; -#endif + const ChanType *chantype; Obj *wp; if(sizeof(Workbuf) % WorkbufSize != 0) @@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking) sbuf.nobj = nobj; // (Silence the compiler) -#if 0 chan = nil; chantype = nil; chan_ret = nil; -#endif goto next_block; @@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking) runtime_xadd64(&gcstats.obj.cnt, 1); } - if(ti != 0 && false) { + if(ti != 0) { if(Debug > 1) { runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti); } @@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking) runtime_throw("invalid gc type info"); } } - } else if(UseSpanType && false) { + } else if(UseSpanType) { if(CollectStats) runtime_xadd64(&gcstats.obj.notype, 1); -#if 0 type = runtime_gettype(b); if(type != 0) { if(CollectStats) @@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking) t = (Type*)(type & ~(uintptr)(PtrSize-1)); switch(type & (PtrSize-1)) { case TypeInfo_SingleObject: - pc = (uintptr*)t->gc; + pc = (const uintptr*)t->__gc; precise_type = true; // type information about 'b' is precise stack_top.count = 1; stack_top.elemsize = pc[0]; break; case TypeInfo_Array: - pc = (uintptr*)t->gc; + pc = (const uintptr*)t->__gc; if(pc[0] == 0) goto next_block; precise_type = true; // type information about 'b' is precise @@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking) break; case TypeInfo_Chan: chan = (Hchan*)b; - chantype = (ChanType*)t; + chantype = (const ChanType*)t; chan_ret = nil; pc = chanProg; break; @@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking) if(Debug > 1) runtime_printf("scanblock %p %D unknown type\n", b, (int64)n); } -#endif } else { pc = defaultProg; if(Debug > 1) @@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking) // eface->__object if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) { - if(t->__size <= sizeof(void*)) { + if(__go_is_pointer_type(t)) { if((t->__code & KindNoPointers)) continue; @@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking) // dgcsym1 in case TPTR32/case TPTR64. See rationale there. et = ((const PtrType*)t)->elem; if(!(et->__code & KindNoPointers)) - // objti = (uintptr)((const PtrType*)t)->elem->gc; - objti = 0; + objti = (uintptr)((const PtrType*)t)->elem->__gc; } } else { obj = eface->__object; - // objti = (uintptr)t->gc; - objti = 0; + objti = (uintptr)t->__gc; } } break; @@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking) // iface->tab if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) { - *sbuf.ptr.pos++ = (PtrTarget){iface->tab, /* (uintptr)itabtype->gc */ 0}; + *sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0}; if(sbuf.ptr.pos == sbuf.ptr.end) flushptrbuf(&sbuf); } // iface->data if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) { - // t = iface->tab->type; - t = nil; - if(t->__size <= sizeof(void*)) { + t = (const Type*)iface->tab[0]; + if(__go_is_pointer_type(t)) { if((t->__code & KindNoPointers)) continue; @@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking) // dgcsym1 in case TPTR32/case TPTR64. See rationale there. et = ((const PtrType*)t)->elem; if(!(et->__code & KindNoPointers)) - // objti = (uintptr)((const PtrType*)t)->elem->gc; - objti = 0; + objti = (uintptr)((const PtrType*)t)->elem->__gc; } } else { obj = iface->__object; - // objti = (uintptr)t->gc; - objti = 0; + objti = (uintptr)t->__gc; } } break; @@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking) // Stack push. *stack_ptr-- = stack_top; stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/}; - pc = (uintptr*)((byte*)pc + *(int32*)(pc+2)); // target of the CALL instruction + pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction continue; case GC_REGION: @@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking) flushobjbuf(&sbuf); continue; -#if 0 case GC_CHAN_PTR: chan = *(Hchan**)(stack_top.b + pc[1]); if(Debug > 2 && chan != nil) @@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking) // in-use part of the circular buffer is scanned. // (Channel routines zero the unused part, so the current // code does not lead to leaks, it's just a little inefficient.) - *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size, - (uintptr)chantype->elem->gc | PRECISE | LOOP}; + *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size, + (uintptr)chantype->elem->__gc | PRECISE | LOOP}; if(sbuf.obj.pos == sbuf.obj.end) flushobjbuf(&sbuf); } @@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking) goto next_block; pc = chan_ret; continue; -#endif default: runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc); @@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s) } // State of background sweep. -// Pretected by gclock. +// Protected by gclock. static struct { G* g; @@ -2260,12 +2241,6 @@ gc(struct gc_args *args) work.markfor = runtime_parforalloc(MaxGcproc); m->locks--; - if(itabtype == nil) { - // get C pointer to the Go type "itab" - // runtime_gc_itab_ptr(&eface); - // itabtype = ((PtrType*)eface.__type_descriptor)->elem; - } - t1 = 0; if(runtime_debug.gctrace) t1 = runtime_nanotime(); diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 6650be1b3d3..c96290a0b06 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -800,7 +800,7 @@ uintptr runtime_memlimit(void); enum { - UseSpanType = 0, + UseSpanType = 1, }; #define runtime_setitimer setitimer |