| author | |
| committer | |
| log | 2e7f53f1f0d8339b8dc90ad7e0bc9963f1ec471c |
| tree | eb01071160fb814d972d4db3ee611d5ae5524629 |
| parent | 614cab5d68176ea56e48195d04997738297429a1 |
| signature | Commit is signed but in an unrecognized format. |
6 files changed, 58 insertions(+), 17 deletions(-)
src/all_types.hpp+4-3| ... | ... | @@ -1725,6 +1725,7 @@ struct CodeGen { |
| 1725 | 1725 | LLVMValueRef cur_async_resume_index_ptr; |
| 1726 | 1726 | LLVMValueRef cur_async_awaiter_ptr; |
| 1727 | 1727 | LLVMValueRef cur_async_prev_val; |
| 1728 | LLVMValueRef cur_async_prev_val_field_ptr; | |
| 1728 | 1729 | LLVMBasicBlockRef cur_preamble_llvm_block; |
| 1729 | 1730 | size_t cur_resume_block_count; |
| 1730 | 1731 | LLVMValueRef cur_err_ret_trace_val_arg; |
| ... | ... | @@ -1886,6 +1887,7 @@ struct CodeGen { |
| 1886 | 1887 | bool system_linker_hack; |
| 1887 | 1888 | bool reported_bad_link_libc_error; |
| 1888 | 1889 | bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. |
| 1890 | bool cur_is_after_return; | |
| 1889 | 1891 | |
| 1890 | 1892 | //////////////////////////// Participates in Input Parameter Cache Hash |
| 1891 | 1893 | /////// Note: there is a separate cache hash for builtin.zig, when adding fields, |
| ... | ... | @@ -3639,8 +3641,6 @@ struct IrInstructionCoroResume { |
| 3639 | 3641 | |
| 3640 | 3642 | struct IrInstructionTestCancelRequested { |
| 3641 | 3643 | IrInstruction base; |
| 3642 | ||
| 3643 | bool use_return_begin_prev_value; | |
| 3644 | 3644 | }; |
| 3645 | 3645 | |
| 3646 | 3646 | enum ResultLocId { |
| ... | ... | @@ -3730,7 +3730,8 @@ static const size_t err_union_payload_index = 1; |
| 3730 | 3730 | static const size_t coro_fn_ptr_index = 0; |
| 3731 | 3731 | static const size_t coro_resume_index = 1; |
| 3732 | 3732 | static const size_t coro_awaiter_index = 2; |
| 3733 | static const size_t coro_ret_start = 3; | |
| 3733 | static const size_t coro_prev_val_index = 3; | |
| 3734 | static const size_t coro_ret_start = 4; | |
| 3734 | 3735 | |
| 3735 | 3736 | // TODO call graph analysis to find out what this number needs to be for every function |
| 3736 | 3737 | // MUST BE A POWER OF TWO. |
src/analyze.cpp+4| ... | ... | @@ -5246,6 +5246,9 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) { |
| 5246 | 5246 | field_names.append("@awaiter"); |
| 5247 | 5247 | field_types.append(g->builtin_types.entry_usize); |
| 5248 | 5248 | |
| 5249 | field_names.append("@prev_val"); | |
| 5250 | field_types.append(g->builtin_types.entry_usize); | |
| 5251 | ||
| 5249 | 5252 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 5250 | 5253 | ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false); |
| 5251 | 5254 | field_names.append("@result_ptr_callee"); |
| ... | ... | @@ -7592,6 +7595,7 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 7592 | 7595 | field_types.append(ptr_fn_llvm_type); // fn_ptr |
| 7593 | 7596 | field_types.append(usize_type_ref); // resume_index |
| 7594 | 7597 | field_types.append(usize_type_ref); // awaiter |
| 7598 | field_types.append(usize_type_ref); // prev_val | |
| 7595 | 7599 | |
| 7596 | 7600 | bool have_result_type = result_type != nullptr && type_has_bits(result_type); |
| 7597 | 7601 | if (have_result_type) { |
src/codegen.cpp+20-3| ... | ... | @@ -2226,7 +2226,18 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar |
| 2226 | 2226 | return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, ""); |
| 2227 | 2227 | } |
| 2228 | 2228 | |
| 2229 | static LLVMValueRef get_cur_async_prev_val(CodeGen *g) { | |
| 2230 | if (g->cur_async_prev_val != nullptr) { | |
| 2231 | return g->cur_async_prev_val; | |
| 2232 | } | |
| 2233 | g->cur_async_prev_val = LLVMBuildLoad(g->builder, g->cur_async_prev_val_field_ptr, ""); | |
| 2234 | return g->cur_async_prev_val; | |
| 2235 | } | |
| 2236 | ||
| 2229 | 2237 | static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { |
| 2238 | // This becomes invalid when a suspend happens. | |
| 2239 | g->cur_async_prev_val = nullptr; | |
| 2240 | ||
| 2230 | 2241 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2231 | 2242 | LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint); |
| 2232 | 2243 | size_t new_block_index = g->cur_resume_block_count; |
| ... | ... | @@ -2319,6 +2330,9 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable, |
| 2319 | 2330 | LLVMBasicBlockRef incoming_blocks[] = { after_resume_block, switch_bb }; |
| 2320 | 2331 | LLVMAddIncoming(g->cur_async_prev_val, incoming_values, incoming_blocks, 2); |
| 2321 | 2332 | |
| 2333 | g->cur_is_after_return = true; | |
| 2334 | LLVMBuildStore(g->builder, g->cur_async_prev_val, g->cur_async_prev_val_field_ptr); | |
| 2335 | ||
| 2322 | 2336 | if (!ret_type_has_bits) { |
| 2323 | 2337 | return nullptr; |
| 2324 | 2338 | } |
| ... | ... | @@ -2366,7 +2380,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 2366 | 2380 | ZigType *any_frame_type = get_any_frame_type(g, ret_type); |
| 2367 | 2381 | LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false); |
| 2368 | 2382 | LLVMValueRef mask_val = LLVMConstNot(one); |
| 2369 | LLVMValueRef masked_prev_val = LLVMBuildAnd(g->builder, g->cur_async_prev_val, mask_val, ""); | |
| 2383 | LLVMValueRef masked_prev_val = LLVMBuildAnd(g->builder, get_cur_async_prev_val(g), mask_val, ""); | |
| 2370 | 2384 | LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val, |
| 2371 | 2385 | get_llvm_type(g, any_frame_type), ""); |
| 2372 | 2386 | LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn, nullptr); |
| ... | ... | @@ -5590,8 +5604,8 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex |
| 5590 | 5604 | { |
| 5591 | 5605 | if (!fn_is_async(g->cur_fn)) |
| 5592 | 5606 | return LLVMConstInt(LLVMInt1Type(), 0, false); |
| 5593 | if (instruction->use_return_begin_prev_value) { | |
| 5594 | return LLVMBuildTrunc(g->builder, g->cur_async_prev_val, LLVMInt1Type(), ""); | |
| 5607 | if (g->cur_is_after_return) { | |
| 5608 | return LLVMBuildTrunc(g->builder, get_cur_async_prev_val(g), LLVMInt1Type(), ""); | |
| 5595 | 5609 | } else { |
| 5596 | 5610 | zig_panic("TODO"); |
| 5597 | 5611 | } |
| ... | ... | @@ -7063,6 +7077,7 @@ static void do_code_gen(CodeGen *g) { |
| 7063 | 7077 | } |
| 7064 | 7078 | |
| 7065 | 7079 | if (is_async) { |
| 7080 | g->cur_is_after_return = false; | |
| 7066 | 7081 | g->cur_resume_block_count = 0; |
| 7067 | 7082 | |
| 7068 | 7083 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| ... | ... | @@ -7099,6 +7114,8 @@ static void do_code_gen(CodeGen *g) { |
| 7099 | 7114 | g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, |
| 7100 | 7115 | trace_field_index_stack, ""); |
| 7101 | 7116 | } |
| 7117 | g->cur_async_prev_val_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, | |
| 7118 | coro_prev_val_index, ""); | |
| 7102 | 7119 | |
| 7103 | 7120 | LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, ""); |
| 7104 | 7121 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4); |
src/ir.cpp+4-8| ... | ... | @@ -3325,12 +3325,9 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode |
| 3325 | 3325 | return &instruction->base; |
| 3326 | 3326 | } |
| 3327 | 3327 | |
| 3328 | static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 3329 | bool use_return_begin_prev_value) | |
| 3330 | { | |
| 3328 | static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 3331 | 3329 | IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node); |
| 3332 | 3330 | instruction->base.value.type = irb->codegen->builtin_types.entry_bool; |
| 3333 | instruction->use_return_begin_prev_value = use_return_begin_prev_value; | |
| 3334 | 3331 | |
| 3335 | 3332 | return &instruction->base; |
| 3336 | 3333 | } |
| ... | ... | @@ -3546,7 +3543,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3546 | 3543 | |
| 3547 | 3544 | if (need_test_cancel) { |
| 3548 | 3545 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 3549 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node, true); | |
| 3546 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node); | |
| 3550 | 3547 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled, |
| 3551 | 3548 | all_defers_block, normal_defers_block, force_comptime)); |
| 3552 | 3549 | } |
| ... | ... | @@ -3830,7 +3827,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3830 | 3827 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3831 | 3828 | return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result)); |
| 3832 | 3829 | } |
| 3833 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, child_scope, block_node, true); | |
| 3830 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, child_scope, block_node); | |
| 3834 | 3831 | IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers"); |
| 3835 | 3832 | IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers"); |
| 3836 | 3833 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, child_scope, "RetStmt"); |
| ... | ... | @@ -24725,8 +24722,7 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir |
| 24725 | 24722 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { |
| 24726 | 24723 | return ir_const_bool(ira, &instruction->base, false); |
| 24727 | 24724 | } |
| 24728 | return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node, | |
| 24729 | instruction->use_return_begin_prev_value); | |
| 24725 | return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node); | |
| 24730 | 24726 | } |
| 24731 | 24727 | |
| 24732 | 24728 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
src/ir_print.cpp+1-2| ... | ... | @@ -1551,8 +1551,7 @@ static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction) |
| 1551 | 1551 | } |
| 1552 | 1552 | |
| 1553 | 1553 | static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancelRequested *instruction) { |
| 1554 | const char *arg = instruction->use_return_begin_prev_value ? "UseReturnBeginPrevValue" : "AdditionalCheck"; | |
| 1555 | fprintf(irp->f, "@testCancelRequested(%s)", arg); | |
| 1554 | fprintf(irp->f, "@testCancelRequested()"); | |
| 1556 | 1555 | } |
| 1557 | 1556 | |
| 1558 | 1557 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
test/stage1/behavior/coroutines.zig+25-1| ... | ... | @@ -318,7 +318,7 @@ test "@asyncCall with return type" { |
| 318 | 318 | } |
| 319 | 319 | }; |
| 320 | 320 | var foo = Foo{ .bar = Foo.middle }; |
| 321 | var bytes: [100]u8 = undefined; | |
| 321 | var bytes: [150]u8 = undefined; | |
| 322 | 322 | var aresult: i32 = 0; |
| 323 | 323 | _ = @asyncCall(&bytes, &aresult, foo.bar); |
| 324 | 324 | expect(aresult == 0); |
| ... | ... | @@ -589,3 +589,27 @@ test "pass string literal to async function" { |
| 589 | 589 | }; |
| 590 | 590 | S.doTheTest(); |
| 591 | 591 | } |
| 592 | ||
| 593 | test "cancel inside an errdefer" { | |
| 594 | const S = struct { | |
| 595 | var frame: anyframe = undefined; | |
| 596 | ||
| 597 | fn doTheTest() void { | |
| 598 | _ = async amainWrap(); | |
| 599 | resume frame; | |
| 600 | } | |
| 601 | ||
| 602 | fn amainWrap() !void { | |
| 603 | var foo = async func(); | |
| 604 | errdefer cancel foo; | |
| 605 | return error.Bad; | |
| 606 | } | |
| 607 | ||
| 608 | fn func() void { | |
| 609 | frame = @frame(); | |
| 610 | suspend; | |
| 611 | } | |
| 612 | ||
| 613 | }; | |
| 614 | S.doTheTest(); | |
| 615 | } |