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`.
This commit is contained in:
Luuk de Gram 2023-03-12 16:02:02 +01:00
parent b0024c4884
commit 09abd53da7
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664
3 changed files with 40 additions and 12 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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 {