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

     1  package compiler
     2  
     3  // This file provides function to lower interface intrinsics to their final LLVM
     4  // form, optimizing them in the process.
     5  //
     6  // During SSA construction, the following pseudo-calls are created:
     7  //     runtime.typeAssert(typecode, assertedType)
     8  //     runtime.interfaceImplements(typecode, interfaceMethodSet)
     9  //     runtime.interfaceMethod(typecode, interfaceMethodSet, signature)
    10  // See src/runtime/interface.go for details.
    11  // These calls are to declared but not defined functions, so the optimizer will
    12  // leave them alone.
    13  //
    14  // This pass lowers the above functions to their final form:
    15  //
    16  // typeAssert:
    17  //     Replaced with an icmp instruction so it can be directly used in a type
    18  //     switch. This is very easy to optimize for LLVM: it will often translate a
    19  //     type switch into a regular switch statement.
    20  //     When this type assert is not possible (the type is never used in an
    21  //     interface), this call is replaced with a constant false to optimize the
    22  //     type assert away completely.
    23  //
    24  // interfaceImplements:
    25  //     This call is translated into a call that checks whether the underlying
    26  //     type is one of the types implementing this interface.
    27  //     When there is only one type implementing this interface, the check is
    28  //     replaced with a simple icmp instruction, just like a type assert.
    29  //     When there is no type at all that implements this interface, it is
    30  //     replaced with a constant false to optimize it completely.
    31  //
    32  // interfaceMethod:
    33  //     This call is replaced with a call to a function that calls the
    34  //     appropriate method depending on the underlying type.
    35  //     When there is only one type implementing this interface, this call is
    36  //     translated into a direct call of that method.
    37  //     When there is no type implementing this interface, this code is marked
    38  //     unreachable as there is no way such an interface could be constructed.
    39  //
    40  // Note that this way of implementing interfaces is very different from how the
    41  // main Go compiler implements them. For more details on how the main Go
    42  // compiler does it: https://research.swtch.com/interfaces
    43  
    44  import (
    45  	"sort"
    46  	"strings"
    47  
    48  	"tinygo.org/x/go-llvm"
    49  )
    50  
    51  // signatureInfo is a Go signature of an interface method. It does not represent
    52  // any method in particular.
    53  type signatureInfo struct {
    54  	name       string
    55  	methods    []*methodInfo
    56  	interfaces []*interfaceInfo
    57  }
    58  
    59  // methodName takes a method name like "func String()" and returns only the
    60  // name, which is "String" in this case.
    61  func (s *signatureInfo) methodName() string {
    62  	if !strings.HasPrefix(s.name, "func ") {
    63  		panic("signature must start with \"func \"")
    64  	}
    65  	methodName := s.name[len("func "):]
    66  	if openingParen := strings.IndexByte(methodName, '('); openingParen < 0 {
    67  		panic("no opening paren in signature name")
    68  	} else {
    69  		return methodName[:openingParen]
    70  	}
    71  }
    72  
    73  // methodInfo describes a single method on a concrete type.
    74  type methodInfo struct {
    75  	*signatureInfo
    76  	function llvm.Value
    77  }
    78  
    79  // typeInfo describes a single concrete Go type, which can be a basic or a named
    80  // type. If it is a named type, it may have methods.
    81  type typeInfo struct {
    82  	name                string
    83  	typecode            llvm.Value
    84  	methodSet           llvm.Value
    85  	num                 uint64 // the type number after lowering
    86  	countMakeInterfaces int    // how often this type is used in an interface
    87  	countTypeAsserts    int    // how often a type assert happens on this method
    88  	methods             []*methodInfo
    89  }
    90  
    91  // getMethod looks up the method on this type with the given signature and
    92  // returns it. The method must exist on this type, otherwise getMethod will
    93  // panic.
    94  func (t *typeInfo) getMethod(signature *signatureInfo) *methodInfo {
    95  	for _, method := range t.methods {
    96  		if method.signatureInfo == signature {
    97  			return method
    98  		}
    99  	}
   100  	panic("could not find method")
   101  }
   102  
   103  // typeInfoSlice implements sort.Slice, sorting the most commonly used types
   104  // first.
   105  type typeInfoSlice []*typeInfo
   106  
   107  func (t typeInfoSlice) Len() int { return len(t) }
   108  func (t typeInfoSlice) Less(i, j int) bool {
   109  	// Try to sort the most commonly used types first.
   110  	if t[i].countTypeAsserts != t[j].countTypeAsserts {
   111  		return t[i].countTypeAsserts < t[j].countTypeAsserts
   112  	}
   113  	if t[i].countMakeInterfaces != t[j].countMakeInterfaces {
   114  		return t[i].countMakeInterfaces < t[j].countMakeInterfaces
   115  	}
   116  	return t[i].name < t[j].name
   117  }
   118  func (t typeInfoSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
   119  
   120  // interfaceInfo keeps information about a Go interface type, including all
   121  // methods it has.
   122  type interfaceInfo struct {
   123  	name        string                        // name with $interface suffix
   124  	signatures  []*signatureInfo              // method set
   125  	types       typeInfoSlice                 // types this interface implements
   126  	assertFunc  llvm.Value                    // runtime.interfaceImplements replacement
   127  	methodFuncs map[*signatureInfo]llvm.Value // runtime.interfaceMethod replacements for each signature
   128  }
   129  
   130  // id removes the $interface suffix from the name and returns the clean
   131  // interface name including import path.
   132  func (itf *interfaceInfo) id() string {
   133  	if !strings.HasSuffix(itf.name, "$interface") {
   134  		panic("interface type does not have $interface suffix: " + itf.name)
   135  	}
   136  	return itf.name[:len(itf.name)-len("$interface")]
   137  }
   138  
   139  // lowerInterfacesPass keeps state related to the interface lowering pass. The
   140  // pass has been implemented as an object type because of its complexity, but
   141  // should be seen as a regular function call (see LowerInterfaces).
   142  type lowerInterfacesPass struct {
   143  	*Compiler
   144  	types      map[string]*typeInfo
   145  	signatures map[string]*signatureInfo
   146  	interfaces map[string]*interfaceInfo
   147  }
   148  
   149  // Lower all interface functions. They are emitted by the compiler as
   150  // higher-level intrinsics that need some lowering before LLVM can work on them.
   151  // This is done so that a few cleanup passes can run before assigning the final
   152  // type codes.
   153  func (c *Compiler) LowerInterfaces() {
   154  	p := &lowerInterfacesPass{
   155  		Compiler:   c,
   156  		types:      make(map[string]*typeInfo),
   157  		signatures: make(map[string]*signatureInfo),
   158  		interfaces: make(map[string]*interfaceInfo),
   159  	}
   160  	p.run()
   161  }
   162  
   163  // run runs the pass itself.
   164  func (p *lowerInterfacesPass) run() {
   165  	// Collect all type codes.
   166  	typecodeIDPtr := llvm.PointerType(p.mod.GetTypeByName("runtime.typecodeID"), 0)
   167  	typeInInterfacePtr := llvm.PointerType(p.mod.GetTypeByName("runtime.typeInInterface"), 0)
   168  	var typesInInterfaces []llvm.Value
   169  	for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
   170  		switch global.Type() {
   171  		case typecodeIDPtr:
   172  			// Retrieve Go type information based on an opaque global variable.
   173  			// Only the name of the global is relevant, the object itself is
   174  			// discarded afterwards.
   175  			name := global.Name()
   176  			t := &typeInfo{
   177  				name:     name,
   178  				typecode: global,
   179  			}
   180  			p.types[name] = t
   181  		case typeInInterfacePtr:
   182  			// Count per type how often it is put in an interface. Also, collect
   183  			// all methods this type has (if it is named).
   184  			typesInInterfaces = append(typesInInterfaces, global)
   185  			initializer := global.Initializer()
   186  			typecode := llvm.ConstExtractValue(initializer, []uint32{0})
   187  			methodSet := llvm.ConstExtractValue(initializer, []uint32{1})
   188  			t := p.types[typecode.Name()]
   189  			p.addTypeMethods(t, methodSet)
   190  
   191  			// Count the number of MakeInterface instructions, for sorting the
   192  			// typecodes later.
   193  			t.countMakeInterfaces += len(getUses(global))
   194  		}
   195  	}
   196  
   197  	// Count per type how often it is type asserted on (e.g. in a switch
   198  	// statement).
   199  	typeAssert := p.mod.NamedFunction("runtime.typeAssert")
   200  	typeAssertUses := getUses(typeAssert)
   201  	for _, use := range typeAssertUses {
   202  		typecode := use.Operand(1)
   203  		name := typecode.Name()
   204  		p.types[name].countTypeAsserts++
   205  	}
   206  
   207  	// Find all interface method calls.
   208  	interfaceMethod := p.mod.NamedFunction("runtime.interfaceMethod")
   209  	interfaceMethodUses := getUses(interfaceMethod)
   210  	for _, use := range interfaceMethodUses {
   211  		methodSet := use.Operand(1).Operand(0)
   212  		name := methodSet.Name()
   213  		if _, ok := p.interfaces[name]; !ok {
   214  			p.addInterface(methodSet)
   215  		}
   216  	}
   217  
   218  	// Find all interface type asserts.
   219  	interfaceImplements := p.mod.NamedFunction("runtime.interfaceImplements")
   220  	interfaceImplementsUses := getUses(interfaceImplements)
   221  	for _, use := range interfaceImplementsUses {
   222  		methodSet := use.Operand(1).Operand(0)
   223  		name := methodSet.Name()
   224  		if _, ok := p.interfaces[name]; !ok {
   225  			p.addInterface(methodSet)
   226  		}
   227  	}
   228  
   229  	// Find all the interfaces that are implemented per type.
   230  	for _, t := range p.types {
   231  		// This type has no methods, so don't spend time calculating them.
   232  		if len(t.methods) == 0 {
   233  			continue
   234  		}
   235  
   236  		// Pre-calculate a set of signatures that this type has, for easy
   237  		// lookup/check.
   238  		typeSignatureSet := make(map[*signatureInfo]struct{})
   239  		for _, method := range t.methods {
   240  			typeSignatureSet[method.signatureInfo] = struct{}{}
   241  		}
   242  
   243  		// A set of interfaces, mapped from the name to the info.
   244  		// When the name maps to a nil pointer, one of the methods of this type
   245  		// exists in the given interface but not all of them so this type
   246  		// doesn't implement the interface.
   247  		satisfiesInterfaces := make(map[string]*interfaceInfo)
   248  
   249  		for _, method := range t.methods {
   250  			for _, itf := range method.interfaces {
   251  				if _, ok := satisfiesInterfaces[itf.name]; ok {
   252  					// interface already checked with a different method
   253  					continue
   254  				}
   255  				// check whether this interface satisfies this type
   256  				satisfies := true
   257  				for _, itfSignature := range itf.signatures {
   258  					if _, ok := typeSignatureSet[itfSignature]; !ok {
   259  						satisfiesInterfaces[itf.name] = nil // does not satisfy
   260  						satisfies = false
   261  						break
   262  					}
   263  				}
   264  				if !satisfies {
   265  					continue
   266  				}
   267  				satisfiesInterfaces[itf.name] = itf
   268  			}
   269  		}
   270  
   271  		// Add this type to all interfaces that satisfy this type.
   272  		for _, itf := range satisfiesInterfaces {
   273  			if itf == nil {
   274  				// Interface does not implement this type, but one of the
   275  				// methods on this type also exists on the interface.
   276  				continue
   277  			}
   278  			itf.types = append(itf.types, t)
   279  		}
   280  	}
   281  
   282  	// Sort all types added to the interfaces, to check for more common types
   283  	// first.
   284  	for _, itf := range p.interfaces {
   285  		sort.Sort(itf.types)
   286  	}
   287  
   288  	// Replace all interface methods with their uses, if possible.
   289  	for _, use := range interfaceMethodUses {
   290  		typecode := use.Operand(0)
   291  		signature := p.signatures[use.Operand(2).Name()]
   292  
   293  		methodSet := use.Operand(1).Operand(0) // global variable
   294  		itf := p.interfaces[methodSet.Name()]
   295  		if len(itf.types) == 0 {
   296  			// This method call is impossible: no type implements this
   297  			// interface. In fact, the previous type assert that got this
   298  			// interface value should already have returned false.
   299  			// Replace the function pointer with undef (which will then be
   300  			// called), indicating to the optimizer this code is unreachable.
   301  			use.ReplaceAllUsesWith(llvm.Undef(p.uintptrType))
   302  			use.EraseFromParentAsInstruction()
   303  		} else if len(itf.types) == 1 {
   304  			// There is only one implementation of the given type.
   305  			// Call that function directly.
   306  			p.replaceInvokeWithCall(use, itf.types[0], signature)
   307  		} else {
   308  			// There are multiple types implementing this interface, thus there
   309  			// are multiple possible functions to call. Delegate calling the
   310  			// right function to a special wrapper function.
   311  			inttoptrs := getUses(use)
   312  			if len(inttoptrs) != 1 || inttoptrs[0].IsAIntToPtrInst().IsNil() {
   313  				panic("expected exactly one inttoptr use of runtime.interfaceMethod")
   314  			}
   315  			inttoptr := inttoptrs[0]
   316  			calls := getUses(inttoptr)
   317  			if len(calls) != 1 || calls[0].IsACallInst().IsNil() {
   318  				panic("expected exactly one call use of runtime.interfaceMethod")
   319  			}
   320  			call := calls[0]
   321  
   322  			// Set up parameters for the call. First copy the regular params...
   323  			params := make([]llvm.Value, call.OperandsCount())
   324  			paramTypes := make([]llvm.Type, len(params))
   325  			for i := 0; i < len(params)-1; i++ {
   326  				params[i] = call.Operand(i)
   327  				paramTypes[i] = params[i].Type()
   328  			}
   329  			// then add the typecode to the end of the list.
   330  			params[len(params)-1] = typecode
   331  			paramTypes[len(params)-1] = p.uintptrType
   332  
   333  			// Create a function that redirects the call to the destination
   334  			// call, after selecting the right concrete type.
   335  			redirector := p.getInterfaceMethodFunc(itf, signature, call.Type(), paramTypes)
   336  
   337  			// Replace the old lookup/inttoptr/call with the new call.
   338  			p.builder.SetInsertPointBefore(call)
   339  			retval := p.builder.CreateCall(redirector, params, "")
   340  			if retval.Type().TypeKind() != llvm.VoidTypeKind {
   341  				call.ReplaceAllUsesWith(retval)
   342  			}
   343  			call.EraseFromParentAsInstruction()
   344  			inttoptr.EraseFromParentAsInstruction()
   345  			use.EraseFromParentAsInstruction()
   346  		}
   347  	}
   348  
   349  	// Replace all typeasserts on interface types with matches on their concrete
   350  	// types, if possible.
   351  	for _, use := range interfaceImplementsUses {
   352  		actualType := use.Operand(0)
   353  
   354  		methodSet := use.Operand(1).Operand(0) // global variable
   355  		itf := p.interfaces[methodSet.Name()]
   356  		if len(itf.types) == 0 {
   357  			// There are no types implementing this interface, so this assert
   358  			// can never succeed.
   359  			// Signal this to the optimizer by branching on constant false. It
   360  			// should remove the "then" block.
   361  			use.ReplaceAllUsesWith(llvm.ConstInt(p.ctx.Int1Type(), 0, false))
   362  			use.EraseFromParentAsInstruction()
   363  		} else if len(itf.types) == 1 {
   364  			// There is only one type implementing this interface.
   365  			// Transform this interface assert into comparison against a
   366  			// constant.
   367  			p.builder.SetInsertPointBefore(use)
   368  			assertedType := p.builder.CreatePtrToInt(itf.types[0].typecode, p.uintptrType, "typeassert.typecode")
   369  			commaOk := p.builder.CreateICmp(llvm.IntEQ, assertedType, actualType, "typeassert.ok")
   370  			use.ReplaceAllUsesWith(commaOk)
   371  			use.EraseFromParentAsInstruction()
   372  		} else {
   373  			// There are multiple possible types implementing this interface.
   374  			// Create a function that does a type switch on all available types
   375  			// that implement this interface.
   376  			fn := p.getInterfaceImplementsFunc(itf)
   377  			p.builder.SetInsertPointBefore(use)
   378  			commaOk := p.builder.CreateCall(fn, []llvm.Value{actualType}, "typeassert.ok")
   379  			use.ReplaceAllUsesWith(commaOk)
   380  			use.EraseFromParentAsInstruction()
   381  		}
   382  	}
   383  
   384  	// Make a slice of types sorted by frequency of use.
   385  	typeSlice := make(typeInfoSlice, 0, len(p.types))
   386  	for _, t := range p.types {
   387  		typeSlice = append(typeSlice, t)
   388  	}
   389  	sort.Sort(sort.Reverse(typeSlice))
   390  
   391  	// A type code must fit in 16 bits.
   392  	if len(typeSlice) >= 1<<16 {
   393  		panic("typecode does not fit in a uint16: too many types in this program")
   394  	}
   395  
   396  	// Assign a type code for each type.
   397  	p.assignTypeCodes(typeSlice)
   398  
   399  	// Replace each use of a runtime.typeInInterface with the constant type
   400  	// code.
   401  	for _, global := range typesInInterfaces {
   402  		for _, use := range getUses(global) {
   403  			t := p.types[llvm.ConstExtractValue(global.Initializer(), []uint32{0}).Name()]
   404  			typecode := llvm.ConstInt(p.uintptrType, t.num, false)
   405  			use.ReplaceAllUsesWith(typecode)
   406  		}
   407  	}
   408  
   409  	// Replace each type assert with an actual type comparison or (if the type
   410  	// assert is impossible) the constant false.
   411  	for _, use := range typeAssertUses {
   412  		actualType := use.Operand(0)
   413  		assertedTypeGlobal := use.Operand(1)
   414  		t := p.types[assertedTypeGlobal.Name()]
   415  		var commaOk llvm.Value
   416  		if t.countMakeInterfaces == 0 {
   417  			// impossible type assert: optimize accordingly
   418  			commaOk = llvm.ConstInt(p.ctx.Int1Type(), 0, false)
   419  		} else {
   420  			// regular type assert
   421  			p.builder.SetInsertPointBefore(use)
   422  			commaOk = p.builder.CreateICmp(llvm.IntEQ, llvm.ConstPtrToInt(assertedTypeGlobal, p.uintptrType), actualType, "typeassert.ok")
   423  		}
   424  		use.ReplaceAllUsesWith(commaOk)
   425  		use.EraseFromParentAsInstruction()
   426  	}
   427  
   428  	// Fill in each helper function for type asserts on interfaces
   429  	// (interface-to-interface matches).
   430  	for _, itf := range p.interfaces {
   431  		if !itf.assertFunc.IsNil() {
   432  			p.createInterfaceImplementsFunc(itf)
   433  		}
   434  		for signature := range itf.methodFuncs {
   435  			p.createInterfaceMethodFunc(itf, signature)
   436  		}
   437  	}
   438  
   439  	// Replace all ptrtoint typecode placeholders with their final type code
   440  	// numbers.
   441  	for _, typ := range p.types {
   442  		for _, use := range getUses(typ.typecode) {
   443  			if !use.IsAConstantExpr().IsNil() && use.Opcode() == llvm.PtrToInt {
   444  				use.ReplaceAllUsesWith(llvm.ConstInt(p.uintptrType, typ.num, false))
   445  			}
   446  		}
   447  	}
   448  
   449  	// Remove stray runtime.typeInInterface globals. Required for the following
   450  	// cleanup.
   451  	for _, global := range typesInInterfaces {
   452  		global.EraseFromParentAsGlobal()
   453  	}
   454  
   455  	// Remove method sets of types. Unnecessary, but cleans up the IR for
   456  	// inspection.
   457  	for _, typ := range p.types {
   458  		if !typ.methodSet.IsNil() {
   459  			typ.methodSet.EraseFromParentAsGlobal()
   460  			typ.methodSet = llvm.Value{}
   461  		}
   462  	}
   463  }
   464  
   465  // addTypeMethods reads the method set of the given type info struct. It
   466  // retrieves the signatures and the references to the method functions
   467  // themselves for later type<->interface matching.
   468  func (p *lowerInterfacesPass) addTypeMethods(t *typeInfo, methodSet llvm.Value) {
   469  	if !t.methodSet.IsNil() || methodSet.IsNull() {
   470  		// no methods or methods already read
   471  		return
   472  	}
   473  	methodSet = methodSet.Operand(0) // get global from GEP
   474  
   475  	// This type has methods, collect all methods of this type.
   476  	t.methodSet = methodSet
   477  	set := methodSet.Initializer() // get value from global
   478  	for i := 0; i < set.Type().ArrayLength(); i++ {
   479  		methodData := llvm.ConstExtractValue(set, []uint32{uint32(i)})
   480  		signatureName := llvm.ConstExtractValue(methodData, []uint32{0}).Name()
   481  		function := llvm.ConstExtractValue(methodData, []uint32{1}).Operand(0)
   482  		signature := p.getSignature(signatureName)
   483  		method := &methodInfo{
   484  			function:      function,
   485  			signatureInfo: signature,
   486  		}
   487  		signature.methods = append(signature.methods, method)
   488  		t.methods = append(t.methods, method)
   489  	}
   490  }
   491  
   492  // addInterface reads information about an interface, which is the
   493  // fully-qualified name and the signatures of all methods it has.
   494  func (p *lowerInterfacesPass) addInterface(methodSet llvm.Value) {
   495  	name := methodSet.Name()
   496  	t := &interfaceInfo{
   497  		name: name,
   498  	}
   499  	p.interfaces[name] = t
   500  	methodSet = methodSet.Initializer() // get global value from getelementptr
   501  	for i := 0; i < methodSet.Type().ArrayLength(); i++ {
   502  		signatureName := llvm.ConstExtractValue(methodSet, []uint32{uint32(i)}).Name()
   503  		signature := p.getSignature(signatureName)
   504  		signature.interfaces = append(signature.interfaces, t)
   505  		t.signatures = append(t.signatures, signature)
   506  	}
   507  }
   508  
   509  // getSignature returns a new *signatureInfo, creating it if it doesn't already
   510  // exist.
   511  func (p *lowerInterfacesPass) getSignature(name string) *signatureInfo {
   512  	if _, ok := p.signatures[name]; !ok {
   513  		p.signatures[name] = &signatureInfo{
   514  			name: name,
   515  		}
   516  	}
   517  	return p.signatures[name]
   518  }
   519  
   520  // replaceInvokeWithCall replaces a runtime.interfaceMethod + inttoptr with a
   521  // concrete method. This can be done when only one type implements the
   522  // interface.
   523  func (p *lowerInterfacesPass) replaceInvokeWithCall(use llvm.Value, typ *typeInfo, signature *signatureInfo) {
   524  	inttoptrs := getUses(use)
   525  	if len(inttoptrs) != 1 || inttoptrs[0].IsAIntToPtrInst().IsNil() {
   526  		panic("expected exactly one inttoptr use of runtime.interfaceMethod")
   527  	}
   528  	inttoptr := inttoptrs[0]
   529  	function := typ.getMethod(signature).function
   530  	if inttoptr.Type() != function.Type() {
   531  		p.builder.SetInsertPointBefore(use)
   532  		function = p.builder.CreateBitCast(function, inttoptr.Type(), "")
   533  	}
   534  	inttoptr.ReplaceAllUsesWith(function)
   535  	inttoptr.EraseFromParentAsInstruction()
   536  	use.EraseFromParentAsInstruction()
   537  }
   538  
   539  // getInterfaceImplementsFunc returns a function that checks whether a given
   540  // interface type implements a given interface, by checking all possible types
   541  // that implement this interface.
   542  func (p *lowerInterfacesPass) getInterfaceImplementsFunc(itf *interfaceInfo) llvm.Value {
   543  	if !itf.assertFunc.IsNil() {
   544  		return itf.assertFunc
   545  	}
   546  
   547  	// Create the function and function signature.
   548  	// TODO: debug info
   549  	fnName := itf.id() + "$typeassert"
   550  	fnType := llvm.FunctionType(p.ctx.Int1Type(), []llvm.Type{p.uintptrType}, false)
   551  	itf.assertFunc = llvm.AddFunction(p.mod, fnName, fnType)
   552  	itf.assertFunc.Param(0).SetName("actualType")
   553  
   554  	// Type asserts will be made for each type, so increment the counter for
   555  	// those.
   556  	for _, typ := range itf.types {
   557  		typ.countTypeAsserts++
   558  	}
   559  
   560  	return itf.assertFunc
   561  }
   562  
   563  // createInterfaceImplementsFunc finishes the work of
   564  // getInterfaceImplementsFunc, because it needs to run after types have a type
   565  // code assigned.
   566  //
   567  // The type match is implemented using a big type switch over all possible
   568  // types.
   569  func (p *lowerInterfacesPass) createInterfaceImplementsFunc(itf *interfaceInfo) {
   570  	fn := itf.assertFunc
   571  	fn.SetLinkage(llvm.InternalLinkage)
   572  	fn.SetUnnamedAddr(true)
   573  
   574  	// TODO: debug info
   575  
   576  	// Create all used basic blocks.
   577  	entry := llvm.AddBasicBlock(fn, "entry")
   578  	thenBlock := llvm.AddBasicBlock(fn, "then")
   579  	elseBlock := llvm.AddBasicBlock(fn, "else")
   580  
   581  	// Add all possible types as cases.
   582  	p.builder.SetInsertPointAtEnd(entry)
   583  	actualType := fn.Param(0)
   584  	sw := p.builder.CreateSwitch(actualType, elseBlock, len(itf.types))
   585  	for _, typ := range itf.types {
   586  		sw.AddCase(llvm.ConstInt(p.uintptrType, typ.num, false), thenBlock)
   587  	}
   588  
   589  	// Fill 'then' block (type assert was successful).
   590  	p.builder.SetInsertPointAtEnd(thenBlock)
   591  	p.builder.CreateRet(llvm.ConstInt(p.ctx.Int1Type(), 1, false))
   592  
   593  	// Fill 'else' block (type asserted failed).
   594  	p.builder.SetInsertPointAtEnd(elseBlock)
   595  	p.builder.CreateRet(llvm.ConstInt(p.ctx.Int1Type(), 0, false))
   596  }
   597  
   598  // getInterfaceMethodFunc returns a thunk for calling a method on an interface.
   599  // It only declares the function, createInterfaceMethodFunc actually defines the
   600  // function.
   601  func (p *lowerInterfacesPass) getInterfaceMethodFunc(itf *interfaceInfo, signature *signatureInfo, returnType llvm.Type, params []llvm.Type) llvm.Value {
   602  	if fn, ok := itf.methodFuncs[signature]; ok {
   603  		// This function has already been created.
   604  		return fn
   605  	}
   606  	if itf.methodFuncs == nil {
   607  		// initialize the above map
   608  		itf.methodFuncs = make(map[*signatureInfo]llvm.Value)
   609  	}
   610  
   611  	// Construct the function name, which is of the form:
   612  	//     (main.Stringer).String
   613  	fnName := "(" + itf.id() + ")." + signature.methodName()
   614  	fnType := llvm.FunctionType(returnType, params, false)
   615  	fn := llvm.AddFunction(p.mod, fnName, fnType)
   616  	fn.LastParam().SetName("actualType")
   617  	itf.methodFuncs[signature] = fn
   618  	return fn
   619  }
   620  
   621  // createInterfaceMethodFunc finishes the work of getInterfaceMethodFunc,
   622  // because it needs to run after type codes have been assigned to concrete
   623  // types.
   624  //
   625  // Matching the actual type is implemented using a big type switch over all
   626  // possible types.
   627  func (p *lowerInterfacesPass) createInterfaceMethodFunc(itf *interfaceInfo, signature *signatureInfo) {
   628  	fn := itf.methodFuncs[signature]
   629  	fn.SetLinkage(llvm.InternalLinkage)
   630  	fn.SetUnnamedAddr(true)
   631  
   632  	// TODO: debug info
   633  
   634  	// Create entry block.
   635  	entry := llvm.AddBasicBlock(fn, "entry")
   636  
   637  	// Create default block and make it unreachable (which it is, because all
   638  	// possible types are checked).
   639  	defaultBlock := llvm.AddBasicBlock(fn, "default")
   640  	p.builder.SetInsertPointAtEnd(defaultBlock)
   641  	p.builder.CreateUnreachable()
   642  
   643  	// Create type switch in entry block.
   644  	p.builder.SetInsertPointAtEnd(entry)
   645  	actualType := fn.LastParam()
   646  	sw := p.builder.CreateSwitch(actualType, defaultBlock, len(itf.types))
   647  
   648  	// Collect the params that will be passed to the functions to call.
   649  	// These params exclude the receiver (which may actually consist of multiple
   650  	// parts).
   651  	params := make([]llvm.Value, fn.ParamsCount()-2)
   652  	for i := range params {
   653  		params[i] = fn.Param(i + 1)
   654  	}
   655  
   656  	// Define all possible functions that can be called.
   657  	for _, typ := range itf.types {
   658  		bb := llvm.AddBasicBlock(fn, typ.name)
   659  		sw.AddCase(llvm.ConstInt(p.uintptrType, typ.num, false), bb)
   660  
   661  		// The function we will redirect to when the interface has this type.
   662  		function := typ.getMethod(signature).function
   663  
   664  		p.builder.SetInsertPointAtEnd(bb)
   665  		receiver := fn.FirstParam()
   666  		if receiver.Type() != function.FirstParam().Type() {
   667  			// When the receiver is a pointer, it is not wrapped. This means the
   668  			// i8* has to be cast to the correct pointer type of the target
   669  			// function.
   670  			receiver = p.builder.CreateBitCast(receiver, function.FirstParam().Type(), "")
   671  		}
   672  		retval := p.builder.CreateCall(function, append([]llvm.Value{receiver}, params...), "")
   673  		if retval.Type().TypeKind() == llvm.VoidTypeKind {
   674  			p.builder.CreateRetVoid()
   675  		} else {
   676  			p.builder.CreateRet(retval)
   677  		}
   678  	}
   679  }