]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: rewrite Value to separate out pointer vs. nonpointer info.
authorKeith Randall <khr@golang.org>
Thu, 19 Dec 2013 23:15:24 +0000 (15:15 -0800)
committerKeith Randall <khr@golang.org>
Thu, 19 Dec 2013 23:15:24 +0000 (15:15 -0800)
Needed for precise gc and copying stacks.

reflect.Value now takes 4 words instead of 3.

Still to do:
 - un-iword-ify channel ops.
 - un-iword-ify method receivers.

R=golang-dev, iant, rsc, khr
CC=golang-dev
https://golang.org/cl/43040043

src/pkg/reflect/makefunc.go
src/pkg/reflect/type.go
src/pkg/reflect/value.go
src/pkg/runtime/hashmap.c

index 9b1b7d5721baa91cc821b3fde1a21b19f0d84d3c..0e61fdea7a34176fb0f665bffba9803d6cd624af 100644 (file)
@@ -56,7 +56,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 
        impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
 
-       return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
+       return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift}
 }
 
 // makeFuncStub is an assembly function that is the code half of
@@ -87,7 +87,7 @@ func makeMethodValue(op string, v Value) Value {
        // Ignoring the flagMethod bit, v describes the receiver, not the method type.
        fl := v.flag & (flagRO | flagAddr | flagIndir)
        fl |= flag(v.typ.Kind()) << flagKindShift
-       rcvr := Value{v.typ, v.val, fl}
+       rcvr := Value{v.typ, v.ptr, v.scalar, fl}
 
        // v.Type returns the actual type of the method value.
        funcType := v.Type().(*rtype)
@@ -109,7 +109,7 @@ func makeMethodValue(op string, v Value) Value {
        // but we want Interface() and other operations to fail early.
        methodReceiver(op, fv.rcvr, fv.method)
 
-       return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+       return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift}
 }
 
 // methodValueCall is an assembly function that is the code half of
index ffc653b192a092407ea676072aa9de7bb1564ab0..0f38781113ac0344b373836c584a7bde17da2673 100644 (file)
@@ -478,6 +478,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) {
@@ -496,7 +498,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
 }
index 7764ffade2c2681936848177a26879fdf72a4a54..e37a3f8879e58083723f9fbfaf8b0b644696bdb7 100644 (file)
@@ -62,14 +62,15 @@ type Value struct {
        // typ holds the type of the value represented by a Value.
        typ *rtype
 
-       // val holds the 1-word representation of the value.
-       // If flag's flagIndir bit is set, then val is a pointer to the data.
-       // Otherwise val is a word holding the actual data.
-       // When the data is smaller than a word, it begins at
-       // the first byte (in the memory address sense) of val.
-       // We use unsafe.Pointer so that the garbage collector
-       // knows that val could be a pointer.
-       val unsafe.Pointer
+       // Pointer-valued data or, if flagIndir is set, pointer to data.
+       // Valid when either flagIndir is set or typ.pointers() is true.
+       ptr unsafe.Pointer
+
+       // Non-pointer-valued data.  When the data is smaller
+       // than a word, it begins at the first byte (in the memory
+       // address sense) of this field.
+       // Valid when flagIndir is not set and typ.pointers() is false.
+       scalar uintptr
 
        // flag holds metadata about the value.
        // The lowest bits are flag bits:
@@ -108,6 +109,78 @@ func (f flag) kind() Kind {
        return Kind((f >> flagKindShift) & flagKindMask)
 }
 
+// pointer returns the underlying pointer represented by v.
+// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+func (v Value) pointer() unsafe.Pointer {
+       if v.typ.size != ptrSize || !v.typ.pointers() {
+               panic("can't call pointer on a non-pointer Value")
+       }
+       if v.flag&flagIndir != 0 {
+               return *(*unsafe.Pointer)(v.ptr)
+       }
+       return v.ptr
+}
+
+// packEface converts v to the empty interface.
+func packEface(v Value) interface{} {
+       t := v.typ
+       var i interface{}
+       e := (*emptyInterface)(unsafe.Pointer(&i))
+       // First, fill in the data portion of the interface.
+       switch {
+       case t.size > ptrSize:
+               // Value is indirect, and so is the interface we're making.
+               ptr := v.ptr
+               if v.flag&flagAddr != 0 {
+                       // TODO: pass safe boolean from valueInterface so
+                       // we don't need to copy if safe==true?
+                       c := unsafe_New(t)
+                       memmove(c, ptr, t.size)
+                       ptr = c
+               }
+               e.word = iword(ptr)
+       case v.flag&flagIndir != 0:
+               // Value is indirect, but interface is direct.  We need
+               // to load the data at v.ptr into the interface data word.
+               if t.pointers() {
+                       e.word = iword(*(*unsafe.Pointer)(v.ptr))
+               } else {
+                       e.word = iword(loadScalar(v.ptr, t.size))
+               }
+       default:
+               // Value is direct, and so is the interface.
+               if t.pointers() {
+                       e.word = iword(v.ptr)
+               } else {
+                       e.word = iword(v.scalar)
+               }
+       }
+       // Now, fill in the type portion.  We're very careful here not
+       // to have any operation between the e.word and e.typ assignments
+       // that would let the garbage collector observe the partially-built
+       // interface value.
+       e.typ = t
+       return i
+}
+
+// unpackEface converts the empty interface i to a Value.
+func unpackEface(i interface{}) Value {
+       e := (*emptyInterface)(unsafe.Pointer(&i))
+       // NOTE: don't read e.word until we know whether it is really a pointer or not.
+       t := e.typ
+       if t == nil {
+               return Value{}
+       }
+       f := flag(t.Kind()) << flagKindShift
+       if t.size > ptrSize {
+               return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
+       }
+       if t.pointers() {
+               return Value{t, unsafe.Pointer(e.word), 0, f}
+       }
+       return Value{t, nil, uintptr(e.word), f}
+}
+
 // A ValueError occurs when a Value method is invoked on
 // a Value that does not support it.  Such cases are documented
 // in the description of each method.
@@ -143,24 +216,57 @@ func methodName() string {
 // unsafe.Pointer to represent it, so that if iword appears
 // in a struct, the garbage collector knows that might be
 // a pointer.
+// TODO: get rid of all occurrences of iword (except in the interface decls below?)
+// We want to get rid of the "feature" that an unsafe.Pointer is sometimes a pointer
+// and sometimes a uintptr.
 type iword unsafe.Pointer
 
+// Get an iword that represents this value.
+// TODO: this function goes away at some point
 func (v Value) iword() iword {
-       if v.flag&flagIndir != 0 && v.typ.size <= ptrSize {
+       t := v.typ
+       if t == nil {
+               return iword(nil)
+       }
+       if v.flag&flagIndir != 0 {
+               if v.typ.size > ptrSize {
+                       return iword(v.ptr)
+               }
                // Have indirect but want direct word.
-               return loadIword(v.val, v.typ.size)
+               if t.pointers() {
+                       return iword(*(*unsafe.Pointer)(v.ptr))
+               }
+               return iword(loadScalar(v.ptr, v.typ.size))
+       }
+       if t.pointers() {
+               return iword(v.ptr)
        }
-       return iword(v.val)
+       return iword(v.scalar)
 }
 
-// loadIword loads n bytes at p from memory into an iword.
-func loadIword(p unsafe.Pointer, n uintptr) iword {
+// Build a Value from a type/iword pair, plus any extra flags.
+// TODO: this function goes away at some point
+func fromIword(t *rtype, w iword, fl flag) Value {
+       fl |= flag(t.Kind()) << flagKindShift
+       if t.size > ptrSize {
+               return Value{t, unsafe.Pointer(w), 0, fl | flagIndir}
+       } else if t.pointers() {
+               return Value{t, unsafe.Pointer(w), 0, fl}
+       } else {
+               return Value{t, nil, uintptr(w), fl}
+       }
+}
+
+// loadScalar loads n bytes at p from memory into a uintptr
+// that forms the second word of an interface.  The data
+// must be non-pointer in nature.
+func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
        // Run the copy ourselves instead of calling memmove
        // to avoid moving w to the heap.
-       var w iword
+       var w uintptr
        switch n {
        default:
-               panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
+               panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value")
        case 0:
        case 1:
                *(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -182,13 +288,13 @@ func loadIword(p unsafe.Pointer, n uintptr) iword {
        return w
 }
 
-// storeIword stores n bytes from w into p.
-func storeIword(p unsafe.Pointer, w iword, n uintptr) {
+// storeScalar stores n bytes from w into p.
+func storeScalar(p unsafe.Pointer, w uintptr, n uintptr) {
        // Run the copy ourselves instead of calling memmove
        // to avoid moving w to the heap.
        switch n {
        default:
-               panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
+               panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value")
        case 0:
        case 1:
                *(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -278,7 +384,7 @@ func (v Value) Addr() Value {
        if v.flag&flagAddr == 0 {
                panic("reflect.Value.Addr of unaddressable value")
        }
-       return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+       return Value{v.typ.ptrTo(), v.ptr, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
 }
 
 // Bool returns v's underlying value.
@@ -286,9 +392,9 @@ func (v Value) Addr() Value {
 func (v Value) Bool() bool {
        v.mustBe(Bool)
        if v.flag&flagIndir != 0 {
-               return *(*bool)(v.val)
+               return *(*bool)(v.ptr)
        }
-       return *(*bool)(unsafe.Pointer(&v.val))
+       return *(*bool)(unsafe.Pointer(&v.scalar))
 }
 
 // Bytes returns v's underlying value.
@@ -299,7 +405,7 @@ func (v Value) Bytes() []byte {
                panic("reflect.Value.Bytes of non-byte slice")
        }
        // Slice is always bigger than a word; assume flagIndir.
-       return *(*[]byte)(v.val)
+       return *(*[]byte)(v.ptr)
 }
 
 // runes returns v's underlying value.
@@ -310,7 +416,7 @@ func (v Value) runes() []rune {
                panic("reflect.Value.Bytes of non-rune slice")
        }
        // Slice is always bigger than a word; assume flagIndir.
-       return *(*[]rune)(v.val)
+       return *(*[]rune)(v.ptr)
 }
 
 // CanAddr returns true if the value's address can be obtained with Addr.
@@ -373,9 +479,9 @@ func (v Value) call(op string, in []Value) []Value {
        if v.flag&flagMethod != 0 {
                t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
        } else if v.flag&flagIndir != 0 {
-               fn = *(*unsafe.Pointer)(v.val)
+               fn = *(*unsafe.Pointer)(v.ptr)
        } else {
-               fn = v.val
+               fn = v.ptr
        }
 
        if fn == nil {
@@ -477,10 +583,12 @@ func (v Value) call(op string, in []Value) []Value {
                n := targ.size
                addr := unsafe.Pointer(uintptr(ptr) + off)
                v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
-               if v.flag&flagIndir == 0 {
-                       storeIword(addr, iword(v.val), n)
+               if v.flag&flagIndir != 0 {
+                       memmove(addr, v.ptr, n)
+               } else if targ.pointers() {
+                       *(*unsafe.Pointer)(addr) = v.ptr
                } else {
-                       memmove(addr, v.val, n)
+                       storeScalar(addr, v.scalar, n)
                }
                off += n
        }
@@ -514,7 +622,7 @@ func (v Value) call(op string, in []Value) []Value {
                a := uintptr(tv.Align())
                off = (off + a - 1) &^ (a - 1)
                fl := flagIndir | flag(tv.Kind())<<flagKindShift
-               ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(ptr) + off), fl}
+               ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(ptr) + off), 0, fl}
                off += tv.Size()
        }
 
@@ -544,18 +652,20 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
        for _, arg := range ftyp.in {
                typ := arg
                off += -off & uintptr(typ.align-1)
-               v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
-               if typ.size <= ptrSize {
-                       // value fits in word.
-                       v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
-               } else {
+               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.
                        // 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.
-                       v.val = unsafe_New(typ)
-                       memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
+                       v.ptr = unsafe_New(typ)
+                       memmove(v.ptr, addr, typ.size)
                        v.flag |= flagIndir
+               } else if typ.pointers() {
+                       v.ptr = *(*unsafe.Pointer)(addr)
+               } else {
+                       v.scalar = loadScalar(addr, typ.size)
                }
                in = append(in, v)
                off += typ.size
@@ -584,10 +694,12 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
                        }
                        off += -off & uintptr(typ.align-1)
                        addr := unsafe.Pointer(uintptr(ptr) + off)
-                       if v.flag&flagIndir == 0 {
-                               storeIword(addr, iword(v.val), typ.size)
+                       if v.flag&flagIndir != 0 {
+                               memmove(addr, v.ptr, typ.size)
+                       } else if typ.pointers() {
+                               *(*unsafe.Pointer)(addr) = v.ptr
                        } else {
-                               memmove(addr, v.val, typ.size)
+                               storeScalar(addr, v.scalar, typ.size)
                        }
                        off += typ.size
                }
@@ -610,7 +722,7 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
                        panic("reflect: " + op + " of unexported method")
                }
                t = m.typ
-               iface := (*nonEmptyInterface)(v.val)
+               iface := (*nonEmptyInterface)(v.ptr)
                if iface.itab == nil {
                        panic("reflect: " + op + " of method on nil interface value")
                }
@@ -729,10 +841,10 @@ func (v Value) Cap() int {
        case Array:
                return v.typ.Len()
        case Chan:
-               return int(chancap(v.iword()))
+               return int(chancap(v.pointer()))
        case Slice:
                // Slice is always bigger than a word; assume flagIndir.
-               return (*SliceHeader)(v.val).Cap
+               return (*sliceHeader)(v.ptr).Cap
        }
        panic(&ValueError{"reflect.Value.Cap", k})
 }
@@ -742,7 +854,7 @@ func (v Value) Cap() int {
 func (v Value) Close() {
        v.mustBe(Chan)
        v.mustBeExported()
-       chanclose(v.iword())
+       chanclose(v.pointer())
 }
 
 // Complex returns v's underlying value, as a complex128.
@@ -752,12 +864,12 @@ func (v Value) Complex() complex128 {
        switch k {
        case Complex64:
                if v.flag&flagIndir != 0 {
-                       return complex128(*(*complex64)(v.val))
+                       return complex128(*(*complex64)(v.ptr))
                }
-               return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
+               return complex128(*(*complex64)(unsafe.Pointer(&v.scalar)))
        case Complex128:
                // complex128 is always bigger than a word; assume flagIndir.
-               return *(*complex128)(v.val)
+               return *(*complex128)(v.ptr)
        }
        panic(&ValueError{"reflect.Value.Complex", k})
 }
@@ -770,48 +882,31 @@ func (v Value) Elem() Value {
        k := v.kind()
        switch k {
        case Interface:
-               var (
-                       typ *rtype
-                       val unsafe.Pointer
-               )
+               var eface interface{}
                if v.typ.NumMethod() == 0 {
-                       eface := (*emptyInterface)(v.val)
-                       if eface.typ == nil {
-                               // nil interface value
-                               return Value{}
-                       }
-                       typ = eface.typ
-                       val = unsafe.Pointer(eface.word)
+                       eface = *(*interface{})(v.ptr)
                } else {
-                       iface := (*nonEmptyInterface)(v.val)
-                       if iface.itab == nil {
-                               // nil interface value
-                               return Value{}
-                       }
-                       typ = iface.itab.typ
-                       val = unsafe.Pointer(iface.word)
+                       eface = (interface{})(*(*interface {
+                               M()
+                       })(v.ptr))
                }
-               fl := v.flag & flagRO
-               fl |= flag(typ.Kind()) << flagKindShift
-               if typ.size > ptrSize {
-                       fl |= flagIndir
-               }
-               return Value{typ, val, fl}
-
+               x := unpackEface(eface)
+               x.flag |= v.flag & flagRO
+               return x
        case Ptr:
-               val := v.val
+               ptr := v.ptr
                if v.flag&flagIndir != 0 {
-                       val = *(*unsafe.Pointer)(val)
+                       ptr = *(*unsafe.Pointer)(ptr)
                }
                // The returned value's address is v's value.
-               if val == nil {
+               if ptr == nil {
                        return Value{}
                }
                tt := (*ptrType)(unsafe.Pointer(v.typ))
                typ := tt.elem
                fl := v.flag&flagRO | flagIndir | flagAddr
                fl |= flag(typ.Kind() << flagKindShift)
-               return Value{typ, val, fl}
+               return Value{typ, ptr, 0, fl}
        }
        panic(&ValueError{"reflect.Value.Elem", k})
 }
@@ -835,20 +930,26 @@ func (v Value) Field(i int) Value {
        }
        fl |= flag(typ.Kind()) << flagKindShift
 
-       var val unsafe.Pointer
+       var ptr unsafe.Pointer
+       var scalar uintptr
        switch {
        case fl&flagIndir != 0:
                // Indirect.  Just bump pointer.
-               val = unsafe.Pointer(uintptr(v.val) + field.offset)
+               ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
+       case typ.pointers():
+               if field.offset != 0 {
+                       panic("field access of ptr value isn't at offset 0")
+               }
+               ptr = v.ptr
        case bigEndian:
-               // Direct.  Discard leading bytes.
-               val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+               // Must be scalar.  Discard leading bytes.
+               scalar = v.scalar << (field.offset * 8)
        default:
-               // Direct.  Discard leading bytes.
-               val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
+               // Must be scalar.  Discard leading bytes.
+               scalar = v.scalar >> (field.offset * 8)
        }
 
-       return Value{typ, val, fl}
+       return Value{typ, ptr, scalar, fl}
 }
 
 // FieldByIndex returns the nested field corresponding to index.
@@ -896,14 +997,14 @@ func (v Value) Float() float64 {
        switch k {
        case Float32:
                if v.flag&flagIndir != 0 {
-                       return float64(*(*float32)(v.val))
+                       return float64(*(*float32)(v.ptr))
                }
-               return float64(*(*float32)(unsafe.Pointer(&v.val)))
+               return float64(*(*float32)(unsafe.Pointer(&v.scalar)))
        case Float64:
                if v.flag&flagIndir != 0 {
-                       return *(*float64)(v.val)
+                       return *(*float64)(v.ptr)
                }
-               return *(*float64)(unsafe.Pointer(&v.val))
+               return *(*float64)(unsafe.Pointer(&v.scalar))
        }
        panic(&ValueError{"reflect.Value.Float", k})
 }
@@ -926,41 +1027,48 @@ func (v Value) Index(i int) Value {
                offset := uintptr(i) * typ.size
 
                var val unsafe.Pointer
+               var scalar uintptr
                switch {
                case fl&flagIndir != 0:
                        // Indirect.  Just bump pointer.
-                       val = unsafe.Pointer(uintptr(v.val) + offset)
+                       val = unsafe.Pointer(uintptr(v.ptr) + offset)
+               case typ.pointers():
+                       if offset != 0 {
+                               panic("can't Index(i) with i!=0 on ptrLike value")
+                       }
+                       val = v.ptr
                case bigEndian:
                        // Direct.  Discard leading bytes.
-                       val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+                       scalar = v.scalar << (offset * 8)
                default:
                        // Direct.  Discard leading bytes.
-                       val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+                       scalar = v.scalar >> (offset * 8)
                }
-               return Value{typ, val, fl}
+               return Value{typ, val, scalar, fl}
 
        case Slice:
                // Element flag same as Elem of Ptr.
                // Addressable, indirect, possibly read-only.
                fl := flagAddr | flagIndir | v.flag&flagRO
-               s := (*SliceHeader)(v.val)
+               s := (*sliceHeader)(v.ptr)
                if i < 0 || i >= s.Len {
                        panic("reflect: slice index out of range")
                }
                tt := (*sliceType)(unsafe.Pointer(v.typ))
                typ := tt.elem
                fl |= flag(typ.Kind()) << flagKindShift
-               val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
-               return Value{typ, val, fl}
+               val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+               return Value{typ, val, 0, fl}
 
        case String:
                fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
-               s := (*StringHeader)(v.val)
+               s := (*stringHeader)(v.ptr)
                if i < 0 || i >= s.Len {
                        panic("reflect: string index out of range")
                }
-               val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
-               return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
+               b := uintptr(0)
+               *(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i)))
+               return Value{uint8Type, nil, b, fl}
        }
        panic(&ValueError{"reflect.Value.Index", k})
 }
@@ -971,11 +1079,11 @@ func (v Value) Int() int64 {
        k := v.kind()
        var p unsafe.Pointer
        if v.flag&flagIndir != 0 {
-               p = v.val
+               p = v.ptr
        } else {
-               // The escape analysis is good enough that &v.val
+               // The escape analysis is good enough that &v.scalar
                // does not trigger a heap allocation.
-               p = unsafe.Pointer(&v.val)
+               p = unsafe.Pointer(&v.scalar)
        }
        switch k {
        case Int:
@@ -1023,47 +1131,33 @@ func valueInterface(v Value, safe bool) interface{} {
                v = makeMethodValue("Interface", v)
        }
 
-       k := v.kind()
-       if k == Interface {
+       if v.kind() == Interface {
                // Special case: return the element inside the interface.
                // Empty interface has one layout, all interfaces with
                // methods have a second layout.
                if v.NumMethod() == 0 {
-                       return *(*interface{})(v.val)
+                       return *(*interface{})(v.ptr)
                }
                return *(*interface {
                        M()
-               })(v.val)
-       }
-
-       // Non-interface value.
-       var eface emptyInterface
-       eface.typ = v.typ
-       eface.word = v.iword()
-
-       // Don't need to allocate if v is not addressable or fits in one word.
-       if v.flag&flagAddr != 0 && v.typ.size > ptrSize {
-               // eface.word is a pointer to the actual data,
-               // which might be changed.  We need to return
-               // a pointer to unchanging data, so make a copy.
-               ptr := unsafe_New(v.typ)
-               memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
-               eface.word = iword(ptr)
+               })(v.ptr)
        }
 
-       return *(*interface{})(unsafe.Pointer(&eface))
+       // TODO: pass safe to packEface so we don't need to copy if safe==true?
+       return packEface(v)
 }
 
 // InterfaceData returns the interface v's value as a uintptr pair.
 // It panics if v's Kind is not Interface.
 func (v Value) InterfaceData() [2]uintptr {
+       // TODO: deprecate this
        v.mustBe(Interface)
        // We treat this as a read operation, so we allow
        // it even for unexported data, because the caller
        // has to import "unsafe" to turn it into something
        // that can be abused.
        // Interface value is always bigger than a word; assume flagIndir.
-       return *(*[2]uintptr)(v.val)
+       return *(*[2]uintptr)(v.ptr)
 }
 
 // IsNil returns true if v is a nil value.
@@ -1075,7 +1169,7 @@ func (v Value) IsNil() bool {
                if v.flag&flagMethod != 0 {
                        return false
                }
-               ptr := v.val
+               ptr := v.ptr
                if v.flag&flagIndir != 0 {
                        ptr = *(*unsafe.Pointer)(ptr)
                }
@@ -1083,7 +1177,7 @@ func (v Value) IsNil() bool {
        case Interface, Slice:
                // Both interface and slice are nil if first word is 0.
                // Both are always bigger than a word; assume flagIndir.
-               return *(*unsafe.Pointer)(v.val) == nil
+               return *(*unsafe.Pointer)(v.ptr) == nil
        }
        panic(&ValueError{"reflect.Value.IsNil", k})
 }
@@ -1112,15 +1206,15 @@ func (v Value) Len() int {
                tt := (*arrayType)(unsafe.Pointer(v.typ))
                return int(tt.len)
        case Chan:
-               return chanlen(v.iword())
+               return chanlen(v.pointer())
        case Map:
-               return maplen(v.iword())
+               return maplen(v.pointer())
        case Slice:
                // Slice is bigger than a word; assume flagIndir.
-               return (*SliceHeader)(v.val).Len
+               return (*sliceHeader)(v.ptr).Len
        case String:
                // String is bigger than a word; assume flagIndir.
-               return (*StringHeader)(v.val).Len
+               return (*stringHeader)(v.ptr).Len
        }
        panic(&ValueError{"reflect.Value.Len", k})
 }
@@ -1142,17 +1236,32 @@ func (v Value) MapIndex(key Value) Value {
        // of unexported fields.
        key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
 
-       word, ok := mapaccess(v.typ, v.iword(), key.iword())
-       if !ok {
+       var k unsafe.Pointer
+       if key.flag&flagIndir != 0 {
+               k = key.ptr
+       } else if key.typ.pointers() {
+               k = unsafe.Pointer(&key.ptr)
+       } else {
+               k = unsafe.Pointer(&key.scalar)
+       }
+       e := mapaccess(v.typ, v.pointer(), k)
+       if e == nil {
                return Value{}
        }
        typ := tt.elem
        fl := (v.flag | key.flag) & flagRO
+       fl |= flag(typ.Kind()) << flagKindShift
        if typ.size > ptrSize {
-               fl |= flagIndir
+               // Copy result so future changes to the map
+               // won't change the underlying value.
+               c := unsafe_New(typ)
+               memmove(c, e, typ.size)
+               return Value{typ, c, 0, fl | flagIndir}
+       } else if typ.pointers() {
+               return Value{typ, *(*unsafe.Pointer)(e), 0, fl}
+       } else {
+               return Value{typ, nil, loadScalar(e, typ.size), fl}
        }
-       fl |= flag(typ.Kind()) << flagKindShift
-       return Value{typ, unsafe.Pointer(word), fl}
 }
 
 // MapKeys returns a slice containing all the keys present in the map,
@@ -1164,13 +1273,9 @@ func (v Value) MapKeys() []Value {
        tt := (*mapType)(unsafe.Pointer(v.typ))
        keyType := tt.key
 
-       fl := v.flag & flagRO
-       fl |= flag(keyType.Kind()) << flagKindShift
-       if keyType.size > ptrSize {
-               fl |= flagIndir
-       }
+       fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift
 
-       m := v.iword()
+       m := v.pointer()
        mlen := int(0)
        if m != nil {
                mlen = maplen(m)
@@ -1179,11 +1284,24 @@ func (v Value) MapKeys() []Value {
        a := make([]Value, mlen)
        var i int
        for i = 0; i < len(a); i++ {
-               keyWord, ok := mapiterkey(it)
-               if !ok {
+               key := mapiterkey(it)
+               if key == nil {
+                       // Someone deleted an entry from the map since we
+                       // called maplen above.  It's a data race, but nothing
+                       // we can do about it.
                        break
                }
-               a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
+               if keyType.size > ptrSize {
+                       // Copy result so future changes to the map
+                       // won't change the underlying value.
+                       c := unsafe_New(keyType)
+                       memmove(c, key, keyType.size)
+                       a[i] = Value{keyType, c, 0, fl | flagIndir}
+               } else if keyType.pointers() {
+                       a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl}
+               } else {
+                       a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl}
+               }
                mapiternext(it)
        }
        return a[:i]
@@ -1206,7 +1324,7 @@ func (v Value) Method(i int) Value {
        fl := v.flag & (flagRO | flagIndir)
        fl |= flag(Func) << flagKindShift
        fl |= flag(i)<<flagMethodShift | flagMethod
-       return Value{v.typ, v.val, fl}
+       return Value{v.typ, v.ptr, v.scalar, fl}
 }
 
 // NumMethod returns the number of methods in the value's method set.
@@ -1316,15 +1434,16 @@ func (v Value) OverflowUint(x uint64) bool {
 // code pointer, but not necessarily enough to identify a
 // single function uniquely. The only guarantee is that the
 // result is zero if and only if v is a nil func Value.
+//
+// If v's Kind is Slice, the returned pointer is to the first
+// element of the slice.  If the slice is nil the returned value
+// is 0.  If the slice is empty but non-nil the return value is non-zero.
 func (v Value) Pointer() uintptr {
+       // TODO: deprecate
        k := v.kind()
        switch k {
        case Chan, Map, Ptr, UnsafePointer:
-               p := v.val
-               if v.flag&flagIndir != 0 {
-                       p = *(*unsafe.Pointer)(p)
-               }
-               return uintptr(p)
+               return uintptr(v.pointer())
        case Func:
                if v.flag&flagMethod != 0 {
                        // As the doc comment says, the returned pointer is an
@@ -1336,10 +1455,7 @@ func (v Value) Pointer() uintptr {
                        f := methodValueCall
                        return **(**uintptr)(unsafe.Pointer(&f))
                }
-               p := v.val
-               if v.flag&flagIndir != 0 {
-                       p = *(*unsafe.Pointer)(p)
-               }
+               p := v.pointer()
                // Non-nil func value points at data block.
                // First word of data block is actual code.
                if p != nil {
@@ -1348,7 +1464,7 @@ func (v Value) Pointer() uintptr {
                return uintptr(p)
 
        case Slice:
-               return (*SliceHeader)(v.val).Data
+               return (*SliceHeader)(v.ptr).Data
        }
        panic(&ValueError{"reflect.Value.Pointer", k})
 }
@@ -1371,14 +1487,9 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
        if ChanDir(tt.dir)&RecvDir == 0 {
                panic("reflect: recv on send-only channel")
        }
-       word, selected, ok := chanrecv(v.typ, v.iword(), nb)
+       word, selected, ok := chanrecv(v.typ, v.pointer(), nb)
        if selected {
-               typ := tt.elem
-               fl := flag(typ.Kind()) << flagKindShift
-               if typ.size > ptrSize {
-                       fl |= flagIndir
-               }
-               val = Value{typ, unsafe.Pointer(word), fl}
+               val = fromIword(tt.elem, word, 0)
        }
        return
 }
@@ -1401,7 +1512,7 @@ func (v Value) send(x Value, nb bool) (selected bool) {
        }
        x.mustBeExported()
        x = x.assignTo("reflect.Value.Send", tt.elem, nil)
-       return chansend(v.typ, v.iword(), x.iword(), nb)
+       return chansend(v.typ, v.pointer(), x.iword(), nb)
 }
 
 // Set assigns x to the value v.
@@ -1412,13 +1523,15 @@ func (v Value) Set(x Value) {
        x.mustBeExported() // do not let unexported x leak
        var target *interface{}
        if v.kind() == Interface {
-               target = (*interface{})(v.val)
+               target = (*interface{})(v.ptr)
        }
        x = x.assignTo("reflect.Set", v.typ, target)
        if x.flag&flagIndir != 0 {
-               memmove(v.val, x.val, v.typ.size)
+               memmove(v.ptr, x.ptr, v.typ.size)
+       } else if x.typ.pointers() {
+               *(*unsafe.Pointer)(v.ptr) = x.ptr
        } else {
-               storeIword(v.val, iword(x.val), v.typ.size)
+               memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size)
        }
 }
 
@@ -1427,7 +1540,7 @@ func (v Value) Set(x Value) {
 func (v Value) SetBool(x bool) {
        v.mustBeAssignable()
        v.mustBe(Bool)
-       *(*bool)(v.val) = x
+       *(*bool)(v.ptr) = x
 }
 
 // SetBytes sets v's underlying value.
@@ -1438,7 +1551,7 @@ func (v Value) SetBytes(x []byte) {
        if v.typ.Elem().Kind() != Uint8 {
                panic("reflect.Value.SetBytes of non-byte slice")
        }
-       *(*[]byte)(v.val) = x
+       *(*[]byte)(v.ptr) = x
 }
 
 // setRunes sets v's underlying value.
@@ -1449,7 +1562,7 @@ func (v Value) setRunes(x []rune) {
        if v.typ.Elem().Kind() != Int32 {
                panic("reflect.Value.setRunes of non-rune slice")
        }
-       *(*[]rune)(v.val) = x
+       *(*[]rune)(v.ptr) = x
 }
 
 // SetComplex sets v's underlying value to x.
@@ -1460,9 +1573,9 @@ func (v Value) SetComplex(x complex128) {
        default:
                panic(&ValueError{"reflect.Value.SetComplex", k})
        case Complex64:
-               *(*complex64)(v.val) = complex64(x)
+               *(*complex64)(v.ptr) = complex64(x)
        case Complex128:
-               *(*complex128)(v.val) = x
+               *(*complex128)(v.ptr) = x
        }
 }
 
@@ -1474,9 +1587,9 @@ func (v Value) SetFloat(x float64) {
        default:
                panic(&ValueError{"reflect.Value.SetFloat", k})
        case Float32:
-               *(*float32)(v.val) = float32(x)
+               *(*float32)(v.ptr) = float32(x)
        case Float64:
-               *(*float64)(v.val) = x
+               *(*float64)(v.ptr) = x
        }
 }
 
@@ -1488,15 +1601,15 @@ func (v Value) SetInt(x int64) {
        default:
                panic(&ValueError{"reflect.Value.SetInt", k})
        case Int:
-               *(*int)(v.val) = int(x)
+               *(*int)(v.ptr) = int(x)
        case Int8:
-               *(*int8)(v.val) = int8(x)
+               *(*int8)(v.ptr) = int8(x)
        case Int16:
-               *(*int16)(v.val) = int16(x)
+               *(*int16)(v.ptr) = int16(x)
        case Int32:
-               *(*int32)(v.val) = int32(x)
+               *(*int32)(v.ptr) = int32(x)
        case Int64:
-               *(*int64)(v.val) = x
+               *(*int64)(v.ptr) = x
        }
 }
 
@@ -1506,7 +1619,7 @@ func (v Value) SetInt(x int64) {
 func (v Value) SetLen(n int) {
        v.mustBeAssignable()
        v.mustBe(Slice)
-       s := (*SliceHeader)(v.val)
+       s := (*sliceHeader)(v.ptr)
        if n < 0 || n > int(s.Cap) {
                panic("reflect: slice length out of range in SetLen")
        }
@@ -1519,7 +1632,7 @@ func (v Value) SetLen(n int) {
 func (v Value) SetCap(n int) {
        v.mustBeAssignable()
        v.mustBe(Slice)
-       s := (*SliceHeader)(v.val)
+       s := (*sliceHeader)(v.ptr)
        if n < int(s.Len) || n > int(s.Cap) {
                panic("reflect: slice capacity out of range in SetCap")
        }
@@ -1537,11 +1650,29 @@ func (v Value) SetMapIndex(key, val Value) {
        key.mustBeExported()
        tt := (*mapType)(unsafe.Pointer(v.typ))
        key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
-       if val.typ != nil {
-               val.mustBeExported()
-               val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+       var k unsafe.Pointer
+       if key.flag&flagIndir != 0 {
+               k = key.ptr
+       } else if key.typ.pointers() {
+               k = unsafe.Pointer(&key.ptr)
+       } else {
+               k = unsafe.Pointer(&key.scalar)
+       }
+       if val.typ == nil {
+               mapdelete(v.typ, v.pointer(), k)
+               return
+       }
+       val.mustBeExported()
+       val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+       var e unsafe.Pointer
+       if val.flag&flagIndir != 0 {
+               e = val.ptr
+       } else if val.typ.pointers() {
+               e = unsafe.Pointer(&val.ptr)
+       } else {
+               e = unsafe.Pointer(&val.scalar)
        }
-       mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil)
+       mapassign(v.typ, v.pointer(), k, e)
 }
 
 // SetUint sets v's underlying value to x.
@@ -1552,17 +1683,17 @@ func (v Value) SetUint(x uint64) {
        default:
                panic(&ValueError{"reflect.Value.SetUint", k})
        case Uint:
-               *(*uint)(v.val) = uint(x)
+               *(*uint)(v.ptr) = uint(x)
        case Uint8:
-               *(*uint8)(v.val) = uint8(x)
+               *(*uint8)(v.ptr) = uint8(x)
        case Uint16:
-               *(*uint16)(v.val) = uint16(x)
+               *(*uint16)(v.ptr) = uint16(x)
        case Uint32:
-               *(*uint32)(v.val) = uint32(x)
+               *(*uint32)(v.ptr) = uint32(x)
        case Uint64:
-               *(*uint64)(v.val) = x
+               *(*uint64)(v.ptr) = x
        case Uintptr:
-               *(*uintptr)(v.val) = uintptr(x)
+               *(*uintptr)(v.ptr) = uintptr(x)
        }
 }
 
@@ -1571,7 +1702,7 @@ func (v Value) SetUint(x uint64) {
 func (v Value) SetPointer(x unsafe.Pointer) {
        v.mustBeAssignable()
        v.mustBe(UnsafePointer)
-       *(*unsafe.Pointer)(v.val) = x
+       *(*unsafe.Pointer)(v.ptr) = x
 }
 
 // SetString sets v's underlying value to x.
@@ -1579,7 +1710,7 @@ func (v Value) SetPointer(x unsafe.Pointer) {
 func (v Value) SetString(x string) {
        v.mustBeAssignable()
        v.mustBe(String)
-       *(*string)(v.val) = x
+       *(*string)(v.ptr) = x
 }
 
 // Slice returns v[i:j].
@@ -1602,24 +1733,21 @@ func (v Value) Slice(i, j int) Value {
                tt := (*arrayType)(unsafe.Pointer(v.typ))
                cap = int(tt.len)
                typ = (*sliceType)(unsafe.Pointer(tt.slice))
-               base = v.val
+               base = v.ptr
 
        case Slice:
                typ = (*sliceType)(unsafe.Pointer(v.typ))
-               s := (*SliceHeader)(v.val)
+               s := (*sliceHeader)(v.ptr)
                base = unsafe.Pointer(s.Data)
                cap = s.Cap
 
        case String:
-               s := (*StringHeader)(v.val)
+               s := (*stringHeader)(v.ptr)
                if i < 0 || j < i || j > s.Len {
                        panic("reflect.Value.Slice: string slice index out of bounds")
                }
-               var x string
-               val := (*StringHeader)(unsafe.Pointer(&x))
-               val.Data = s.Data + uintptr(i)
-               val.Len = j - i
-               return Value{v.typ, unsafe.Pointer(&x), v.flag}
+               t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+               return Value{v.typ, unsafe.Pointer(&t), 0, v.flag}
        }
 
        if i < 0 || j < i || j > cap {
@@ -1629,14 +1757,14 @@ func (v Value) Slice(i, j int) Value {
        // Declare slice so that gc can see the base pointer in it.
        var x []unsafe.Pointer
 
-       // Reinterpret as *SliceHeader to edit.
-       s := (*SliceHeader)(unsafe.Pointer(&x))
-       s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+       // Reinterpret as *sliceHeader to edit.
+       s := (*sliceHeader)(unsafe.Pointer(&x))
+       s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
        s.Len = j - i
        s.Cap = cap - i
 
        fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
-       return Value{typ.common(), unsafe.Pointer(&x), fl}
+       return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
 }
 
 // Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
@@ -1659,12 +1787,12 @@ func (v Value) Slice3(i, j, k int) Value {
                tt := (*arrayType)(unsafe.Pointer(v.typ))
                cap = int(tt.len)
                typ = (*sliceType)(unsafe.Pointer(tt.slice))
-               base = v.val
+               base = v.ptr
 
        case Slice:
                typ = (*sliceType)(unsafe.Pointer(v.typ))
-               s := (*SliceHeader)(v.val)
-               base = unsafe.Pointer(s.Data)
+               s := (*sliceHeader)(v.ptr)
+               base = s.Data
                cap = s.Cap
        }
 
@@ -1676,14 +1804,14 @@ func (v Value) Slice3(i, j, k int) Value {
        // can see the base pointer in it.
        var x []unsafe.Pointer
 
-       // Reinterpret as *SliceHeader to edit.
-       s := (*SliceHeader)(unsafe.Pointer(&x))
-       s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+       // Reinterpret as *sliceHeader to edit.
+       s := (*sliceHeader)(unsafe.Pointer(&x))
+       s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
        s.Len = j - i
        s.Cap = k - i
 
        fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
-       return Value{typ.common(), unsafe.Pointer(&x), fl}
+       return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
 }
 
 // String returns the string v's underlying value, as a string.
@@ -1695,7 +1823,7 @@ func (v Value) String() string {
        case Invalid:
                return "<invalid Value>"
        case String:
-               return *(*string)(v.val)
+               return *(*string)(v.ptr)
        }
        // If you call String on a reflect.Value of other type, it's better to
        // print something than to panic. Useful in debugging.
@@ -1761,11 +1889,11 @@ func (v Value) Uint() uint64 {
        k := v.kind()
        var p unsafe.Pointer
        if v.flag&flagIndir != 0 {
-               p = v.val
+               p = v.ptr
        } else {
-               // The escape analysis is good enough that &v.val
+               // The escape analysis is good enough that &v.scalar
                // does not trigger a heap allocation.
-               p = unsafe.Pointer(&v.val)
+               p = unsafe.Pointer(&v.scalar)
        }
        switch k {
        case Uint:
@@ -1788,13 +1916,14 @@ func (v Value) Uint() uint64 {
 // It is for advanced clients that also import the "unsafe" package.
 // It panics if v is not addressable.
 func (v Value) UnsafeAddr() uintptr {
+       // TODO: deprecate
        if v.typ == nil {
                panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
        }
        if v.flag&flagAddr == 0 {
                panic("reflect.Value.UnsafeAddr of unaddressable value")
        }
-       return uintptr(v.val)
+       return uintptr(v.ptr)
 }
 
 // StringHeader is the runtime representation of a string.
@@ -1808,6 +1937,12 @@ type StringHeader struct {
        Len  int
 }
 
+// stringHeader is a safe version of StringHeader used within this package.
+type stringHeader struct {
+       Data unsafe.Pointer
+       Len  int
+}
+
 // SliceHeader is the runtime representation of a slice.
 // It cannot be used safely or portably and its representation may
 // change in a later release.
@@ -1820,6 +1955,13 @@ type SliceHeader struct {
        Cap  int
 }
 
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+       Data unsafe.Pointer
+       Len  int
+       Cap  int
+}
+
 func typesMustMatch(what string, t1, t2 Type) {
        if t1 != t2 {
                panic(what + ": " + t1.String() + " != " + t2.String())
@@ -1908,6 +2050,8 @@ func Copy(dst, src Value) int {
 
        // If sk is an in-line array, cannot take its address.
        // Instead, copy element by element.
+       // TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar))
+       // if we teach the compiler that ptrs don't escape from memmove.
        if src.flag&flagIndir == 0 {
                for i := 0; i < n; i++ {
                        dst.Index(i).Set(src.Index(i))
@@ -1918,14 +2062,14 @@ func Copy(dst, src Value) int {
        // Copy via memmove.
        var da, sa unsafe.Pointer
        if dk == Array {
-               da = dst.val
+               da = dst.ptr
        } else {
-               da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
+               da = (*sliceHeader)(dst.ptr).Data
        }
        if sk == Array {
-               sa = src.val
+               sa = src.ptr
        } else {
-               sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
+               sa = (*sliceHeader)(src.ptr).Data
        }
        memmove(da, sa, uintptr(n)*de.Size())
        return n
@@ -2056,12 +2200,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
        chosen, word, recvOK := rselect(runcases)
        if runcases[chosen].dir == uintptr(SelectRecv) {
                tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
-               typ := tt.elem
-               fl := flag(typ.Kind()) << flagKindShift
-               if typ.size > ptrSize {
-                       fl |= flagIndir
-               }
-               recv = Value{typ, unsafe.Pointer(word), fl}
+               recv = fromIword(tt.elem, word, 0)
        }
        return chosen, recv, recvOK
 }
@@ -2090,16 +2229,8 @@ func MakeSlice(typ Type, len, cap int) Value {
                panic("reflect.MakeSlice: len > cap")
        }
 
-       // Declare slice so that gc can see the base pointer in it.
-       var x []unsafe.Pointer
-
-       // Reinterpret as *SliceHeader to edit.
-       s := (*SliceHeader)(unsafe.Pointer(&x))
-       s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap))
-       s.Len = len
-       s.Cap = cap
-
-       return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
+       s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+       return Value{typ.common(), unsafe.Pointer(&s), 0, flagIndir | flag(Slice)<<flagKindShift}
 }
 
 // MakeChan creates a new channel with the specified type and buffer size.
@@ -2114,7 +2245,7 @@ func MakeChan(typ Type, buffer int) Value {
                panic("reflect.MakeChan: unidirectional channel type")
        }
        ch := makechan(typ.(*rtype), uint64(buffer))
-       return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift}
+       return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift}
 }
 
 // MakeMap creates a new map of the specified type.
@@ -2123,7 +2254,7 @@ func MakeMap(typ Type) Value {
                panic("reflect.MakeMap of non-map type")
        }
        m := makemap(typ.(*rtype))
-       return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
+       return Value{typ.common(), m, 0, flag(Map) << flagKindShift}
 }
 
 // Indirect returns the value that v points to.
@@ -2144,21 +2275,13 @@ func ValueOf(i interface{}) Value {
        }
 
        // TODO(rsc): Eliminate this terrible hack.
-       // In the call to packValue, eface.typ doesn't escape,
-       // and eface.word is an integer.  So it looks like
-       // i (= eface) doesn't escape.  But really it does,
-       // because eface.word is actually a pointer.
+       // In the call to unpackEface, i.typ doesn't escape,
+       // and i.word is an integer.  So it looks like
+       // i doesn't escape.  But really it does,
+       // because i.word is actually a pointer.
        escapes(i)
 
-       // For an interface value with the noAddr bit set,
-       // the representation is identical to an empty interface.
-       eface := *(*emptyInterface)(unsafe.Pointer(&i))
-       typ := eface.typ
-       fl := flag(typ.Kind()) << flagKindShift
-       if typ.size > ptrSize {
-               fl |= flagIndir
-       }
-       return Value{typ, unsafe.Pointer(eface.word), fl}
+       return unpackEface(i)
 }
 
 // Zero returns a Value representing the zero value for the specified type.
@@ -2173,9 +2296,9 @@ func Zero(typ Type) Value {
        t := typ.common()
        fl := flag(t.Kind()) << flagKindShift
        if t.size <= ptrSize {
-               return Value{t, nil, fl}
+               return Value{t, nil, 0, fl}
        }
-       return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
+       return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
 }
 
 // New returns a Value representing a pointer to a new zero value
@@ -2186,14 +2309,14 @@ func New(typ Type) Value {
        }
        ptr := unsafe_New(typ.(*rtype))
        fl := flag(Ptr) << flagKindShift
-       return Value{typ.common().ptrTo(), ptr, fl}
+       return Value{typ.common().ptrTo(), ptr, 0, fl}
 }
 
 // NewAt returns a Value representing a pointer to a value of the
 // specified type, using p as that pointer.
 func NewAt(typ Type, p unsafe.Pointer) Value {
        fl := flag(Ptr) << flagKindShift
-       return Value{typ.common().ptrTo(), p, fl}
+       return Value{typ.common().ptrTo(), p, 0, fl}
 }
 
 // assignTo returns a value v that can be assigned directly to typ.
@@ -2211,7 +2334,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
                v.typ = dst
                fl := v.flag & (flagRO | flagAddr | flagIndir)
                fl |= flag(dst.Kind()) << flagKindShift
-               return Value{dst, v.val, fl}
+               return Value{dst, v.ptr, v.scalar, fl}
 
        case implements(dst, v.typ):
                if target == nil {
@@ -2223,7 +2346,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
                } else {
                        ifaceE2I(dst, x, unsafe.Pointer(target))
                }
-               return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+               return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift}
        }
 
        // Failed.
@@ -2335,20 +2458,20 @@ func makeInt(f flag, bits uint64, t Type) Value {
                // Assume ptrSize >= 4, so this must be uint64.
                ptr := unsafe_New(typ)
                *(*uint64)(unsafe.Pointer(ptr)) = bits
-               return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+               return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
        }
-       var w iword
+       var s uintptr
        switch typ.size {
        case 1:
-               *(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
+               *(*uint8)(unsafe.Pointer(&s)) = uint8(bits)
        case 2:
-               *(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
+               *(*uint16)(unsafe.Pointer(&s)) = uint16(bits)
        case 4:
-               *(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
+               *(*uint32)(unsafe.Pointer(&s)) = uint32(bits)
        case 8:
-               *(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
+               *(*uint64)(unsafe.Pointer(&s)) = uint64(bits)
        }
-       return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+       return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 // makeFloat returns a Value of type t equal to v (possibly truncated to float32),
@@ -2359,17 +2482,17 @@ func makeFloat(f flag, v float64, t Type) Value {
                // Assume ptrSize >= 4, so this must be float64.
                ptr := unsafe_New(typ)
                *(*float64)(unsafe.Pointer(ptr)) = v
-               return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+               return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
        }
 
-       var w iword
+       var s uintptr
        switch typ.size {
        case 4:
-               *(*float32)(unsafe.Pointer(&w)) = float32(v)
+               *(*float32)(unsafe.Pointer(&s)) = float32(v)
        case 8:
-               *(*float64)(unsafe.Pointer(&w)) = v
+               *(*float64)(unsafe.Pointer(&s)) = v
        }
-       return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+       return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 // makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
@@ -2384,13 +2507,13 @@ func makeComplex(f flag, v complex128, t Type) Value {
                case 16:
                        *(*complex128)(unsafe.Pointer(ptr)) = v
                }
-               return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+               return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
        }
 
        // Assume ptrSize <= 8 so this must be complex64.
-       var w iword
-       *(*complex64)(unsafe.Pointer(&w)) = complex64(v)
-       return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+       var s uintptr
+       *(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+       return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 func makeString(f flag, v string, t Type) Value {
@@ -2493,15 +2616,15 @@ func cvtStringRunes(v Value, t Type) Value {
 func cvtDirect(v Value, typ Type) Value {
        f := v.flag
        t := typ.common()
-       val := v.val
+       ptr := v.ptr
        if f&flagAddr != 0 {
                // indirect, mutable word - make a copy
-               ptr := unsafe_New(t)
-               memmove(ptr, val, t.size)
-               val = ptr
+               c := unsafe_New(t)
+               memmove(c, ptr, t.size)
+               ptr = c
                f &^= flagAddr
        }
-       return Value{t, val, v.flag&flagRO | f}
+       return Value{t, ptr, v.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f?
 }
 
 // convertOp: concrete -> interface
@@ -2513,7 +2636,7 @@ func cvtT2I(v Value, typ Type) Value {
        } else {
                ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
        }
-       return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+       return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
 }
 
 // convertOp: interface -> interface
@@ -2527,20 +2650,21 @@ func cvtI2I(v Value, typ Type) Value {
 }
 
 // implemented in ../pkg/runtime
-func chancap(ch iword) int
-func chanclose(ch iword)
-func chanlen(ch iword) int
-func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
-func chansend(t *rtype, ch iword, val iword, nb bool) bool
-
-func makechan(typ *rtype, size uint64) (ch iword)
-func makemap(t *rtype) (m iword)
-func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
-func mapassign(t *rtype, m iword, key, val iword, ok bool)
-func mapiterinit(t *rtype, m iword) *byte
-func mapiterkey(it *byte) (key iword, ok bool)
-func mapiternext(it *byte)
-func maplen(m iword) int
+func chancap(ch unsafe.Pointer) int
+func chanclose(ch unsafe.Pointer)
+func chanlen(ch unsafe.Pointer) int
+func chanrecv(t *rtype, ch unsafe.Pointer, nb bool) (val iword, selected, received bool)
+func chansend(t *rtype, ch unsafe.Pointer, val iword, nb bool) bool
+
+func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
+func makemap(t *rtype) (m unsafe.Pointer)
+func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+func mapiternext(it unsafe.Pointer)
+func maplen(m unsafe.Pointer) int
 
 func call(fn, arg unsafe.Pointer, n uint32)
 func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
index e42121b044248befa04b791661645e8b363d1e2e..5d625c15a86426de6427bf9f64f1ef934a4e1c15 100644 (file)
@@ -1060,40 +1060,16 @@ runtime·mapaccess2(MapType *t, Hmap *h, byte *ak, byte *av, bool pres)
 }
 
 // For reflect:
-//     func mapaccess(t type, h map, key iword) (val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+//     func mapaccess(t type, h map, key unsafe.Pointer) (val unsafe.Pointer)
 void
-reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
+reflect·mapaccess(MapType *t, Hmap *h, byte *key, byte *val)
 {
-       byte *ak, *av, *r;
-
-       if(raceenabled && h != nil)
+       if(raceenabled && h != nil) {
                runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
-
-       if(t->key->size <= sizeof(key))
-               ak = (byte*)&key;
-       else
-               ak = (byte*)key;
-
-       av = hash_lookup(t, h, &ak);
-       if(av == nil) {
-               val = 0;
-               pres = false;
-       } else {
-               if(t->elem->size <= sizeof(val)) {
-                       val = 0; // clear high-order bits if value is smaller than a word
-                       t->elem->alg->copy(t->elem->size, &val, av);
-               } else {
-                       // make a copy because reflect can hang on to result indefinitely
-                       r = runtime·cnew(t->elem);
-                       t->elem->alg->copy(t->elem->size, r, av);
-                       val = (uintptr)r;
-               }
-               pres = true;
+               runtime·racereadrangepc(key, t->key->size, runtime·getcallerpc(&t), reflect·mapaccess);
        }
+       val = hash_lookup(t, h, &key);
        FLUSH(&val);
-       FLUSH(&pres);
 }
 
 // mapassign1(mapType *type, hmap *map[any]any, key *any, val *any);
@@ -1148,50 +1124,50 @@ runtime·mapdelete(MapType *t, Hmap *h, byte *ak)
 }
 
 // For reflect:
-//     func mapassign(t type h map, key, val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+//     func mapassign(t type h map, key, val unsafe.Pointer)
 void
-reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
+reflect·mapassign(MapType *t, Hmap *h, byte *key, byte *val)
 {
-       byte *ak, *av;
-
        if(h == nil)
                runtime·panicstring("assignment to entry in nil map");
-       if(raceenabled)
+       if(raceenabled) {
                runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
-       if(t->key->size <= sizeof(key))
-               ak = (byte*)&key;
-       else
-               ak = (byte*)key;
-       if(!pres) {
-               hash_remove(t, h, ak);
-
-               if(debug) {
-                       runtime·prints("mapassign: map=");
-                       runtime·printpointer(h);
-                       runtime·prints("; key=");
-                       t->key->alg->print(t->key->size, ak);
-                       runtime·prints("; val=nil");
-                       runtime·prints("\n");
-               }
-       } else {
-               if(t->elem->size <= sizeof(val))
-                       av = (byte*)&val;
-               else
-                       av = (byte*)val;
-
-               hash_insert(t, h, ak, av);
-
-               if(debug) {
-                       runtime·prints("mapassign: map=");
-                       runtime·printpointer(h);
-                       runtime·prints("; key=");
-                       t->key->alg->print(t->key->size, ak);
-                       runtime·prints("; val=");
-                       t->elem->alg->print(t->elem->size, av);
-                       runtime·prints("\n");
-               }
+               runtime·racereadrangepc(key, t->key->size, runtime·getcallerpc(&t), reflect·mapassign);
+               runtime·racereadrangepc(val, t->elem->size, runtime·getcallerpc(&t), reflect·mapassign);
+       }
+
+       hash_insert(t, h, key, val);
+
+       if(debug) {
+               runtime·prints("mapassign: map=");
+               runtime·printpointer(h);
+               runtime·prints("; key=");
+               t->key->alg->print(t->key->size, key);
+               runtime·prints("; val=");
+               t->elem->alg->print(t->elem->size, val);
+               runtime·prints("\n");
+       }
+}
+
+// For reflect:
+//     func mapdelete(t type h map, key unsafe.Pointer)
+void
+reflect·mapdelete(MapType *t, Hmap *h, byte *key)
+{
+       if(h == nil)
+               runtime·panicstring("delete from nil map");
+       if(raceenabled) {
+               runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
+               runtime·racereadrangepc(key, t->key->size, runtime·getcallerpc(&t), reflect·mapassign);
+       }
+       hash_remove(t, h, key);
+
+       if(debug) {
+               runtime·prints("mapdelete: map=");
+               runtime·printpointer(h);
+               runtime·prints("; key=");
+               t->key->alg->print(t->key->size, key);
+               runtime·prints("\n");
        }
 }
 
@@ -1254,34 +1230,12 @@ reflect·mapiternext(struct hash_iter *it)
 }
 
 // For reflect:
-//     func mapiterkey(h map) (key iword, ok bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
+//     func mapiterkey(h map) (key unsafe.Pointer)
 void
-reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
+reflect·mapiterkey(struct hash_iter *it, byte *key)
 {
-       byte *res, *r;
-       Type *tkey;
-
-       res = it->key;
-       if(res == nil) {
-               key = 0;
-               ok = false;
-       } else {
-               tkey = it->t->key;
-               if(tkey->size <= sizeof(key)) {
-                       key = 0; // clear high-order bits if value is smaller than a word
-                       tkey->alg->copy(tkey->size, (byte*)&key, res);
-               } else {
-                       // make a copy because reflect can hang on to result indefinitely
-                       r = runtime·cnew(tkey);
-                       tkey->alg->copy(tkey->size, r, res);
-                       key = (uintptr)r;
-               }
-               ok = true;
-       }
+       key = it->key;
        FLUSH(&key);
-       FLUSH(&ok);
 }
 
 // For reflect: