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 }