authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-07-17 20:22:25+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-07-19 17:22:46+02:00
log1a3304ed236b60cd31c790bae929a78c58c9d33e
treef0cee69c44e49054a0641f6a6152578e46ffd2b6
parent3fd6e93f4f6f34658d5e198064f54e1dad09e241
signaturelock-open Commit is signed but in an unrecognized format.

test/link: add shared-memory test for WebAssembly


4 files changed, 100 insertions(+), 3 deletions(-)

lib/std/Build/Step/CheckObject.zig+14-3
......@@ -1012,6 +1012,10 @@ const WasmDumper = struct {
10121012 const start = try std.leb.readULEB128(u32, reader);
10131013 try writer.print("\nstart {d}\n", .{start});
10141014 },
1015 .data_count => {
1016 const count = try std.leb.readULEB128(u32, reader);
1017 try writer.print("\ncount {d}\n", .{count});
1018 },
10151019 else => {}, // skip unknown sections
10161020 }
10171021 }
......@@ -1143,9 +1147,16 @@ const WasmDumper = struct {
11431147 .data => {
11441148 var i: u32 = 0;
11451149 while (i < entries) : (i += 1) {
1146 const index = try std.leb.readULEB128(u32, reader);
1150 const flags = try std.leb.readULEB128(u32, reader);
1151 const index = if (flags & 0x02 != 0)
1152 try std.leb.readULEB128(u32, reader)
1153 else
1154 0;
11471155 try writer.print("memory index 0x{x}\n", .{index});
1148 try parseDumpInit(step, reader, writer);
1156 if (flags == 0) {
1157 try parseDumpInit(step, reader, writer);
1158 }
1159
11491160 const size = try std.leb.readULEB128(u32, reader);
11501161 try writer.print("size {d}\n", .{size});
11511162 try reader.skipBytes(size, .{}); // we do not care about the content of the segments
......@@ -1174,7 +1185,7 @@ const WasmDumper = struct {
11741185 }
11751186
11761187 fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void {
1177 const byte = try std.leb.readULEB128(u8, reader);
1188 const byte = try reader.readByte();
11781189 const opcode = std.meta.intToEnum(std.wasm.Opcode, byte) catch {
11791190 return step.fail("invalid wasm opcode '{d}'", .{byte});
11801191 };
lib/std/Build/Step/Compile.zig+4
......@@ -65,6 +65,7 @@ sanitize_thread: bool,
6565rdynamic: bool,
6666dwarf_format: ?std.dwarf.Format = null,
6767import_memory: bool = false,
68export_memory: bool = false,
6869/// For WebAssembly targets, this will allow for undefined symbols to
6970/// be imported from the host environment.
7071import_symbols: bool = false,
......@@ -1662,6 +1663,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16621663 if (self.import_memory) {
16631664 try zig_args.append("--import-memory");
16641665 }
1666 if (self.export_memory) {
1667 try zig_args.append("--export-memory");
1668 }
16651669 if (self.import_symbols) {
16661670 try zig_args.append("--import-symbols");
16671671 }
test/link/wasm/shared-memory/build.zig created+77
......@@ -0,0 +1,77 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test");
5 b.default_step = test_step;
6
7 add(b, test_step, .Debug);
8
9 // Enable the following build modes once garbage-collection is implemented properly.
10 // add(b, test_step, .ReleaseFast);
11 // add(b, test_step, .ReleaseSmall);
12 // add(b, test_step, .ReleaseSafe);
13}
14
15fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {
16 {
17 const lib = b.addSharedLibrary(.{
18 .name = "lib",
19 .root_source_file = .{ .path = "lib.zig" },
20 .target = .{
21 .cpu_arch = .wasm32,
22 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
23 .cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }),
24 .os_tag = .freestanding,
25 },
26 .optimize = optimize_mode,
27 });
28 lib.use_lld = false;
29 lib.strip = false;
30 lib.import_memory = true;
31 lib.export_memory = true;
32 lib.shared_memory = true;
33 lib.max_memory = 67108864;
34 lib.single_threaded = false;
35 lib.export_symbol_names = &.{"foo"};
36
37 const check_lib = lib.checkObject();
38
39 check_lib.checkStart("Section import");
40 check_lib.checkNext("entries 1");
41 check_lib.checkNext("module env");
42 check_lib.checkNext("name memory"); // ensure we are importing memory
43
44 check_lib.checkStart("Section export");
45 check_lib.checkNext("entries 2");
46 check_lib.checkNext("name memory"); // ensure we also export memory again
47
48 // This section *must* be emit as the start function is set to the index
49 // of __wasm_init_memory
50 check_lib.checkStart("Section start");
51
52 // This section is only and *must* be emit when shared-memory is enabled
53 check_lib.checkStart("Section data_count");
54 check_lib.checkNext("count 3");
55
56 check_lib.checkStart("Section custom");
57 check_lib.checkNext("name name");
58 check_lib.checkNext("type function");
59 check_lib.checkNext("name __wasm_init_memory");
60 check_lib.checkNext("name __wasm_init_tls");
61 check_lib.checkNext("type global");
62 check_lib.checkNext("name __tls_size");
63 check_lib.checkNext("name __tls_align");
64 check_lib.checkNext("name __tls_base");
65
66 check_lib.checkNext("type data_segment");
67 check_lib.checkNext("names 3");
68 check_lib.checkNext("index 0");
69 check_lib.checkNext("name .rodata");
70 check_lib.checkNext("index 1");
71 check_lib.checkNext("name .bss");
72 check_lib.checkNext("index 2");
73 check_lib.checkNext("name .tdata");
74
75 test_step.dependOn(&check_lib.step);
76 }
77}
test/link/wasm/shared-memory/lib.zig created+5
......@@ -0,0 +1,5 @@
1threadlocal var some_tls_global: u32 = 1;
2
3export fn foo() void {
4 some_tls_global = 2;
5}