diff --git a/.gitignore b/.gitignore index 1694882f..9fd2026d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ zig-cache .zig-cache +zig-pkg zig-out test/testrunner/bin \ No newline at end of file diff --git a/build.zig b/build.zig index 8d58a9f5..de4653fa 100644 --- a/build.zig +++ b/build.zig @@ -1,28 +1,24 @@ -const Build = @import("std").Build; +const std = @import("std"); +const Build = std.Build; pub fn build(b: *Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const zware_module = b.createModule(.{ - .root_source_file = b.path("src/main.zig"), - }); - - try b.modules.put(b.dupe("zware"), zware_module); - - const main_mod = b.addModule("zware", .{ + const zware = b.addModule("zware", .{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); + const lib = b.addLibrary(.{ .name = "zware", - .root_module = main_mod, + .root_module = zware, }); b.installArtifact(lib); const main_tests = b.addTest(.{ - .root_module = main_mod, + .root_module = zware, .use_llvm = true, }); @@ -41,7 +37,7 @@ pub fn build(b: *Build) !void { }), .use_llvm = true, }); - testrunner.root_module.addImport("zware", zware_module); + testrunner.root_module.addImport("zware", zware); const testsuite_dep = b.dependency("testsuite", .{}); @@ -53,6 +49,7 @@ pub fn build(b: *Build) !void { const json_file = run_wast2json.addOutputFileArg(b.fmt("{s}.json", .{test_name})); const run_test = b.addRunArtifact(testrunner); + run_test.setName(b.fmt("run test-{s}", .{test_name})); run_test.addFileArg(json_file); run_test.cwd = json_file.dirname(); const step = b.step(b.fmt("test-{s}", .{test_name}), b.fmt("Run the '{s}' test", .{test_name})); @@ -74,14 +71,12 @@ pub fn build(b: *Build) !void { }), .use_llvm = true, }); - exe.root_module.addImport("zware", zware_module); + exe.root_module.addImport("zware", zware); 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); - } + passthroughArgs(b, run); b.step("run", "Run the cmdline runner zware-run").dependOn(&run.step); } @@ -94,14 +89,12 @@ pub fn build(b: *Build) !void { .optimize = optimize, }), }); - exe.root_module.addImport("zware", zware_module); + exe.root_module.addImport("zware", zware); 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); - } + passthroughArgs(b, run); b.step("gen", "Run the cmdline runner zware-gen").dependOn(&run.step); } } @@ -127,35 +120,38 @@ fn addWast2Json(b: *Build) *Build.Step.Compile { .SIZEOF_SIZE_T = @sizeOf(usize), }); - const wabt_lib = b.addLibrary(.{ - .name = "wabt", - .root_module = b.createModule(.{ - .target = b.graph.host, - .optimize = .Debug, - }), + const wabt_mod = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .link_libcpp = true, }); - wabt_lib.addConfigHeader(wabt_config_h); - wabt_lib.addIncludePath(wabt_dep.path("include")); - wabt_lib.addCSourceFiles(.{ + wabt_mod.addConfigHeader(wabt_config_h); + wabt_mod.addIncludePath(wabt_dep.path("include")); + wabt_mod.addCSourceFiles(.{ .root = wabt_dep.path("."), .files = &wabt_files, }); - wabt_lib.linkLibCpp(); - const wast2json = b.addExecutable(.{ - .name = "wast2json", - .root_module = b.createModule(.{ - .target = b.graph.host, - }), + const wabt_lib = b.addLibrary(.{ + .name = "wabt", + .root_module = wabt_mod, }); + + const wast2json = b.createModule(.{ + .target = b.graph.host, + .link_libcpp = true, + }); + wast2json.addConfigHeader(wabt_config_h); wast2json.addIncludePath(wabt_dep.path("include")); wast2json.addCSourceFile(.{ .file = wabt_dep.path("src/tools/wast2json.cc"), }); - wast2json.linkLibCpp(); wast2json.linkLibrary(wabt_lib); - return wast2json; + return b.addExecutable(.{ + .name = "wast2json", + .root_module = wast2json, + }); } const test_names = [_][]const u8{ @@ -282,3 +278,14 @@ const wabt_files = [_][]const u8{ "src/wast-lexer.cc", "src/wast-parser.cc", }; + +// zig 0.17.0 and 0.16.0 compatible args passthrough function +inline fn passthroughArgs(b: *Build, run: *Build.Step.Run) void { + if (comptime @import("builtin").zig_version.order(std.SemanticVersion.parse("0.16.0") catch unreachable) == .gt) { + run.addPassthruArgs(); + } else { + if (b.args) |args| { + for (args) |arg| run.addArg(arg); + } + } +} diff --git a/build.zig.zon b/build.zig.zon index 248ba622..db560f91 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,7 +2,7 @@ .name = .zware, .version = "0.0.1", .fingerprint = 0xea6cb8e2e9e30e64, - .minimum_zig_version = "0.15.2", + .minimum_zig_version = "0.16.0", .dependencies = .{ .wabt = .{ .url = "https://github.com/WebAssembly/wabt/archive/39f85a791cbbad91a253a851841a29777efdc2cd.tar.gz", diff --git a/examples/fib/build.zig b/examples/fib/build.zig index d5145bd9..3007cbda 100644 --- a/examples/fib/build.zig +++ b/examples/fib/build.zig @@ -1,4 +1,5 @@ -const Build = @import("std").Build; +const std = @import("std"); +const Build = std.Build; pub fn build(b: *Build) void { const target = b.standardTargetOptions(.{}); @@ -20,10 +21,19 @@ pub fn build(b: *Build) void { const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| { - run_cmd.addArgs(args); - } + passthroughArgs(b, run_cmd); const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); } + +// zig 0.17.0 and 0.16.0 compatible args passthrough function +inline fn passthroughArgs(b: *Build, run: *Build.Step.Run) void { + if (comptime @import("builtin").zig_version.order(std.SemanticVersion.parse("0.16.0") catch unreachable) == .gt) { + run.addPassthruArgs(); + } else { + if (b.args) |args| { + for (args) |arg| run.addArg(arg); + } + } +} diff --git a/examples/fib/src/fib.zig b/examples/fib/src/fib.zig index f2db15fd..682d2137 100644 --- a/examples/fib/src/fib.zig +++ b/examples/fib/src/fib.zig @@ -3,12 +3,9 @@ const zware = @import("zware"); const Store = zware.Store; const Module = zware.Module; const Instance = zware.Instance; -const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator; -var gpa = GeneralPurposeAllocator(.{}){}; -pub fn main() !void { - defer _ = gpa.deinit(); - const alloc = gpa.allocator(); +pub fn main(init: std.process.Init) !void { + const alloc = init.gpa; const bytes = @embedFile("fib.wasm"); diff --git a/src/instance.zig b/src/instance.zig index 5f739f8a..f77aae14 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -75,7 +75,7 @@ pub const Instance = struct { .wasi_preopens = .empty, .wasi_args = .empty, - .wasi_env = .{}, + .wasi_env = .empty, }; } @@ -323,9 +323,9 @@ pub const Instance = struct { const function = try self.getFunc(funcidx); - var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = [_]VirtualMachine.Frame{undefined} ** options.frame_stack_size; - var label_stack: [options.label_stack_size]VirtualMachine.Label = [_]VirtualMachine.Label{undefined} ** options.label_stack_size; - var op_stack: [options.operand_stack_size]u64 = [_]u64{0} ** options.operand_stack_size; + var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = @splat(undefined); + var label_stack: [options.label_stack_size]VirtualMachine.Label = @splat(undefined); + var op_stack: [options.operand_stack_size]u64 = @splat(0); switch (function.subtype) { .function => |f| { @@ -386,9 +386,9 @@ pub const Instance = struct { pub fn invokeStart(self: *Instance, index: u32, comptime options: VirtualMachineOptions) !void { const function = try self.getFunc(index); - var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = [_]VirtualMachine.Frame{undefined} ** options.frame_stack_size; - var label_stack: [options.label_stack_size]VirtualMachine.Label = [_]VirtualMachine.Label{undefined} ** options.label_stack_size; - var op_stack: [options.operand_stack_size]u64 = [_]u64{0} ** options.operand_stack_size; + var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = @splat(undefined); + var label_stack: [options.label_stack_size]VirtualMachine.Label = @splat(undefined); + var op_stack: [options.operand_stack_size]u64 = @splat(0); switch (function.subtype) { .function => |f| { @@ -427,9 +427,9 @@ pub const Instance = struct { } pub fn invokeExpression(self: *Instance, start: usize, comptime Result: type, comptime options: VirtualMachineOptions) !Result { - var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = [_]VirtualMachine.Frame{undefined} ** options.frame_stack_size; - var label_stack: [options.label_stack_size]VirtualMachine.Label = [_]VirtualMachine.Label{undefined} ** options.label_stack_size; - var op_stack: [options.operand_stack_size]u64 = [_]u64{0} ** options.operand_stack_size; + var frame_stack: [options.frame_stack_size]VirtualMachine.Frame = @splat(undefined); + var label_stack: [options.label_stack_size]VirtualMachine.Label = @splat(undefined); + var op_stack: [options.operand_stack_size]u64 = @splat(0); var vm = VirtualMachine.init(op_stack[0..], frame_stack[0..], label_stack[0..], self); diff --git a/src/instance/vm.zig b/src/instance/vm.zig index 4286d544..08b4face 100644 --- a/src/instance/vm.zig +++ b/src/instance/vm.zig @@ -2682,9 +2682,9 @@ pub const WasmError = error{ const testing = std.testing; test "operand push / pop test" { - var op_stack: [6]u64 = [_]u64{0} ** 6; - var frame_stack_mem: [1024]VirtualMachine.Frame = [_]VirtualMachine.Frame{undefined} ** 1024; - var label_stack_mem: [1024]VirtualMachine.Label = [_]VirtualMachine.Label{undefined} ** 1024; + var op_stack: [6]u64 = @splat(0); + var frame_stack_mem: [1024]VirtualMachine.Frame = @splat(undefined); + var label_stack_mem: [1024]VirtualMachine.Label = @splat(undefined); var inst: Instance = undefined; diff --git a/src/module.zig b/src/module.zig index fd91bb19..ad5ac795 100644 --- a/src/module.zig +++ b/src/module.zig @@ -83,14 +83,14 @@ pub const Module = struct { pub fn decode(self: *Module) !void { if (self.decoded) return error.AlreadyDecoded; var decoder = Decoder{ - .fbs = .{ .pos = 0, .buffer = self.wasm_bin }, + .rd = .fixed(self.wasm_bin), }; - const rd = decoder.fbs.reader(); + const rd = &decoder.rd; - const magic = try rd.readBytesNoEof(4); + const magic = try rd.take(4); if (!mem.eql(u8, magic[0..], "\x00asm")) return error.MagicNumberNotFound; - const version = try rd.readInt(u32, .little); + const version = try rd.takeInt(u32, .little); if (version != 1) return error.UnknownBinaryVersion; // FIXME: in hindsight I don't like this: @@ -148,17 +148,17 @@ pub const Module = struct { }; pub const Decoder = struct { - fbs: std.Io.FixedBufferStream([]const u8), + rd: std.Io.Reader, pub fn decodeSection(self: *Decoder, module: *Module) !void { - const id: SectionType = self.readEnum(SectionType) catch |err| switch (err) { + const id: SectionType = self.takeEnum(SectionType) catch |err| switch (err) { error.EndOfStream => return error.WasmFileEnd, else => return err, }; - const size = try self.readLEB128(u32); + const size = try self.takeLeb128(u32); - const section_start = self.fbs.pos; + const section_start = self.rd.seek; switch (id) { .Custom => try self.decodeCustomSection(module, size), @@ -176,38 +176,38 @@ pub const Decoder = struct { .DataCount => try self.decodeDataCountSection(module, size), } - const section_end = self.fbs.pos; + const section_end = self.rd.seek; if (section_end - section_start != size) return error.MalformedSectionMismatchedSize; } fn decodeTypeSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.types.count = count; var f: usize = 0; while (f < count) : (f += 1) { - const tag = try self.readByte(); + const tag = try self.takeByte(); if (tag != 0x60) return error.ExpectedFuncTypeTag; - const param_count = try self.readLEB128(u32); - const params_start = self.fbs.pos; + const param_count = try self.takeLeb128(u32); + const params_start = self.rd.seek; { var i: usize = 0; while (i < param_count) : (i += 1) { - _ = try self.readEnum(ValType); + _ = try self.takeEnum(ValType); } } - const params_end = self.fbs.pos; + const params_end = self.rd.seek; - const results_count = try self.readLEB128(u32); - const results_start = self.fbs.pos; + const results_count = try self.takeLeb128(u32); + const results_start = self.rd.seek; { var i: usize = 0; while (i < results_count) : (i += 1) { - _ = try self.readEnum(ValType); + _ = try self.takeEnum(ValType); } } - const results_end = self.fbs.pos; + const results_end = self.rd.seek; const params = module.wasm_bin[params_start..params_end]; const results = module.wasm_bin[results_start..results_end]; @@ -228,22 +228,22 @@ pub const Decoder = struct { } fn decodeImportSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.imports.count = count; var i: usize = 0; while (i < count) : (i += 1) { - const module_name_length = try self.readLEB128(u32); - const module_name = try self.readSlice(module_name_length); + const module_name_length = try self.takeLeb128(u32); + const module_name = try self.takeSlice(module_name_length); if (!unicode.utf8ValidateSlice(module_name)) return error.NameNotUTF8; - const name_length = try self.readLEB128(u32); - const name = try self.readSlice(name_length); + const name_length = try self.takeLeb128(u32); + const name = try self.takeSlice(name_length); if (!unicode.utf8ValidateSlice(name)) return error.NameNotUTF8; - const tag = try self.readEnum(Tag); + const tag = try self.takeEnum(Tag); if (i > math.maxInt(u32)) return error.ExpectedU32Index; const import_index: u32 = @truncate(i); @@ -263,7 +263,7 @@ pub const Decoder = struct { } fn decodeFunctionSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.functions.count = count; var i: usize = 0; @@ -273,7 +273,7 @@ pub const Decoder = struct { } fn decodeFunction(self: *Decoder, module: *Module, import: ?u32) !void { - const typeidx = try self.readLEB128(u32); + const typeidx = try self.takeLeb128(u32); if (typeidx >= module.types.list.items.len) return error.ValidatorInvalidTypeIndex; @@ -288,7 +288,7 @@ pub const Decoder = struct { } fn decodeTableSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.tables.count = count; var i: usize = 0; @@ -298,14 +298,14 @@ pub const Decoder = struct { } fn decodeTable(self: *Decoder, module: *Module, import: ?u32) !void { - const reftype = try self.readEnum(RefType); - const limit_type = try self.readEnum(LimitType); - const min = try self.readLEB128(u32); + const reftype = try self.takeEnum(RefType); + const limit_type = try self.takeEnum(LimitType); + const min = try self.takeLeb128(u32); const max: ?u32 = blk: { switch (limit_type) { .Min => break :blk null, .MinMax => { - const max = try self.readLEB128(u32); + const max = try self.takeLeb128(u32); if (min > max) return error.ValidatorTableMinGreaterThanMax; break :blk max; }, @@ -322,7 +322,7 @@ pub const Decoder = struct { } fn decodeMemorySection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.memories.count = count; var i: usize = 0; @@ -334,14 +334,14 @@ pub const Decoder = struct { fn decodeMemory(self: *Decoder, module: *Module, import: ?u32) !void { if (module.memories.list.items.len > 0) return error.ValidatorMultipleMemories; - const limit_type = try self.readEnum(LimitType); - const min = try self.readLEB128(u32); + const limit_type = try self.takeEnum(LimitType); + const min = try self.takeLeb128(u32); if (min > 65536) return error.ValidatorMemoryMinTooLarge; const max: ?u32 = blk: { switch (limit_type) { .Min => break :blk null, .MinMax => { - const max = try self.readLEB128(u32); + const max = try self.takeLeb128(u32); if (min > max) return error.ValidatorMemoryMinGreaterThanMax; if (max > 65536) return error.ValidatorMemoryMaxTooLarge; break :blk max; @@ -358,7 +358,7 @@ pub const Decoder = struct { } fn decodeGlobalSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.globals.count = count; var i: usize = 0; @@ -368,8 +368,8 @@ pub const Decoder = struct { } fn decodeGlobal(self: *Decoder, module: *Module, import: ?u32) !void { - const global_type = try self.readEnum(ValType); - const mutability = try self.readEnum(Mutability); + const global_type = try self.takeEnum(ValType); + const mutability = try self.takeEnum(Mutability); var parsed_code: ?Parsed = null; @@ -391,13 +391,13 @@ pub const Decoder = struct { } fn decodeExportSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.exports.count = count; var i: usize = 0; while (i < count) : (i += 1) { - const name_length = try self.readLEB128(u32); - const name = try self.readSlice(name_length); + const name_length = try self.takeLeb128(u32); + const name = try self.takeSlice(name_length); if (!unicode.utf8ValidateSlice(name)) return error.NameNotUTF8; @@ -405,8 +405,8 @@ pub const Decoder = struct { if (mem.eql(u8, name, exprt.name)) return error.ValidatorDuplicateExportName; } - const tag = try self.readEnum(Tag); - const index = try self.readLEB128(u32); + const tag = try self.takeEnum(Tag); + const index = try self.takeLeb128(u32); switch (tag) { .Func => { @@ -429,7 +429,7 @@ pub const Decoder = struct { fn decodeStartSection(self: *Decoder, module: *Module) !void { if (module.start != null) return error.MultipleStartSections; - const funcidx = try self.readLEB128(u32); + const funcidx = try self.takeLeb128(u32); const func = try module.functions.lookup(funcidx); const functype = try module.types.lookup(func.typeidx); @@ -439,12 +439,12 @@ pub const Decoder = struct { } fn decodeElementSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.elements.count = count; var i: usize = 0; while (i < count) : (i += 1) { - const elem_type = try self.readLEB128(u32); + const elem_type = try self.takeLeb128(u32); switch (elem_type) { 0 => { @@ -453,13 +453,13 @@ pub const Decoder = struct { const parsed_offset_code = try self.readConstantExpression(module, .I32); - const data_length = try self.readLEB128(u32); + const data_length = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; var j: usize = 0; while (j < data_length) : (j += 1) { - const funcidx = try self.readLEB128(u32); + const funcidx = try self.takeLeb128(u32); if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; @@ -482,15 +482,15 @@ pub const Decoder = struct { }); }, 1 => { - _ = try self.readEnum(ElemKind); + _ = try self.takeEnum(ElemKind); - const data_length = try self.readLEB128(u32); + const data_length = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; var j: usize = 0; while (j < data_length) : (j += 1) { - const funcidx = try self.readLEB128(u32); + const funcidx = try self.takeLeb128(u32); if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; @@ -510,20 +510,20 @@ pub const Decoder = struct { }); }, 2 => { - const tableidx = try self.readLEB128(u32); + const tableidx = try self.takeLeb128(u32); if (tableidx >= module.tables.list.items.len) return error.ValidatorElemUnknownTable; const parsed_offset_code = try self.readConstantExpression(module, .I32); - _ = try self.readEnum(ElemKind); - const data_length = try self.readLEB128(u32); + _ = try self.takeEnum(ElemKind); + const data_length = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; var j: usize = 0; while (j < data_length) : (j += 1) { - const funcidx = try self.readLEB128(u32); + const funcidx = try self.takeLeb128(u32); if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; @@ -546,14 +546,14 @@ pub const Decoder = struct { }); }, 3 => { - _ = try self.readEnum(ElemKind); - const data_length = try self.readLEB128(u32); + _ = try self.takeEnum(ElemKind); + const data_length = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; var j: usize = 0; while (j < data_length) : (j += 1) { - const funcidx = try self.readLEB128(u32); + const funcidx = try self.takeLeb128(u32); if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; @@ -578,7 +578,7 @@ pub const Decoder = struct { const parsed_offset_code = try self.readConstantExpression(module, .I32); - const init_expression_count = try self.readLEB128(u32); + const init_expression_count = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; @@ -599,8 +599,8 @@ pub const Decoder = struct { }); }, 5 => { // Passive - const reftype = try self.readEnum(RefType); - const expr_count = try self.readLEB128(u32); + const reftype = try self.takeEnum(RefType); + const expr_count = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; @@ -619,8 +619,8 @@ pub const Decoder = struct { }); }, 7 => { // Declarative - const reftype = try self.readEnum(RefType); - const expr_count = try self.readLEB128(u32); + const reftype = try self.takeEnum(RefType); + const expr_count = try self.takeLeb128(u32); const first_init_offset = module.element_init_offsets.items.len; @@ -646,11 +646,11 @@ pub const Decoder = struct { fn decodeDataCountSection(self: *Decoder, module: *Module, size: u32) !void { if (size == 0) return; - module.data_count = try self.readLEB128(u32); + module.data_count = try self.takeLeb128(u32); } fn decodeCodeSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); module.codes.count = count; try module.parsed_code.ensureTotalCapacity(module.alloc, count * 32); @@ -662,9 +662,9 @@ pub const Decoder = struct { var i: usize = 0; while (i < count) : (i += 1) { // size: the number of bytes defining the function, includes bytes defining locals - _ = try self.readLEB128(u32); + _ = try self.takeLeb128(u32); - const locals_definitions_count = try self.readLEB128(u32); + const locals_definitions_count = try self.takeLeb128(u32); const locals_start = module.local_types.items.len; @@ -672,8 +672,8 @@ pub const Decoder = struct { var j: usize = 0; var locals_count: usize = 0; while (j < locals_definitions_count) : (j += 1) { - const type_count = try self.readLEB128(u32); - const local_type = try self.readEnum(ValType); + const type_count = try self.takeLeb128(u32); + const local_type = try self.takeEnum(ValType); locals_count += type_count; try module.local_types.append(module.alloc, .{ .count = type_count, .valtype = local_type }); @@ -694,7 +694,7 @@ pub const Decoder = struct { } fn decodeDataSection(self: *Decoder, module: *Module) !void { - const count = try self.readLEB128(u32); + const count = try self.takeLeb128(u32); if (module.data_count) |data_count| { if (count != data_count) return error.DataCountSectionDataSectionCountMismatch; @@ -704,7 +704,7 @@ pub const Decoder = struct { var i: usize = 0; while (i < count) : (i += 1) { - const data_section_type = try self.readLEB128(u32); + const data_section_type = try self.takeLeb128(u32); switch (data_section_type) { 0 => { @@ -714,8 +714,8 @@ pub const Decoder = struct { const parsed_code = try self.readConstantExpression(module, .I32); - const data_length = try self.readLEB128(u32); - const data = try self.readSlice(data_length); + const data_length = try self.takeLeb128(u32); + const data = try self.takeSlice(data_length); try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, @@ -727,8 +727,8 @@ pub const Decoder = struct { }); }, 1 => { - const data_length = try self.readLEB128(u32); - const data = try self.readSlice(data_length); + const data_length = try self.takeLeb128(u32); + const data = try self.takeSlice(data_length); try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, @@ -737,14 +737,14 @@ pub const Decoder = struct { }); }, 2 => { - const memidx = try self.readLEB128(u32); + const memidx = try self.takeLeb128(u32); if (memidx >= module.memories.list.items.len) return error.ValidatorDataMemoryReferenceInvalid; const parsed_code = try self.readConstantExpression(module, .I32); - const data_length = try self.readLEB128(u32); - const data = try self.readSlice(data_length); + const data_length = try self.takeLeb128(u32); + const data = try self.takeSlice(data_length); try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, @@ -763,15 +763,15 @@ pub const Decoder = struct { } fn decodeCustomSection(self: *Decoder, module: *Module, size: u32) !void { - const offset = self.fbs.pos; + const offset = self.rd.seek; - const name_length = try self.readLEB128(u32); - const name = try self.readSlice(name_length); + const name_length = try self.takeLeb128(u32); + const name = try self.takeSlice(name_length); if (!unicode.utf8ValidateSlice(name)) return error.NameNotUTF8; - const data_length = try math.sub(usize, size, (self.fbs.pos - offset)); - const data = try self.readSlice(data_length); + const data_length = try math.sub(usize, size, (self.rd.seek - offset)); + const data = try self.takeSlice(data_length); try module.customs.list.append(module.alloc, Custom{ .name = name, @@ -780,8 +780,8 @@ pub const Decoder = struct { } pub fn readConstantExpression(self: *Decoder, module: *Module, valtype: ValType) !Parsed { - const rd = self.fbs.reader(); - const code = module.wasm_bin[rd.context.pos..]; + const rd = self.rd; + const code = module.wasm_bin[rd.seek..]; var parser = Parser.init(module, self); defer parser.deinit(); @@ -790,7 +790,7 @@ pub const Decoder = struct { } pub fn readFunction(self: *Decoder, module: *Module, locals: []LocalType, funcidx: usize) !Parsed { - const code = module.wasm_bin[self.fbs.pos..]; + const code = module.wasm_bin[self.rd.seek..]; var parser = Parser.init(module, self); defer parser.deinit(); @@ -798,29 +798,46 @@ pub const Decoder = struct { return parser.parseFunction(funcidx, locals, code); } - fn readByte(self: *Decoder) !u8 { - return self.fbs.reader().readByte(); + fn takeByte(self: *Decoder) !u8 { + return self.rd.takeByte(); } - fn readEnum(self: *Decoder, comptime T: type) !T { - return self.fbs.reader().readEnum(T, .little); + fn takeEnum(self: *Decoder, comptime T: type) !T { + return self.rd.takeEnum(T, .little); } - fn readLEB128(self: *Decoder, comptime T: type) !T { - const readFn = switch (@typeInfo(T).int.signedness) { - .signed => std.leb.readILEB128, - .unsigned => std.leb.readUleb128, - }; - return readFn(T, self.fbs.reader()); + fn takeLeb128(self: *Decoder, comptime T: type) !T { + return takeLeb128Exact(&self.rd, T); + } + + pub fn takeSlice(self: *Decoder, count: usize) ![]const u8 { + return self.rd.take(count); } - pub fn readSlice(self: *Decoder, count: usize) ![]const u8 { - const start = self.fbs.pos; - const end = self.fbs.pos + count; - if (end > self.fbs.buffer.len) - return error.EndOfStream; - self.fbs.pos = end; - return self.fbs.buffer[start..self.fbs.pos]; + /// a wrapper around `std.Io.Reader.takeLeb128` that checks + /// that at most 8/7 times the integer size rounded up bytes are consumed, + /// which is the maximum number of bytes any leb128 should need. + /// the webassembly testsuite expects the decoder to error + /// on such "overlong" values with "integer representation tool long" + pub inline fn takeLeb128Exact(rd: *std.Io.Reader, comptime T: type) !T { + const leb_size = comptime std.math.divCeil(usize, @sizeOf(T) * 8, 7) catch unreachable; + // we need to prevent rebasing during takeLeb128 call, + // so fill ensure we have the leb_size buffered + rd.fill(leb_size) catch |err| { + switch (err) { + error.EndOfStream => {}, + error.ReadFailed => return err, + } + }; + const seek_pre = rd.seek; + const value = try rd.takeLeb128(T); + const rd_was_rebased = seek_pre > rd.seek; + if (rd_was_rebased or (rd.seek - seek_pre) > leb_size) { + // the leb128 representation is bigger than 8/7 of the requested + // integer size which is bigger than necessary + return error.InvalidValue; + } + return value; } }; diff --git a/src/module/parser.zig b/src/module/parser.zig index e906efdf..34aaa36c 100644 --- a/src/module/parser.zig +++ b/src/module/parser.zig @@ -29,7 +29,7 @@ pub const Parser = struct { validator: Validator = undefined, params: ?[]const ValType, locals: ?[]LocalType, - continuation_stack: [1024]usize = [_]usize{0} ** 1024, + continuation_stack: [1024]usize = @splat(0), continuation_stack_ptr: usize, is_constant: bool = false, scope: usize, @@ -65,7 +65,7 @@ pub const Parser = struct { } const bytes_read = self.bytesRead(); - _ = try self.decoder.readSlice(bytes_read); + _ = try self.decoder.takeSlice(bytes_read); // Patch last end so that it is return self.module.parsed_code.items[self.module.parsed_code.items.len - 1] = .@"return"; @@ -81,8 +81,8 @@ pub const Parser = struct { self.code = code; const code_start = self.module.parsed_code.items.len; - const in: [0]ValType = [_]ValType{} ** 0; - const out: [1]ValType = [_]ValType{valtype} ** 1; + const in: [0]ValType = .{}; + const out: [1]ValType = @splat(valtype); try self.validator.pushControlFrame( .block, @@ -107,7 +107,7 @@ pub const Parser = struct { } const bytes_read = self.bytesRead(); - _ = try self.decoder.readSlice(bytes_read); + _ = try self.decoder.takeSlice(bytes_read); // Patch last end so that it is return self.module.parsed_code.items[self.module.parsed_code.items.len - 1] = .@"return"; @@ -160,8 +160,11 @@ pub const Parser = struct { if (self.code.len == 0) return null; if (self.scope == 0) return null; - // 1. Get the instruction we're going to return and increment code - const instr = std.meta.intToEnum(Opcode, self.code[0]) catch return error.IllegalOpcode; + // 1. Get the instruction we're going to return and increment + const instr = std.enums.fromInt( + Opcode, + self.code[0], + ) orelse return error.IllegalOpcode; self.code = self.code[1..]; var rr: Rr = undefined; @@ -398,7 +401,10 @@ pub const Parser = struct { const type_count = try self.readLEB128Mem(u32); if (type_count != 1) return error.OnlyOneSelectTTypeSupported; // Future versions may support more than one const valuetype_raw = try self.readLEB128Mem(u32); - const valuetype = try std.meta.intToEnum(ValType, valuetype_raw); + const valuetype = std.enums.fromInt( + ValType, + valuetype_raw, + ) orelse return error.InvalidValue; try self.validator.validateSelectT(valuetype); @@ -1016,7 +1022,10 @@ pub const Parser = struct { .@"i64.extend32_s" => rr = Rr.@"i64.extend32_s", .@"ref.null" => { const rtype = try self.readLEB128Mem(u32); - const reftype = std.meta.intToEnum(RefType, rtype) catch return error.MalformedRefType; + const reftype = std.enums.fromInt( + RefType, + rtype, + ) orelse return error.MalformedRefType; try self.validator.validateRefNull(reftype); rr = Rr{ .@"ref.null" = reftype }; @@ -1045,7 +1054,10 @@ pub const Parser = struct { }, .misc => { const version = try self.readLEB128Mem(u32); - const misc_opcode = try std.meta.intToEnum(MiscOpcode, version); + const misc_opcode = std.enums.fromInt( + MiscOpcode, + version, + ) orelse return error.InvalidOpCode; try self.validator.validateMisc(misc_opcode); switch (misc_opcode) { @@ -1186,71 +1198,49 @@ pub const Parser = struct { } pub fn readLEB128Mem(self: *Parser, comptime T: type) !T { - var buf = std.Io.fixedBufferStream(self.code); - - const readFn = switch (@typeInfo(T).int.signedness) { - .signed => std.leb.readIleb128, - .unsigned => std.leb.readUleb128, - }; - const value = try readFn(T, buf.reader()); - - if (@typeInfo(T).int.signedness == .signed) { - // The following is a bit of a kludge that should really - // be fixed in either the std lib readILEB128 or using a - // a fresh implementation. The issue is that the wasm spec - // expects the "unused" bits in a negative ILEB128 to all be - // one and the same bits in a positive ILEB128 to be zero. - switch (T) { - i32 => if (buf.pos == 5 and value < 0 and buf.buffer[4] & 0x70 != 0x70) return error.Overflow, - i64 => if (buf.pos == 10 and value < 0 and buf.buffer[9] & 0x7e != 0x7e) return error.Overflow, - else => @compileError("self.readLEB128Mem expects an unsigned type, i32 or i64"), - } - } - - self.code.ptr += buf.pos; - self.code.len -= buf.pos; + var rd = std.Io.Reader.fixed(self.code); + const value = try Decoder.takeLeb128Exact(&rd, T); + self.code.ptr += rd.seek; + self.code.len -= rd.seek; return value; } pub fn readU32(self: *Parser) !u32 { - var buf = std.Io.fixedBufferStream(self.code); - const rd = buf.reader(); - const value = try rd.readInt(u32, .little); + var rd = std.Io.Reader.fixed(self.code); + const value = try rd.takeInt(u32, .little); - self.code.ptr += buf.pos; - self.code.len -= buf.pos; + self.code.ptr += rd.seek; + self.code.len -= rd.seek; return value; } pub fn readU64(self: *Parser) !u64 { - var buf = std.Io.fixedBufferStream(self.code); - const rd = buf.reader(); - const value = try rd.readInt(u64, .little); + var rd = std.Io.Reader.fixed(self.code); + const value = try rd.takeInt(u64, .little); - self.code.ptr += buf.pos; - self.code.len -= buf.pos; + self.code.ptr += rd.seek; + self.code.len -= rd.seek; return value; } pub fn readByte(self: *Parser) !u8 { - var buf = std.Io.fixedBufferStream(self.code); - const rd = buf.reader(); - const value = try rd.readByte(); + var rd = std.Io.Reader.fixed(self.code); + const value = try rd.takeByte(); - self.code.ptr += buf.pos; - self.code.len -= buf.pos; + self.code.ptr += rd.seek; + self.code.len -= rd.seek; return value; } }; -const EMPTY = [0]ValType{} ** 0; -const I32_OUT = [1]ValType{.I32} ** 1; -const I64_OUT = [1]ValType{.I64} ** 1; -const F32_OUT = [1]ValType{.F32} ** 1; -const F64_OUT = [1]ValType{.F64} ** 1; -const V128_OUT = [1]ValType{.V128} ** 1; -const FUNCREF_OUT = [1]ValType{.FuncRef} ** 1; -const EXTERNREF_OUT = [1]ValType{.ExternRef} ** 1; +const EMPTY: [0]ValType = .{}; +const I32_OUT: [1]ValType = @splat(.I32); +const I64_OUT: [1]ValType = @splat(.I64); +const F32_OUT: [1]ValType = @splat(.F32); +const F64_OUT: [1]ValType = @splat(.F64); +const V128_OUT: [1]ValType = @splat(.V128); +const FUNCREF_OUT: [1]ValType = @splat(.FuncRef); +const EXTERNREF_OUT: [1]ValType = @splat(.ExternRef); pub fn valueTypeFromBlockType(block_type: i32) !ValType { return switch (block_type) { diff --git a/src/module/validator.zig b/src/module/validator.zig index 0962620e..219ae42c 100644 --- a/src/module/validator.zig +++ b/src/module/validator.zig @@ -85,7 +85,7 @@ pub const Validator = struct { if (!(arity <= 64)) return error.TODOAllocation; - var temp = [_]Type{.{ .Known = .I32 }} ** 64; // TODO: allocate some memory for this + var temp: [64]Type = @splat(.{ .Known = .I32 }); // TODO: allocate some memory for this for (labelTypes(frame_n), 0..) |_, i| { temp[i] = try v.popOperandExpecting(Type{ .Known = labelTypes(frame_n)[arity - i - 1] }); } @@ -687,8 +687,8 @@ test "validate add i32" { var v = Validator.init(arena.allocator(), false); defer v.deinit(); - var in: [0]ValType = [_]ValType{} ** 0; - var out: [1]ValType = [_]ValType{.I32} ** 1; + var in: [0]ValType = .{}; + var out: [1]ValType = @splat(.I32); _ = try v.pushControlFrame(.block, in[0..], out[0..]); _ = try v.validate(.@"i32.const"); _ = try v.validate(.drop); @@ -705,8 +705,8 @@ test "validate add i64" { var v = Validator.init(arena.allocator(), false); defer v.deinit(); - var in: [0]ValType = [_]ValType{} ** 0; - var out: [1]ValType = [_]ValType{.I64} ** 1; + var in: [0]ValType = .{}; + var out: [1]ValType = @splat(.I64); _ = try v.pushControlFrame(.block, in[0..], out[0..]); _ = try v.validate(.@"i64.const"); _ = try v.validate(.@"i64.const"); @@ -721,8 +721,8 @@ test "validate add f32" { var v = Validator.init(arena.allocator(), false); defer v.deinit(); - var in: [0]ValType = [_]ValType{} ** 0; - var out: [1]ValType = [_]ValType{.F32} ** 1; + var in: [0]ValType = .{}; + var out: [1]ValType = @splat(.F32); _ = try v.pushControlFrame(.block, in[0..], out[0..]); _ = try v.validate(.@"f32.const"); _ = try v.validate(.@"f32.const"); @@ -737,8 +737,8 @@ test "validate add f64" { var v = Validator.init(arena.allocator(), false); defer v.deinit(); - var in: [0]ValType = [_]ValType{} ** 0; - var out: [1]ValType = [_]ValType{.F64} ** 1; + var in: [0]ValType = .{}; + var out: [1]ValType = @splat(.F64); _ = try v.pushControlFrame(.block, in[0..], out[0..]); _ = try v.validate(.@"f64.const"); _ = try v.validate(.@"f64.const"); @@ -753,8 +753,8 @@ test "validate: add error on mismatched types" { var v = Validator.init(arena.allocator(), false); defer v.deinit(); - var in: [0]ValType = [_]ValType{} ** 0; - var out: [1]ValType = [_]ValType{.I32} ** 1; + var in: [0]ValType = .{}; + var out: [1]ValType = @splat(.I32); _ = try v.pushControlFrame(.block, in[0..], out[0..]); _ = try v.validate(.@"i64.const"); _ = try v.validate(.@"i32.const"); diff --git a/test/testrunner/src/testrunner.zig b/test/testrunner/src/testrunner.zig index 8a1fa782..c47dd815 100644 --- a/test/testrunner/src/testrunner.zig +++ b/test/testrunner/src/testrunner.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const fs = std.fs; const fmt = std.fmt; const mem = std.mem; const math = std.math; @@ -14,7 +13,6 @@ const Memory = zware.Memory; const Function = zware.Function; const Global = zware.Global; const VirtualMachine = zware.VirtualMachine; -const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator; const ArenaAllocator = std.heap.ArenaAllocator; const StringHashMap = std.hash_map.StringHashMap; const ArrayList = std.ArrayList; @@ -32,8 +30,6 @@ const WasmError = zware.WasmError; // See https://github.com/WebAssembly/spec/blob/master/interpreter/README.md#s-expression-syntax // for information on the format of the .wast files. -var gpa = GeneralPurposeAllocator(.{}){}; - fn print(_: *VirtualMachine, _: usize) WasmError!void { std.debug.print("print\n", .{}); } @@ -70,23 +66,18 @@ fn print_f64_f64(vm: *VirtualMachine, _: usize) WasmError!void { std.debug.print("print_f64_f64: {}, {}\n", .{ value_f64_1, value_f64_2 }); } -pub fn main() anyerror!void { - defer _ = gpa.deinit(); +pub fn main(init: std.process.Init) anyerror!void { + const alloc = init.arena.allocator(); + const io = init.io; // 1. Get .json file from command line - var args = try process.argsWithAllocator(gpa.allocator()); - defer args.deinit(); + var args = try init.minimal.args.iterateAllocator(init.arena.allocator()); _ = args.skip(); const filename = args.next() orelse return error.NoFilename; std.log.info("testing: {s}", .{filename}); - var arena = ArenaAllocator.init(gpa.allocator()); - defer _ = arena.deinit(); - - const alloc = arena.allocator(); - // 2. Parse json and find .wasm file - const json_string = try fs.cwd().readFileAlloc(alloc, filename, 0xFFFFFFF); + const json_string = try std.Io.Dir.cwd().readFileAlloc(io, filename, alloc, .unlimited); const dynamic_tree = try std.json.parseFromSliceLeaky(std.json.Value, alloc, json_string, .{}); const r = try std.json.parseFromValueLeaky(Wast, alloc, dynamic_tree, .{}); @@ -130,7 +121,7 @@ pub fn main() anyerror!void { wasm_filename = command.module.filename; std.debug.print("(module): {s}:{} ({s})\n", .{ r.source_filename, command.module.line, wasm_filename }); - program = try fs.cwd().readFileAlloc(alloc, wasm_filename, 0xFFFFFFF); + program = try std.Io.Dir.cwd().readFileAlloc(io, wasm_filename, alloc, .unlimited); errdefer { std.debug.print("(module): {s} at {}:{s}\n", .{ r.source_filename, command.module.line, wasm_filename }); @@ -405,7 +396,7 @@ pub fn main() anyerror!void { wasm_filename = command.assert_invalid.filename; std.debug.print("(invalid): {s}:{} ({s})\n", .{ r.source_filename, command.assert_invalid.line, wasm_filename }); - program = try fs.cwd().readFileAlloc(alloc, wasm_filename, 0xFFFFFFF); + program = try std.Io.Dir.cwd().readFileAlloc(io, wasm_filename, alloc, .unlimited); module = Module.init(alloc, program); errdefer { @@ -469,7 +460,7 @@ pub fn main() anyerror!void { if (mem.endsWith(u8, command.assert_malformed.filename, ".wat")) continue; wasm_filename = command.assert_malformed.filename; std.debug.print("(malformed): {s}:{} ({s})\n", .{ r.source_filename, command.assert_malformed.line, wasm_filename }); - program = try fs.cwd().readFileAlloc(alloc, wasm_filename, 0xFFFFFFF); + program = try std.Io.Dir.cwd().readFileAlloc(io, wasm_filename, alloc, .unlimited); module = Module.init(alloc, program); const trap = command.assert_malformed.text; @@ -502,7 +493,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, trap, "malformed reference type")) { switch (err) { - error.InvalidValue => continue, + error.InvalidEnumTag => continue, else => {}, } } @@ -523,7 +514,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, trap, "malformed section id")) { switch (err) { - error.InvalidValue => continue, + error.InvalidEnumTag => continue, else => {}, } } @@ -547,6 +538,7 @@ pub fn main() anyerror!void { error.InvalidValue => continue, error.ExpectedFuncTypeTag => continue, error.Overflow => continue, + error.InvalidEnumTag => continue, else => {}, } } @@ -594,7 +586,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, trap, "malformed import kind")) { switch (err) { - error.InvalidValue => continue, + error.InvalidEnumTag => continue, else => {}, } } @@ -602,7 +594,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, trap, "integer too large")) { switch (err) { error.Overflow => continue, - error.InvalidValue => continue, // test/testsuite/binary.wast:601 I think the test is wrong + error.InvalidEnumTag => continue, // test/testsuite/binary.wast:1463 else => {}, } } @@ -616,7 +608,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, trap, "malformed mutability")) { switch (err) { - error.InvalidValue => continue, + error.InvalidEnumTag => continue, else => {}, } } @@ -666,7 +658,7 @@ pub fn main() anyerror!void { .assert_unlinkable => { wasm_filename = command.assert_unlinkable.filename; std.debug.print("(unlinkable): {s}:{} ({s})\n", .{ r.source_filename, command.assert_unlinkable.line, wasm_filename }); - program = try fs.cwd().readFileAlloc(alloc, wasm_filename, 0xFFFFFFF); + program = try std.Io.Dir.cwd().readFileAlloc(io, wasm_filename, alloc, .unlimited); module = Module.init(alloc, program); try module.decode(); @@ -693,7 +685,7 @@ pub fn main() anyerror!void { .assert_uninstantiable => { wasm_filename = command.assert_uninstantiable.filename; std.debug.print("(uninstantiable): {s}:{} ({s})\n", .{ r.source_filename, command.assert_uninstantiable.line, wasm_filename }); - program = try fs.cwd().readFileAlloc(alloc, wasm_filename, 0xFFFFFFF); + program = try std.Io.Dir.cwd().readFileAlloc(io, wasm_filename, alloc, .unlimited); module = Module.init(alloc, program); try module.decode(); diff --git a/tools/zware-gen.zig b/tools/zware-gen.zig index 8fffb8b8..ce7d7ed5 100644 --- a/tools/zware-gen.zig +++ b/tools/zware-gen.zig @@ -1,6 +1,5 @@ const std = @import("std"); const mem = std.mem; -const fs = std.fs; const fmt = std.fmt; const process = std.process; const zware = @import("zware"); @@ -8,28 +7,25 @@ const ArrayList = std.ArrayList; const Module = zware.Module; const Store = zware.Store; const Instance = zware.Instance; -const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator; -var gpa = GeneralPurposeAllocator(.{}){}; -pub fn main() !void { - defer _ = gpa.deinit(); - var alloc = gpa.allocator(); +pub fn main(init: std.process.Init) !void { + const alloc = init.gpa; + const io = init.io; - var args = try process.argsWithAllocator(alloc); - defer args.deinit(); + var args = try init.minimal.args.iterateAllocator(init.arena.allocator()); _ = args.skip(); const filename = args.next() orelse return error.NoFilename; - const program = try fs.cwd().readFileAlloc(alloc, filename, 0xFFFFFFF); + const program = try std.Io.Dir.cwd().readFileAlloc(init.io, filename, alloc, .unlimited); defer alloc.free(program); var module = Module.init(alloc, program); defer module.deinit(); try module.decode(); - const stdout_fd = std.fs.File.stdout(); + const stdout_fd = std.Io.File.stdout(); var stdout_buf: [4096]u8 = undefined; - var stdout_writer = stdout_fd.writer(&stdout_buf); + var stdout_writer = stdout_fd.writer(io, &stdout_buf); const stdout = &stdout_writer.interface; try stdout.print("const std = @import(\"std\");\n", .{}); diff --git a/tools/zware-run.zig b/tools/zware-run.zig index 4fae1afb..6e053460 100644 --- a/tools/zware-run.zig +++ b/tools/zware-run.zig @@ -18,11 +18,11 @@ const global = struct { //.verbose_log = true, }){} else std.heap.ArenaAllocator.init(std.heap.page_allocator); const alloc = allocator_instance.allocator(); - var import_stubs: std.ArrayListUnmanaged(ImportStub) = .{}; + var import_stubs: std.ArrayListUnmanaged(ImportStub) = .empty; }; -pub fn main() !void { - try main2(); +pub fn main(init: std.process.Init) !void { + try main2(init); if (enable_leak_detection) { switch (global.allocator_instance.deinit()) { .ok => {}, @@ -30,16 +30,16 @@ pub fn main() !void { } } } -fn main2() !void { +fn main2(init: std.process.Init) !void { defer global.import_stubs.deinit(global.alloc); - const full_cmdline = try std.process.argsAlloc(global.alloc); - defer std.process.argsFree(global.alloc, full_cmdline); + const io = init.io; + const full_cmdline = try init.minimal.args.toSlice(init.arena.allocator()); if (full_cmdline.len <= 1) { - const stderr_fd = std.fs.File.stderr(); + const stderr_fd = std.Io.File.stderr(); var stderr_buf: [4096]u8 = undefined; - var stderr_writer = stderr_fd.writer(&stderr_buf); + var stderr_writer = stderr_fd.writer(io, &stderr_buf); const stderr = &stderr_writer.interface; try stderr.writeAll("Usage: zware-run FILE.wasm FUNCTION\n"); try stderr.flush(); @@ -57,21 +57,30 @@ fn main2() !void { var store = zware.Store.init(global.alloc); defer store.deinit(); - const wasm_content = content_blk: { - var file = std.fs.cwd().openFile(wasm_path, .{}) catch |e| { - std.log.err("failed to open '{s}': {s}", .{ wasm_path, @errorName(e) }); - std.process.exit(0xff); - }; - defer file.close(); - break :content_blk try file.readToEndAlloc(global.alloc, std.math.maxInt(usize)); + const wasm_content = std.Io.Dir.cwd().readFileAlloc( + io, + wasm_path, + global.alloc, + .unlimited, + ) catch |err| { + std.log.err("failed to read '{s}': {s}", .{ wasm_path, @errorName(err) }); + std.process.exit(0xff); }; + // content_blk: { + // var file = std.Io.Dir.cwd().openFile(io, wasm_path, .{}) catch |e| { + // std.log.err("failed to open '{s}': {s}", .{ wasm_path, @errorName(e) }); + // std.process.exit(0xff); + // }; + // defer file.close(); + // break :content_blk try file.readToEndAlloc(global.alloc, std.math.maxInt(usize)); + // }; defer global.alloc.free(wasm_content); var module = zware.Module.init(global.alloc, wasm_content); defer module.deinit(); try module.decode(); - const export_funcidx = try getExportFunction(&module, wasm_func_name); + const export_funcidx = try getExportFunction(io, &module, wasm_func_name); const export_funcdef = module.functions.list.items[export_funcidx]; const export_functype = try module.types.lookup(export_funcdef.typeidx); if (export_functype.params.len != 0) { @@ -104,12 +113,12 @@ fn main2() !void { } } -fn getExportFunction(module: *const zware.Module, func_name: []const u8) !usize { +fn getExportFunction(io: std.Io, module: *const zware.Module, func_name: []const u8) !usize { return module.getExport(.Func, func_name) catch |err| switch (err) { error.ExportNotFound => { - const stderr_fd = std.fs.File.stderr(); + const stderr_fd = std.Io.File.stderr(); var stderr_buf: [4096]u8 = undefined; - var stderr_writer = stderr_fd.writer(&stderr_buf); + var stderr_writer = stderr_fd.writer(io, &stderr_buf); const stderr = &stderr_writer.interface; var export_func_count: usize = 0; for (module.exports.list.items) |exp| {