diff --git a/compiler/compiler.go b/compiler/compiler.go index 29e6e0a9..be15f789 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -23,7 +23,7 @@ import ( // Version of the compiler pacakge. Must be incremented each time the compiler // package changes in a way that affects the generated LLVM module. // This version is independent of the TinyGo version number. -const Version = 6 // last change: fix issue 1304 +const Version = 7 // last change: don't rely on runtime.typecodeID struct type name func init() { llvm.InitializeAllTargets() diff --git a/compiler/interface.go b/compiler/interface.go index 6cca7876..8b3988a1 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -341,7 +341,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value { commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "") } else { - globalName := "reflect/types.type:" + getTypeCodeName(expr.AssertedType) + "$id" + globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType) assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName) if assertedTypeCodeGlobal.IsNil() { // Create a new typecode global. diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index 1405abf1..e5aa7eef 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -19,7 +19,7 @@ target triple = "i686--linux" @"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null } @"func String() string" = external constant i8 @"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"] -@"reflect/types.type:basic:int$id" = external constant i8 +@"reflect/types.typeid:basic:int" = external constant i8 @"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"] declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) @@ -51,7 +51,7 @@ entry: define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr { entry: - %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.type:basic:int$id", i8* undef, i8* null) + %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null) br i1 %typecode, label %typeassert.ok, label %typeassert.next typeassert.ok: ; preds = %entry diff --git a/interp/interpreter.go b/interp/interpreter.go index 3bbf9e5f..c0dc45d9 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -328,7 +328,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent return nil, mem, r.errorAt(inst, err) } actualType := actualTypePtrToInt.Operand(0) - if actualType.Name()+"$id" == assertedType.Name() { + if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") { locals[inst.localIndex] = literalValue{uint8(1)} } else { locals[inst.localIndex] = literalValue{uint8(0)} diff --git a/interp/testdata/interface.ll b/interp/testdata/interface.ll index 8031632f..060256d2 100644 --- a/interp/testdata/interface.ll +++ b/interp/testdata/interface.ll @@ -6,7 +6,7 @@ target triple = "x86_64--linux" @main.v1 = global i1 0 @"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null } -@"reflect/types.type:named:main.foo$id" = external constant i8 +@"reflect/types.typeid:named:main.foo" = external constant i8 @"reflect/types.type:basic:int" = external constant %runtime.typecodeID @@ -21,7 +21,7 @@ entry: define internal void @main.init() unnamed_addr { entry: ; Test type asserts. - %typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.type:named:main.foo$id", i8* undef, i8* null) + %typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null) store i1 %typecode, i1* @main.v1 ret void } diff --git a/transform/interface-lowering.go b/transform/interface-lowering.go index e8b6deec..c39765f6 100644 --- a/transform/interface-lowering.go +++ b/transform/interface-lowering.go @@ -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 diff --git a/transform/testdata/interface.ll b/transform/testdata/interface.ll index 487ecbb2..e00d1b23 100644 --- a/transform/testdata/interface.ll +++ b/transform/testdata/interface.ll @@ -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: diff --git a/transform/testdata/interface.out.ll b/transform/testdata/interface.out.ll index faff1254..44d3145e 100644 --- a/transform/testdata/interface.out.ll +++ b/transform/testdata/interface.out.ll @@ -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 }