Commit 09abd53da7

Luuk de Gram <luuk@degram.dev>
2023-03-12 16:02:02
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`.
1 parent b0024c4
Changed files (3)
lib
src
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
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 {
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);
     }
 }