Skip to content

Commit 9ab5121

Browse files
committed
cmd/compile: use new runtime type mechanism for type switches and asserts
Change-Id: Ife7d6d6d773ac0d8ac38dbd2da7dccc519998b63 Reviewed-on: https://go-review.googlesource.com/c/go/+/534816 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 2d9e8de commit 9ab5121

File tree

3 files changed

+44
-18
lines changed

3 files changed

+44
-18
lines changed

src/cmd/compile/internal/rttype/rttype.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ var Method *types.Type
3838
var StructField *types.Type
3939
var UncommonType *types.Type
4040

41+
// Type switches and asserts
42+
var InterfaceSwitch *types.Type
43+
var TypeAssert *types.Type
44+
4145
func Init() {
4246
// Note: this has to be called explicitly instead of being
4347
// an init function so it runs after the types package has
@@ -57,6 +61,9 @@ func Init() {
5761
StructField = fromReflect(reflect.TypeOf(abi.StructField{}))
5862
UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{}))
5963

64+
InterfaceSwitch = fromReflect(reflect.TypeOf(abi.InterfaceSwitch{}))
65+
TypeAssert = fromReflect(reflect.TypeOf(abi.TypeAssert{}))
66+
6067
// Make sure abi functions are correct. These functions are used
6168
// by the linker which doesn't have the ability to do type layout,
6269
// so we check the functions it uses here.
@@ -87,6 +94,8 @@ func fromReflect(rt reflect.Type) *types.Type {
8794
// must be CalcSize'd before using.
8895
func reflectToType(rt reflect.Type) *types.Type {
8996
switch rt.Kind() {
97+
case reflect.Bool:
98+
return types.Types[types.TBOOL]
9099
case reflect.Int:
91100
return types.Types[types.TINT]
92101
case reflect.Int32:
@@ -181,6 +190,12 @@ func (c Cursor) WriteInt32(val int32) {
181190
}
182191
objw.Uint32(c.lsym, int(c.offset), uint32(val))
183192
}
193+
func (c Cursor) WriteBool(val bool) {
194+
if c.typ.Kind() != types.TBOOL {
195+
base.Fatalf("can't write bool, it has kind %s", c.typ.Kind())
196+
}
197+
objw.Bool(c.lsym, int(c.offset), val)
198+
}
184199

185200
// WriteSymPtrOff writes a "pointer" to the given symbol. The symbol
186201
// is encoded as a uint32 offset from the start of the section.
@@ -255,3 +270,14 @@ func (a ArrayCursor) Elem(i int) Cursor {
255270
}
256271
return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ}
257272
}
273+
274+
// ModifyArray converts a cursor pointing at a type [k]T to a cursor pointing
275+
// at a type [n]T.
276+
// Also returns the size delta, aka (n-k)*sizeof(T).
277+
func (c Cursor) ModifyArray(n int) (ArrayCursor, int64) {
278+
if c.typ.Kind() != types.TARRAY {
279+
base.Fatalf("can't call ModifyArray on non-array %v", c.typ)
280+
}
281+
k := c.typ.NumElem()
282+
return ArrayCursor{c: Cursor{lsym: c.lsym, offset: c.offset, typ: c.typ.Elem()}, n: n}, (int64(n) - k) * c.typ.Elem().Size()
283+
}

src/cmd/compile/internal/walk/expr.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"cmd/compile/internal/ir"
1515
"cmd/compile/internal/objw"
1616
"cmd/compile/internal/reflectdata"
17+
"cmd/compile/internal/rttype"
1718
"cmd/compile/internal/staticdata"
1819
"cmd/compile/internal/typecheck"
1920
"cmd/compile/internal/types"
@@ -738,15 +739,12 @@ func makeTypeAssertDescriptor(target *types.Type, canFail bool) *obj.LSym {
738739
// Allocate an internal/abi.TypeAssert descriptor for that call.
739740
lsym := types.LocalPkg.Lookup(fmt.Sprintf(".typeAssert.%d", typeAssertGen)).LinksymABI(obj.ABI0)
740741
typeAssertGen++
741-
off := 0
742-
off = objw.SymPtr(lsym, off, typecheck.LookupRuntimeVar("emptyTypeAssertCache"), 0)
743-
off = objw.SymPtr(lsym, off, reflectdata.TypeSym(target).Linksym(), 0)
744-
off = objw.Bool(lsym, off, canFail)
745-
off += types.PtrSize - 1
746-
objw.Global(lsym, int32(off), obj.LOCAL)
747-
// Set the type to be just a single pointer, as the cache pointer is the
748-
// only one that GC needs to see.
749-
lsym.Gotype = reflectdata.TypeLinksym(types.Types[types.TUINT8].PtrTo())
742+
c := rttype.NewCursor(lsym, 0, rttype.TypeAssert)
743+
c.Field("Cache").WritePtr(typecheck.LookupRuntimeVar("emptyTypeAssertCache"))
744+
c.Field("Inter").WritePtr(reflectdata.TypeSym(target).Linksym())
745+
c.Field("CanFail").WriteBool(canFail)
746+
objw.Global(lsym, int32(rttype.TypeAssert.Size()), obj.LOCAL)
747+
lsym.Gotype = reflectdata.TypeLinksym(rttype.TypeAssert)
750748
return lsym
751749
}
752750

src/cmd/compile/internal/walk/switch.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -527,16 +527,18 @@ func walkSwitchType(sw *ir.SwitchStmt) {
527527
// Build an internal/abi.InterfaceSwitch descriptor to pass to the runtime.
528528
lsym := types.LocalPkg.Lookup(fmt.Sprintf(".interfaceSwitch.%d", interfaceSwitchGen)).LinksymABI(obj.ABI0)
529529
interfaceSwitchGen++
530-
off := 0
531-
off = objw.SymPtr(lsym, off, typecheck.LookupRuntimeVar("emptyInterfaceSwitchCache"), 0)
532-
off = objw.Uintptr(lsym, off, uint64(len(interfaceCases)))
533-
for _, c := range interfaceCases {
534-
off = objw.SymPtr(lsym, off, reflectdata.TypeSym(c.typ.Type()).Linksym(), 0)
530+
c := rttype.NewCursor(lsym, 0, rttype.InterfaceSwitch)
531+
c.Field("Cache").WritePtr(typecheck.LookupRuntimeVar("emptyInterfaceSwitchCache"))
532+
c.Field("NCases").WriteInt(int64(len(interfaceCases)))
533+
array, sizeDelta := c.Field("Cases").ModifyArray(len(interfaceCases))
534+
for i, c := range interfaceCases {
535+
array.Elem(i).WritePtr(reflectdata.TypeSym(c.typ.Type()).Linksym())
535536
}
536-
objw.Global(lsym, int32(off), obj.LOCAL)
537-
// Set the type to be just a single pointer, as the cache pointer is the
538-
// only one that GC needs to see.
539-
lsym.Gotype = reflectdata.TypeLinksym(types.Types[types.TUINT8].PtrTo())
537+
objw.Global(lsym, int32(rttype.InterfaceSwitch.Size()+sizeDelta), obj.LOCAL)
538+
// The GC only needs to see the first pointer in the structure (all the others
539+
// are to static locations). So the InterfaceSwitch type itself is fine, even
540+
// though it might not cover the whole array we wrote above.
541+
lsym.Gotype = reflectdata.TypeLinksym(rttype.InterfaceSwitch)
540542

541543
// Call runtime to do switch
542544
// case, itab = runtime.interfaceSwitch(&descriptor, typeof(arg))

0 commit comments

Comments
 (0)