if off&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
- bv.Set(int32(off / int64(Widthptr))) // pointer in first slot
+ // The first word of an interface is a pointer, but we don't
+ // treat it as such.
+ // 1. If it is a non-empty interface, the pointer points to an itab
+ // which is always in persistentalloc space.
+ // 2. If it is an empty interface, the pointer points to a _type.
+ // a. If it is a compile-time-allocated type, it points into
+ // the read-only data section.
+ // b. If it is a reflect-allocated type, it points into the Go heap.
+ // Reflect is responsible for keeping a reference to
+ // the underlying type so it won't be GCd.
+ // If we ever have a moving GC, we need to change this for 2b (as
+ // well as scan itabs to update their itab._type fields).
bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot
case TSLICE:
// struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true:
// struct { Type *type; void *data; }
- clobberPtr(b, v, offset)
+ // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
clobberPtr(b, v, offset+int64(Widthptr))
case TSLICE:
case TINTER:
// struct { Itab *tab; void *data; } or
// struct { Type *type; void *data; }
+ // Note: see comment in plive.go:onebitwalktype1.
return 2 * int64(Widthptr)
case TSLICE:
p.w.Ptr(offset / int64(Widthptr))
case TINTER:
- p.w.Ptr(offset / int64(Widthptr))
+ // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
p.w.Ptr(offset/int64(Widthptr) + 1)
case TSLICE:
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
+ u := types.Types[TUINTPTR]
t := types.NewPtr(types.Types[TUINT8])
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this interface up into two separate variables.
if n.Type.IsEmptyInterface() {
f = ".type"
}
- c := e.splitSlot(&name, f, 0, t)
- d := e.splitSlot(&name, ".data", t.Size(), t)
+ c := e.splitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
+ d := e.splitSlot(&name, ".data", u.Size(), t)
return c, d
}
// Return the two parts of the larger variable.
- return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
+ return ssa.LocalSlot{N: n, Type: u, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
}
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
}
func decomposeInterfacePhi(v *Value) {
+ uintptrType := v.Block.Func.Config.Types.Uintptr
ptrType := v.Block.Func.Config.Types.BytePtr
- itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
+ itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType)
data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
for _, a := range v.Args {
- itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, a))
+ itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a))
data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
}
v.reset(OpIMake)
(Load <t> ptr mem) && t.IsInterface() ->
(IMake
- (Load <typ.BytePtr> ptr mem)
+ (Load <typ.Uintptr> ptr mem)
(Load <typ.BytePtr>
(OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr)
mem))
// interface ops
(ConstInterface) ->
(IMake
- (ConstNil <typ.BytePtr>)
+ (ConstNil <typ.Uintptr>)
(ConstNil <typ.BytePtr>))
(NilCheck (GetG mem) mem) -> mem
(Arg {n} [off]) && v.Type.IsInterface() ->
(IMake
- (Arg <typ.BytePtr> {n} [off])
+ (Arg <typ.Uintptr> {n} [off])
(Arg <typ.BytePtr> {n} [off+config.PtrSize]))
(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 ->
// Interfaces
{name: "IMake", argLength: 2}, // arg0=itab, arg1=data
- {name: "ITab", argLength: 1, typ: "BytePtr"}, // arg0=interface, returns itable field
+ {name: "ITab", argLength: 1, typ: "Uintptr"}, // arg0=interface, returns itable field
{name: "IData", argLength: 1}, // arg0=interface, returns data field
// Structs
}
// match: (Load <t> ptr mem)
// cond: t.IsInterface()
- // result: (IMake (Load <typ.BytePtr> ptr mem) (Load <typ.BytePtr> (OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr) mem))
+ // result: (IMake (Load <typ.Uintptr> ptr mem) (Load <typ.BytePtr> (OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr) mem))
for {
t := v.Type
_ = v.Args[1]
break
}
v.reset(OpIMake)
- v0 := b.NewValue0(v.Pos, OpLoad, typ.BytePtr)
+ v0 := b.NewValue0(v.Pos, OpLoad, typ.Uintptr)
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
}
// match: (Arg {n} [off])
// cond: v.Type.IsInterface()
- // result: (IMake (Arg <typ.BytePtr> {n} [off]) (Arg <typ.BytePtr> {n} [off+config.PtrSize]))
+ // result: (IMake (Arg <typ.Uintptr> {n} [off]) (Arg <typ.BytePtr> {n} [off+config.PtrSize]))
for {
off := v.AuxInt
n := v.Aux
break
}
v.reset(OpIMake)
- v0 := b.NewValue0(v.Pos, OpArg, typ.BytePtr)
+ v0 := b.NewValue0(v.Pos, OpArg, typ.Uintptr)
v0.AuxInt = off
v0.Aux = n
v.AddArg(v0)
_ = typ
// match: (ConstInterface)
// cond:
- // result: (IMake (ConstNil <typ.BytePtr>) (ConstNil <typ.BytePtr>))
+ // result: (IMake (ConstNil <typ.Uintptr>) (ConstNil <typ.BytePtr>))
for {
v.reset(OpIMake)
- v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
+ v0 := b.NewValue0(v.Pos, OpConstNil, typ.Uintptr)
v.AddArg(v0)
v1 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
v.AddArg(v1)
x := v.Args[0]
y := v.Args[1]
v.reset(OpEqPtr)
- v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+ v0 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v0.AddArg(x)
v.AddArg(v0)
- v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+ v1 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v1.AddArg(y)
v.AddArg(v1)
return true
x := v.Args[0]
y := v.Args[1]
v.reset(OpNeqPtr)
- v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+ v0 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v0.AddArg(x)
v.AddArg(v0)
- v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr)
+ v1 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v1.AddArg(y)
v.AddArg(v1)
return true
infoString = []byte{typePointer, typeScalar}
infoSlice = []byte{typePointer, typeScalar, typeScalar}
- infoEface = []byte{typePointer, typePointer}
- infoIface = []byte{typePointer, typePointer}
+ infoEface = []byte{typeScalar, typePointer}
+ infoIface = []byte{typeScalar, typePointer}
)
func f9() bool {
g8()
x := i9
- y := interface{}(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+ x.data x.type$" "live at call to str: x.data x.type$"
+ y := interface{}(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+ x.data$" "live at call to str: x.data$"
i9 = y // make y escape so the line above has to call convT2E
return x != y
}