mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-09 13:33:39 +00:00
transform: don't rely on struct name of runtime.typecodeID
Sometimes, LLVM may rename named structs when merging modules. Therefore, we can't rely on typecodeID structs to retain their struct names. This commit changes the interface lowering pass to not rely on these names. The interp package does however still rely on this name, but I hope to fix that in the future.
This commit is contained in:
committed by
Ron Evans
parent
49ec3eb58e
commit
61243f6c57
@@ -163,16 +163,13 @@ func LowerInterfaces(mod llvm.Module, sizeLevel int) error {
|
||||
// run runs the pass itself.
|
||||
func (p *lowerInterfacesPass) run() error {
|
||||
// Collect all type codes.
|
||||
typecodeID := p.mod.GetTypeByName("runtime.typecodeID")
|
||||
typecodeIDPtr := llvm.PointerType(typecodeID, 0)
|
||||
var typecodeIDs []llvm.Value
|
||||
for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
|
||||
switch global.Type() {
|
||||
case typecodeIDPtr:
|
||||
if strings.HasPrefix(global.Name(), "reflect/types.type:") {
|
||||
// Retrieve Go type information based on an opaque global variable.
|
||||
// Only the name of the global is relevant, the object itself is
|
||||
// discarded afterwards.
|
||||
name := global.Name()
|
||||
name := strings.TrimPrefix(global.Name(), "reflect/types.type:")
|
||||
if _, ok := p.types[name]; !ok {
|
||||
typecodeIDs = append(typecodeIDs, global)
|
||||
t := &typeInfo{
|
||||
@@ -196,8 +193,7 @@ func (p *lowerInterfacesPass) run() error {
|
||||
typeAssertUses := getUses(typeAssert)
|
||||
for _, use := range typeAssertUses {
|
||||
typecode := use.Operand(1)
|
||||
name := typecode.Name() // name with $id suffix
|
||||
name = name[:len(name)-len("$id")] // remove $id suffix
|
||||
name := strings.TrimPrefix(typecode.Name(), "reflect/types.typeid:")
|
||||
if t, ok := p.types[name]; ok {
|
||||
t.countTypeAsserts++
|
||||
}
|
||||
@@ -360,7 +356,7 @@ func (p *lowerInterfacesPass) run() error {
|
||||
if use.IsAConstantExpr().IsNil() {
|
||||
continue
|
||||
}
|
||||
t := p.types[global.Name()]
|
||||
t := p.types[strings.TrimPrefix(global.Name(), "reflect/types.type:")]
|
||||
typecode := llvm.ConstInt(p.uintptrType, t.num, false)
|
||||
switch use.Opcode() {
|
||||
case llvm.PtrToInt:
|
||||
@@ -381,8 +377,7 @@ func (p *lowerInterfacesPass) run() error {
|
||||
llvmFalse := llvm.ConstInt(p.ctx.Int1Type(), 0, false)
|
||||
for _, use := range typeAssertUses {
|
||||
actualType := use.Operand(0)
|
||||
name := use.Operand(1).Name() // name with $id suffix
|
||||
name = name[:len(name)-len("$id")] // remove $id suffix
|
||||
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
|
||||
if t, ok := p.types[name]; ok {
|
||||
// The type exists in the program, so lower to a regular integer
|
||||
// comparison.
|
||||
@@ -423,13 +418,12 @@ func (p *lowerInterfacesPass) run() error {
|
||||
|
||||
// Remove most objects created for interface and reflect lowering.
|
||||
// Unnecessary, but cleans up the IR for inspection and testing.
|
||||
zeroTypeCode := llvm.ConstNull(typecodeID)
|
||||
for _, typ := range p.types {
|
||||
// Only some typecodes have an initializer.
|
||||
initializer := typ.typecode.Initializer()
|
||||
if !initializer.IsNil() {
|
||||
references := llvm.ConstExtractValue(initializer, []uint32{0})
|
||||
typ.typecode.SetInitializer(zeroTypeCode)
|
||||
typ.typecode.SetInitializer(llvm.ConstNull(initializer.Type()))
|
||||
if strings.HasPrefix(typ.name, "reflect/types.type:struct:") {
|
||||
// Structs have a 'references' field that is not a typecode but
|
||||
// a pointer to a runtime.structField array and therefore a
|
||||
|
||||
Vendored
+4
-4
@@ -5,8 +5,8 @@ target triple = "armv7m-none-eabi"
|
||||
%runtime.interfaceMethodInfo = type { i8*, i32 }
|
||||
|
||||
@"reflect/types.type:basic:uint8" = external constant %runtime.typecodeID
|
||||
@"reflect/types.type:basic:uint8$id" = external constant i8
|
||||
@"reflect/types.type:basic:int16$id" = external constant i8
|
||||
@"reflect/types.typeid:basic:uint8" = external constant i8
|
||||
@"reflect/types.typeid:basic:int16" = external constant i8
|
||||
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
|
||||
@"func NeverImplementedMethod()" = external constant i8
|
||||
@"Unmatched$interface" = private constant [1 x i8*] [i8* @"func NeverImplementedMethod()"]
|
||||
@@ -55,7 +55,7 @@ typeswitch.Doubler:
|
||||
ret void
|
||||
|
||||
typeswitch.notDoubler:
|
||||
%isByte = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.type:basic:uint8$id")
|
||||
%isByte = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.typeid:basic:uint8")
|
||||
br i1 %isByte, label %typeswitch.byte, label %typeswitch.notByte
|
||||
|
||||
typeswitch.byte:
|
||||
@@ -66,7 +66,7 @@ typeswitch.byte:
|
||||
|
||||
typeswitch.notByte:
|
||||
; this is a type assert that always fails
|
||||
%isInt16 = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.type:basic:int16$id")
|
||||
%isInt16 = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.typeid:basic:int16")
|
||||
br i1 %isInt16, label %typeswitch.int16, label %typeswitch.notInt16
|
||||
|
||||
typeswitch.int16:
|
||||
|
||||
Vendored
+4
-4
@@ -5,8 +5,8 @@ target triple = "armv7m-none-eabi"
|
||||
%runtime.interfaceMethodInfo = type { i8*, i32 }
|
||||
|
||||
@"reflect/types.type:basic:uint8" = external constant %runtime.typecodeID
|
||||
@"reflect/types.type:basic:uint8$id" = external constant i8
|
||||
@"reflect/types.type:basic:int16$id" = external constant i8
|
||||
@"reflect/types.typeid:basic:uint8" = external constant i8
|
||||
@"reflect/types.typeid:basic:int16" = external constant i8
|
||||
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
|
||||
@"func NeverImplementedMethod()" = external constant i8
|
||||
@"func Double() int" = external constant i8
|
||||
@@ -93,14 +93,14 @@ define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
|
||||
define internal i32 @"(Doubler).Double"(i8* %0, i8* %1, i32 %actualType, i8* %parentHandle) unnamed_addr {
|
||||
entry:
|
||||
switch i32 %actualType, label %default [
|
||||
i32 68, label %"reflect/types.type:named:Number"
|
||||
i32 68, label %"named:Number"
|
||||
]
|
||||
|
||||
default: ; preds = %entry
|
||||
call void @runtime.nilPanic(i8* undef, i8* undef)
|
||||
unreachable
|
||||
|
||||
"reflect/types.type:named:Number": ; preds = %entry
|
||||
"named:Number": ; preds = %entry
|
||||
%2 = call i32 @"(Number).Double$invoke"(i8* %0, i8* %1)
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user