authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-12 16:02:02+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-18 20:13:29+01:00
log09abd53da701a5ef4db4b81463e2535e192a5eee
tree50e03af2943873007bed1e1e4e71f7de89c7e970
parentb0024c48841b78a962918cd4ab20459ba6451050
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: refactor Limits and add flags

Rather than adding the flags "on-demand" during limits writing, we now properly parse them and store the flags within the limits itself. This also allows us to store whether we're using shared- memory or not. Only when the correct flag is set will we set the max within `Limits` or else we will leave it `undefined`.

3 files changed, 40 insertions(+), 12 deletions(-)

lib/std/wasm.zig+15-1
......@@ -551,8 +551,22 @@ test "Wasm - valtypes" {
551551
552552/// Limits classify the size range of resizeable storage associated with memory types and table types.
553553pub const Limits = struct {
554 flags: u8,
554555 min: u32,
555 max: ?u32,
556 max: u32,
557
558 pub const Flags = enum(u8) {
559 WASM_LIMITS_FLAG_HAS_MAX = 0x1,
560 WASM_LIMITS_FLAG_IS_SHARED = 0x2,
561 };
562
563 pub fn hasFlag(limits: Limits, flag: Flags) bool {
564 return limits.flags & @enumToInt(flag) != 0;
565 }
566
567 pub fn setFlag(limits: *Limits, flag: Flags) void {
568 limits.flags |= @enumToInt(flag);
569 }
556570};
557571
558572/// Initialization expressions are used to set the initial value on an object
src/link/Wasm.zig+17-8
......@@ -111,7 +111,11 @@ functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.
111111/// Output global section
112112wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
113113/// Memory section
114memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
114memories: std.wasm.Memory = .{ .limits = .{
115 .min = 0,
116 .max = undefined,
117 .flags = 0,
118} },
115119/// Output table section
116120tables: std.ArrayListUnmanaged(std.wasm.Table) = .{},
117121/// Output export section
......@@ -396,7 +400,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
396400 const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);
397401 const symbol = loc.getSymbol(wasm_bin);
398402 const table: std.wasm.Table = .{
399 .limits = .{ .min = 0, .max = null }, // will be overwritten during `mapFunctionTable`
403 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
400404 .reftype = .funcref,
401405 };
402406 if (options.output_mode == .Obj or options.import_table) {
......@@ -1524,7 +1528,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
15241528 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
15251529 const symbol = sym_loc.getSymbol(wasm);
15261530 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
1527 table.limits = .{ .min = index, .max = index };
1531 table.limits = .{ .min = index, .max = index, .flags = 0x1 };
15281532 }
15291533}
15301534
......@@ -2236,8 +2240,9 @@ fn setupMemory(wasm: *Wasm) !void {
22362240 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
22372241 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
22382242 const sym = loc.getSymbol(wasm);
2239 sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{
2240 .global_type = .{ .valtype = .i32_const, .mutable = false },
2243 sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
2244 try wasm.wasm_globals.append(wasm.base.allocator, .{
2245 .global_type = .{ .valtype = .i32, .mutable = false },
22412246 .init = .{ .i32_const = @intCast(i32, memory_ptr) },
22422247 });
22432248 }
......@@ -2305,6 +2310,10 @@ fn setupMemory(wasm: *Wasm) !void {
23052310 return error.MemoryTooBig;
23062311 }
23072312 wasm.memories.limits.max = @intCast(u32, max_memory / page_size);
2313 wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX);
2314 if (wasm.base.options.shared_memory) {
2315 wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED);
2316 }
23082317 log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});
23092318 }
23102319}
......@@ -3517,10 +3526,10 @@ fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: a
35173526}
35183527
35193528fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
3520 try leb.writeULEB128(writer, @boolToInt(limits.max != null));
3529 try writer.writeByte(limits.flags);
35213530 try leb.writeULEB128(writer, limits.min);
3522 if (limits.max) |max| {
3523 try leb.writeULEB128(writer, max);
3531 if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
3532 try leb.writeULEB128(writer, limits.max);
35243533 }
35253534}
35263535
src/link/Wasm/Object.zig+8-3
......@@ -852,12 +852,17 @@ fn readEnum(comptime T: type, reader: anytype) !T {
852852}
853853
854854fn readLimits(reader: anytype) !std.wasm.Limits {
855 const flags = try readLeb(u1, reader);
855 const flags = try reader.readByte();
856856 const min = try readLeb(u32, reader);
857 return std.wasm.Limits{
857 var limits: std.wasm.Limits = .{
858 .flags = flags,
858859 .min = min,
859 .max = if (flags == 0) null else try readLeb(u32, reader),
860 .max = undefined,
860861 };
862 if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
863 limits.max = try readLeb(u32, reader);
864 }
865 return limits;
861866}
862867
863868fn readInit(reader: anytype) !std.wasm.InitExpression {