]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: mark the first word of an interface as a uintptr
authorKeith Randall <khr@google.com>
Tue, 27 Feb 2018 21:46:03 +0000 (13:46 -0800)
committerKeith Randall <khr@golang.org>
Tue, 27 Feb 2018 22:58:32 +0000 (22:58 +0000)
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>
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/decompose.go
src/cmd/compile/internal/ssa/gen/dec.rules
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/rewritedec.go
src/cmd/compile/internal/ssa/rewritegeneric.go
src/runtime/gcinfo_test.go
test/live.go

index 7d856cc59e2d7a0988929ab2173262f877f697cc..60c726ff589e57dc8ef34abfbd87a713b5a2ea34 100644 (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:
index e556409d4b650a984f7b7ebd5af7e0fd18584176..08d87a7f5d3d49f04710198ed656b39b1ba92c3e 100644 (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:
index a9342aedf455b72905ace416a03dc30ad61ee5c4..192e13eeb56d36b69c21fe324416c2014ce7c312 100644 (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) {
index 0cabfb61e727dd80eb43ad88b86604f2bdd571f9..af85090248fea80c7e948f993ad10e3705761d2a 100644 (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)
index a475a2d26a1cbb805637c9e825a24a66b9a3f970..b56db78a56caf318cfbda8a35c4e6b5a02358712 100644 (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))
index 0e9109b79938ca5e12695baf63c604d63ebf9883..8d394438816c6b08f6aac675c2d660552f5b85b3 100644 (file)
 // 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 ->
index 6cfa9d2e713dcaa9649457bc0e45e92020d802b9..17080fbb3d7197ce744c306dfa1be2fbe94b83c7 100644 (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
index f0e837aef57a4f782610574ca59431859aa520b0..36729a553d55f501f0519b4cbfd00308e1d38566 100644 (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)
index 6f7e658440de1a1c2bc06968d38047ee2cd8540b..414514c5ac1d0d25d28a552f1f04b12b51daf379 100644 (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
index 14f514f96a23e8bdc89e02448b6e3130a32a8a71..767e08d5400054aa6498ceab37aaf76ee1ea4239 100644 (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}
 )
index e54336ead7f5a13495104effc091c5d829a8feca..ecab83e276ae4d2e29844bc2c10a52e9f77772c7 100644 (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
 }