authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-17 20:05:24+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-22 21:57:38+02:00
log6c1ab376ddcdbb05610487e5b813d42ff37da40d
tree759a47fde287b33ae3e40b88a83dc8723b98b379
parentd4ceb12ae9d409dbd52c1f5c96312a1e6ad7d6bc
signature Commit is signed but in an unrecognized format.

wasm: store `__zig_lt_errors_len` in linear data

Rather than using a function call to verify if an error fits within the global error set's length, we now store the error set' size in the .rodata segment of the linear memory and load that value onto the stack to check with the integer value.

2 files changed, 43 insertions(+), 45 deletions(-)

src/arch/wasm/CodeGen.zig+6-6
...@@ -3339,13 +3339,14 @@ fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3339,13 +3339,14 @@ fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3339fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3339fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3340 const un_op = func.air.instructions.items(.data)[inst].un_op;3340 const un_op = func.air.instructions.items(.data)[inst].un_op;
3341 const operand = try func.resolveInst(un_op);3341 const operand = try func.resolveInst(un_op);
3342 const sym_index = try func.bin_file.getGlobalSymbol("__zig_lt_errors_len", null);3342 const sym_index = try func.bin_file.getGlobalSymbol("__zig_errors_len", null);
3343 const errors_len = WValue{ .memory = sym_index };
33433344
3344 try func.emitWValue(operand);3345 try func.emitWValue(operand);
3345 try func.addLabel(.call, sym_index);3346 const errors_len_val = try func.load(errors_len, Type.err_int, 0);
3346 const result = try func.allocLocal(Type.bool);3347 const result = try func.cmp(.stack, errors_len_val, Type.err_int, .lt);
3347 try func.addLabel(.local_set, result.local.value);3348
3348 return func.finishAir(inst, result, &.{un_op});3349 return func.finishAir(inst, try result.toLocal(func, Type.bool), &.{un_op});
3349}3350}
33503351
3351fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3352fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -6518,7 +6519,6 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {...@@ -6518,7 +6519,6 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
65186519
6519fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6520fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6520 const ty_op = func.air.instructions.items(.data)[inst].ty_op;6521 const ty_op = func.air.instructions.items(.data)[inst].ty_op;
6521 if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
65226522
6523 const operand = try func.resolveInst(ty_op.operand);6523 const operand = try func.resolveInst(ty_op.operand);
6524 const error_set_ty = func.air.getRefType(ty_op.ty);6524 const error_set_ty = func.air.getRefType(ty_op.ty);
src/link/Wasm.zig+37-39
...@@ -1209,9 +1209,10 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -1209,9 +1209,10 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
1209 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);1209 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1210 }1210 }
1211 }1211 }
1212 if (wasm.undefs.fetchSwapRemove("__zig_lt_errors_len")) |kv| {1212 if (wasm.undefs.fetchSwapRemove("__zig_errors_len")) |kv| {
1213 const loc = try wasm.createSyntheticSymbol("__zig_lt_errors_len", .function);1213 const loc = try wasm.createSyntheticSymbol("__zig_errors_len", .data);
1214 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);1214 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
1215 _ = wasm.resolved_symbols.swapRemove(kv.value);
1215 }1216 }
1216}1217}
12171218
...@@ -2189,44 +2190,41 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -2189,44 +2190,41 @@ fn setupInitFunctions(wasm: *Wasm) !void {
2189 std.sort.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);2190 std.sort.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
2190}2191}
21912192
2192/// Generates the function which verifies if an integer value is less than the2193/// Generates an atom containing the global error set' size.
2193/// amount of error values. This will only be generated if the symbol exists.2194/// This will only be generated if the symbol exists.
2194fn setupLtErrorsLenFunction(wasm: *Wasm) !void {2195fn setupErrorsLen(wasm: *Wasm) !void {
2195 if (wasm.findGlobalSymbol("__zig_lt_errors_len") == null) return;2196 const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;
2196 const errors_len = wasm.base.options.module.?.global_error_set.count();
2197
2198 var body_list = std.ArrayList(u8).init(wasm.base.allocator);
2199 defer body_list.deinit();
2200 const writer = body_list.writer();
2201
2202 {
2203 // generates bytecode for the following function:
2204 // fn (index: u16) bool {
2205 // return index < errors_len;
2206 // }
2207
2208 // no locals
2209 try leb.writeULEB128(writer, @as(u32, 0));
2210
2211 // get argument
2212 try writer.writeByte(std.wasm.opcode(.local_get));
2213 try leb.writeULEB128(writer, @as(u32, 0));
2214
2215 // get error length
2216 try writer.writeByte(std.wasm.opcode(.i32_const));
2217 try leb.writeULEB128(writer, @intCast(u32, errors_len));
2218
2219 try writer.writeByte(std.wasm.opcode(.i32_lt_u));
2220
2221 // stack values are implicit return values so keep the value
2222 // on the stack and end the function.
22232197
2224 // end function2198 const errors_len = wasm.base.options.module.?.global_error_set.count();
2225 try writer.writeByte(std.wasm.opcode(.end));2199 // overwrite existing atom if it already exists (maybe the error set has increased)
2226 }2200 // if not, allcoate a new atom.
2201 const atom_index = if (wasm.symbol_atom.get(loc)) |index| blk: {
2202 const atom = wasm.getAtomPtr(index);
2203 if (atom.next) |next_atom_index| {
2204 const next_atom = wasm.getAtomPtr(next_atom_index);
2205 next_atom.prev = atom.prev;
2206 atom.next = null;
2207 }
2208 if (atom.prev) |prev_index| {
2209 const prev_atom = wasm.getAtomPtr(prev_index);
2210 prev_atom.next = atom.next;
2211 atom.prev = null;
2212 }
2213 atom.deinit(wasm);
2214 break :blk index;
2215 } else new_atom: {
2216 const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
2217 try wasm.symbol_atom.put(wasm.base.allocator, loc, atom_index);
2218 try wasm.managed_atoms.append(wasm.base.allocator, undefined);
2219 break :new_atom atom_index;
2220 };
2221 const atom = wasm.getAtomPtr(atom_index);
2222 atom.* = Atom.empty;
2223 atom.sym_index = loc.index;
2224 atom.size = 2;
2225 try atom.code.writer(wasm.base.allocator).writeIntLittle(u16, @intCast(u16, errors_len));
22272226
2228 const func_type: std.wasm.Type = .{ .params = &.{std.wasm.Valtype.i32}, .returns = &.{std.wasm.Valtype.i32} };2227 try wasm.parseAtom(atom_index, .{ .data = .read_only });
2229 try wasm.createSyntheticFunction("__zig_lt_errors_len", func_type, &body_list);
2230}2228}
22312229
2232/// Creates a function body for the `__wasm_call_ctors` symbol.2230/// Creates a function body for the `__wasm_call_ctors` symbol.
...@@ -3361,6 +3359,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -3361,6 +3359,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3361 // So we can rebuild the binary file on each incremental update3359 // So we can rebuild the binary file on each incremental update
3362 defer wasm.resetState();3360 defer wasm.resetState();
3363 try wasm.setupInitFunctions();3361 try wasm.setupInitFunctions();
3362 try wasm.setupErrorsLen();
3364 try wasm.setupStart();3363 try wasm.setupStart();
3365 try wasm.setupImports();3364 try wasm.setupImports();
3366 if (wasm.base.options.module) |mod| {3365 if (wasm.base.options.module) |mod| {
...@@ -3423,7 +3422,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -3423,7 +3422,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3423 try wasm.setupInitMemoryFunction();3422 try wasm.setupInitMemoryFunction();
3424 try wasm.setupTLSRelocationsFunction();3423 try wasm.setupTLSRelocationsFunction();
3425 try wasm.initializeTLSFunction();3424 try wasm.initializeTLSFunction();
3426 try wasm.setupLtErrorsLenFunction();
3427 try wasm.setupExports();3425 try wasm.setupExports();
3428 try wasm.writeToFile(enabled_features, emit_features_count, arena);3426 try wasm.writeToFile(enabled_features, emit_features_count, arena);
3429}3427}