| ... | @@ -69,8 +69,8 @@ imported_globals_count: u32 = 0, | ... | @@ -69,8 +69,8 @@ imported_globals_count: u32 = 0, |
| 69 | /// The count of imported tables. This number will be appended | 69 | /// The count of imported tables. This number will be appended |
| 70 | /// to the table indexes when sections are merged. | 70 | /// to the table indexes when sections are merged. |
| 71 | imported_tables_count: u32 = 0, | 71 | imported_tables_count: u32 = 0, |
| 72 | /// Map of symbol locations, represented by its `wasm.Import` | 72 | /// Map of symbol locations, represented by its `types.Import` |
| 73 | imports: std.AutoHashMapUnmanaged(SymbolLoc, wasm.Import) = .{}, | 73 | imports: std.AutoHashMapUnmanaged(SymbolLoc, types.Import) = .{}, |
| 74 | /// Represents non-synthetic section entries. | 74 | /// Represents non-synthetic section entries. |
| 75 | /// Used for code, data and custom sections. | 75 | /// Used for code, data and custom sections. |
| 76 | segments: std.ArrayListUnmanaged(Segment) = .{}, | 76 | segments: std.ArrayListUnmanaged(Segment) = .{}, |
| ... | @@ -94,7 +94,7 @@ memories: wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, | ... | @@ -94,7 +94,7 @@ memories: wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, |
| 94 | /// Output table section | 94 | /// Output table section |
| 95 | tables: std.ArrayListUnmanaged(wasm.Table) = .{}, | 95 | tables: std.ArrayListUnmanaged(wasm.Table) = .{}, |
| 96 | /// Output export section | 96 | /// Output export section |
| 97 | exports: std.ArrayListUnmanaged(wasm.Export) = .{}, | 97 | exports: std.ArrayListUnmanaged(types.Export) = .{}, |
| 98 | | 98 | |
| 99 | /// Indirect function table, used to call function pointers | 99 | /// Indirect function table, used to call function pointers |
| 100 | /// When this is non-zero, we must emit a table entry, | 100 | /// When this is non-zero, we must emit a table entry, |
| ... | @@ -105,8 +105,8 @@ function_table: std.AutoHashMapUnmanaged(u32, u32) = .{}, | ... | @@ -105,8 +105,8 @@ function_table: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 105 | | 105 | |
| 106 | /// All object files and their data which are linked into the final binary | 106 | /// All object files and their data which are linked into the final binary |
| 107 | objects: std.ArrayListUnmanaged(Object) = .{}, | 107 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 108 | /// A map of global names to their symbol location | 108 | /// A map of global names (read: offset into string table) to their symbol location |
| 109 | globals: std.StringHashMapUnmanaged(SymbolLoc) = .{}, | 109 | globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .{}, |
| 110 | /// Maps discarded symbols and their positions to the location of the symbol | 110 | /// Maps discarded symbols and their positions to the location of the symbol |
| 111 | /// it was resolved to | 111 | /// it was resolved to |
| 112 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, | 112 | discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| ... | @@ -119,7 +119,8 @@ resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, | ... | @@ -119,7 +119,8 @@ resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| 119 | symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, | 119 | symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, |
| 120 | /// Maps a symbol's location to its export name, which may differ from the decl's name | 120 | /// Maps a symbol's location to its export name, which may differ from the decl's name |
| 121 | /// which does the exporting. | 121 | /// which does the exporting. |
| 122 | export_names: std.AutoHashMapUnmanaged(SymbolLoc, []const u8) = .{}, | 122 | /// Note: The value represents the offset into the string table, rather than the actual string. |
| | 123 | export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, |
| 123 | | 124 | |
| 124 | pub const Segment = struct { | 125 | pub const Segment = struct { |
| 125 | alignment: u32, | 126 | alignment: u32, |
| ... | @@ -223,6 +224,15 @@ pub const StringTable = struct { | ... | @@ -223,6 +224,15 @@ pub const StringTable = struct { |
| 223 | return mem.sliceTo(@ptrCast([*:0]const u8, self.string_data.items.ptr + off), 0); | 224 | return mem.sliceTo(@ptrCast([*:0]const u8, self.string_data.items.ptr + off), 0); |
| 224 | } | 225 | } |
| 225 | | 226 | |
| | 227 | /// Returns the offset of a given string when it exists. |
| | 228 | /// Will return null if the given string does not yet exist within the string table. |
| | 229 | pub fn getOffset(self: *StringTable, string: []const u8) ?u32 { |
| | 230 | return self.string_table.getKeyAdapted( |
| | 231 | string, |
| | 232 | std.hash_map.StringIndexAdapter{ .bytes = &self.string_data }, |
| | 233 | ); |
| | 234 | } |
| | 235 | |
| 226 | /// Frees all resources of the string table. Any references pointing | 236 | /// Frees all resources of the string table. Any references pointing |
| 227 | /// to the strings will be invalid. | 237 | /// to the strings will be invalid. |
| 228 | pub fn deinit(self: *StringTable, allocator: Allocator) void { | 238 | pub fn deinit(self: *StringTable, allocator: Allocator) void { |
| ... | @@ -250,16 +260,17 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -250,16 +260,17 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 250 | try file.writeAll(&(wasm.magic ++ wasm.version)); | 260 | try file.writeAll(&(wasm.magic ++ wasm.version)); |
| 251 | | 261 | |
| 252 | // As sym_index '0' is reserved, we use it for our stack pointer symbol | 262 | // As sym_index '0' is reserved, we use it for our stack pointer symbol |
| | 263 | const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer"); |
| 253 | const symbol = try wasm_bin.symbols.addOne(allocator); | 264 | const symbol = try wasm_bin.symbols.addOne(allocator); |
| 254 | symbol.* = .{ | 265 | symbol.* = .{ |
| 255 | .name = try wasm_bin.string_table.put(allocator, "__stack_pointer"), | 266 | .name = sym_name, |
| 256 | .tag = .global, | 267 | .tag = .global, |
| 257 | .flags = 0, | 268 | .flags = 0, |
| 258 | .index = 0, | 269 | .index = 0, |
| 259 | }; | 270 | }; |
| 260 | const loc: SymbolLoc = .{ .file = null, .index = 0 }; | 271 | const loc: SymbolLoc = .{ .file = null, .index = 0 }; |
| 261 | try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {}); | 272 | try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {}); |
| 262 | try wasm_bin.globals.putNoClobber(allocator, "__stack_pointer", loc); | 273 | try wasm_bin.globals.putNoClobber(allocator, sym_name, loc); |
| 263 | | 274 | |
| 264 | // For object files we will import the stack pointer symbol | 275 | // For object files we will import the stack pointer symbol |
| 265 | if (options.output_mode == .Obj) { | 276 | if (options.output_mode == .Obj) { |
| ... | @@ -268,8 +279,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -268,8 +279,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 268 | allocator, | 279 | allocator, |
| 269 | .{ .file = null, .index = 0 }, | 280 | .{ .file = null, .index = 0 }, |
| 270 | .{ | 281 | .{ |
| 271 | .module_name = wasm_bin.host_name, | 282 | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), |
| 272 | .name = "__stack_pointer", | 283 | .name = sym_name, |
| 273 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, | 284 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 274 | }, | 285 | }, |
| 275 | ); | 286 | ); |
| ... | @@ -344,6 +355,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -344,6 +355,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 344 | .index = sym_index, | 355 | .index = sym_index, |
| 345 | }; | 356 | }; |
| 346 | const sym_name = object.string_table.get(symbol.name); | 357 | const sym_name = object.string_table.get(symbol.name); |
| | 358 | const sym_name_index = try self.string_table.put(self.base.allocator, sym_name); |
| 347 | | 359 | |
| 348 | if (symbol.isLocal()) { | 360 | if (symbol.isLocal()) { |
| 349 | if (symbol.isUndefined()) { | 361 | if (symbol.isUndefined()) { |
| ... | @@ -358,7 +370,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -358,7 +370,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 358 | // TODO: locals are allowed to have duplicate symbol names | 370 | // TODO: locals are allowed to have duplicate symbol names |
| 359 | // TODO: Store undefined symbols so we can verify at the end if they've all been found | 371 | // TODO: Store undefined symbols so we can verify at the end if they've all been found |
| 360 | // if not, emit an error (unless --allow-undefined is enabled). | 372 | // if not, emit an error (unless --allow-undefined is enabled). |
| 361 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name); | 373 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index); |
| 362 | if (!maybe_existing.found_existing) { | 374 | if (!maybe_existing.found_existing) { |
| 363 | maybe_existing.value_ptr.* = location; | 375 | maybe_existing.value_ptr.* = location; |
| 364 | try self.resolved_symbols.putNoClobber(self.base.allocator, location, {}); | 376 | try self.resolved_symbols.putNoClobber(self.base.allocator, location, {}); |
| ... | @@ -383,13 +395,18 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -383,13 +395,18 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 383 | continue; // Do not overwrite defined symbols with undefined symbols | 395 | continue; // Do not overwrite defined symbols with undefined symbols |
| 384 | } | 396 | } |
| 385 | | 397 | |
| | 398 | // when both symbols are weak, we skip overwriting |
| | 399 | if (existing_sym.isWeak() and symbol.isWeak()) { |
| | 400 | continue; |
| | 401 | } |
| | 402 | |
| 386 | // simply overwrite with the new symbol | 403 | // simply overwrite with the new symbol |
| 387 | log.debug("Overwriting symbol '{s}'", .{sym_name}); | 404 | log.debug("Overwriting symbol '{s}'", .{sym_name}); |
| 388 | log.debug(" old definition in '{s}'", .{existing_file_path}); | 405 | log.debug(" old definition in '{s}'", .{existing_file_path}); |
| 389 | log.debug(" new definition in '{s}'", .{object.name}); | 406 | log.debug(" new definition in '{s}'", .{object.name}); |
| 390 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); | 407 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); |
| 391 | maybe_existing.value_ptr.* = location; | 408 | maybe_existing.value_ptr.* = location; |
| 392 | try self.globals.put(self.base.allocator, sym_name, location); | 409 | try self.globals.put(self.base.allocator, sym_name_index, location); |
| 393 | try self.resolved_symbols.put(self.base.allocator, location, {}); | 410 | try self.resolved_symbols.put(self.base.allocator, location, {}); |
| 394 | assert(self.resolved_symbols.swapRemove(existing_loc)); | 411 | assert(self.resolved_symbols.swapRemove(existing_loc)); |
| 395 | } | 412 | } |
| ... | @@ -696,7 +713,7 @@ pub fn deleteExport(self: *Wasm, exp: Export) void { | ... | @@ -696,7 +713,7 @@ pub fn deleteExport(self: *Wasm, exp: Export) void { |
| 696 | if (self.export_names.fetchRemove(loc)) |kv| { | 713 | if (self.export_names.fetchRemove(loc)) |kv| { |
| 697 | assert(self.globals.remove(kv.value)); | 714 | assert(self.globals.remove(kv.value)); |
| 698 | } else { | 715 | } else { |
| 699 | assert(self.globals.remove(symbol_name)); | 716 | assert(self.globals.remove(symbol.name)); |
| 700 | } | 717 | } |
| 701 | } | 718 | } |
| 702 | | 719 | |
| ... | @@ -723,7 +740,9 @@ pub fn updateDeclExports( | ... | @@ -723,7 +740,9 @@ pub fn updateDeclExports( |
| 723 | )); | 740 | )); |
| 724 | continue; | 741 | continue; |
| 725 | } | 742 | } |
| 726 | if (self.globals.getPtr(exp.options.name)) |existing_loc| { | 743 | |
| | 744 | const export_name = try self.string_table.put(self.base.allocator, exp.options.name); |
| | 745 | if (self.globals.getPtr(export_name)) |existing_loc| { |
| 727 | if (existing_loc.index == decl.link.wasm.sym_index) continue; | 746 | if (existing_loc.index == decl.link.wasm.sym_index) continue; |
| 728 | const existing_sym: Symbol = existing_loc.getSymbol(self).*; | 747 | const existing_sym: Symbol = existing_loc.getSymbol(self).*; |
| 729 | | 748 | |
| ... | @@ -775,13 +794,13 @@ pub fn updateDeclExports( | ... | @@ -775,13 +794,13 @@ pub fn updateDeclExports( |
| 775 | } | 794 | } |
| 776 | // Ensure the symbol will be exported using the given name | 795 | // Ensure the symbol will be exported using the given name |
| 777 | if (!mem.eql(u8, exp.options.name, sym_loc.getName(self))) { | 796 | if (!mem.eql(u8, exp.options.name, sym_loc.getName(self))) { |
| 778 | try self.export_names.put(self.base.allocator, sym_loc, exp.options.name); | 797 | try self.export_names.put(self.base.allocator, sym_loc, export_name); |
| 779 | } | 798 | } |
| 780 | | 799 | |
| 781 | symbol.setGlobal(true); | 800 | symbol.setGlobal(true); |
| 782 | try self.globals.put( | 801 | try self.globals.put( |
| 783 | self.base.allocator, | 802 | self.base.allocator, |
| 784 | exp.options.name, | 803 | export_name, |
| 785 | sym_loc, | 804 | sym_loc, |
| 786 | ); | 805 | ); |
| 787 | | 806 | |
| ... | @@ -832,14 +851,14 @@ fn mapFunctionTable(self: *Wasm) void { | ... | @@ -832,14 +851,14 @@ fn mapFunctionTable(self: *Wasm) void { |
| 832 | | 851 | |
| 833 | fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | 852 | fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 834 | // For the import name itself, we use the decl's name, rather than the fully qualified name | 853 | // For the import name itself, we use the decl's name, rather than the fully qualified name |
| 835 | const decl_name = mem.sliceTo(decl.name, 0); | 854 | const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0)); |
| 836 | const symbol_index = decl.link.wasm.sym_index; | 855 | const symbol_index = decl.link.wasm.sym_index; |
| 837 | const symbol: *Symbol = &self.symbols.items[symbol_index]; | 856 | const symbol: *Symbol = &self.symbols.items[symbol_index]; |
| 838 | symbol.setUndefined(true); | 857 | symbol.setUndefined(true); |
| 839 | symbol.setGlobal(true); | 858 | symbol.setGlobal(true); |
| 840 | try self.globals.putNoClobber( | 859 | try self.globals.putNoClobber( |
| 841 | self.base.allocator, | 860 | self.base.allocator, |
| 842 | decl_name, | 861 | decl_name_index, |
| 843 | .{ .file = null, .index = symbol_index }, | 862 | .{ .file = null, .index = symbol_index }, |
| 844 | ); | 863 | ); |
| 845 | try self.resolved_symbols.put(self.base.allocator, .{ .file = null, .index = symbol_index }, {}); | 864 | try self.resolved_symbols.put(self.base.allocator, .{ .file = null, .index = symbol_index }, {}); |
| ... | @@ -852,8 +871,8 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -852,8 +871,8 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 852 | } else self.host_name; | 871 | } else self.host_name; |
| 853 | if (!gop.found_existing) { | 872 | if (!gop.found_existing) { |
| 854 | gop.value_ptr.* = .{ | 873 | gop.value_ptr.* = .{ |
| 855 | .module_name = module_name, | 874 | .module_name = try self.string_table.put(self.base.allocator, module_name), |
| 856 | .name = decl_name, | 875 | .name = decl_name_index, |
| 857 | .kind = .{ .function = decl.fn_link.wasm.type_index }, | 876 | .kind = .{ .function = decl.fn_link.wasm.type_index }, |
| 858 | }; | 877 | }; |
| 859 | } | 878 | } |
| ... | @@ -1001,9 +1020,18 @@ fn setupImports(self: *Wasm) !void { | ... | @@ -1001,9 +1020,18 @@ fn setupImports(self: *Wasm) !void { |
| 1001 | } | 1020 | } |
| 1002 | | 1021 | |
| 1003 | log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(self)}); | 1022 | log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(self)}); |
| 1004 | const import = self.objects.items[symbol_loc.file.?].findImport(symbol.tag.externalType(), symbol.index); | 1023 | const object = self.objects.items[symbol_loc.file.?]; |
| 1005 | // TODO: De-duplicate imports | 1024 | const import = object.findImport(symbol.tag.externalType(), symbol.index); |
| 1006 | try self.imports.putNoClobber(self.base.allocator, symbol_loc, import); | 1025 | |
| | 1026 | // We copy the import to a new import to ensure the names contain references |
| | 1027 | // to the internal string table, rather than of the object file. |
| | 1028 | var new_imp: types.Import = .{ |
| | 1029 | .module_name = try self.string_table.put(self.base.allocator, object.string_table.get(import.module_name)), |
| | 1030 | .name = try self.string_table.put(self.base.allocator, object.string_table.get(import.name)), |
| | 1031 | .kind = import.kind, |
| | 1032 | }; |
| | 1033 | // TODO: De-duplicate imports when they contain the same names and type |
| | 1034 | try self.imports.putNoClobber(self.base.allocator, symbol_loc, new_imp); |
| 1007 | } | 1035 | } |
| 1008 | | 1036 | |
| 1009 | // Assign all indexes of the imports to their representing symbols | 1037 | // Assign all indexes of the imports to their representing symbols |
| ... | @@ -1013,7 +1041,7 @@ fn setupImports(self: *Wasm) !void { | ... | @@ -1013,7 +1041,7 @@ fn setupImports(self: *Wasm) !void { |
| 1013 | var it = self.imports.iterator(); | 1041 | var it = self.imports.iterator(); |
| 1014 | while (it.next()) |entry| { | 1042 | while (it.next()) |entry| { |
| 1015 | const symbol = entry.key_ptr.*.getSymbol(self); | 1043 | const symbol = entry.key_ptr.*.getSymbol(self); |
| 1016 | const import: wasm.Import = entry.value_ptr.*; | 1044 | const import: types.Import = entry.value_ptr.*; |
| 1017 | switch (import.kind) { | 1045 | switch (import.kind) { |
| 1018 | .function => { | 1046 | .function => { |
| 1019 | symbol.index = function_index; | 1047 | symbol.index = function_index; |
| ... | @@ -1045,7 +1073,8 @@ fn setupImports(self: *Wasm) !void { | ... | @@ -1045,7 +1073,8 @@ fn setupImports(self: *Wasm) !void { |
| 1045 | /// and merges it into a single section for each. | 1073 | /// and merges it into a single section for each. |
| 1046 | fn mergeSections(self: *Wasm) !void { | 1074 | fn mergeSections(self: *Wasm) !void { |
| 1047 | // append the indirect function table if initialized | 1075 | // append the indirect function table if initialized |
| 1048 | if (self.globals.get("__indirect_function_table")) |sym_loc| { | 1076 | if (self.string_table.getOffset("__indirect_function_table")) |offset| { |
| | 1077 | const sym_loc = self.globals.get(offset).?; |
| 1049 | const table: wasm.Table = .{ | 1078 | const table: wasm.Table = .{ |
| 1050 | .limits = .{ .min = @intCast(u32, self.function_table.count()), .max = null }, | 1079 | .limits = .{ .min = @intCast(u32, self.function_table.count()), .max = null }, |
| 1051 | .reftype = .funcref, | 1080 | .reftype = .funcref, |
| ... | @@ -1114,7 +1143,7 @@ fn mergeTypes(self: *Wasm) !void { | ... | @@ -1114,7 +1143,7 @@ fn mergeTypes(self: *Wasm) !void { |
| 1114 | | 1143 | |
| 1115 | if (symbol.isUndefined()) { | 1144 | if (symbol.isUndefined()) { |
| 1116 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)}); | 1145 | log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)}); |
| 1117 | const import: *wasm.Import = self.imports.getPtr(sym_loc).?; | 1146 | const import: *types.Import = self.imports.getPtr(sym_loc).?; |
| 1118 | const original_type = object.func_types[import.kind.function]; | 1147 | const original_type = object.func_types[import.kind.function]; |
| 1119 | import.kind.function = try self.putOrGetFuncType(original_type); | 1148 | import.kind.function = try self.putOrGetFuncType(original_type); |
| 1120 | } else { | 1149 | } else { |
| ... | @@ -1135,13 +1164,13 @@ fn setupExports(self: *Wasm) !void { | ... | @@ -1135,13 +1164,13 @@ fn setupExports(self: *Wasm) !void { |
| 1135 | if (!symbol.isExported()) continue; | 1164 | if (!symbol.isExported()) continue; |
| 1136 | | 1165 | |
| 1137 | const sym_name = sym_loc.getName(self); | 1166 | const sym_name = sym_loc.getName(self); |
| 1138 | const export_name = if (self.export_names.get(sym_loc)) |name| name else sym_name; | 1167 | const export_name = if (self.export_names.get(sym_loc)) |name| name else symbol.name; |
| 1139 | const exp: wasm.Export = .{ | 1168 | const exp: types.Export = .{ |
| 1140 | .name = export_name, | 1169 | .name = export_name, |
| 1141 | .kind = symbol.tag.externalType(), | 1170 | .kind = symbol.tag.externalType(), |
| 1142 | .index = symbol.index, | 1171 | .index = symbol.index, |
| 1143 | }; | 1172 | }; |
| 1144 | log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ sym_name, exp.name, exp.index }); | 1173 | log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{ sym_name, self.string_table.get(exp.name), exp.index }); |
| 1145 | try self.exports.append(self.base.allocator, exp); | 1174 | try self.exports.append(self.base.allocator, exp); |
| 1146 | } | 1175 | } |
| 1147 | | 1176 | |
| ... | @@ -1151,7 +1180,7 @@ fn setupExports(self: *Wasm) !void { | ... | @@ -1151,7 +1180,7 @@ fn setupExports(self: *Wasm) !void { |
| 1151 | fn setupStart(self: *Wasm) !void { | 1180 | fn setupStart(self: *Wasm) !void { |
| 1152 | const entry_name = self.base.options.entry orelse "_start"; | 1181 | const entry_name = self.base.options.entry orelse "_start"; |
| 1153 | | 1182 | |
| 1154 | const symbol_loc = self.globals.get(entry_name) orelse { | 1183 | const symbol_name_offset = self.string_table.getOffset(entry_name) orelse { |
| 1155 | if (self.base.options.output_mode == .Exe) { | 1184 | if (self.base.options.output_mode == .Exe) { |
| 1156 | if (self.base.options.wasi_exec_model == .reactor) return; // Not required for reactors | 1185 | if (self.base.options.wasi_exec_model == .reactor) return; // Not required for reactors |
| 1157 | } else { | 1186 | } else { |
| ... | @@ -1161,6 +1190,7 @@ fn setupStart(self: *Wasm) !void { | ... | @@ -1161,6 +1190,7 @@ fn setupStart(self: *Wasm) !void { |
| 1161 | return error.MissingSymbol; | 1190 | return error.MissingSymbol; |
| 1162 | }; | 1191 | }; |
| 1163 | | 1192 | |
| | 1193 | const symbol_loc = self.globals.get(symbol_name_offset).?; |
| 1164 | const symbol = symbol_loc.getSymbol(self); | 1194 | const symbol = symbol_loc.getSymbol(self); |
| 1165 | if (symbol.tag != .function) { | 1195 | if (symbol.tag != .function) { |
| 1166 | log.err("Entry symbol '{s}' is not a function", .{entry_name}); | 1196 | log.err("Entry symbol '{s}' is not a function", .{entry_name}); |
| ... | @@ -1443,9 +1473,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1443,9 +1473,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1443 | | 1473 | |
| 1444 | // import table is always first table so emit that first | 1474 | // import table is always first table so emit that first |
| 1445 | if (import_table) { | 1475 | if (import_table) { |
| 1446 | const table_imp: wasm.Import = .{ | 1476 | const table_imp: types.Import = .{ |
| 1447 | .module_name = self.host_name, | 1477 | .module_name = try self.string_table.put(self.base.allocator, self.host_name), |
| 1448 | .name = "__indirect_function_table", | 1478 | .name = try self.string_table.put(self.base.allocator, "__indirect_function_table"), |
| 1449 | .kind = .{ | 1479 | .kind = .{ |
| 1450 | .table = .{ | 1480 | .table = .{ |
| 1451 | .limits = .{ | 1481 | .limits = .{ |
| ... | @@ -1456,23 +1486,23 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1456,23 +1486,23 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1456 | }, | 1486 | }, |
| 1457 | }, | 1487 | }, |
| 1458 | }; | 1488 | }; |
| 1459 | try emitImport(writer, table_imp); | 1489 | try self.emitImport(writer, table_imp); |
| 1460 | } | 1490 | } |
| 1461 | | 1491 | |
| 1462 | var it = self.imports.iterator(); | 1492 | var it = self.imports.iterator(); |
| 1463 | while (it.next()) |entry| { | 1493 | while (it.next()) |entry| { |
| 1464 | assert(entry.key_ptr.*.getSymbol(self).isUndefined()); | 1494 | assert(entry.key_ptr.*.getSymbol(self).isUndefined()); |
| 1465 | const import = entry.value_ptr.*; | 1495 | const import = entry.value_ptr.*; |
| 1466 | try emitImport(writer, import); | 1496 | try self.emitImport(writer, import); |
| 1467 | } | 1497 | } |
| 1468 | | 1498 | |
| 1469 | if (import_memory) { | 1499 | if (import_memory) { |
| 1470 | const mem_imp: wasm.Import = .{ | 1500 | const mem_imp: types.Import = .{ |
| 1471 | .module_name = self.host_name, | 1501 | .module_name = try self.string_table.put(self.base.allocator, self.host_name), |
| 1472 | .name = "__linear_memory", | 1502 | .name = try self.string_table.put(self.base.allocator, "__linear_memory"), |
| 1473 | .kind = .{ .memory = self.memories.limits }, | 1503 | .kind = .{ .memory = self.memories.limits }, |
| 1474 | }; | 1504 | }; |
| 1475 | try emitImport(writer, mem_imp); | 1505 | try self.emitImport(writer, mem_imp); |
| 1476 | } | 1506 | } |
| 1477 | | 1507 | |
| 1478 | try writeVecSectionHeader( | 1508 | try writeVecSectionHeader( |
| ... | @@ -1567,8 +1597,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1567,8 +1597,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1567 | const header_offset = try reserveVecSectionHeader(file); | 1597 | const header_offset = try reserveVecSectionHeader(file); |
| 1568 | const writer = file.writer(); | 1598 | const writer = file.writer(); |
| 1569 | for (self.exports.items) |exp| { | 1599 | for (self.exports.items) |exp| { |
| 1570 | try leb.writeULEB128(writer, @intCast(u32, exp.name.len)); | 1600 | const name = self.string_table.get(exp.name); |
| 1571 | try writer.writeAll(exp.name); | 1601 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| | 1602 | try writer.writeAll(name); |
| 1572 | try leb.writeULEB128(writer, @enumToInt(exp.kind)); | 1603 | try leb.writeULEB128(writer, @enumToInt(exp.kind)); |
| 1573 | try leb.writeULEB128(writer, exp.index); | 1604 | try leb.writeULEB128(writer, exp.index); |
| 1574 | } | 1605 | } |
| ... | @@ -1747,9 +1778,12 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -1747,9 +1778,12 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 1747 | | 1778 | |
| 1748 | for (self.resolved_symbols.keys()) |sym_loc| { | 1779 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 1749 | const symbol = sym_loc.getSymbol(self).*; | 1780 | const symbol = sym_loc.getSymbol(self).*; |
| | 1781 | const name = if (symbol.isUndefined()) blk: { |
| | 1782 | break :blk self.string_table.get(self.imports.get(sym_loc).?.name); |
| | 1783 | } else sym_loc.getName(self); |
| 1750 | switch (symbol.tag) { | 1784 | switch (symbol.tag) { |
| 1751 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = sym_loc.getName(self) }), | 1785 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), |
| 1752 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = sym_loc.getName(self) }), | 1786 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = name }), |
| 1753 | else => {}, | 1787 | else => {}, |
| 1754 | } | 1788 | } |
| 1755 | } | 1789 | } |
| ... | @@ -1831,12 +1865,14 @@ fn emitInit(writer: anytype, init_expr: wasm.InitExpression) !void { | ... | @@ -1831,12 +1865,14 @@ fn emitInit(writer: anytype, init_expr: wasm.InitExpression) !void { |
| 1831 | try writer.writeByte(wasm.opcode(.end)); | 1865 | try writer.writeByte(wasm.opcode(.end)); |
| 1832 | } | 1866 | } |
| 1833 | | 1867 | |
| 1834 | fn emitImport(writer: anytype, import: wasm.Import) !void { | 1868 | fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void { |
| 1835 | try leb.writeULEB128(writer, @intCast(u32, import.module_name.len)); | 1869 | const module_name = self.string_table.get(import.module_name); |
| 1836 | try writer.writeAll(import.module_name); | 1870 | try leb.writeULEB128(writer, @intCast(u32, module_name.len)); |
| | 1871 | try writer.writeAll(module_name); |
| 1837 | | 1872 | |
| 1838 | try leb.writeULEB128(writer, @intCast(u32, import.name.len)); | 1873 | const name = self.string_table.get(import.name); |
| 1839 | try writer.writeAll(import.name); | 1874 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| | 1875 | try writer.writeAll(name); |
| 1840 | | 1876 | |
| 1841 | try writer.writeByte(@enumToInt(import.kind)); | 1877 | try writer.writeByte(@enumToInt(import.kind)); |
| 1842 | switch (import.kind) { | 1878 | switch (import.kind) { |
| ... | @@ -2353,7 +2389,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * | ... | @@ -2353,7 +2389,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: * |
| 2353 | try leb.writeULEB128(writer, @enumToInt(symbol.tag)); | 2389 | try leb.writeULEB128(writer, @enumToInt(symbol.tag)); |
| 2354 | try leb.writeULEB128(writer, symbol.flags); | 2390 | try leb.writeULEB128(writer, symbol.flags); |
| 2355 | | 2391 | |
| 2356 | const sym_name = if (self.export_names.get(sym_loc)) |exp_name| exp_name else sym_loc.getName(self); | 2392 | const sym_name = if (self.export_names.get(sym_loc)) |exp_name| self.string_table.get(exp_name) else sym_loc.getName(self); |
| 2357 | switch (symbol.tag) { | 2393 | switch (symbol.tag) { |
| 2358 | .data => { | 2394 | .data => { |
| 2359 | try leb.writeULEB128(writer, @intCast(u32, sym_name.len)); | 2395 | try leb.writeULEB128(writer, @intCast(u32, sym_name.len)); |