1
0
mirror of https://github.com/golang/go synced 2024-11-26 01:07:57 -07:00

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: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2018-02-27 13:46:03 -08:00 committed by Keith Randall
parent b80b4a23d1
commit 2413b54888
11 changed files with 39 additions and 25 deletions

View File

@ -385,7 +385,18 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
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:
@ -870,7 +881,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) {
// 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:

View File

@ -794,6 +794,7 @@ func typeptrdata(t *types.Type) int64 {
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:
@ -1858,7 +1859,7 @@ func (p *GCProg) emit(t *types.Type, offset int64) {
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:

View File

@ -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) {
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.
@ -5184,12 +5185,12 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
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) {

View File

@ -200,12 +200,13 @@ func decomposeComplexPhi(v *Value) {
}
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)

View File

@ -81,7 +81,7 @@
(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))

View File

@ -752,7 +752,7 @@
// interface ops
(ConstInterface) ->
(IMake
(ConstNil <typ.BytePtr>)
(ConstNil <typ.Uintptr>)
(ConstNil <typ.BytePtr>))
(NilCheck (GetG mem) mem) -> mem
@ -779,7 +779,7 @@
(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 ->

View File

@ -422,7 +422,7 @@ var genericOps = []opData{
// 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

View File

@ -230,7 +230,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool {
}
// 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]
@ -240,7 +240,7 @@ func rewriteValuedec_OpLoad_0(v *Value) bool {
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)

View File

@ -6940,7 +6940,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool {
}
// 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
@ -6948,7 +6948,7 @@ func rewriteValuegeneric_OpArg_0(v *Value) bool {
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)
@ -7298,10 +7298,10 @@ func rewriteValuegeneric_OpConstInterface_0(v *Value) bool {
_ = 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)
@ -10209,10 +10209,10 @@ func rewriteValuegeneric_OpEqInter_0(v *Value) bool {
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
@ -18008,10 +18008,10 @@ func rewriteValuegeneric_OpNeqInter_0(v *Value) bool {
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

View File

@ -200,6 +200,6 @@ var (
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}
)

View File

@ -141,7 +141,7 @@ var i9 interface{}
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
}