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 {
17251725 LLVMValueRef cur_async_resume_index_ptr;
17261726 LLVMValueRef cur_async_awaiter_ptr;
17271727 LLVMValueRef cur_async_prev_val;
1728 LLVMValueRef cur_async_prev_val_field_ptr;
17281729 LLVMBasicBlockRef cur_preamble_llvm_block;
17291730 size_t cur_resume_block_count;
17301731 LLVMValueRef cur_err_ret_trace_val_arg;
......@@ -1886,6 +1887,7 @@ struct CodeGen {
18861887 bool system_linker_hack;
18871888 bool reported_bad_link_libc_error;
18881889 bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.
1890 bool cur_is_after_return;
18891891
18901892 //////////////////////////// Participates in Input Parameter Cache Hash
18911893 /////// Note: there is a separate cache hash for builtin.zig, when adding fields,
......@@ -3639,8 +3641,6 @@ struct IrInstructionCoroResume {
36393641
36403642struct IrInstructionTestCancelRequested {
36413643 IrInstruction base;
3642
3643 bool use_return_begin_prev_value;
36443644};
36453645
36463646enum ResultLocId {
......@@ -3730,7 +3730,8 @@ static const size_t err_union_payload_index = 1;
37303730static const size_t coro_fn_ptr_index = 0;
37313731static const size_t coro_resume_index = 1;
37323732static 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
37353736// TODO call graph analysis to find out what this number needs to be for every function
37363737// MUST BE A POWER OF TWO.
src/analyze.cpp+4
......@@ -5246,6 +5246,9 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
52465246 field_names.append("@awaiter");
52475247 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
52495252 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
52505253 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
52515254 field_names.append("@result_ptr_callee");
......@@ -7592,6 +7595,7 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
75927595 field_types.append(ptr_fn_llvm_type); // fn_ptr
75937596 field_types.append(usize_type_ref); // resume_index
75947597 field_types.append(usize_type_ref); // awaiter
7598 field_types.append(usize_type_ref); // prev_val
75957599
75967600 bool have_result_type = result_type != nullptr && type_has_bits(result_type);
75977601 if (have_result_type) {
src/codegen.cpp+20-3
......@@ -2226,7 +2226,18 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar
22262226 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
22272227}
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
22292237static 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
22302241 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
22312242 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint);
22322243 size_t new_block_index = g->cur_resume_block_count;
......@@ -2319,6 +2330,9 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
23192330 LLVMBasicBlockRef incoming_blocks[] = { after_resume_block, switch_bb };
23202331 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
23222336 if (!ret_type_has_bits) {
23232337 return nullptr;
23242338 }
......@@ -2366,7 +2380,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
23662380 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
23672381 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);
23682382 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, "");
23702384 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val,
23712385 get_llvm_type(g, any_frame_type), "");
23722386 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
55905604{
55915605 if (!fn_is_async(g->cur_fn))
55925606 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(), "");
55955609 } else {
55965610 zig_panic("TODO");
55975611 }
......@@ -7063,6 +7077,7 @@ static void do_code_gen(CodeGen *g) {
70637077 }
70647078
70657079 if (is_async) {
7080 g->cur_is_after_return = false;
70667081 g->cur_resume_block_count = 0;
70677082
70687083 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
......@@ -7099,6 +7114,8 @@ static void do_code_gen(CodeGen *g) {
70997114 g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
71007115 trace_field_index_stack, "");
71017116 }
7117 g->cur_async_prev_val_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7118 coro_prev_val_index, "");
71027119
71037120 LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, "");
71047121 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
33253325 return &instruction->base;
33263326}
33273327
3328static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node,
3329 bool use_return_begin_prev_value)
3330{
3328static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node) {
33313329 IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node);
33323330 instruction->base.value.type = irb->codegen->builtin_types.entry_bool;
3333 instruction->use_return_begin_prev_value = use_return_begin_prev_value;
33343331
33353332 return &instruction->base;
33363333}
......@@ -3546,7 +3543,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35463543
35473544 if (need_test_cancel) {
35483545 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);
35503547 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled,
35513548 all_defers_block, normal_defers_block, force_comptime));
35523549 }
......@@ -3830,7 +3827,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
38303827 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
38313828 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
38323829 }
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);
38343831 IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers");
38353832 IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers");
38363833 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
2472524722 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
2472624723 return ir_const_bool(ira, &instruction->base, false);
2472724724 }
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);
2473024726}
2473124727
2473224728static 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)
15511551}
15521552
15531553static 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()");
15561555}
15571556
15581557static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
test/stage1/behavior/coroutines.zig+25-1
......@@ -318,7 +318,7 @@ test "@asyncCall with return type" {
318318 }
319319 };
320320 var foo = Foo{ .bar = Foo.middle };
321 var bytes: [100]u8 = undefined;
321 var bytes: [150]u8 = undefined;
322322 var aresult: i32 = 0;
323323 _ = @asyncCall(&bytes, &aresult, foo.bar);
324324 expect(aresult == 0);
......@@ -589,3 +589,27 @@ test "pass string literal to async function" {
589589 };
590590 S.doTheTest();
591591}
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}