1
0
mirror of https://github.com/golang/go synced 2024-09-29 04:24:36 -06:00

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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Keith Randall 2023-10-12 10:57:04 -07:00
parent 2d9e8ded94
commit 9ab5121691
3 changed files with 44 additions and 18 deletions

View File

@ -38,6 +38,10 @@ var Method *types.Type
var StructField *types.Type var StructField *types.Type
var UncommonType *types.Type var UncommonType *types.Type
// Type switches and asserts
var InterfaceSwitch *types.Type
var TypeAssert *types.Type
func Init() { func Init() {
// Note: this has to be called explicitly instead of being // Note: this has to be called explicitly instead of being
// an init function so it runs after the types package has // an init function so it runs after the types package has
@ -57,6 +61,9 @@ func Init() {
StructField = fromReflect(reflect.TypeOf(abi.StructField{})) StructField = fromReflect(reflect.TypeOf(abi.StructField{}))
UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{})) UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{}))
InterfaceSwitch = fromReflect(reflect.TypeOf(abi.InterfaceSwitch{}))
TypeAssert = fromReflect(reflect.TypeOf(abi.TypeAssert{}))
// Make sure abi functions are correct. These functions are used // Make sure abi functions are correct. These functions are used
// by the linker which doesn't have the ability to do type layout, // by the linker which doesn't have the ability to do type layout,
// so we check the functions it uses here. // so we check the functions it uses here.
@ -87,6 +94,8 @@ func fromReflect(rt reflect.Type) *types.Type {
// must be CalcSize'd before using. // must be CalcSize'd before using.
func reflectToType(rt reflect.Type) *types.Type { func reflectToType(rt reflect.Type) *types.Type {
switch rt.Kind() { switch rt.Kind() {
case reflect.Bool:
return types.Types[types.TBOOL]
case reflect.Int: case reflect.Int:
return types.Types[types.TINT] return types.Types[types.TINT]
case reflect.Int32: case reflect.Int32:
@ -181,6 +190,12 @@ func (c Cursor) WriteInt32(val int32) {
} }
objw.Uint32(c.lsym, int(c.offset), uint32(val)) objw.Uint32(c.lsym, int(c.offset), uint32(val))
} }
func (c Cursor) WriteBool(val bool) {
if c.typ.Kind() != types.TBOOL {
base.Fatalf("can't write bool, it has kind %s", c.typ.Kind())
}
objw.Bool(c.lsym, int(c.offset), val)
}
// WriteSymPtrOff writes a "pointer" to the given symbol. The symbol // WriteSymPtrOff writes a "pointer" to the given symbol. The symbol
// is encoded as a uint32 offset from the start of the section. // is encoded as a uint32 offset from the start of the section.
@ -255,3 +270,14 @@ func (a ArrayCursor) Elem(i int) Cursor {
} }
return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ} return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ}
} }
// ModifyArray converts a cursor pointing at a type [k]T to a cursor pointing
// at a type [n]T.
// Also returns the size delta, aka (n-k)*sizeof(T).
func (c Cursor) ModifyArray(n int) (ArrayCursor, int64) {
if c.typ.Kind() != types.TARRAY {
base.Fatalf("can't call ModifyArray on non-array %v", c.typ)
}
k := c.typ.NumElem()
return ArrayCursor{c: Cursor{lsym: c.lsym, offset: c.offset, typ: c.typ.Elem()}, n: n}, (int64(n) - k) * c.typ.Elem().Size()
}

View File

