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" {...@@ -551,8 +551,22 @@ test "Wasm - valtypes" {
551551
552/// Limits classify the size range of resizeable storage associated with memory types and table types.552/// Limits classify the size range of resizeable storage associated with memory types and table types.
553pub const Limits = struct {553pub const Limits = struct {
554 flags: u8,
554 min: u32,555 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 }
556};570};
557571
558/// Initialization expressions are used to set the initial value on an object572/// 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....@@ -111,7 +111,11 @@ functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.
111/// Output global section111/// Output global section
112wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},112wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
113/// Memory section113/// 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} },
115/// Output table section119/// Output table section
116tables: std.ArrayListUnmanaged(std.wasm.Table) = .{},120tables: std.ArrayListUnmanaged(std.wasm.Table) = .{},
117/// Output export section121/// Output export section
...@@ -396,7 +400,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -396,7 +400,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
396 const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);400 const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table);
397 const symbol = loc.getSymbol(wasm_bin);401 const symbol = loc.getSymbol(wasm_bin);
398 const table: std.wasm.Table = .{402 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`
400 .reftype = .funcref,404 .reftype = .funcref,
401 };405 };
402 if (options.output_mode == .Obj or options.import_table) {406 if (options.output_mode == .Obj or options.import_table) {
...@@ -1524,7 +1528,7 @@ fn mapFunctionTable(wasm: *Wasm) void {...@@ -1524,7 +1528,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
1524 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;1528 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
1525 const symbol = sym_loc.getSymbol(wasm);1529 const symbol = sym_loc.getSymbol(wasm);
1526 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];1530 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 };
1528 }1532 }
1529}1533}
15301534
...@@ -2236,8 +2240,9 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2236,8 +2240,9 @@ fn setupMemory(wasm: *Wasm) !void {
2236 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {2240 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
2237 if (wasm.findGlobalSymbol("__tls_base")) |loc| {2241 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2238 const sym = loc.getSymbol(wasm);2242 const sym = loc.getSymbol(wasm);
2239 sym.index = try wasm.globals.append(wasm.base.allocator, wasm.imports.globalCount, .{2243 sym.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
2240 .global_type = .{ .valtype = .i32_const, .mutable = false },2244 try wasm.wasm_globals.append(wasm.base.allocator, .{
2245 .global_type = .{ .valtype = .i32, .mutable = false },
2241 .init = .{ .i32_const = @intCast(i32, memory_ptr) },2246 .init = .{ .i32_const = @intCast(i32, memory_ptr) },
2242 });2247 });
2243 }2248 }
...@@ -2305,6 +2310,10 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2305,6 +2310,10 @@ fn setupMemory(wasm: *Wasm) !void {
2305 return error.MemoryTooBig;2310 return error.MemoryTooBig;
2306 }2311 }
2307 wasm.memories.limits.max = @intCast(u32, max_memory / page_size);2312 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 }
2308 log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});2317 log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});
2309 }2318 }
2310}2319}
...@@ -3517,10 +3526,10 @@ fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: a...@@ -3517,10 +3526,10 @@ fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: a
3517}3526}
35183527
3519fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {3528fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
3520 try leb.writeULEB128(writer, @boolToInt(limits.max != null));3529 try writer.writeByte(limits.flags);
3521 try leb.writeULEB128(writer, limits.min);3530 try leb.writeULEB128(writer, limits.min);
3522 if (limits.max) |max| {3531 if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
3523 try leb.writeULEB128(writer, max);3532 try leb.writeULEB128(writer, limits.max);
3524 }3533 }
3525}3534}
35263535
src/link/Wasm/Object.zig+8-3
...@@ -852,12 +852,17 @@ fn readEnum(comptime T: type, reader: anytype) !T {...@@ -852,12 +852,17 @@ fn readEnum(comptime T: type, reader: anytype) !T {
852}852}
853853
854fn readLimits(reader: anytype) !std.wasm.Limits {854fn readLimits(reader: anytype) !std.wasm.Limits {
855 const flags = try readLeb(u1, reader);855 const flags = try reader.readByte();
856 const min = try readLeb(u32, reader);856 const min = try readLeb(u32, reader);
857 return std.wasm.Limits{857 var limits: std.wasm.Limits = .{
858 .flags = flags,
858 .min = min,859 .min = min,
859 .max = if (flags == 0) null else try readLeb(u32, reader),860 .max = undefined,
860 };861 };
862 if (limits.hasFlag(.WASM_LIMITS_FLAG_HAS_MAX)) {
863 limits.max = try readLeb(u32, reader);
864 }
865 return limits;
861}866}
862867
863fn readInit(reader: anytype) !std.wasm.InitExpression {868fn readInit(reader: anytype) !std.wasm.InitExpression {