aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler/interface.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2022-06-24 00:09:03 +0200
committerRon Evans <[email protected]>2023-02-17 22:54:34 +0100
commit4e8453167f42976aad87099ffdb3746fc540d6a6 (patch)
treeb3acee7dc97a19219fd1a84cabaf9b9d8eba1f3a /compiler/interface.go
parentebb410afd916047ee17f0e51dfba36ad3a6c002b (diff)
downloadtinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.tar.gz
tinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.zip
all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in the binary. Instead of compressing it and storing it in a number of sidetables, it is stored similar to how the Go compiler toolchain stores it (but still more compactly). This has a number of advantages: * It is much easier to add new features to reflect support. They can simply be added to these structs without requiring massive changes (especially in the reflect lowering pass). * It removes the reflect lowering pass, which was a large amount of hard to understand and debug code. * The reflect lowering pass also required merging all LLVM IR into one module, which is terrible for performance especially when compiling large amounts of code. See issue 2870 for details. * It is (probably!) easier to reason about for the compiler. The downside is that it increases code size a bit, especially when reflect is involved. I hope to fix some of that in later patches.
Diffstat (limited to 'compiler/interface.go')
-rw-r--r--compiler/interface.go450
1 files changed, 288 insertions, 162 deletions
diff --git a/compiler/interface.go b/compiler/interface.go
index 2007b7d7c..a359f33a4 100644
--- a/compiler/interface.go
+++ b/compiler/interface.go
@@ -6,6 +6,7 @@ package compiler
// interface-lowering.go for more details.
import (
+ "fmt"
"go/token"
"go/types"
"strconv"
@@ -15,6 +16,49 @@ import (
"tinygo.org/x/go-llvm"
)
+// Type kinds for basic types.
+// They must match the constants for the Kind type in src/reflect/type.go.
+var basicTypes = [...]uint8{
+ types.Bool: 1,
+ types.Int: 2,
+ types.Int8: 3,
+ types.Int16: 4,
+ types.Int32: 5,
+ types.Int64: 6,
+ types.Uint: 7,
+ types.Uint8: 8,
+ types.Uint16: 9,
+ types.Uint32: 10,
+ types.Uint64: 11,
+ types.Uintptr: 12,
+ types.Float32: 13,
+ types.Float64: 14,
+ types.Complex64: 15,
+ types.Complex128: 16,
+ types.String: 17,
+ types.UnsafePointer: 18,
+}
+
+// These must also match the constants for the Kind type in src/reflect/type.go.
+const (
+ typeKindChan = 19
+ typeKindInterface = 20
+ typeKindPointer = 21
+ typeKindSlice = 22
+ typeKindArray = 23
+ typeKindSignature = 24
+ typeKindMap = 25
+ typeKindStruct = 26
+)
+
+// Flags stored in the first byte of the struct field byte array. Must be kept
+// up to date with src/reflect/type.go.
+const (
+ structFieldFlagAnonymous = 1 << iota
+ structFieldFlagHasTag
+ structFieldFlagIsExported
+)
+
// createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction.
// It tries to put the type in the interface value, but if that's not possible,
// it will do an allocation of the right size and put that in the interface
@@ -23,10 +67,9 @@ import (
// An interface value is a {typecode, value} tuple named runtime._interface.
func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) llvm.Value {
itfValue := b.emitPointerPack([]llvm.Value{val})
- itfTypeCodeGlobal := b.getTypeCode(typ)
- itfTypeCode := b.CreatePtrToInt(itfTypeCodeGlobal, b.uintptrType, "")
+ itfType := b.getTypeCode(typ)
itf := llvm.Undef(b.getLLVMRuntimeType("_interface"))
- itf = b.CreateInsertValue(itf, itfTypeCode, 0, "")
+ itf = b.CreateInsertValue(itf, itfType, 0, "")
itf = b.CreateInsertValue(itf, itfValue, 1, "")
return itf
}
@@ -41,118 +84,236 @@ func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type)
}
// getTypeCode returns a reference to a type code.
-// It returns a pointer to an external global which should be replaced with the
-// real type in the interface lowering pass.
+// A type code is a pointer to a constant global that describes the type.
+// This function returns a pointer to the 'kind' field (which might not be the
+// first field in the struct).
func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
+ ms := c.program.MethodSets.MethodSet(typ)
+ hasMethodSet := ms.Len() != 0
+ if _, ok := typ.Underlying().(*types.Interface); ok {
+ hasMethodSet = false
+ }
globalName := "reflect/types.type:" + getTypeCodeName(typ)
global := c.mod.NamedGlobal(globalName)
if global.IsNil() {
- // Create a new typecode global.
- global = llvm.AddGlobal(c.mod, c.getLLVMRuntimeType("typecodeID"), globalName)
- // Some type classes contain more information for underlying types or
- // element types. Store it directly in the typecode global to make
- // reflect lowering simpler.
- var references llvm.Value
- var length int64
- var methodSet llvm.Value
- var ptrTo llvm.Value
- var typeAssert llvm.Value
+ var typeFields []llvm.Value
+ // Define the type fields. These must match the structs in
+ // src/reflect/type.go (ptrType, arrayType, etc). See the comment at the
+ // top of src/reflect/type.go for more information on the layout of these structs.
+ typeFieldTypes := []*types.Var{
+ types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
+ }
switch typ := typ.(type) {
+ case *types.Basic:
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ )
case *types.Named:
- references = c.getTypeCode(typ.Underlying())
- case *types.Chan:
- references = c.getTypeCode(typ.Elem())
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
+ )
+ case *types.Chan, *types.Slice:
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
+ )
case *types.Pointer:
- references = c.getTypeCode(typ.Elem())
- case *types.Slice:
- references = c.getTypeCode(typ.Elem())
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
+ )
case *types.Array:
- references = c.getTypeCode(typ.Elem())
- length = typ.Len()
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
+ types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
+ )
+ case *types.Map:
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ )
case *types.Struct:
- // Take a pointer to the typecodeID of the first field (if it exists).
- structGlobal := c.makeStructTypeFields(typ)
- references = llvm.ConstBitCast(structGlobal, global.Type())
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
+ )
case *types.Interface:
- methodSetGlobal := c.getInterfaceMethodSet(typ)
- references = llvm.ConstBitCast(methodSetGlobal, global.Type())
- }
- if _, ok := typ.Underlying().(*types.Interface); !ok {
- methodSet = c.getTypeMethodSet(typ)
- } else {
- typeAssert = c.getInterfaceImplementsFunc(typ)
- typeAssert = llvm.ConstPtrToInt(typeAssert, c.uintptrType)
- }
- if _, ok := typ.Underlying().(*types.Pointer); !ok {
- ptrTo = c.getTypeCode(types.NewPointer(typ))
- }
- globalValue := llvm.ConstNull(global.GlobalValueType())
- if !references.IsNil() {
- globalValue = c.builder.CreateInsertValue(globalValue, references, 0, "")
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ )
+ // TODO: methods
+ case *types.Signature:
+ typeFieldTypes = append(typeFieldTypes,
+ types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
+ )
+ // TODO: signature params and return values
}
- if length != 0 {
- lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false)
- globalValue = c.builder.CreateInsertValue(globalValue, lengthValue, 1, "")
+ if hasMethodSet {
+ // This method set is appended at the start of the struct. It is
+ // removed in the interface lowering pass.
+ // TODO: don't remove these and instead do what upstream Go is doing
+ // instead. See: https://research.swtch.com/interfaces. This can
+ // likely be optimized in LLVM using
+ // https://llvm.org/docs/TypeMetadata.html.
+ typeFieldTypes = append([]*types.Var{
+ types.NewVar(token.NoPos, nil, "methodSet", types.Typ[types.UnsafePointer]),
+ }, typeFieldTypes...)
}
- if !methodSet.IsNil() {
- globalValue = c.builder.CreateInsertValue(globalValue, methodSet, 2, "")
- }
- if !ptrTo.IsNil() {
- globalValue = c.builder.CreateInsertValue(globalValue, ptrTo, 3, "")
+ globalType := types.NewStruct(typeFieldTypes, nil)
+ global = llvm.AddGlobal(c.mod, c.getLLVMType(globalType), globalName)
+ metabyte := getTypeKind(typ)
+ switch typ := typ.(type) {
+ case *types.Basic:
+ typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
+ case *types.Named:
+ typeFields = []llvm.Value{
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ c.getTypeCode(typ.Underlying()), // underlying
+ }
+ metabyte |= 1 << 5 // "named" flag
+ case *types.Chan:
+ typeFields = []llvm.Value{
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ c.getTypeCode(typ.Elem()), // elementType
+ }
+ case *types.Slice:
+ typeFields = []llvm.Value{
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ c.getTypeCode(typ.Elem()), // elementType
+ }
+ case *types.Pointer:
+ typeFields = []llvm.Value{c.getTypeCode(typ.Elem())}
+ case *types.Array:
+ typeFields = []llvm.Value{
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ c.getTypeCode(typ.Elem()), // elementType
+ llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false), // length
+ }
+ case *types.Map:
+ typeFields = []llvm.Value{
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ }
+ case *types.Struct:
+ typeFields = []llvm.Value{
+ llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
+ c.getTypeCode(types.NewPointer(typ)), // ptrTo
+ }
+ structFieldType := c.getLLVMRuntimeType("structField")
+ var fields []llvm.Value
+ for i := 0; i < typ.NumFields(); i++ {
+ field := typ.Field(i)
+ var flags uint8
+ if field.Anonymous() {
+ flags |= structFieldFlagAnonymous
+ }
+ if typ.Tag(i) != "" {
+ flags |= structFieldFlagHasTag
+ }
+ if token.IsExported(field.Name()) {
+ flags |= structFieldFlagIsExported
+ }
+ data := string(flags) + field.Name() + "\x00"
+ if typ.Tag(i) != "" {
+ if len(typ.Tag(i)) > 0xff {
+ c.addError(field.Pos(), fmt.Sprintf("struct tag is %d bytes which is too long, max is 255", len(typ.Tag(i))))
+ }
+ data += string([]byte{byte(len(typ.Tag(i)))}) + typ.Tag(i)
+ }
+ dataInitializer := c.ctx.ConstString(data, false)
+ dataGlobal := llvm.AddGlobal(c.mod, dataInitializer.Type(), globalName+"."+field.Name())
+ dataGlobal.SetInitializer(dataInitializer)
+ dataGlobal.SetAlignment(1)
+ dataGlobal.SetUnnamedAddr(true)
+ dataGlobal.SetLinkage(llvm.InternalLinkage)
+ dataGlobal.SetGlobalConstant(true)
+ fieldType := c.getTypeCode(field.Type())
+ fields = append(fields, llvm.ConstNamedStruct(structFieldType, []llvm.Value{
+ fieldType,
+ llvm.ConstGEP(dataGlobal.GlobalValueType(), dataGlobal, []llvm.Value{
+ llvm.ConstInt(c.ctx.Int32Type(), 0, false),
+ llvm.ConstInt(c.ctx.Int32Type(), 0, false),
+ }),
+ }))
+ }
+ typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
+ case *types.Interface:
+ typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
+ // TODO: methods
+ case *types.Signature:
+ typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
+ // TODO: params, return values, etc
}
- if !typeAssert.IsNil() {
- globalValue = c.builder.CreateInsertValue(globalValue, typeAssert, 4, "")
+ // Prepend metadata byte.
+ typeFields = append([]llvm.Value{
+ llvm.ConstInt(c.ctx.Int8Type(), uint64(metabyte), false),
+ }, typeFields...)
+ if hasMethodSet {
+ typeFields = append([]llvm.Value{
+ llvm.ConstBitCast(c.getTypeMethodSet(typ), c.i8ptrType),
+ }, typeFields...)
}
+ alignment := c.targetData.TypeAllocSize(c.i8ptrType)
+ globalValue := c.ctx.ConstStruct(typeFields, false)
global.SetInitializer(globalValue)
global.SetLinkage(llvm.LinkOnceODRLinkage)
global.SetGlobalConstant(true)
+ global.SetAlignment(int(alignment))
+ if c.Debug {
+ file := c.getDIFile("<Go type>")
+ diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{
+ Name: "type " + typ.String(),
+ File: file,
+ Line: 1,
+ Type: c.getDIType(globalType),
+ LocalToUnit: false,
+ Expr: c.dibuilder.CreateExpression(nil),
+ AlignInBits: uint32(alignment * 8),
+ })
+ global.AddMetadata(0, diglobal)
+ }
}
- return global
+ offset := uint64(0)
+ if hasMethodSet {
+ // The pointer to the method set is always the first element of the
+ // global (if there is a method set). However, the pointer we return
+ // should point to the 'kind' field not the method set.
+ offset = 1
+ }
+ return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{
+ llvm.ConstInt(llvm.Int32Type(), 0, false),
+ llvm.ConstInt(llvm.Int32Type(), offset, false),
+ })
}
-// makeStructTypeFields creates a new global that stores all type information
-// related to this struct type, and returns the resulting global. This global is
-// actually an array of all the fields in the structs.
-func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
- // The global is an array of runtime.structField structs.
- runtimeStructField := c.getLLVMRuntimeType("structField")
- structGlobalType := llvm.ArrayType(runtimeStructField, typ.NumFields())
- structGlobal := llvm.AddGlobal(c.mod, structGlobalType, "reflect/types.structFields")
- structGlobalValue := llvm.ConstNull(structGlobalType)
- for i := 0; i < typ.NumFields(); i++ {
- fieldGlobalValue := llvm.ConstNull(runtimeStructField)
- fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, c.getTypeCode(typ.Field(i).Type()), 0, "")
- fieldNameType, fieldName := c.makeGlobalArray([]byte(typ.Field(i).Name()), "reflect/types.structFieldName", c.ctx.Int8Type())
- fieldName.SetLinkage(llvm.PrivateLinkage)
- fieldName.SetUnnamedAddr(true)
- fieldName = llvm.ConstGEP(fieldNameType, fieldName, []llvm.Value{
- llvm.ConstInt(c.ctx.Int32Type(), 0, false),
- llvm.ConstInt(c.ctx.Int32Type(), 0, false),
- })
- fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldName, 1, "")
- if typ.Tag(i) != "" {
- fieldTagType, fieldTag := c.makeGlobalArray([]byte(typ.Tag(i)), "reflect/types.structFieldTag", c.ctx.Int8Type())
- fieldTag.SetLinkage(llvm.PrivateLinkage)
- fieldTag.SetUnnamedAddr(true)
- fieldTag = llvm.ConstGEP(fieldTagType, fieldTag, []llvm.Value{
- llvm.ConstInt(c.ctx.Int32Type(), 0, false),
- llvm.ConstInt(c.ctx.Int32Type(), 0, false),
- })
- fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldTag, 2, "")
- }
- if typ.Field(i).Embedded() {
- fieldEmbedded := llvm.ConstInt(c.ctx.Int1Type(), 1, false)
- fieldGlobalValue = c.builder.CreateInsertValue(fieldGlobalValue, fieldEmbedded, 3, "")
- }
- structGlobalValue = c.builder.CreateInsertValue(structGlobalValue, fieldGlobalValue, i, "")
+// getTypeKind returns the type kind for the given type, as defined by
+// reflect.Kind.
+func getTypeKind(t types.Type) uint8 {
+ switch t := t.Underlying().(type) {
+ case *types.Basic:
+ return basicTypes[t.Kind()]
+ case *types.Chan:
+ return typeKindChan
+ case *types.Interface:
+ return typeKindInterface
+ case *types.Pointer:
+ return typeKindPointer
+ case *types.Slice:
+ return typeKindSlice
+ case *types.Array:
+ return typeKindArray
+ case *types.Signature:
+ return typeKindSignature
+ case *types.Map:
+ return typeKindMap
+ case *types.Struct:
+ return typeKindStruct
+ default:
+ panic("unknown type")
}
- structGlobal.SetInitializer(structGlobalValue)
- structGlobal.SetUnnamedAddr(true)
- structGlobal.SetLinkage(llvm.PrivateLinkage)
- return structGlobal
}
-var basicTypes = [...]string{
+var basicTypeNames = [...]string{
types.Bool: "bool",
types.Int: "int",
types.Int8: "int8",
@@ -183,7 +344,7 @@ func getTypeCodeName(t types.Type) string {
case *types.Array:
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
case *types.Basic:
- return "basic:" + basicTypes[t.Kind()]
+ return "basic:" + basicTypeNames[t.Kind()]
case *types.Chan:
return "chan:" + getTypeCodeName(t.Elem())
case *types.Interface:
@@ -235,75 +396,40 @@ func getTypeCodeName(t types.Type) string {
// getTypeMethodSet returns a reference (GEP) to a global method set. This
// method set should be unreferenced after the interface lowering pass.
func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
- global := c.mod.NamedGlobal(typ.String() + "$methodset")
- zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
- if !global.IsNil() {
- // the method set already exists
- return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{zero, zero})
- }
-
- ms := c.program.MethodSets.MethodSet(typ)
- if ms.Len() == 0 {
- // no methods, so can leave that one out
- return llvm.ConstPointerNull(llvm.PointerType(c.getLLVMRuntimeType("interfaceMethodInfo"), 0))
- }
-
- methods := make([]llvm.Value, ms.Len())
- interfaceMethodInfoType := c.getLLVMRuntimeType("interfaceMethodInfo")
- for i := 0; i < ms.Len(); i++ {
- method := ms.At(i)
- signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func))
- fn := c.program.MethodValue(method)
- llvmFnType, llvmFn := c.getFunction(fn)
- if llvmFn.IsNil() {
- // compiler error, so panic
- panic("cannot find function: " + c.getFunctionInfo(fn).linkName)
+ globalName := typ.String() + "$methodset"
+ global := c.mod.NamedGlobal(globalName)
+ if global.IsNil() {
+ ms := c.program.MethodSets.MethodSet(typ)
+
+ // Create method set.
+ var signatures, wrappers []llvm.Value
+ for i := 0; i < ms.Len(); i++ {
+ method := ms.At(i)
+ signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func))
+ signatures = append(signatures, signatureGlobal)
+ fn := c.program.MethodValue(method)
+ llvmFnType, llvmFn := c.getFunction(fn)
+ if llvmFn.IsNil() {
+ // compiler error, so panic
+ panic("cannot find function: " + c.getFunctionInfo(fn).linkName)
+ }
+ wrapper := c.getInterfaceInvokeWrapper(fn, llvmFnType, llvmFn)
+ wrappers = append(wrappers, wrapper)
}
- wrapper := c.getInterfaceInvokeWrapper(fn, llvmFnType, llvmFn)
- methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{
- signatureGlobal,
- llvm.ConstPtrToInt(wrapper, c.uintptrType),
- })
- methods[i] = methodInfo
- }
- arrayType := llvm.ArrayType(interfaceMethodInfoType, len(methods))
- value := llvm.ConstArray(interfaceMethodInfoType, methods)
- global = llvm.AddGlobal(c.mod, arrayType, typ.String()+"$methodset")
- global.SetInitializer(value)
- global.SetGlobalConstant(true)
- global.SetLinkage(llvm.LinkOnceODRLinkage)
- return llvm.ConstGEP(arrayType, global, []llvm.Value{zero, zero})
-}
-// getInterfaceMethodSet returns a global variable with the method set of the
-// given named interface type. This method set is used by the interface lowering
-// pass.
-func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value {
- name := typ.String()
- if _, ok := typ.(*types.Named); !ok {
- // Anonymous interface.
- name = "reflect/types.interface:" + name
- }
- global := c.mod.NamedGlobal(name + "$interface")
- zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
- if !global.IsNil() {
- // method set already exist, return it
- return llvm.ConstGEP(global.GlobalValueType(), global, []llvm.Value{zero, zero})
- }
-
- // Every method is a *i8 reference indicating the signature of this method.
- methods := make([]llvm.Value, typ.Underlying().(*types.Interface).NumMethods())
- for i := range methods {
- method := typ.Underlying().(*types.Interface).Method(i)
- methods[i] = c.getMethodSignature(method)
+ // Construct global value.
+ globalValue := c.ctx.ConstStruct([]llvm.Value{
+ llvm.ConstInt(c.uintptrType, uint64(ms.Len()), false),
+ llvm.ConstArray(c.i8ptrType, signatures),
+ c.ctx.ConstStruct(wrappers, false),
+ }, false)
+ global = llvm.AddGlobal(c.mod, globalValue.Type(), globalName)
+ global.SetInitializer(globalValue)
+ global.SetGlobalConstant(true)
+ global.SetUnnamedAddr(true)
+ global.SetLinkage(llvm.LinkOnceODRLinkage)
}
-
- value := llvm.ConstArray(c.i8ptrType, methods)
- global = llvm.AddGlobal(c.mod, value.Type(), name+"$interface")
- global.SetInitializer(value)
- global.SetGlobalConstant(true)
- global.SetLinkage(llvm.LinkOnceODRLinkage)
- return llvm.ConstGEP(value.Type(), global, []llvm.Value{zero, zero})
+ return global
}
// getMethodSignatureName returns a unique name (that can be used as the name of
@@ -443,7 +569,7 @@ func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) ll
fnName := getTypeCodeName(assertedType.Underlying()) + ".$typeassert"
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
- llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.uintptrType}, false)
+ llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.i8ptrType}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
c.addStandardDeclaredAttributes(llvmFn)
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
@@ -464,7 +590,7 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
for i := 0; i < sig.Params().Len(); i++ {
paramTuple = append(paramTuple, sig.Params().At(i))
}
- paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.Uintptr]))
+ paramTuple = append(paramTuple, types.NewVar(token.NoPos, nil, "$typecode", types.Typ[types.UnsafePointer]))
llvmFnType := c.getRawFuncType(types.NewSignature(sig.Recv(), types.NewTuple(paramTuple...), sig.Results(), false))
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
c.addStandardDeclaredAttributes(llvmFn)
@@ -601,7 +727,7 @@ func typestring(t types.Type) string {
case *types.Array:
return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem())
case *types.Basic:
- return basicTypes[t.Kind()]
+ return basicTypeNames[t.Kind()]
case *types.Chan:
switch t.Dir() {
case types.SendRecv: