authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-09 17:34:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-09 17:34:06-04:00
log2e7f53f1f0d8339b8dc90ad7e0bc9963f1ec471c
treeeb01071160fb814d972d4db3ee611d5ae5524629
parent614cab5d68176ea56e48195d04997738297429a1
signature Commit is signed but in an unrecognized format.

fix cancel inside an errdefer


6 files changed, 58 insertions(+), 17 deletions(-)

src/all_types.hpp+4-3
...@@ -1725,6 +1725,7 @@ struct CodeGen {...@@ -1725,6 +1725,7 @@ struct CodeGen {
1725 LLVMValueRef cur_async_resume_index_ptr;1725 LLVMValueRef cur_async_resume_index_ptr;
1726 LLVMValueRef cur_async_awaiter_ptr;1726 LLVMValueRef cur_async_awaiter_ptr;
1727 LLVMValueRef cur_async_prev_val;1727 LLVMValueRef cur_async_prev_val;
1728 LLVMValueRef cur_async_prev_val_field_ptr;
1728 LLVMBasicBlockRef cur_preamble_llvm_block;1729 LLVMBasicBlockRef cur_preamble_llvm_block;
1729 size_t cur_resume_block_count;1730 size_t cur_resume_block_count;
1730 LLVMValueRef cur_err_ret_trace_val_arg;1731 LLVMValueRef cur_err_ret_trace_val_arg;
...@@ -1886,6 +1887,7 @@ struct CodeGen {...@@ -1886,6 +1887,7 @@ struct CodeGen {
1886 bool system_linker_hack;1887 bool system_linker_hack;
1887 bool reported_bad_link_libc_error;1888 bool reported_bad_link_libc_error;
1888 bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.1889 bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.
1890 bool cur_is_after_return;
18891891
1890 //////////////////////////// Participates in Input Parameter Cache Hash1892 //////////////////////////// Participates in Input Parameter Cache Hash
1891 /////// Note: there is a separate cache hash for builtin.zig, when adding fields,1893 /////// Note: there is a separate cache hash for builtin.zig, when adding fields,
...@@ -3639,8 +3641,6 @@ struct IrInstructionCoroResume {...@@ -3639,8 +3641,6 @@ struct IrInstructionCoroResume {
36393641
3640struct IrInstructionTestCancelRequested {3642struct IrInstructionTestCancelRequested {
3641 IrInstruction base;3643 IrInstruction base;
3642
3643 bool use_return_begin_prev_value;
3644};3644};
36453645
3646enum ResultLocId {3646enum ResultLocId {
...@@ -3730,7 +3730,8 @@ static const size_t err_union_payload_index = 1;...@@ -3730,7 +3730,8 @@ static const size_t err_union_payload_index = 1;
3730static const size_t coro_fn_ptr_index = 0;3730static const size_t coro_fn_ptr_index = 0;
3731static const size_t coro_resume_index = 1;3731static const size_t coro_resume_index = 1;
3732static const size_t coro_awaiter_index = 2;3732static const size_t coro_awaiter_index = 2;
3733static const size_t coro_ret_start = 3;3733static const size_t coro_prev_val_index = 3;
3734static const size_t coro_ret_start = 4;
37343735
3735// TODO call graph analysis to find out what this number needs to be for every function3736// TODO call graph analysis to find out what this number needs to be for every function
3736// MUST BE A POWER OF TWO.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,6 +5246,9 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
5246 field_names.append("@awaiter");5246 field_names.append("@awaiter");
5247 field_types.append(g->builtin_types.entry_usize);5247 field_types.append(g->builtin_types.entry_usize);
52485248
5249 field_names.append("@prev_val");
5250 field_types.append(g->builtin_types.entry_usize);
5251
5249 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;5252 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5250 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);5253 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5251 field_names.append("@result_ptr_callee");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,6 +7595,7 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
7592 field_types.append(ptr_fn_llvm_type); // fn_ptr7595 field_types.append(ptr_fn_llvm_type); // fn_ptr
7593 field_types.append(usize_type_ref); // resume_index7596 field_types.append(usize_type_ref); // resume_index
7594 field_types.append(usize_type_ref); // awaiter7597 field_types.append(usize_type_ref); // awaiter
7598 field_types.append(usize_type_ref); // prev_val
75957599
7596 bool have_result_type = result_type != nullptr && type_has_bits(result_type);7600 bool have_result_type = result_type != nullptr && type_has_bits(result_type);
7597 if (have_result_type) {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,7 +2226,18 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar
2226 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");2226 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
2227}2227}
22282228
2229static 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
2229static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) {2237static 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 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;2241 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2231 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint);2242 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint);
2232 size_t new_block_index = g->cur_resume_block_count;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,6 +2330,9 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
2319 LLVMBasicBlockRef incoming_blocks[] = { after_resume_block, switch_bb };2330 LLVMBasicBlockRef incoming_blocks[] = { after_resume_block, switch_bb };
2320 LLVMAddIncoming(g->cur_async_prev_val, incoming_values, incoming_blocks, 2);2331 LLVMAddIncoming(g->cur_async_prev_val, incoming_values, incoming_blocks, 2);
23212332
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 if (!ret_type_has_bits) {2336 if (!ret_type_has_bits) {
2323 return nullptr;2337 return nullptr;
2324 }2338 }
...@@ -2366,7 +2380,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -2366,7 +2380,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
2366 ZigType *any_frame_type = get_any_frame_type(g, ret_type);2380 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
2367 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);2381 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);
2368 LLVMValueRef mask_val = LLVMConstNot(one);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 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val,2384 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val,
2371 get_llvm_type(g, any_frame_type), "");2385 get_llvm_type(g, any_frame_type), "");
2372 LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn, nullptr);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,8 +5604,8 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex
5590{5604{
5591 if (!fn_is_async(g->cur_fn))5605 if (!fn_is_async(g->cur_fn))
5592 return LLVMConstInt(LLVMInt1Type(), 0, false);5606 return LLVMConstInt(LLVMInt1Type(), 0, false);
5593 if (instruction->use_return_begin_prev_value) {5607 if (g->cur_is_after_return) {
5594 return LLVMBuildTrunc(g->builder, g->cur_async_prev_val, LLVMInt1Type(), "");5608 return LLVMBuildTrunc(g->builder, get_cur_async_prev_val(g), LLVMInt1Type(), "");
5595 } else {5609 } else {
5596 zig_panic("TODO");5610 zig_panic("TODO");
5597 }5611 }
...@@ -7063,6 +7077,7 @@ static void do_code_gen(CodeGen *g) {...@@ -7063,6 +7077,7 @@ static void do_code_gen(CodeGen *g) {
7063 }7077 }
70647078
7065 if (is_async) {7079 if (is_async) {
7080 g->cur_is_after_return = false;
7066 g->cur_resume_block_count = 0;7081 g->cur_resume_block_count = 0;
70677082
7068 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;7083 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
...@@ -7099,6 +7114,8 @@ static void do_code_gen(CodeGen *g) {...@@ -7099,6 +7114,8 @@ static void do_code_gen(CodeGen *g) {
7099 g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,7114 g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7100 trace_field_index_stack, "");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, "");
71027119
7103 LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, "");7120 LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, "");
7104 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4);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,12 +3325,9 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode
3325 return &instruction->base;3325 return &instruction->base;
3326}3326}
33273327
3328static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node,3328static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3329 bool use_return_begin_prev_value)
3330{
3331 IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node);3329 IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node);
3332 instruction->base.value.type = irb->codegen->builtin_types.entry_bool;3330 instruction->base.value.type = irb->codegen->builtin_types.entry_bool;
3333 instruction->use_return_begin_prev_value = use_return_begin_prev_value;
33343331
3335 return &instruction->base;3332 return &instruction->base;
3336}3333}
...@@ -3546,7 +3543,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3546,7 +3543,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35463543
3547 if (need_test_cancel) {3544 if (need_test_cancel) {
3548 ir_set_cursor_at_end_and_append_block(irb, ok_block);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 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled,3547 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled,
3551 all_defers_block, normal_defers_block, force_comptime));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,7 +3827,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3830 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);3827 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3831 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));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 IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers");3831 IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers");
3835 IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers");3832 IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers");
3836 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, child_scope, "RetStmt");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,8 +24722,7 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir
24725 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {24722 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
24726 return ir_const_bool(ira, &instruction->base, false);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,24725 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
24729 instruction->use_return_begin_prev_value);
24730}24726}
2473124727
24732static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24728static 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,8 +1551,7 @@ static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction)
1551}1551}
15521552
1553static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancelRequested *instruction) {1553static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancelRequested *instruction) {
1554 const char *arg = instruction->use_return_begin_prev_value ? "UseReturnBeginPrevValue" : "AdditionalCheck";1554 fprintf(irp->f, "@testCancelRequested()");
1555 fprintf(irp->f, "@testCancelRequested(%s)", arg);
1556}1555}
15571556
1558static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1557static 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,7 +318,7 @@ test "@asyncCall with return type" {
318 }318 }
319 };319 };
320 var foo = Foo{ .bar = Foo.middle };320 var foo = Foo{ .bar = Foo.middle };
321 var bytes: [100]u8 = undefined;321 var bytes: [150]u8 = undefined;
322 var aresult: i32 = 0;322 var aresult: i32 = 0;
323 _ = @asyncCall(&bytes, &aresult, foo.bar);323 _ = @asyncCall(&bytes, &aresult, foo.bar);
324 expect(aresult == 0);324 expect(aresult == 0);
...@@ -589,3 +589,27 @@ test "pass string literal to async function" {...@@ -589,3 +589,27 @@ test "pass string literal to async function" {
589 };589 };
590 S.doTheTest();590 S.doTheTest();
591}591}
592
593test "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}