| author | |
| committer | |
| log | 2fa588e81d60cfe319446bd0483c6bf296f40c40 |
| tree | e1cf362f872de63e4c14cd869c1a8549ff7e2519 |
| parent | 19961c50e4db10fc4ada428928a7f5d1a2966da6 |
closes #11643 files changed, 47 insertions(+), 13 deletions(-)
src/analyze.cpp+1-1| ... | @@ -5583,7 +5583,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeT | ... | @@ -5583,7 +5583,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeT |
| 5583 | return; | 5583 | return; |
| 5584 | } | 5584 | } |
| 5585 | case ConstPtrSpecialHardCodedAddr: | 5585 | case ConstPtrSpecialHardCodedAddr: |
| 5586 | buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name), | 5586 | buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name), |
| 5587 | const_val->data.x_ptr.data.hard_coded_addr.addr); | 5587 | const_val->data.x_ptr.data.hard_coded_addr.addr); |
| 5588 | return; | 5588 | return; |
| 5589 | case ConstPtrSpecialDiscard: | 5589 | case ConstPtrSpecialDiscard: |
src/ir.cpp+14-3| ... | @@ -7112,6 +7112,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7112,6 +7112,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7112 | IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); | 7112 | IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); |
| 7113 | ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); | 7113 | ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); |
| 7114 | } | 7114 | } |
| 7115 | // Before we destroy the coroutine frame, we need to load the target promise into | ||
| 7116 | // a register or local variable which does not get spilled into the frame, | ||
| 7117 | // otherwise llvm tries to access memory inside the destroyed frame. | ||
| 7118 | IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, | ||
| 7119 | irb->exec->await_handle_var_ptr, false); | ||
| 7120 | IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); | ||
| 7115 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); | 7121 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 7116 | 7122 | ||
| 7117 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); | 7123 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); |
| ... | @@ -7126,6 +7132,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7126,6 +7132,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7126 | incoming_values[1] = const_bool_true; | 7132 | incoming_values[1] = const_bool_true; |
| 7127 | IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); | 7133 | IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); |
| 7128 | 7134 | ||
| 7135 | IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2); | ||
| 7136 | IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2); | ||
| 7137 | merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block; | ||
| 7138 | merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node); | ||
| 7139 | merge_incoming_blocks[1] = irb->exec->coro_normal_final; | ||
| 7140 | merge_incoming_values[1] = await_handle_in_block; | ||
| 7141 | IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values); | ||
| 7142 | |||
| 7129 | Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME); | 7143 | Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME); |
| 7130 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, | 7144 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, |
| 7131 | ImplicitAllocatorIdLocalVar); | 7145 | ImplicitAllocatorIdLocalVar); |
| ... | @@ -7152,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -7152,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7152 | ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false); | 7166 | ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false); |
| 7153 | 7167 | ||
| 7154 | ir_set_cursor_at_end_and_append_block(irb, resume_block); | 7168 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 7155 | IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, | ||
| 7156 | irb->exec->await_handle_var_ptr, false); | ||
| 7157 | IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); | ||
| 7158 | ir_build_coro_resume(irb, scope, node, awaiter_handle); | 7169 | ir_build_coro_resume(irb, scope, node, awaiter_handle); |
| 7159 | ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false); | 7170 | ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false); |
| 7160 | } | 7171 | } |
test/cases/coroutines.zig+32-9| ... | @@ -5,7 +5,10 @@ const assert = std.debug.assert; | ... | @@ -5,7 +5,10 @@ const assert = std.debug.assert; |
| 5 | var x: i32 = 1; | 5 | var x: i32 = 1; |
| 6 | 6 | ||
| 7 | test "create a coroutine and cancel it" { | 7 | test "create a coroutine and cancel it" { |
| 8 | const p = try async<std.debug.global_allocator> simpleAsyncFn(); | 8 | var da = std.heap.DirectAllocator.init(); |
| 9 | defer da.deinit(); | ||
| 10 | |||
| 11 | const p = try async<&da.allocator> simpleAsyncFn(); | ||
| 9 | comptime assert(@typeOf(p) == promise->void); | 12 | comptime assert(@typeOf(p) == promise->void); |
| 10 | cancel p; | 13 | cancel p; |
| 11 | assert(x == 2); | 14 | assert(x == 2); |
| ... | @@ -17,8 +20,11 @@ async fn simpleAsyncFn() void { | ... | @@ -17,8 +20,11 @@ async fn simpleAsyncFn() void { |
| 17 | } | 20 | } |
| 18 | 21 | ||
| 19 | test "coroutine suspend, resume, cancel" { | 22 | test "coroutine suspend, resume, cancel" { |
| 23 | var da = std.heap.DirectAllocator.init(); | ||
| 24 | defer da.deinit(); | ||
| 25 | |||
| 20 | seq('a'); | 26 | seq('a'); |
| 21 | const p = try async<std.debug.global_allocator> testAsyncSeq(); | 27 | const p = try async<&da.allocator> testAsyncSeq(); |
| 22 | seq('c'); | 28 | seq('c'); |
| 23 | resume p; | 29 | resume p; |
| 24 | seq('f'); | 30 | seq('f'); |
| ... | @@ -43,7 +49,10 @@ fn seq(c: u8) void { | ... | @@ -43,7 +49,10 @@ fn seq(c: u8) void { |
| 43 | } | 49 | } |
| 44 | 50 | ||
| 45 | test "coroutine suspend with block" { | 51 | test "coroutine suspend with block" { |
| 46 | const p = try async<std.debug.global_allocator> testSuspendBlock(); | 52 | var da = std.heap.DirectAllocator.init(); |
| 53 | defer da.deinit(); | ||
| 54 | |||
| 55 | const p = try async<&da.allocator> testSuspendBlock(); | ||
| 47 | std.debug.assert(!result); | 56 | std.debug.assert(!result); |
| 48 | resume a_promise; | 57 | resume a_promise; |
| 49 | std.debug.assert(result); | 58 | std.debug.assert(result); |
| ... | @@ -64,8 +73,11 @@ var await_a_promise: promise = undefined; | ... | @@ -64,8 +73,11 @@ var await_a_promise: promise = undefined; |
| 64 | var await_final_result: i32 = 0; | 73 | var await_final_result: i32 = 0; |
| 65 | 74 | ||
| 66 | test "coroutine await" { | 75 | test "coroutine await" { |
| 76 | var da = std.heap.DirectAllocator.init(); | ||
| 77 | defer da.deinit(); | ||
| 78 | |||
| 67 | await_seq('a'); | 79 | await_seq('a'); |
| 68 | const p = async<std.debug.global_allocator> await_amain() catch unreachable; | 80 | const p = async<&da.allocator> await_amain() catch unreachable; |
| 69 | await_seq('f'); | 81 | await_seq('f'); |
| 70 | resume await_a_promise; | 82 | resume await_a_promise; |
| 71 | await_seq('i'); | 83 | await_seq('i'); |
| ... | @@ -100,8 +112,11 @@ fn await_seq(c: u8) void { | ... | @@ -100,8 +112,11 @@ fn await_seq(c: u8) void { |
| 100 | var early_final_result: i32 = 0; | 112 | var early_final_result: i32 = 0; |
| 101 | 113 | ||
| 102 | test "coroutine await early return" { | 114 | test "coroutine await early return" { |
| 115 | var da = std.heap.DirectAllocator.init(); | ||
| 116 | defer da.deinit(); | ||
| 117 | |||
| 103 | early_seq('a'); | 118 | early_seq('a'); |
| 104 | const p = async<std.debug.global_allocator> early_amain() catch unreachable; | 119 | const p = async<&da.allocator> early_amain() catch unreachable; |
| 105 | early_seq('f'); | 120 | early_seq('f'); |
| 106 | assert(early_final_result == 1234); | 121 | assert(early_final_result == 1234); |
| 107 | assert(std.mem.eql(u8, early_points, "abcdef")); | 122 | assert(std.mem.eql(u8, early_points, "abcdef")); |
| ... | @@ -146,7 +161,9 @@ test "async function with dot syntax" { | ... | @@ -146,7 +161,9 @@ test "async function with dot syntax" { |
| 146 | suspend; | 161 | suspend; |
| 147 | } | 162 | } |
| 148 | }; | 163 | }; |
| 149 | const p = try async<std.debug.global_allocator> S.foo(); | 164 | var da = std.heap.DirectAllocator.init(); |
| 165 | defer da.deinit(); | ||
| 166 | const p = try async<&da.allocator> S.foo(); | ||
| 150 | cancel p; | 167 | cancel p; |
| 151 | assert(S.y == 2); | 168 | assert(S.y == 2); |
| 152 | } | 169 | } |
| ... | @@ -157,7 +174,9 @@ test "async fn pointer in a struct field" { | ... | @@ -157,7 +174,9 @@ test "async fn pointer in a struct field" { |
| 157 | bar: async<*std.mem.Allocator> fn (*i32) void, | 174 | bar: async<*std.mem.Allocator> fn (*i32) void, |
| 158 | }; | 175 | }; |
| 159 | var foo = Foo{ .bar = simpleAsyncFn2 }; | 176 | var foo = Foo{ .bar = simpleAsyncFn2 }; |
| 160 | const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable; | 177 | var da = std.heap.DirectAllocator.init(); |
| 178 | defer da.deinit(); | ||
| 179 | const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; | ||
| 161 | assert(data == 2); | 180 | assert(data == 2); |
| 162 | cancel p; | 181 | cancel p; |
| 163 | assert(data == 4); | 182 | assert(data == 4); |
| ... | @@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { | ... | @@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { |
| 169 | } | 188 | } |
| 170 | 189 | ||
| 171 | test "async fn with inferred error set" { | 190 | test "async fn with inferred error set" { |
| 172 | const p = (async<std.debug.global_allocator> failing()) catch unreachable; | 191 | var da = std.heap.DirectAllocator.init(); |
| 192 | defer da.deinit(); | ||
| 193 | const p = (async<&da.allocator> failing()) catch unreachable; | ||
| 173 | resume p; | 194 | resume p; |
| 174 | cancel p; | 195 | cancel p; |
| 175 | } | 196 | } |
| ... | @@ -181,7 +202,9 @@ async fn failing() !void { | ... | @@ -181,7 +202,9 @@ async fn failing() !void { |
| 181 | test "error return trace across suspend points - early return" { | 202 | test "error return trace across suspend points - early return" { |
| 182 | const p = nonFailing(); | 203 | const p = nonFailing(); |
| 183 | resume p; | 204 | resume p; |
| 184 | const p2 = try async<std.debug.global_allocator> printTrace(p); | 205 | var da = std.heap.DirectAllocator.init(); |
| 206 | defer da.deinit(); | ||
| 207 | const p2 = try async<&da.allocator> printTrace(p); | ||
| 185 | cancel p2; | 208 | cancel p2; |
| 186 | } | 209 | } |
| 187 | 210 |