Commit 128034481a

Vexu <15308111+Vexu@users.noreply.github.com>
2019-11-26 09:34:38
solve recursion in self hosted
1 parent 36849d8
lib/std/event/fs.zig
@@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type {
         allocator: *Allocator,
 
         const OsData = switch (builtin.os) {
-            .macosx, .freebsd, .netbsd, .dragonfly => struct {
-                file_table: FileTable,
-                table_lock: event.Lock,
-
-                const FileTable = std.StringHashMap(*Put);
-                const Put = struct {
-                    putter_frame: @Frame(kqPutEvents),
-                    cancelled: bool = false,
-                    value: V,
-                };
-            },
-
+            // TODO https://github.com/ziglang/zig/issues/3778
+            .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
             .linux => LinuxOsData,
             .windows => WindowsOsData,
 
             else => @compileError("Unsupported OS"),
         };
 
+        const KqOsData = struct {
+            file_table: FileTable,
+            table_lock: event.Lock,
+
+            const FileTable = std.StringHashMap(*Put);
+            const Put = struct {
+                putter_frame: @Frame(kqPutEvents),
+                cancelled: bool = false,
+                value: V,
+            };
+        };
+
         const WindowsOsData = struct {
             table_lock: event.Lock,
             dir_table: DirTable,
src-self-hosted/compilation.zig
@@ -133,7 +133,7 @@ pub const Compilation = struct {
     zig_std_dir: []const u8,
 
     /// lazily created when we need it
-    tmp_dir: event.Future(BuildError![]u8),
+    tmp_dir: event.Future(BuildError![]u8) = event.Future(BuildError![]u8).init(),
 
     version_major: u32 = 0,
     version_minor: u32 = 0,
@@ -158,7 +158,7 @@ pub const Compilation = struct {
 
     /// functions that have their own objects that we need to link
     /// it uses an optional pointer so that tombstone removals are possible
-    fn_link_set: event.Locked(FnLinkSet),
+    fn_link_set: event.Locked(FnLinkSet) = event.Locked(FnLinkSet).init(FnLinkSet.init()),
 
     pub const FnLinkSet = std.TailQueue(?*Value.Fn);
 
@@ -227,9 +227,9 @@ pub const Compilation = struct {
     /// need to wait on this group before deinitializing
     deinit_group: event.Group(void),
 
-    // destroy_frame: @Frame(createAsync),
-    // main_loop_frame: @Frame(Compilation.mainLoop),
-    main_loop_future: event.Future(void),
+    destroy_frame: *@Frame(createAsync),
+    main_loop_frame: *@Frame(Compilation.mainLoop),
+    main_loop_future: event.Future(void) = event.Future(void).init(),
 
     have_err_ret_tracing: bool = false,
 
@@ -245,6 +245,8 @@ pub const Compilation = struct {
 
     fs_watch: *fs.Watch(*Scope.Root),
 
+    cancelled: bool = false,
+
     const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
     const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
     const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
@@ -348,7 +350,9 @@ pub const Compilation = struct {
         zig_lib_dir: []const u8,
     ) !*Compilation {
         var optional_comp: ?*Compilation = null;
-        var frame = async createAsync(
+        var frame = try zig_compiler.allocator.create(@Frame(createAsync));
+        errdefer zig_compiler.allocator.destroy(frame);
+        frame.* = async createAsync(
             &optional_comp,
             zig_compiler,
             name,
@@ -385,15 +389,12 @@ pub const Compilation = struct {
             .build_mode = build_mode,
             .zig_lib_dir = zig_lib_dir,
             .zig_std_dir = undefined,
-            .tmp_dir = event.Future(BuildError![]u8).init(),
-            // .destroy_frame = @frame(),
-            // .main_loop_frame = undefined,
-            .main_loop_future = event.Future(void).init(),
+            .destroy_frame = @frame(),
+            .main_loop_frame = undefined,
 
             .name = undefined,
             .llvm_triple = undefined,
             .is_static = is_static,
-            .fn_link_set = event.Locked(FnLinkSet).init(FnLinkSet.init()),
             .link_libs_list = undefined,
 
             .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)),
@@ -505,7 +506,10 @@ pub const Compilation = struct {
         try comp.initTypes();
         defer comp.primitive_type_table.deinit();
 
-        // comp.main_loop_frame = async comp.mainLoop();
+        comp.main_loop_frame = try allocator.create(@Frame(mainLoop));
+        defer allocator.destroy(comp.main_loop_frame);
+
+        comp.main_loop_frame.* = async comp.mainLoop();
         // Set this to indicate that initialization completed successfully.
         // from here on out we must not return an error.
         // This must occur before the first suspend/await.
@@ -718,8 +722,11 @@ pub const Compilation = struct {
     }
 
     pub fn destroy(self: *Compilation) void {
-        // await self.main_loop_frame;
-        // resume self.destroy_frame;
+        const allocator = self.gpa();
+        self.cancelled = true;
+        await self.main_loop_frame;
+        resume self.destroy_frame;
+        allocator.destroy(self.destroy_frame);
     }
 
     fn start(self: *Compilation) void {
@@ -732,7 +739,7 @@ pub const Compilation = struct {
 
         var build_result = self.initialCompile();
 
-        while (true) {
+        while (!self.cancelled) {
             const link_result = if (build_result) blk: {
                 break :blk self.maybeLink();
             } else |err| err;
@@ -1130,11 +1137,10 @@ pub const Compilation = struct {
         return link_lib;
     }
 
-    /// cancels itself so no need to await or cancel the promise.
     async fn startFindingNativeLibC(self: *Compilation) void {
-        std.event.Loop.instance.?.yield();
+        event.Loop.startCpuBoundOperation();
         // we don't care if it fails, we're just trying to kick off the future resolution
-        _ = (self.zig_compiler.getNativeLibC()) catch return;
+        _ = self.zig_compiler.getNativeLibC() catch return;
     }
 
     /// General Purpose Allocator. Must free when done.
@@ -1215,7 +1221,10 @@ pub const Compilation = struct {
         node: *ast.Node,
         expected_type: *Type,
     ) !*Value {
-        const analyzed_code = try comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type);
+        var frame = try comp.gpa().create(@Frame(genAndAnalyzeCode));
+        defer comp.gpa().destroy(frame);
+        frame.* = async comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type);
+        const analyzed_code = try await frame;
         defer analyzed_code.destroy(comp.gpa());
 
         return analyzed_code.getCompTimeResult(comp);
@@ -1315,12 +1324,15 @@ fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
         try fn_type.non_key.Normal.variable_list.append(var_scope);
     }
 
-    const analyzed_code = try comp.genAndAnalyzeCode(
+    var frame = try comp.gpa().create(@Frame(Compilation.genAndAnalyzeCode));
+    defer comp.gpa().destroy(frame);
+    frame.* = async comp.genAndAnalyzeCode(
         tree_scope,
         fn_val.child_scope,
         body_node,
         fn_type.key.data.Normal.return_type,
     );
+    const analyzed_code = try await frame;
     errdefer analyzed_code.destroy(comp.gpa());
 
     assert(fn_val.block_scope != null);
src-self-hosted/ir.zig
@@ -658,7 +658,7 @@ pub const Inst = struct {
                 const amt = try align_inst.getAsConstAlign(ira);
                 break :blk Type.Pointer.Align{ .Override = amt };
             } else blk: {
-                break :blk Type.Pointer.Align{ .Abi = {} };
+                break :blk .Abi;
             };
             const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
                 .child_type = child_type,
@@ -1078,6 +1078,14 @@ pub const Builder = struct {
         self.current_basic_block = basic_block;
     }
 
+    pub fn genNodeRecursive(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
+        const alloc = irb.comp.gpa();
+        var frame = try alloc.create(@Frame(genNode));
+        defer alloc.destroy(frame);
+        frame.* = async irb.genNode(node, scope, lval);
+        return await frame;
+    }
+
     pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
         switch (node.id) {
             .Root => unreachable,
@@ -1157,7 +1165,7 @@ pub const Builder = struct {
             },
             .GroupedExpression => {
                 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
-                return irb.genNode(grouped_expr.expr, scope, lval);
+                return irb.genNodeRecursive(grouped_expr.expr, scope, lval);
             },
             .BuiltinCall => return error.Unimplemented,
             .ErrorSetDecl => return error.Unimplemented,
@@ -1187,14 +1195,13 @@ pub const Builder = struct {
     }
 
     fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
-    async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
-        const fn_ref = try irb.genNode(suffix_op.lhs, scope, .None);
+        const fn_ref = try irb.genNodeRecursive(suffix_op.lhs.node, scope, .None);
 
         const args = try irb.arena().alloc(*Inst, call.params.len);
         var it = call.params.iterator(0);
         var i: usize = 0;
         while (it.next()) |arg_node_ptr| : (i += 1) {
-            args[i] = try irb.genNode(arg_node_ptr.*, scope, .None);
+            args[i] = try irb.genNodeRecursive(arg_node_ptr.*, scope, .None);
         }
 
         //bool is_async = node->data.fn_call_expr.is_async;
@@ -1239,7 +1246,7 @@ pub const Builder = struct {
         //} else {
         //    align_value = nullptr;
         //}
-        const child_type = try irb.genNode(prefix_op.rhs, scope, .None);
+        const child_type = try irb.genNodeRecursive(prefix_op.rhs, scope, .None);
 
         //uint32_t bit_offset_start = 0;
         //if (node->data.pointer_type.bit_offset_start != nullptr) {
@@ -1438,7 +1445,7 @@ pub const Builder = struct {
                 child_scope = &defer_child_scope.base;
                 continue;
             }
-            const statement_value = try irb.genNode(statement_node, child_scope, .None);
+            const statement_value = try irb.genNodeRecursive(statement_node, child_scope, .None);
 
             is_continuation_unreachable = statement_value.isNoReturn();
             if (is_continuation_unreachable) {
@@ -1534,7 +1541,7 @@ pub const Builder = struct {
 
                 const outer_scope = irb.begin_scope.?;
                 const return_value = if (control_flow_expr.rhs) |rhs| blk: {
-                    break :blk try irb.genNode(rhs, scope, .None);
+                    break :blk try irb.genNodeRecursive(rhs, scope, .None);
                 } else blk: {
                     break :blk try irb.buildConstVoid(scope, src_span, true);
                 };
@@ -1713,7 +1720,7 @@ pub const Builder = struct {
                     };
                     if (generate) {
                         const defer_expr_scope = defer_scope.defer_expr_scope;
-                        const instruction = try irb.genNode(
+                        const instruction = try irb.genNodeRecursive(
                             defer_expr_scope.expr_node,
                             &defer_expr_scope.base,
                             .None,
src-self-hosted/libc_installation.zig
@@ -400,7 +400,7 @@ fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool
     const argv = [_][]const u8{ cc_exe, arg1 };
 
     // TODO This simulates evented I/O for the child process exec
-    std.event.Loop.instance.?.yield();
+    event.Loop.startCpuBoundOperation();
     const errorable_result = std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
     const exec_result = if (std.debug.runtime_safety) blk: {
         break :blk errorable_result catch unreachable;
src-self-hosted/link.zig
@@ -623,16 +623,15 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
 }
 
 fn addFnObjects(ctx: *Context) !void {
-    // at this point it's guaranteed nobody else has this lock, so we circumvent it
-    // and avoid having to be an async function
-    const fn_link_set = &ctx.comp.fn_link_set.private_data;
+    const held = ctx.comp.fn_link_set.acquire();
+    defer held.release();
 
-    var it = fn_link_set.first;
+    var it = held.value.first;
     while (it) |node| {
         const fn_val = node.data orelse {
             // handle the tombstone. See Value.Fn.destroy.
             it = node.next;
-            fn_link_set.remove(node);
+            held.value.remove(node);
             ctx.comp.gpa().destroy(node);
             continue;
         };
src-self-hosted/main.zig
@@ -127,7 +127,7 @@ pub fn main() !void {
     try stderr.print("unknown command: {}\n\n", args[1]);
     try stderr.write(usage);
     process.argsFree(allocator, args);
-    defer process.exit(1);
+    process.exit(1);
 }
 
 const usage_build_generic =
@@ -467,7 +467,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
 
 fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
     var count: usize = 0;
-    while (true) { // TODO(Vexu)
+    while (!comp.cancelled) {
         const build_event = comp.events.get();
         count += 1;
 
@@ -545,7 +545,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
                 "Try running `zig libc` to see an example for the native target.\n",
             libc_paths_file,
             @errorName(err),
-        ) catch process.exit(1);
+        ) catch {};
         process.exit(1);
     };
 }
@@ -568,7 +568,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
     defer zig_compiler.deinit();
 
     const libc = zig_compiler.getNativeLibC() catch |err| {
-        stderr.print("unable to find libc: {}\n", @errorName(err)) catch process.exit(1);
+        stderr.print("unable to find libc: {}\n", @errorName(err)) catch {};
         process.exit(1);
     };
     libc.render(stdout) catch process.exit(1);
@@ -706,7 +706,8 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
             while (try it.next()) |entry| {
                 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
                     const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name });
-                    try group.call(fmtPath, fmt, full_path, check_mode);
+                    @panic("TODO https://github.com/ziglang/zig/issues/3777");
+                    // try group.call(fmtPath, fmt, full_path, check_mode);
                 }
             }
             return group.wait();
src-self-hosted/util.zig
@@ -167,7 +167,7 @@ pub fn getDarwinArchString(self: Target) [:0]const u8 {
         .powerpc64 => return "ppc64",
         .powerpc64le => return "ppc64le",
         // @tagName should be able to return sentinel terminated slice
-        else => @panic("TODO"), //return @tagName(arch),
+        else => @panic("TODO https://github.com/ziglang/zig/issues/3779"), //return @tagName(arch),
     }
 }
 
src-self-hosted/value.zig
@@ -350,7 +350,7 @@ pub const Value = struct {
                 .mut = mut,
                 .vol = Type.Pointer.Vol.Non,
                 .size = size,
-                .alignment = Type.Pointer.Align.Abi,
+                .alignment = .Abi,
             });
             var ptr_type_consumed = false;
             errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);