summaryrefslogtreecommitdiff
path: root/src/pkg/reflect/type.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/reflect/type.go')
-rw-r--r--src/pkg/reflect/type.go131
1 files changed, 130 insertions, 1 deletions
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 7afb7defe..40d76f99d 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,6 +16,7 @@
package reflect
import (
+ "runtime"
"strconv"
"sync"
"unsafe"
@@ -252,6 +253,7 @@ type rtype struct {
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
+ zero unsafe.Pointer // pointer to zero value
}
// Method on non-interface type
@@ -477,6 +479,8 @@ func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
+func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
+
func (t *rtype) common() *rtype { return t }
func (t *uncommonType) Method(i int) (m Method) {
@@ -495,7 +499,7 @@ func (t *uncommonType) Method(i int) (m Method) {
mt := p.typ
m.Type = mt
fn := unsafe.Pointer(&p.tfn)
- m.Func = Value{mt, fn, fl}
+ m.Func = Value{mt, fn, 0, fl}
m.Index = i
return
}
@@ -1089,6 +1093,7 @@ func (t *rtype) ptrTo() *rtype {
p.uncommonType = nil
p.ptrToThis = nil
+ p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
if t.kind&kindNoPointers != 0 {
@@ -1475,6 +1480,7 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.elem = typ
ch.uncommonType = nil
ch.ptrToThis = nil
+ ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
ch.gc = unsafe.Pointer(&chanGC{
width: ch.size,
@@ -1534,6 +1540,14 @@ func MapOf(key, elem Type) Type {
mt.hmap = hMapOf(mt.bucket)
mt.uncommonType = nil
mt.ptrToThis = nil
+ mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
+ mt.gc = unsafe.Pointer(&ptrGC{
+ width: unsafe.Sizeof(uintptr(0)),
+ op: _GC_PTR,
+ off: 0,
+ elemgc: mt.hmap.gc,
+ end: _GC_END,
+ })
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
@@ -1566,6 +1580,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
offset += ptrsize
+ if runtime.GOARCH == "amd64p32" {
+ offset += 4
+ }
+
// keys
if ktyp.kind&kindNoPointers == 0 {
gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
@@ -1709,6 +1727,7 @@ func SliceOf(t Type) Type {
slice.elem = typ
slice.uncommonType = nil
slice.ptrToThis = nil
+ slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
if typ.size == 0 {
slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
@@ -1778,6 +1797,7 @@ func arrayOf(count int, elem Type) Type {
// TODO: array.gc
array.uncommonType = nil
array.ptrToThis = nil
+ array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -1795,3 +1815,112 @@ func toType(t *rtype) Type {
}
return t
}
+
+type layoutKey struct {
+ t *rtype // function signature
+ rcvr *rtype // receiver type, or nil if none
+}
+
+type layoutType struct {
+ t *rtype
+ argSize uintptr // size of arguments
+ retOffset uintptr // offset of return values.
+}
+
+var layoutCache struct {
+ sync.RWMutex
+ m map[layoutKey]layoutType
+}
+
+// funcLayout computes a struct type representing the layout of the
+// function arguments and return values for the function type t.
+// If rcvr != nil, rcvr specifies the type of the receiver.
+// The returned type exists only for GC, so we only fill out GC relevant info.
+// Currently, that's just size and the GC program. We also fill in
+// the name for possible debugging use.
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
+ if t.Kind() != Func {
+ panic("reflect: funcLayout of non-func type")
+ }
+ if rcvr != nil && rcvr.Kind() == Interface {
+ panic("reflect: funcLayout with interface receiver " + rcvr.String())
+ }
+ k := layoutKey{t, rcvr}
+ layoutCache.RLock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.RUnlock()
+ return x.t, x.argSize, x.retOffset
+ }
+ layoutCache.RUnlock()
+ layoutCache.Lock()
+ if x := layoutCache.m[k]; x.t != nil {
+ layoutCache.Unlock()
+ return x.t, x.argSize, x.retOffset
+ }
+
+ tt := (*funcType)(unsafe.Pointer(t))
+
+ // compute gc program for arguments
+ gc := make([]uintptr, 1) // first entry is size, filled in at the end
+ offset := uintptr(0)
+ if rcvr != nil {
+ // 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 {
+ // we pass a pointer to the receiver.
+ gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc))
+ } else if rcvr.pointers() {
+ // rcvr is a one-word pointer object. Its gc program
+ // is just what we need here.
+ gc = appendGCProgram(gc, rcvr)
+ }
+ offset += ptrSize
+ }
+ for _, arg := range tt.in {
+ offset = align(offset, uintptr(arg.align))
+ if arg.pointers() {
+ gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc))
+ }
+ offset += arg.size
+ }
+ argSize = offset
+ if runtime.GOARCH == "amd64p32" {
+ offset = align(offset, 8)
+ }
+ offset = align(offset, ptrSize)
+ retOffset = offset
+ for _, res := range tt.out {
+ offset = align(offset, uintptr(res.align))
+ if res.pointers() {
+ gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc))
+ }
+ offset += res.size
+ }
+ gc = append(gc, _GC_END)
+ gc[0] = offset
+
+ // build dummy rtype holding gc program
+ x := new(rtype)
+ x.size = offset
+ x.gc = unsafe.Pointer(&gc[0])
+ var s string
+ if rcvr != nil {
+ s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+ } else {
+ s = "funcargs(" + *t.string + ")"
+ }
+ x.string = &s
+
+ // cache result for future callers
+ if layoutCache.m == nil {
+ layoutCache.m = make(map[layoutKey]layoutType)
+ }
+ layoutCache.m[k] = layoutType{
+ t: x,
+ argSize: argSize,
+ retOffset: retOffset,
+ }
+ layoutCache.Unlock()
+ return x, argSize, retOffset
+}