authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-31 21:56:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-31 22:01:10-07:00
loge501cf51a01f6f0ae4326180cdd4274588ceed1d
tree172175693b81ce2b14609fb9d6347487bdc3b926
parentbf9978a57a9d939aefb3babcca28f87cb34331b0

link.File.Wasm: unify the string tables

Before, the wasm struct had a string table, the ZigObject had a string table, and each Object had a string table. Now there is just the one. This makes for more efficient use of memory and simplifies logic, particularly with regards to linker state serialization. This commit additionally adds significantly more integer type safety.

5 files changed, 433 insertions(+), 460 deletions(-)

src/link/Wasm.zig+374-386
......@@ -36,11 +36,16 @@ const Value = @import("../Value.zig");
3636const ZigObject = @import("Wasm/ZigObject.zig");
3737
3838base: link.File,
39/// Null-terminated strings, indexes have type String and string_table provides
40/// lookup.
41string_bytes: std.ArrayListUnmanaged(u8),
42/// Omitted when serializing linker state.
43string_table: String.Table,
3944/// Symbol name of the entry function to export
40entry_name: ?[]const u8,
45entry_name: OptionalString,
4146/// When true, will allow undefined symbols
4247import_symbols: bool,
43/// List of *global* symbol names to export to the host environment.
48/// Set of *global* symbol names to export to the host environment.
4449export_symbol_names: []const []const u8,
4550/// When defined, sets the start of the data section.
4651global_base: ?u64,
......@@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{},
6368/// LLVM uses "env" by default when none is given. This would be a good default for Zig
6469/// to support existing code.
6570/// TODO: Allow setting this through a flag?
66host_name: []const u8 = "env",
71host_name: String,
6772/// List of symbols generated by the linker.
6873synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty,
6974/// Maps atoms to their segment index
70atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .empty,
75atoms: std.AutoHashMapUnmanaged(Segment.Index, Atom.Index) = .empty,
7176/// List of all atoms.
7277managed_atoms: std.ArrayListUnmanaged(Atom) = .empty,
73/// Represents the index into `segments` where the 'code' section
74/// lives.
75code_section_index: ?u32 = null,
76/// The index of the segment representing the custom '.debug_info' section.
77debug_info_index: ?u32 = null,
78/// The index of the segment representing the custom '.debug_line' section.
79debug_line_index: ?u32 = null,
80/// The index of the segment representing the custom '.debug_loc' section.
81debug_loc_index: ?u32 = null,
82/// The index of the segment representing the custom '.debug_ranges' section.
83debug_ranges_index: ?u32 = null,
84/// The index of the segment representing the custom '.debug_pubnames' section.
85debug_pubnames_index: ?u32 = null,
86/// The index of the segment representing the custom '.debug_pubtypes' section.
87debug_pubtypes_index: ?u32 = null,
88/// The index of the segment representing the custom '.debug_pubtypes' section.
89debug_str_index: ?u32 = null,
90/// The index of the segment representing the custom '.debug_pubtypes' section.
91debug_abbrev_index: ?u32 = null,
78
9279/// The count of imported functions. This number will be appended
9380/// to the function indexes as their index starts at the lowest non-extern function.
9481imported_functions_count: u32 = 0,
......@@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,
10491/// Used for code, data and custom sections.
10592segments: std.ArrayListUnmanaged(Segment) = .empty,
10693/// Maps a data segment key (such as .rodata) to the index into `segments`.
107data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,
94data_segments: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty,
10895/// A table of `NamedSegment` which provide meta data
10996/// about a data symbol such as its name where the key is
11097/// the segment index, which can be found from `data_segments`
111segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty,
112/// Deduplicated string table for strings used by symbols, imports and exports.
113string_table: StringTable = .{},
98segment_info: std.AutoArrayHashMapUnmanaged(Segment.Index, NamedSegment) = .empty,
11499
115100// Output sections
116101/// Output type section
......@@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,
158143/// e.g. when an undefined symbol references a symbol from the archive.
159144lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty,
160145
161/// A map of global names (read: offset into string table) to their symbol location
162globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .empty,
146/// A map of global names to their symbol location
147globals: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
163148/// The list of GOT symbols and their location
164149got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty,
165150/// Maps discarded symbols and their positions to the location of the symbol
......@@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty,
169154/// into the final binary.
170155resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty,
171156/// Symbols that remain undefined after symbol resolution.
172/// Note: The key represents an offset into the string table, rather than the actual string.
173undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,
157undefs: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
174158/// Maps a symbol's location to an atom. This can be used to find meta
175159/// data of a symbol, such as its size, or its offset to perform a relocation.
176160/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
......@@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,
178162
179163/// `--verbose-link` output.
180164/// Initialized on creation, appended to as inputs are added, printed during `flush`.
165/// String data is allocated into Compilation arena.
181166dump_argv_list: std.ArrayListUnmanaged([]const u8),
182167
168/// Represents the index into `segments` where the 'code' section lives.
169code_section_index: Segment.OptionalIndex = .none,
170custom_sections: CustomSections,
171preloaded_strings: PreloadedStrings,
172
173/// Type reflection is used on the field names to autopopulate each field
174/// during initialization.
175const PreloadedStrings = struct {
176 __heap_base: String,
177 __heap_end: String,
178 __indirect_function_table: String,
179 __linear_memory: String,
180 __stack_pointer: String,
181 __tls_align: String,
182 __tls_base: String,
183 __tls_size: String,
184 __wasm_apply_global_tls_relocs: String,
185 __wasm_call_ctors: String,
186 __wasm_init_memory: String,
187 __wasm_init_memory_flag: String,
188 __wasm_init_tls: String,
189 __zig_err_name_table: String,
190 __zig_err_names: String,
191 __zig_errors_len: String,
192 _initialize: String,
193 _start: String,
194 memory: String,
195};
196
197/// Type reflection is used on the field names to autopopulate each inner `name` field.
198const CustomSections = struct {
199 @".debug_info": CustomSection,
200 @".debug_pubtypes": CustomSection,
201 @".debug_abbrev": CustomSection,
202 @".debug_line": CustomSection,
203 @".debug_str": CustomSection,
204 @".debug_pubnames": CustomSection,
205 @".debug_loc": CustomSection,
206 @".debug_ranges": CustomSection,
207};
208
209const CustomSection = struct {
210 name: String,
211 index: Segment.OptionalIndex,
212};
213
214/// Index into string_bytes
215pub const String = enum(u32) {
216 _,
217
218 const Table = std.HashMapUnmanaged(String, void, TableContext, std.hash_map.default_max_load_percentage);
219
220 const TableContext = struct {
221 bytes: []const u8,
222
223 pub fn eql(_: @This(), a: String, b: String) bool {
224 return a == b;
225 }
226
227 pub fn hash(ctx: @This(), key: String) u64 {
228 return std.hash_map.hashString(mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0));
229 }
230 };
231
232 const TableIndexAdapter = struct {
233 bytes: []const u8,
234
235 pub fn eql(ctx: @This(), a: []const u8, b: String) bool {
236 return mem.eql(u8, a, mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0));
237 }
238
239 pub fn hash(_: @This(), adapted_key: []const u8) u64 {
240 assert(mem.indexOfScalar(u8, adapted_key, 0) == null);
241 return std.hash_map.hashString(adapted_key);
242 }
243 };
244
245 pub fn toOptional(i: String) OptionalString {
246 const result: OptionalString = @enumFromInt(@intFromEnum(i));
247 assert(result != .none);
248 return result;
249 }
250};
251
252pub const OptionalString = enum(u32) {
253 none = std.math.maxInt(u32),
254 _,
255
256 pub fn unwrap(i: OptionalString) ?String {
257 if (i == .none) return null;
258 return @enumFromInt(@intFromEnum(i));
259 }
260};
261
183262/// Index into objects array or the zig object.
184263pub const ObjectId = enum(u16) {
185264 zig_object = std.math.maxInt(u16) - 1,
......@@ -222,6 +301,26 @@ pub const Segment = struct {
222301 offset: u32,
223302 flags: u32,
224303
304 const Index = enum(u32) {
305 _,
306
307 pub fn toOptional(i: Index) OptionalIndex {
308 const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
309 assert(result != .none);
310 return result;
311 }
312 };
313
314 const OptionalIndex = enum(u32) {
315 none = std.math.maxInt(u32),
316 _,
317
318 pub fn unwrap(i: OptionalIndex) ?Index {
319 if (i == .none) return null;
320 return @enumFromInt(@intFromEnum(i));
321 }
322 };
323
225324 pub const Flag = enum(u32) {
226325 WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,
227326 WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
......@@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {
260359}
261360
262361/// From a given location, returns the name of the symbol.
263pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 {
264 if (wasm.discarded.get(loc)) |new_loc| {
265 return wasm.symbolLocName(new_loc);
266 }
267 switch (loc.file) {
268 .none => {
269 const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)];
270 return wasm.string_table.get(sym.name);
271 },
272 .zig_object => {
273 const zo = wasm.zig_object.?;
274 const sym = zo.symbols.items[@intFromEnum(loc.index)];
275 return zo.string_table.get(sym.name).?;
276 },
277 _ => {
278 const obj = &wasm.objects.items[@intFromEnum(loc.file)];
279 const sym = obj.symtable[@intFromEnum(loc.index)];
280 return obj.string_table.get(sym.name);
281 },
282 }
362pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) [:0]const u8 {
363 return wasm.stringSlice(wasm.symbolLocSymbol(loc).name);
283364}
284365
285366/// From a given symbol location, returns the final location.
......@@ -325,75 +406,6 @@ pub const InitFuncLoc = struct {
325406 return lhs.priority < rhs.priority;
326407 }
327408};
328/// Generic string table that duplicates strings
329/// and converts them into offsets instead.
330pub const StringTable = struct {
331 /// Table that maps string offsets, which is used to de-duplicate strings.
332 /// Rather than having the offset map to the data, the `StringContext` holds all bytes of the string.
333 /// The strings are stored as a contigious array where each string is zero-terminated.
334 string_table: std.HashMapUnmanaged(
335 u32,
336 void,
337 std.hash_map.StringIndexContext,
338 std.hash_map.default_max_load_percentage,
339 ) = .{},
340 /// Holds the actual data of the string table.
341 string_data: std.ArrayListUnmanaged(u8) = .empty,
342
343 /// Accepts a string and searches for a corresponding string.
344 /// When found, de-duplicates the string and returns the existing offset instead.
345 /// When the string is not found in the `string_table`, a new entry will be inserted
346 /// and the new offset to its data will be returned.
347 pub fn put(table: *StringTable, allocator: Allocator, string: []const u8) !u32 {
348 const gop = try table.string_table.getOrPutContextAdapted(
349 allocator,
350 string,
351 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
352 .{ .bytes = &table.string_data },
353 );
354 if (gop.found_existing) {
355 const off = gop.key_ptr.*;
356 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
357 return off;
358 }
359
360 try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);
361 const offset: u32 = @intCast(table.string_data.items.len);
362
363 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
364
365 table.string_data.appendSliceAssumeCapacity(string);
366 table.string_data.appendAssumeCapacity(0);
367
368 gop.key_ptr.* = offset;
369
370 return offset;
371 }
372
373 /// From a given offset, returns its corresponding string value.
374 /// Asserts offset does not exceed bounds.
375 pub fn get(table: StringTable, off: u32) []const u8 {
376 assert(off < table.string_data.items.len);
377 return mem.sliceTo(@as([*:0]const u8, @ptrCast(table.string_data.items.ptr + off)), 0);
378 }
379
380 /// Returns the offset of a given string when it exists.
381 /// Will return null if the given string does not yet exist within the string table.
382 pub fn getOffset(table: *StringTable, string: []const u8) ?u32 {
383 return table.string_table.getKeyAdapted(
384 string,
385 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
386 );
387 }
388
389 /// Frees all resources of the string table. Any references pointing
390 /// to the strings will be invalid.
391 pub fn deinit(table: *StringTable, allocator: Allocator) void {
392 table.string_data.deinit(allocator);
393 table.string_table.deinit(allocator);
394 table.* = undefined;
395 }
396};
397409
398410pub fn open(
399411 arena: Allocator,
......@@ -451,6 +463,8 @@ pub fn createEmpty(
451463 .build_id = options.build_id,
452464 },
453465 .name = undefined,
466 .string_table = .empty,
467 .string_bytes = .empty,
454468 .import_table = options.import_table,
455469 .export_table = options.export_table,
456470 .import_symbols = options.import_symbols,
......@@ -459,20 +473,38 @@ pub fn createEmpty(
459473 .initial_memory = options.initial_memory,
460474 .max_memory = options.max_memory,
461475
462 .entry_name = switch (options.entry) {
463 .disabled => null,
464 .default => if (output_mode != .Exe) null else defaultEntrySymbolName(wasi_exec_model),
465 .enabled => defaultEntrySymbolName(wasi_exec_model),
466 .named => |name| name,
467 },
476 .entry_name = undefined,
468477 .zig_object = null,
469478 .dump_argv_list = .empty,
479 .host_name = undefined,
480 .custom_sections = undefined,
481 .preloaded_strings = undefined,
470482 };
471483 if (use_llvm and comp.config.have_zcu) {
472484 wasm.llvm_object = try LlvmObject.create(arena, comp);
473485 }
474486 errdefer wasm.base.destroy();
475487
488 wasm.host_name = try wasm.internString("env");
489
490 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
491 @field(wasm.custom_sections, field.name) = .{
492 .index = .none,
493 .name = try wasm.internString(field.name),
494 };
495 }
496
497 inline for (@typeInfo(PreloadedStrings).@"struct".fields) |field| {
498 @field(wasm.preloaded_strings, field.name) = try wasm.internString(field.name);
499 }
500
501 wasm.entry_name = switch (options.entry) {
502 .disabled => .none,
503 .default => if (output_mode != .Exe) .none else defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
504 .enabled => defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
505 .named => |name| (try wasm.internString(name)).toOptional(),
506 };
507
476508 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
477509 // LLVM emits the object file (if any); LLD links it into the final product.
478510 return wasm;
......@@ -498,22 +530,18 @@ pub fn createEmpty(
498530
499531 // create stack pointer symbol
500532 {
501 const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
533 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__stack_pointer, .global);
502534 const symbol = wasm.symbolLocSymbol(loc);
503535 // For object files we will import the stack pointer symbol
504536 if (output_mode == .Obj) {
505537 symbol.setUndefined(true);
506538 symbol.index = @intCast(wasm.imported_globals_count);
507539 wasm.imported_globals_count += 1;
508 try wasm.imports.putNoClobber(
509 gpa,
510 loc,
511 .{
512 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
513 .name = symbol.name,
514 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
515 },
516 );
540 try wasm.imports.putNoClobber(gpa, loc, .{
541 .module_name = wasm.host_name,
542 .name = symbol.name,
543 .kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
544 });
517545 } else {
518546 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
519547 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
......@@ -530,7 +558,7 @@ pub fn createEmpty(
530558
531559 // create indirect function pointer symbol
532560 {
533 const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
561 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__indirect_function_table, .table);
534562 const symbol = wasm.symbolLocSymbol(loc);
535563 const table: std.wasm.Table = .{
536564 .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
......@@ -541,7 +569,7 @@ pub fn createEmpty(
541569 symbol.index = @intCast(wasm.imported_tables_count);
542570 wasm.imported_tables_count += 1;
543571 try wasm.imports.put(gpa, loc, .{
544 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
572 .module_name = wasm.host_name,
545573 .name = symbol.name,
546574 .kind = .{ .table = table },
547575 });
......@@ -558,7 +586,7 @@ pub fn createEmpty(
558586
559587 // create __wasm_call_ctors
560588 {
561 const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
589 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_call_ctors, .function);
562590 const symbol = wasm.symbolLocSymbol(loc);
563591 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
564592 // we do not know the function index until after we merged all sections.
......@@ -569,7 +597,7 @@ pub fn createEmpty(
569597 // shared-memory symbols for TLS support
570598 if (shared_memory) {
571599 {
572 const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
600 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_base, .global);
573601 const symbol = wasm.symbolLocSymbol(loc);
574602 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
575603 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
......@@ -580,7 +608,7 @@ pub fn createEmpty(
580608 });
581609 }
582610 {
583 const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
611 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_size, .global);
584612 const symbol = wasm.symbolLocSymbol(loc);
585613 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
586614 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
......@@ -591,7 +619,7 @@ pub fn createEmpty(
591619 });
592620 }
593621 {
594 const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
622 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_align, .global);
595623 const symbol = wasm.symbolLocSymbol(loc);
596624 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
597625 symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
......@@ -602,7 +630,7 @@ pub fn createEmpty(
602630 });
603631 }
604632 {
605 const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
633 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_tls, .function);
606634 const symbol = wasm.symbolLocSymbol(loc);
607635 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
608636 }
......@@ -655,13 +683,11 @@ pub fn addOrUpdateImport(
655683
656684/// For a given name, creates a new global synthetic symbol.
657685/// Leaves index undefined and the default flags (0).
658fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {
659 const gpa = wasm.base.comp.gpa;
660 const name_offset = try wasm.string_table.put(gpa, name);
661 return wasm.createSyntheticSymbolOffset(name_offset, tag);
686fn createSyntheticSymbol(wasm: *Wasm, name: String, tag: Symbol.Tag) !SymbolLoc {
687 return wasm.createSyntheticSymbolOffset(name, tag);
662688}
663689
664fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
690fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: String, tag: Symbol.Tag) !SymbolLoc {
665691 const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);
666692 const loc: SymbolLoc = .{ .index = sym_index, .file = .none };
667693 const gpa = wasm.base.comp.gpa;
......@@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy
803829 return &obj.symtable[@intFromEnum(index)];
804830}
805831
806fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 {
807 const obj = wasm.objectById(object_id) orelse {
808 const zo = wasm.zig_object.?;
809 const sym = zo.symbols.items[@intFromEnum(index)];
810 return zo.string_table.get(sym.name).?;
811 };
812 const sym = obj.symtable[@intFromEnum(index)];
813 return obj.string_table.get(sym.name);
814}
815
816832fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func {
817833 const obj = wasm.objectById(object_id) orelse {
818834 const zo = wasm.zig_object.?;
......@@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind
850866 return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]);
851867}
852868
853/// For a given offset, returns its string value.
854/// Asserts string exists in the object string table.
855fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 {
856 const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?;
857 return obj.string_table.get(offset);
858}
859
860869/// Returns the object element pointer, or null if it is the ZigObject.
861870fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object {
862871 if (object_id == .zig_object) return null;
......@@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
876885 .file = object_id.toOptional(),
877886 .index = sym_index,
878887 };
879 const sym_name = objectString(wasm, object_id, symbol.name);
880 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
881 continue;
882 }
883 const sym_name_index = try wasm.string_table.put(gpa, sym_name);
888 if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
884889
885890 if (symbol.isLocal()) {
886891 if (symbol.isUndefined()) {
887 diags.addParseError(obj_path, "local symbol '{s}' references import", .{sym_name});
892 diags.addParseError(obj_path, "local symbol '{s}' references import", .{
893 wasm.stringSlice(symbol.name),
894 });
888895 }
889896 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
890897 continue;
891898 }
892899
893 const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index);
900 const maybe_existing = try wasm.globals.getOrPut(gpa, symbol.name);
894901 if (!maybe_existing.found_existing) {
895902 maybe_existing.value_ptr.* = location;
896903 try wasm.resolved_symbols.putNoClobber(gpa, location, {});
897904
898905 if (symbol.isUndefined()) {
899 try wasm.undefs.putNoClobber(gpa, sym_name_index, location);
906 try wasm.undefs.putNoClobber(gpa, symbol.name, location);
900907 }
901908 continue;
902909 }
......@@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
918925 }
919926 // both are defined and weak, we have a symbol collision.
920927 var err = try diags.addErrorWithNotes(2);
921 try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});
928 try err.addMsg("symbol '{s}' defined multiple times", .{wasm.stringSlice(symbol.name)});
922929 try err.addNote("first definition in '{'}'", .{existing_file_path});
923930 try err.addNote("next definition in '{'}'", .{obj_path});
924931 }
......@@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
929936
930937 if (symbol.tag != existing_sym.tag) {
931938 var err = try diags.addErrorWithNotes(2);
932 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });
939 try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{
940 wasm.stringSlice(symbol.name), @tagName(symbol.tag), @tagName(existing_sym.tag),
941 });
933942 try err.addNote("first definition in '{'}'", .{existing_file_path});
934943 try err.addNote("next definition in '{'}'", .{obj_path});
935944 }
......@@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
937946 if (existing_sym.isUndefined() and symbol.isUndefined()) {
938947 // only verify module/import name for function symbols
939948 if (symbol.tag == .function) {
940 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: {
941 const imp = objectImport(wasm, existing_obj_id, existing_loc.index);
942 break :blk objectString(wasm, existing_obj_id, imp.module_name);
943 } else blk: {
944 const name_index = wasm.imports.get(existing_loc).?.module_name;
945 break :blk wasm.string_table.get(name_index);
946 };
949 const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id|
950 objectImport(wasm, existing_obj_id, existing_loc.index).module_name
951 else
952 wasm.imports.get(existing_loc).?.module_name;
947953
948 const imp = objectImport(wasm, object_id, sym_index);
949 const module_name = objectString(wasm, object_id, imp.module_name);
950 if (!mem.eql(u8, existing_name, module_name)) {
954 const module_name = objectImport(wasm, object_id, sym_index).module_name;
955 if (existing_name != module_name) {
951956 var err = try diags.addErrorWithNotes(2);
952957 try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
953 sym_name,
954 existing_name,
955 module_name,
958 wasm.stringSlice(symbol.name),
959 wasm.stringSlice(existing_name),
960 wasm.stringSlice(module_name),
956961 });
957962 try err.addNote("first definition in '{'}'", .{existing_file_path});
958963 try err.addNote("next definition in '{'}'", .{obj_path});
......@@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
969974 const new_ty = wasm.getGlobalType(location);
970975 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
971976 var err = try diags.addErrorWithNotes(2);
972 try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});
977 try err.addMsg("symbol '{s}' mismatching global types", .{wasm.stringSlice(symbol.name)});
973978 try err.addNote("first definition in '{'}'", .{existing_file_path});
974979 try err.addNote("next definition in '{'}'", .{obj_path});
975980 }
......@@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
980985 const new_ty = wasm.getFunctionSignature(location);
981986 if (!existing_ty.eql(new_ty)) {
982987 var err = try diags.addErrorWithNotes(3);
983 try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});
988 try err.addMsg("symbol '{s}' mismatching function signatures.", .{wasm.stringSlice(symbol.name)});
984989 try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
985990 try err.addNote("first definition in '{'}'", .{existing_file_path});
986991 try err.addNote("next definition in '{'}'", .{obj_path});
......@@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
9961001 }
9971002
9981003 // simply overwrite with the new symbol
999 log.debug("Overwriting symbol '{s}'", .{sym_name});
1004 log.debug("Overwriting symbol '{s}'", .{wasm.stringSlice(symbol.name)});
10001005 log.debug(" old definition in '{'}'", .{existing_file_path});
10011006 log.debug(" new definition in '{'}'", .{obj_path});
10021007 try wasm.discarded.putNoClobber(gpa, existing_loc, location);
10031008 maybe_existing.value_ptr.* = location;
1004 try wasm.globals.put(gpa, sym_name_index, location);
1009 try wasm.globals.put(gpa, symbol.name, location);
10051010 try wasm.resolved_symbols.put(gpa, location, {});
10061011 assert(wasm.resolved_symbols.swapRemove(existing_loc));
10071012 if (existing_sym.isUndefined()) {
1008 _ = wasm.undefs.swapRemove(sym_name_index);
1013 _ = wasm.undefs.swapRemove(symbol.name);
10091014 }
10101015 }
10111016}
......@@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
10211026 const sym_name_index = wasm.undefs.keys()[index];
10221027
10231028 for (wasm.lazy_archives.items) |lazy_archive| {
1024 const sym_name = wasm.string_table.get(sym_name_index);
1029 const sym_name = wasm.stringSlice(sym_name_index);
10251030 log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{
10261031 sym_name, lazy_archive.path,
10271032 });
......@@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
10661071 if (!wasm.hasPassiveInitializationSegments()) {
10671072 return;
10681073 }
1069 const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);
1074 const sym_loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory, .function);
10701075 wasm.symbolLocSymbol(sym_loc).mark();
10711076
10721077 const flag_address: u32 = if (shared_memory) address: {
10731078 // when we have passive initialization segments and shared memory
10741079 // `setupMemory` will create this symbol and set its virtual address.
1075 const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
1080 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory_flag).?;
10761081 break :address wasm.symbolLocSymbol(loc).virtual_address;
10771082 } else 0;
10781083
......@@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
11131118 try writer.writeByte(std.wasm.opcode(.end));
11141119 }
11151120
1116 var it = wasm.data_segments.iterator();
1117 var segment_index: u32 = 0;
1118 while (it.next()) |entry| : (segment_index += 1) {
1119 const segment: Segment = wasm.segments.items[entry.value_ptr.*];
1120 if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
1121 for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |key, value, segment_index_usize| {
1122 const segment_index: u32 = @intCast(segment_index_usize);
1123 const segment = wasm.segmentPtr(value);
1124 if (segment.needsPassiveInitialization(import_memory, key)) {
11211125 // For passive BSS segments we can simple issue a memory.fill(0).
11221126 // For non-BSS segments we do a memory.init. Both these
11231127 // instructions take as their first argument the destination
11241128 // address.
11251129 try writeI32Const(writer, segment.offset);
11261130
1127 if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {
1131 if (shared_memory and std.mem.eql(u8, key, ".tdata")) {
11281132 // When we initialize the TLS segment we also set the `__tls_base`
11291133 // global. This allows the runtime to use this static copy of the
11301134 // TLS data for the first/main thread.
11311135 try writeI32Const(writer, segment.offset);
11321136 try writer.writeByte(std.wasm.opcode(.global_set));
1133 const loc = wasm.findGlobalSymbol("__tls_base").?;
1137 const loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
11341138 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
11351139 }
11361140
11371141 try writeI32Const(writer, 0);
11381142 try writeI32Const(writer, segment.size);
11391143 try writer.writeByte(std.wasm.opcode(.misc_prefix));
1140 if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) {
1144 if (std.mem.eql(u8, key, ".bss")) {
11411145 // fill bss segment with zeroes
11421146 try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill));
11431147 } else {
......@@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
11871191 try writer.writeByte(std.wasm.opcode(.end)); // end $drop
11881192 }
11891193
1190 it.reset();
1191 segment_index = 0;
1192 while (it.next()) |entry| : (segment_index += 1) {
1193 const name = entry.key_ptr.*;
1194 const segment: Segment = wasm.segments.items[entry.value_ptr.*];
1194 for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |name, value, segment_index_usize| {
1195 const segment_index: u32 = @intCast(segment_index_usize);
1196 const segment = wasm.segmentPtr(value);
11951197 if (segment.needsPassiveInitialization(import_memory, name) and
11961198 !std.mem.eql(u8, name, ".bss"))
11971199 {
......@@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
12111213 try writer.writeByte(std.wasm.opcode(.end));
12121214
12131215 try wasm.createSyntheticFunction(
1214 "__wasm_init_memory",
1216 wasm.preloaded_strings.__wasm_init_memory,
12151217 std.wasm.Type{ .params = &.{}, .returns = &.{} },
12161218 &function_body,
12171219 );
......@@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
12301232 return;
12311233 }
12321234
1233 const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);
1235 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_apply_global_tls_relocs, .function);
12341236 wasm.symbolLocSymbol(loc).mark();
12351237 var function_body = std.ArrayList(u8).init(gpa);
12361238 defer function_body.deinit();
......@@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
12441246 if (sym.tag == .data and sym.isDefined()) {
12451247 // get __tls_base
12461248 try writer.writeByte(std.wasm.opcode(.global_get));
1247 try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index);
1249 try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__tls_base).?).index);
12481250
12491251 // add the virtual address of the symbol
12501252 try writer.writeByte(std.wasm.opcode(.i32_const));
......@@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
12601262 try writer.writeByte(std.wasm.opcode(.end));
12611263
12621264 try wasm.createSyntheticFunction(
1263 "__wasm_apply_global_tls_relocs",
1265 wasm.preloaded_strings.__wasm_apply_global_tls_relocs,
12641266 std.wasm.Type{ .params = &.{}, .returns = &.{} },
12651267 &function_body,
12661268 );
......@@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
14221424 const gpa = comp.gpa;
14231425 const shared_memory = comp.config.shared_memory;
14241426
1425 if (wasm.string_table.getOffset("__heap_base")) |name_offset| {
1427 if (wasm.getExistingString("__heap_base")) |name_offset| {
14261428 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
14271429 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
14281430 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
......@@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
14301432 }
14311433 }
14321434
1433 if (wasm.string_table.getOffset("__heap_end")) |name_offset| {
1435 if (wasm.getExistingString("__heap_end")) |name_offset| {
14341436 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
14351437 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
14361438 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
......@@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
14391441 }
14401442
14411443 if (!shared_memory) {
1442 if (wasm.string_table.getOffset("__tls_base")) |name_offset| {
1444 if (wasm.getExistingString("__tls_base")) |name_offset| {
14431445 if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
14441446 const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
14451447 try wasm.discarded.putNoClobber(gpa, kv.value, loc);
......@@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
14561458 }
14571459}
14581460
1459// Tries to find a global symbol by its name. Returns null when not found,
1460/// and its location when it is found.
1461pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {
1462 const offset = wasm.string_table.getOffset(name) orelse return null;
1463 return wasm.globals.get(offset);
1461pub fn findGlobalSymbol(wasm: *const Wasm, name: []const u8) ?SymbolLoc {
1462 const name_index = wasm.getExistingString(name) orelse return null;
1463 return wasm.globals.get(name_index);
14641464}
14651465
14661466fn checkUndefinedSymbols(wasm: *const Wasm) !void {
......@@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void {
15161516 for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa);
15171517 wasm.lazy_archives.deinit(gpa);
15181518
1519 if (wasm.findGlobalSymbol("__wasm_init_tls")) |loc| {
1519 if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls)) |loc| {
15201520 const atom = wasm.symbol_atom.get(loc).?;
15211521 wasm.getAtomPtr(atom).deinit(gpa);
15221522 }
......@@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void {
15441544 wasm.init_funcs.deinit(gpa);
15451545 wasm.exports.deinit(gpa);
15461546
1547 wasm.string_bytes.deinit(gpa);
15471548 wasm.string_table.deinit(gpa);
15481549 wasm.dump_argv_list.deinit(gpa);
15491550}
......@@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
16491650/// and then returns the index to it.
16501651pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
16511652 _ = lib_name;
1652 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name);
1653 const name_index = try wasm.internString(name);
1654 return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name_index);
16531655}
16541656
16551657/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.
......@@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void {
17211723 }
17221724
17231725 if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) {
1724 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
1726 const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
17251727 const import = wasm.imports.getPtr(sym_loc).?;
17261728 import.kind.table.limits.min = index - 1; // we start at index 1.
17271729 } else if (index > 1) {
17281730 log.debug("Appending indirect function table", .{});
1729 const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
1731 const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
17301732 const symbol = wasm.symbolLocSymbol(sym_loc);
17311733 const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
17321734 table.limits = .{ .min = index, .max = index, .flags = 0x1 };
......@@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
17351737
17361738/// From a given index, append the given `Atom` at the back of the linked list.
17371739/// Simply inserts it into the map of atoms when it doesn't exist yet.
1738pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
1740pub fn appendAtomAtIndex(wasm: *Wasm, index: Segment.Index, atom_index: Atom.Index) !void {
17391741 const gpa = wasm.base.comp.gpa;
17401742 const atom = wasm.getAtomPtr(atom_index);
17411743 if (wasm.atoms.getPtr(index)) |last_index_ptr| {
......@@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void {
17521754
17531755 var it = wasm.atoms.iterator();
17541756 while (it.next()) |entry| {
1755 const segment = &wasm.segments.items[entry.key_ptr.*];
1757 const segment = wasm.segmentPtr(entry.key_ptr.*);
17561758 var atom_index = entry.value_ptr.*;
1757 if (entry.key_ptr.* == wasm.code_section_index) {
1759 if (entry.key_ptr.toOptional() == wasm.code_section_index) {
17581760 // Code section is allocated upon writing as they are required to be ordered
17591761 // to synchronise with the function section.
17601762 continue;
......@@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
18251827 };
18261828 const segment_name = segment_info[symbol.index].outputName(merge_segment);
18271829 const segment_index = wasm.data_segments.get(segment_name).?;
1828 const segment = wasm.segments.items[segment_index];
1830 const segment = wasm.segmentPtr(segment_index);
18291831
18301832 // TLS symbols have their virtual address set relative to their own TLS segment,
18311833 // rather than the entire Data section.
......@@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
18391841
18401842fn sortDataSegments(wasm: *Wasm) !void {
18411843 const gpa = wasm.base.comp.gpa;
1842 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .empty;
1844 var new_mapping: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty;
18431845 try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());
18441846 errdefer new_mapping.deinit(gpa);
18451847
......@@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void {
18941896 };
18951897 if (ty.params.len != 0) {
18961898 var err = try diags.addErrorWithNotes(0);
1897 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)});
1899 try err.addMsg("constructor functions cannot take arguments: '{s}'", .{wasm.stringSlice(symbol.name)});
18981900 }
1899 log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});
1901 log.debug("appended init func '{s}'\n", .{wasm.stringSlice(symbol.name)});
19001902 wasm.init_funcs.appendAssumeCapacity(.{
19011903 .index = @enumFromInt(init_func.symbol_index),
19021904 .file = @enumFromInt(object_index),
......@@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
19131915 mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
19141916
19151917 if (wasm.init_funcs.items.len > 0) {
1916 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
1918 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
19171919 try wasm.mark(loc);
19181920 }
19191921}
......@@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void {
19271929fn initializeCallCtorsFunction(wasm: *Wasm) !void {
19281930 const gpa = wasm.base.comp.gpa;
19291931 // No code to emit, so also no ctors to call
1930 if (wasm.code_section_index == null) {
1932 if (wasm.code_section_index == .none) {
19311933 // Make sure to remove it from the resolved symbols so we do not emit
19321934 // it within any section. TODO: Remove this once we implement garbage collection.
1933 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
1935 const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
19341936 assert(wasm.resolved_symbols.swapRemove(loc));
19351937 return;
19361938 }
......@@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
19651967 }
19661968
19671969 try wasm.createSyntheticFunction(
1968 "__wasm_call_ctors",
1970 wasm.preloaded_strings.__wasm_call_ctors,
19691971 std.wasm.Type{ .params = &.{}, .returns = &.{} },
19701972 &function_body,
19711973 );
......@@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
19731975
19741976fn createSyntheticFunction(
19751977 wasm: *Wasm,
1976 symbol_name: []const u8,
1978 symbol_name: String,
19771979 func_ty: std.wasm.Type,
19781980 function_body: *std.ArrayList(u8),
19791981) !void {
19801982 const gpa = wasm.base.comp.gpa;
1981 const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?
1983 const loc = wasm.globals.get(symbol_name).?;
19821984 const symbol = wasm.symbolLocSymbol(loc);
19831985 if (symbol.isDead()) {
19841986 return;
......@@ -1998,7 +2000,7 @@ fn createSyntheticFunction(
19982000 const atom = wasm.getAtomPtr(atom_index);
19992001 atom.size = @intCast(function_body.items.len);
20002002 atom.code = function_body.moveToUnmanaged();
2001 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
2003 try wasm.appendAtomAtIndex(wasm.code_section_index.unwrap().?, atom_index);
20022004}
20032005
20042006/// Unlike `createSyntheticFunction` this function is to be called by
......@@ -2016,7 +2018,7 @@ pub fn createFunction(
20162018
20172019/// If required, sets the function index in the `start` section.
20182020fn setupStartSection(wasm: *Wasm) !void {
2019 if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {
2021 if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory)) |loc| {
20202022 wasm.entry = wasm.symbolLocSymbol(loc).index;
20212023 }
20222024}
......@@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
20292031 if (!shared_memory) return;
20302032
20312033 // ensure function is marked as we must emit it
2032 wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark();
2034 wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls).?).mark();
20332035
20342036 var function_body = std.ArrayList(u8).init(gpa);
20352037 defer function_body.deinit();
......@@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
20412043 // If there's a TLS segment, initialize it during runtime using the bulk-memory feature
20422044 if (wasm.data_segments.getIndex(".tdata")) |data_index| {
20432045 const segment_index = wasm.data_segments.entries.items(.value)[data_index];
2044 const segment = wasm.segments.items[segment_index];
2046 const segment = wasm.segmentPtr(segment_index);
20452047
20462048 const param_local: u32 = 0;
20472049
20482050 try writer.writeByte(std.wasm.opcode(.local_get));
20492051 try leb.writeUleb128(writer, param_local);
20502052
2051 const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
2053 const tls_base_loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
20522054 try writer.writeByte(std.wasm.opcode(.global_set));
20532055 try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index);
20542056
......@@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
20762078 // If we have to perform any TLS relocations, call the corresponding function
20772079 // which performs all runtime TLS relocations. This is a synthetic function,
20782080 // generated by the linker.
2079 if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {
2081 if (wasm.globals.get(wasm.preloaded_strings.__wasm_apply_global_tls_relocs)) |loc| {
20802082 try writer.writeByte(std.wasm.opcode(.call));
20812083 try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
20822084 wasm.symbolLocSymbol(loc).mark();
......@@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
20852087 try writer.writeByte(std.wasm.opcode(.end));
20862088
20872089 try wasm.createSyntheticFunction(
2088 "__wasm_init_tls",
2090 wasm.preloaded_strings.__wasm_init_tls,
20892091 std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },
20902092 &function_body,
20912093 );
......@@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void {
21012103 };
21022104
21032105 const symbol = wasm.symbolLocSymbol(symbol_loc);
2104 if (symbol.isDead() or
2105 !symbol.requiresImport() or
2106 std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table"))
2107 {
2108 continue;
2109 }
2106 if (symbol.isDead()) continue;
2107 if (!symbol.requiresImport()) continue;
2108 if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
21102109
2111 log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)});
2110 log.debug("Symbol '{s}' will be imported from the host", .{wasm.stringSlice(symbol.name)});
21122111 const import = objectImport(wasm, object_id, symbol_loc.index);
21132112
21142113 // We copy the import to a new import to ensure the names contain references
21152114 // to the internal string table, rather than of the object file.
21162115 const new_imp: Import = .{
2117 .module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)),
2118 .name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)),
2116 .module_name = import.module_name,
2117 .name = import.name,
21192118 .kind = import.kind,
21202119 };
21212120 // TODO: De-duplicate imports when they contain the same names and type
......@@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void {
22832282 var failed_exports = false;
22842283
22852284 for (force_exp_names) |exp_name| {
2286 const loc = wasm.findGlobalSymbol(exp_name) orelse {
2285 const exp_name_interned = try wasm.internString(exp_name);
2286 const loc = wasm.globals.get(exp_name_interned) orelse {
22872287 var err = try diags.addErrorWithNotes(0);
22882288 try err.addMsg("could not export '{s}', symbol not found", .{exp_name});
22892289 failed_exports = true;
......@@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void {
23102310 const symbol = wasm.symbolLocSymbol(sym_loc);
23112311 if (!symbol.isExported(comp.config.rdynamic)) continue;
23122312
2313 const sym_name = wasm.symbolLocName(sym_loc);
2314 const export_name = if (sym_loc.file == .none)
2315 symbol.name
2316 else
2317 try wasm.string_table.put(gpa, sym_name);
23182313 const exp: Export = if (symbol.tag == .data) exp: {
23192314 const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
23202315 try wasm.wasm_globals.append(gpa, .{
......@@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void {
23222317 .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },
23232318 });
23242319 break :exp .{
2325 .name = export_name,
2320 .name = symbol.name,
23262321 .kind = .global,
23272322 .index = global_index,
23282323 };
23292324 } else .{
2330 .name = export_name,
2325 .name = symbol.name,
23312326 .kind = symbol.tag.externalType(),
23322327 .index = symbol.index,
23332328 };
23342329 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
2335 sym_name,
2336 wasm.string_table.get(exp.name),
2330 wasm.stringSlice(symbol.name),
2331 wasm.stringSlice(exp.name),
23372332 exp.index,
23382333 });
23392334 try wasm.exports.append(gpa, exp);
......@@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void {
23462341 const comp = wasm.base.comp;
23472342 const diags = &wasm.base.comp.link_diags;
23482343 // do not export entry point if user set none or no default was set.
2349 const entry_name = wasm.entry_name orelse return;
2344 const entry_name = wasm.entry_name.unwrap() orelse return;
23502345
2351 const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
2352 var err = try diags.addErrorWithNotes(0);
2353 try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
2354 return error.FlushFailure;
2346 const symbol_loc = wasm.globals.get(entry_name) orelse {
2347 var err = try diags.addErrorWithNotes(1);
2348 try err.addMsg("entry symbol '{s}' missing", .{wasm.stringSlice(entry_name)});
2349 try err.addNote("'-fno-entry' suppresses this error", .{});
2350 return error.LinkFailure;
23552351 };
23562352
23572353 const symbol = wasm.symbolLocSymbol(symbol_loc);
2358 if (symbol.tag != .function) {
2359 var err = try diags.addErrorWithNotes(0);
2360 try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
2361 return error.FlushFailure;
2362 }
2354 if (symbol.tag != .function)
2355 return diags.fail("entry symbol '{s}' is not a function", .{wasm.stringSlice(entry_name)});
23632356
23642357 // Ensure the symbol is exported so host environment can access it
23652358 if (comp.config.output_mode != .Obj) {
......@@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void {
23872380
23882381 const is_obj = comp.config.output_mode == .Obj;
23892382
2390 const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
2383 const stack_ptr = if (wasm.globals.get(wasm.preloaded_strings.__stack_pointer)) |loc| index: {
23912384 const sym = wasm.symbolLocSymbol(loc);
23922385 break :index sym.index - wasm.imported_globals_count;
23932386 } else null;
......@@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void {
24042397 var offset: u32 = @as(u32, @intCast(memory_ptr));
24052398 var data_seg_it = wasm.data_segments.iterator();
24062399 while (data_seg_it.next()) |entry| {
2407 const segment = &wasm.segments.items[entry.value_ptr.*];
2400 const segment = wasm.segmentPtr(entry.value_ptr.*);
24082401 memory_ptr = segment.alignment.forward(memory_ptr);
24092402
24102403 // set TLS-related symbols
24112404 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
2412 if (wasm.findGlobalSymbol("__tls_size")) |loc| {
2405 if (wasm.globals.get(wasm.preloaded_strings.__tls_size)) |loc| {
24132406 const sym = wasm.symbolLocSymbol(loc);
24142407 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
24152408 }
2416 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
2409 if (wasm.globals.get(wasm.preloaded_strings.__tls_align)) |loc| {
24172410 const sym = wasm.symbolLocSymbol(loc);
24182411 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
24192412 }
2420 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2413 if (wasm.globals.get(wasm.preloaded_strings.__tls_base)) |loc| {
24212414 const sym = wasm.symbolLocSymbol(loc);
24222415 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
24232416 @as(i32, 0)
......@@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void {
24352428 if (shared_memory and wasm.hasPassiveInitializationSegments()) {
24362429 // align to pointer size
24372430 memory_ptr = mem.alignForward(u64, memory_ptr, 4);
2438 const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
2431 const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory_flag, .data);
24392432 const sym = wasm.symbolLocSymbol(loc);
24402433 sym.mark();
24412434 sym.virtual_address = @as(u32, @intCast(memory_ptr));
......@@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void {
24522445
24532446 // One of the linked object files has a reference to the __heap_base symbol.
24542447 // We must set its virtual address so it can be used in relocations.
2455 if (wasm.findGlobalSymbol("__heap_base")) |loc| {
2448 if (wasm.globals.get(wasm.preloaded_strings.__heap_base)) |loc| {
24562449 const symbol = wasm.symbolLocSymbol(loc);
24572450 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
24582451 }
......@@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void {
24822475 wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size));
24832476 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
24842477
2485 if (wasm.findGlobalSymbol("__heap_end")) |loc| {
2478 if (wasm.globals.get(wasm.preloaded_strings.__heap_end)) |loc| {
24862479 const symbol = wasm.symbolLocSymbol(loc);
24872480 symbol.virtual_address = @as(u32, @intCast(memory_ptr));
24882481 }
......@@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void {
25122505/// From a given object's index and the index of the segment, returns the corresponding
25132506/// index of the segment within the final data section. When the segment does not yet
25142507/// exist, a new one will be initialized and appended. The new index will be returned in that case.
2515pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 {
2508pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Segment.Index {
25162509 const comp = wasm.base.comp;
25172510 const gpa = comp.gpa;
25182511 const diags = &wasm.base.comp.link_diags;
25192512 const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];
2520 const index: u32 = @intCast(wasm.segments.items.len);
2513 const index: Segment.Index = @enumFromInt(wasm.segments.items.len);
25212514 const shared_memory = comp.config.shared_memory;
25222515
25232516 switch (symbol.tag) {
......@@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol
25452538 return index;
25462539 } else return result.value_ptr.*;
25472540 },
2548 .function => return wasm.code_section_index orelse blk: {
2549 wasm.code_section_index = index;
2541 .function => return wasm.code_section_index.unwrap() orelse blk: {
2542 wasm.code_section_index = index.toOptional();
25502543 try wasm.appendDummySegment();
25512544 break :blk index;
25522545 },
25532546 .section => {
2554 const section_name = objectSymbolName(wasm, object_id, symbol_index);
2555 if (mem.eql(u8, section_name, ".debug_info")) {
2556 return wasm.debug_info_index orelse blk: {
2557 wasm.debug_info_index = index;
2558 try wasm.appendDummySegment();
2559 break :blk index;
2560 };
2561 } else if (mem.eql(u8, section_name, ".debug_line")) {
2562 return wasm.debug_line_index orelse blk: {
2563 wasm.debug_line_index = index;
2564 try wasm.appendDummySegment();
2565 break :blk index;
2566 };
2567 } else if (mem.eql(u8, section_name, ".debug_loc")) {
2568 return wasm.debug_loc_index orelse blk: {
2569 wasm.debug_loc_index = index;
2570 try wasm.appendDummySegment();
2571 break :blk index;
2572 };
2573 } else if (mem.eql(u8, section_name, ".debug_ranges")) {
2574 return wasm.debug_ranges_index orelse blk: {
2575 wasm.debug_ranges_index = index;
2576 try wasm.appendDummySegment();
2577 break :blk index;
2578 };
2579 } else if (mem.eql(u8, section_name, ".debug_pubnames")) {
2580 return wasm.debug_pubnames_index orelse blk: {
2581 wasm.debug_pubnames_index = index;
2582 try wasm.appendDummySegment();
2583 break :blk index;
2584 };
2585 } else if (mem.eql(u8, section_name, ".debug_pubtypes")) {
2586 return wasm.debug_pubtypes_index orelse blk: {
2587 wasm.debug_pubtypes_index = index;
2588 try wasm.appendDummySegment();
2589 break :blk index;
2590 };
2591 } else if (mem.eql(u8, section_name, ".debug_abbrev")) {
2592 return wasm.debug_abbrev_index orelse blk: {
2593 wasm.debug_abbrev_index = index;
2594 try wasm.appendDummySegment();
2595 break :blk index;
2596 };
2597 } else if (mem.eql(u8, section_name, ".debug_str")) {
2598 return wasm.debug_str_index orelse blk: {
2599 wasm.debug_str_index = index;
2600 try wasm.appendDummySegment();
2601 break :blk index;
2602 };
2547 const section_name = wasm.objectSymbol(object_id, symbol_index).name;
2548
2549 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
2550 if (@field(wasm.custom_sections, field.name).name == section_name) {
2551 const field_ptr = &@field(wasm.custom_sections, field.name).index;
2552 return field_ptr.unwrap() orelse {
2553 field_ptr.* = index.toOptional();
2554 try wasm.appendDummySegment();
2555 return index;
2556 };
2557 }
26032558 } else {
2604 var err = try diags.addErrorWithNotes(1);
2605 try err.addMsg("found unknown section '{s}'", .{section_name});
2606 try err.addNote("defined in '{'}'", .{objectPath(wasm, object_id)});
2607 return error.UnexpectedValue;
2559 return diags.failParse(objectPath(wasm, object_id), "unknown section: {s}", .{
2560 wasm.stringSlice(section_name),
2561 });
26082562 }
26092563 },
26102564 else => unreachable,
......@@ -2803,10 +2757,9 @@ fn writeToFile(
28032757 }
28042758
28052759 if (import_memory) {
2806 const mem_name = if (is_obj) "__linear_memory" else "memory";
28072760 const mem_imp: Import = .{
2808 .module_name = try wasm.string_table.put(gpa, wasm.host_name),
2809 .name = try wasm.string_table.put(gpa, mem_name),
2761 .module_name = wasm.host_name,
2762 .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory,
28102763 .kind = .{ .memory = wasm.memories.limits },
28112764 };
28122765 try wasm.emitImport(binary_writer, mem_imp);
......@@ -2898,7 +2851,7 @@ fn writeToFile(
28982851 const header_offset = try reserveVecSectionHeader(&binary_bytes);
28992852
29002853 for (wasm.exports.items) |exp| {
2901 const name = wasm.string_table.get(exp.name);
2854 const name = wasm.stringSlice(exp.name);
29022855 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
29032856 try binary_writer.writeAll(name);
29042857 try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));
......@@ -2937,7 +2890,7 @@ fn writeToFile(
29372890 if (wasm.function_table.count() > 0) {
29382891 const header_offset = try reserveVecSectionHeader(&binary_bytes);
29392892
2940 const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
2893 const table_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
29412894 const table_sym = wasm.symbolLocSymbol(table_loc);
29422895
29432896 const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
......@@ -2982,7 +2935,7 @@ fn writeToFile(
29822935 }
29832936
29842937 // Code section
2985 if (wasm.code_section_index != null) {
2938 if (wasm.code_section_index != .none) {
29862939 const header_offset = try reserveVecSectionHeader(&binary_bytes);
29872940 const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count
29882941
......@@ -3022,7 +2975,7 @@ fn writeToFile(
30222975 // want to guarantee the data is zero initialized
30232976 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
30242977 const segment_index = entry.value_ptr.*;
3025 const segment = wasm.segments.items[segment_index];
2978 const segment = wasm.segmentPtr(segment_index);
30262979 if (segment.size == 0) continue; // do not emit empty segments
30272980 segment_count += 1;
30282981 var atom_index = wasm.atoms.get(segment_index).?;
......@@ -3133,24 +3086,8 @@ fn writeToFile(
31333086 var debug_bytes = std.ArrayList(u8).init(gpa);
31343087 defer debug_bytes.deinit();
31353088
3136 const DebugSection = struct {
3137 name: []const u8,
3138 index: ?u32,
3139 };
3140
3141 const debug_sections: []const DebugSection = &.{
3142 .{ .name = ".debug_info", .index = wasm.debug_info_index },
3143 .{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index },
3144 .{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index },
3145 .{ .name = ".debug_line", .index = wasm.debug_line_index },
3146 .{ .name = ".debug_str", .index = wasm.debug_str_index },
3147 .{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index },
3148 .{ .name = ".debug_loc", .index = wasm.debug_loc_index },
3149 .{ .name = ".debug_ranges", .index = wasm.debug_ranges_index },
3150 };
3151
3152 for (debug_sections) |item| {
3153 if (item.index) |index| {
3089 inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
3090 if (@field(wasm.custom_sections, field.name).index.unwrap()) |index| {
31543091 var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
31553092 while (true) {
31563093 atom.resolveRelocs(wasm);
......@@ -3158,7 +3095,7 @@ fn writeToFile(
31583095 if (atom.prev == .null) break;
31593096 atom = wasm.getAtomPtr(atom.prev);
31603097 }
3161 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
3098 try emitDebugSection(&binary_bytes, debug_bytes.items, field.name);
31623099 debug_bytes.clearRetainingCapacity();
31633100 }
31643101 }
......@@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
34303367}
34313368
34323369fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {
3433 const module_name = wasm.string_table.get(import.module_name);
3370 const module_name = wasm.stringSlice(import.module_name);
34343371 try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
34353372 try writer.writeAll(module_name);
34363373
3437 const name = wasm.string_table.get(import.name);
3374 const name = wasm.stringSlice(import.name);
34383375 try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));
34393376 try writer.writeAll(name);
34403377
......@@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
35153452 }
35163453 try man.addOptionalFile(module_obj_path);
35173454 try man.addOptionalFilePath(compiler_rt_path);
3518 man.hash.addOptionalBytes(wasm.entry_name);
3455 man.hash.addOptionalBytes(wasm.optionalStringSlice(wasm.entry_name));
35193456 man.hash.add(wasm.base.stack_size);
35203457 man.hash.add(wasm.base.build_id);
35213458 man.hash.add(import_memory);
......@@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
36643601 try argv.append("--export-dynamic");
36653602 }
36663603
3667 if (wasm.entry_name) |entry_name| {
3604 if (wasm.optionalStringSlice(wasm.entry_name)) |entry_name| {
36683605 try argv.appendSlice(&.{ "--entry", entry_name });
36693606 } else {
36703607 try argv.append("--no-entry");
......@@ -4009,7 +3946,7 @@ fn emitCodeRelocations(
40093946 section_index: u32,
40103947 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),
40113948) !void {
4012 const code_index = wasm.code_section_index orelse return;
3949 const code_index = wasm.code_section_index.unwrap() orelse return;
40133950 const writer = binary_bytes.writer();
40143951 const header_offset = try reserveCustomSectionHeader(binary_bytes);
40153952
......@@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
41064043
41074044 var it = wasm.data_segments.iterator();
41084045 while (it.next()) |entry| {
4109 const segment: Segment = wasm.segments.items[entry.value_ptr.*];
4046 const segment = wasm.segmentPtr(entry.value_ptr.*);
41104047 if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
41114048 return true;
41124049 }
......@@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
42134150 }
42144151}
42154152
4216fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 {
4153fn defaultEntrySymbolName(
4154 preloaded_strings: *const PreloadedStrings,
4155 wasi_exec_model: std.builtin.WasiExecModel,
4156) String {
42174157 return switch (wasi_exec_model) {
4218 .reactor => "_initialize",
4219 .command => "_start",
4158 .reactor => preloaded_strings._initialize,
4159 .command => preloaded_strings._start,
42204160 };
42214161}
42224162
......@@ -4352,7 +4292,7 @@ pub const Atom = struct {
43524292 symbol.tag != .section and
43534293 symbol.isDead())
43544294 {
4355 const val = atom.thombstone(wasm) orelse relocation.addend;
4295 const val = atom.tombstone(wasm) orelse relocation.addend;
43564296 return @bitCast(val);
43574297 }
43584298 switch (relocation.relocation_type) {
......@@ -4394,7 +4334,7 @@ pub const Atom = struct {
43944334 },
43954335 .R_WASM_FUNCTION_OFFSET_I32 => {
43964336 if (symbol.isUndefined()) {
4397 const val = atom.thombstone(wasm) orelse relocation.addend;
4337 const val = atom.tombstone(wasm) orelse relocation.addend;
43984338 return @bitCast(val);
43994339 }
44004340 const target_atom_index = wasm.symbol_atom.get(target_loc).?;
......@@ -4411,16 +4351,19 @@ pub const Atom = struct {
44114351 }
44124352 }
44134353
4414 // For a given `Atom` returns whether it has a thombstone value or not.
4354 // For a given `Atom` returns whether it has a tombstone value or not.
44154355 /// This defines whether we want a specific value when a section is dead.
4416 fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 {
4417 const atom_name = wasm.symbolLocName(atom.symbolLoc());
4418 if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) {
4356 fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 {
4357 const atom_name = wasm.symbolLocSymbol(atom.symbolLoc()).name;
4358 if (atom_name == wasm.custom_sections.@".debug_ranges".name or
4359 atom_name == wasm.custom_sections.@".debug_loc".name)
4360 {
44194361 return -2;
4420 } else if (std.mem.startsWith(u8, atom_name, ".debug_")) {
4362 } else if (std.mem.startsWith(u8, wasm.stringSlice(atom_name), ".debug_")) {
44214363 return -1;
4364 } else {
4365 return null;
44224366 }
4423 return null;
44244367 }
44254368};
44264369
......@@ -4509,8 +4452,8 @@ pub const Relocation = struct {
45094452/// of the import using offsets into a string table, rather than the slices itself.
45104453/// This saves us (potentially) 24 bytes per import on 64bit machines.
45114454pub const Import = struct {
4512 module_name: u32,
4513 name: u32,
4455 module_name: String,
4456 name: String,
45144457 kind: std.wasm.Import.Kind,
45154458};
45164459
......@@ -4519,7 +4462,7 @@ pub const Import = struct {
45194462/// of the export using offsets into a string table, rather than the slice itself.
45204463/// This saves us (potentially) 12 bytes per export on 64bit machines.
45214464pub const Export = struct {
4522 name: u32,
4465 name: String,
45234466 index: u32,
45244467 kind: std.wasm.ExternalKind,
45254468};
......@@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In
47194662 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
47204663 atom.original_offset = relocatable_data.offset;
47214664
4722 const segment: *Wasm.Segment = &wasm.segments.items[final_index];
4665 const segment = wasm.segmentPtr(final_index);
47234666 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
47244667 segment.alignment = segment.alignment.max(atom.alignment);
47254668 }
......@@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize {
47824725 }
47834726 return relocs.len;
47844727}
4728
4729pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
4730 const gpa = wasm.base.comp.gpa;
4731 const gop = try wasm.string_table.getOrPutContextAdapted(
4732 gpa,
4733 @as([]const u8, bytes),
4734 @as(String.TableIndexAdapter, .{ .bytes = wasm.string_bytes.items }),
4735 @as(String.TableContext, .{ .bytes = wasm.string_bytes.items }),
4736 );
4737 if (gop.found_existing) return gop.key_ptr.*;
4738
4739 try wasm.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1);
4740 const new_off: String = @enumFromInt(wasm.string_bytes.items.len);
4741
4742 wasm.string_bytes.appendSliceAssumeCapacity(bytes);
4743 wasm.string_bytes.appendAssumeCapacity(0);
4744
4745 gop.key_ptr.* = new_off;
4746
4747 return new_off;
4748}
4749
4750pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
4751 return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{
4752 .bytes = wasm.string_bytes.items,
4753 }));
4754}
4755
4756pub fn stringSlice(wasm: *const Wasm, index: String) [:0]const u8 {
4757 const slice = wasm.string_bytes.items[@intFromEnum(index)..];
4758 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
4759}
4760
4761pub fn optionalStringSlice(wasm: *const Wasm, index: OptionalString) ?[:0]const u8 {
4762 return stringSlice(wasm, index.unwrap() orelse return null);
4763}
4764
4765pub fn castToString(wasm: *const Wasm, index: u32) String {
4766 assert(index == 0 or wasm.string_bytes.items[index - 1] == 0);
4767 return @enumFromInt(index);
4768}
4769
4770fn segmentPtr(wasm: *const Wasm, index: Segment.Index) *Segment {
4771 return &wasm.segments.items[@intFromEnum(index)];
4772}
src/link/Wasm/Archive.zig+1-1
......@@ -173,7 +173,7 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
173173
174174/// From a given file offset, starts reading for a file header.
175175/// When found, parses the object file into an `Object` and returns it.
176pub fn parseObject(archive: Archive, wasm: *const Wasm, file_contents: []const u8, path: Path) !Object {
176pub fn parseObject(archive: Archive, wasm: *Wasm, file_contents: []const u8, path: Path) !Object {
177177 var fbs = std.io.fixedBufferStream(file_contents);
178178 const header = try fbs.reader().readStruct(Header);
179179
src/link/Wasm/Object.zig+23-21
......@@ -63,10 +63,6 @@ comdat_info: []const Wasm.Comdat = &.{},
6363/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
6464/// after performing relocations.
6565relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,
66/// String table for all strings required by the object file, such as symbol names,
67/// import name, module name and export names. Each string will be deduplicated
68/// and returns an offset into the table.
69string_table: Wasm.StringTable = .{},
7066/// Amount of functions in the `import` sections.
7167imported_functions_count: u32 = 0,
7268/// Amount of globals in the `import` section.
......@@ -126,7 +122,7 @@ pub const RelocatableData = struct {
126122/// When a max size is given, will only parse up to the given size,
127123/// else will read until the end of the file.
128124pub fn create(
129 wasm: *const Wasm,
125 wasm: *Wasm,
130126 file_contents: []const u8,
131127 path: Path,
132128 archive_member_name: ?[]const u8,
......@@ -187,7 +183,6 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
187183 }
188184 }
189185 object.relocatable_data.deinit(gpa);
190 object.string_table.deinit(gpa);
191186 object.* = undefined;
192187}
193188
......@@ -242,9 +237,9 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm: *const Wasm) !?Symbol
242237 }
243238 } else unreachable;
244239
245 if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {
240 if (table_import.name != wasm.preloaded_strings.__indirect_function_table) {
246241 return diags.failParse(object.path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
247 object.string_table.get(table_import.name),
242 wasm.stringSlice(table_import.name),
248243 });
249244 }
250245
......@@ -264,10 +259,12 @@ const Parser = struct {
264259 reader: std.io.FixedBufferStream([]const u8),
265260 /// Object file we're building
266261 object: *Object,
267 /// Read-only reference to the WebAssembly linker
268 wasm: *const Wasm,
262 /// Mutable so that the string table can be modified.
263 wasm: *Wasm,
269264
270265 fn parseObject(parser: *Parser, gpa: Allocator) anyerror!void {
266 const wasm = parser.wasm;
267
271268 {
272269 var magic_bytes: [4]u8 = undefined;
273270 try parser.reader.reader().readNoEof(&magic_bytes);
......@@ -316,7 +313,7 @@ const Parser = struct {
316313 .type = .custom,
317314 .data = debug_content.ptr,
318315 .size = debug_size,
319 .index = try parser.object.string_table.put(gpa, name),
316 .index = @intFromEnum(try wasm.internString(name)),
320317 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
321318 .section_index = section_index,
322319 });
......@@ -375,8 +372,8 @@ const Parser = struct {
375372 };
376373
377374 import.* = .{
378 .module_name = try parser.object.string_table.put(gpa, module_name),
379 .name = try parser.object.string_table.put(gpa, name),
375 .module_name = try wasm.internString(module_name),
376 .name = try wasm.internString(name),
380377 .kind = kind_value,
381378 };
382379 }
......@@ -422,7 +419,7 @@ const Parser = struct {
422419 defer gpa.free(name);
423420 try reader.readNoEof(name);
424421 exp.* = .{
425 .name = try parser.object.string_table.put(gpa, name),
422 .name = try wasm.internString(name),
426423 .kind = try readEnum(std.wasm.ExternalKind, reader),
427424 .index = try readLeb(u32, reader),
428425 };
......@@ -587,6 +584,7 @@ const Parser = struct {
587584 /// `parser` is used to provide access to other sections that may be needed,
588585 /// such as access to the `import` section to find the name of a symbol.
589586 fn parseSubsection(parser: *Parser, gpa: Allocator, reader: anytype) !void {
587 const wasm = parser.wasm;
590588 const sub_type = try leb.readUleb128(u8, reader);
591589 log.debug("Found subsection: {s}", .{@tagName(@as(Wasm.SubsectionType, @enumFromInt(sub_type)))});
592590 const payload_len = try leb.readUleb128(u32, reader);
......@@ -680,7 +678,7 @@ const Parser = struct {
680678 symbol.* = try parser.parseSymbol(gpa, reader);
681679 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
682680 @tagName(symbol.tag),
683 parser.object.string_table.get(symbol.name),
681 wasm.stringSlice(symbol.name),
684682 symbol.flags,
685683 });
686684 }
......@@ -697,15 +695,18 @@ const Parser = struct {
697695 if (parser.object.relocatable_data.get(.custom)) |custom_sections| {
698696 for (custom_sections) |*data| {
699697 if (!data.represented) {
698 const name = wasm.castToString(data.index);
700699 try symbols.append(.{
701 .name = data.index,
700 .name = name,
702701 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
703702 .tag = .section,
704703 .virtual_address = 0,
705704 .index = data.section_index,
706705 });
707706 data.represented = true;
708 log.debug("Created synthetic custom section symbol for '{s}'", .{parser.object.string_table.get(data.index)});
707 log.debug("Created synthetic custom section symbol for '{s}'", .{
708 wasm.stringSlice(name),
709 });
709710 }
710711 }
711712 }
......@@ -719,7 +720,8 @@ const Parser = struct {
719720 /// requires access to `Object` to find the name of a symbol when it's
720721 /// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.
721722 fn parseSymbol(parser: *Parser, gpa: Allocator, reader: anytype) !Symbol {
722 const tag = @as(Symbol.Tag, @enumFromInt(try leb.readUleb128(u8, reader)));
723 const wasm = parser.wasm;
724 const tag: Symbol.Tag = @enumFromInt(try leb.readUleb128(u8, reader));
723725 const flags = try leb.readUleb128(u32, reader);
724726 var symbol: Symbol = .{
725727 .flags = flags,
......@@ -735,7 +737,7 @@ const Parser = struct {
735737 const name = try gpa.alloc(u8, name_len);
736738 defer gpa.free(name);
737739 try reader.readNoEof(name);
738 symbol.name = try parser.object.string_table.put(gpa, name);
740 symbol.name = try wasm.internString(name);
739741
740742 // Data symbols only have the following fields if the symbol is defined
741743 if (symbol.isDefined()) {
......@@ -750,7 +752,7 @@ const Parser = struct {
750752 const section_data = parser.object.relocatable_data.get(.custom).?;
751753 for (section_data) |*data| {
752754 if (data.section_index == symbol.index) {
753 symbol.name = data.index;
755 symbol.name = wasm.castToString(data.index);
754756 data.represented = true;
755757 break;
756758 }
......@@ -765,7 +767,7 @@ const Parser = struct {
765767 const name = try gpa.alloc(u8, name_len);
766768 defer gpa.free(name);
767769 try reader.readNoEof(name);
768 break :name try parser.object.string_table.put(gpa, name);
770 break :name try wasm.internString(name);
769771 } else parser.object.findImport(symbol).name;
770772 },
771773 }
src/link/Wasm/Symbol.zig+3-2
......@@ -8,8 +8,8 @@
88/// Can contain any of the flags defined in `Flag`
99flags: u32,
1010/// Symbol name, when the symbol is undefined the name will be taken from the import.
11/// Note: This is an index into the string table.
12name: u32,
11/// Note: This is an index into the wasm string table.
12name: wasm.String,
1313/// Index into the list of objects based on set `tag`
1414/// NOTE: This will be set to `undefined` when `tag` is `data`
1515/// and the symbol is undefined.
......@@ -207,3 +207,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO
207207
208208const std = @import("std");
209209const Symbol = @This();
210const wasm = @import("../Wasm.zig");
src/link/Wasm/ZigObject.zig+32-50
......@@ -23,16 +23,14 @@ globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
2323atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .empty,
2424/// List of all symbols generated by Zig code.
2525symbols: std.ArrayListUnmanaged(Symbol) = .empty,
26/// Map from symbol name offset to their index into the `symbols` list.
27global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,
26/// Map from symbol name to their index into the `symbols` list.
27global_syms: std.AutoHashMapUnmanaged(Wasm.String, Symbol.Index) = .empty,
2828/// List of symbol indexes which are free to be used.
2929symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,
3030/// Extra metadata about the linking section, such as alignment of segments and their name.
3131segment_info: std.ArrayListUnmanaged(Wasm.NamedSegment) = .empty,
3232/// List of indexes which contain a free slot in the `segment_info` list.
3333segment_free_list: std.ArrayListUnmanaged(u32) = .empty,
34/// File encapsulated string table, used to deduplicate strings within the generated file.
35string_table: StringTable = .{},
3634/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
3735uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .empty,
3836/// List of atom indexes of functions that are generated by the backend.
......@@ -88,13 +86,9 @@ const NavInfo = struct {
8886 atom: Atom.Index = .null,
8987 exports: std.ArrayListUnmanaged(Symbol.Index) = .empty,
9088
91 fn @"export"(ni: NavInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index {
89 fn @"export"(ni: NavInfo, zo: *const ZigObject, name: Wasm.String) ?Symbol.Index {
9290 for (ni.exports.items) |sym_index| {
93 const sym_name_index = zig_object.symbol(sym_index).name;
94 const sym_name = zig_object.string_table.getAssumeExists(sym_name_index);
95 if (std.mem.eql(u8, name, sym_name)) {
96 return sym_index;
97 }
91 if (zo.symbol(sym_index).name == name) return sym_index;
9892 }
9993 return null;
10094 }
......@@ -126,14 +120,14 @@ pub fn init(zig_object: *ZigObject, wasm: *Wasm) !void {
126120
127121fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {
128122 const gpa = wasm.base.comp.gpa;
129 const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");
123 const sym_index = try zig_object.getGlobalSymbol(gpa, wasm.preloaded_strings.__stack_pointer);
130124 const sym = zig_object.symbol(sym_index);
131125 sym.index = zig_object.imported_globals_count;
132126 sym.tag = .global;
133127 const is_wasm32 = wasm.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;
134128 try zig_object.imports.putNoClobber(gpa, sym_index, .{
135129 .name = sym.name,
136 .module_name = try zig_object.string_table.insert(gpa, wasm.host_name),
130 .module_name = wasm.host_name,
137131 .kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
138132 });
139133 zig_object.imported_globals_count += 1;
......@@ -174,7 +168,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
174168 atom.deinit(gpa);
175169 }
176170 }
177 if (zig_object.findGlobalSymbol("__zig_errors_len")) |sym_index| {
171 if (zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len)) |sym_index| {
178172 const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;
179173 wasm.getAtomPtr(atom_index).deinit(gpa);
180174 }
......@@ -206,7 +200,6 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
206200 zig_object.segment_info.deinit(gpa);
207201 zig_object.segment_free_list.deinit(gpa);
208202
209 zig_object.string_table.deinit(gpa);
210203 if (zig_object.dwarf) |*dwarf| {
211204 dwarf.deinit();
212205 }
......@@ -219,7 +212,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
219212pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.Index {
220213 try zig_object.symbols.ensureUnusedCapacity(gpa, 1);
221214 const sym: Symbol = .{
222 .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls
215 .name = undefined, // will be set after updateDecl as well as during atom creation for decls
223216 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
224217 .tag = .undefined, // will be set after updateDecl
225218 .index = std.math.maxInt(u32), // will be set during atom parsing
......@@ -345,7 +338,7 @@ fn finishUpdateNav(
345338 const atom_index = nav_info.atom;
346339 const atom = wasm.getAtomPtr(atom_index);
347340 const sym = zig_object.symbol(atom.sym_index);
348 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
341 sym.name = try wasm.internString(nav.fqn.toSlice(ip));
349342 try atom.code.appendSlice(gpa, code);
350343 atom.size = @intCast(code.len);
351344
......@@ -432,7 +425,7 @@ pub fn getOrCreateAtomForNav(
432425 gop.value_ptr.* = .{ .atom = try wasm.createAtom(sym_index, .zig_object) };
433426 const nav = ip.getNav(nav_index);
434427 const sym = zig_object.symbol(sym_index);
435 sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
428 sym.name = try wasm.internString(nav.fqn.toSlice(ip));
436429 }
437430 return gop.value_ptr.atom;
438431}
......@@ -500,7 +493,7 @@ fn lowerConst(
500493 const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
501494 errdefer gpa.free(segment_name);
502495 zig_object.symbol(sym_index).* = .{
503 .name = try zig_object.string_table.insert(gpa, name),
496 .name = try wasm.internString(name),
504497 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
505498 .tag = .data,
506499 .index = try zig_object.createDataSegment(
......@@ -551,11 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm: *Wasm, pt: Zcu.PerThrea
551544 const slice_ty = Type.slice_const_u8_sentinel_0;
552545 atom.alignment = slice_ty.abiAlignment(pt.zcu);
553546
554 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table");
555547 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_name_table");
556548 const sym = zig_object.symbol(sym_index);
557549 sym.* = .{
558 .name = sym_name,
550 .name = wasm.preloaded_strings.__zig_err_name_table,
559551 .tag = .data,
560552 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
561553 .index = try zig_object.createDataSegment(gpa, segment_name, atom.alignment),
......@@ -583,11 +575,10 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThrea
583575 const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);
584576 const names_atom = wasm.getAtomPtr(names_atom_index);
585577 names_atom.alignment = .@"1";
586 const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
587578 const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");
588579 const names_symbol = zig_object.symbol(names_sym_index);
589580 names_symbol.* = .{
590 .name = sym_name,
581 .name = wasm.preloaded_strings.__zig_err_names,
591582 .tag = .data,
592583 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
593584 .index = try zig_object.createDataSegment(gpa, segment_name, names_atom.alignment),
......@@ -661,14 +652,14 @@ pub fn addOrUpdateImport(
661652 // For the import name, we use the decl's name, rather than the fully qualified name
662653 // Also mangle the name when the lib name is set and not equal to "C" so imports with the same
663654 // name but different module can be resolved correctly.
664 const mangle_name = lib_name != null and
665 !std.mem.eql(u8, lib_name.?, "c");
666 const full_name = if (mangle_name) full_name: {
667 break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? });
668 } else name;
655 const mangle_name = if (lib_name) |n| !std.mem.eql(u8, n, "c") else false;
656 const full_name = if (mangle_name)
657 try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? })
658 else
659 name;
669660 defer if (mangle_name) gpa.free(full_name);
670661
671 const decl_name_index = try zig_object.string_table.insert(gpa, full_name);
662 const decl_name_index = try wasm.internString(full_name);
672663 const sym: *Symbol = &zig_object.symbols.items[@intFromEnum(symbol_index)];
673664 sym.setUndefined(true);
674665 sym.setGlobal(true);
......@@ -680,13 +671,11 @@ pub fn addOrUpdateImport(
680671
681672 if (type_index) |ty_index| {
682673 const gop = try zig_object.imports.getOrPut(gpa, symbol_index);
683 const module_name = if (lib_name) |l_name| l_name else wasm.host_name;
684 if (!gop.found_existing) {
685 zig_object.imported_functions_count += 1;
686 }
674 const module_name = if (lib_name) |n| try wasm.internString(n) else wasm.host_name;
675 if (!gop.found_existing) zig_object.imported_functions_count += 1;
687676 gop.value_ptr.* = .{
688 .module_name = try zig_object.string_table.insert(gpa, module_name),
689 .name = try zig_object.string_table.insert(gpa, name),
677 .module_name = module_name,
678 .name = try wasm.internString(name),
690679 .kind = .{ .function = ty_index },
691680 };
692681 sym.tag = .function;
......@@ -699,8 +688,7 @@ pub fn addOrUpdateImport(
699688/// such as an exported or imported symbol.
700689/// If the symbol does not yet exist, creates a new one symbol instead
701690/// and then returns the index to it.
702pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8) !Symbol.Index {
703 const name_index = try zig_object.string_table.insert(gpa, name);
691pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name_index: Wasm.String) !Symbol.Index {
704692 const gop = try zig_object.global_syms.getOrPut(gpa, name_index);
705693 if (gop.found_existing) {
706694 return gop.value_ptr.*;
......@@ -840,7 +828,8 @@ pub fn deleteExport(
840828 .uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
841829 };
842830 const nav_info = zig_object.navs.getPtr(nav_index) orelse return;
843 if (nav_info.@"export"(zig_object, name.toSlice(&zcu.intern_pool))) |sym_index| {
831 const name_interned = wasm.getExistingString(name.toSlice(&zcu.intern_pool)).?;
832 if (nav_info.@"export"(zig_object, name_interned)) |sym_index| {
844833 const sym = zig_object.symbol(sym_index);
845834 nav_info.deleteExport(sym_index);
846835 std.debug.assert(zig_object.global_syms.remove(sym.name));
......@@ -886,14 +875,13 @@ pub fn updateExports(
886875 continue;
887876 }
888877
889 const export_string = exp.opts.name.toSlice(ip);
890 const sym_index = if (nav_info.@"export"(zig_object, export_string)) |idx| idx else index: {
878 const export_name = try wasm.internString(exp.opts.name.toSlice(ip));
879 const sym_index = if (nav_info.@"export"(zig_object, export_name)) |idx| idx else index: {
891880 const sym_index = try zig_object.allocateSymbol(gpa);
892881 try nav_info.appendExport(gpa, sym_index);
893882 break :index sym_index;
894883 };
895884
896 const export_name = try zig_object.string_table.insert(gpa, export_string);
897885 const sym = zig_object.symbol(sym_index);
898886 sym.setGlobal(true);
899887 sym.setUndefined(false);
......@@ -922,7 +910,7 @@ pub fn updateExports(
922910 if (exp.opts.visibility == .hidden) {
923911 sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
924912 }
925 log.debug(" with name '{s}' - {}", .{ export_string, sym });
913 log.debug(" with name '{s}' - {}", .{ wasm.stringSlice(export_name), sym });
926914 try zig_object.global_syms.put(gpa, export_name, sym_index);
927915 try wasm.symbol_atom.put(gpa, .{ .file = .zig_object, .index = sym_index }, atom_index);
928916 }
......@@ -1014,7 +1002,7 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
10141002/// This will only be generated if the symbol exists.
10151003fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
10161004 const gpa = wasm.base.comp.gpa;
1017 const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;
1005 const sym_index = zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len) orelse return;
10181006
10191007 const errors_len = 1 + wasm.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;
10201008 // overwrite existing atom if it already exists (maybe the error set has increased)
......@@ -1045,11 +1033,6 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
10451033 try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
10461034}
10471035
1048fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?Symbol.Index {
1049 const offset = zig_object.string_table.getOffset(name) orelse return null;
1050 return zig_object.global_syms.get(offset);
1051}
1052
10531036/// Initializes symbols and atoms for the debug sections
10541037/// Initialization is only done when compiling Zig code.
10551038/// When Zig is invoked as a linker instead, the atoms
......@@ -1082,7 +1065,7 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?
10821065 const atom = wasm.getAtomPtr(atom_index);
10831066 zig_object.symbols.items[sym_index] = .{
10841067 .tag = .section,
1085 .name = try zig_object.string_table.put(gpa, name),
1068 .name = try wasm.internString(name),
10861069 .index = 0,
10871070 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
10881071 };
......@@ -1197,7 +1180,7 @@ pub fn createFunction(
11971180 const sym_index = try zig_object.allocateSymbol(gpa);
11981181 const sym = zig_object.symbol(sym_index);
11991182 sym.tag = .function;
1200 sym.name = try zig_object.string_table.insert(gpa, symbol_name);
1183 sym.name = try wasm.internString(symbol_name);
12011184 const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);
12021185 sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });
12031186
......@@ -1244,7 +1227,6 @@ const Dwarf = @import("../Dwarf.zig");
12441227const InternPool = @import("../../InternPool.zig");
12451228const Liveness = @import("../../Liveness.zig");
12461229const Zcu = @import("../../Zcu.zig");
1247const StringTable = @import("../StringTable.zig");
12481230const Symbol = @import("Symbol.zig");
12491231const Type = @import("../../Type.zig");
12501232const Value = @import("../../Value.zig");