Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for WASI reactor in pure Zig-exe. #9178

Merged
merged 6 commits into from Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/std/builtin.zig
Expand Up @@ -455,6 +455,13 @@ pub const LinkMode = enum {
Dynamic,
};

/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const WasiExecModel = enum {
command,
reactor,
};

/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Version = struct {
Expand Down
28 changes: 17 additions & 11 deletions lib/std/start.zig
Expand Up @@ -64,8 +64,9 @@ comptime {
}
} else if (native_os == .uefi) {
if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
} else if (native_arch.isWasm() and native_os == .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
} else if (native_arch.isWasm()) {
const wasm_start_sym = if (builtin.wasi_exec_model == .reactor) "_initialize" else "_start";
if (!@hasDecl(root, wasm_start_sym)) @export(wasm_start, .{ .name = wasm_start_sym });
} else if (native_os != .other and native_os != .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
}
Expand Down Expand Up @@ -134,10 +135,21 @@ fn _DllMainCRTStartup(
return std.os.windows.TRUE;
}

fn wasm_freestanding_start() callconv(.C) void {
// This is marked inline because for some reason LLVM in release mode fails to inline it,
fn wasm_start() callconv(.C) void {
// The entrypoint is marked inline because for some reason LLVM in release mode fails to inline it,
// and we want fewer call frames in stack traces.
_ = @call(.{ .modifier = .always_inline }, callMain, .{});
switch (native_os) {
.freestanding => {
_ = @call(.{ .modifier = .always_inline }, callMain, .{});
},
.wasi => {
switch (builtin.wasi_exec_model) {
.reactor => _ = @call(.{ .modifier = .always_inline }, callMain, .{}),
.command => std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})),
}
},
else => @compileError("unsupported OS"),
}
}

fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv(.C) usize {
Expand All @@ -163,12 +175,6 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
}

fn _start() callconv(.Naked) noreturn {
if (native_os == .wasi) {
// This is marked inline because for some reason LLVM in release mode fails to inline it,
// and we want fewer call frames in stack traces.
std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{}));
}

switch (native_arch) {
.x86_64 => {
argc_argv_ptr = asm volatile (
Expand Down
17 changes: 14 additions & 3 deletions src/Compilation.zig
Expand Up @@ -724,7 +724,7 @@ pub const InitOptions = struct {
test_name_prefix: ?[]const u8 = null,
subsystem: ?std.Target.SubSystem = null,
/// WASI-only. Type of WASI execution model ("command" or "reactor").
wasi_exec_model: ?wasi_libc.CRTFile = null,
mathetake marked this conversation as resolved.
Show resolved Hide resolved
wasi_exec_model: ?std.builtin.WasiExecModel = null,
};

fn addPackageTableToCacheHash(
Expand Down Expand Up @@ -787,6 +787,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {

const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib;

// WASI-only. Resolve the optinal exec-model option, defaults to command.
const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command;

const comp: *Compilation = comp: {
// For allocations that have the same lifetime as Compilation. This arena is used only during this
// initialization and then is freed in deinit().
Expand Down Expand Up @@ -1344,7 +1347,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.disable_lld_caching = options.disable_lld_caching,
.subsystem = options.subsystem,
.is_test = options.is_test,
.wasi_exec_model = options.wasi_exec_model,
.wasi_exec_model = wasi_exec_model,
});
errdefer bin_file.destroy();
comp.* = .{
Expand Down Expand Up @@ -1446,7 +1449,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
});
}
comp.work_queue.writeAssumeCapacity(&[_]Job{
.{ .wasi_libc_crt_file = comp.bin_file.options.wasi_exec_model orelse .crt1_o },
.{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) },
.{ .wasi_libc_crt_file = .libc_a },
});
}
Expand Down Expand Up @@ -3638,6 +3641,14 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)),
});

if (target.os.tag == .wasi) {
const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model));
try buffer.writer().print(
\\pub const wasi_exec_model = std.builtin.WasiExecModel.{};
\\
, .{wasi_exec_model_fmt});
}

if (comp.bin_file.options.is_test) {
try buffer.appendSlice(
\\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later
Expand Down
2 changes: 1 addition & 1 deletion src/link.zig
Expand Up @@ -119,7 +119,7 @@ pub const Options = struct {
libc_installation: ?*const LibCInstallation,

/// WASI-only. Type of WASI execution model ("command" or "reactor").
wasi_exec_model: ?wasi_libc.CRTFile = null,
wasi_exec_model: std.builtin.WasiExecModel = undefined,

pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
return if (options.use_lld) .Obj else options.output_mode;
Expand Down
13 changes: 9 additions & 4 deletions src/link/Wasm.zig
Expand Up @@ -682,10 +682,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
// before corrupting globals. See https://github.com/ziglang/zig/issues/4496
try argv.append("--stack-first");

// Reactor execution model does not have _start so lld doesn't look for it.
if (self.base.options.wasi_exec_model) |exec_model| blk: {
if (exec_model != .crt1_reactor_o) break :blk;
if (self.base.options.wasi_exec_model == .reactor) {
// Reactor execution model does not have _start so lld doesn't look for it.
try argv.append("--no-entry");
// Make sure "_initialize" is exported even if this is pure Zig WASI reactor
// where WASM_SYMBOL_EXPORTED flag in LLVM is not set on _initialize.
try argv.appendSlice(&[_][]const u8{
"--export",
"_initialize",
});
}
} else {
try argv.append("--no-entry"); // So lld doesn't look for _start.
Expand All @@ -712,7 +717,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
if (self.base.options.link_libc) {
try argv.append(try comp.get_libc_crt_file(
arena,
wasi_libc.crtFileFullName(self.base.options.wasi_exec_model orelse .crt1_o),
wasi_libc.execModelCrtFileFullName(self.base.options.wasi_exec_model),
));
try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
}
Expand Down
15 changes: 9 additions & 6 deletions src/main.zig
Expand Up @@ -321,6 +321,7 @@ const usage_build_generic =
\\ medium|large]
\\ -mred-zone Force-enable the "red-zone"
\\ -mno-red-zone Force-disable the "red-zone"
\\ -mexec-model=[value] Execution model (WASI only)
\\ --name [name] Override root name (not a file path)
\\ -O [mode] Choose what to optimize for
\\ Debug (default) Optimizations off, safety on
Expand Down Expand Up @@ -616,7 +617,7 @@ fn buildOutputType(
var subsystem: ?std.Target.SubSystem = null;
var major_subsystem_version: ?u32 = null;
var minor_subsystem_version: ?u32 = null;
var wasi_exec_model: ?wasi_libc.CRTFile = null;
var wasi_exec_model: ?std.builtin.WasiExecModel = null;

var system_libs = std.ArrayList([]const u8).init(gpa);
defer system_libs.deinit();
Expand Down Expand Up @@ -1065,6 +1066,10 @@ fn buildOutputType(
mem.startsWith(u8, arg, "-I"))
{
try clang_argv.append(arg);
} else if (mem.startsWith(u8, arg, "-mexec-model=")) {
wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse {
fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]});
};
} else {
fatal("unrecognized parameter: '{s}'", .{arg});
}
Expand Down Expand Up @@ -1271,11 +1276,9 @@ fn buildOutputType(
.nostdlibinc => want_native_include_dirs = false,
.strip => strip = true,
.exec_model => {
if (std.mem.eql(u8, it.only_arg, "reactor")) {
wasi_exec_model = .crt1_reactor_o;
} else if (std.mem.eql(u8, it.only_arg, "command")) {
wasi_exec_model = .crt1_command_o;
}
wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, it.only_arg) orelse {
fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg});
};
},
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/wasi_libc.zig
Expand Up @@ -45,9 +45,15 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
};
}

pub fn crtFileFullName(crt_file: CRTFile) []const u8 {
return switch (crt_file) {
.crt1_o => "crt1.o",
pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile {
return switch (wasi_exec_model) {
.reactor => CRTFile.crt1_reactor_o,
.command => CRTFile.crt1_command_o,
};
}

pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 {
return switch (execModelCrtFile(wasi_exec_model)) {
.crt1_reactor_o => "crt1-reactor.o",
.crt1_command_o => "crt1-command.o",
else => unreachable,
Expand Down