Commit 2413b548 authored by Keith Randall's avatar Keith Randall Committed by Keith Randall

cmd/compile: mark the first word of an interface as a uintptr

The first word of an interface is a pointer, but for the purposes
of GC we don't need to 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).

Write barriers on the first word of interfaces have already been removed.

Change-Id: I643e91d7ac4de980ac2717436eff94097c65d959
Reviewed-on: https://go-review.googlesource.com/97518
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent b80b4a23
...@@ -385,7 +385,18 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) { ...@@ -385,7 +385,18 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
if off&int64(Widthptr-1) != 0 { if off&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t) 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 bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot
case TSLICE: case TSLICE:
...@@ -870,7 +881,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) { ...@@ -870,7 +881,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) {
// struct { Itab *tab; void *data; } // struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true: // or, when isnilinter(t)==true:
// struct { Type *type; void *data; } // 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)) clobberPtr(b, v, offset+int64(Widthptr))
case TSLICE: case TSLICE:
......
...@@ -794,6 +794,7 @@ func typeptrdata(t *types.Type) int64 { ...@@ -794,6 +794,7 @@ func typeptrdata(t *types.Type) int64 {
case TINTER: case TINTER:
// struct { Itab *tab; void *data; } or // struct { Itab *tab; void *data; } or
// struct { Type *type; void *data; } // struct { Type *type; void *data; }
// Note: see comment in plive.go:onebitwalktype1.
return 2 * int64(Widthptr) return 2 * int64(Widthptr)
case TSLICE: case TSLICE:
...@@ -1858,7 +1859,7 @@ func (p *GCProg) emit(t *types.Type, offset int64) { ...@@ -1858,7 +1859,7 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
p.w.Ptr(offset / int64(Widthptr)) p.w.Ptr(offset / int64(Widthptr))
case TINTER: 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) p.w.Ptr(offset/int64(Widthptr) + 1)
case TSLICE: case TSLICE:
......
...@@ -5177,6 +5177,7 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { ...@@ -5177,6 +5177,7 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node) n := name.N.(*Node)
u := types.Types[TUINTPTR]
t := types.NewPtr(types.Types[TUINT8]) t := types.NewPtr(types.Types[TUINT8])
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this interface up into two separate variables. // Split this interface up into two separate variables.
...@@ -5184,12 +5185,12 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot ...@@ -5184,12 +5185,12 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
if n.Type.IsEmptyInterface() { if n.Type.IsEmptyInterface() {
f = ".type" f = ".type"
} }
c := e.splitSlot(&name, f, 0, t) c := e.splitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
d := e.splitSlot(&name, ".data", t.Size(), t) d := e.splitSlot(&name, ".data", u.Size(), t)
return c, d return c, d
} }
// Return the two parts of the larger variable. // 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 (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
......
...@@ -200,12 +200,13 @@ func decomposeComplexPhi(v *Value) { ...@@ -200,12 +200,13 @@ func decomposeComplexPhi(v *Value) {
} }
func decomposeInterfacePhi(v *Value) { func decomposeInterfacePhi(v *Value) {
uintptrType := v.Block.Func.Config.Types.Uintptr
ptrType := v.Block.Func.Config.Types.BytePtr 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) data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
for _, a := range v.Args { 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)) data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
} }
v.reset(OpIMake) v.reset(OpIMake)
......
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
(Load <t> ptr mem) && t.IsInterface() -> (Load <t> ptr mem) && t.IsInterface() ->
(IMake (IMake
(Load <typ.BytePtr> ptr mem) (Load <typ.Uintptr> ptr mem)
(Load <typ.BytePtr> (Load <typ.BytePtr>
(OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr) (OffPtr <typ.BytePtrPtr> [config.PtrSize] ptr)
mem)) mem))
......
...@@ -752,7 +752,7 @@ ...@@ -752,7 +752,7 @@
// interface ops // interface ops
(ConstInterface) -> (ConstInterface) ->
(IMake (IMake
(ConstNil <typ.BytePtr>) (ConstNil <typ.Uintptr>)
(ConstNil <typ.BytePtr>)) (ConstNil <typ.BytePtr>))
(NilCheck (GetG mem) mem) -> mem (NilCheck (GetG mem) mem) -> mem
...@@ -779,7 +779,7 @@ ...@@ -779,7 +779,7 @@
(Arg {n} [off]) && v.Type.IsInterface() -> (Arg {n} [off]) && v.Type.IsInterface() ->
(IMake (IMake
(Arg <typ.BytePtr> {n} [off]) (Arg <typ.Uintptr> {n} [off])
(Arg <typ.BytePtr> {n} [off+config.PtrSize])) (Arg <typ.BytePtr> {n} [off+config.PtrSize]))
(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 -> (Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 ->
......
...@@ -422,7 +422,7 @@ var genericOps = []opData{ ...@@ -422,7 +422,7 @@ var genericOps = []opData{
// Interfaces // Interfaces
{name: "IMake", argLength: 2}, // arg0=itab, arg1=data {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 {name: "IData", argLength: 1}, // arg0=interface, returns data field
// Structs // Structs
......
...@@ -230,7 +230,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool { ...@@ -230,7 +230,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool {
} }
// match: (Load <t> ptr mem) // match: (Load <t> ptr mem)
// cond: t.IsInterface() // 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 { for {
t := v.Type t := v.Type
_ = v.Args[1] _ = v.Args[1]
...@@ -240,7 +240,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool { ...@@ -240,7 +240,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool {
break break
} }
v.reset(OpIMake) v.reset(OpIMake)
v0 := b.NewValue0(v.Pos, OpLoad, typ.BytePtr) v0 := b.NewValue0(v.Pos, OpLoad, typ.Uintptr)
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
......
...@@ -6940,7 +6940,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool { ...@@ -6940,7 +6940,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool {
} }
// match: (Arg {n} [off]) // match: (Arg {n} [off])
// cond: v.Type.IsInterface() // 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 { for {
off := v.AuxInt off := v.AuxInt
n := v.Aux n := v.Aux
...@@ -6948,7 +6948,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool { ...@@ -6948,7 +6948,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool {
break break
} }
v.reset(OpIMake) v.reset(OpIMake)
v0 := b.NewValue0(v.Pos, OpArg, typ.BytePtr) v0 := b.NewValue0(v.Pos, OpArg, typ.Uintptr)
v0.AuxInt = off v0.AuxInt = off
v0.Aux = n v0.Aux = n
v.AddArg(v0) v.AddArg(v0)
...@@ -7298,10 +7298,10 @@ func rewriteValuegeneric_OpConstInterface_0(v *Value) bool { ...@@ -7298,10 +7298,10 @@ func rewriteValuegeneric_OpConstInterface_0(v *Value) bool {
_ = typ _ = typ
// match: (ConstInterface) // match: (ConstInterface)
// cond: // cond:
// result: (IMake (ConstNil <typ.BytePtr>) (ConstNil <typ.BytePtr>)) // result: (IMake (ConstNil <typ.Uintptr>) (ConstNil <typ.BytePtr>))
for { for {
v.reset(OpIMake) v.reset(OpIMake)
v0 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr) v0 := b.NewValue0(v.Pos, OpConstNil, typ.Uintptr)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr) v1 := b.NewValue0(v.Pos, OpConstNil, typ.BytePtr)
v.AddArg(v1) v.AddArg(v1)
...@@ -10209,10 +10209,10 @@ func rewriteValuegeneric_OpEqInter_0(v *Value) bool { ...@@ -10209,10 +10209,10 @@ func rewriteValuegeneric_OpEqInter_0(v *Value) bool {
x := v.Args[0] x := v.Args[0]
y := v.Args[1] y := v.Args[1]
v.reset(OpEqPtr) v.reset(OpEqPtr)
v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr) v0 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v0.AddArg(x) v0.AddArg(x)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr) v1 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v1.AddArg(y) v1.AddArg(y)
v.AddArg(v1) v.AddArg(v1)
return true return true
...@@ -18008,10 +18008,10 @@ func rewriteValuegeneric_OpNeqInter_0(v *Value) bool { ...@@ -18008,10 +18008,10 @@ func rewriteValuegeneric_OpNeqInter_0(v *Value) bool {
x := v.Args[0] x := v.Args[0]
y := v.Args[1] y := v.Args[1]
v.reset(OpNeqPtr) v.reset(OpNeqPtr)
v0 := b.NewValue0(v.Pos, OpITab, typ.BytePtr) v0 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v0.AddArg(x) v0.AddArg(x)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Pos, OpITab, typ.BytePtr) v1 := b.NewValue0(v.Pos, OpITab, typ.Uintptr)
v1.AddArg(y) v1.AddArg(y)
v.AddArg(v1) v.AddArg(v1)
return true return true
......
...@@ -200,6 +200,6 @@ var ( ...@@ -200,6 +200,6 @@ var (
infoString = []byte{typePointer, typeScalar} infoString = []byte{typePointer, typeScalar}
infoSlice = []byte{typePointer, typeScalar, typeScalar} infoSlice = []byte{typePointer, typeScalar, typeScalar}
infoEface = []byte{typePointer, typePointer} infoEface = []byte{typeScalar, typePointer}
infoIface = []byte{typePointer, typePointer} infoIface = []byte{typeScalar, typePointer}
) )
...@@ -141,7 +141,7 @@ var i9 interface{} ...@@ -141,7 +141,7 @@ var i9 interface{}
func f9() bool { func f9() bool {
g8() g8()
x := i9 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 i9 = y // make y escape so the line above has to call convT2E
return x != y return x != y
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment