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 {...@@ -1042,9 +1042,9 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
1042 try cg.addInst(.{1042 try cg.addInst(.{
1043 .tag = .uav_ref,1043 .tag = .uav_ref,
1044 .data = if (is_obj) .{1044 .data = if (is_obj) .{
1045 .uav_obj = try wasm.refUavObj(cg.pt, uav.ip_index),1045 .uav_obj = try wasm.refUavObj(uav.ip_index),
1046 } else .{1046 } else .{
1047 .uav_exe = try wasm.refUavExe(cg.pt, uav.ip_index),1047 .uav_exe = try wasm.refUavExe(uav.ip_index),
1048 },1048 },
1049 });1049 });
1050 } else {1050 } else {
...@@ -1052,10 +1052,10 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {...@@ -1052,10 +1052,10 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
1052 .tag = .uav_ref_off,1052 .tag = .uav_ref_off,
1053 .data = .{1053 .data = .{
1054 .payload = if (is_obj) try cg.addExtra(Mir.UavRefOffObj{1054 .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),
1056 .offset = uav.offset,1056 .offset = uav.offset,
1057 }) else try cg.addExtra(Mir.UavRefOffExe{1057 }) 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),
1059 .offset = uav.offset,1059 .offset = uav.offset,
1060 }),1060 }),
1061 },1061 },
src/codegen.zig+1-1
...@@ -676,7 +676,7 @@ fn lowerUavRef(...@@ -676,7 +676,7 @@ fn lowerUavRef(
676 } else {676 } else {
677 try wasm.uav_fixups.ensureUnusedCapacity(gpa, 1);677 try wasm.uav_fixups.ensureUnusedCapacity(gpa, 1);
678 wasm.uav_fixups.appendAssumeCapacity(.{678 wasm.uav_fixups.appendAssumeCapacity(.{
679 .uavs_exe_index = try wasm.refUavExe(pt, uav.val),679 .uavs_exe_index = try wasm.refUavExe(uav.val),
680 .offset = @intCast(code.items.len),680 .offset = @intCast(code.items.len),
681 });681 });
682 }682 }
src/link/Wasm.zig+75-23
...@@ -2364,24 +2364,50 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -2364,24 +2364,50 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
2364 return;2364 return;
2365 }2365 }
23662366
2367 const zcu_data = try lowerZcuData(wasm, pt, nav_init);
2368
2369 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
2370
2371 if (is_obj) {2367 if (is_obj) {
2372 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);2368 var uavs_i = wasm.uavs_obj.entries.len;
2373 gop.value_ptr.* = zcu_data;2369 var navs_i = wasm.navs_obj.entries.len;
2374 wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_obj = @enumFromInt(gop.index) }), {});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 }
2375 }2410 }
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) }), {});
2385}2411}
23862412
2387pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {2413pub 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...@@ -3346,18 +3372,23 @@ pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableInd
3346 return @enumFromInt(gop.index);3372 return @enumFromInt(gop.index);
3347}3373}
33483374
3349pub fn refUavObj(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !UavsObjIndex {3375pub fn refUavObj(wasm: *Wasm, ip_index: InternPool.Index) !UavsObjIndex {
3350 const comp = wasm.base.comp;3376 const comp = wasm.base.comp;
3351 const gpa = comp.gpa;3377 const gpa = comp.gpa;
3352 assert(comp.config.output_mode == .Obj);3378 assert(comp.config.output_mode == .Obj);
3379 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
3353 const gop = try wasm.uavs_obj.getOrPut(gpa, ip_index);3380 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 };
3355 const uav_index: UavsObjIndex = @enumFromInt(gop.index);3386 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 }), {});
3357 return uav_index;3388 return uav_index;
3358}3389}
33593390
3360pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !UavsExeIndex {3391pub fn refUavExe(wasm: *Wasm, ip_index: InternPool.Index) !UavsExeIndex {
3361 const comp = wasm.base.comp;3392 const comp = wasm.base.comp;
3362 const gpa = comp.gpa;3393 const gpa = comp.gpa;
3363 assert(comp.config.output_mode != .Obj);3394 assert(comp.config.output_mode != .Obj);
...@@ -3365,9 +3396,9 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua...@@ -3365,9 +3396,9 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua
3365 if (gop.found_existing) {3396 if (gop.found_existing) {
3366 gop.value_ptr.count += 1;3397 gop.value_ptr.count += 1;
3367 } else {3398 } else {
3368 const zcu_data = try lowerZcuData(wasm, pt, ip_index);
3369 gop.value_ptr.* = .{3399 gop.value_ptr.* = .{
3370 .code = zcu_data.code,3400 // Lowering the value is delayed to avoid recursion.
3401 .code = undefined,
3371 .count = 1,3402 .count = 1,
3372 };3403 };
3373 }3404 }
...@@ -3376,6 +3407,21 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua...@@ -3376,6 +3407,21 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua
3376 return uav_index;3407 return uav_index;
3377}3408}
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
3379pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {3425pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
3380 const comp = wasm.base.comp;3426 const comp = wasm.base.comp;
3381 const gpa = comp.gpa;3427 const gpa = comp.gpa;
...@@ -3385,8 +3431,9 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {...@@ -3385,8 +3431,9 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
3385 gop.value_ptr.count += 1;3431 gop.value_ptr.count += 1;
3386 } else {3432 } else {
3387 gop.value_ptr.* = .{3433 gop.value_ptr.* = .{
3434 // Lowering the value is delayed to avoid recursion.
3388 .code = undefined,3435 .code = undefined,
3389 .count = 1,3436 .count = 0,
3390 };3437 };
3391 }3438 }
3392 const navs_exe_index: NavsExeIndex = @enumFromInt(gop.index);3439 const navs_exe_index: NavsExeIndex = @enumFromInt(gop.index);
...@@ -3481,6 +3528,11 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {...@@ -3481,6 +3528,11 @@ pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool {
3481 return mem.eql(u8, s, ".bss") or mem.startsWith(u8, s, ".bss.");3528 return mem.eql(u8, s, ".bss") or mem.startsWith(u8, s, ".bss.");
3482}3529}
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.
3484fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {3536fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !ZcuDataObj {
3485 const code_start: u32 = @intCast(wasm.string_bytes.items.len);3537 const code_start: u32 = @intCast(wasm.string_bytes.items.len);
3486 const relocs_start: u32 = @intCast(wasm.out_relocs.len);3538 const relocs_start: u32 = @intCast(wasm.out_relocs.len);