authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-22 14:36:14-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-22 14:36:14-04:00
logfcadeb50c04199fce2d9675ba2976680c71c67ff
tree6d4bba1ab17adc6f6b42539c2dbeadf166327e37
parent650e07ebd96d6c476cadc1f7c19856e950ceef9c
signaturelock-open Commit is signed but in an unrecognized format.

fix multiple coroutines existing clobbering each other


5 files changed, 123 insertions(+), 45 deletions(-)

src/analyze.cpp+50-18
...@@ -1865,7 +1865,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -1865,7 +1865,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
1865}1865}
18661866
1867static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {1867static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
1868 assert(frame_type->data.frame.locals_struct == nullptr);1868 if (frame_type->data.frame.locals_struct != nullptr)
1869 return ErrorNone;
18691870
1870 ZigFn *fn = frame_type->data.frame.fn;1871 ZigFn *fn = frame_type->data.frame.fn;
1871 switch (fn->anal_state) {1872 switch (fn->anal_state) {
...@@ -3824,6 +3825,15 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_typ...@@ -3824,6 +3825,15 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_typ
3824 }3825 }
38253826
3826 fn_table_entry->anal_state = FnAnalStateComplete;3827 fn_table_entry->anal_state = FnAnalStateComplete;
3828
3829 if (fn_table_entry->resume_blocks.length != 0) {
3830 ZigType *frame_type = get_coro_frame_type(g, fn_table_entry);
3831 Error err;
3832 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {
3833 fn_table_entry->anal_state = FnAnalStateInvalid;
3834 return;
3835 }
3836 }
3827}3837}
38283838
3829static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {3839static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
...@@ -7050,18 +7060,12 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {...@@ -7050,18 +7060,12 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
7050 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);7060 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
7051}7061}
70527062
7053void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {7063static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7054 if (fn_type->llvm_di_type != nullptr) {7064 if (fn_type->llvm_di_type != nullptr) return;
7055 if (fn != nullptr) {
7056 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
7057 fn->raw_di_type = fn_type->data.fn.raw_di_type;
7058 }
7059 return;
7060 }
70617065
7062 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;7066 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
7063 bool first_arg_return = want_first_arg_sret(g, fn_type_id);7067 bool first_arg_return = want_first_arg_sret(g, fn_type_id);
7064 bool is_async = fn_type_id->cc == CallingConventionAsync || (fn != nullptr && fn->resume_blocks.length != 0);7068 bool is_async = fn_type_id->cc == CallingConventionAsync;
7065 bool is_c_abi = fn_type_id->cc == CallingConventionC;7069 bool is_c_abi = fn_type_id->cc == CallingConventionC;
7066 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);7070 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
7067 // +1 for maybe making the first argument the return value7071 // +1 for maybe making the first argument the return value
...@@ -7100,7 +7104,11 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {...@@ -7100,7 +7104,11 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7100 if (is_async) {7104 if (is_async) {
7101 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);7105 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);
71027106
7103 ZigType *frame_type = (fn == nullptr) ? g->builtin_types.entry_frame_header : get_coro_frame_type(g, fn);7107 ZigType *frame_type = g->builtin_types.entry_frame_header;
7108 Error err;
7109 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {
7110 zig_unreachable();
7111 }
7104 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);7112 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7105 gen_param_types.append(get_llvm_type(g, ptr_type));7113 gen_param_types.append(get_llvm_type(g, ptr_type));
7106 param_di_types.append(get_llvm_di_type(g, ptr_type));7114 param_di_types.append(get_llvm_di_type(g, ptr_type));
...@@ -7150,12 +7158,7 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {...@@ -7150,12 +7158,7 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7150 for (size_t i = 0; i < gen_param_types.length; i += 1) {7158 for (size_t i = 0; i < gen_param_types.length; i += 1) {
7151 assert(gen_param_types.items[i] != nullptr);7159 assert(gen_param_types.items[i] != nullptr);
7152 }7160 }
7153 if (fn != nullptr) {7161
7154 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7155 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
7156 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7157 return;
7158 }
7159 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),7162 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7160 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);7163 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
7161 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);7164 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
...@@ -7165,6 +7168,35 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {...@@ -7165,6 +7168,35 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7165 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");7168 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
7166}7169}
71677170
7171void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
7172 if (fn->raw_di_type != nullptr) return;
7173
7174 ZigType *fn_type = fn->type_entry;
7175 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
7176 bool cc_async = fn_type_id->cc == CallingConventionAsync;
7177 bool inferred_async = fn->resume_blocks.length != 0;
7178 bool is_async = cc_async || inferred_async;
7179 if (!is_async) {
7180 resolve_llvm_types_fn_type(g, fn_type);
7181 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
7182 fn->raw_di_type = fn_type->data.fn.raw_di_type;
7183 return;
7184 }
7185
7186 ZigType *gen_return_type = g->builtin_types.entry_usize;
7187 ZigList<ZigLLVMDIType *> param_di_types = {};
7188 // first "parameter" is return value
7189 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7190
7191 ZigType *frame_type = get_coro_frame_type(g, fn);
7192 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7193 LLVMTypeRef gen_param_type = get_llvm_type(g, ptr_type);
7194 param_di_types.append(get_llvm_di_type(g, ptr_type));
7195
7196 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), &gen_param_type, 1, false);
7197 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7198}
7199
7168static void resolve_llvm_types_anyerror(CodeGen *g) {7200static void resolve_llvm_types_anyerror(CodeGen *g) {
7169 ZigType *entry = g->builtin_types.entry_global_error_set;7201 ZigType *entry = g->builtin_types.entry_global_error_set;
7170 entry->llvm_type = get_llvm_type(g, g->err_tag_type);7202 entry->llvm_type = get_llvm_type(g, g->err_tag_type);
...@@ -7241,7 +7273,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7241,7 +7273,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7241 case ZigTypeIdArray:7273 case ZigTypeIdArray:
7242 return resolve_llvm_types_array(g, type);7274 return resolve_llvm_types_array(g, type);
7243 case ZigTypeIdFn:7275 case ZigTypeIdFn:
7244 return resolve_llvm_types_fn(g, type, nullptr);7276 return resolve_llvm_types_fn_type(g, type);
7245 case ZigTypeIdErrorSet: {7277 case ZigTypeIdErrorSet: {
7246 if (type->llvm_di_type != nullptr) return;7278 if (type->llvm_di_type != nullptr) return;
72477279
src/analyze.hpp+1-1
...@@ -247,6 +247,6 @@ void src_assert(bool ok, AstNode *source_node);...@@ -247,6 +247,6 @@ void src_assert(bool ok, AstNode *source_node);
247bool is_container(ZigType *type_entry);247bool is_container(ZigType *type_entry);
248ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);248ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);
249249
250void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn);250void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
251251
252#endif252#endif
src/codegen.cpp+40-26
...@@ -371,10 +371,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -371,10 +371,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));371 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372 }372 }
373373
374 bool is_async = fn_table_entry->resume_blocks.length != 0 || cc == CallingConventionAsync;
375
374376
375 ZigType *fn_type = fn_table_entry->type_entry;377 ZigType *fn_type = fn_table_entry->type_entry;
376 // Make the raw_type_ref populated378 // Make the raw_type_ref populated
377 resolve_llvm_types_fn(g, fn_type, fn_table_entry);379 resolve_llvm_types_fn(g, fn_table_entry);
378 LLVMTypeRef fn_llvm_type = fn_table_entry->raw_type_ref;380 LLVMTypeRef fn_llvm_type = fn_table_entry->raw_type_ref;
379 if (fn_table_entry->body_node == nullptr) {381 if (fn_table_entry->body_node == nullptr) {
380 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));382 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
...@@ -397,7 +399,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -397,7 +399,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
397 assert(entry->value->id == TldIdFn);399 assert(entry->value->id == TldIdFn);
398 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);400 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
399 // Make the raw_type_ref populated401 // Make the raw_type_ref populated
400 resolve_llvm_types_fn(g, tld_fn->fn_entry->type_entry, tld_fn->fn_entry);402 resolve_llvm_types_fn(g, tld_fn->fn_entry);
401 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),403 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
402 tld_fn->fn_entry->raw_type_ref);404 tld_fn->fn_entry->raw_type_ref);
403 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,405 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
...@@ -517,18 +519,22 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -517,18 +519,22 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
517 init_gen_i = 1;519 init_gen_i = 1;
518 }520 }
519521
520 // set parameter attributes522 if (is_async) {
521 FnWalk fn_walk = {};523 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
522 fn_walk.id = FnWalkIdAttrs;524 } else {
523 fn_walk.data.attrs.fn = fn_table_entry;525 // set parameter attributes
524 fn_walk.data.attrs.gen_i = init_gen_i;526 FnWalk fn_walk = {};
525 walk_function_params(g, fn_type, &fn_walk);527 fn_walk.id = FnWalkIdAttrs;
528 fn_walk.data.attrs.fn = fn_table_entry;
529 fn_walk.data.attrs.gen_i = init_gen_i;
530 walk_function_params(g, fn_type, &fn_walk);
526531
527 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);532 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
528 if (err_ret_trace_arg_index != UINT32_MAX) {533 if (err_ret_trace_arg_index != UINT32_MAX) {
529 // Error return trace memory is in the stack, which is impossible to be at address 0534 // Error return trace memory is in the stack, which is impossible to be at address 0
530 // on any architecture.535 // on any architecture.
531 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");536 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
537 }
532 }538 }
533539
534 return fn_table_entry->llvm_value;540 return fn_table_entry->llvm_value;
...@@ -6254,14 +6260,21 @@ static void do_code_gen(CodeGen *g) {...@@ -6254,14 +6260,21 @@ static void do_code_gen(CodeGen *g) {
6254 } else if (is_c_abi) {6260 } else if (is_c_abi) {
6255 fn_walk_var.data.vars.var = var;6261 fn_walk_var.data.vars.var = var;
6256 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);6262 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
6263 } else if (is_async) {
6264 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start + var_i, "");
6265 if (var->decl_node) {
6266 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
6267 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
6268 (unsigned)(var->decl_node->line + 1),
6269 get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
6270 gen_var_debug_decl(g, var);
6271 }
6257 } else {6272 } else {
6258 ZigType *gen_type;6273 ZigType *gen_type;
6259 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];6274 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
6260 assert(gen_info->gen_index != SIZE_MAX);6275 assert(gen_info->gen_index != SIZE_MAX);
62616276
6262 if (is_async) {6277 if (handle_is_ptr(var->var_type)) {
6263 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start + var_i, "");
6264 } else if (handle_is_ptr(var->var_type)) {
6265 if (gen_info->is_byval) {6278 if (gen_info->is_byval) {
6266 gen_type = var->var_type;6279 gen_type = var->var_type;
6267 } else {6280 } else {
...@@ -6307,16 +6320,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6307,16 +6320,7 @@ static void do_code_gen(CodeGen *g) {
6307 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));6320 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
6308 }6321 }
63096322
6310 // create debug variable declarations for parameters6323 if (is_async) {
6311 // rely on the first variables in the variable_list being parameters.
6312 FnWalk fn_walk_init = {};
6313 fn_walk_init.id = FnWalkIdInits;
6314 fn_walk_init.data.inits.fn = fn_table_entry;
6315 fn_walk_init.data.inits.llvm_fn = fn;
6316 fn_walk_init.data.inits.gen_i = gen_i_init;
6317 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
6318
6319 if (fn_table_entry->resume_blocks.length != 0) {
6320 if (!g->strip_debug_symbols) {6324 if (!g->strip_debug_symbols) {
6321 AstNode *source_node = fn_table_entry->proto_node;6325 AstNode *source_node = fn_table_entry->proto_node;
6322 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,6326 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
...@@ -6354,8 +6358,18 @@ static void do_code_gen(CodeGen *g) {...@@ -6354,8 +6358,18 @@ static void do_code_gen(CodeGen *g) {
6354 LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_i + 2, false);6358 LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_i + 2, false);
6355 LLVMAddCase(switch_instr, case_value, fn_table_entry->resume_blocks.at(resume_i)->llvm_block);6359 LLVMAddCase(switch_instr, case_value, fn_table_entry->resume_blocks.at(resume_i)->llvm_block);
6356 }6360 }
6361 } else {
6362 // create debug variable declarations for parameters
6363 // rely on the first variables in the variable_list being parameters.
6364 FnWalk fn_walk_init = {};
6365 fn_walk_init.id = FnWalkIdInits;
6366 fn_walk_init.data.inits.fn = fn_table_entry;
6367 fn_walk_init.data.inits.llvm_fn = fn;
6368 fn_walk_init.data.inits.gen_i = gen_i_init;
6369 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
6357 }6370 }
63586371
6372
6359 ir_render(g, fn_table_entry);6373 ir_render(g, fn_table_entry);
63606374
6361 }6375 }
test/runtime_safety.zig+14
...@@ -1,6 +1,20 @@...@@ -1,6 +1,20 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("invalid resume of async function",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\pub fn main() void {
9 \\ var p = async suspendOnce();
10 \\ resume p; //ok
11 \\ resume p; //bad
12 \\}
13 \\fn suspendOnce() void {
14 \\ suspend;
15 \\}
16 );
17
4 cases.addRuntimeSafety(".? operator on null pointer",18 cases.addRuntimeSafety(".? operator on null pointer",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {19 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);20 \\ @import("std").os.exit(126);
test/stage1/behavior/coroutines.zig+18
...@@ -29,6 +29,24 @@ fn simpleAsyncFnWithArg(delta: i32) void {...@@ -29,6 +29,24 @@ fn simpleAsyncFnWithArg(delta: i32) void {
29 suspend;29 suspend;
30 global_y += delta;30 global_y += delta;
31}31}
32
33test "suspend at end of function" {
34 const S = struct {
35 var x: i32 = 1;
36
37 fn doTheTest() void {
38 expect(x == 1);
39 const p = async suspendAtEnd();
40 expect(x == 2);
41 }
42
43 fn suspendAtEnd() void {
44 x += 1;
45 suspend;
46 }
47 };
48 S.doTheTest();
49}
32//test "coroutine suspend, resume" {50//test "coroutine suspend, resume" {
33// seq('a');51// seq('a');
34// const p = try async<allocator> testAsyncSeq();52// const p = try async<allocator> testAsyncSeq();