From 09abd53da701a5ef4db4b81463e2535e192a5eee Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 12 Mar 2023 16:02:02 +0100 Subject: [PATCH] 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`. --- lib/std/wasm.zig | 16 +++++++++++++++- src/link/Wasm.zig | 25 +++++++++++++++++-------- src/link/Wasm/Object.zig | 11 ++++++++--- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig index 25a0bb7abf..35d0ba4866 100644 --- a/lib/std/wasm.zig +++ b/lib/std/wasm.zig @@ -551,8 +551,22 @@ test "Wasm - valtypes" { /// Limits classify the size range of resizeable storage associated with memory types and table types. pub const Limits = struct { + flags: u8, min: u32, - max: ?u32, + max: u32, + + pub const Flags = enum(u8) { + WASM_LIMITS_FLAG_HAS_MAX = 0x1, + WASM_LIMITS_FLAG_IS_SHARED = 0x2, + }; + + pub fn hasFlag(limits: Limits, flag: Flags) bool { + return limits.flags & @enumToInt(flag) != 0; + } + + pub fn setFlag(limits: *Limits, flag: Flags) void { + limits.flags |= @enumToInt(flag); + } }; /// Initialization expressions are used to set the initial value on an object diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 287f880d92..50846eecf1 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -111,7 +111,11 @@ functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std. /// Output global section wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, /// Memory section -memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, +memories: std.wasm.Memory = .{ .limits = .{ + .min = 0, + .max = undefined, + .flags = 0, +} }, /// Output table section tables: std.ArrayListUnmanaged(std.wasm.Table) = .{}, /// Output export section @@ -396,7 +400,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table); const symbol = loc.getSymbol(wasm_bin); const table: std.wasm.Table = .{ - .limits = .{ .min = 0, .max = null }, // will be overwritten during `mapFunctionTable` + .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` .reftype = .funcref, }; if (options.output_mode == .Obj or options.import_table) { @@ -1524,7 +1528,7 @@ fn mapFunctionTable(wasm: *Wasm) void { const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; const symbol = sym_loc.getSymbol(wasm); const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; - table.limits = .{ .min = index, .max = index }; + table.limits = .{ .min = index, .max = index, .flags = 0x1 }; } } @@ -2236,8 +2240,9 @@ fn setupMemory(wasm: *Wasm) !void { if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { if (wasm.findGlobalSymbol("__tls_base")) |loc| { const sym = loc.getSymbol(wasm); - sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{ - .global_type = .{ .valtype = .i32_const, .mutable = false }, + sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count; + try wasm.wasm_globals.append(wasm.base.allocator, .{ + .global_type = .{ .valtype = .i32, .mutable = false }, .init = .{ .i32_const = @intCast(i32, memory_ptr) }, }); } @@ -2305,6 +2310,10 @@ fn setupMemory(wasm: *Wasm) !void { return error.MemoryTooBig; } wasm.memories.limits.max = @intCast(u32, max_memory / page_size); + wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX); + if (wasm.base.options.shared_memory) { + wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED); + } log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max}); } } @@ -3517,10 +3526,10 @@ fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: a } fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void { - try leb.writeULEB128(writer, @boolToInt(limits.max != null)); + try writer.writeByte(limits.flags); try leb.writeULEB128(writer, limits.min); - if (limits.max) |max| { - try leb.writeULEB128(writer, max); + if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) { + try leb.writeULEB128(writer, limits.max); } } diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 4b918064c1..92336efbf2 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -852,12 +852,17 @@ fn readEnum(comptime T: type, reader: anytype) !T { } fn readLimits(reader: anytype) !std.wasm.Limits { - const flags = try readLeb(u1, reader); + const flags = try reader.readByte(); const min = try readLeb(u32, reader); - return std.wasm.Limits{ + var limits: std.wasm.Limits = .{ + .flags = flags, .min = min, - .max = if (flags == 0) null else try readLeb(u32, reader), + .max = undefined, }; + if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) { + limits.max = try readLeb(u32, reader); + } + return limits; } fn readInit(reader: anytype) !std.wasm.InitExpression {