| ... | ... | @@ -109,7 +109,7 @@ globals: std.StringHashMapUnmanaged(SymbolLoc) = .{}, |
| 109 | 109 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| 110 | 110 | /// List of all symbol locations which have been resolved by the linker and will be emit |
| 111 | 111 | /// into the final binary. |
| 112 | | resolved_symbols: std.ArrayListUnmanaged(SymbolLoc) = .{}, |
| 112 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| 113 | 113 | |
| 114 | 114 | pub const Segment = struct { |
| 115 | 115 | alignment: u32, |
| ... | ... | @@ -134,10 +134,10 @@ pub const SymbolLoc = struct { |
| 134 | 134 | |
| 135 | 135 | /// From a given location, returns the corresponding symbol in the wasm binary |
| 136 | 136 | pub fn getSymbol(self: SymbolLoc, wasm_bin: *const Wasm) *Symbol { |
| 137 | if (wasm_bin.discarded.get(self)) |new_loc| { |
| 138 | return new_loc.getSymbol(wasm_bin); |
| 139 | } |
| 137 | 140 | if (self.file) |object_index| { |
| 138 | | if (wasm_bin.discarded.get(self)) |old_loc| { |
| 139 | | return old_loc.getSymbol(wasm_bin); |
| 140 | | } |
| 141 | 141 | const object = wasm_bin.objects.items[object_index]; |
| 142 | 142 | return &object.symtable[self.index]; |
| 143 | 143 | } |
| ... | ... | @@ -245,7 +245,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 245 | 245 | log.err(" symbol '{s}' defined in '{s}'", .{ symbol.name, object.name }); |
| 246 | 246 | return error.undefinedLocal; |
| 247 | 247 | } |
| 248 | | try self.resolved_symbols.append(self.base.allocator, location); |
| 248 | try self.resolved_symbols.putNoClobber(self.base.allocator, location, {}); |
| 249 | 249 | continue; |
| 250 | 250 | } |
| 251 | 251 | |
| ... | ... | @@ -255,6 +255,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 255 | 255 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name); |
| 256 | 256 | if (!maybe_existing.found_existing) { |
| 257 | 257 | maybe_existing.value_ptr.* = location; |
| 258 | try self.resolved_symbols.putNoClobber(self.base.allocator, location, {}); |
| 258 | 259 | continue; |
| 259 | 260 | } |
| 260 | 261 | |
| ... | ... | @@ -277,12 +278,14 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 277 | 278 | } |
| 278 | 279 | |
| 279 | 280 | // simply overwrite with the new symbol |
| 280 | | log.info("Overwriting symbol '{s}'", .{symbol.name}); |
| 281 | | log.info(" old definition in '{s}'", .{existing_file_path}); |
| 282 | | log.info(" new definition in '{s}'", .{object.name}); |
| 281 | log.debug("Overwriting symbol '{s}'", .{symbol.name}); |
| 282 | log.debug(" old definition in '{s}'", .{existing_file_path}); |
| 283 | log.debug(" new definition in '{s}'", .{object.name}); |
| 283 | 284 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); |
| 284 | 285 | maybe_existing.value_ptr.* = location; |
| 285 | 286 | try self.globals.put(self.base.allocator, sym_name, location); |
| 287 | try self.resolved_symbols.put(self.base.allocator, location, {}); |
| 288 | assert(self.resolved_symbols.swapRemove(existing_loc)); |
| 286 | 289 | } |
| 287 | 290 | } |
| 288 | 291 | |
| ... | ... | @@ -360,6 +363,11 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 360 | 363 | atom.sym_index = @intCast(u32, self.symbols.items.len); |
| 361 | 364 | self.symbols.appendAssumeCapacity(symbol); |
| 362 | 365 | } |
| 366 | |
| 367 | try self.resolved_symbols.putNoClobber(self.base.allocator, .{ |
| 368 | .index = atom.sym_index, |
| 369 | .file = null, |
| 370 | }, {}); |
| 363 | 371 | } |
| 364 | 372 | |
| 365 | 373 | pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| ... | ... | @@ -454,7 +462,9 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 454 | 462 | const atom: *Atom = &decl.link.wasm; |
| 455 | 463 | atom.size = @intCast(u32, code.len); |
| 456 | 464 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); |
| 457 | | self.symbols.items[atom.sym_index].name = try self.base.allocator.dupeZ(u8, std.mem.sliceTo(decl.name, 0)); |
| 465 | const symbol = &self.symbols.items[atom.sym_index]; |
| 466 | symbol.name = try self.base.allocator.dupeZ(u8, std.mem.sliceTo(decl.name, 0)); |
| 467 | symbol.setFlag(.WASM_SYM_BINDING_LOCAL); |
| 458 | 468 | try atom.code.appendSlice(self.base.allocator, code); |
| 459 | 469 | } |
| 460 | 470 | |
| ... | ... | @@ -566,7 +576,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 566 | 576 | if (decl.isExtern()) { |
| 567 | 577 | assert(self.imports.remove(.{ .file = null, .index = atom.sym_index })); |
| 568 | 578 | } |
| 569 | | |
| 579 | assert(self.resolved_symbols.swapRemove(.{ .index = atom.sym_index, .file = null })); |
| 570 | 580 | atom.deinit(self.base.allocator); |
| 571 | 581 | } |
| 572 | 582 | |
| ... | ... | @@ -594,7 +604,7 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 594 | 604 | symbol.name = try self.base.allocator.dupeZ(u8, decl_name); |
| 595 | 605 | symbol.setUndefined(true); |
| 596 | 606 | // also add it as a global so it can be resolved |
| 597 | | try self.globals.put(self.base.allocator, decl_name, .{ .file = null, .index = symbol_index }); |
| 607 | try self.globals.putNoClobber(self.base.allocator, decl_name, .{ .file = null, .index = symbol_index }); |
| 598 | 608 | switch (decl.ty.zigTypeTag()) { |
| 599 | 609 | .Fn => { |
| 600 | 610 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); |
| ... | ... | @@ -620,7 +630,7 @@ const Kind = union(enum) { |
| 620 | 630 | |
| 621 | 631 | /// Parses an Atom and inserts its metadata into the corresponding sections. |
| 622 | 632 | fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 623 | | const symbol: *Symbol = &self.symbols.items[atom.sym_index]; |
| 633 | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self); |
| 624 | 634 | const final_index: u32 = switch (kind) { |
| 625 | 635 | .function => |fn_data| result: { |
| 626 | 636 | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); |
| ... | ... | @@ -711,7 +721,19 @@ fn allocateAtoms(self: *Wasm) !void { |
| 711 | 721 | } |
| 712 | 722 | |
| 713 | 723 | fn setupImports(self: *Wasm) !void { |
| 714 | | for (self.resolved_symbols.items) |symbol_loc| { |
| 724 | log.debug("Merging imports", .{}); |
| 725 | var discarded_it = self.discarded.keyIterator(); |
| 726 | while (discarded_it.next()) |discarded| { |
| 727 | if (discarded.file == null) { |
| 728 | // remove an import if it was resolved |
| 729 | if (self.imports.remove(discarded.*)) { |
| 730 | log.debug("Removed symbol '{s}' as an import", .{ |
| 731 | discarded.getSymbol(self).name, |
| 732 | }); |
| 733 | } |
| 734 | } |
| 735 | } |
| 736 | for (self.resolved_symbols.keys()) |symbol_loc| { |
| 715 | 737 | if (symbol_loc.file == null) { |
| 716 | 738 | // imports generated by Zig code are already in the `import` section |
| 717 | 739 | continue; |
| ... | ... | @@ -755,6 +777,12 @@ fn setupImports(self: *Wasm) !void { |
| 755 | 777 | self.imported_functions_count = function_index; |
| 756 | 778 | self.imported_globals_count = global_index; |
| 757 | 779 | self.imported_tables_count = table_index; |
| 780 | |
| 781 | log.debug("Merged ({d}) functions, ({d}) globals, and ({d}) tables into import section", .{ |
| 782 | function_index, |
| 783 | global_index, |
| 784 | table_index, |
| 785 | }); |
| 758 | 786 | } |
| 759 | 787 | |
| 760 | 788 | /// Takes the global, function and table section from each linked object file |
| ... | ... | @@ -770,7 +798,7 @@ fn mergeSections(self: *Wasm) !void { |
| 770 | 798 | try self.tables.append(self.base.allocator, table); |
| 771 | 799 | } |
| 772 | 800 | |
| 773 | | for (self.resolved_symbols.items) |sym_loc| { |
| 801 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 774 | 802 | if (sym_loc.file == null) { |
| 775 | 803 | // Zig code-generated symbols are already within the sections and do not |
| 776 | 804 | // require to be merged |
| ... | ... | @@ -816,7 +844,7 @@ fn mergeSections(self: *Wasm) !void { |
| 816 | 844 | /// 'types' section, while assigning the type index to the representing |
| 817 | 845 | /// section (import, export, function). |
| 818 | 846 | fn mergeTypes(self: *Wasm) !void { |
| 819 | | for (self.resolved_symbols.items) |sym_loc| { |
| 847 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 820 | 848 | if (sym_loc.file == null) { |
| 821 | 849 | // zig code-generated symbols are already present in final type section |
| 822 | 850 | continue; |
| ... | ... | @@ -850,7 +878,7 @@ fn setupExports(self: *Wasm) !void { |
| 850 | 878 | try self.exports.append(self.base.allocator, .{ .name = "memory", .kind = .memory, .index = 0 }); |
| 851 | 879 | } |
| 852 | 880 | |
| 853 | | for (self.resolved_symbols.items) |sym_loc| { |
| 881 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 854 | 882 | const symbol = sym_loc.getSymbol(self); |
| 855 | 883 | if (!symbol.isExported()) continue; |
| 856 | 884 | |
| ... | ... | @@ -1067,7 +1095,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1067 | 1095 | var object_index: u16 = 0; |
| 1068 | 1096 | while (object_index < self.objects.items.len) : (object_index += 1) { |
| 1069 | 1097 | try self.resolveSymbolsInObject(object_index); |
| 1070 | | try self.objects.items[object_index].parseIntoAtoms(self.base.allocator, object_index, self); |
| 1071 | 1098 | } |
| 1072 | 1099 | |
| 1073 | 1100 | // When we finish/error we reset the state of the linker |
| ... | ... | @@ -1090,6 +1117,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1090 | 1117 | } |
| 1091 | 1118 | } |
| 1092 | 1119 | |
| 1120 | while (object_index > 0) { |
| 1121 | object_index -= 1; |
| 1122 | try self.objects.items[object_index].parseIntoAtoms(self.base.allocator, object_index, self); |
| 1123 | } |
| 1124 | |
| 1093 | 1125 | try self.setupMemory(); |
| 1094 | 1126 | try self.allocateAtoms(); |
| 1095 | 1127 | self.mapFunctionTable(); |
| ... | ... | @@ -1428,7 +1460,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1428 | 1460 | var segments = try std.ArrayList(Name).initCapacity(self.base.allocator, self.data_segments.count()); |
| 1429 | 1461 | defer segments.deinit(); |
| 1430 | 1462 | |
| 1431 | | for (self.symbols.items) |symbol| { |
| 1463 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 1464 | const symbol = sym_loc.getSymbol(self).*; |
| 1432 | 1465 | switch (symbol.tag) { |
| 1433 | 1466 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |
| 1434 | 1467 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |