| ... | ... | @@ -189,7 +189,10 @@ debug_sections: DebugSections = .{}, |
| 189 | 189 | |
| 190 | 190 | flush_buffer: Flush = .{}, |
| 191 | 191 | |
| 192 | | missing_exports_init: []String = &.{}, |
| 192 | /// Empty until `prelink`. There it is populated based on object files. |
| 193 | /// Next, it is copied into `Flush.missing_exports` just before `flush` |
| 194 | /// and that data is used during `flush`. |
| 195 | missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty, |
| 193 | 196 | entry_resolution: FunctionImport.Resolution = .unresolved, |
| 194 | 197 | |
| 195 | 198 | /// Empty when outputting an object. |
| ... | ... | @@ -206,13 +209,7 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp |
| 206 | 209 | /// Tracks the value at the end of prelink, at which point `functions` |
| 207 | 210 | /// contains only object file functions, and nothing from the Zcu yet. |
| 208 | 211 | functions_end_prelink: u32 = 0, |
| 209 | | /// Immutable after prelink. The undefined functions coming only from all object files. |
| 210 | | /// The Zcu must satisfy these. |
| 211 | | function_imports_init_keys: []String = &.{}, |
| 212 | | function_imports_init_vals: []FunctionImportId = &.{}, |
| 213 | | /// Initialized as copy of `function_imports_init_keys` and |
| 214 | | /// `function_import_init_vals`; entries are deleted as they are satisfied by |
| 215 | | /// the Zcu. |
| 212 | /// Entries are deleted as they are satisfied by the Zcu. |
| 216 | 213 | function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty, |
| 217 | 214 | |
| 218 | 215 | /// Ordered list of non-import globals that will appear in the final binary. |
| ... | ... | @@ -221,8 +218,6 @@ globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty, |
| 221 | 218 | /// Tracks the value at the end of prelink, at which point `globals` |
| 222 | 219 | /// contains only object file globals, and nothing from the Zcu yet. |
| 223 | 220 | globals_end_prelink: u32 = 0, |
| 224 | | global_imports_init_keys: []String = &.{}, |
| 225 | | global_imports_init_vals: []GlobalImportId = &.{}, |
| 226 | 221 | global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty, |
| 227 | 222 | |
| 228 | 223 | /// Ordered list of non-import tables that will appear in the final binary. |
| ... | ... | @@ -233,11 +228,10 @@ table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty |
| 233 | 228 | /// Ordered list of data segments that will appear in the final binary. |
| 234 | 229 | /// When sorted, to-be-merged segments will be made adjacent. |
| 235 | 230 | /// Values are offset relative to segment start. |
| 236 | | data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32) = .empty, |
| 231 | data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, void) = .empty, |
| 237 | 232 | |
| 238 | 233 | error_name_table_ref_count: u32 = 0, |
| 239 | 234 | |
| 240 | | any_exports_updated: bool = true, |
| 241 | 235 | /// Set to true if any `GLOBAL_INDEX` relocation is encountered with |
| 242 | 236 | /// `SymbolFlags.tls` set to true. This is for objects only; final |
| 243 | 237 | /// value must be this OR'd with the same logic for zig functions |
| ... | ... | @@ -313,7 +307,7 @@ pub const GlobalExport = extern struct { |
| 313 | 307 | global_index: GlobalIndex, |
| 314 | 308 | }; |
| 315 | 309 | |
| 316 | | /// 0. Index into `function_imports` |
| 310 | /// 0. Index into `Flush.function_imports` |
| 317 | 311 | /// 1. Index into `functions`. |
| 318 | 312 | /// |
| 319 | 313 | /// Note that function_imports indexes are subject to swap removals during |
| ... | ... | @@ -529,13 +523,6 @@ pub const SymbolFlags = packed struct(u32) { |
| 529 | 523 | return flags.exported; |
| 530 | 524 | } |
| 531 | 525 | |
| 532 | | pub fn requiresImport(flags: SymbolFlags, is_data: bool) bool { |
| 533 | | if (is_data) return false; |
| 534 | | if (!flags.undefined) return false; |
| 535 | | if (flags.binding == .weak) return false; |
| 536 | | return true; |
| 537 | | } |
| 538 | | |
| 539 | 526 | /// Returns the name as how it will be output into the final object |
| 540 | 527 | /// file or binary. When `merge` is true, this will return the |
| 541 | 528 | /// short name. i.e. ".rodata". When false, it returns the entire name instead. |
| ... | ... | @@ -2268,6 +2255,8 @@ pub fn deinit(wasm: *Wasm) void { |
| 2268 | 2255 | |
| 2269 | 2256 | wasm.params_scratch.deinit(gpa); |
| 2270 | 2257 | wasm.returns_scratch.deinit(gpa); |
| 2258 | |
| 2259 | wasm.missing_exports.deinit(gpa); |
| 2271 | 2260 | } |
| 2272 | 2261 | |
| 2273 | 2262 | pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| ... | ... | @@ -2306,28 +2295,27 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index |
| 2306 | 2295 | const gpa = comp.gpa; |
| 2307 | 2296 | const is_obj = comp.config.output_mode == .Obj; |
| 2308 | 2297 | |
| 2309 | | const is_extern, const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { |
| 2310 | | .func => return, |
| 2311 | | .@"extern" => .{ true, .none }, |
| 2312 | | .variable => |variable| .{ false, variable.init }, |
| 2313 | | else => .{ false, nav.status.resolved.val }, |
| 2298 | const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { |
| 2299 | .func => return, // global const which is a function alias |
| 2300 | .@"extern" => { |
| 2301 | if (is_obj) { |
| 2302 | assert(!wasm.navs_obj.contains(nav_index)); |
| 2303 | } else { |
| 2304 | assert(!wasm.navs_exe.contains(nav_index)); |
| 2305 | } |
| 2306 | try wasm.imports.put(gpa, nav_index, {}); |
| 2307 | return; |
| 2308 | }, |
| 2309 | .variable => |variable| variable.init, |
| 2310 | else => nav.status.resolved.val, |
| 2314 | 2311 | }; |
| 2315 | | if (is_extern) { |
| 2316 | | try wasm.imports.put(gpa, nav_index, {}); |
| 2317 | | if (is_obj) { |
| 2318 | | if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources"); |
| 2319 | | } else { |
| 2320 | | if (wasm.navs_exe.swapRemove(nav_index)) @panic("TODO reclaim resources"); |
| 2321 | | } |
| 2322 | | return; |
| 2323 | | } |
| 2324 | | _ = wasm.imports.swapRemove(nav_index); |
| 2312 | assert(!wasm.imports.contains(nav_index)); |
| 2325 | 2313 | |
| 2326 | 2314 | if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) { |
| 2327 | 2315 | if (is_obj) { |
| 2328 | | if (wasm.navs_obj.swapRemove(nav_index)) @panic("TODO reclaim resources"); |
| 2316 | assert(!wasm.navs_obj.contains(nav_index)); |
| 2329 | 2317 | } else { |
| 2330 | | if (wasm.navs_exe.swapRemove(nav_index)) @panic("TODO reclaim resources"); |
| 2318 | assert(!wasm.navs_exe.contains(nav_index)); |
| 2331 | 2319 | } |
| 2332 | 2320 | return; |
| 2333 | 2321 | } |
| ... | ... | @@ -2339,9 +2327,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index |
| 2339 | 2327 | if (is_obj) { |
| 2340 | 2328 | const gop = try wasm.navs_obj.getOrPut(gpa, nav_index); |
| 2341 | 2329 | gop.value_ptr.* = zcu_data; |
| 2342 | | wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ |
| 2343 | | .nav_obj = @enumFromInt(gop.index), |
| 2344 | | }), @as(u32, undefined)); |
| 2330 | wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_obj = @enumFromInt(gop.index) }), {}); |
| 2345 | 2331 | } |
| 2346 | 2332 | |
| 2347 | 2333 | assert(zcu_data.relocs.len == 0); |
| ... | ... | @@ -2351,9 +2337,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index |
| 2351 | 2337 | .code = zcu_data.code, |
| 2352 | 2338 | .count = 0, |
| 2353 | 2339 | }; |
| 2354 | | wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ |
| 2355 | | .nav_exe = @enumFromInt(gop.index), |
| 2356 | | }), @as(u32, undefined)); |
| 2340 | wasm.data_segments.putAssumeCapacity(.pack(wasm, .{ .nav_exe = @enumFromInt(gop.index) }), {}); |
| 2357 | 2341 | } |
| 2358 | 2342 | |
| 2359 | 2343 | pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { |
| ... | ... | @@ -2380,7 +2364,6 @@ pub fn deleteExport( |
| 2380 | 2364 | }, |
| 2381 | 2365 | .uav => |uav_index| assert(wasm.uav_exports.swapRemove(.{ .uav_index = uav_index, .name = export_name })), |
| 2382 | 2366 | } |
| 2383 | | wasm.any_exports_updated = true; |
| 2384 | 2367 | } |
| 2385 | 2368 | |
| 2386 | 2369 | pub fn updateExports( |
| ... | ... | @@ -2409,7 +2392,6 @@ pub fn updateExports( |
| 2409 | 2392 | .uav => |uav_index| try wasm.uav_exports.put(gpa, .{ .uav_index = uav_index, .name = name }, export_idx), |
| 2410 | 2393 | } |
| 2411 | 2394 | } |
| 2412 | | wasm.any_exports_updated = true; |
| 2413 | 2395 | } |
| 2414 | 2396 | |
| 2415 | 2397 | pub fn loadInput(wasm: *Wasm, input: link.Input) !void { |
| ... | ... | @@ -2464,32 +2446,28 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 2464 | 2446 | const gpa = comp.gpa; |
| 2465 | 2447 | const rdynamic = comp.config.rdynamic; |
| 2466 | 2448 | |
| 2467 | | { |
| 2468 | | var missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty; |
| 2469 | | defer missing_exports.deinit(gpa); |
| 2470 | | for (wasm.export_symbol_names) |exp_name| { |
| 2471 | | const exp_name_interned = try wasm.internString(exp_name); |
| 2472 | | if (wasm.object_function_imports.getPtr(exp_name_interned)) |import| { |
| 2473 | | if (import.resolution != .unresolved) { |
| 2474 | | import.flags.exported = true; |
| 2475 | | continue; |
| 2476 | | } |
| 2449 | assert(wasm.missing_exports.entries.len == 0); |
| 2450 | for (wasm.export_symbol_names) |exp_name| { |
| 2451 | const exp_name_interned = try wasm.internString(exp_name); |
| 2452 | if (wasm.object_function_imports.getPtr(exp_name_interned)) |import| { |
| 2453 | if (import.resolution != .unresolved) { |
| 2454 | import.flags.exported = true; |
| 2455 | continue; |
| 2477 | 2456 | } |
| 2478 | | if (wasm.object_global_imports.getPtr(exp_name_interned)) |import| { |
| 2479 | | if (import.resolution != .unresolved) { |
| 2480 | | import.flags.exported = true; |
| 2481 | | continue; |
| 2482 | | } |
| 2457 | } |
| 2458 | if (wasm.object_global_imports.getPtr(exp_name_interned)) |import| { |
| 2459 | if (import.resolution != .unresolved) { |
| 2460 | import.flags.exported = true; |
| 2461 | continue; |
| 2483 | 2462 | } |
| 2484 | | if (wasm.object_table_imports.getPtr(exp_name_interned)) |import| { |
| 2485 | | if (import.resolution != .unresolved) { |
| 2486 | | import.flags.exported = true; |
| 2487 | | continue; |
| 2488 | | } |
| 2463 | } |
| 2464 | if (wasm.object_table_imports.getPtr(exp_name_interned)) |import| { |
| 2465 | if (import.resolution != .unresolved) { |
| 2466 | import.flags.exported = true; |
| 2467 | continue; |
| 2489 | 2468 | } |
| 2490 | | try missing_exports.put(gpa, exp_name_interned, {}); |
| 2491 | 2469 | } |
| 2492 | | wasm.missing_exports_init = try gpa.dupe(String, missing_exports.keys()); |
| 2470 | try wasm.missing_exports.put(gpa, exp_name_interned, {}); |
| 2493 | 2471 | } |
| 2494 | 2472 | |
| 2495 | 2473 | if (wasm.entry_name.unwrap()) |entry_name| { |
| ... | ... | @@ -2515,8 +2493,6 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 2515 | 2493 | } |
| 2516 | 2494 | } |
| 2517 | 2495 | wasm.functions_end_prelink = @intCast(wasm.functions.entries.len); |
| 2518 | | wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys()); |
| 2519 | | wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.values()); |
| 2520 | 2496 | wasm.function_exports_len = @intCast(wasm.function_exports.items.len); |
| 2521 | 2497 | |
| 2522 | 2498 | for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| { |
| ... | ... | @@ -2525,8 +2501,6 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 2525 | 2501 | } |
| 2526 | 2502 | } |
| 2527 | 2503 | wasm.globals_end_prelink = @intCast(wasm.globals.entries.len); |
| 2528 | | wasm.global_imports_init_keys = try gpa.dupe(String, wasm.global_imports.keys()); |
| 2529 | | wasm.global_imports_init_vals = try gpa.dupe(GlobalImportId, wasm.global_imports.values()); |
| 2530 | 2504 | wasm.global_exports_len = @intCast(wasm.global_exports.items.len); |
| 2531 | 2505 | |
| 2532 | 2506 | for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| { |
| ... | ... | @@ -2692,6 +2666,7 @@ pub fn flushModule( |
| 2692 | 2666 | const comp = wasm.base.comp; |
| 2693 | 2667 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 2694 | 2668 | const diags = &comp.link_diags; |
| 2669 | const gpa = comp.gpa; |
| 2695 | 2670 | |
| 2696 | 2671 | if (wasm.llvm_object) |llvm_object| { |
| 2697 | 2672 | try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); |
| ... | ... | @@ -2728,6 +2703,10 @@ pub fn flushModule( |
| 2728 | 2703 | defer wasm.data_segments.shrinkRetainingCapacity(data_segments_end_zcu); |
| 2729 | 2704 | |
| 2730 | 2705 | wasm.flush_buffer.clear(); |
| 2706 | try wasm.flush_buffer.missing_exports.reinit(gpa, wasm.missing_exports.keys(), &.{}); |
| 2707 | try wasm.flush_buffer.data_segments.reinit(gpa, wasm.data_segments.keys(), &.{}); |
| 2708 | try wasm.flush_buffer.function_imports.reinit(gpa, wasm.function_imports.keys(), wasm.function_imports.values()); |
| 2709 | try wasm.flush_buffer.global_imports.reinit(gpa, wasm.global_imports.keys(), wasm.global_imports.values()); |
| 2731 | 2710 | |
| 2732 | 2711 | return wasm.flush_buffer.finish(wasm) catch |err| switch (err) { |
| 2733 | 2712 | error.OutOfMemory => return error.OutOfMemory, |
| ... | ... | @@ -3330,7 +3309,7 @@ pub fn refUavObj(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua |
| 3330 | 3309 | const gop = try wasm.uavs_obj.getOrPut(gpa, ip_index); |
| 3331 | 3310 | if (!gop.found_existing) gop.value_ptr.* = try lowerZcuData(wasm, pt, ip_index); |
| 3332 | 3311 | const uav_index: UavsObjIndex = @enumFromInt(gop.index); |
| 3333 | | try wasm.data_segments.put(gpa, .pack(wasm, .{ .uav_obj = uav_index }), @as(u32, undefined)); |
| 3312 | try wasm.data_segments.put(gpa, .pack(wasm, .{ .uav_obj = uav_index }), {}); |
| 3334 | 3313 | return uav_index; |
| 3335 | 3314 | } |
| 3336 | 3315 | |
| ... | ... | @@ -3349,34 +3328,34 @@ pub fn refUavExe(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Ua |
| 3349 | 3328 | }; |
| 3350 | 3329 | } |
| 3351 | 3330 | const uav_index: UavsExeIndex = @enumFromInt(gop.index); |
| 3352 | | try wasm.data_segments.put(gpa, .pack(wasm, .{ .uav_exe = uav_index }), @as(u32, undefined)); |
| 3331 | try wasm.data_segments.put(gpa, .pack(wasm, .{ .uav_exe = uav_index }), {}); |
| 3353 | 3332 | return uav_index; |
| 3354 | 3333 | } |
| 3355 | 3334 | |
| 3356 | | /// Asserts it is called after `Wasm.data_segments` is fully populated and sorted. |
| 3335 | /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. |
| 3357 | 3336 | pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 { |
| 3358 | 3337 | assert(wasm.flush_buffer.memory_layout_finished); |
| 3359 | 3338 | const comp = wasm.base.comp; |
| 3360 | 3339 | assert(comp.config.output_mode != .Obj); |
| 3361 | 3340 | const ds_id: DataSegment.Id = .pack(wasm, .{ .uav_exe = uav_index }); |
| 3362 | | return wasm.data_segments.get(ds_id).?; |
| 3341 | return wasm.flush_buffer.data_segments.get(ds_id).?; |
| 3363 | 3342 | } |
| 3364 | 3343 | |
| 3365 | | /// Asserts it is called after `Wasm.data_segments` is fully populated and sorted. |
| 3344 | /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. |
| 3366 | 3345 | pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { |
| 3367 | 3346 | assert(wasm.flush_buffer.memory_layout_finished); |
| 3368 | 3347 | const comp = wasm.base.comp; |
| 3369 | 3348 | assert(comp.config.output_mode != .Obj); |
| 3370 | 3349 | const ds_id: DataSegment.Id = .pack(wasm, .{ .nav_exe = @enumFromInt(wasm.navs_exe.getIndex(nav_index).?) }); |
| 3371 | | return wasm.data_segments.get(ds_id).?; |
| 3350 | return wasm.flush_buffer.data_segments.get(ds_id).?; |
| 3372 | 3351 | } |
| 3373 | 3352 | |
| 3374 | | /// Asserts it is called after `Wasm.data_segments` is fully populated and sorted. |
| 3353 | /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. |
| 3375 | 3354 | pub fn errorNameTableAddr(wasm: *Wasm) u32 { |
| 3376 | 3355 | assert(wasm.flush_buffer.memory_layout_finished); |
| 3377 | 3356 | const comp = wasm.base.comp; |
| 3378 | 3357 | assert(comp.config.output_mode != .Obj); |
| 3379 | | return wasm.data_segments.get(.__zig_error_name_table).?; |
| 3358 | return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?; |
| 3380 | 3359 | } |
| 3381 | 3360 | |
| 3382 | 3361 | fn convertZcuFnType( |