| ... | @@ -109,7 +109,7 @@ globals: std.StringHashMapUnmanaged(SymbolLoc) = .{}, | ... | @@ -109,7 +109,7 @@ globals: std.StringHashMapUnmanaged(SymbolLoc) = .{}, |
| 109 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, | 109 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| 110 | /// List of all symbol locations which have been resolved by the linker and will be emit | 110 | /// List of all symbol locations which have been resolved by the linker and will be emit |
| 111 | /// into the final binary. | 111 | /// into the final binary. |
| 112 | resolved_symbols: std.ArrayListUnmanaged(SymbolLoc) = .{}, | 112 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| 113 | | 113 | |
| 114 | pub const Segment = struct { | 114 | pub const Segment = struct { |
| 115 | alignment: u32, | 115 | alignment: u32, |
| ... | @@ -134,10 +134,10 @@ pub const SymbolLoc = struct { | ... | @@ -134,10 +134,10 @@ pub const SymbolLoc = struct { |
| 134 | | 134 | |
| 135 | /// From a given location, returns the corresponding symbol in the wasm binary | 135 | /// From a given location, returns the corresponding symbol in the wasm binary |
| 136 | pub fn getSymbol(self: SymbolLoc, wasm_bin: *const Wasm) *Symbol { | 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 | if (self.file) |object_index| { | 140 | if (self.file) |object_index| { |
| 138 | if (wasm_bin.discarded.get(self)) |old_loc| { | | |
| 139 | return old_loc.getSymbol(wasm_bin); | | |
| 140 | } | | |
| 141 | const object = wasm_bin.objects.items[object_index]; | 141 | const object = wasm_bin.objects.items[object_index]; |
| 142 | return &object.symtable[self.index]; | 142 | return &object.symtable[self.index]; |
| 143 | } | 143 | } |
| ... | @@ -245,7 +245,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -245,7 +245,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 245 | log.err(" symbol '{s}' defined in '{s}'", .{ symbol.name, object.name }); | 245 | log.err(" symbol '{s}' defined in '{s}'", .{ symbol.name, object.name }); |
| 246 | return error.undefinedLocal; | 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 | continue; | 249 | continue; |
| 250 | } | 250 | } |
| 251 | | 251 | |
| ... | @@ -255,6 +255,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -255,6 +255,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 255 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name); | 255 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name); |
| 256 | if (!maybe_existing.found_existing) { | 256 | if (!maybe_existing.found_existing) { |
| 257 | maybe_existing.value_ptr.* = location; | 257 | maybe_existing.value_ptr.* = location; |
| | 258 | try self.resolved_symbols.putNoClobber(self.base.allocator, location, {}); |
| 258 | continue; | 259 | continue; |
| 259 | } | 260 | } |
| 260 | | 261 | |
| ... | @@ -277,12 +278,14 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -277,12 +278,14 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 277 | } | 278 | } |
| 278 | | 279 | |
| 279 | // simply overwrite with the new symbol | 280 | // simply overwrite with the new symbol |
| 280 | log.info("Overwriting symbol '{s}'", .{symbol.name}); | 281 | log.debug("Overwriting symbol '{s}'", .{symbol.name}); |
| 281 | log.info(" old definition in '{s}'", .{existing_file_path}); | 282 | log.debug(" old definition in '{s}'", .{existing_file_path}); |
| 282 | log.info(" new definition in '{s}'", .{object.name}); | 283 | log.debug(" new definition in '{s}'", .{object.name}); |
| 283 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); | 284 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); |
| 284 | maybe_existing.value_ptr.* = location; | 285 | maybe_existing.value_ptr.* = location; |
| 285 | try self.globals.put(self.base.allocator, sym_name, location); | 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,6 +363,11 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 360 | atom.sym_index = @intCast(u32, self.symbols.items.len); | 363 | atom.sym_index = @intCast(u32, self.symbols.items.len); |
| 361 | self.symbols.appendAssumeCapacity(symbol); | 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 | pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 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,7 +462,9 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 454 | const atom: *Atom = &decl.link.wasm; | 462 | const atom: *Atom = &decl.link.wasm; |
| 455 | atom.size = @intCast(u32, code.len); | 463 | atom.size = @intCast(u32, code.len); |
| 456 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); | 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 | try atom.code.appendSlice(self.base.allocator, code); | 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,7 +576,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 566 | if (decl.isExtern()) { | 576 | if (decl.isExtern()) { |
| 567 | assert(self.imports.remove(.{ .file = null, .index = atom.sym_index })); | 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 | atom.deinit(self.base.allocator); | 580 | atom.deinit(self.base.allocator); |
| 571 | } | 581 | } |
| 572 | | 582 | |
| ... | @@ -594,7 +604,7 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -594,7 +604,7 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 594 | symbol.name = try self.base.allocator.dupeZ(u8, decl_name); | 604 | symbol.name = try self.base.allocator.dupeZ(u8, decl_name); |
| 595 | symbol.setUndefined(true); | 605 | symbol.setUndefined(true); |
| 596 | // also add it as a global so it can be resolved | 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 | switch (decl.ty.zigTypeTag()) { | 608 | switch (decl.ty.zigTypeTag()) { |
| 599 | .Fn => { | 609 | .Fn => { |
| 600 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); | 610 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); |
| ... | @@ -620,7 +630,7 @@ const Kind = union(enum) { | ... | @@ -620,7 +630,7 @@ const Kind = union(enum) { |
| 620 | | 630 | |
| 621 | /// Parses an Atom and inserts its metadata into the corresponding sections. | 631 | /// Parses an Atom and inserts its metadata into the corresponding sections. |
| 622 | fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { | 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 | const final_index: u32 = switch (kind) { | 634 | const final_index: u32 = switch (kind) { |
| 625 | .function => |fn_data| result: { | 635 | .function => |fn_data| result: { |
| 626 | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); | 636 | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); |
| ... | @@ -711,7 +721,19 @@ fn allocateAtoms(self: *Wasm) !void { | ... | @@ -711,7 +721,19 @@ fn allocateAtoms(self: *Wasm) !void { |
| 711 | } | 721 | } |
| 712 | | 722 | |
| 713 | fn setupImports(self: *Wasm) !void { | 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 | if (symbol_loc.file == null) { | 737 | if (symbol_loc.file == null) { |
| 716 | // imports generated by Zig code are already in the `import` section | 738 | // imports generated by Zig code are already in the `import` section |
| 717 | continue; | 739 | continue; |
| ... | @@ -755,6 +777,12 @@ fn setupImports(self: *Wasm) !void { | ... | @@ -755,6 +777,12 @@ fn setupImports(self: *Wasm) !void { |
| 755 | self.imported_functions_count = function_index; | 777 | self.imported_functions_count = function_index; |
| 756 | self.imported_globals_count = global_index; | 778 | self.imported_globals_count = global_index; |
| 757 | self.imported_tables_count = table_index; | 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 | /// Takes the global, function and table section from each linked object file | 788 | /// Takes the global, function and table section from each linked object file |
| ... | @@ -770,7 +798,7 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -770,7 +798,7 @@ fn mergeSections(self: *Wasm) !void { |
| 770 | try self.tables.append(self.base.allocator, table); | 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 | if (sym_loc.file == null) { | 802 | if (sym_loc.file == null) { |
| 775 | // Zig code-generated symbols are already within the sections and do not | 803 | // Zig code-generated symbols are already within the sections and do not |
| 776 | // require to be merged | 804 | // require to be merged |
| ... | @@ -816,7 +844,7 @@ fn mergeSections(self: *Wasm) !void { | ... | @@ -816,7 +844,7 @@ fn mergeSections(self: *Wasm) !void { |
| 816 | /// 'types' section, while assigning the type index to the representing | 844 | /// 'types' section, while assigning the type index to the representing |
| 817 | /// section (import, export, function). | 845 | /// section (import, export, function). |
| 818 | fn mergeTypes(self: *Wasm) !void { | 846 | fn mergeTypes(self: *Wasm) !void { |
| 819 | for (self.resolved_symbols.items) |sym_loc| { | 847 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 820 | if (sym_loc.file == null) { | 848 | if (sym_loc.file == null) { |
| 821 | // zig code-generated symbols are already present in final type section | 849 | // zig code-generated symbols are already present in final type section |
| 822 | continue; | 850 | continue; |
| ... | @@ -850,7 +878,7 @@ fn setupExports(self: *Wasm) !void { | ... | @@ -850,7 +878,7 @@ fn setupExports(self: *Wasm) !void { |
| 850 | try self.exports.append(self.base.allocator, .{ .name = "memory", .kind = .memory, .index = 0 }); | 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 | const symbol = sym_loc.getSymbol(self); | 882 | const symbol = sym_loc.getSymbol(self); |
| 855 | if (!symbol.isExported()) continue; | 883 | if (!symbol.isExported()) continue; |
| 856 | | 884 | |
| ... | @@ -1067,7 +1095,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1067,7 +1095,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1067 | var object_index: u16 = 0; | 1095 | var object_index: u16 = 0; |
| 1068 | while (object_index < self.objects.items.len) : (object_index += 1) { | 1096 | while (object_index < self.objects.items.len) : (object_index += 1) { |
| 1069 | try self.resolveSymbolsInObject(object_index); | 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 | // When we finish/error we reset the state of the linker | 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,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 | try self.setupMemory(); | 1125 | try self.setupMemory(); |
| 1094 | try self.allocateAtoms(); | 1126 | try self.allocateAtoms(); |
| 1095 | self.mapFunctionTable(); | 1127 | self.mapFunctionTable(); |
| ... | @@ -1428,7 +1460,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1428,7 +1460,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1428 | var segments = try std.ArrayList(Name).initCapacity(self.base.allocator, self.data_segments.count()); | 1460 | var segments = try std.ArrayList(Name).initCapacity(self.base.allocator, self.data_segments.count()); |
| 1429 | defer segments.deinit(); | 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 | switch (symbol.tag) { | 1465 | switch (symbol.tag) { |
| 1433 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), | 1466 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |
| 1434 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), | 1467 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |