diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go index 9b1b7d5721b..0e61fdea7a3 100644 --- a/src/pkg/reflect/makefunc.go +++ b/src/pkg/reflect/makefunc.go @@ -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) & 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 { - // Have indirect but want direct word. - return loadIword(v.val, v.typ.size) + t := v.typ + if t == nil { + return iword(nil) } - return iword(v.val) + if v.flag&flagIndir != 0 { + if v.typ.size > ptrSize { + return iword(v.ptr) + } + // Have indirect but want direct word. + 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.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)<>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())< 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<= 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) + })(v.ptr) } - // 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) - } - - 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 - if typ.size > ptrSize { - fl |= flagIndir - } fl |= flag(typ.Kind()) << flagKindShift - return Value{typ, unsafe.Pointer(word), fl} + if typ.size > ptrSize { + // 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} + } } // 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())< 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)< 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) } - mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil) + 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.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)<" 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)< 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)<= 4, so this must be uint64. ptr := unsafe_New(typ) *(*uint64)(unsafe.Pointer(ptr)) = bits - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<= 4, so this must be float64. ptr := unsafe_New(typ) *(*float64)(unsafe.Pointer(ptr)) = v - return Value{typ, ptr, f | flagIndir | flag(typ.Kind())< 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)< 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 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 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 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) diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c index e42121b0442..5d625c15a86 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -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); + runtime·racereadrangepc(key, t->key->size, runtime·getcallerpc(&t), reflect·mapassign); + runtime·racereadrangepc(val, t->elem->size, runtime·getcallerpc(&t), reflect·mapassign); + } - 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, key, 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, key); + runtime·prints("; val="); + t->elem->alg->print(t->elem->size, val); + runtime·prints("\n"); + } +} - 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"); - } +// 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: