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 zware-run to run wasm binaries from the command-line #231

Merged
merged 1 commit into from
Oct 20, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ pub fn build(b: *Build) !void {
const test_step = b.step("test", "Run all the tests");
test_step.dependOn(unittest_step);
test_step.dependOn(testsuite_step);

{
const exe = b.addExecutable(.{
.name = "zware-run",
.root_source_file = b.path("tools/zware-run/main.zig"),
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zware", zware_module);
const install = b.addInstallArtifact(exe, .{});
b.getInstallStep().dependOn(&install.step);
const run = b.addRunArtifact(exe);
run.step.dependOn(&install.step);
if (b.args) |args| {
run.addArgs(args);
}
b.step("run", "Run the cmdline runner zware-run").dependOn(&run.step);
}
}

fn addWast2Json(b: *Build) *Build.Step.Compile {
Expand Down
44 changes: 44 additions & 0 deletions src/error.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const std = @import("std");

const module = @import("module.zig");

/// A function can take a reference to this to pass extra error information to the caller.
/// A function that does this guarantees the reference will be populated if it returns error.SeeContext.
/// Error implements a format function.
/// The same error instance can be re-used for multiple calls.
///
/// Example usage:
/// ----
/// var zware_error: Error = undefined;
/// foo(&zware_error) catch |err| switch (err) {
/// error.SeeContext => std.log.err("foo failed: {}", .{zware_error}),
/// else => |err| return err,
/// };
/// ---
pub const Error = union(enum) {
missing_import: module.Import,
any: anyerror,

/// Called by a function that wants to both populate this error instance and let the caller
/// know it's been populated by returning error.SeeContext.
pub fn set(self: *Error, e: Error) error{SeeContext} {
self.* = e;
return error.SeeContext;
}
pub fn format(
self: Error,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = fmt;
_ = options;
switch (self) {
.missing_import => |import| try writer.print(
"missing {s} import '{s}' from module '{s}'",
.{ @tagName(import.desc_tag), import.name, import.module },
),
.any => |e| try writer.print("{s}", .{@errorName(e)}),
}
}
};
24 changes: 19 additions & 5 deletions src/instance.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const math = std.math;
const posix = std.posix;
const wasi = std.os.wasi;
const ArrayList = std.ArrayList;
const Error = @import("error.zig").Error;
const Module = @import("module.zig").Module;
const Store = @import("store.zig").ArrayListStore;
const Function = @import("store/function.zig").Function;
Expand Down Expand Up @@ -128,9 +129,20 @@ pub const Instance = struct {
}

pub fn instantiate(self: *Instance) !void {
var context: Error = undefined;
self.instantiateWithError(&context) catch |err| switch (err) {
error.SeeContext => switch (context) {
.missing_import => return error.ImportNotFound,
.any => |e| return e,
},
else => |e| return e,
};
}

pub fn instantiateWithError(self: *Instance, err: *Error) !void {
if (self.module.decoded == false) return error.ModuleNotDecoded;

try self.instantiateImports();
try self.instantiateImports(err);
try self.instantiateFunctions();
try self.instantiateGlobals();
try self.instantiateMemories();
Expand All @@ -143,9 +155,11 @@ pub const Instance = struct {
}
}

fn instantiateImports(self: *Instance) !void {
fn instantiateImports(self: *Instance, err: *Error) error{ OutOfMemory, SeeContext }!void {
for (self.module.imports.list.items) |import| {
const import_handle = try self.store.import(import.module, import.name, import.desc_tag);
const import_handle = self.store.import(import.module, import.name, import.desc_tag) catch |e| switch (e) {
error.ImportNotFound => return err.set(.{ .missing_import = import }),
};
switch (import.desc_tag) {
.Func => try self.funcaddrs.append(import_handle),
.Mem => try self.memaddrs.append(import_handle),
Expand Down Expand Up @@ -361,7 +375,7 @@ pub const Instance = struct {
},
.host_function => |host_func| {
var vm = VirtualMachine.init(op_stack[0..], frame_stack[0..], label_stack[0..], self);
try host_func.func(&vm);
try host_func.func(&vm, host_func.context);
},
}
}
Expand Down Expand Up @@ -404,7 +418,7 @@ pub const Instance = struct {
},
.host_function => |host_func| {
var vm = VirtualMachine.init(op_stack[0..], frame_stack[0..], label_stack[0..], self);
try host_func.func(&vm);
try host_func.func(&vm, host_func.context);
},
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/instance/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ pub const VirtualMachine = struct {
next_ip = f.start;
},
.host_function => |hf| {
try hf.func(self);
try hf.func(self, hf.context);
next_ip = ip + 1;
},
}
Expand Down Expand Up @@ -350,7 +350,7 @@ pub const VirtualMachine = struct {
next_ip = func.start;
},
.host_function => |host_func| {
try host_func.func(self);
try host_func.func(self, host_func.context);

next_ip = ip + 1;
},
Expand Down
2 changes: 2 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub const Error = @import("error.zig").Error;
pub const Module = @import("module.zig").Module;
pub const FuncType = @import("module.zig").FuncType;
pub const Instance = @import("instance.zig").Instance;
pub const VirtualMachine = @import("instance/vm.zig").VirtualMachine;
pub const WasmError = @import("instance/vm.zig").WasmError;
Expand Down
4 changes: 2 additions & 2 deletions src/module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub const Module = struct {
return count;
}

pub fn getExport(self: *Module, tag: Tag, name: []const u8) !usize {
pub fn getExport(self: *const Module, tag: Tag, name: []const u8) !usize {
for (self.exports.list.items) |exported| {
if (tag == exported.tag and mem.eql(u8, name, exported.name)) return exported.index;
}
Expand Down Expand Up @@ -841,7 +841,7 @@ fn Section(comptime T: type) type {
return self.list.items;
}

pub fn lookup(self: *Self, idx: anytype) !T {
pub fn lookup(self: *const Self, idx: anytype) !T {
const index = switch (@TypeOf(idx)) {
u32 => idx,
usize => math.cast(u32, idx) orelse return error.IndexTooLarge,
Expand Down
13 changes: 12 additions & 1 deletion src/store.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const Mutability = @import("module.zig").Mutability;
const RefType = @import("valtype.zig").RefType;
const ValType = @import("valtype.zig").ValType;
const Instance = @import("instance.zig").Instance;
const VirtualMachine = @import("instance/vm.zig").VirtualMachine;
const WasmError = @import("instance/vm.zig").WasmError;

// - Stores provide the runtime memory shared between modules
// - For different applications you may want to use a store that
Expand Down Expand Up @@ -188,13 +190,22 @@ pub const ArrayListStore = struct {

// Helper functions for exposing values

pub fn exposeHostFunction(self: *ArrayListStore, module: []const u8, function_name: []const u8, host_function_pointer: anytype, params: []const ValType, results: []const ValType) !void {
pub fn exposeHostFunction(
self: *ArrayListStore,
module: []const u8,
function_name: []const u8,
host_function_pointer: *const fn (*VirtualMachine, usize) WasmError!void,
host_function_context: usize,
params: []const ValType,
results: []const ValType,
) !void {
const funcaddr = try self.addFunction(Function{
.params = params,
.results = results,
.subtype = .{
.host_function = .{
.func = host_function_pointer,
.context = host_function_context,
},
},
});
Expand Down
3 changes: 2 additions & 1 deletion src/store/function.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ pub const Function = struct {
instance: *Instance,
},
host_function: struct {
func: *const fn (*VirtualMachine) WasmError!void,
func: *const fn (*VirtualMachine, usize) WasmError!void,
context: usize,
},
},

Expand Down
30 changes: 14 additions & 16 deletions test/testrunner/src/testrunner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,37 @@ const WasmError = zware.WasmError;

var gpa = GeneralPurposeAllocator(.{}){};

fn print(_: *VirtualMachine) WasmError!void {
fn print(_: *VirtualMachine, _: usize) WasmError!void {
std.debug.print("print\n", .{});
}

fn print_i32(vm: *VirtualMachine) WasmError!void {
fn print_i32(vm: *VirtualMachine, _: usize) WasmError!void {
const value = vm.popOperand(i32);
std.debug.print("print_i32: {}\n", .{value});
}

fn print_i64(vm: *VirtualMachine) WasmError!void {
fn print_i64(vm: *VirtualMachine, _: usize) WasmError!void {
const value = vm.popOperand(i64);
std.debug.print("print_i64: {}\n", .{value});
}

fn print_f32(vm: *VirtualMachine) WasmError!void {
fn print_f32(vm: *VirtualMachine, _: usize) WasmError!void {
const value = vm.popOperand(f32);
std.debug.print("print_f32: {}\n", .{value});
}

fn print_f64(vm: *VirtualMachine) WasmError!void {
fn print_f64(vm: *VirtualMachine, _: usize) WasmError!void {
const value = vm.popOperand(f64);
std.debug.print("print_f64: {}\n", .{value});
}

fn print_i32_f32(vm: *VirtualMachine) WasmError!void {
fn print_i32_f32(vm: *VirtualMachine, _: usize) WasmError!void {
const value_f32 = vm.popOperand(f32);
const value_i32 = vm.popOperand(i32);
std.debug.print("print_i32_f32: {}, {}\n", .{ value_i32, value_f32 });
}

fn print_f64_f64(vm: *VirtualMachine) WasmError!void {
fn print_f64_f64(vm: *VirtualMachine, _: usize) WasmError!void {
const value_f64_2 = vm.popOperand(f64);
const value_f64_1 = vm.popOperand(f64);
std.debug.print("print_f64_f64: {}, {}\n", .{ value_f64_1, value_f64_2 });
Expand Down Expand Up @@ -113,13 +113,13 @@ pub fn main() anyerror!void {
try store.exposeGlobal(spectest, "global_f64", 666, .F64, .Immutable);

// Expose host functions
try store.exposeHostFunction(spectest, "print", print, &[_]ValType{}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i32", print_i32, &[_]ValType{.I32}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i64", print_i64, &[_]ValType{.I64}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f32", print_f32, &[_]ValType{.F32}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f64", print_f64, &[_]ValType{.F64}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i32_f32", print_i32_f32, &[_]ValType{.I32, .F32}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f64_f64", print_f64_f64, &[_]ValType{.F64, .F64}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print", print, 0, &[_]ValType{}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i32", print_i32, 0, &[_]ValType{.I32}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i64", print_i64, 0, &[_]ValType{.I64}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f32", print_f32, 0, &[_]ValType{.F32}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f64", print_f64, 0, &[_]ValType{.F64}, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_i32_f32", print_i32_f32, 0, &[_]ValType{ .I32, .F32 }, &[_]ValType{});
try store.exposeHostFunction(spectest, "print_f64_f64", print_f64_f64, 0, &[_]ValType{ .F64, .F64 }, &[_]ValType{});

var current_instance: *Instance = undefined;
var registered_names = StringHashMap(*Instance).init(alloc);
Expand Down Expand Up @@ -893,7 +893,6 @@ const CommandRegister = struct {
as: []const u8,
};


const Action = union(enum) {
invoke: ActionInvoke,
get: ActionGet,
Expand Down Expand Up @@ -929,7 +928,6 @@ const ActionGet = struct {
module: ?[]const u8 = null,
};


const Value = struct {
type: []const u8,
value: []const u8,
Expand Down
Loading
Loading