createRunDefers emits code to run all deferred functions.
()
| 501 | |
| 502 | // createRunDefers emits code to run all deferred functions. |
| 503 | func (b *builder) createRunDefers() { |
| 504 | deferType := b.getLLVMRuntimeType("_defer") |
| 505 | |
| 506 | // Add a loop like the following: |
| 507 | // for stack != nil { |
| 508 | // _stack := stack |
| 509 | // stack = stack.next |
| 510 | // switch _stack.callback { |
| 511 | // case 0: |
| 512 | // // run first deferred call |
| 513 | // case 1: |
| 514 | // // run second deferred call |
| 515 | // // etc. |
| 516 | // default: |
| 517 | // unreachable |
| 518 | // } |
| 519 | // } |
| 520 | |
| 521 | // Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end. |
| 522 | end := b.insertBasicBlock("rundefers.end") |
| 523 | unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default") |
| 524 | loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop") |
| 525 | loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead") |
| 526 | b.CreateBr(loophead) |
| 527 | |
| 528 | // Create loop head: |
| 529 | // for stack != nil { |
| 530 | b.SetInsertPointAtEnd(loophead) |
| 531 | deferData := b.CreateLoad(b.dataPtrType, b.deferPtr, "") |
| 532 | stackIsNil := b.CreateICmp(llvm.IntEQ, deferData, llvm.ConstPointerNull(deferData.Type()), "stackIsNil") |
| 533 | b.CreateCondBr(stackIsNil, end, loop) |
| 534 | |
| 535 | // Create loop body: |
| 536 | // _stack := stack |
| 537 | // stack = stack.next |
| 538 | // switch stack.callback { |
| 539 | b.SetInsertPointAtEnd(loop) |
| 540 | nextStackGEP := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{ |
| 541 | llvm.ConstInt(b.ctx.Int32Type(), 0, false), |
| 542 | llvm.ConstInt(b.ctx.Int32Type(), 1, false), // .next field |
| 543 | }, "stack.next.gep") |
| 544 | nextStack := b.CreateLoad(b.dataPtrType, nextStackGEP, "stack.next") |
| 545 | b.CreateStore(nextStack, b.deferPtr) |
| 546 | gep := b.CreateInBoundsGEP(deferType, deferData, []llvm.Value{ |
| 547 | llvm.ConstInt(b.ctx.Int32Type(), 0, false), |
| 548 | llvm.ConstInt(b.ctx.Int32Type(), 0, false), // .callback field |
| 549 | }, "callback.gep") |
| 550 | callback := b.CreateLoad(b.uintptrType, gep, "callback") |
| 551 | sw := b.CreateSwitch(callback, unreachable, len(b.allDeferFuncs)) |
| 552 | |
| 553 | for i, callback := range b.allDeferFuncs { |
| 554 | // Create switch case, for example: |
| 555 | // case 0: |
| 556 | // // run first deferred call |
| 557 | block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i)) |
| 558 | sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block) |
| 559 | b.SetInsertPointAtEnd(block) |
| 560 | switch callback := callback.(type) { |
no test coverage detected