diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index 0bbc710dfc79..346d0f294a46 100644 --- a/lib/std/event/fs.zig +++ b/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, @@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type { os.linux.EINVAL => unreachable, os.linux.EFAULT => unreachable, os.linux.EAGAIN => { - global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN); + global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN | os.EPOLLONESHOT); }, else => unreachable, } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 7d4fb5fa7213..030112985ade 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -25,10 +25,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) const context = llvm_handle.node.data; - const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory; + const module = llvm.ModuleCreateWithNameInContext(comp.name.toSliceConst(), context) orelse return error.OutOfMemory; defer llvm.DisposeModule(module); - llvm.SetTarget(module, comp.llvm_triple.ptr()); + llvm.SetTarget(module, comp.llvm_triple.toSliceConst()); llvm.SetDataLayout(module, comp.target_layout_str); if (util.getObjectFormat(comp.target) == .coff) { @@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) const producer = try std.Buffer.allocPrint( &code.arena.allocator, "zig {}.{}.{}", - u32(c.ZIG_VERSION_MAJOR), - u32(c.ZIG_VERSION_MINOR), - u32(c.ZIG_VERSION_PATCH), + @as(u32, c.ZIG_VERSION_MAJOR), + @as(u32, c.ZIG_VERSION_MINOR), + @as(u32, c.ZIG_VERSION_PATCH), ); const flags = ""; const runtime_version = 0; const compile_unit_file = llvm.CreateFile( dibuilder, - comp.name.ptr(), - comp.root_package.root_src_dir.ptr(), + comp.name.toSliceConst(), + comp.root_package.root_src_dir.toSliceConst(), ) orelse return error.OutOfMemory; const is_optimized = comp.build_mode != .Debug; const compile_unit = llvm.CreateCompileUnit( dibuilder, DW.LANG_C99, compile_unit_file, - producer.ptr(), + producer.toSliceConst(), is_optimized, flags, runtime_version, @@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) // verify the llvm module when safety is on if (std.debug.runtime_safety) { - var error_ptr: ?[*]u8 = null; + var error_ptr: ?[*:0]u8 = null; _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); } @@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) const is_small = comp.build_mode == .ReleaseSmall; const is_debug = comp.build_mode == .Debug; - var err_msg: [*]u8 = undefined; + var err_msg: [*:0]u8 = undefined; // TODO integrate this with evented I/O if (llvm.TargetMachineEmitToFile( comp.target_machine, module, - output_path.ptr(), + output_path.toSliceConst(), llvm.EmitBinary, &err_msg, is_debug, @@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, - fn_val.symbol_name.ptr(), + fn_val.symbol_name.toSliceConst(), llvm_fn_type, ) orelse return error.OutOfMemory; @@ -379,7 +379,7 @@ fn renderLoadUntyped( ptr: *llvm.Value, alignment: Type.Pointer.Align, vol: Type.Pointer.Vol, - name: [*]const u8, + name: [*:0]const u8, ) !*llvm.Value { const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; switch (vol) { @@ -390,7 +390,7 @@ fn renderLoadUntyped( return result; } -fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value { +fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*:0]const u8) !*llvm.Value { return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); } @@ -438,7 +438,7 @@ pub fn renderAlloca( ) !*llvm.Value { const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); const name_with_null = try std.cstr.addNullByte(ofile.arena, name); - const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory; + const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, @ptrCast([*:0]const u8, name_with_null.ptr)) orelse return error.OutOfMemory; llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type)); return result; } diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 2f0de0c5212a..a43d4ebc8301 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -93,7 +93,7 @@ pub const ZigCompiler = struct { return LlvmHandle{ .node = node }; } - pub async fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { + pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { if (self.native_libc.start()) |ptr| return ptr; try self.native_libc.data.findNative(self.allocator); self.native_libc.resolve(); @@ -133,62 +133,62 @@ 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, - version_minor: u32, - version_patch: u32, + version_major: u32 = 0, + version_minor: u32 = 0, + version_patch: u32 = 0, - linker_script: ?[]const u8, - out_h_path: ?[]const u8, + linker_script: ?[]const u8 = null, + out_h_path: ?[]const u8 = null, - is_test: bool, - each_lib_rpath: bool, - strip: bool, + is_test: bool = false, + each_lib_rpath: bool = false, + strip: bool = false, is_static: bool, - linker_rdynamic: bool, + linker_rdynamic: bool = false, - clang_argv: []const []const u8, - lib_dirs: []const []const u8, - rpath_list: []const []const u8, - assembly_files: []const []const u8, + clang_argv: []const []const u8 = [_][]const u8{}, + lib_dirs: []const []const u8 = [_][]const u8{}, + rpath_list: []const []const u8 = [_][]const u8{}, + assembly_files: []const []const u8 = [_][]const u8{}, /// paths that are explicitly provided by the user to link against - link_objects: []const []const u8, + link_objects: []const []const u8 = [_][]const u8{}, /// 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); - windows_subsystem_windows: bool, - windows_subsystem_console: bool, + windows_subsystem_windows: bool = false, + windows_subsystem_console: bool = false, link_libs_list: ArrayList(*LinkLib), - libc_link_lib: ?*LinkLib, + libc_link_lib: ?*LinkLib = null, - err_color: errmsg.Color, + err_color: errmsg.Color = .Auto, - verbose_tokenize: bool, - verbose_ast_tree: bool, - verbose_ast_fmt: bool, - verbose_cimport: bool, - verbose_ir: bool, - verbose_llvm_ir: bool, - verbose_link: bool, + verbose_tokenize: bool = false, + verbose_ast_tree: bool = false, + verbose_ast_fmt: bool = false, + verbose_cimport: bool = false, + verbose_ir: bool = false, + verbose_llvm_ir: bool = false, + verbose_link: bool = false, - darwin_frameworks: []const []const u8, - darwin_version_min: DarwinVersionMin, + darwin_frameworks: []const []const u8 = [_][]const u8{}, + darwin_version_min: DarwinVersionMin = .None, - test_filters: []const []const u8, - test_name_prefix: ?[]const u8, + test_filters: []const []const u8 = [_][]const u8{}, + test_name_prefix: ?[]const u8 = null, - emit_file_type: Emit, + emit_file_type: Emit = .Binary, kind: Kind, - link_out_file: ?[]const u8, + link_out_file: ?[]const u8 = null, events: *event.Channel(Event), exported_symbol_names: event.Locked(Decl.Table), @@ -213,7 +213,7 @@ pub const Compilation = struct { target_machine: *llvm.TargetMachine, target_data_ref: *llvm.TargetData, - target_layout_str: [*]u8, + target_layout_str: [*:0]u8, target_ptr_bits: u32, /// for allocating things which have the same lifetime as this Compilation @@ -222,16 +222,16 @@ pub const Compilation = struct { root_package: *Package, std_package: *Package, - override_libc: ?*LibCInstallation, + override_libc: ?*LibCInstallation = null, /// 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, + have_err_ret_tracing: bool = false, /// not locked because it is read-only primitive_type_table: TypeTable, @@ -243,7 +243,9 @@ pub const Compilation = struct { c_int_types: [CInt.list.len]*Type.Int, - // 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 ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.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, @@ -359,7 +363,11 @@ pub const Compilation = struct { is_static, zig_lib_dir, ); - return optional_comp orelse if (await frame) |_| unreachable else |err| err; + // TODO causes segfault + // return optional_comp orelse if (await frame) |_| unreachable else |err| err; + if (optional_comp) |comp| { + return comp; + } else if (await frame) |_| unreachable else |err| return err; } async fn createAsync( @@ -385,50 +393,14 @@ 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, - - .version_major = 0, - .version_minor = 0, - .version_patch = 0, - - .verbose_tokenize = false, - .verbose_ast_tree = false, - .verbose_ast_fmt = false, - .verbose_cimport = false, - .verbose_ir = false, - .verbose_llvm_ir = false, - .verbose_link = false, - - .linker_script = null, - .out_h_path = null, - .is_test = false, - .each_lib_rpath = false, - .strip = false, .is_static = is_static, - .linker_rdynamic = false, - .clang_argv = [_][]const u8{}, - .lib_dirs = [_][]const u8{}, - .rpath_list = [_][]const u8{}, - .assembly_files = [_][]const u8{}, - .link_objects = [_][]const u8{}, - .fn_link_set = event.Locked(FnLinkSet).init(FnLinkSet.init()), - .windows_subsystem_windows = false, - .windows_subsystem_console = false, .link_libs_list = undefined, - .libc_link_lib = null, - .err_color = errmsg.Color.Auto, - .darwin_frameworks = [_][]const u8{}, - .darwin_version_min = DarwinVersionMin.None, - .test_filters = [_][]const u8{}, - .test_name_prefix = null, - .emit_file_type = Emit.Binary, - .link_out_file = null, + .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)), .prelink_group = event.Group(BuildError!void).init(allocator), .deinit_group = event.Group(void).init(allocator), @@ -458,11 +430,9 @@ pub const Compilation = struct { .root_package = undefined, .std_package = undefined, - .override_libc = null, - .have_err_ret_tracing = false, .primitive_type_table = undefined, - // .fs_watch = undefined, + .fs_watch = undefined, }; comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); comp.primitive_type_table = TypeTable.init(comp.arena()); @@ -534,13 +504,16 @@ pub const Compilation = struct { comp.root_package = try Package.create(comp.arena(), ".", ""); } - // comp.fs_watch = try fs.Watch(*Scope.Root).create(16); - // defer comp.fs_watch.destroy(); + comp.fs_watch = try fs.Watch(*Scope.Root).init(allocator, 16); + defer comp.fs_watch.deinit(); 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. @@ -559,7 +532,7 @@ pub const Compilation = struct { } /// it does ref the result because it could be an arbitrary integer size - pub async fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type { + pub fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type { if (name.len >= 2) { switch (name[0]) { 'i', 'u' => blk: { @@ -753,8 +726,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 { @@ -767,7 +743,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; @@ -795,47 +771,47 @@ pub const Compilation = struct { self.events.put(Event{ .Error = err }); } - // // First, get an item from the watch channel, waiting on the channel. - // var group = event.Group(BuildError!void).init(self.gpa()); - // { - // const ev = (self.fs_watch.channel.get()) catch |err| { - // build_result = err; - // continue; - // }; - // const root_scope = ev.data; - // group.call(rebuildFile, self, root_scope) catch |err| { - // build_result = err; - // continue; - // }; - // } - // // Next, get all the items from the channel that are buffered up. - // while (self.fs_watch.channel.getOrNull()) |ev_or_err| { - // if (ev_or_err) |ev| { - // const root_scope = ev.data; - // group.call(rebuildFile, self, root_scope) catch |err| { - // build_result = err; - // continue; - // }; - // } else |err| { - // build_result = err; - // continue; - // } - // } - // build_result = group.wait(); + // First, get an item from the watch channel, waiting on the channel. + var group = event.Group(BuildError!void).init(self.gpa()); + { + const ev = (self.fs_watch.channel.get()) catch |err| { + build_result = err; + continue; + }; + const root_scope = ev.data; + group.call(rebuildFile, self, root_scope) catch |err| { + build_result = err; + continue; + }; + } + // Next, get all the items from the channel that are buffered up. + while (self.fs_watch.channel.getOrNull()) |ev_or_err| { + if (ev_or_err) |ev| { + const root_scope = ev.data; + group.call(rebuildFile, self, root_scope) catch |err| { + build_result = err; + continue; + }; + } else |err| { + build_result = err; + continue; + } + } + build_result = group.wait(); } } - async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) !void { + async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) BuildError!void { const tree_scope = blk: { - const source_code = ""; - // const source_code = fs.readFile( - // root_scope.realpath, - // max_src_size, - // ) catch |err| { - // try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err)); - // return; - // }; - // errdefer self.gpa().free(source_code); + const source_code = fs.readFile( + self.gpa(), + root_scope.realpath, + max_src_size, + ) catch |err| { + try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err)); + return; + }; + errdefer self.gpa().free(source_code); const tree = try std.zig.parse(self.gpa(), source_code); errdefer { @@ -873,7 +849,7 @@ pub const Compilation = struct { try decl_group.wait(); } - async fn rebuildChangedDecls( + fn rebuildChangedDecls( self: *Compilation, group: *event.Group(BuildError!void), locked_table: *Decl.Table, @@ -962,7 +938,7 @@ pub const Compilation = struct { } } - async fn initialCompile(self: *Compilation) !void { + fn initialCompile(self: *Compilation) !void { if (self.root_src_path) |root_src_path| { const root_scope = blk: { // TODO async/await std.fs.realpath @@ -981,7 +957,7 @@ pub const Compilation = struct { } } - async fn maybeLink(self: *Compilation) !void { + fn maybeLink(self: *Compilation) !void { (self.prelink_group.wait()) catch |err| switch (err) { error.SemanticAnalysisFailed => {}, else => return err, @@ -1165,11 +1141,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. @@ -1184,7 +1159,7 @@ pub const Compilation = struct { /// If the temporary directory for this compilation has not been created, it creates it. /// Then it creates a random file name in that dir and returns it. - pub async fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer { + pub fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer { const tmp_dir = try self.getTmpDir(); const file_prefix = self.getRandomFileName(); @@ -1200,14 +1175,14 @@ pub const Compilation = struct { /// If the temporary directory for this Compilation has not been created, creates it. /// Then returns it. The directory is unique to this Compilation and cleaned up when /// the Compilation deinitializes. - async fn getTmpDir(self: *Compilation) ![]const u8 { + fn getTmpDir(self: *Compilation) ![]const u8 { if (self.tmp_dir.start()) |ptr| return ptr.*; self.tmp_dir.data = self.getTmpDirImpl(); self.tmp_dir.resolve(); return self.tmp_dir.data; } - async fn getTmpDirImpl(self: *Compilation) ![]u8 { + fn getTmpDirImpl(self: *Compilation) ![]u8 { const comp_dir_name = self.getRandomFileName(); const zig_dir_path = try getZigDir(self.gpa()); defer self.gpa().free(zig_dir_path); @@ -1217,7 +1192,7 @@ pub const Compilation = struct { return tmp_dir; } - async fn getRandomFileName(self: *Compilation) [12]u8 { + fn getRandomFileName(self: *Compilation) [12]u8 { // here we replace the standard +/ with -_ so that it can be used in a file name const b64_fs_encoder = std.base64.Base64Encoder.init( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", @@ -1243,20 +1218,23 @@ pub const Compilation = struct { } /// Returns a value which has been ref()'d once - async fn analyzeConstValue( + fn analyzeConstValue( comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, 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); } - async fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type { + fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type { const meta_type = &Type.MetaType.get(comp).base; defer meta_type.base.deref(comp); @@ -1287,7 +1265,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib } /// The function that actually does the generation. -async fn generateDecl(comp: *Compilation, decl: *Decl) !void { +fn generateDecl(comp: *Compilation, decl: *Decl) !void { switch (decl.id) { .Var => @panic("TODO"), .Fn => { @@ -1298,7 +1276,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void { } } -async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { +fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { const tree_scope = fn_decl.base.tree_scope; const body_node = fn_decl.fn_proto.body_node orelse return generateDeclFnProto(comp, fn_decl); @@ -1315,7 +1293,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { // The Decl.Fn owns the initial 1 reference count const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); - fn_decl.value = Decl.Fn.Val{ .Fn = fn_val }; + fn_decl.value = .{ .Fn = fn_val }; symbol_name_consumed = true; // Define local parameter variables @@ -1350,12 +1328,15 @@ async 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); @@ -1382,7 +1363,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 { return std.fs.getAppDataDir(allocator, "zig"); } -async fn analyzeFnType( +fn analyzeFnType( comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, @@ -1444,7 +1425,7 @@ async fn analyzeFnType( return fn_type; } -async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { +fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { const fn_type = try analyzeFnType( comp, fn_decl.base.tree_scope, @@ -1459,6 +1440,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void { // The Decl.Fn owns the initial 1 reference count const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name); - fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val }; + fn_decl.value = .{ .FnProto = fn_proto_val }; symbol_name_consumed = true; } diff --git a/src-self-hosted/decl.zig b/src-self-hosted/decl.zig index 21a99729f582..e68a1458d6b2 100644 --- a/src-self-hosted/decl.zig +++ b/src-self-hosted/decl.zig @@ -69,15 +69,12 @@ pub const Decl = struct { pub const Fn = struct { base: Decl, - value: Val, - fn_proto: *ast.Node.FnProto, - - // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous - pub const Val = union(enum) { + value: union(enum) { Unresolved, Fn: *Value.Fn, FnProto: *Value.FnProto, - }; + }, + fn_proto: *ast.Node.FnProto, pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 { return if (self.fn_proto.extern_export_inline_token) |tok_index| x: { diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 905d21811425..8d1c32cefd90 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -110,7 +110,7 @@ pub const Inst = struct { unreachable; } - pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst { + pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst { switch (base.id) { .Return => return @fieldParentPtr(Return, "base", base).analyze(ira), .Const => return @fieldParentPtr(Const, "base", base).analyze(ira), @@ -422,7 +422,7 @@ pub const Inst = struct { return false; } - pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst { + pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst { const target = try self.params.target.getAsParam(); if (ira.getCompTimeValOrNullUndefOk(target)) |val| { @@ -472,7 +472,7 @@ pub const Inst = struct { return false; } - pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst { + pub fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst { (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => return error.SemanticAnalysisFailed, @@ -516,7 +516,7 @@ pub const Inst = struct { return false; } - pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst { + pub fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst { switch (self.params.var_scope.data) { .Const => @panic("TODO"), .Param => |param| { @@ -563,7 +563,7 @@ pub const Inst = struct { return false; } - pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst { + pub fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst { const target = try self.params.target.getAsParam(); const target_type = target.getKnownType(); if (target_type.id != .Pointer) { @@ -645,7 +645,7 @@ pub const Inst = struct { return false; } - pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst { + pub fn analyze(self: *const PtrType, ira: *Analyze) !*Inst { const child_type = try self.params.child_type.getAsConstType(ira); // if (child_type->id == TypeTableEntryIdUnreachable) { // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); @@ -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, @@ -927,7 +927,7 @@ pub const Variable = struct { pub const BasicBlock = struct { ref_count: usize, - name_hint: [*]const u8, // must be a C string literal + name_hint: [*:0]const u8, debug_id: usize, scope: *Scope, instruction_list: std.ArrayList(*Inst), @@ -1051,7 +1051,7 @@ pub const Builder = struct { } /// No need to clean up resources thanks to the arena allocator. - pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { + pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*:0]const u8) !*BasicBlock { const basic_block = try self.arena().create(BasicBlock); basic_block.* = BasicBlock{ .ref_count = 0, @@ -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, @@ -1186,14 +1194,14 @@ pub const Builder = struct { } } - 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); + 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 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; @@ -1214,7 +1222,7 @@ pub const Builder = struct { //return ir_lval_wrap(irb, scope, fn_call, lval); } - async fn genPtrType( + fn genPtrType( irb: *Builder, prefix_op: *ast.Node.PrefixOp, ptr_info: ast.Node.PrefixOp.PtrInfo, @@ -1238,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) { @@ -1307,9 +1315,9 @@ pub const Builder = struct { var rest: []const u8 = undefined; if (int_token.len >= 3 and int_token[0] == '0') { base = switch (int_token[1]) { - 'b' => u8(2), - 'o' => u8(8), - 'x' => u8(16), + 'b' => 2, + 'o' => 8, + 'x' => 16, else => unreachable, }; rest = int_token[2..]; @@ -1339,7 +1347,7 @@ pub const Builder = struct { return inst; } - pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst { + pub fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst { const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token); const src_span = Span.token(str_lit.token); @@ -1389,7 +1397,7 @@ pub const Builder = struct { } } - pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { + pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst { const block_scope = try Scope.Block.create(irb.comp, parent_scope); const outer_block_scope = &block_scope.base; @@ -1437,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) { @@ -1499,7 +1507,7 @@ pub const Builder = struct { return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true); } - pub async fn genControlFlowExpr( + pub fn genControlFlowExpr( irb: *Builder, control_flow_expr: *ast.Node.ControlFlowExpression, scope: *Scope, @@ -1533,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); }; @@ -1596,7 +1604,7 @@ pub const Builder = struct { } } - pub async fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst { + pub fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst { const src_span = Span.token(identifier.token); const name = irb.code.tree_scope.tree.tokenSlice(identifier.token); @@ -1694,7 +1702,7 @@ pub const Builder = struct { return result; } - async fn genDefersForBlock( + fn genDefersForBlock( irb: *Builder, inner_scope: *Scope, outer_scope: *Scope, @@ -1712,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, @@ -1797,7 +1805,7 @@ pub const Builder = struct { // Look at the params and ref() other instructions comptime var i = 0; inline while (i < @memberCount(I.Params)) : (i += 1) { - const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i))); + const FieldType = comptime @typeOf(@field(@as(I.Params, undefined), @memberName(I.Params, i))); switch (FieldType) { *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self), *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self), @@ -1909,7 +1917,7 @@ pub const Builder = struct { VarScope: *Scope.Var, }; - async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident { + fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident { var s = scope; while (true) { switch (s.id) { @@ -2519,7 +2527,7 @@ const Analyze = struct { } }; -pub async fn gen( +pub fn gen( comp: *Compilation, body_node: *ast.Node, tree_scope: *Scope.AstTree, @@ -2541,7 +2549,7 @@ pub async fn gen( return irb.finish(); } -pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code { +pub fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code { const old_entry_bb = old_code.basic_block_list.at(0); var ira = try Analyze.init(comp, old_code.tree_scope, expected_type); diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index 42e7de5d0839..71cec00eba52 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -143,7 +143,7 @@ pub const LibCInstallation = struct { } /// Finds the default, native libc. - pub async fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { + pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { self.initEmpty(); var group = event.Group(FindError!void).init(allocator); errdefer group.wait() catch {}; @@ -393,14 +393,14 @@ pub const LibCInstallation = struct { }; /// caller owns returned memory -async fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { +fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { const cc_exe = std.os.getenv("CC") orelse "cc"; const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file); defer allocator.free(arg1); 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; diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index aafe05eb8be9..67490b4e1f0f 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -11,7 +11,7 @@ const util = @import("util.zig"); const Context = struct { comp: *Compilation, arena: std.heap.ArenaAllocator, - args: std.ArrayList([*]const u8), + args: std.ArrayList([*:0]const u8), link_in_crt: bool, link_err: error{OutOfMemory}!void, @@ -21,7 +21,7 @@ const Context = struct { out_file_path: std.Buffer, }; -pub async fn link(comp: *Compilation) !void { +pub fn link(comp: *Compilation) !void { var ctx = Context{ .comp = comp, .arena = std.heap.ArenaAllocator.init(comp.gpa()), @@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void { .out_file_path = undefined, }; defer ctx.arena.deinit(); - ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator); + ctx.args = std.ArrayList([*:0]const u8).init(&ctx.arena.allocator); ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator); if (comp.link_out_file) |out_file| { @@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void { try ctx.args.append("lld"); if (comp.haveLibC()) { - ctx.libc = ctx.comp.override_libc orelse blk: { + // TODO https://github.com/ziglang/zig/issues/3190 + var libc = ctx.comp.override_libc orelse blk: { switch (comp.target) { Target.Native => { break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; @@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void { else => return error.LibCRequiredButNotProvidedOrFound, } }; + ctx.libc = libc; } try constructLinkerArgs(&ctx); @@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { //} try ctx.args.append("-o"); - try ctx.args.append(ctx.out_file_path.ptr()); + try ctx.args.append(ctx.out_file_path.toSliceConst()); if (ctx.link_in_crt) { const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; @@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { if (ctx.comp.haveLibC()) { try ctx.args.append("-L"); - try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr); + // TODO addNullByte should probably return [:0]u8 + try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr)); try ctx.args.append("-L"); - try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); if (!ctx.comp.is_static) { const dl = blk: { @@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { return error.LibCMissingDynamicLinker; }; try ctx.args.append("-dynamic-linker"); - try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); } } @@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // .o files for (ctx.comp.link_objects) |link_object| { const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); - try ctx.args.append(link_obj_with_null.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); } try addFnObjects(ctx); @@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename }); const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path); - try ctx.args.append(full_path_with_null.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, full_path_with_null.ptr)); } fn constructLinkerArgsCoff(ctx: *Context) !void { @@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { const is_library = ctx.comp.kind == .Lib; const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst()); - try ctx.args.append(out_arg.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, out_arg.ptr)); if (ctx.comp.haveLibC()) { - try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr); - try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr); - try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr)); } if (ctx.link_in_crt) { @@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { if (ctx.comp.is_static) { const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str); - try ctx.args.append(cmt_lib_name.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, cmt_lib_name.ptr)); } else { const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str); - try ctx.args.append(msvcrt_lib_name.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, msvcrt_lib_name.ptr)); } const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str); - try ctx.args.append(vcruntime_lib_name.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, vcruntime_lib_name.ptr)); const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str); - try ctx.args.append(crt_lib_name.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, crt_lib_name.ptr)); // Visual C++ 2015 Conformance Changes // https://msdn.microsoft.com/en-us/library/bb531344.aspx @@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { for (ctx.comp.link_objects) |link_object| { const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); - try ctx.args.append(link_obj_with_null.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); } try addFnObjects(ctx); @@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { //} try ctx.args.append("-arch"); - const darwin_arch_str = try std.cstr.addNullByte( - &ctx.arena.allocator, - ctx.comp.target.getDarwinArchString(), - ); - try ctx.args.append(darwin_arch_str.ptr); + try ctx.args.append(util.getDarwinArchString(ctx.comp.target)); const platform = try DarwinPlatform.get(ctx.comp); switch (platform.kind) { @@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"), } const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro); - try ctx.args.append(ver_str.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, ver_str.ptr)); if (ctx.comp.kind == .Exe) { if (ctx.comp.is_static) { @@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } try ctx.args.append("-o"); - try ctx.args.append(ctx.out_file_path.ptr()); + try ctx.args.append(ctx.out_file_path.toSliceConst()); //for (size_t i = 0; i < g->rpath_list.length; i += 1) { // Buf *rpath = g->rpath_list.at(i); @@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { for (ctx.comp.link_objects) |link_object| { const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); - try ctx.args.append(link_obj_with_null.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr)); } try addFnObjects(ctx); @@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } else { if (mem.indexOfScalar(u8, lib.name, '/') == null) { const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name); - try ctx.args.append(arg.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); } else { const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); - try ctx.args.append(arg.ptr); + try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); } } } @@ -626,20 +625,19 @@ 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; }; - try ctx.args.append(fn_val.containing_object.ptr()); + try ctx.args.append(fn_val.containing_object.toSliceConst()); it = node.next; } } diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index af42adb97dfa..476637b2c2c7 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal; extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value; pub const ConstStringInContext = LLVMConstStringInContext; -extern fn LLVMConstStringInContext(C: *Context, Str: [*:0]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; +extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; pub const ConstInt = LLVMConstInt; extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index bf3fb4dea5bd..4288c4ea9ae7 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -49,14 +49,15 @@ const usage = const Command = struct { name: []const u8, - exec: fn (*Allocator, []const []const u8) anyerror!void, + exec: async fn (*Allocator, []const []const u8) anyerror!void, }; pub fn main() !void { // This allocator needs to be thread-safe because we use it for the event.Loop // which multiplexes async functions onto kernel threads. // libc allocator is guaranteed to have this property. - const allocator = std.heap.c_allocator; + // TODO https://github.com/ziglang/zig/issues/3783 + const allocator = std.heap.page_allocator; stdout = &std.io.getStdOut().outStream().stream; @@ -118,14 +119,18 @@ pub fn main() !void { }, }; - for (commands) |command| { + inline for (commands) |command| { if (mem.eql(u8, command.name, args[1])) { - return command.exec(allocator, args[2..]); + var frame = try allocator.create(@Frame(command.exec)); + defer allocator.destroy(frame); + frame.* = async command.exec(allocator, args[2..]); + return await frame; } } try stderr.print("unknown command: {}\n\n", args[1]); try stderr.write(usage); + process.argsFree(allocator, args); process.exit(1); } @@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co comp.link_objects = link_objects; comp.start(); - const frame = async processBuildEvents(comp, color); + processBuildEvents(comp, color); } -async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { +fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { var count: usize = 0; - while (true) { - // TODO directly awaiting async should guarantee memory allocation elision + while (!comp.cancelled) { const build_event = comp.events.get(); count += 1; @@ -545,7 +549,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); }; } @@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { var zig_compiler = try ZigCompiler.init(allocator); defer zig_compiler.deinit(); - const frame = async findLibCAsync(&zig_compiler); -} - -async fn findLibCAsync(zig_compiler: *ZigCompiler) void { 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); @@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { process.exit(1); } - return asyncFmtMain( - allocator, - &flags, - color, - ); + var fmt = Fmt{ + .allocator = allocator, + .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)), + .any_error = false, + .color = color, + }; + + const check_mode = flags.present("check"); + + var group = event.Group(FmtError!void).init(allocator); + for (flags.positionals.toSliceConst()) |file_path| { + try group.call(fmtPath, &fmt, file_path, check_mode); + } + try group.wait(); + if (fmt.any_error) { + process.exit(1); + } } const FmtError = error{ @@ -673,30 +685,6 @@ const FmtError = error{ CurrentWorkingDirectoryUnlinked, } || fs.File.OpenError; -async fn asyncFmtMain( - allocator: *Allocator, - flags: *const Args, - color: errmsg.Color, -) FmtError!void { - var fmt = Fmt{ - .allocator = allocator, - .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)), - .any_error = false, - .color = color, - }; - - const check_mode = flags.present("check"); - - var group = event.Group(FmtError!void).init(allocator); - for (flags.positionals.toSliceConst()) |file_path| { - try group.call(fmtPath, &fmt, file_path, check_mode); - } - try group.wait(); - if (fmt.any_error) { - process.exit(1); - } -} - async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); defer fmt.allocator.free(file_path); @@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro if (try held.value.put(file_path, {})) |_| return; } - const source_code = ""; - // const source_code = event.fs.readFile( - // file_path, - // max_src_size, - // ) catch |err| switch (err) { - // error.IsDir, error.AccessDenied => { - // // TODO make event based (and dir.next()) - // var dir = try fs.Dir.cwd().openDirList(file_path); - // defer dir.close(); - - // var group = event.Group(FmtError!void).init(fmt.allocator); - // while (try dir.next()) |entry| { - // if (entry.kind == fs.Dir.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); - // } - // } - // return group.wait(); - // }, - // else => { - // // TODO lock stderr printing - // try stderr.print("unable to open '{}': {}\n", file_path, err); - // fmt.any_error = true; - // return; - // }, - // }; - // defer fmt.allocator.free(source_code); + const source_code = event.fs.readFile( + fmt.allocator, + file_path, + max_src_size, + ) catch |err| switch (err) { + error.IsDir, error.AccessDenied => { + var dir = try fs.Dir.cwd().openDirList(file_path); + defer dir.close(); + + var group = event.Group(FmtError!void).init(fmt.allocator); + var it = dir.iterate(); + 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 }); + @panic("TODO https://github.com/ziglang/zig/issues/3777"); + // try group.call(fmtPath, fmt, full_path, check_mode); + } + } + return group.wait(); + }, + else => { + // TODO lock stderr printing + try stderr.print("unable to open '{}': {}\n", file_path, err); + fmt.any_error = true; + return; + }, + }; + defer fmt.allocator.free(source_code); const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { try stderr.print("error parsing file '{}': {}\n", file_path, err); @@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { .exec = cmdInternalBuildInfo, }}; - for (sub_commands) |sub_command| { + inline for (sub_commands) |sub_command| { if (mem.eql(u8, sub_command.name, args[0])) { - try sub_command.exec(allocator, args[1..]); - return; + var frame = try allocator.create(@Frame(sub_command.exec)); + defer allocator.destroy(frame); + frame.* = async sub_command.exec(allocator, args[1..]); + return await frame; } } diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index 85b9d6b912f5..62b7914dbc8d 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -26,7 +26,8 @@ test "stage2" { } const file1 = "1.zig"; -const allocator = std.heap.c_allocator; +// TODO https://github.com/ziglang/zig/issues/3783 +const allocator = std.heap.page_allocator; pub const TestContext = struct { zig_compiler: ZigCompiler, @@ -94,8 +95,8 @@ pub const TestContext = struct { &self.zig_compiler, "test", file1_path, - Target.Native, - Compilation.Kind.Obj, + .Native, + .Obj, .Debug, true, // is_static self.zig_lib_dir, @@ -116,7 +117,7 @@ pub const TestContext = struct { const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr()); const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 }); - const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{.Native = {}}).exeFileExt()); + const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{ .Native = {} }).exeFileExt()); if (std.fs.path.dirname(file1_path)) |dirname| { try std.fs.makePath(allocator, dirname); } @@ -128,8 +129,8 @@ pub const TestContext = struct { &self.zig_compiler, "test", file1_path, - Target.Native, - Compilation.Kind.Exe, + .Native, + .Exe, .Debug, false, self.zig_lib_dir, @@ -148,15 +149,12 @@ pub const TestContext = struct { exe_file: []const u8, expected_output: []const u8, ) anyerror!void { - // TODO this should not be necessary - const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file); - defer comp.destroy(); const build_event = comp.events.get(); switch (build_event) { .Ok => { - const argv = [_][]const u8{exe_file_2}; + const argv = [_][]const u8{exe_file}; // TODO use event loop const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024); switch (child.term) { @@ -173,13 +171,13 @@ pub const TestContext = struct { return error.OutputMismatch; } }, - Compilation.Event.Error => |err| return err, - Compilation.Event.Fail => |msgs| { + .Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err, + .Fail => |msgs| { const stderr = std.io.getStdErr(); try stderr.write("build incorrectly failed:\n"); for (msgs) |msg| { defer msg.destroy(); - try msg.printToFile(stderr, errmsg.Color.Auto); + try msg.printToFile(stderr, .Auto); } }, } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 3bf39d908587..8b068150b66f 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -53,7 +53,7 @@ pub const Type = struct { base: *Type, allocator: *Allocator, llvm_context: *llvm.Context, - ) (error{OutOfMemory}!*llvm.Type) { + ) error{OutOfMemory}!*llvm.Type { switch (base.id) { .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), @@ -184,7 +184,7 @@ pub const Type = struct { /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead. /// Otherwise, this one will grab one from the pool and then release it. - pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 { + pub fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 { if (base.abi_alignment.start()) |ptr| return ptr.*; { @@ -200,7 +200,7 @@ pub const Type = struct { } /// If you have an llvm conext handy, you can use it here. - pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { + pub fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { if (base.abi_alignment.start()) |ptr| return ptr.*; base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context); @@ -209,7 +209,7 @@ pub const Type = struct { } /// Lower level function that does the work. See getAbiAlignment. - async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { + fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); } @@ -367,7 +367,7 @@ pub const Type = struct { } /// takes ownership of key.Normal.params on success - pub async fn get(comp: *Compilation, key: Key) !*Fn { + pub fn get(comp: *Compilation, key: Key) !*Fn { { const held = comp.fn_type_table.acquire(); defer held.release(); @@ -564,7 +564,7 @@ pub const Type = struct { return comp.u8_type; } - pub async fn get(comp: *Compilation, key: Key) !*Int { + pub fn get(comp: *Compilation, key: Key) !*Int { { const held = comp.int_type_table.acquire(); defer held.release(); @@ -606,7 +606,7 @@ pub const Type = struct { comp.registerGarbage(Int, &self.garbage_node); } - pub async fn gcDestroy(self: *Int, comp: *Compilation) void { + pub fn gcDestroy(self: *Int, comp: *Compilation) void { { const held = comp.int_type_table.acquire(); defer held.release(); @@ -700,7 +700,7 @@ pub const Type = struct { comp.registerGarbage(Pointer, &self.garbage_node); } - pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void { + pub fn gcDestroy(self: *Pointer, comp: *Compilation) void { { const held = comp.ptr_type_table.acquire(); defer held.release(); @@ -711,14 +711,14 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 { + pub fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 { switch (self.key.alignment) { .Abi => return self.key.child_type.getAbiAlignment(comp), .Override => |alignment| return alignment, } } - pub async fn get( + pub fn get( comp: *Compilation, key: Key, ) !*Pointer { @@ -726,8 +726,10 @@ pub const Type = struct { switch (key.alignment) { .Abi => {}, .Override => |alignment| { + // TODO https://github.com/ziglang/zig/issues/3190 + var align_spill = alignment; const abi_align = try key.child_type.getAbiAlignment(comp); - if (abi_align == alignment) { + if (abi_align == align_spill) { normal_key.alignment = .Abi; } }, @@ -828,7 +830,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub async fn get(comp: *Compilation, key: Key) !*Array { + pub fn get(comp: *Compilation, key: Key) !*Array { key.elem_type.base.ref(); errdefer key.elem_type.base.deref(comp); diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index f1d892411f1d..070ba9ba87ef 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -32,21 +32,21 @@ pub fn getFloatAbi(self: Target) FloatAbi { }; } -pub fn getObjectFormat(self: Target) Target.ObjectFormat { - return switch (self) { - .Native => @import("builtin").object_format, - .Cross => { +pub fn getObjectFormat(target: Target) Target.ObjectFormat { + switch (target) { + .Native => return @import("builtin").object_format, + .Cross => blk: { if (target.isWindows() or target.isUefi()) { - break .coff; + return .coff; } else if (target.isDarwin()) { - break .macho; + return .macho; } if (target.isWasm()) { - break .wasm; + return .wasm; } - break .elf; + return .elf; }, - }; + } } pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { @@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { } } -pub fn getDarwinArchString(self: Target) []const u8 { +pub fn getDarwinArchString(self: Target) [:0]const u8 { const arch = self.getArch(); switch (arch) { .aarch64 => return "arm64", @@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 { .powerpc => return "ppc", .powerpc64 => return "ppc64", .powerpc64le => return "ppc64le", - else => return @tagName(arch), + // @tagName should be able to return sentinel terminated slice + else => @panic("TODO https://github.com/ziglang/zig/issues/3779"), //return @tagName(arch), } } diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 0458bac12a3a..accd70d9ccf5 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -156,7 +156,7 @@ pub const Value = struct { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, - self.symbol_name.ptr(), + self.symbol_name.toSliceConst(), llvm_fn_type, ) orelse return error.OutOfMemory; @@ -241,7 +241,7 @@ pub const Value = struct { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, - self.symbol_name.ptr(), + self.symbol_name.toSliceConst(), llvm_fn_type, ) orelse return error.OutOfMemory; @@ -334,7 +334,7 @@ pub const Value = struct { field_index: usize, }; - pub async fn createArrayElemPtr( + pub fn createArrayElemPtr( comp: *Compilation, array_val: *Array, mut: Type.Pointer.Mut, @@ -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); @@ -390,13 +390,13 @@ pub const Value = struct { const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; const ptr_bit_count = ofile.comp.target_ptr_bits; const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; - const indices = [_]*llvm.Value{ + var indices = [_]*llvm.Value{ llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, }; return llvm.ConstInBoundsGEP( array_llvm_value, - &indices, + @ptrCast([*]*llvm.Value, &indices), @intCast(c_uint, indices.len), ) orelse return error.OutOfMemory; }, @@ -423,7 +423,7 @@ pub const Value = struct { }; /// Takes ownership of buffer - pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array { + pub fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array { const u8_type = Type.Int.get_u8(comp); defer u8_type.base.base.deref(comp);