summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-08-18 21:13:11 -0400
committerRuss Cox <rsc@golang.org>2014-08-18 21:13:11 -0400
commitb7f5e43fbdf09081deb1ca809c6d7e822a683cd6 (patch)
tree3ae0896f509ed021080dfff0e01b32d2e3ed3e8c /src/pkg
parent4596bf5fed92a4526dd55d27f903c74bf03618cd (diff)
downloadgo-b7f5e43fbdf09081deb1ca809c6d7e822a683cd6.tar.gz
cmd/gc, runtime: refactor interface inlining decision into compiler
We need to change the interface value representation for concurrent garbage collection, so that there is no ambiguity about whether the data word holds a pointer or scalar. This CL does NOT make any representation changes. Instead, it removes representation assumptions from various pieces of code throughout the tree. The isdirectiface function in cmd/gc/subr.c is now the only place that decides that policy. The policy propagates out from there in the reflect metadata, as a new flag in the internal kind value. A follow-up CL will change the representation by changing the isdirectiface function. If that CL causes problems, it will be easy to roll back. Update issue 8405. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://codereview.appspot.com/129090043
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/database/sql/convert_test.go37
-rw-r--r--src/pkg/reflect/all_test.go3
-rw-r--r--src/pkg/reflect/type.go21
-rw-r--r--src/pkg/reflect/value.go75
-rw-r--r--src/pkg/runtime/alg.go8
-rw-r--r--src/pkg/runtime/heapdump.c4
-rw-r--r--src/pkg/runtime/iface.go12
-rw-r--r--src/pkg/runtime/malloc.c8
-rw-r--r--src/pkg/runtime/malloc.go9
-rw-r--r--src/pkg/runtime/mgc0.c6
-rw-r--r--src/pkg/runtime/stack.c4
-rw-r--r--src/pkg/runtime/typekind.go44
-rw-r--r--src/pkg/runtime/typekind.h3
13 files changed, 159 insertions, 75 deletions
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
index 6e2483012..98af9fb64 100644
--- a/src/pkg/database/sql/convert_test.go
+++ b/src/pkg/database/sql/convert_test.go
@@ -283,6 +283,26 @@ func TestValueConverters(t *testing.T) {
// Tests that assigning to RawBytes doesn't allocate (and also works).
func TestRawBytesAllocs(t *testing.T) {
+ var tests = []struct {
+ name string
+ in interface{}
+ want string
+ }{
+ {"uint64", uint64(12345678), "12345678"},
+ {"uint32", uint32(1234), "1234"},
+ {"uint16", uint16(12), "12"},
+ {"uint8", uint8(1), "1"},
+ {"uint", uint(123), "123"},
+ {"int", int(123), "123"},
+ {"int8", int8(1), "1"},
+ {"int16", int16(12), "12"},
+ {"int32", int32(1234), "1234"},
+ {"int64", int64(12345678), "12345678"},
+ {"float32", float32(1.5), "1.5"},
+ {"float64", float64(64), "64"},
+ {"bool", false, "false"},
+ }
+
buf := make(RawBytes, 10)
test := func(name string, in interface{}, want string) {
if err := convertAssign(&buf, in); err != nil {
@@ -301,20 +321,11 @@ func TestRawBytesAllocs(t *testing.T) {
t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want))
}
}
+
n := testing.AllocsPerRun(100, func() {
- test("uint64", uint64(12345678), "12345678")
- test("uint32", uint32(1234), "1234")
- test("uint16", uint16(12), "12")
- test("uint8", uint8(1), "1")
- test("uint", uint(123), "123")
- test("int", int(123), "123")
- test("int8", int8(1), "1")
- test("int16", int16(12), "12")
- test("int32", int32(1234), "1234")
- test("int64", int64(12345678), "12345678")
- test("float32", float32(1.5), "1.5")
- test("float64", float64(64), "64")
- test("bool", false, "false")
+ for _, tt := range tests {
+ test(tt.name, tt.in, tt.want)
+ }
})
// The numbers below are only valid for 64-bit interface word sizes,
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index f12271173..d9781699e 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -3213,6 +3213,9 @@ func checkSameType(t *testing.T, x, y interface{}) {
}
func TestArrayOf(t *testing.T) {
+ // TODO(rsc): Finish ArrayOf and enable-test.
+ t.Skip("ArrayOf is not finished (and not exported)")
+
// check construction and use of type not in binary
type T int
at := ArrayOf(10, TypeOf(T(1)))
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index d7d497459..47aecd002 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -383,12 +383,11 @@ type Method struct {
Index int // index for Type.Method
}
-// High bit says whether type has
-// embedded pointers,to help garbage collector.
const (
- kindMask = 0x3f
- kindGCProg = 0x40
- kindNoPointers = 0x80
+ kindDirectIface = 1 << 5
+ kindGCProg = 1 << 6 // Type.gc points to GC program
+ kindNoPointers = 1 << 7
+ kindMask = (1 << 5) - 1
)
func (k Kind) String() string {
@@ -1503,6 +1502,7 @@ func (gc *gcProg) appendProg(t *rtype) {
var prog []byte
if t.kind&kindGCProg != 0 {
// Ensure that the runtime has unrolled GC program.
+ // TODO(rsc): Do not allocate.
unsafe_New(t)
// The program is stored in t.gc[0], skip unroll flag.
prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:]
@@ -1652,6 +1652,8 @@ func SliceOf(t Type) Type {
//
// TODO(rsc): Unexported for now. Export once the alg field is set correctly
// for the type. This may require significant work.
+//
+// TODO(rsc): TestArrayOf is also disabled. Re-enable.
func arrayOf(count int, elem Type) Type {
typ := elem.(*rtype)
slice := SliceOf(elem)
@@ -1676,6 +1678,7 @@ func arrayOf(count int, elem Type) Type {
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := new(arrayType)
*array = *prototype
+ // TODO: Set extra kind bits correctly.
array.string = &s
array.hash = fnv1(typ.hash, '[')
for n := uint32(count); n > 0; n >>= 8 {
@@ -1692,6 +1695,7 @@ func arrayOf(count int, elem Type) Type {
array.fieldAlign = typ.fieldAlign
// TODO: array.alg
// TODO: array.gc
+ // TODO:
array.uncommonType = nil
array.ptrToThis = nil
array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
@@ -1763,7 +1767,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
// Reflect uses the "interface" calling convention for
// methods, where receivers take one word of argument
// space no matter how big they actually are.
- if rcvr.size > ptrSize {
+ if !isDirectIface(rcvr) {
// we pass a pointer to the receiver.
gc.append(bitsPointer)
} else if rcvr.pointers() {
@@ -1813,3 +1817,8 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
layoutCache.Unlock()
return x, argSize, retOffset
}
+
+// isDirectIface reports whether t is stored directly in an interface value.
+func isDirectIface(t *rtype) bool {
+ return t.kind&kindDirectIface != 0
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 2cbda3983..dda852a3e 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -82,7 +82,7 @@ type Value struct {
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
- // If typ.size > ptrSize, code can assume that flagIndir is set.
+ // If !isDirectIface(typ), code can assume that flagIndir is set.
flag
// A method value represents a curried method invocation
@@ -128,7 +128,10 @@ func packEface(v Value) interface{} {
e := (*emptyInterface)(unsafe.Pointer(&i))
// First, fill in the data portion of the interface.
switch {
- case t.size > ptrSize:
+ case !isDirectIface(t):
+ if v.flag&flagIndir == 0 {
+ panic("bad indir")
+ }
// Value is indirect, and so is the interface we're making.
ptr := v.ptr
if v.flag&flagAddr != 0 {
@@ -172,7 +175,7 @@ func unpackEface(i interface{}) Value {
return Value{}
}
f := flag(t.Kind()) << flagKindShift
- if t.size > ptrSize {
+ if !isDirectIface(t) {
return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
}
if t.pointers() {
@@ -607,8 +610,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift}
- if typ.size > ptrSize {
- // value does not fit in word.
+ if !isDirectIface(typ) {
+ // value cannot be inlined in interface data.
// Must make a copy, because f might keep a reference to it,
// and we cannot let f keep a reference to the stack frame
// after this function returns, not even a read-only reference.
@@ -714,7 +717,7 @@ func storeRcvr(v Value, p unsafe.Pointer) {
iface := (*nonEmptyInterface)(v.ptr)
*(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
} else if v.flag&flagIndir != 0 {
- if t.size > ptrSize {
+ if !isDirectIface(t) {
*(*unsafe.Pointer)(p) = v.ptr
} else if t.pointers() {
*(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
@@ -987,7 +990,13 @@ func (v Value) Index(i int) Value {
val = unsafe.Pointer(uintptr(v.ptr) + offset)
case typ.pointers():
if offset != 0 {
- panic("can't Index(i) with i!=0 on ptrLike value")
+ // This is an array stored inline in an interface value.
+ // And the array element type has pointers.
+ // Since the inline storage space is only a single word,
+ // this implies we must be holding an array of length 1
+ // with an element type that is a single pointer.
+ // If the offset is not 0, something has gone wrong.
+ panic("reflect: internal error: unexpected array index")
}
val = v.ptr
case bigEndian:
@@ -1014,14 +1023,13 @@ func (v Value) Index(i int) Value {
return Value{typ, val, 0, fl}
case String:
- fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
+ fl := v.flag&flagRO | flag(Uint8<<flagKindShift) | flagIndir
s := (*stringHeader)(v.ptr)
if i < 0 || i >= s.Len {
panic("reflect: string index out of range")
}
- b := uintptr(0)
- *(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i)))
- return Value{uint8Type, nil, b, fl}
+ p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
+ return Value{uint8Type, p, 0, fl}
}
panic(&ValueError{"reflect.Value.Index", k})
}
@@ -1209,7 +1217,7 @@ func (v Value) MapIndex(key Value) Value {
typ := tt.elem
fl := (v.flag | key.flag) & flagRO
fl |= flag(typ.Kind()) << flagKindShift
- if typ.size > ptrSize {
+ if !isDirectIface(typ) {
// Copy result so future changes to the map
// won't change the underlying value.
c := unsafe_New(typ)
@@ -1249,7 +1257,7 @@ func (v Value) MapKeys() []Value {
// we can do about it.
break
}
- if keyType.size > ptrSize {
+ if !isDirectIface(keyType) {
// Copy result so future changes to the map
// won't change the underlying value.
c := unsafe_New(keyType)
@@ -1448,7 +1456,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
t := tt.elem
val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
var p unsafe.Pointer
- if t.size > ptrSize {
+ if !isDirectIface(t) {
p = unsafe_New(t)
val.ptr = p
val.flag |= flagIndir
@@ -1620,6 +1628,7 @@ func (v Value) SetCap(n int) {
// SetMapIndex sets the value associated with key in the map v to val.
// It panics if v's Kind is not Map.
// If val is the zero Value, SetMapIndex deletes the key from the map.
+// Otherwise if v holds a nil map, SetMapIndex will panic.
// As in Go, key's value must be assignable to the map's key type,
// and val's value must be assignable to the map's value type.
func (v Value) SetMapIndex(key, val Value) {
@@ -2189,7 +2198,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
t := tt.elem
p := runcases[chosen].val
fl := flag(t.Kind()) << flagKindShift
- if t.size > ptrSize {
+ if !isDirectIface(t) {
recv = Value{t, p, 0, fl | flagIndir}
} else if t.pointers() {
recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
@@ -2290,7 +2299,7 @@ func Zero(typ Type) Value {
}
t := typ.common()
fl := flag(t.Kind()) << flagKindShift
- if t.size <= ptrSize {
+ if isDirectIface(t) {
return Value{t, nil, 0, fl}
}
return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
@@ -2449,10 +2458,18 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
// where t is a signed or unsigned int type.
func makeInt(f flag, bits uint64, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
- // Assume ptrSize >= 4, so this must be uint64.
+ if !isDirectIface(typ) {
ptr := unsafe_New(typ)
- *(*uint64)(unsafe.Pointer(ptr)) = bits
+ switch typ.size {
+ case 1:
+ *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
+ case 2:
+ *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
+ case 4:
+ *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
+ case 8:
+ *(*uint64)(unsafe.Pointer(ptr)) = bits
+ }
return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
var s uintptr
@@ -2473,10 +2490,14 @@ func makeInt(f flag, bits uint64, t Type) Value {
// where t is a float32 or float64 type.
func makeFloat(f flag, v float64, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
- // Assume ptrSize >= 4, so this must be float64.
+ if !isDirectIface(typ) {
ptr := unsafe_New(typ)
- *(*float64)(unsafe.Pointer(ptr)) = v
+ switch typ.size {
+ case 4:
+ *(*float32)(unsafe.Pointer(ptr)) = float32(v)
+ case 8:
+ *(*float64)(unsafe.Pointer(ptr)) = v
+ }
return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
@@ -2494,7 +2515,7 @@ func makeFloat(f flag, v float64, t Type) Value {
// where t is a complex64 or complex128 type.
func makeComplex(f flag, v complex128, t Type) Value {
typ := t.common()
- if typ.size > ptrSize {
+ if !isDirectIface(typ) {
ptr := unsafe_New(typ)
switch typ.size {
case 8:
@@ -2505,9 +2526,13 @@ func makeComplex(f flag, v complex128, t Type) Value {
return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
}
- // Assume ptrSize <= 8 so this must be complex64.
var s uintptr
- *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+ switch typ.size {
+ case 8:
+ *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+ case 16:
+ *(*complex128)(unsafe.Pointer(&s)) = v
+ }
return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
}
diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go
index 409f0fa0c..650f68495 100644
--- a/src/pkg/runtime/alg.go
+++ b/src/pkg/runtime/alg.go
@@ -117,7 +117,7 @@ func interhash(a *iface, s, h uintptr) uintptr {
// but we can print a better error.
panic(errorString("hash of unhashable type " + *t._string))
}
- if uintptr(t.size) <= ptrSize {
+ if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
@@ -135,7 +135,7 @@ func nilinterhash(a *eface, s, h uintptr) uintptr {
// but we can print a better error.
panic(errorString("hash of unhashable type " + *t._string))
}
- if uintptr(t.size) <= ptrSize {
+ if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
@@ -208,7 +208,7 @@ func efaceeq(p, q interface{}) bool {
// but we can print a better error.
panic(errorString("comparing uncomparable type " + *t._string))
}
- if uintptr(t.size) <= ptrSize {
+ if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
}
return eq(x.data, y.data, uintptr(t.size))
@@ -232,7 +232,7 @@ func ifaceeq(p, q interface {
// but we can print a better error.
panic(errorString("comparing uncomparable type " + *t._string))
}
- if uintptr(t.size) <= ptrSize {
+ if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
}
return eq(x.data, y.data, uintptr(t.size))
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
index aa817fcee..babb32fe5 100644
--- a/src/pkg/runtime/heapdump.c
+++ b/src/pkg/runtime/heapdump.c
@@ -196,7 +196,7 @@ dumptype(Type *t)
write((byte*)".", 1);
write(t->x->name->str, t->x->name->len);
}
- dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+ dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
dumpfields((BitVector){0, nil});
}
@@ -584,7 +584,7 @@ itab_callback(Itab *tab)
dumpint(TagItab);
dumpint((uintptr)tab);
t = tab->type;
- dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+ dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
}
static void
diff --git a/src/pkg/runtime/iface.go b/src/pkg/runtime/iface.go
index 9bd6fc761..60dfb49db 100644
--- a/src/pkg/runtime/iface.go
+++ b/src/pkg/runtime/iface.go
@@ -135,7 +135,7 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
size := uintptr(t.size)
ep := (*eface)(unsafe.Pointer(&e))
- if size <= ptrSize {
+ if isDirectIface(t) {
ep._type = t
memmove(unsafe.Pointer(&ep.data), elem, size)
} else {
@@ -157,7 +157,7 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer)
}
size := uintptr(t.size)
pi := (*iface)(unsafe.Pointer(&i))
- if size <= ptrSize {
+ if isDirectIface(t) {
pi.tab = tab
memmove(unsafe.Pointer(&pi.data), elem, size)
} else {
@@ -182,7 +182,7 @@ func assertI2T(t *_type, i fInterface) (r struct{}) {
panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
}
size := uintptr(t.size)
- if size <= ptrSize {
+ if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
} else {
memmove(unsafe.Pointer(&r), ip.data, size)
@@ -202,7 +202,7 @@ func assertI2T2(t *_type, i fInterface) (r byte) {
return
}
*ok = true
- if size <= ptrSize {
+ if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
} else {
memmove(unsafe.Pointer(&r), ip.data, size)
@@ -226,7 +226,7 @@ func assertE2T(t *_type, e interface{}) (r struct{}) {
panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
}
size := uintptr(t.size)
- if size <= ptrSize {
+ if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
} else {
memmove(unsafe.Pointer(&r), ep.data, size)
@@ -245,7 +245,7 @@ func assertE2T2(t *_type, e interface{}) (r byte) {
return
}
*ok = true
- if size <= ptrSize {
+ if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
} else {
memmove(unsafe.Pointer(&r), ep.data, size)
diff --git a/src/pkg/runtime/malloc.c b/src/pkg/runtime/malloc.c
index 8b9447dad..f4143669e 100644
--- a/src/pkg/runtime/malloc.c
+++ b/src/pkg/runtime/malloc.c
@@ -459,7 +459,7 @@ setFinalizer(Eface obj, Eface finalizer)
}
if(finalizer.type != nil) {
runtime·createfing();
- if(finalizer.type->kind != KindFunc)
+ if((finalizer.type->kind&KindMask) != KindFunc)
goto badfunc;
ft = (FuncType*)finalizer.type;
if(ft->dotdotdot || ft->in.len != 1)
@@ -467,12 +467,12 @@ setFinalizer(Eface obj, Eface finalizer)
fint = *(Type**)ft->in.array;
if(fint == obj.type) {
// ok - same type
- } else if(fint->kind == KindPtr && (fint->x == nil || fint->x->name == nil || obj.type->x == nil || obj.type->x->name == nil) && ((PtrType*)fint)->elem == ((PtrType*)obj.type)->elem) {
+ } else if((fint->kind&KindMask) == KindPtr && (fint->x == nil || fint->x->name == nil || obj.type->x == nil || obj.type->x->name == nil) && ((PtrType*)fint)->elem == ((PtrType*)obj.type)->elem) {
// ok - not same type, but both pointers,
// one or the other is unnamed, and same element type, so assignable.
- } else if(fint->kind == KindInterface && ((InterfaceType*)fint)->mhdr.len == 0) {
+ } else if((fint->kind&KindMask) == KindInterface && ((InterfaceType*)fint)->mhdr.len == 0) {
// ok - satisfies empty interface
- } else if(fint->kind == KindInterface && runtime·ifaceE2I2((InterfaceType*)fint, obj, &iface)) {
+ } else if((fint->kind&KindMask) == KindInterface && runtime·ifaceE2I2((InterfaceType*)fint, obj, &iface)) {
// ok - satisfies non-empty interface
} else
goto badfunc;
diff --git a/src/pkg/runtime/malloc.go b/src/pkg/runtime/malloc.go
index f116efaba..ce7e06210 100644
--- a/src/pkg/runtime/malloc.go
+++ b/src/pkg/runtime/malloc.go
@@ -14,15 +14,6 @@ const (
flagNoScan = 1 << 0 // GC doesn't have to scan object
flagNoZero = 1 << 1 // don't zero memory
- kindArray = 17
- kindFunc = 19
- kindInterface = 20
- kindPtr = 22
- kindStruct = 25
- kindMask = 1<<6 - 1
- kindGCProg = 1 << 6
- kindNoPointers = 1 << 7
-
maxTinySize = 16
tinySizeClass = 2
maxSmallSize = 32 << 10
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index ef44d7f78..3583d77d1 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -367,7 +367,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
iface = (Iface*)(b+i);
if(iface->tab != nil) {
typ = iface->tab->type;
- if(typ->size > PtrSize || !(typ->kind&KindNoPointers))
+ if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
obj = iface->data;
}
break;
@@ -375,7 +375,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
eface = (Eface*)(b+i);
typ = eface->type;
if(typ != nil) {
- if(typ->size > PtrSize || !(typ->kind&KindNoPointers))
+ if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
obj = eface->data;
}
break;
@@ -1675,7 +1675,7 @@ runfinq(void)
}
if(f->fint == nil)
runtime·throw("missing type in runfinq");
- if(f->fint->kind == KindPtr) {
+ if((f->fint->kind&KindMask) == KindPtr) {
// direct use of pointer
*(void**)frame = f->arg;
} else if(((InterfaceType*)f->fint)->mhdr.len == 0) {
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index 772080af5..b4e992e65 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -585,7 +585,7 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
break;
case BitsEface:
t = (Type*)scanp[i];
- if(t != nil && (t->size > PtrSize || (t->kind & KindNoPointers) == 0)) {
+ if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
p = scanp[i+1];
if(minp <= p && p < maxp) {
if(StackDebug >= 3)
@@ -602,7 +602,7 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
if(tab != nil) {
t = tab->type;
//runtime·printf(" type=%p\n", t);
- if(t->size > PtrSize || (t->kind & KindNoPointers) == 0) {
+ if((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0) {
p = scanp[i+1];
if(minp <= p && p < maxp) {
if(StackDebug >= 3)
diff --git a/src/pkg/runtime/typekind.go b/src/pkg/runtime/typekind.go
new file mode 100644
index 000000000..598553628
--- /dev/null
+++ b/src/pkg/runtime/typekind.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ kindBool = 1 + iota
+ kindInt
+ kindInt8
+ kindInt16
+ kindInt32
+ kindInt64
+ kindUint
+ kindUint8
+ kindUint16
+ kindUint32
+ kindUint64
+ kindUintptr
+ kindFloat32
+ kindFloat64
+ kindComplex64
+ kindComplex128
+ kindArray
+ kindChan
+ kindFunc
+ kindInterface
+ kindMap
+ kindPtr
+ kindSlice
+ kindString
+ kindStruct
+ kindUnsafePointer
+
+ kindDirectIface = 1 << 5
+ kindGCProg = 1 << 6 // Type.gc points to GC program
+ kindNoPointers = 1 << 7
+ kindMask = (1 << 5) - 1
+)
+
+// isDirectIface reports whether t is stored directly in an interface value.
+func isDirectIface(t *_type) bool {
+ return t.kind&kindDirectIface != 0
+}
diff --git a/src/pkg/runtime/typekind.h b/src/pkg/runtime/typekind.h
index bf6ade08d..7c611e8ba 100644
--- a/src/pkg/runtime/typekind.h
+++ b/src/pkg/runtime/typekind.h
@@ -33,8 +33,9 @@ enum {
KindStruct,
KindUnsafePointer,
+ KindDirectIface = 1<<5,
KindGCProg = 1<<6, // Type.gc points to GC program
KindNoPointers = 1<<7,
- KindMask = (1<<6)-1,
+ KindMask = (1<<5)-1,
};