Merge pull request #67 from mitchellh/wasm-shared

wasm: use shared, imported memory
This commit is contained in:
Mitchell Hashimoto
2022-12-24 16:37:38 -08:00
committed by GitHub
5 changed files with 52 additions and 9 deletions

View File

@ -112,16 +112,44 @@ pub fn build(b: *std.build.Builder) !void {
// wasm // wasm
{ {
// Build our Wasm target.
const wasm_target: std.zig.CrossTarget = .{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
.cpu_features_add = std.Target.wasm.featureSet(&.{
// We use this to explicitly request shared memory.
.atomics,
// Not explicitly used but compiler could use them if they want.
.bulk_memory,
.reference_types,
.sign_ext,
}),
};
// Whether we're using wasm shared memory. Some behaviors change.
// For now we require this but I wanted to make the code handle both
// up front.
const wasm_shared: bool = true;
exe_options.addOption(bool, "wasm_shared", wasm_shared);
const wasm = b.addSharedLibrary( const wasm = b.addSharedLibrary(
"ghostty-wasm", "ghostty-wasm",
"src/main_wasm.zig", "src/main_wasm.zig",
.{ .unversioned = {} }, .{ .unversioned = {} },
); );
wasm.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); wasm.setTarget(wasm_target);
wasm.setBuildMode(mode); wasm.setBuildMode(mode);
wasm.setOutputDir("zig-out"); wasm.setOutputDir("zig-out");
wasm.addOptions("build_options", exe_options); wasm.addOptions("build_options", exe_options);
// So that we can use web workers with our wasm binary
wasm.import_memory = true;
wasm.initial_memory = 65536 * 25;
wasm.max_memory = 65536 * 65536; // Maximum number of pages in wasm32
wasm.shared_memory = wasm_shared;
// Stack protector adds extern requirements that we don't satisfy. // Stack protector adds extern requirements that we don't satisfy.
wasm.stack_protector = false; wasm.stack_protector = false;
@ -136,7 +164,7 @@ pub fn build(b: *std.build.Builder) !void {
// it lets us test some basic functionality. // it lets us test some basic functionality.
const test_step = b.step("test-wasm", "Run all tests for wasm"); const test_step = b.step("test-wasm", "Run all tests for wasm");
const main_test = b.addTest("src/main_wasm.zig"); const main_test = b.addTest("src/main_wasm.zig");
main_test.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi }); main_test.setTarget(wasm_target);
main_test.addOptions("build_options", exe_options); main_test.addOptions("build_options", exe_options);
try addDeps(b, main_test, true); try addDeps(b, main_test, true);
test_step.dependOn(&main_test.step); test_step.dependOn(&main_test.step);

View File

@ -4,9 +4,11 @@ const zjs = new ZigJS();
const importObject = { const importObject = {
module: {}, module: {},
env: { env: {
memory: new WebAssembly.Memory({ initial: 25, maximum: 65536, shared: true }),
log: (ptr: number, len: number) => { log: (ptr: number, len: number) => {
const view = new DataView(zjs.memory.buffer, ptr, Number(len)); const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len);
const str = new TextDecoder('utf-8').decode(view); const data = arr.slice();
const str = new TextDecoder('utf-8').decode(data);
console.log(str); console.log(str);
}, },
}, },
@ -20,8 +22,8 @@ fetch(url.href).then(response =>
).then(bytes => ).then(bytes =>
WebAssembly.instantiate(bytes, importObject) WebAssembly.instantiate(bytes, importObject)
).then(results => { ).then(results => {
const memory = importObject.env.memory;
const { const {
memory,
malloc, malloc,
free, free,
face_new, face_new,

View File

@ -423,9 +423,17 @@ pub const Wasm = struct {
defer mem_buf.deinit(); defer mem_buf.deinit();
// Create an array that points to our buffer // Create an array that points to our buffer
const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray"); const arr = arr: {
defer Uint8ClampedArray.deinit(); const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray");
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len }); defer Uint8ClampedArray.deinit();
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len });
if (!wasm.shared_mem) break :arr arr;
// If we're sharing memory then we have to copy the data since
// we can't set ImageData directly using a SharedArrayBuffer.
defer arr.deinit();
break :arr try arr.call(js.Object, "slice", .{});
};
defer arr.deinit(); defer arr.deinit();
// Create the image data from our array // Create the image data from our array

View File

@ -1,6 +1,7 @@
//! This file contains helpers for wasm compilation. //! This file contains helpers for wasm compilation.
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const options = @import("build_options");
comptime { comptime {
if (!builtin.target.isWasm()) { if (!builtin.target.isWasm()) {
@ -8,6 +9,10 @@ comptime {
} }
} }
/// True if we're in shared memory mode. If true, then the memory buffer
/// in JS will be backed by a SharedArrayBuffer and some behaviors change.
pub const shared_mem = options.wasm_shared;
/// The allocator to use in wasm environments. /// The allocator to use in wasm environments.
/// ///
/// The return values of this should NOT be sent to the host environment /// The return values of this should NOT be sent to the host environment

2
vendor/zig-js vendored

@ -1 +1 @@
Subproject commit 5e3a5ce776f7b424022494a830f66ace224fe7ff Subproject commit c89c1965cc6bf6ede97c1b891b624ce5282853d1