summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-03 22:56:09 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-03 22:56:09 +0000
commitaa5ae5757ffe8a3efa80a966801a73f6e534f046 (patch)
treeba1dd2b0b5d5bd16e9bc5c7dce503f320e8a896a /libgo
parenta3f448f02f99dd76c2e2ce51fa04e2d58878d1ac (diff)
downloadgcc-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.go45
-rw-r--r--libgo/go/runtime/type.go3
-rw-r--r--libgo/runtime/go-type.h5
-rw-r--r--libgo/runtime/go-unsafe-pointer.c10
-rw-r--r--libgo/runtime/mgc0.c79
-rw-r--r--libgo/runtime/runtime.h2
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