compiler, runtime, reflect: make type descriptors more like Go 1.8
Change the type descriptor structure to be more like the one in the Go
1.8 runtime. Specifically we add the ptrdata field, rename the gc
field to gcdata and change the type to *byte, and rearrange a few of
the fields. The structure is still not identical to the Go 1.8
structure--we don't use any of the tricks to reduce overall executable
size--but it is more similar.
For now we don't use the new ptrdata field, and the gcdata field is
still the old format rather than the new Go 1.8 ptrmask/gcprog format.
Change-Id: I809bbd182db6cdd94983d01a4d94ce946f98d633
Reviewed-on: https://go-review.googlesource.com/41081
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/go/expressions.cc b/go/expressions.cc
index 2953b3d..b930ec2 100644
--- a/go/expressions.cc
+++ b/go/expressions.cc
@@ -14572,7 +14572,7 @@
protected:
Type*
do_type()
- { return Type::lookup_integer_type("uintptr"); }
+ { return Type::make_pointer_type(Type::lookup_integer_type("uint8")); }
bool
do_is_static_initializer() const
diff --git a/go/types.cc b/go/types.cc
index a48ea30..aa43df3 100644
--- a/go/types.cc
+++ b/go/types.cc
@@ -1482,6 +1482,7 @@
Location bloc = Linemap::predeclared_location();
Type* uint8_type = Type::lookup_integer_type("uint8");
+ Type* pointer_uint8_type = Type::make_pointer_type(uint8_type);
Type* uint32_type = Type::lookup_integer_type("uint32");
Type* uintptr_type = Type::lookup_integer_type("uintptr");
Type* string_type = Type::lookup_string_type();
@@ -1548,15 +1549,16 @@
// The type descriptor type.
Struct_type* type_descriptor_type =
- Type::make_builtin_struct_type(11,
+ Type::make_builtin_struct_type(12,
+ "size", uintptr_type,
+ "ptrdata", uintptr_type,
+ "hash", uint32_type,
"kind", uint8_type,
"align", uint8_type,
"fieldAlign", uint8_type,
- "size", uintptr_type,
- "hash", uint32_type,
"hashfn", hash_fntype,
"equalfn", equal_fntype,
- "gc", uintptr_type,
+ "gcdata", pointer_uint8_type,
"string", pointer_string_type,
"", pointer_uncommon_type,
"ptrToThis",
@@ -2312,30 +2314,25 @@
const Struct_field_list* fields = td_type->struct_type()->fields();
Expression_list* vals = new Expression_list();
- vals->reserve(9);
+ vals->reserve(12);
if (!this->has_pointer())
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
if (this->points_to() != NULL)
runtime_type_kind |= RUNTIME_TYPE_KIND_DIRECT_IFACE;
+ int64_t ptrsize;
+ int64_t ptrdata;
+ if (this->needs_gcprog(gogo, &ptrsize, &ptrdata))
+ runtime_type_kind |= RUNTIME_TYPE_KIND_GC_PROG;
+
Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("kind"));
- vals->push_back(Expression::make_integer_ul(runtime_type_kind, p->type(),
- bloc));
-
- ++p;
- go_assert(p->is_field_name("align"));
- Expression::Type_info type_info = Expression::TYPE_INFO_ALIGNMENT;
- vals->push_back(Expression::make_type_info(this, type_info));
-
- ++p;
- go_assert(p->is_field_name("fieldAlign"));
- type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT;
- vals->push_back(Expression::make_type_info(this, type_info));
-
- ++p;
go_assert(p->is_field_name("size"));
- type_info = Expression::TYPE_INFO_SIZE;
+ Expression::Type_info type_info = Expression::TYPE_INFO_SIZE;
+ vals->push_back(Expression::make_type_info(this, type_info));
+
+ ++p;
+ go_assert(p->is_field_name("ptrdata"));
+ type_info = Expression::TYPE_INFO_DESCRIPTOR_PTRDATA;
vals->push_back(Expression::make_type_info(this, type_info));
++p;
@@ -2348,6 +2345,21 @@
vals->push_back(Expression::make_integer_ul(h, p->type(), bloc));
++p;
+ go_assert(p->is_field_name("kind"));
+ vals->push_back(Expression::make_integer_ul(runtime_type_kind, p->type(),
+ bloc));
+
+ ++p;
+ go_assert(p->is_field_name("align"));
+ type_info = Expression::TYPE_INFO_ALIGNMENT;
+ vals->push_back(Expression::make_type_info(this, type_info));
+
+ ++p;
+ go_assert(p->is_field_name("fieldAlign"));
+ type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT;
+ vals->push_back(Expression::make_type_info(this, type_info));
+
+ ++p;
go_assert(p->is_field_name("hashfn"));
Function_type* hash_fntype = p->type()->function_type();
@@ -2373,7 +2385,7 @@
vals->push_back(Expression::make_func_reference(equal_fn, NULL, bloc));
++p;
- go_assert(p->is_field_name("gc"));
+ go_assert(p->is_field_name("gcdata"));
vals->push_back(Expression::make_gc_symbol(this));
++p;
@@ -2442,7 +2454,10 @@
gogo->backend()->var_expression(t->gc_symbol_var_, VE_rvalue, bloc);
Bexpression* addr_expr =
gogo->backend()->address_expression(var_expr, bloc);
- Btype* ubtype = Type::lookup_integer_type("uintptr")->get_backend(gogo);
+
+ Type* uint8_type = Type::lookup_integer_type("uint8");
+ Type* pointer_uint8_type = Type::make_pointer_type(uint8_type);
+ Btype* ubtype = pointer_uint8_type->get_backend(gogo);
return gogo->backend()->convert_expression(ubtype, addr_expr, bloc);
}
@@ -2578,6 +2593,22 @@
return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
}
+// A temporary function to convert a GC_symbol_expression, with type
+// *byte, to type uintptr, so that it can be stored in a GC symbol.
+// This will be discarded when we move to the Go 1.8 garbage
+// collector.
+
+static Expression*
+to_uintptr(Expression* expr)
+{
+ go_assert(expr->type()->points_to() != NULL);
+ Location loc = expr->location();
+ expr = Expression::make_cast(Type::make_pointer_type(Type::make_void_type()),
+ expr, loc);
+ return Expression::make_cast(Type::lookup_integer_type("uintptr"), expr,
+ loc);
+}
+
// Advance the OFFSET of the GC symbol by this type's width.
void
@@ -5555,7 +5586,7 @@
(*vals)->push_back(*offset);
if (this->to_type_->has_pointer())
- (*vals)->push_back(Expression::make_gc_symbol(this->to_type_));
+ (*vals)->push_back(to_uintptr(Expression::make_gc_symbol(this->to_type_)));
this->advance_gc_offset(offset);
}
@@ -8002,7 +8033,7 @@
(*vals)->push_back(*offset);
if (element_size != 0 && ok)
- (*vals)->push_back(Expression::make_gc_symbol(element_type));
+ (*vals)->push_back(to_uintptr(Expression::make_gc_symbol(element_type)));
this->advance_gc_offset(offset);
}
@@ -8075,7 +8106,7 @@
Expression* width =
Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
(*vals)->push_back(width);
- (*vals)->push_back(Expression::make_gc_symbol(this));
+ (*vals)->push_back(to_uintptr(Expression::make_gc_symbol(this)));
}
this->advance_gc_offset(offset);
}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 0325260..00349ba 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -259,20 +259,21 @@
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct {
- kind uint8 // enumeration for C
- align int8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- _ uint8 // unused/padding
size uintptr
- hash uint32 // hash of type; avoids computation in hash tables
+ ptrdata uintptr // size of memory prefix holding all pointers
+ hash uint32 // hash of type; avoids computation in hash tables
+ kind uint8 // enumeration for C
+ align int8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ _ uint8 // unused/padding
hashfn func(unsafe.Pointer, uintptr) uintptr // hash function
equalfn func(unsafe.Pointer, unsafe.Pointer) bool // equality function
- 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
+ gcdata *byte // 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
}
// Method on non-interface type
@@ -1190,15 +1191,15 @@
pp.elem = t
if t.kind&kindNoPointers != 0 {
- pp.gc = unsafe.Pointer(&ptrDataGCProg)
+ pp.gcdata = (*byte)(unsafe.Pointer(&ptrDataGCProg))
} else {
- pp.gc = unsafe.Pointer(&ptrGC{
+ pp.gcdata = (*byte)(unsafe.Pointer(&ptrGC{
width: pp.size,
op: _GC_PTR,
off: 0,
- elemgc: t.gc,
+ elemgc: unsafe.Pointer(t.gcdata),
end: _GC_END,
- })
+ }))
}
q := canonicalize(&pp.rtype)
@@ -1584,16 +1585,16 @@
ch.uncommonType = nil
ch.ptrToThis = nil
- ch.gc = unsafe.Pointer(&chanGC{
+ ch.gcdata = (*byte)(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})
+ // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gcdata is wrong.
+ // ch.gcdata = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
return cachePut(ckey, &ch.rtype)
}
@@ -1734,7 +1735,7 @@
ft.ptrToThis = nil
// TODO(cmang): Generate GC data for funcs.
- ft.gc = unsafe.Pointer(&ptrDataGCProg)
+ ft.gcdata = (*byte)(unsafe.Pointer(&ptrDataGCProg))
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
@@ -1913,7 +1914,7 @@
fieldAlign: uint8(maxAlign),
size: size,
kind: kind,
- gc: gcPtr,
+ gcdata: (*byte)(gcPtr),
}
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s
@@ -1922,7 +1923,7 @@
// Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype, offset uintptr) []uintptr {
- p := t.gc
+ p := unsafe.Pointer(t.gcdata)
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
for {
@@ -1967,9 +1968,9 @@
offset = (offset + 1) / 2 * 2
offset += unsafe.Sizeof(uint16(0)) // bucketsize
offset = (offset + ptrsize - 1) / ptrsize * ptrsize
- // gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // buckets
+ // gc = append(gc, _GC_PTR, offset, uintptr(bucket.gcdata)) // buckets
offset += ptrsize
- // gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // oldbuckets
+ // gc = append(gc, _GC_PTR, offset, uintptr(bucket.gcdata)) // oldbuckets
offset += ptrsize
offset += ptrsize // nevacuate
gc = append(gc, _GC_END)
@@ -1977,7 +1978,7 @@
h := new(rtype)
h.size = offset
- // h.gc = unsafe.Pointer(&gc[0])
+ // h.gcdata = unsafe.Pointer(&gc[0])
s := "hmap(" + *bucket.string + ")"
h.string = &s
return h
@@ -2038,19 +2039,19 @@
slice.ptrToThis = nil
if typ.size == 0 {
- slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
+ slice.gcdata = (*byte)(unsafe.Pointer(&sliceEmptyGCProg))
} else {
- slice.gc = unsafe.Pointer(&sliceGC{
+ slice.gcdata = (*byte)(unsafe.Pointer(&sliceGC{
width: slice.size,
op: _GC_SLICE,
off: 0,
- elemgc: typ.gc,
+ elemgc: unsafe.Pointer(typ.gcdata),
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})
+ // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gcdata is wrong.
+ // slice.gcdata = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
return cachePut(ckey, &slice.rtype)
}
@@ -2229,7 +2230,7 @@
if !hasPtr {
typ.kind |= kindNoPointers
gc := [...]uintptr{size, _GC_END}
- typ.gc = unsafe.Pointer(&gc[0])
+ typ.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
} else {
typ.kind &^= kindNoPointers
gc := []uintptr{size}
@@ -2237,7 +2238,7 @@
gc = appendGCProgram(gc, ft.typ, ft.offset)
}
gc = append(gc, _GC_END)
- typ.gc = unsafe.Pointer(&gc[0])
+ typ.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
}
typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
@@ -2365,18 +2366,18 @@
// No pointers.
array.kind |= kindNoPointers
gc := [...]uintptr{array.size, _GC_END}
- array.gc = unsafe.Pointer(&gc[0])
+ array.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
case count == 1:
// In memory, 1-element array looks just like the element.
array.kind |= typ.kind & kindGCProg
- array.gc = typ.gc
+ array.gcdata = typ.gcdata
default:
gc := []uintptr{array.size, _GC_ARRAY_START, 0, uintptr(count), typ.size}
gc = appendGCProgram(gc, typ, 0)
gc = append(gc, _GC_ARRAY_NEXT, _GC_END)
- array.gc = unsafe.Pointer(&gc[0])
+ array.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
}
array.kind &^= kindDirectIface
diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go
index cfee35a..6788f24 100644
--- a/libgo/go/runtime/type.go
+++ b/libgo/go/runtime/type.go
@@ -9,17 +9,18 @@
import "unsafe"
type _type struct {
+ size uintptr
+ ptrdata uintptr
+ hash uint32
kind uint8
align int8
fieldAlign uint8
_ uint8
- size uintptr
- hash uint32
hashfn func(unsafe.Pointer, uintptr) uintptr
equalfn func(unsafe.Pointer, unsafe.Pointer) bool
- gc unsafe.Pointer
+ gcdata *byte
string *string
*uncommontype
ptrToThis *_type
diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h
index e155254..03806f6 100644
--- a/libgo/runtime/go-type.h
+++ b/libgo/runtime/go-type.h
@@ -66,6 +66,17 @@
struct __go_type_descriptor
{
+ /* The size in bytes of a value of this type. Note that all types
+ in Go have a fixed size. */
+ uintptr_t __size;
+
+ /* The size of the memory prefix of a value of this type that holds
+ all pointers. */
+ uintptr_t __ptrdata;
+
+ /* The type's hash code. */
+ uint32_t __hash;
+
/* The type code for this type, one of the type kind values above.
This is used by unsafe.Reflect and unsafe.Typeof to determine the
type descriptor to return for this type itself. It is also used
@@ -78,13 +89,6 @@
/* The alignment in bytes of a struct field with this type. */
unsigned char __field_align;
- /* The size in bytes of a value of this type. Note that all types
- in Go have a fixed size. */
- uintptr_t __size;
-
- /* The type's hash code. */
- uint32_t __hash;
-
/* This function takes a pointer to a value of this type, and the
size of this type, and returns a hash code. We pass the size
explicitly becaues it means that we can share a single instance
@@ -96,7 +100,7 @@
const FuncVal *__equalfn;
/* The garbage collection data. */
- const uintptr *__gc;
+ const byte *__gcdata;
/* A string describing this type. This is only used for
debugging. */
diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c
index 3a97ee1..483f6ab 100644
--- a/libgo/runtime/go-unsafe-pointer.c
+++ b/libgo/runtime/go-unsafe-pointer.c
@@ -46,22 +46,24 @@
const struct __go_type_descriptor unsafe_Pointer =
{
+ /* __size */
+ sizeof (void *),
+ /* __ptrdata */
+ sizeof (void *),
+ /* __hash */
+ 78501163U,
/* __code */
GO_UNSAFE_POINTER | GO_DIRECT_IFACE,
/* __align */
__alignof (void *),
/* __field_align */
offsetof (struct field_align, p) - 1,
- /* __size */
- sizeof (void *),
- /* __hash */
- 78501163U,
/* __hashfn */
&runtime_pointerhash_descriptor,
/* __equalfn */
&runtime_pointerequal_descriptor,
- /* __gc */
- unsafe_Pointer_gc,
+ /* __gcdata */
+ (const byte*)(unsafe_Pointer_gc),
/* __reflection */
&reflection_string,
/* __uncommon */
@@ -95,22 +97,24 @@
{
/* __common */
{
+ /* __size */
+ sizeof (void *),
+ /* __ptrdata */
+ sizeof (void *),
+ /* __hash */
+ 1256018616U,
/* __code */
GO_PTR | GO_DIRECT_IFACE,
/* __align */
__alignof (void *),
/* __field_align */
offsetof (struct field_align, p) - 1,
- /* __size */
- sizeof (void *),
- /* __hash */
- 1256018616U,
/* __hashfn */
&runtime_pointerhash_descriptor,
/* __equalfn */
&runtime_pointerequal_descriptor,
- /* __gc */
- pointer_unsafe_Pointer_gc,
+ /* __gcdata */
+ (const byte*)(pointer_unsafe_Pointer_gc),
/* __reflection */
&preflection_string,
/* __uncommon */
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 357641d..8e7d7ef 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -674,7 +674,7 @@
// Runtime and gc think differently about closures.
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
pc1 = (uintptr*)objti;
- pc2 = (const uintptr*)t->__gc;
+ pc2 = (const uintptr*)t->__gcdata;
// 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]) {
@@ -801,13 +801,13 @@
t = (Type*)(type & ~(uintptr)(PtrSize-1));
switch(type & (PtrSize-1)) {
case TypeInfo_SingleObject:
- pc = (const uintptr*)t->__gc;
+ pc = (const uintptr*)t->__gcdata;
precise_type = true; // type information about 'b' is precise
stack_top.count = 1;
stack_top.elemsize = pc[0];
break;
case TypeInfo_Array:
- pc = (const uintptr*)t->__gc;
+ pc = (const uintptr*)t->__gcdata;
if(pc[0] == 0)
goto next_block;
precise_type = true; // type information about 'b' is precise
@@ -926,11 +926,11 @@
// 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 = (uintptr)((const PtrType*)t)->elem->__gcdata;
}
} else {
obj = eface->data;
- objti = (uintptr)t->__gc;
+ objti = (uintptr)t->__gcdata;
}
}
break;
@@ -964,11 +964,11 @@
// 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 = (uintptr)((const PtrType*)t)->elem->__gcdata;
}
} else {
obj = iface->data;
- objti = (uintptr)t->__gc;
+ objti = (uintptr)t->__gcdata;
}
}
break;
@@ -1095,7 +1095,7 @@
// (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){chan->buf, chancap*chantype->elem->__size,
- (uintptr)chantype->elem->__gc | PRECISE | LOOP};
+ (uintptr)chantype->elem->__gcdata | PRECISE | LOOP};
if(sbuf.obj.pos == sbuf.obj.end)
flushobjbuf(&sbuf);
}