Skip to content
This repository was archived by the owner on Jun 9, 2026. It is now read-only.
Open
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
12 changes: 6 additions & 6 deletions src/Memory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ const std = @import("std");
const Memory = @This();

pages: std.ArrayListUnmanaged(*[65536]u8),
allocator: *std.mem.Allocator,
context: ?*c_void,
allocator: std.mem.Allocator,
context: ?*anyopaque,

const page_size = 65536;

pub fn init(allocator: *std.mem.Allocator, context: ?*c_void, initial_pages: u16) !Memory {
pub fn init(allocator: std.mem.Allocator, context: ?*anyopaque, initial_pages: u16) !Memory {
var result = Memory{ .allocator = allocator, .pages = .{}, .context = context };
try result.grow(initial_pages);
return result;
Expand All @@ -35,7 +35,7 @@ pub fn grow(self: *Memory, additional_pages: u16) !void {
if (new_page_count > 65536) {
return error.OutOfMemory;
}
try self.pages.ensureCapacity(self.allocator, new_page_count);
try self.pages.ensureTotalCapacity(self.allocator, new_page_count);

var i: u16 = 0;
while (i < additional_pages) : (i += 1) {
Expand Down Expand Up @@ -130,11 +130,11 @@ pub fn P(comptime T: type) type {
}

pub fn add(self: Self, change: u32) !Self {
return init(try std.math.add(u32, @enumToInt(self), try std.math.mul(u32, change, stride)));
return Self.init(try std.math.add(u32, @enumToInt(self), try std.math.mul(u32, change, stride)));
}

pub fn sub(self: Self, change: u32) !Self {
return init(try std.math.sub(u32, @enumToInt(self), try std.math.mul(u32, change, stride)));
return Self.init(try std.math.sub(u32, @enumToInt(self), try std.math.mul(u32, change, stride)));
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/execution.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Execution = @This();

memory: *Memory,
funcs: []const Instance.Func,
allocator: *std.mem.Allocator,
allocator: std.mem.Allocator,
instance: *const Instance,

stack: []Op.Fixval,
Expand Down
2 changes: 2 additions & 0 deletions src/func/global.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ test "set global" {

{
const result = try instance.call("get", .{@as(i32, 1)});
_ = result;
try std.testing.expectEqual(Instance.Value{ .I32 = 1 }, instance.getGlobal(0));
}

{
const result = try instance.call("get", .{@as(i32, 5)});
_ = result;
try std.testing.expectEqual(Instance.Value{ .I32 = 5 }, instance.getGlobal(0));
}
}
3 changes: 3 additions & 0 deletions src/func/imports.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test "import" {
var instance = try module.instantiate(std.testing.allocator, null, struct {
pub const env = struct {
pub fn thing(mem: *Memory, arg: i32) i32 {
_ = mem;
return arg + 1;
}
};
Expand Down Expand Up @@ -48,10 +49,12 @@ test "import multiple" {
var instance = try module.instantiate(std.testing.allocator, null, struct {
pub const env = struct {
pub fn add(mem: *Memory, arg0: i32, arg1: i32) i32 {
_ = mem;
return arg0 + arg1;
}

pub fn mul(mem: *Memory, arg0: i32, arg1: i32) i32 {
_ = mem;
return arg0 * arg1;
}
};
Expand Down
17 changes: 9 additions & 8 deletions src/instance.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Memory = @import("Memory.zig");
const Instance = @This();

module: *const Module,
allocator: *std.mem.Allocator,
allocator: std.mem.Allocator,
memory: Memory,
exports: std.StringHashMap(Export),
funcs: []const Func,
Expand All @@ -17,7 +17,7 @@ globals: []Op.Fixval,
// TODO: revisit if wasm ever becomes multi-threaded
mutex: std.Thread.Mutex,

pub fn init(module: *const Module, allocator: *std.mem.Allocator, context: ?*c_void, comptime Imports: type) !Instance {
pub fn init(module: *const Module, allocator: std.mem.Allocator, context: ?*anyopaque, comptime Imports: type) !Instance {
var exports = std.StringHashMap(Export).init(allocator);
errdefer exports.deinit();
for (module.@"export") |exp| {
Expand Down Expand Up @@ -110,8 +110,8 @@ pub fn deinit(self: *Instance) void {
}

pub fn call(self: *Instance, name: []const u8, params: anytype) !?Value {
const lock = self.mutex.acquire();
defer lock.release();
self.mutex.lock();
defer self.mutex.unlock();

const exp = self.exports.get(name) orelse return error.ExportNotFound;
if (exp != .Func) {
Expand Down Expand Up @@ -282,9 +282,9 @@ pub fn ImportManager(comptime Imports: type) type {
var kvs: []const KV = &[0]KV{};
inline for (std.meta.declarations(Imports)) |decl| {
if (decl.is_pub) {
inline for (std.meta.declarations(decl.data.Type)) |decl2| {
inline for (std.meta.declarations(@field(Imports, decl.name))) |decl2| {
if (decl2.is_pub) {
const func = @field(decl.data.Type, decl2.name);
const func = @field(@field(Imports, decl.name), decl2.name);
const fn_info = @typeInfo(@TypeOf(func)).Fn;
const shimmed = helpers.shim(func);
kvs = kvs ++ [1]KV{.{
Expand All @@ -308,10 +308,11 @@ pub fn ImportManager(comptime Imports: type) type {
}

const map = if (kvs.len > 0) std.ComptimeStringMap(V, kvs) else {};
const final_kvs = kvs;

return struct {
pub fn get(module: []const u8, field: []const u8) ?V {
if (kvs.len == 0) return null;
if (final_kvs.len == 0) return null;

var buffer: [1 << 10]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buffer);
Expand Down Expand Up @@ -341,6 +342,6 @@ pub const Func = struct {
},
};

test "" {
test {
_ = call;
}
6 changes: 3 additions & 3 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub const Wasi = @import("wasi.zig");
pub fn main() !u8 {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = &gpa.allocator;
const allocator = gpa.allocator();

const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
Expand All @@ -18,7 +18,7 @@ pub fn main() !u8 {
defer file.close();

var wasi = Wasi{ .argv = args[1..] };
const exit_code = @enumToInt(try wasi.run(&gpa.allocator, file.reader()));
const exit_code = @enumToInt(try wasi.run(allocator, file.reader()));
if (exit_code > 255) {
std.debug.print("Exit code {} > 255\n", .{exit_code});
return 255;
Expand All @@ -27,7 +27,7 @@ pub fn main() !u8 {
}
}

test "" {
test {
_ = Instance;
_ = Module;
_ = Op;
Expand Down
35 changes: 20 additions & 15 deletions src/module.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const builtin = @import("builtin");
const std = @import("std");
const Instance = @import("instance.zig");
const Op = @import("op.zig");
Expand Down Expand Up @@ -236,7 +237,7 @@ test "readVarint" {
}

fn readVarintEnum(comptime E: type, reader: anytype) !E {
const raw = try readVarint(std.meta.TagType(E), reader);
const raw = try readVarint(std.meta.Tag(E), reader);
if (@typeInfo(E).Enum.is_exhaustive) {
return try std.meta.intToEnum(E, raw);
} else {
Expand All @@ -260,7 +261,7 @@ fn Mut(comptime T: type) type {

// --- Before ---
// const count = try readVarint(u32, section.reader());
// result.field = arena.allocator.alloc(@TypeOf(result.field), count);
// result.field = arena.allocator().alloc(@TypeOf(result.field), count);
// for (result.field) |*item| {
//
// --- After ---
Expand All @@ -270,12 +271,12 @@ fn allocInto(self: *Module, ptr_to_slice: anytype, count: usize) !Mut(std.meta.C
const Slice = Mut(std.meta.Child(@TypeOf(ptr_to_slice)));
std.debug.assert(@typeInfo(Slice).Pointer.size == .Slice);

var result = try self.arena.allocator.alloc(std.meta.Child(Slice), count);
var result = try self.arena.allocator().alloc(std.meta.Child(Slice), count);
ptr_to_slice.* = result;
return result;
}

pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
pub fn parse(allocator: std.mem.Allocator, reader: anytype) !Module {
const signature = try reader.readIntLittle(u32);
if (signature != magic_number) {
return error.InvalidFormat;
Expand All @@ -289,7 +290,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
var result = Module.init(std.heap.ArenaAllocator.init(allocator));
errdefer result.arena.deinit();

var customs = std.ArrayList(Module.Section(.custom)).init(&result.arena.allocator);
var customs = std.ArrayList(Module.Section(.custom)).init(result.arena.allocator());
errdefer customs.deinit();

while (true) {
Expand Down Expand Up @@ -320,12 +321,12 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
const count = try readVarint(u32, section.reader());
for (try result.allocInto(&result.import, count)) |*i| {
const module_len = try readVarint(u32, section.reader());
const module_data = try result.arena.allocator.alloc(u8, module_len);
const module_data = try result.arena.allocator().alloc(u8, module_len);
try section.reader().readNoEof(module_data);
i.module = module_data;

const field_len = try readVarint(u32, section.reader());
const field_data = try result.arena.allocator.alloc(u8, field_len);
const field_data = try result.arena.allocator().alloc(u8, field_len);
try section.reader().readNoEof(field_data);
i.field = field_data;

Expand Down Expand Up @@ -380,7 +381,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
const count = try readVarint(u32, section.reader());
for (try result.allocInto(&result.@"export", count)) |*e| {
const field_len = try readVarint(u32, section.reader());
const field_data = try result.arena.allocator.alloc(u8, field_len);
const field_data = try result.arena.allocator().alloc(u8, field_len);
try section.reader().readNoEof(field_data);
e.field = field_data;
e.kind = try readVarintEnum(ExternalKind, section.reader());
Expand All @@ -390,6 +391,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
},
.start => {
const index = try readVarint(u32, section.reader());
_ = index;
result.start = .{
.index = try readVarintEnum(Index.Function, section.reader()),
};
Expand All @@ -402,6 +404,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
e.offset = try InitExpr.parse(section.reader());

const num_elem = try readVarint(u32, section.reader());
_ = num_elem;
for (try result.allocInto(&e.elems, count)) |*func| {
func.* = try readVarintEnum(Index.Function, section.reader());
}
Expand All @@ -416,7 +419,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {

c.locals = blk: {
// TODO: double pass here to preallocate the exact array size
var list = std.ArrayList(Type.Value).init(&result.arena.allocator);
var list = std.ArrayList(Type.Value).init(result.arena.allocator());
var local_count = try readVarint(u32, body.reader());
while (local_count > 0) : (local_count -= 1) {
var current_count = try readVarint(u32, body.reader());
Expand All @@ -429,7 +432,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
};

c.body = body: {
var list = std.ArrayList(Module.Instr).init(&result.arena.allocator);
var list = std.ArrayList(Module.Instr).init(result.arena.allocator());
while (true) {
const opcode = body.reader().readByte() catch |err| switch (err) {
error.EndOfStream => {
Expand Down Expand Up @@ -472,7 +475,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
const target_count = try readVarint(u32, body.reader());
const size = target_count + 1; // Implementation detail: we shove the default into the last element of the array

const data = try result.arena.allocator.alloc(u32, size);
const data = try result.arena.allocator().alloc(u32, size);
for (data) |*item| {
item.* = try readVarint(u32, body.reader());
}
Expand All @@ -499,7 +502,7 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
d.offset = try InitExpr.parse(section.reader());

const size = try readVarint(u32, section.reader());
const data = try result.arena.allocator.alloc(u8, size);
const data = try result.arena.allocator().alloc(u8, size);
try section.reader().readNoEof(data);
d.data = data;
}
Expand All @@ -509,21 +512,23 @@ pub fn parse(allocator: *std.mem.Allocator, reader: anytype) !Module {
const custom_section = try customs.addOne();

const name_len = try readVarint(u32, section.reader());
const name = try result.arena.allocator.alloc(u8, name_len);
const name = try result.arena.allocator().alloc(u8, name_len);
try section.reader().readNoEof(name);
custom_section.name = name;

const payload = try result.arena.allocator.alloc(u8, section.bytes_left);
const payload = try result.arena.allocator().alloc(u8, section.bytes_left);
try section.reader().readNoEof(payload);
custom_section.payload = payload;

try expectEos(section.reader());
},
.data_count => @panic("TODO: handle this section"),
_ => @panic("TODO handle unexpected section"),
}

// Putting this in all the switch paths makes debugging much easier
// Leaving an extra one here in case one of the paths is missing
if (std.builtin.mode == .Debug) {
if (builtin.mode == .Debug) {
try expectEos(section.reader());
}
}
Expand Down
17 changes: 10 additions & 7 deletions src/module/post_process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn init(module: *Module) !PostProcess {
var temp_arena = std.heap.ArenaAllocator.init(module.arena.child_allocator);
defer temp_arena.deinit();

var import_funcs = std.ArrayList(ImportFunc).init(&module.arena.allocator);
var import_funcs = std.ArrayList(ImportFunc).init(module.arena.allocator());
for (module.import) |import| {
switch (import.kind) {
.Function => |type_idx| {
Expand All @@ -44,8 +44,8 @@ pub fn init(module: *Module) !PostProcess {
}
}

var stack_validator = StackValidator.init(&temp_arena.allocator);
var jumps = InstrJumps.init(&module.arena.allocator);
var stack_validator = StackValidator.init(temp_arena.allocator());
var jumps = InstrJumps.init(module.arena.allocator());

for (module.code) |code, f| {
try stack_validator.process(import_funcs.items, module, f);
Expand All @@ -64,12 +64,13 @@ pub fn init(module: *Module) !PostProcess {
});
},
.br_table => {
const targets = try module.arena.allocator.alloc(JumpTarget, instr.arg.Array.len);
const targets = try module.arena.allocator().alloc(JumpTarget, instr.arg.Array.len);
for (targets) |*target, t| {
const block_level = instr.arg.Array.ptr[t];
const block = stack_validator.blocks.upFrom(instr_idx, block_level) orelse return error.JumpExceedsBlock;
const block_instr = code.body[block.start_idx];
const target_idx = if (block_instr.op == .loop) block.start_idx else block.end_idx;
_ = target_idx;
target.addr = @intCast(u32, if (block_instr.op == .loop) block.start_idx else block.end_idx);
target.has_value = block.data != .Empty;
}
Expand Down Expand Up @@ -151,7 +152,7 @@ pub fn StackLedger(comptime T: type) type {
top: ?*Node,
list: std.ArrayList(?Node),

pub fn init(allocator: *std.mem.Allocator) Self {
pub fn init(allocator: std.mem.Allocator) Self {
return .{
.top = null,
.list = std.ArrayList(?Node).init(allocator),
Expand All @@ -169,6 +170,8 @@ pub fn StackLedger(comptime T: type) type {
}

pub fn format(self: Self, comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
_ = opts;
try writer.writeAll("StackLedger(");
var iter = self.top;
while (iter) |node| {
Expand All @@ -181,7 +184,7 @@ pub fn StackLedger(comptime T: type) type {
pub fn reset(self: *Self, size: usize) !void {
self.top = null;
self.list.shrinkRetainingCapacity(0);
try self.list.ensureCapacity(size);
try self.list.ensureTotalCapacity(size);
}

pub fn upFrom(self: Self, start_idx: usize, levels: usize) ?*const Node {
Expand Down Expand Up @@ -233,7 +236,7 @@ const StackValidator = struct {
types: StackLedger(Module.Type.Value),
blocks: StackLedger(Module.Type.Block),

pub fn init(allocator: *std.mem.Allocator) StackValidator {
pub fn init(allocator: std.mem.Allocator) StackValidator {
return .{
.types = StackLedger(Module.Type.Value).init(allocator),
.blocks = StackLedger(Module.Type.Block).init(allocator),
Expand Down
Loading