diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 30211fb8..d978ec36 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -14,9 +14,7 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v2 - - uses: mlugg/setup-zig@v1.2.1 - with: - version: 0.14.0 + - uses: mlugg/setup-zig@v2.0.5 - run: zig build unittest testsuite: strategy: @@ -25,18 +23,14 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v2 - - uses: mlugg/setup-zig@v1.2.1 - with: - version: 0.14.0 + - uses: mlugg/setup-zig@v2.0.5 - name: Run testsuite run: zig build testsuite lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: mlugg/setup-zig@v1.2.1 - with: - version: 0.14.0 + - uses: mlugg/setup-zig@v2.0.5 - run: zig fmt --check src/*.zig fib: strategy: @@ -45,9 +39,7 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v2 - - uses: mlugg/setup-zig@v1.2.1 - with: - version: 0.14.0 + - uses: mlugg/setup-zig@v2.0.5 - name: Build fib working-directory: ./examples/fib run: zig build @@ -58,8 +50,6 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v2 - - uses: mlugg/setup-zig@v1.2.1 - with: - version: 0.14.0 + - uses: mlugg/setup-zig@v2.0.5 - name: Build zware-gen, zware-run and libzware.a run: zig build diff --git a/README.md b/README.md index f147c2a4..5491fe7a 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ pub fn main() !void { ### Compile-time -- Zig 0.12 (master) +- Zig 0.15.1 (master) ### Run-time diff --git a/build.zig b/build.zig index 4613799d..8d58a9f5 100644 --- a/build.zig +++ b/build.zig @@ -10,17 +10,20 @@ pub fn build(b: *Build) !void { try b.modules.put(b.dupe("zware"), zware_module); - const lib = b.addStaticLibrary(.{ - .name = "zware", + const main_mod = 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, + }); b.installArtifact(lib); const main_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .optimize = optimize, + .root_module = main_mod, + .use_llvm = true, }); const run_main_tests = b.addRunArtifact(main_tests); @@ -31,9 +34,12 @@ pub fn build(b: *Build) !void { const testrunner = b.addExecutable(.{ .name = "testrunner", - .root_source_file = b.path("test/testrunner/src/testrunner.zig"), - .target = target, - .optimize = optimize, + .root_module = b.addModule("testrunner", .{ + .root_source_file = b.path("test/testrunner/src/testrunner.zig"), + .target = target, + .optimize = optimize, + }), + .use_llvm = true, }); testrunner.root_module.addImport("zware", zware_module); @@ -61,9 +67,12 @@ pub fn build(b: *Build) !void { { const exe = b.addExecutable(.{ .name = "zware-run", - .root_source_file = b.path("tools/zware-run.zig"), - .target = target, - .optimize = optimize, + .root_module = b.addModule("zware-run", .{ + .root_source_file = b.path("tools/zware-run.zig"), + .target = target, + .optimize = optimize, + }), + .use_llvm = true, }); exe.root_module.addImport("zware", zware_module); const install = b.addInstallArtifact(exe, .{}); @@ -79,9 +88,11 @@ pub fn build(b: *Build) !void { { const exe = b.addExecutable(.{ .name = "zware-gen", - .root_source_file = b.path("tools/zware-gen.zig"), - .target = target, - .optimize = optimize, + .root_module = b.addModule("zware-gen", .{ + .root_source_file = b.path("tools/zware-gen.zig"), + .target = target, + .optimize = optimize, + }), }); exe.root_module.addImport("zware", zware_module); const install = b.addInstallArtifact(exe, .{}); @@ -116,10 +127,12 @@ fn addWast2Json(b: *Build) *Build.Step.Compile { .SIZEOF_SIZE_T = @sizeOf(usize), }); - const wabt_lib = b.addStaticLibrary(.{ + const wabt_lib = b.addLibrary(.{ .name = "wabt", - .target = b.graph.host, - .optimize = .Debug, + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + }), }); wabt_lib.addConfigHeader(wabt_config_h); wabt_lib.addIncludePath(wabt_dep.path("include")); @@ -131,7 +144,9 @@ fn addWast2Json(b: *Build) *Build.Step.Compile { const wast2json = b.addExecutable(.{ .name = "wast2json", - .target = b.graph.host, + .root_module = b.createModule(.{ + .target = b.graph.host, + }), }); wast2json.addConfigHeader(wabt_config_h); wast2json.addIncludePath(wabt_dep.path("include")); diff --git a/build.zig.zon b/build.zig.zon index 9e5cd669..6ce79c19 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.14.0", + .minimum_zig_version = "0.15.1", .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 ba990bb0..d5145bd9 100644 --- a/examples/fib/build.zig +++ b/examples/fib/build.zig @@ -6,9 +6,12 @@ pub fn build(b: *Build) void { const exe = b.addExecutable(.{ .name = "fib", - .root_source_file = b.path("src/fib.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/fib.zig"), + .target = target, + .optimize = optimize, + }), + .use_llvm = true, }); exe.root_module.addAnonymousImport("zware", .{ .root_source_file = b.path("../../src/main.zig"), diff --git a/src/error.zig b/src/error.zig index 628da38f..639ef5d7 100644 --- a/src/error.zig +++ b/src/error.zig @@ -27,12 +27,8 @@ pub const Error = union(enum) { } pub fn format( self: Error, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + writer: *std.Io.Writer, ) !void { - _ = fmt; - _ = options; switch (self) { .missing_import => |import| try writer.print( "missing {s} import '{s}' from module '{s}'", diff --git a/src/instance.zig b/src/instance.zig index 8c7d778b..d252a5a3 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -33,6 +33,7 @@ const VirtualMachineOptions = struct { // - `tableaddrs`: as per `memaddrs` but for tables // - `globaladdrs`: as per `memaddrs` but for globals pub const Instance = struct { + alloc: mem.Allocator, module: Module, store: *Store, funcaddrs: ArrayList(usize), @@ -55,38 +56,39 @@ pub const Instance = struct { // a VirtualMachine swaps out its `inst` (instance) pointer as // it executes; an arbitrary `inst` will not contain the correct // data. - wasi_preopens: std.AutoHashMap(wasi.fd_t, WasiPreopen), + wasi_preopens: std.AutoHashMapUnmanaged(wasi.fd_t, WasiPreopen), wasi_args: std.ArrayList([:0]u8), - wasi_env: std.StringHashMap([]const u8), + wasi_env: std.StringHashMapUnmanaged([]const u8), pub fn init(alloc: mem.Allocator, store: *Store, module: Module) Instance { return Instance{ + .alloc = alloc, .module = module, .store = store, - .funcaddrs = ArrayList(usize).init(alloc), - .memaddrs = ArrayList(usize).init(alloc), - .tableaddrs = ArrayList(usize).init(alloc), - .globaladdrs = ArrayList(usize).init(alloc), - .elemaddrs = ArrayList(usize).init(alloc), - .dataaddrs = ArrayList(usize).init(alloc), - - .wasi_preopens = std.AutoHashMap(wasi.fd_t, WasiPreopen).init(alloc), - .wasi_args = ArrayList([:0]u8).init(alloc), - .wasi_env = std.StringHashMap([]const u8).init(alloc), + .funcaddrs = .empty, + .memaddrs = .empty, + .tableaddrs = .empty, + .globaladdrs = .empty, + .elemaddrs = .empty, + .dataaddrs = .empty, + + .wasi_preopens = .empty, + .wasi_args = .empty, + .wasi_env = .empty, }; } pub fn deinit(self: *Instance) void { - defer self.funcaddrs.deinit(); - defer self.memaddrs.deinit(); - defer self.tableaddrs.deinit(); - defer self.globaladdrs.deinit(); - defer self.elemaddrs.deinit(); - defer self.dataaddrs.deinit(); - - defer self.wasi_preopens.deinit(); - defer self.wasi_args.deinit(); - defer self.wasi_env.deinit(); + defer self.funcaddrs.deinit(self.alloc); + defer self.memaddrs.deinit(self.alloc); + defer self.tableaddrs.deinit(self.alloc); + defer self.globaladdrs.deinit(self.alloc); + defer self.elemaddrs.deinit(self.alloc); + defer self.dataaddrs.deinit(self.alloc); + + defer self.wasi_preopens.deinit(self.alloc); + defer self.wasi_args.deinit(self.alloc); + defer self.wasi_env.deinit(self.alloc); } pub fn getFunc(self: *Instance, funcidx: usize) !Function { @@ -161,10 +163,10 @@ pub const Instance = struct { 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), - .Table => try self.tableaddrs.append(import_handle), - .Global => try self.globaladdrs.append(import_handle), + .Func => try self.funcaddrs.append(self.alloc, import_handle), + .Mem => try self.memaddrs.append(self.alloc, import_handle), + .Table => try self.tableaddrs.append(self.alloc, import_handle), + .Global => try self.globaladdrs.append(self.alloc, import_handle), } } } @@ -208,7 +210,7 @@ pub const Instance = struct { }); // Need to do this regardless of if import or internal - try self.funcaddrs.append(handle); + try self.funcaddrs.append(self.alloc, handle); } } } @@ -226,7 +228,7 @@ pub const Instance = struct { .mutability = global_def.mutability, .valtype = global_def.valtype, }); - try self.globaladdrs.append(handle); + try self.globaladdrs.append(self.alloc, handle); } } } @@ -239,7 +241,7 @@ pub const Instance = struct { try memtype.limits.checkMatch(imported_mem.size(), imported_mem.max); } else { const handle = try self.store.addMemory(memtype.limits.min, memtype.limits.max); - try self.memaddrs.append(handle); + try self.memaddrs.append(self.alloc, handle); } } } @@ -252,7 +254,7 @@ pub const Instance = struct { try tabletype.limits.checkMatch(imported_table.min, imported_table.max); } else { const handle = try self.store.addTable(tabletype.reftype, tabletype.limits.min, tabletype.limits.max); - try self.tableaddrs.append(handle); + try self.tableaddrs.append(self.alloc, handle); } } } @@ -260,7 +262,7 @@ pub const Instance = struct { fn instantiateData(self: *Instance) !void { for (self.module.datas.list.items) |datatype| { const dataddr = try self.store.addData(datatype.count); - try self.dataaddrs.append(dataddr); + try self.dataaddrs.append(self.alloc, dataddr); var data = try self.store.data(dataddr); // TODO: Do we actually need to copy the data or just close over module bytes? @@ -285,7 +287,7 @@ pub const Instance = struct { fn instantiateElements(self: *Instance) !void { for (self.module.elements.list.items) |elemtype| { const elemaddr = try self.store.addElem(elemtype.reftype, elemtype.count); - try self.elemaddrs.append(elemaddr); + try self.elemaddrs.append(self.alloc, elemaddr); var elem = try self.store.elem(elemaddr); for (self.module.element_init_offsets.items[elemtype.init .. elemtype.init + elemtype.count], 0..) |expr, j| { diff --git a/src/instance/vm.zig b/src/instance/vm.zig index 5105dd3d..4286d544 100644 --- a/src/instance/vm.zig +++ b/src/instance/vm.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const os = std.os; const posix = std.posix; const mem = std.mem; @@ -52,9 +53,9 @@ pub const VirtualMachine = struct { // These fields match the types in Instance but are // instead pointers. These will point to the Instance // that initialises the VirtualMachine - wasi_preopens: *std.AutoHashMap(wasi.fd_t, WasiPreopen), + wasi_preopens: *std.AutoHashMapUnmanaged(wasi.fd_t, WasiPreopen), wasi_args: *std.ArrayList([:0]u8), - wasi_env: *std.StringHashMap([]const u8), + wasi_env: *std.StringHashMapUnmanaged([]const u8), pub const Frame = struct { locals: []u64 = undefined, // TODO: we're in trouble if we move our stacks in memory @@ -125,7 +126,11 @@ pub const VirtualMachine = struct { inline fn dispatch(self: *VirtualMachine, next_ip: usize, code: []Rr) WasmError!void { const next_instr = code[next_ip]; - return try @call(.always_tail, lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); + if (builtin.zig_backend == .stage2_x86_64) { + @compileError("zware currently requires the LLVM backend for `.always_tail`. See https://github.com/ziglang/zig/issues/24044"); + } + + return @call(.always_tail, lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); } pub const REF_NULL: u64 = 0xFFFF_FFFF_FFFF_FFFF; @@ -2111,7 +2116,11 @@ pub const VirtualMachine = struct { inline fn miscDispatch(self: *VirtualMachine, next_ip: usize, code: []Rr) WasmError!void { const next_instr = code[next_ip].misc; - return try @call(.always_tail, misc_lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); + if (builtin.zig_backend == .stage2_x86_64) { + @compileError("zware currently requires the LLVM backend for `.always_tail`. See https://github.com/ziglang/zig/issues/24044"); + } + + return @call(.always_tail, misc_lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); } fn @"i32.trunc_sat_f32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { diff --git a/src/module.zig b/src/module.zig index c6125343..fd91bb19 100644 --- a/src/module.zig +++ b/src/module.zig @@ -41,43 +41,43 @@ pub const Module = struct { return Module{ .alloc = alloc, .wasm_bin = wasm_bin, - .customs = Section(Custom).init(alloc), - .types = Section(FuncType).init(alloc), - .imports = Section(Import).init(alloc), - .functions = Section(Function).init(alloc), - .tables = Section(TableType).init(alloc), - .memories = Section(MemType).init(alloc), - .globals = Section(GlobalType).init(alloc), - .exports = Section(Export).init(alloc), - .elements = Section(ElementSegment).init(alloc), - .codes = Section(Code).init(alloc), - .datas = Section(DataSegment).init(alloc), - .element_init_offsets = ArrayList(usize).init(alloc), - .parsed_code = ArrayList(Rr).init(alloc), - .local_types = ArrayList(LocalType).init(alloc), - .br_table_indices = ArrayList(u32).init(alloc), - .references = ArrayList(u32).init(alloc), + .customs = .empty, + .types = .empty, + .imports = .empty, + .functions = .empty, + .tables = .empty, + .memories = .empty, + .globals = .empty, + .exports = .empty, + .elements = .empty, + .codes = .empty, + .datas = .empty, + .element_init_offsets = .empty, + .parsed_code = .empty, + .local_types = .empty, + .br_table_indices = .empty, + .references = .empty, }; } pub fn deinit(self: *Module) void { - defer self.customs.deinit(); - defer self.types.deinit(); - defer self.imports.deinit(); - defer self.functions.deinit(); - defer self.tables.deinit(); - defer self.memories.deinit(); - defer self.globals.deinit(); - defer self.exports.deinit(); - defer self.elements.deinit(); - defer self.codes.deinit(); - defer self.datas.deinit(); - - defer self.element_init_offsets.deinit(); - defer self.parsed_code.deinit(); - defer self.local_types.deinit(); - defer self.br_table_indices.deinit(); - defer self.references.deinit(); + defer self.customs.deinit(self.alloc); + defer self.types.deinit(self.alloc); + defer self.imports.deinit(self.alloc); + defer self.functions.deinit(self.alloc); + defer self.tables.deinit(self.alloc); + defer self.memories.deinit(self.alloc); + defer self.globals.deinit(self.alloc); + defer self.exports.deinit(self.alloc); + defer self.elements.deinit(self.alloc); + defer self.codes.deinit(self.alloc); + defer self.datas.deinit(self.alloc); + + defer self.element_init_offsets.deinit(self.alloc); + defer self.parsed_code.deinit(self.alloc); + defer self.local_types.deinit(self.alloc); + defer self.br_table_indices.deinit(self.alloc); + defer self.references.deinit(self.alloc); } pub fn decode(self: *Module) !void { @@ -97,7 +97,7 @@ pub const Module = struct { // Push an initial return instruction so we don't have to // track the end of a function to use its return on invoke // See https://github.com/malcolmstill/zware/pull/133 - try self.parsed_code.append(.@"return"); + try self.parsed_code.append(self.alloc, .@"return"); var i: usize = 0; while (true) : (i += 1) { @@ -148,7 +148,7 @@ pub const Module = struct { }; pub const Decoder = struct { - fbs: std.io.FixedBufferStream([]const u8), + fbs: std.Io.FixedBufferStream([]const u8), pub fn decodeSection(self: *Decoder, module: *Module) !void { const id: SectionType = self.readEnum(SectionType) catch |err| switch (err) { @@ -220,7 +220,7 @@ pub const Decoder = struct { results_valtype.ptr = @ptrCast(results.ptr); results_valtype.len = results.len; - try module.types.list.append(FuncType{ + try module.types.list.append(module.alloc, FuncType{ .params = params_valtype, .results = results_valtype, }); @@ -254,7 +254,7 @@ pub const Decoder = struct { .Global => try self.decodeGlobal(module, import_index), }; - try module.imports.list.append(Import{ + try module.imports.list.append(module.alloc, Import{ .module = module_name, .name = name, .desc_tag = tag, @@ -281,7 +281,7 @@ pub const Decoder = struct { module.function_index_start = module.functions.list.items.len; } - try module.functions.list.append(Function{ + try module.functions.list.append(module.alloc, Function{ .typeidx = typeidx, .import = import, }); @@ -311,7 +311,7 @@ pub const Decoder = struct { }, } }; - try module.tables.list.append(TableType{ + try module.tables.list.append(module.alloc, TableType{ .import = import, .reftype = reftype, .limits = Limit{ @@ -348,7 +348,7 @@ pub const Decoder = struct { }, } }; - try module.memories.list.append(MemType{ + try module.memories.list.append(module.alloc, MemType{ .import = import, .limits = Limit{ .min = min, @@ -382,7 +382,7 @@ pub const Decoder = struct { if (parsed_code == null and import == null) return error.ExpectedOneOrTheOther; if (parsed_code != null and import != null) return error.ExpectedOneOrTheOther; - try module.globals.list.append(GlobalType{ + try module.globals.list.append(module.alloc, GlobalType{ .valtype = global_type, .mutability = mutability, .start = if (parsed_code) |pc| pc.start else null, @@ -411,14 +411,14 @@ pub const Decoder = struct { switch (tag) { .Func => { if (index >= module.functions.list.items.len) return error.ValidatorExportUnknownFunction; - try module.references.append(index); + try module.references.append(module.alloc, index); }, .Table => if (index >= module.tables.list.items.len) return error.ValidatorExportUnknownTable, .Mem => if (index >= module.memories.list.items.len) return error.ValidatorExportUnknownMemory, .Global => if (index >= module.globals.list.items.len) return error.ValidatorExportUnknownGlobal, } - try module.exports.list.append(Export{ + try module.exports.list.append(module.alloc, Export{ .name = name, .tag = tag, .index = index, @@ -463,15 +463,15 @@ pub const Decoder = struct { if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; - try module.references.append(funcidx); + try module.references.append(module.alloc, funcidx); const init_offset = module.parsed_code.items.len; - try module.parsed_code.append(Rr{ .@"ref.func" = funcidx }); - try module.parsed_code.append(Rr.@"return"); - try module.element_init_offsets.append(init_offset); + try module.parsed_code.append(module.alloc, Rr{ .@"ref.func" = funcidx }); + try module.parsed_code.append(module.alloc, Rr.@"return"); + try module.element_init_offsets.append(module.alloc, init_offset); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = .FuncRef, .init = first_init_offset, .count = data_length, @@ -494,15 +494,15 @@ pub const Decoder = struct { if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; - try module.references.append(funcidx); + try module.references.append(module.alloc, funcidx); const init_offset = module.parsed_code.items.len; - try module.parsed_code.append(Rr{ .@"ref.func" = funcidx }); - try module.parsed_code.append(Rr.@"return"); - try module.element_init_offsets.append(init_offset); + try module.parsed_code.append(module.alloc, Rr{ .@"ref.func" = funcidx }); + try module.parsed_code.append(module.alloc, Rr.@"return"); + try module.element_init_offsets.append(module.alloc, init_offset); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = .FuncRef, .init = first_init_offset, .count = data_length, @@ -527,15 +527,15 @@ pub const Decoder = struct { if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; - try module.references.append(funcidx); + try module.references.append(module.alloc, funcidx); const init_offset = module.parsed_code.items.len; - try module.parsed_code.append(Rr{ .@"ref.func" = funcidx }); - try module.parsed_code.append(Rr.@"return"); - try module.element_init_offsets.append(init_offset); + try module.parsed_code.append(module.alloc, Rr{ .@"ref.func" = funcidx }); + try module.parsed_code.append(module.alloc, Rr.@"return"); + try module.element_init_offsets.append(module.alloc, init_offset); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = .FuncRef, .init = first_init_offset, .count = data_length, @@ -557,15 +557,15 @@ pub const Decoder = struct { if (funcidx >= module.functions.list.items.len) return error.ValidatorElemUnknownFunctionIndex; - try module.references.append(funcidx); + try module.references.append(module.alloc, funcidx); const init_offset = module.parsed_code.items.len; - try module.parsed_code.append(Rr{ .@"ref.func" = funcidx }); - try module.parsed_code.append(Rr.@"return"); - try module.element_init_offsets.append(init_offset); + try module.parsed_code.append(module.alloc, Rr{ .@"ref.func" = funcidx }); + try module.parsed_code.append(module.alloc, Rr.@"return"); + try module.element_init_offsets.append(module.alloc, init_offset); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = .FuncRef, .init = first_init_offset, .count = data_length, @@ -585,10 +585,10 @@ pub const Decoder = struct { var j: usize = 0; while (j < init_expression_count) : (j += 1) { const parsed_init_code = try self.readConstantExpression(module, .FuncRef); - try module.element_init_offsets.append(parsed_init_code.start); + try module.element_init_offsets.append(module.alloc, parsed_init_code.start); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = .FuncRef, .init = first_init_offset, .count = init_expression_count, @@ -608,10 +608,10 @@ pub const Decoder = struct { while (j < expr_count) : (j += 1) { const init_offset = module.parsed_code.items.len; _ = try self.readConstantExpression(module, .FuncRef); - try module.element_init_offsets.append(init_offset); + try module.element_init_offsets.append(module.alloc, init_offset); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = reftype, .init = first_init_offset, .count = expr_count, @@ -627,10 +627,10 @@ pub const Decoder = struct { var j: usize = 0; while (j < expr_count) : (j += 1) { const parsed_init_code = try self.readConstantExpression(module, .FuncRef); - try module.element_init_offsets.append(parsed_init_code.start); + try module.element_init_offsets.append(module.alloc, parsed_init_code.start); } - try module.elements.list.append(ElementSegment{ + try module.elements.list.append(module.alloc, ElementSegment{ .reftype = reftype, .init = first_init_offset, .count = expr_count, @@ -653,7 +653,7 @@ pub const Decoder = struct { const count = try self.readLEB128(u32); module.codes.count = count; - try module.parsed_code.ensureTotalCapacity(count * 32); + try module.parsed_code.ensureTotalCapacity(module.alloc, count * 32); if (count == 0) return; @@ -676,7 +676,7 @@ pub const Decoder = struct { const local_type = try self.readEnum(ValType); locals_count += type_count; - try module.local_types.append(.{ .count = type_count, .valtype = local_type }); + try module.local_types.append(module.alloc, .{ .count = type_count, .valtype = local_type }); } if (locals_count >= 0x100000000) return error.TooManyLocals; @@ -685,7 +685,7 @@ pub const Decoder = struct { if (function_index_start + i >= module.functions.list.items.len) return error.FunctionCodeSectionsInconsistent; const parsed_code = try self.readFunction(module, locals, function_index_start + i); - try module.codes.list.append(Code{ + try module.codes.list.append(module.alloc, Code{ .locals_count = locals_count, .start = parsed_code.start, .required_stack_space = parsed_code.max_depth, @@ -717,7 +717,7 @@ pub const Decoder = struct { const data_length = try self.readLEB128(u32); const data = try self.readSlice(data_length); - try module.datas.list.append(DataSegment{ + try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, .data = data, .mode = DataSegmentMode{ .Active = .{ @@ -730,7 +730,7 @@ pub const Decoder = struct { const data_length = try self.readLEB128(u32); const data = try self.readSlice(data_length); - try module.datas.list.append(DataSegment{ + try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, .data = data, .mode = .Passive, @@ -746,7 +746,7 @@ pub const Decoder = struct { const data_length = try self.readLEB128(u32); const data = try self.readSlice(data_length); - try module.datas.list.append(DataSegment{ + try module.datas.list.append(module.alloc, DataSegment{ .count = data_length, .data = data, .mode = DataSegmentMode{ .Active = .{ @@ -773,7 +773,7 @@ pub const Decoder = struct { const data_length = try math.sub(usize, size, (self.fbs.pos - offset)); const data = try self.readSlice(data_length); - try module.customs.list.append(Custom{ + try module.customs.list.append(module.alloc, Custom{ .name = name, .data = data, }); @@ -809,7 +809,7 @@ pub const Decoder = struct { fn readLEB128(self: *Decoder, comptime T: type) !T { const readFn = switch (@typeInfo(T).int.signedness) { .signed => std.leb.readILEB128, - .unsigned => std.leb.readULEB128, + .unsigned => std.leb.readUleb128, }; return readFn(T, self.fbs.reader()); } @@ -831,14 +831,12 @@ fn Section(comptime T: type) type { const Self = @This(); - pub fn init(alloc: mem.Allocator) Self { - return Self{ - .list = ArrayList(T).init(alloc), - }; - } + pub const empty = Self{ + .list = ArrayList(T).empty, + }; - pub fn deinit(self: *Self) void { - self.list.deinit(); + pub fn deinit(self: *Self, alloc: mem.Allocator) void { + self.list.deinit(alloc); } pub fn itemsSlice(self: *Self) []T { diff --git a/src/module/parser.zig b/src/module/parser.zig index 9cde4c7e..5656330e 100644 --- a/src/module/parser.zig +++ b/src/module/parser.zig @@ -61,7 +61,7 @@ pub const Parser = struct { try self.pushFunction(locals, funcidx); while (try self.next()) |instr| { - try self.module.parsed_code.append(instr); + try self.module.parsed_code.append(self.module.alloc, instr); } const bytes_read = self.bytesRead(); @@ -103,7 +103,7 @@ pub const Parser = struct { => {}, else => return error.ValidatorConstantExpressionRequired, } - try self.module.parsed_code.append(instr); + try self.module.parsed_code.append(self.module.alloc, instr); } const bytes_read = self.bytesRead(); @@ -350,7 +350,7 @@ pub const Parser = struct { var j: usize = 0; while (j < label_count) : (j += 1) { const tmp_label = try self.readLEB128Mem(u32); - try self.module.br_table_indices.append(tmp_label); + try self.module.br_table_indices.append(self.module.alloc, tmp_label); } const ln = try self.readLEB128Mem(u32); const l_star = self.module.br_table_indices.items[label_start .. label_start + j]; @@ -1028,7 +1028,7 @@ pub const Parser = struct { // Gather funcidx* from constant expressions if (self.is_constant) { - try self.module.references.append(funcidx); + try self.module.references.append(self.module.alloc, funcidx); } else { // For functions, check that the funcidx has already been referenced var in_references = false; @@ -1186,11 +1186,11 @@ pub const Parser = struct { } pub fn readLEB128Mem(self: *Parser, comptime T: type) !T { - var buf = std.io.fixedBufferStream(self.code); + var buf = std.Io.fixedBufferStream(self.code); const readFn = switch (@typeInfo(T).int.signedness) { - .signed => std.leb.readILEB128, - .unsigned => std.leb.readULEB128, + .signed => std.leb.readIleb128, + .unsigned => std.leb.readUleb128, }; const value = try readFn(T, buf.reader()); @@ -1213,7 +1213,7 @@ pub const Parser = struct { } pub fn readU32(self: *Parser) !u32 { - var buf = std.io.fixedBufferStream(self.code); + var buf = std.Io.fixedBufferStream(self.code); const rd = buf.reader(); const value = try rd.readInt(u32, .little); @@ -1223,7 +1223,7 @@ pub const Parser = struct { } pub fn readU64(self: *Parser) !u64 { - var buf = std.io.fixedBufferStream(self.code); + var buf = std.Io.fixedBufferStream(self.code); const rd = buf.reader(); const value = try rd.readInt(u64, .little); @@ -1233,7 +1233,7 @@ pub const Parser = struct { } pub fn readByte(self: *Parser) !u8 { - var buf = std.io.fixedBufferStream(self.code); + var buf = std.Io.fixedBufferStream(self.code); const rd = buf.reader(); const value = try rd.readByte(); diff --git a/src/module/validator.zig b/src/module/validator.zig index add2c75f..0962620e 100644 --- a/src/module/validator.zig +++ b/src/module/validator.zig @@ -11,6 +11,7 @@ const MiscOpcode = @import("../opcode.zig").MiscOpcode; const Module = @import("../module.zig").Module; pub const Validator = struct { + alloc: std.mem.Allocator, op_stack: OperandStack = undefined, ctrl_stack: ControlStack = undefined, max_depth: usize = 0, @@ -18,16 +19,17 @@ pub const Validator = struct { pub fn init(alloc: mem.Allocator, is_constant: bool) Validator { return Validator{ - .op_stack = OperandStack.init(alloc), - .ctrl_stack = ControlStack.init(alloc), + .alloc = alloc, + .op_stack = OperandStack.empty, + .ctrl_stack = ControlStack.empty, .is_constant = is_constant, }; } pub fn deinit(self: *Validator) void { // Static allocation? - self.op_stack.deinit(); - self.ctrl_stack.deinit(); + self.op_stack.deinit(self.alloc); + self.ctrl_stack.deinit(self.alloc); } pub fn validateBlock(v: *Validator, in_operands: []const ValType, out_operands: []const ValType) !void { @@ -550,7 +552,7 @@ pub const Validator = struct { pub fn pushOperand(v: *Validator, t: Type) !void { defer v.trackMaxDepth(); - try v.op_stack.append(t); + try v.op_stack.append(v.alloc, t); } fn popOperand(v: *Validator) !Type { @@ -600,7 +602,7 @@ pub const Validator = struct { .height = v.op_stack.items.len, .unreachable_flag = false, }; - try v.ctrl_stack.append(frame); + try v.ctrl_stack.append(v.alloc, frame); try v.pushOperands(in); } diff --git a/src/store.zig b/src/store.zig index d0fe7315..3b69c33e 100644 --- a/src/store.zig +++ b/src/store.zig @@ -44,26 +44,26 @@ pub const ArrayListStore = struct { pub fn init(alloc: mem.Allocator) ArrayListStore { const store = ArrayListStore{ .alloc = alloc, - .functions = ArrayList(Function).init(alloc), - .memories = ArrayList(Memory).init(alloc), - .tables = ArrayList(Table).init(alloc), - .globals = ArrayList(Global).init(alloc), - .elems = ArrayList(Elem).init(alloc), - .datas = ArrayList(Data).init(alloc), - .imports = ArrayList(ImportExport).init(alloc), + .functions = .empty, + .memories = .empty, + .tables = .empty, + .globals = .empty, + .elems = .empty, + .datas = .empty, + .imports = .empty, }; return store; } pub fn deinit(self: *ArrayListStore) void { - defer self.functions.deinit(); - defer self.memories.deinit(); - defer self.tables.deinit(); - defer self.globals.deinit(); - defer self.elems.deinit(); - defer self.datas.deinit(); - defer self.imports.deinit(); + defer self.functions.deinit(self.alloc); + defer self.memories.deinit(self.alloc); + defer self.tables.deinit(self.alloc); + defer self.globals.deinit(self.alloc); + defer self.elems.deinit(self.alloc); + defer self.datas.deinit(self.alloc); + defer self.imports.deinit(self.alloc); for (self.memories.items) |*m| { m.deinit(); @@ -96,7 +96,7 @@ pub const ArrayListStore = struct { } pub fn @"export"(self: *ArrayListStore, module: []const u8, name: []const u8, tag: Tag, handle: usize) !void { - try self.imports.append(ImportExport{ + try self.imports.append(self.alloc, ImportExport{ .import = Import{ .module = module, .name = name, @@ -114,7 +114,7 @@ pub const ArrayListStore = struct { } pub fn addFunction(self: *ArrayListStore, func: Function) !usize { - const fun_ptr = try self.functions.addOne(); + const fun_ptr = try self.functions.addOne(self.alloc); fun_ptr.* = func; return self.functions.items.len - 1; } @@ -128,7 +128,7 @@ pub const ArrayListStore = struct { /// Allocate a new Memory with min / max size and add to store. pub fn addMemory(self: *ArrayListStore, min: u32, max: ?u32) !usize { - const mem_ptr = try self.memories.addOne(); + const mem_ptr = try self.memories.addOne(self.alloc); mem_ptr.* = Memory.init(self.alloc, min, max); _ = try mem_ptr.grow(min); return self.memories.items.len - 1; @@ -142,7 +142,7 @@ pub const ArrayListStore = struct { } pub fn addTable(self: *ArrayListStore, reftype: RefType, entries: u32, max: ?u32) !usize { - const tbl_ptr = try self.tables.addOne(); + const tbl_ptr = try self.tables.addOne(self.alloc); tbl_ptr.* = try Table.init(self.alloc, reftype, entries, max); return self.tables.items.len - 1; } @@ -156,7 +156,7 @@ pub const ArrayListStore = struct { /// Add a Global to the store and return its globaladdr pub fn addGlobal(self: *ArrayListStore, value: Global) !usize { - const glbl_ptr = try self.globals.addOne(); + const glbl_ptr = try self.globals.addOne(self.alloc); glbl_ptr.* = value; return self.globals.items.len - 1; @@ -170,7 +170,7 @@ pub const ArrayListStore = struct { } pub fn addElem(self: *ArrayListStore, reftype: RefType, count: u32) !usize { - const elem_ptr = try self.elems.addOne(); + const elem_ptr = try self.elems.addOne(self.alloc); elem_ptr.* = try Elem.init(self.alloc, reftype, count); return self.elems.items.len - 1; } @@ -183,7 +183,7 @@ pub const ArrayListStore = struct { } pub fn addData(self: *ArrayListStore, count: u32) !usize { - const data_ptr = try self.datas.addOne(); + const data_ptr = try self.datas.addOne(self.alloc); data_ptr.* = try Data.init(self.alloc, count); return self.datas.items.len - 1; } diff --git a/src/store/memory.zig b/src/store/memory.zig index 4750b426..a186503c 100644 --- a/src/store/memory.zig +++ b/src/store/memory.zig @@ -14,14 +14,14 @@ pub const Memory = struct { pub fn init(alloc: mem.Allocator, min: u32, max: ?u32) Memory { return Memory{ .alloc = alloc, - .data = ArrayList(u8).init(alloc), + .data = .empty, .min = min, .max = max, }; } pub fn deinit(self: *Memory) void { - self.data.deinit(); + self.data.deinit(self.alloc); } // Return the size of the memory (in pages) @@ -41,7 +41,7 @@ pub const Memory = struct { const old_size_in_bytes = self.data.items.len; const old_size_in_pages = self.size(); - _ = try self.data.resize(self.data.items.len + PAGE_SIZE * num_pages); + _ = try self.data.resize(self.alloc, self.data.items.len + PAGE_SIZE * num_pages); // Zero memory. FIXME: I don't think this is required (maybe do this only in debug build) @memset(self.data.items[old_size_in_bytes .. old_size_in_bytes + PAGE_SIZE * num_pages], 0); diff --git a/src/store/table.zig b/src/store/table.zig index 805f5c90..82fce941 100644 --- a/src/store/table.zig +++ b/src/store/table.zig @@ -12,8 +12,8 @@ pub const Table = struct { reftype: RefType, pub fn init(alloc: mem.Allocator, reftype: RefType, min: u32, max: ?u32) !Table { - var data = ArrayList(?usize).init(alloc); - try data.appendNTimes(null, min); + var data: ArrayList(?usize) = .empty; + try data.appendNTimes(alloc, null, min); return Table{ .alloc = alloc, @@ -25,7 +25,7 @@ pub const Table = struct { } pub fn deinit(self: *Table) void { - self.data.deinit(); + self.data.deinit(self.alloc); } pub fn lookup(self: *Table, index: u32) !usize { @@ -57,7 +57,7 @@ pub const Table = struct { const old_size = math.cast(u32, self.data.items.len) orelse return error.TableGrowToolarge; - try self.data.appendNTimes(null, n); + try self.data.appendNTimes(self.alloc, null, n); return old_size; } diff --git a/test/testrunner/src/testrunner.zig b/test/testrunner/src/testrunner.zig index f8db3f19..8a1fa782 100644 --- a/test/testrunner/src/testrunner.zig +++ b/test/testrunner/src/testrunner.zig @@ -819,21 +819,21 @@ const Command = union(enum) { const CommandModule = struct { // type: "module" - line: usize, + line: u32, name: ?[]const u8 = null, filename: []const u8, }; const CommandAssertReturn = struct { // type: "assert_return" - line: usize, + line: u32, action: Action, expected: []const Value, }; const CommandAssertTrap = struct { // type: "assert_trap" - line: usize, + line: u32, action: Action, text: []const u8, expected: []const ValueTrap, @@ -841,7 +841,7 @@ const CommandAssertTrap = struct { const CommandAssertMalformed = struct { // type: "assert_malformed" - line: usize, + line: u32, filename: []const u8, text: []const u8, module_type: []const u8, @@ -849,7 +849,7 @@ const CommandAssertMalformed = struct { const CommandAssertInvalid = struct { // type: "assert_invalid" - line: usize, + line: u32, filename: []const u8, text: []const u8, module_type: []const u8, @@ -857,7 +857,7 @@ const CommandAssertInvalid = struct { const CommandAssertExhaustion = struct { // type: "assert_exhaustion" - line: usize, + line: u32, action: Action, text: []const u8, expected: []const ValueTrap, @@ -865,7 +865,7 @@ const CommandAssertExhaustion = struct { const CommandAssertUnlinkable = struct { // type: "assert_unlinkable" - line: usize, + line: u32, filename: []const u8, text: []const u8, module_type: []const u8, @@ -873,7 +873,7 @@ const CommandAssertUnlinkable = struct { const CommandAssertUninstantiable = struct { // type: "assert_uninstantiable" - line: usize, + line: u32, filename: []const u8, text: []const u8, module_type: []const u8, @@ -881,14 +881,14 @@ const CommandAssertUninstantiable = struct { const CommandAction = struct { // type: "action" - line: usize, + line: u32, action: Action, expected: []const ValueTrap, }; const CommandRegister = struct { // type: "register" - line: usize, + line: u32, name: ?[]const u8 = null, as: []const u8, }; diff --git a/tools/zware-gen.zig b/tools/zware-gen.zig index 1273bfd9..8fffb8b8 100644 --- a/tools/zware-gen.zig +++ b/tools/zware-gen.zig @@ -27,9 +27,10 @@ pub fn main() !void { defer module.deinit(); try module.decode(); - const stdout_file = std.io.getStdOut().writer(); - var bw = std.io.bufferedWriter(stdout_file); - const stdout = bw.writer(); + const stdout_fd = std.fs.File.stdout(); + var stdout_buf: [4096]u8 = undefined; + var stdout_writer = stdout_fd.writer(&stdout_buf); + const stdout = &stdout_writer.interface; try stdout.print("const std = @import(\"std\");\n", .{}); try stdout.print("const zware = @import(\"zware\");\n\n", .{}); @@ -222,7 +223,7 @@ pub fn main() !void { } try stdout.print("}};\n\n", .{}); - try bw.flush(); + try stdout.flush(); } fn zigType(v: zware.ValType) []const u8 { diff --git a/tools/zware-run.zig b/tools/zware-run.zig index 94310397..4fae1afb 100644 --- a/tools/zware-run.zig +++ b/tools/zware-run.zig @@ -35,8 +35,14 @@ fn main2() !void { const full_cmdline = try std.process.argsAlloc(global.alloc); defer std.process.argsFree(global.alloc, full_cmdline); + if (full_cmdline.len <= 1) { - try std.io.getStdErr().writer().writeAll("Usage: zware-run FILE.wasm FUNCTION\n"); + const stderr_fd = std.fs.File.stderr(); + var stderr_buf: [4096]u8 = undefined; + var stderr_writer = stderr_fd.writer(&stderr_buf); + const stderr = &stderr_writer.interface; + try stderr.writeAll("Usage: zware-run FILE.wasm FUNCTION\n"); + try stderr.flush(); std.process.exit(0xff); } @@ -81,7 +87,7 @@ fn main2() !void { var zware_error: zware.Error = undefined; instance.instantiateWithError(&zware_error) catch |err| switch (err) { error.SeeContext => { - std.log.err("failed to instantiate the module: {}", .{zware_error}); + std.log.err("failed to instantiate the module: {f}", .{zware_error}); std.process.exit(0xff); }, else => |e| return e, @@ -94,14 +100,17 @@ fn main2() !void { try instance.invoke(wasm_func_name, &in, out_args, .{}); std.log.info("{} output(s)", .{out_args.len}); for (out_args, 0..) |out_arg, out_index| { - std.log.info("output {} {}", .{ out_index, fmtValue(export_functype.results[out_index], out_arg) }); + std.log.info("output {} {f}", .{ out_index, fmtValue(export_functype.results[out_index], out_arg) }); } } fn getExportFunction(module: *const zware.Module, func_name: []const u8) !usize { return module.getExport(.Func, func_name) catch |err| switch (err) { error.ExportNotFound => { - const stderr = std.io.getStdErr().writer(); + const stderr_fd = std.fs.File.stderr(); + var stderr_buf: [4096]u8 = undefined; + var stderr_writer = stderr_fd.writer(&stderr_buf); + const stderr = &stderr_writer.interface; var export_func_count: usize = 0; for (module.exports.list.items) |exp| { if (exp.tag == .Func) { @@ -121,6 +130,7 @@ fn getExportFunction(module: *const zware.Module, func_name: []const u8) !usize } } } + try stderr.flush(); std.process.exit(0xff); }, }; @@ -176,10 +186,10 @@ fn onMissingImport(vm: *zware.VirtualMachine, context: usize) zware.WasmError!vo std.log.info("import function '{s}.{s}' called", .{ stub.module, stub.name }); for (stub.type.params, 0..) |param_type, i| { const value = vm.popAnyOperand(); - std.log.info(" param {} {}", .{ i, fmtValue(param_type, value) }); + std.log.info(" param {} {f}", .{ i, fmtValue(param_type, value) }); } for (stub.type.results, 0..) |result_type, i| { - std.log.info(" result {} {}", .{ i, fmtValue(result_type, 0) }); + std.log.info(" result {} {f}", .{ i, fmtValue(result_type, 0) }); try vm.pushOperand(u64, 0); } } @@ -216,12 +226,8 @@ const FmtValue = struct { value: u64, pub fn format( self: FmtValue, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, writer: anytype, ) !void { - _ = fmt; - _ = options; switch (self.type) { inline else => |t2| try writer.print("({s}) {}", .{ @tagName(t2), cast(t2, self.value) }), }