Skip to main content

lib/quickbeam/wasm_common.zig

const std = @import("std");
const wamr = @import("wamr.zig").wamr;
const wasm_host_imports = @import("wasm_host_imports.zig");

var wamr_initialized = false;

fn copy_error_buf(err_buf: []u8, msg: []const u8) void {
    if (err_buf.len == 0) return;
    const copy_len = @min(msg.len, err_buf.len - 1);
    std.mem.copyForwards(u8, err_buf[0..copy_len], msg[0..copy_len]);
    err_buf[copy_len] = 0;
}

pub fn ensure_init() bool {
    if (wamr_initialized) return true;
    if (wamr.wamr_bridge_init()) {
        wamr_initialized = true;
        return true;
    }
    return false;
}

pub const ManagedInstance = struct {
    inst: *wamr.WamrInstance,
    imports: ?wasm_host_imports.PreparedImports = null,

    pub fn destroy(self: *ManagedInstance) void {
        wamr.wamr_bridge_stop(self.inst);
        if (self.imports) |*imports| {
            wamr.wamr_bridge_unregister_native_modules(@ptrCast(imports.registrations.ptr), @intCast(imports.registrations.len));
            imports.deinit();
        }
        std.heap.c_allocator.destroy(self);
    }
};

pub fn start_managed_instance(
    mod: *wamr.WamrModule,
    stack_size: u32,
    heap_size: u32,
    prepared_imports: ?*wasm_host_imports.PreparedImports,
    err_buf: []u8,
) ?*ManagedInstance {
    const imports = if (prepared_imports) |value|
        if (value.registrations.len > 0) value else null
    else
        null;

    const inst = if (imports) |value|
        wamr.wamr_bridge_start_with_native_modules(mod, stack_size, heap_size, @ptrCast(value.registrations.ptr), @intCast(value.registrations.len), err_buf.ptr, @intCast(err_buf.len))
    else
        wamr.wamr_bridge_start(mod, stack_size, heap_size, err_buf.ptr, @intCast(err_buf.len));
    if (inst == null) return null;

    const inst_nn = inst orelse return null;
    const managed = std.heap.c_allocator.create(ManagedInstance) catch {
        wamr.wamr_bridge_stop(inst_nn);
        if (imports) |value| {
            wamr.wamr_bridge_unregister_native_modules(@ptrCast(value.registrations.ptr), @intCast(value.registrations.len));
            value.deinit();
            value.* = wasm_host_imports.PreparedImports.empty();
        }
        copy_error_buf(err_buf, "resource alloc failed");
        return null;
    };

    managed.* = .{
        .inst = inst_nn,
        .imports = if (imports) |value| value.* else null,
    };

    if (imports) |value| {
        value.* = wasm_host_imports.PreparedImports.empty();
    }

    return managed;
}