github.com/aykevl/tinygo@v0.5.0/compiler/interface.go (about)

     1  package compiler
     2  
     3  // This file transforms interface-related instructions (*ssa.MakeInterface,
     4  // *ssa.TypeAssert, calls on interface types) to an intermediate IR form, to be
     5  // lowered to the final form by the interface lowering pass. See
     6  // interface-lowering.go for more details.
     7  
     8  import (
     9  	"go/token"
    10  	"go/types"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/tinygo-org/tinygo/ir"
    15  	"golang.org/x/tools/go/ssa"
    16  	"tinygo.org/x/go-llvm"
    17  )
    18  
    19  // parseMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction.
    20  // It tries to put the type in the interface value, but if that's not possible,
    21  // it will do an allocation of the right size and put that in the interface
    22  // value field.
    23  //
    24  // An interface value is a {typecode, value} tuple, or {i16, i8*} to be exact.
    25  func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) (llvm.Value, error) {
    26  	var itfValue llvm.Value
    27  	size := c.targetData.TypeAllocSize(val.Type())
    28  	if size > c.targetData.TypeAllocSize(c.i8ptrType) {
    29  		// Allocate on the heap and put a pointer in the interface.
    30  		// TODO: escape analysis.
    31  		sizeValue := llvm.ConstInt(c.uintptrType, size, false)
    32  		alloc := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, "makeinterface.alloc")
    33  		itfValueCast := c.builder.CreateBitCast(alloc, llvm.PointerType(val.Type(), 0), "makeinterface.cast.value")
    34  		c.builder.CreateStore(val, itfValueCast)
    35  		itfValue = c.builder.CreateBitCast(itfValueCast, c.i8ptrType, "makeinterface.cast.i8ptr")
    36  	} else if size == 0 {
    37  		itfValue = llvm.ConstPointerNull(c.i8ptrType)
    38  	} else {
    39  		// Directly place the value in the interface.
    40  		switch val.Type().TypeKind() {
    41  		case llvm.IntegerTypeKind:
    42  			itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "makeinterface.cast.int")
    43  		case llvm.PointerTypeKind:
    44  			itfValue = c.builder.CreateBitCast(val, c.i8ptrType, "makeinterface.cast.ptr")
    45  		case llvm.StructTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
    46  			// A bitcast would be useful here, but bitcast doesn't allow
    47  			// aggregate types. So we'll bitcast it using an alloca.
    48  			// Hopefully this will get optimized away.
    49  			mem := c.builder.CreateAlloca(c.i8ptrType, "makeinterface.cast.struct")
    50  			memStructPtr := c.builder.CreateBitCast(mem, llvm.PointerType(val.Type(), 0), "makeinterface.cast.struct.cast")
    51  			c.builder.CreateStore(val, memStructPtr)
    52  			itfValue = c.builder.CreateLoad(mem, "makeinterface.cast.load")
    53  		default:
    54  			return llvm.Value{}, c.makeError(pos, "todo: makeinterface: cast small type to i8*")
    55  		}
    56  	}
    57  	itfTypeCodeGlobal := c.getTypeCode(typ)
    58  	itfMethodSetGlobal, err := c.getTypeMethodSet(typ)
    59  	if err != nil {
    60  		return llvm.Value{}, nil
    61  	}
    62  	itfConcreteTypeGlobal := c.mod.NamedGlobal("typeInInterface:" + itfTypeCodeGlobal.Name())
    63  	if itfConcreteTypeGlobal.IsNil() {
    64  		typeInInterface := c.mod.GetTypeByName("runtime.typeInInterface")
    65  		itfConcreteTypeGlobal = llvm.AddGlobal(c.mod, typeInInterface, "typeInInterface:"+itfTypeCodeGlobal.Name())
    66  		itfConcreteTypeGlobal.SetInitializer(llvm.ConstNamedStruct(typeInInterface, []llvm.Value{itfTypeCodeGlobal, itfMethodSetGlobal}))
    67  		itfConcreteTypeGlobal.SetGlobalConstant(true)
    68  		itfConcreteTypeGlobal.SetLinkage(llvm.PrivateLinkage)
    69  	}
    70  	itfTypeCode := c.builder.CreatePtrToInt(itfConcreteTypeGlobal, c.uintptrType, "")
    71  	itf := llvm.Undef(c.mod.GetTypeByName("runtime._interface"))
    72  	itf = c.builder.CreateInsertValue(itf, itfTypeCode, 0, "")
    73  	itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
    74  	return itf, nil
    75  }
    76  
    77  // getTypeCode returns a reference to a type code.
    78  // It returns a pointer to an external global which should be replaced with the
    79  // real type in the interface lowering pass.
    80  func (c *Compiler) getTypeCode(typ types.Type) llvm.Value {
    81  	globalName := "type:" + getTypeCodeName(typ)
    82  	global := c.mod.NamedGlobal(globalName)
    83  	if global.IsNil() {
    84  		global = llvm.AddGlobal(c.mod, c.mod.GetTypeByName("runtime.typecodeID"), globalName)
    85  		global.SetGlobalConstant(true)
    86  	}
    87  	return global
    88  }
    89  
    90  // getTypeCodeName returns a name for this type that can be used in the
    91  // interface lowering pass to assign type codes as expected by the reflect
    92  // package. See getTypeCodeNum.
    93  func getTypeCodeName(t types.Type) string {
    94  	name := ""
    95  	if named, ok := t.(*types.Named); ok {
    96  		name = "~" + named.String() + ":"
    97  		t = t.Underlying()
    98  	}
    99  	switch t := t.(type) {
   100  	case *types.Array:
   101  		return "array:" + name + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
   102  	case *types.Basic:
   103  		var kind string
   104  		switch t.Kind() {
   105  		case types.Bool:
   106  			kind = "bool"
   107  		case types.Int:
   108  			kind = "int"
   109  		case types.Int8:
   110  			kind = "int8"
   111  		case types.Int16:
   112  			kind = "int16"
   113  		case types.Int32:
   114  			kind = "int32"
   115  		case types.Int64:
   116  			kind = "int64"
   117  		case types.Uint:
   118  			kind = "uint"
   119  		case types.Uint8:
   120  			kind = "uint8"
   121  		case types.Uint16:
   122  			kind = "uint16"
   123  		case types.Uint32:
   124  			kind = "uint32"
   125  		case types.Uint64:
   126  			kind = "uint64"
   127  		case types.Uintptr:
   128  			kind = "uintptr"
   129  		case types.Float32:
   130  			kind = "float32"
   131  		case types.Float64:
   132  			kind = "float64"
   133  		case types.Complex64:
   134  			kind = "complex64"
   135  		case types.Complex128:
   136  			kind = "complex128"
   137  		case types.String:
   138  			kind = "string"
   139  		case types.UnsafePointer:
   140  			kind = "unsafeptr"
   141  		default:
   142  			panic("unknown basic type: " + t.Name())
   143  		}
   144  		return "basic:" + name + kind
   145  	case *types.Chan:
   146  		return "chan:" + name + getTypeCodeName(t.Elem())
   147  	case *types.Interface:
   148  		methods := make([]string, t.NumMethods())
   149  		for i := 0; i < t.NumMethods(); i++ {
   150  			methods[i] = getTypeCodeName(t.Method(i).Type())
   151  		}
   152  		return "interface:" + name + "{" + strings.Join(methods, ",") + "}"
   153  	case *types.Map:
   154  		keyType := getTypeCodeName(t.Key())
   155  		elemType := getTypeCodeName(t.Elem())
   156  		return "map:" + name + "{" + keyType + "," + elemType + "}"
   157  	case *types.Pointer:
   158  		return "pointer:" + name + getTypeCodeName(t.Elem())
   159  	case *types.Signature:
   160  		params := make([]string, t.Params().Len())
   161  		for i := 0; i < t.Params().Len(); i++ {
   162  			params[i] = getTypeCodeName(t.Params().At(i).Type())
   163  		}
   164  		results := make([]string, t.Results().Len())
   165  		for i := 0; i < t.Results().Len(); i++ {
   166  			results[i] = getTypeCodeName(t.Results().At(i).Type())
   167  		}
   168  		return "func:" + name + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}"
   169  	case *types.Slice:
   170  		return "slice:" + name + getTypeCodeName(t.Elem())
   171  	case *types.Struct:
   172  		elems := make([]string, t.NumFields())
   173  		if t.NumFields() > 2 && t.Field(0).Name() == "C union" {
   174  			// TODO: report this as a normal error instead of panicking.
   175  			panic("cgo unions are not allowed in interfaces")
   176  		}
   177  		for i := 0; i < t.NumFields(); i++ {
   178  			elems[i] = getTypeCodeName(t.Field(i).Type())
   179  		}
   180  		return "struct:" + name + "{" + strings.Join(elems, ",") + "}"
   181  	default:
   182  		panic("unknown type: " + t.String())
   183  	}
   184  }
   185  
   186  // getTypeMethodSet returns a reference (GEP) to a global method set. This
   187  // method set should be unreferenced after the interface lowering pass.
   188  func (c *Compiler) getTypeMethodSet(typ types.Type) (llvm.Value, error) {
   189  	global := c.mod.NamedGlobal(typ.String() + "$methodset")
   190  	zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
   191  	if !global.IsNil() {
   192  		// the method set already exists
   193  		return llvm.ConstGEP(global, []llvm.Value{zero, zero}), nil
   194  	}
   195  
   196  	ms := c.ir.Program.MethodSets.MethodSet(typ)
   197  	if ms.Len() == 0 {
   198  		// no methods, so can leave that one out
   199  		return llvm.ConstPointerNull(llvm.PointerType(c.mod.GetTypeByName("runtime.interfaceMethodInfo"), 0)), nil
   200  	}
   201  
   202  	methods := make([]llvm.Value, ms.Len())
   203  	interfaceMethodInfoType := c.mod.GetTypeByName("runtime.interfaceMethodInfo")
   204  	for i := 0; i < ms.Len(); i++ {
   205  		method := ms.At(i)
   206  		signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func))
   207  		f := c.ir.GetFunction(c.ir.Program.MethodValue(method))
   208  		if f.LLVMFn.IsNil() {
   209  			// compiler error, so panic
   210  			panic("cannot find function: " + f.LinkName())
   211  		}
   212  		fn, err := c.getInterfaceInvokeWrapper(f)
   213  		if err != nil {
   214  			return llvm.Value{}, err
   215  		}
   216  		methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{
   217  			signatureGlobal,
   218  			llvm.ConstPtrToInt(fn, c.uintptrType),
   219  		})
   220  		methods[i] = methodInfo
   221  	}
   222  	arrayType := llvm.ArrayType(interfaceMethodInfoType, len(methods))
   223  	value := llvm.ConstArray(interfaceMethodInfoType, methods)
   224  	global = llvm.AddGlobal(c.mod, arrayType, typ.String()+"$methodset")
   225  	global.SetInitializer(value)
   226  	global.SetGlobalConstant(true)
   227  	global.SetLinkage(llvm.PrivateLinkage)
   228  	return llvm.ConstGEP(global, []llvm.Value{zero, zero}), nil
   229  }
   230  
   231  // getInterfaceMethodSet returns a global variable with the method set of the
   232  // given named interface type. This method set is used by the interface lowering
   233  // pass.
   234  func (c *Compiler) getInterfaceMethodSet(typ *types.Named) llvm.Value {
   235  	global := c.mod.NamedGlobal(typ.String() + "$interface")
   236  	zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
   237  	if !global.IsNil() {
   238  		// method set already exist, return it
   239  		return llvm.ConstGEP(global, []llvm.Value{zero, zero})
   240  	}
   241  
   242  	// Every method is a *i16 reference indicating the signature of this method.
   243  	methods := make([]llvm.Value, typ.Underlying().(*types.Interface).NumMethods())
   244  	for i := range methods {
   245  		method := typ.Underlying().(*types.Interface).Method(i)
   246  		methods[i] = c.getMethodSignature(method)
   247  	}
   248  
   249  	value := llvm.ConstArray(methods[0].Type(), methods)
   250  	global = llvm.AddGlobal(c.mod, value.Type(), typ.String()+"$interface")
   251  	global.SetInitializer(value)
   252  	global.SetGlobalConstant(true)
   253  	global.SetLinkage(llvm.PrivateLinkage)
   254  	return llvm.ConstGEP(global, []llvm.Value{zero, zero})
   255  }
   256  
   257  // getMethodSignature returns a global variable which is a reference to an
   258  // external *i16 indicating the indicating the signature of this method. It is
   259  // used during the interface lowering pass.
   260  func (c *Compiler) getMethodSignature(method *types.Func) llvm.Value {
   261  	signature := ir.MethodSignature(method)
   262  	signatureGlobal := c.mod.NamedGlobal("func " + signature)
   263  	if signatureGlobal.IsNil() {
   264  		signatureGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), "func "+signature)
   265  		signatureGlobal.SetGlobalConstant(true)
   266  	}
   267  	return signatureGlobal
   268  }
   269  
   270  // parseTypeAssert will emit the code for a typeassert, used in if statements
   271  // and in type switches (Go SSA does not have type switches, only if/else
   272  // chains). Note that even though the Go SSA does not contain type switches,
   273  // LLVM will recognize the pattern and make it a real switch in many cases.
   274  //
   275  // Type asserts on concrete types are trivial: just compare type numbers. Type
   276  // asserts on interfaces are more difficult, see the comments in the function.
   277  func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Value, error) {
   278  	itf, err := c.parseExpr(frame, expr.X)
   279  	if err != nil {
   280  		return llvm.Value{}, err
   281  	}
   282  	assertedType, err := c.getLLVMType(expr.AssertedType)
   283  	if err != nil {
   284  		return llvm.Value{}, err
   285  	}
   286  	valueNil, err := c.getZeroValue(assertedType)
   287  	if err != nil {
   288  		return llvm.Value{}, err
   289  	}
   290  
   291  	actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
   292  	commaOk := llvm.Value{}
   293  	if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
   294  		// Type assert on interface type.
   295  		// This pseudo call will be lowered in the interface lowering pass to a
   296  		// real call which checks whether the provided typecode is any of the
   297  		// concrete types that implements this interface.
   298  		// This is very different from how interface asserts are implemented in
   299  		// the main Go compiler, where the runtime checks whether the type
   300  		// implements each method of the interface. See:
   301  		// https://research.swtch.com/interfaces
   302  		methodSet := c.getInterfaceMethodSet(expr.AssertedType.(*types.Named))
   303  		commaOk = c.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
   304  
   305  	} else {
   306  		// Type assert on concrete type.
   307  		// Call runtime.typeAssert, which will be lowered to a simple icmp or
   308  		// const false in the interface lowering pass.
   309  		assertedTypeCodeGlobal := c.getTypeCode(expr.AssertedType)
   310  		commaOk = c.createRuntimeCall("typeAssert", []llvm.Value{actualTypeNum, assertedTypeCodeGlobal}, "typecode")
   311  	}
   312  
   313  	// Add 2 new basic blocks (that should get optimized away): one for the
   314  	// 'ok' case and one for all instructions following this type assert.
   315  	// This is necessary because we need to insert the casted value or the
   316  	// nil value based on whether the assert was successful. Casting before
   317  	// this check tells LLVM that it can use this value and may
   318  	// speculatively dereference pointers before the check. This can lead to
   319  	// a miscompilation resulting in a segfault at runtime.
   320  	// Additionally, this is even required by the Go spec: a failed
   321  	// typeassert should return a zero value, not an incorrectly casted
   322  	// value.
   323  
   324  	prevBlock := c.builder.GetInsertBlock()
   325  	okBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "typeassert.ok")
   326  	nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "typeassert.next")
   327  	frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes
   328  	c.builder.CreateCondBr(commaOk, okBlock, nextBlock)
   329  
   330  	// Retrieve the value from the interface if the type assert was
   331  	// successful.
   332  	c.builder.SetInsertPointAtEnd(okBlock)
   333  	var valueOk llvm.Value
   334  	if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
   335  		// Type assert on interface type. Easy: just return the same
   336  		// interface value.
   337  		valueOk = itf
   338  	} else {
   339  		// Type assert on concrete type. Extract the underlying type from
   340  		// the interface (but only after checking it matches).
   341  		valuePtr := c.builder.CreateExtractValue(itf, 1, "typeassert.value.ptr")
   342  		size := c.targetData.TypeAllocSize(assertedType)
   343  		if size > c.targetData.TypeAllocSize(c.i8ptrType) {
   344  			// Value was stored in an allocated buffer, load it from there.
   345  			valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "")
   346  			valueOk = c.builder.CreateLoad(valuePtrCast, "typeassert.value.ok")
   347  		} else if size == 0 {
   348  			valueOk, err = c.getZeroValue(assertedType)
   349  			if err != nil {
   350  				return llvm.Value{}, err
   351  			}
   352  		} else {
   353  			// Value was stored directly in the interface.
   354  			switch assertedType.TypeKind() {
   355  			case llvm.IntegerTypeKind:
   356  				valueOk = c.builder.CreatePtrToInt(valuePtr, assertedType, "typeassert.value.ok")
   357  			case llvm.PointerTypeKind:
   358  				valueOk = c.builder.CreateBitCast(valuePtr, assertedType, "typeassert.value.ok")
   359  			default: // struct, float, etc.
   360  				// A bitcast would be useful here, but bitcast doesn't allow
   361  				// aggregate types. So we'll bitcast it using an alloca.
   362  				// Hopefully this will get optimized away.
   363  				mem := c.builder.CreateAlloca(c.i8ptrType, "")
   364  				c.builder.CreateStore(valuePtr, mem)
   365  				memCast := c.builder.CreateBitCast(mem, llvm.PointerType(assertedType, 0), "")
   366  				valueOk = c.builder.CreateLoad(memCast, "typeassert.value.ok")
   367  			}
   368  		}
   369  	}
   370  	c.builder.CreateBr(nextBlock)
   371  
   372  	// Continue after the if statement.
   373  	c.builder.SetInsertPointAtEnd(nextBlock)
   374  	phi := c.builder.CreatePHI(assertedType, "typeassert.value")
   375  	phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
   376  
   377  	if expr.CommaOk {
   378  		tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple
   379  		tuple = c.builder.CreateInsertValue(tuple, phi, 0, "")                                                  // insert value
   380  		tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "")                                              // insert 'comma ok' boolean
   381  		return tuple, nil
   382  	} else {
   383  		// This is kind of dirty as the branch above becomes mostly useless,
   384  		// but hopefully this gets optimized away.
   385  		c.createRuntimeCall("interfaceTypeAssert", []llvm.Value{commaOk}, "")
   386  		return phi, nil
   387  	}
   388  }
   389  
   390  // getInvokeCall creates and returns the function pointer and parameters of an
   391  // interface call. It can be used in a call or defer instruction.
   392  func (c *Compiler) getInvokeCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, []llvm.Value, error) {
   393  	// Call an interface method with dynamic dispatch.
   394  	itf, err := c.parseExpr(frame, instr.Value) // interface
   395  	if err != nil {
   396  		return llvm.Value{}, nil, err
   397  	}
   398  
   399  	llvmFnType, err := c.getRawFuncType(instr.Method.Type().(*types.Signature))
   400  	if err != nil {
   401  		return llvm.Value{}, nil, err
   402  	}
   403  
   404  	typecode := c.builder.CreateExtractValue(itf, 0, "invoke.typecode")
   405  	values := []llvm.Value{
   406  		typecode,
   407  		c.getInterfaceMethodSet(instr.Value.Type().(*types.Named)),
   408  		c.getMethodSignature(instr.Method),
   409  	}
   410  	fn := c.createRuntimeCall("interfaceMethod", values, "invoke.func")
   411  	fnCast := c.builder.CreateIntToPtr(fn, llvmFnType, "invoke.func.cast")
   412  	receiverValue := c.builder.CreateExtractValue(itf, 1, "invoke.func.receiver")
   413  
   414  	args := []llvm.Value{receiverValue}
   415  	for _, arg := range instr.Args {
   416  		val, err := c.parseExpr(frame, arg)
   417  		if err != nil {
   418  			return llvm.Value{}, nil, err
   419  		}
   420  		args = append(args, val)
   421  	}
   422  	// Add the context parameter. An interface call never takes a context but we
   423  	// have to supply the parameter anyway.
   424  	args = append(args, llvm.Undef(c.i8ptrType))
   425  	// Add the parent goroutine handle.
   426  	args = append(args, llvm.Undef(c.i8ptrType))
   427  
   428  	return fnCast, args, nil
   429  }
   430  
   431  // interfaceInvokeWrapper keeps some state between getInterfaceInvokeWrapper and
   432  // createInterfaceInvokeWrapper. The former is called during IR construction
   433  // itself and the latter is called when finishing up the IR.
   434  type interfaceInvokeWrapper struct {
   435  	fn           *ir.Function
   436  	wrapper      llvm.Value
   437  	receiverType llvm.Type
   438  }
   439  
   440  // Wrap an interface method function pointer. The wrapper takes in a pointer to
   441  // the underlying value, dereferences it, and calls the real method. This
   442  // wrapper is only needed when the interface value actually doesn't fit in a
   443  // pointer and a pointer to the value must be created.
   444  func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) (llvm.Value, error) {
   445  	wrapperName := f.LinkName() + "$invoke"
   446  	wrapper := c.mod.NamedFunction(wrapperName)
   447  	if !wrapper.IsNil() {
   448  		// Wrapper already created. Return it directly.
   449  		return wrapper, nil
   450  	}
   451  
   452  	// Get the expanded receiver type.
   453  	receiverType, err := c.getLLVMType(f.Params[0].Type())
   454  	if err != nil {
   455  		return llvm.Value{}, err
   456  	}
   457  	expandedReceiverType := c.expandFormalParamType(receiverType)
   458  
   459  	// Does this method even need any wrapping?
   460  	if len(expandedReceiverType) == 1 && receiverType.TypeKind() == llvm.PointerTypeKind {
   461  		// Nothing to wrap.
   462  		// Casting a function signature to a different signature and calling it
   463  		// with a receiver pointer bitcasted to *i8 (as done in calls on an
   464  		// interface) is hopefully a safe (defined) operation.
   465  		return f.LLVMFn, nil
   466  	}
   467  
   468  	// create wrapper function
   469  	fnType := f.LLVMFn.Type().ElementType()
   470  	paramTypes := append([]llvm.Type{c.i8ptrType}, fnType.ParamTypes()[len(expandedReceiverType):]...)
   471  	wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
   472  	wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
   473  	c.interfaceInvokeWrappers = append(c.interfaceInvokeWrappers, interfaceInvokeWrapper{
   474  		fn:           f,
   475  		wrapper:      wrapper,
   476  		receiverType: receiverType,
   477  	})
   478  	return wrapper, nil
   479  }
   480  
   481  // createInterfaceInvokeWrapper finishes the work of getInterfaceInvokeWrapper,
   482  // see that function for details.
   483  func (c *Compiler) createInterfaceInvokeWrapper(state interfaceInvokeWrapper) error {
   484  	wrapper := state.wrapper
   485  	fn := state.fn
   486  	receiverType := state.receiverType
   487  	wrapper.SetLinkage(llvm.InternalLinkage)
   488  	wrapper.SetUnnamedAddr(true)
   489  
   490  	// add debug info if needed
   491  	if c.Debug {
   492  		pos := c.ir.Program.Fset.Position(fn.Pos())
   493  		difunc, err := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
   494  		if err != nil {
   495  			return err
   496  		}
   497  		c.builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
   498  	}
   499  
   500  	// set up IR builder
   501  	block := c.ctx.AddBasicBlock(wrapper, "entry")
   502  	c.builder.SetInsertPointAtEnd(block)
   503  
   504  	var receiverPtr llvm.Value
   505  	if c.targetData.TypeAllocSize(receiverType) > c.targetData.TypeAllocSize(c.i8ptrType) {
   506  		// The receiver is passed in using a pointer. We have to load it here
   507  		// and pass it by value to the real function.
   508  
   509  		// Load the underlying value.
   510  		receiverPtrType := llvm.PointerType(receiverType, 0)
   511  		receiverPtr = c.builder.CreateBitCast(wrapper.Param(0), receiverPtrType, "receiver.ptr")
   512  	} else {
   513  		// The value is stored in the interface, but it is of type struct which
   514  		// is expanded to multiple parameters (e.g. {i8, i8}). So we have to
   515  		// receive the struct as parameter, expand it, and pass it on to the
   516  		// real function.
   517  
   518  		// Cast the passed-in i8* to the struct value (using an alloca) and
   519  		// extract its values.
   520  		alloca := c.builder.CreateAlloca(c.i8ptrType, "receiver.alloca")
   521  		c.builder.CreateStore(wrapper.Param(0), alloca)
   522  		receiverPtr = c.builder.CreateBitCast(alloca, llvm.PointerType(receiverType, 0), "receiver.ptr")
   523  	}
   524  
   525  	receiverValue := c.builder.CreateLoad(receiverPtr, "receiver")
   526  	params := append(c.expandFormalParam(receiverValue), wrapper.Params()[1:]...)
   527  	if fn.LLVMFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind {
   528  		c.builder.CreateCall(fn.LLVMFn, params, "")
   529  		c.builder.CreateRetVoid()
   530  	} else {
   531  		ret := c.builder.CreateCall(fn.LLVMFn, params, "ret")
   532  		c.builder.CreateRet(ret)
   533  	}
   534  
   535  	return nil
   536  }