@ -14,6 +14,7 @@ import (
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/objw" "cmd/compile/internal/objw"
"cmd/compile/internal/reflectdata" "cmd/compile/internal/reflectdata"
"cmd/compile/internal/rttype"
"cmd/compile/internal/staticdata" "cmd/compile/internal/staticdata"
"cmd/compile/internal/typecheck" "cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "cmd/compile/internal/types"
@ -738,15 +739,12 @@ func makeTypeAssertDescriptor(target *types.Type, canFail bool) *obj.LSym {
// Allocate an internal/abi.TypeAssert descriptor for that call. // Allocate an internal/abi.TypeAssert descriptor for that call.
lsym := types.LocalPkg.Lookup(fmt.Sprintf(".typeAssert.%d", typeAssertGen)).LinksymABI(obj.ABI0) lsym := types.LocalPkg.Lookup(fmt.Sprintf(".typeAssert.%d", typeAssertGen)).LinksymABI(obj.ABI0)
typeAssertGen++ typeAssertGen++
off := 0 c := rttype.NewCursor(lsym, 0, rttype.TypeAssert)
off = objw.SymPtr(lsym, off, typecheck.LookupRuntimeVar("emptyTypeAssertCache"), 0) c.Field("Cache").WritePtr(typecheck.LookupRuntimeVar("emptyTypeAssertCache"))
off = objw.SymPtr(lsym, off, reflectdata.TypeSym(target).Linksym(), 0) c.Field("Inter").WritePtr(reflectdata.TypeSym(target).Linksym())
off = objw.Bool(lsym, off, canFail) c.Field("CanFail").WriteBool(canFail)
off += types.PtrSize - 1 objw.Global(lsym, int32(rttype.TypeAssert.Size()), obj.LOCAL)
objw.Global(lsym, int32(off), obj.LOCAL) lsym.Gotype = reflectdata.TypeLinksym(rttype.TypeAssert)
// Set the type to be just a single pointer, as the cache pointer is the
// only one that GC needs to see.
lsym.Gotype = reflectdata.TypeLinksym(types.Types[types.TUINT8].PtrTo())
return lsym return lsym
} }

View File

@ -527,16 +527,18 @@ func walkSwitchType(sw *ir.SwitchStmt) {
// Build an internal/abi.InterfaceSwitch descriptor to pass to the runtime. // Build an internal/abi.InterfaceSwitch descriptor to pass to the runtime.
lsym := types.LocalPkg.Lookup(fmt.Sprintf(".interfaceSwitch.%d", interfaceSwitchGen)).LinksymABI(obj.ABI0) lsym := types.LocalPkg.Lookup(fmt.Sprintf(".interfaceSwitch.%d", interfaceSwitchGen)).LinksymABI(obj.ABI0)
interfaceSwitchGen++ interfaceSwitchGen++
off := 0 c := rttype.NewCursor(lsym, 0, rttype.InterfaceSwitch)
off = objw.SymPtr(lsym, off, typecheck.LookupRuntimeVar("emptyInterfaceSwitchCache"), 0) c.Field("Cache").WritePtr(typecheck.LookupRuntimeVar("emptyInterfaceSwitchCache"))
off = objw.Uintptr(lsym, off, uint64(len(interfaceCases))) c.Field("NCases").WriteInt(int64(len(interfaceCases)))
for _, c := range interfaceCases { array, sizeDelta := c.Field("Cases").ModifyArray(len(interfaceCases))
off = objw.SymPtr(lsym, off, reflectdata.TypeSym(c.typ.Type()).Linksym(), 0) for i, c := range interfaceCases {
array.Elem(i).WritePtr(reflectdata.TypeSym(c.typ.Type()).Linksym())
} }
objw.Global(lsym, int32(off), obj.LOCAL) objw.Global(lsym, int32(rttype.InterfaceSwitch.Size()+sizeDelta), obj.LOCAL)
// Set the type to be just a single pointer, as the cache pointer is the // The GC only needs to see the first pointer in the structure (all the others
// only one that GC needs to see. // are to static locations). So the InterfaceSwitch type itself is fine, even
lsym.Gotype = reflectdata.TypeLinksym(types.Types[types.TUINT8].PtrTo()) // though it might not cover the whole array we wrote above.
lsym.Gotype = reflectdata.TypeLinksym(rttype.InterfaceSwitch)
// Call runtime to do switch // Call runtime to do switch
// case, itab = runtime.interfaceSwitch(&descriptor, typeof(arg)) // case, itab = runtime.interfaceSwitch(&descriptor, typeof(arg))