solve recursion in self hosted

This commit is contained in:
Vexu 2019-11-26 10:34:38 +02:00
parent 36849d8a7b
commit 128034481a
No known key found for this signature in database
GPG Key ID: 5AEABFCAFF5CD8D6
8 changed files with 75 additions and 54 deletions

View File

@ -735,7 +735,15 @@ pub fn Watch(comptime V: type) type {
allocator: *Allocator, allocator: *Allocator,
const OsData = switch (builtin.os) { const OsData = switch (builtin.os) {
.macosx, .freebsd, .netbsd, .dragonfly => struct { // 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, file_table: FileTable,
table_lock: event.Lock, table_lock: event.Lock,
@ -745,12 +753,6 @@ pub fn Watch(comptime V: type) type {
cancelled: bool = false, cancelled: bool = false,
value: V, value: V,
}; };
},
.linux => LinuxOsData,
.windows => WindowsOsData,
else => @compileError("Unsupported OS"),
}; };
const WindowsOsData = struct { const WindowsOsData = struct {

View File

@ -133,7 +133,7 @@ pub const Compilation = struct {
zig_std_dir: []const u8, zig_std_dir: []const u8,
/// lazily created when we need it /// 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_major: u32 = 0,
version_minor: 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 /// functions that have their own objects that we need to link
/// it uses an optional pointer so that tombstone removals are possible /// 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); pub const FnLinkSet = std.TailQueue(?*Value.Fn);
@ -227,9 +227,9 @@ pub const Compilation = struct {
/// need to wait on this group before deinitializing /// need to wait on this group before deinitializing
deinit_group: event.Group(void), deinit_group: event.Group(void),
// destroy_frame: @Frame(createAsync), destroy_frame: *@Frame(createAsync),
// main_loop_frame: @Frame(Compilation.mainLoop), main_loop_frame: *@Frame(Compilation.mainLoop),
main_loop_future: event.Future(void), main_loop_future: event.Future(void) = event.Future(void).init(),
have_err_ret_tracing: bool = false, have_err_ret_tracing: bool = false,
@ -245,6 +245,8 @@ pub const Compilation = struct {
fs_watch: *fs.Watch(*Scope.Root), 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 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 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); 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, zig_lib_dir: []const u8,
) !*Compilation { ) !*Compilation {
var optional_comp: ?*Compilation = null; 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, &optional_comp,
zig_compiler, zig_compiler,
name, name,
@ -385,15 +389,12 @@ pub const Compilation = struct {
.build_mode = build_mode, .build_mode = build_mode,
.zig_lib_dir = zig_lib_dir, .zig_lib_dir = zig_lib_dir,
.zig_std_dir = undefined, .zig_std_dir = undefined,
.tmp_dir = event.Future(BuildError![]u8).init(), .destroy_frame = @frame(),
// .destroy_frame = @frame(), .main_loop_frame = undefined,
// .main_loop_frame = undefined,
.main_loop_future = event.Future(void).init(),
.name = undefined, .name = undefined,
.llvm_triple = undefined, .llvm_triple = undefined,
.is_static = is_static, .is_static = is_static,
.fn_link_set = event.Locked(FnLinkSet).init(FnLinkSet.init()),
.link_libs_list = undefined, .link_libs_list = undefined,
.exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)), .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)),
@ -505,7 +506,10 @@ pub const Compilation = struct {
try comp.initTypes(); try comp.initTypes();
defer comp.primitive_type_table.deinit(); 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. // Set this to indicate that initialization completed successfully.
// from here on out we must not return an error. // from here on out we must not return an error.
// This must occur before the first suspend/await. // This must occur before the first suspend/await.
@ -718,8 +722,11 @@ pub const Compilation = struct {
} }
pub fn destroy(self: *Compilation) void { pub fn destroy(self: *Compilation) void {
// await self.main_loop_frame; const allocator = self.gpa();
// resume self.destroy_frame; self.cancelled = true;
await self.main_loop_frame;
resume self.destroy_frame;
allocator.destroy(self.destroy_frame);
} }
fn start(self: *Compilation) void { fn start(self: *Compilation) void {
@ -732,7 +739,7 @@ pub const Compilation = struct {
var build_result = self.initialCompile(); var build_result = self.initialCompile();
while (true) { while (!self.cancelled) {
const link_result = if (build_result) blk: { const link_result = if (build_result) blk: {
break :blk self.maybeLink(); break :blk self.maybeLink();
} else |err| err; } else |err| err;
@ -1130,11 +1137,10 @@ pub const Compilation = struct {
return link_lib; return link_lib;
} }
/// cancels itself so no need to await or cancel the promise.
async fn startFindingNativeLibC(self: *Compilation) void { 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 // 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. /// General Purpose Allocator. Must free when done.
@ -1215,7 +1221,10 @@ pub const Compilation = struct {
node: *ast.Node, node: *ast.Node,
expected_type: *Type, expected_type: *Type,
) !*Value { ) !*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()); defer analyzed_code.destroy(comp.gpa());
return analyzed_code.getCompTimeResult(comp); 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); 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, tree_scope,
fn_val.child_scope, fn_val.child_scope,
body_node, body_node,
fn_type.key.data.Normal.return_type, fn_type.key.data.Normal.return_type,
); );
const analyzed_code = try await frame;
errdefer analyzed_code.destroy(comp.gpa()); errdefer analyzed_code.destroy(comp.gpa());
assert(fn_val.block_scope != null); assert(fn_val.block_scope != null);

View File

@ -658,7 +658,7 @@ pub const Inst = struct {
const amt = try align_inst.getAsConstAlign(ira); const amt = try align_inst.getAsConstAlign(ira);
break :blk Type.Pointer.Align{ .Override = amt }; break :blk Type.Pointer.Align{ .Override = amt };
} else blk: { } else blk: {
break :blk Type.Pointer.Align{ .Abi = {} }; break :blk .Abi;
}; };
const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{ const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
.child_type = child_type, .child_type = child_type,
@ -1078,6 +1078,14 @@ pub const Builder = struct {
self.current_basic_block = basic_block; 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 { pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
switch (node.id) { switch (node.id) {
.Root => unreachable, .Root => unreachable,
@ -1157,7 +1165,7 @@ pub const Builder = struct {
}, },
.GroupedExpression => { .GroupedExpression => {
const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node); 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, .BuiltinCall => return error.Unimplemented,
.ErrorSetDecl => 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 { 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.genNodeRecursive(suffix_op.lhs.node, scope, .None);
const fn_ref = try irb.genNode(suffix_op.lhs, scope, .None);
const args = try irb.arena().alloc(*Inst, call.params.len); const args = try irb.arena().alloc(*Inst, call.params.len);
var it = call.params.iterator(0); var it = call.params.iterator(0);
var i: usize = 0; var i: usize = 0;
while (it.next()) |arg_node_ptr| : (i += 1) { 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; //bool is_async = node->data.fn_call_expr.is_async;
@ -1239,7 +1246,7 @@ pub const Builder = struct {
//} else { //} else {
// align_value = nullptr; // 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; //uint32_t bit_offset_start = 0;
//if (node->data.pointer_type.bit_offset_start != nullptr) { //if (node->data.pointer_type.bit_offset_start != nullptr) {
@ -1438,7 +1445,7 @@ pub const Builder = struct {
child_scope = &defer_child_scope.base; child_scope = &defer_child_scope.base;
continue; 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(); is_continuation_unreachable = statement_value.isNoReturn();
if (is_continuation_unreachable) { if (is_continuation_unreachable) {
@ -1534,7 +1541,7 @@ pub const Builder = struct {
const outer_scope = irb.begin_scope.?; const outer_scope = irb.begin_scope.?;
const return_value = if (control_flow_expr.rhs) |rhs| blk: { 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: { } else blk: {
break :blk try irb.buildConstVoid(scope, src_span, true); break :blk try irb.buildConstVoid(scope, src_span, true);
}; };
@ -1713,7 +1720,7 @@ pub const Builder = struct {
}; };
if (generate) { if (generate) {
const defer_expr_scope = defer_scope.defer_expr_scope; 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.expr_node,
&defer_expr_scope.base, &defer_expr_scope.base,
.None, .None,

View File

@ -400,7 +400,7 @@ fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool
const argv = [_][]const u8{ cc_exe, arg1 }; const argv = [_][]const u8{ cc_exe, arg1 };
// TODO This simulates evented I/O for the child process exec // 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 errorable_result = std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
const exec_result = if (std.debug.runtime_safety) blk: { const exec_result = if (std.debug.runtime_safety) blk: {
break :blk errorable_result catch unreachable; break :blk errorable_result catch unreachable;

View File

@ -623,16 +623,15 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
} }
fn addFnObjects(ctx: *Context) !void { fn addFnObjects(ctx: *Context) !void {
// at this point it's guaranteed nobody else has this lock, so we circumvent it const held = ctx.comp.fn_link_set.acquire();
// and avoid having to be an async function defer held.release();
const fn_link_set = &ctx.comp.fn_link_set.private_data;
var it = fn_link_set.first; var it = held.value.first;
while (it) |node| { while (it) |node| {
const fn_val = node.data orelse { const fn_val = node.data orelse {
// handle the tombstone. See Value.Fn.destroy. // handle the tombstone. See Value.Fn.destroy.
it = node.next; it = node.next;
fn_link_set.remove(node); held.value.remove(node);
ctx.comp.gpa().destroy(node); ctx.comp.gpa().destroy(node);
continue; continue;
}; };

View File

@ -127,7 +127,7 @@ pub fn main() !void {
try stderr.print("unknown command: {}\n\n", args[1]); try stderr.print("unknown command: {}\n\n", args[1]);
try stderr.write(usage); try stderr.write(usage);
process.argsFree(allocator, args); process.argsFree(allocator, args);
defer process.exit(1); process.exit(1);
} }
const usage_build_generic = 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 { fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
var count: usize = 0; var count: usize = 0;
while (true) { // TODO(Vexu) while (!comp.cancelled) {
const build_event = comp.events.get(); const build_event = comp.events.get();
count += 1; 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", "Try running `zig libc` to see an example for the native target.\n",
libc_paths_file, libc_paths_file,
@errorName(err), @errorName(err),
) catch process.exit(1); ) catch {};
process.exit(1); process.exit(1);
}; };
} }
@ -568,7 +568,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
defer zig_compiler.deinit(); defer zig_compiler.deinit();
const libc = zig_compiler.getNativeLibC() catch |err| { 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); process.exit(1);
}; };
libc.render(stdout) 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| { while (try it.next()) |entry| {
if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { 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 }); 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(); return group.wait();

View File

@ -167,7 +167,7 @@ pub fn getDarwinArchString(self: Target) [:0]const u8 {
.powerpc64 => return "ppc64", .powerpc64 => return "ppc64",
.powerpc64le => return "ppc64le", .powerpc64le => return "ppc64le",
// @tagName should be able to return sentinel terminated slice // @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),
} }
} }

View File

@ -350,7 +350,7 @@ pub const Value = struct {
.mut = mut, .mut = mut,
.vol = Type.Pointer.Vol.Non, .vol = Type.Pointer.Vol.Non,
.size = size, .size = size,
.alignment = Type.Pointer.Align.Abi, .alignment = .Abi,
}); });
var ptr_type_consumed = false; var ptr_type_consumed = false;
errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp); errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);