func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { // Each runtime type is preceded by an interface{}. initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false) global = llvm.AddGlobal(tm.module, initType, "") ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0)) // interface{} containing v's *commonType representation. runtimeTypeValue := llvm.Undef(tm.runtimeType) zero := llvm.ConstNull(llvm.Int32Type()) one := llvm.ConstInt(llvm.Int32Type(), 1, false) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) if tm.commonTypePtrRuntimeType.IsNil() { // Create a dummy pointer value, which we'll update straight after // defining the runtime type info for commonType. tm.commonTypePtrRuntimeType = llvm.Undef(i8ptr) commonTypePtr := &types.Pointer{Base: tm.commonType} commonTypeGlobal, commonTypeRuntimeType := tm.makeRuntimeType(tm.commonType) tm.types[tm.commonType.String()] = runtimeTypeInfo{commonTypeGlobal, commonTypeRuntimeType} commonTypePtrGlobal, commonTypePtrRuntimeType := tm.makeRuntimeType(commonTypePtr) tm.types[commonTypePtr.String()] = runtimeTypeInfo{commonTypePtrGlobal, commonTypePtrRuntimeType} tm.commonTypePtrRuntimeType = llvm.ConstBitCast(commonTypePtrRuntimeType, i8ptr) if tm.pkgpath == tm.commonType.Package { // Update the interace{} header of the commonType/*commonType // runtime types we just created. for _, g := range [...]llvm.Value{commonTypeGlobal, commonTypePtrGlobal} { init := g.Initializer() typptr := tm.commonTypePtrRuntimeType runtimeTypeValue := llvm.ConstExtractValue(init, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, typptr, []uint32{0}) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) g.SetInitializer(init) } } } commonTypePtr := llvm.ConstGEP(global, []llvm.Value{zero, one}) commonTypePtr = llvm.ConstBitCast(commonTypePtr, i8ptr) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, tm.commonTypePtrRuntimeType, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, commonTypePtr, []uint32{1}) init := llvm.Undef(initType) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) init = llvm.ConstInsertValue(init, v, []uint32{1}) global.SetInitializer(init) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) // FIXME clean this up var pkgpathPtr llvm.Value var path string if data, ok := tm.functions.objectdata[n.Obj()]; ok { path = pkgpath(data.Package) } if path != "" { pkgpathPtr = tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } methodset := tm.functions.methods(n) methodfuncs := methodset.nonptr if ptr { methodfuncs = methodset.ptr } // Store methods. methods := make([]llvm.Value, len(methodfuncs)) for i, mfunc := range methodfuncs { ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(mfunc.Name()) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() tfn = llvm.ConstExtractValue(tfn, []uint32{0}) tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) { mfunc := methodset.lookup(mfunc.Name(), true) ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() ifn = llvm.ConstExtractValue(ifn, []uint32{0}) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(tm.inttype, uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) { pkgpath := tm.pkgmap[n.Obj] if pkgpath == "" { // XXX "builtin"? pkgpath = "runtime" } globalname := "__llgo.type.name." + pkgpath + "." + n.Obj.Name if pkgpath != tm.pkgpath { // We're not compiling the package from whence the type came, // so we'll just create a pointer to it here. global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } underlying := n.Underlying if name, ok := underlying.(*types.Name); ok { underlying = name.Underlying } global, ptr = tm.makeRuntimeType(underlying) globalInit := global.Initializer() // Locate the common type. underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1}) commonType := underlyingRuntimeType if underlyingRuntimeType.Type() != tm.runtimeCommonType { commonType = llvm.ConstExtractValue(commonType, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) pkgpathPtr := tm.globalStringPtr(pkgpath) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) // Replace the commonType's string representation. commonType = llvm.ConstInsertValue(commonType, namePtr, []uint32{8}) methods := make([]llvm.Value, len(n.Methods)) for index, m := range n.Methods { method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) ftyp := m.Type.(*types.Func) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // ifn (single-word receiver function pointer for interface calls) ifn := tm.resolver.Resolve(m).LLVMValue() // TODO generate trampoline as necessary. ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, ifn, []uint32{4}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[index] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9}) // Update the global's initialiser. Note that we take a copy // of the underlying type; we're not updating a shared type. if underlyingRuntimeType.Type() != tm.runtimeCommonType { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0}) } else { underlyingRuntimeType = commonType } globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1}) global.SetName(globalname) global.SetInitializer(globalInit) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Name, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) var pkgpathPtr llvm.Value if n.Package != "" { pkgpathPtr = tm.globalStringPtr(n.Package) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } // Store methods. methods := make([]llvm.Value, 0, len(n.Methods)) for _, m := range n.Methods { ftyp := m.Type.(*types.Func) ptrrecv := !types.Identical(ftyp.Recv.Type.(types.Type), n) if !ptr && ptrrecv { // For a type T, we only store methods where the // receiver is T and not *T. For *T we store both. continue } method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn needload := ptr && !ptrrecv if !needload { recvtyp := tm.ToLLVM(ftyp.Recv.Type.(types.Type)) needload = int(tm.target.TypeAllocSize(recvtyp)) > tm.target.PointerSize() } if needload { // If the receiver type is wider than a word, we // need to use an intermediate function which takes // a pointer-receiver, loads it, and then calls the // standard receiver function. fname := fmt.Sprintf("*%s.%s", ftyp.Recv.Type, m.Name) ifn = tm.module.NamedFunction(fname) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods = append(methods, method) } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }