MCPcopy
hub / github.com/tinygo-org/tinygo / createRunDefers

Method createRunDefers

compiler/defer.go:503–717  ·  view source on GitHub ↗

createRunDefers emits code to run all deferred functions.

()

Source from the content-addressed store, hash-verified

501
502// createRunDefers emits code to run all deferred functions.
503func (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) {

Callers 2

createLandingPadMethod · 0.95
createFunctionMethod · 0.95

Calls 15

insertBasicBlockMethod · 0.95
decodeFuncValueMethod · 0.95
createCallMethod · 0.95
createInvokeMethod · 0.95
createBuiltinMethod · 0.95
getParamsFunction · 0.85
getLLVMRuntimeTypeMethod · 0.80
getFuncTypeMethod · 0.80
getLLVMTypeMethod · 0.80
getLLVMFunctionTypeMethod · 0.80
getInvokeFunctionMethod · 0.80
getFunctionInfoMethod · 0.80

Tested by

no test coverage detected