authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-19 15:15:53-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log389b29fd8c13707891486dfed64ed2b9df3f1a39
tree1a0f7e2517e95cf1921e8e19c2045bec98d94d2e
parent4f8a6b0888c8d1df87d254b68344bb99edcfe57c

wasm linker: avoid recursion in lowerZcuData

instead of recursion, callers of the function are responsible for checking the respective tables that might have new entries in them and then calling lowerZcuData again.

3 files changed, 80 insertions(+), 28 deletions(-)

src/arch/wasm/CodeGen.zig+4-4
......@@ -1042,9 +1042,9 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
10421042 try cg.addInst(.{
10431043 .tag = .uav_ref,
10441044 .data = if (is_obj) .{
1045 .uav_obj = try wasm.refUavObj(cg.pt, uav.ip_index),
1045 .uav_obj = try wasm.refUavObj(uav.ip_index),
10461046 } else .{
1047 .uav_exe = try wasm.refUavExe(cg.pt, uav.ip_index),
1047 .uav_exe = try wasm.refUavExe(uav.ip_index),
10481048 },
10491049 });
10501050 } else {
......@@ -1052,10 +1052,10 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
10521052 .tag = .uav_ref_off,
10531053 .data = .{
10541054 .payload = if (is_obj) try cg.addExtra(Mir.UavRefOffObj{
1055 .uav_obj = try wasm.refUavObj(cg.pt, uav.ip_index),
1055 .uav_obj = try wasm.refUavObj(uav.ip_index),
10561056 .offset = uav.offset,
10571057 }) else try cg.addExtra(Mir.UavRefOffExe{
1058 .uav_exe = try wasm.refUavExe(cg.pt, uav.ip_index),
1058 .uav_exe = try wasm.refUavExe(uav.ip_index),
10591059 .offset = uav.offset,
10601060 }),
10611061 },
src/codegen.zig+1-1
......@@ -676,7 +676,7 @@ fn lowerUavRef(
676676 } else {
677677 try wasm.uav_fixups.ensureUnusedCapacity(gpa, 1);
678678 wasm.uav_fixups.appendAssumeCapacity(.{
679 .uavs_exe_index = try wasm.refUavExe(pt, uav.val),
679 .uavs_exe_index = try wasm.refUavExe(uav.val),
680680 .offset = @intCast(code.items.len),
681681 });
682682 }
src/link/Wasm.zig+75-23
......@@ -2364,24 +2364,50 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
23642364 return;
23652365 }
23662366
2367 const zcu_data = try lowerZcuData(wasm, pt, nav_init);
2368
2369 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
2370
23712367 if (is_obj) {
2372 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
2373 gop.value_ptr.* = zcu_data;
2374 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_obj = @enumFromInt(gop.index) }), {});
2368 var uavs_i = wasm.uavs_obj.entries.len;
2369 var navs_i = wasm.navs_obj.entries.len;
2370 _ = try refNavObj(wasm, nav_index); // Possibly creates an entry in `Wasm.navs_obj`.
2371 while (true) {
2372 while (navs_i < wasm.navs_obj.entries.len) : (navs_i += 1) {
2373 const elem_nav = ip.getNav(wasm.navs_obj.keys()[navs_i]);
2374 const elem_nav_init = switch (ip.indexToKey(elem_nav.status.resolved.val)) {
2375 .variable => |variable| variable.init,
2376 else => elem_nav.status.resolved.val,
2377 };
2378 // Call to `lowerZcuData` here possibly creates more entries in these tables.
2379 wasm.navs_obj.values()[navs_i] = try lowerZcuData(wasm, pt, elem_nav_init);
2380 }
2381 while (uavs_i < wasm.uavs_obj.entries.len) : (uavs_i += 1) {
2382 // Call to `lowerZcuData` here possibly creates more entries in these tables.
2383 wasm.uavs_obj.values()[uavs_i] = try lowerZcuData(wasm, pt, wasm.uavs_obj.keys()[uavs_i]);
2384 }
2385 if (navs_i >= wasm.navs_obj.entries.len) break;
2386 }
2387 } else {
2388 var uavs_i = wasm.uavs_exe.entries.len;
2389 var navs_i = wasm.navs_exe.entries.len;
2390 _ = try refNavExe(wasm, nav_index); // Possibly creates an entry in `Wasm.navs_exe`.
2391 while (true) {
2392 while (navs_i < wasm.navs_exe.entries.len) : (navs_i += 1) {
2393 const elem_nav = ip.getNav(wasm.navs_exe.keys()[navs_i]);
2394 const elem_nav_init = switch (ip.indexToKey(elem_nav.status.resolved.val)) {
2395 .variable => |variable| variable.init,
2396 else => elem_nav.status.resolved.val,
2397 };
2398 // Call to `lowerZcuData` here possibly creates more entries in these tables.
2399 const zcu_data = try lowerZcuData(wasm, pt, elem_nav_init);
2400 assert(zcu_data.relocs.len == 0);
2401 wasm.navs_exe.values()[navs_i].code = zcu_data.code;
2402 }
2403 while (uavs_i < wasm.uavs_exe.entries.len) : (uavs_i += 1) {
2404 // Call to `lowerZcuData` here possibly creates more entries in these tables.
2405 const zcu_data = try lowerZcuData(wasm, pt, wasm.uavs_exe.keys()[uavs_i]);
2406 wasm.uavs_exe.values()[uavs_i].code = zcu_data.code;
2407 }
2408 if (navs_i >= wasm.navs_exe.entries.len) break;
2409 }
23752410 }
2376
2377 assert(zcu_data.relocs.len == 0);
2378
2379 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
2380 gop.value_ptr.* = .{
2381 .code = zcu_data.code,
2382 .count = if (gop.found_existing) gop.value_ptr.count else 0,
2383 };
2384 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_exe = @enumFromInt(gop.index) }), {});
23852411}
23862412
23872413pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
......@@ -3346,18 +3372,23 @@ pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableInd
33463372 return @enumFromInt(gop.index);
33473373}
33483374
3349pub fn refUavObj(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !UavsObjIndex {
3375pub fn refUavObj(wasm: *Wasm, ip_index: InternPool.Index) !UavsObjIndex {
33503376 const comp = wasm.base.comp;
33513377 const gpa = comp.gpa;
33523378 assert(comp.config.output_mode == .Obj);
3379 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
33533380 const gop = try wasm.uavs_obj.getOrPut(gpa, ip_index);
3354 if (!gop.found_existing) gop.value_ptr.* = try lowerZcuData(wasm, pt, ip_index);
3381 if (!gop.found_existing) gop.value_ptr.* = .{
3382 // Lowering the value is delayed to avoid recursion.
3383 .code = undefined,
3384 .relocs = undefined,
3385 };
33553386 const uav_index: UavsObjIndex = @enumFromInt(gop.index);
3356 try wasm.data_segments.put(gpa, .pack(wasm, .{ .uav_obj = uav_index }), {});
3387 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .uav_obj = uav_index }), {});
33573388 return uav_index;
33583389}
33593390
3360pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !UavsExeIndex {
3391pub fn refUavExe(wasm: *Wasm, ip_index: InternPool.Index) !UavsExeIndex {
33613392 const comp = wasm.base.comp;
33623393 const gpa = comp.gpa;
33633394 assert(comp.config.output_mode != .Obj);
......@@ -3365,9 +3396,9 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua
33653396 if (gop.found_existing) {
33663397 gop.value_ptr.count += 1;
33673398 } else {
3368 const zcu_data = try lowerZcuData(wasm, pt, ip_index);
33693399 gop.value_ptr.* = .{
3370 .code = zcu_data.code,
3400 // Lowering the value is delayed to avoid recursion.
3401 .code = undefined,
33713402 .count = 1,
33723403 };
33733404 }
......@@ -3376,6 +3407,21 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua
33763407 return uav_index;
33773408}
33783409
3410pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
3411 const comp = wasm.base.comp;
3412 const gpa = comp.gpa;
3413 assert(comp.config.output_mode != .Obj);
3414 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
3415 if (!gop.found_existing) gop.value_ptr.* = .{
3416 // Lowering the value is delayed to avoid recursion.
3417 .code = undefined,
3418 .relocs = undefined,
3419 };
3420 const navs_obj_index: NavsObjIndex = @enumFromInt(gop.index);
3421 try wasm.data_segments.put(gpa, .pack(wasm, .{ .nav_obj = navs_obj_index }), {});
3422 return navs_obj_index;
3423}
3424
33793425pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
33803426 const comp = wasm.base.comp;
33813427 const gpa = comp.gpa;
......@@ -3385,8 +3431,9 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
33853431 gop.value_ptr.count += 1;
33863432 } else {
33873433 gop.value_ptr.* = .{
3434 // Lowering the value is delayed to avoid recursion.
33883435 .code = undefined,
3389 .count = 1,
3436 .count = 0,
33903437 };
33913438 }
33923439 const navs_exe_index: NavsExeIndex = @enumFromInt(gop.index);
......@@ -3481,6 +3528,11 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {
34813528 return mem.eql(u8, s, ".bss") or mem.startsWith(u8, s, ".bss.");
34823529}
34833530
3531/// After this function is called, there may be additional entries in
3532/// `Wasm.uavs_obj`, `Wasm.uavs_exe`, `Wasm.navs_obj`, and `Wasm.navs_exe`
3533/// which have uninitialized code and relocations. This function is
3534/// non-recursive, so callers must coordinate additional calls to populate
3535/// those entries.
34843536fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {
34853537 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
34863538 const relocs_start: u32 = @intCast(wasm.out_relocs.len);