authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-13 17:42:51+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-09-13 17:42:51+02:00
logbe944870298e4694e8ccb3f8c65a0bd152e26dad
tree2039b9fb77c4f3ce9964a6622e51cf01e5fc874a
parente323cf1264f390911dcc2efea71d46be1d631d92
parent3edf8c7a6cb912597bbc97ad97d554e6e4d96cdb
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12823 from Luukdegram/wasm-linker

wasm-linker: misc improvements & cleanups

6 files changed, 1099 insertions(+), 1136 deletions(-)

src/link/Wasm.zig+900-936
...@@ -8,7 +8,6 @@ const assert = std.debug.assert;...@@ -8,7 +8,6 @@ const assert = std.debug.assert;
8const fs = std.fs;8const fs = std.fs;
9const leb = std.leb;9const leb = std.leb;
10const log = std.log.scoped(.link);10const log = std.log.scoped(.link);
11const wasm = std.wasm;
1211
13const Atom = @import("Wasm/Atom.zig");12const Atom = @import("Wasm/Atom.zig");
14const Dwarf = @import("Dwarf.zig");13const Dwarf = @import("Dwarf.zig");
...@@ -106,17 +105,17 @@ dwarf: ?Dwarf = null,...@@ -106,17 +105,17 @@ dwarf: ?Dwarf = null,
106105
107// Output sections106// Output sections
108/// Output type section107/// Output type section
109func_types: std.ArrayListUnmanaged(wasm.Type) = .{},108func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},
110/// Output function section where the key is the original109/// Output function section where the key is the original
111/// function index and the value is function.110/// function index and the value is function.
112/// This allows us to map multiple symbols to the same function.111/// This allows us to map multiple symbols to the same function.
113functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, wasm.Func) = .{},112functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{},
114/// Output global section113/// Output global section
115wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{},114wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
116/// Memory section115/// Memory section
117memories: wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },116memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
118/// Output table section117/// Output table section
119tables: std.ArrayListUnmanaged(wasm.Table) = .{},118tables: std.ArrayListUnmanaged(std.wasm.Table) = .{},
120/// Output export section119/// Output export section
121exports: std.ArrayListUnmanaged(types.Export) = .{},120exports: std.ArrayListUnmanaged(types.Export) = .{},
122121
...@@ -203,39 +202,39 @@ pub const SymbolLoc = struct {...@@ -203,39 +202,39 @@ pub const SymbolLoc = struct {
203 file: ?u16,202 file: ?u16,
204203
205 /// From a given location, returns the corresponding symbol in the wasm binary204 /// From a given location, returns the corresponding symbol in the wasm binary
206 pub fn getSymbol(self: SymbolLoc, wasm_bin: *const Wasm) *Symbol {205 pub fn getSymbol(loc: SymbolLoc, wasm_bin: *const Wasm) *Symbol {
207 if (wasm_bin.discarded.get(self)) |new_loc| {206 if (wasm_bin.discarded.get(loc)) |new_loc| {
208 return new_loc.getSymbol(wasm_bin);207 return new_loc.getSymbol(wasm_bin);
209 }208 }
210 if (self.file) |object_index| {209 if (loc.file) |object_index| {
211 const object = wasm_bin.objects.items[object_index];210 const object = wasm_bin.objects.items[object_index];
212 return &object.symtable[self.index];211 return &object.symtable[loc.index];
213 }212 }
214 return &wasm_bin.symbols.items[self.index];213 return &wasm_bin.symbols.items[loc.index];
215 }214 }
216215
217 /// From a given location, returns the name of the symbol.216 /// From a given location, returns the name of the symbol.
218 pub fn getName(self: SymbolLoc, wasm_bin: *const Wasm) []const u8 {217 pub fn getName(loc: SymbolLoc, wasm_bin: *const Wasm) []const u8 {
219 if (wasm_bin.discarded.get(self)) |new_loc| {218 if (wasm_bin.discarded.get(loc)) |new_loc| {
220 return new_loc.getName(wasm_bin);219 return new_loc.getName(wasm_bin);
221 }220 }
222 if (self.file) |object_index| {221 if (loc.file) |object_index| {
223 const object = wasm_bin.objects.items[object_index];222 const object = wasm_bin.objects.items[object_index];
224 return object.string_table.get(object.symtable[self.index].name);223 return object.string_table.get(object.symtable[loc.index].name);
225 }224 }
226 return wasm_bin.string_table.get(wasm_bin.symbols.items[self.index].name);225 return wasm_bin.string_table.get(wasm_bin.symbols.items[loc.index].name);
227 }226 }
228227
229 /// From a given symbol location, returns the final location.228 /// From a given symbol location, returns the final location.
230 /// e.g. when a symbol was resolved and replaced by the symbol229 /// e.g. when a symbol was resolved and replaced by the symbol
231 /// in a different file, this will return said location.230 /// in a different file, this will return said location.
232 /// If the symbol wasn't replaced by another, this will return231 /// If the symbol wasn't replaced by another, this will return
233 /// the given location itself.232 /// the given location itwasm.
234 pub fn finalLoc(self: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc {233 pub fn finalLoc(loc: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc {
235 if (wasm_bin.discarded.get(self)) |new_loc| {234 if (wasm_bin.discarded.get(loc)) |new_loc| {
236 return new_loc.finalLoc(wasm_bin);235 return new_loc.finalLoc(wasm_bin);
237 }236 }
238 return self;237 return loc;
239 }238 }
240};239};
241240
...@@ -258,12 +257,12 @@ pub const StringTable = struct {...@@ -258,12 +257,12 @@ pub const StringTable = struct {
258 /// When found, de-duplicates the string and returns the existing offset instead.257 /// When found, de-duplicates the string and returns the existing offset instead.
259 /// When the string is not found in the `string_table`, a new entry will be inserted258 /// When the string is not found in the `string_table`, a new entry will be inserted
260 /// and the new offset to its data will be returned.259 /// and the new offset to its data will be returned.
261 pub fn put(self: *StringTable, allocator: Allocator, string: []const u8) !u32 {260 pub fn put(table: *StringTable, allocator: Allocator, string: []const u8) !u32 {
262 const gop = try self.string_table.getOrPutContextAdapted(261 const gop = try table.string_table.getOrPutContextAdapted(
263 allocator,262 allocator,
264 string,263 string,
265 std.hash_map.StringIndexAdapter{ .bytes = &self.string_data },264 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
266 .{ .bytes = &self.string_data },265 .{ .bytes = &table.string_data },
267 );266 );
268 if (gop.found_existing) {267 if (gop.found_existing) {
269 const off = gop.key_ptr.*;268 const off = gop.key_ptr.*;
...@@ -271,13 +270,13 @@ pub const StringTable = struct {...@@ -271,13 +270,13 @@ pub const StringTable = struct {
271 return off;270 return off;
272 }271 }
273272
274 try self.string_data.ensureUnusedCapacity(allocator, string.len + 1);273 try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);
275 const offset = @intCast(u32, self.string_data.items.len);274 const offset = @intCast(u32, table.string_data.items.len);
276275
277 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });276 log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
278277
279 self.string_data.appendSliceAssumeCapacity(string);278 table.string_data.appendSliceAssumeCapacity(string);
280 self.string_data.appendAssumeCapacity(0);279 table.string_data.appendAssumeCapacity(0);
281280
282 gop.key_ptr.* = offset;281 gop.key_ptr.* = offset;
283282
...@@ -286,26 +285,26 @@ pub const StringTable = struct {...@@ -286,26 +285,26 @@ pub const StringTable = struct {
286285
287 /// From a given offset, returns its corresponding string value.286 /// From a given offset, returns its corresponding string value.
288 /// Asserts offset does not exceed bounds.287 /// Asserts offset does not exceed bounds.
289 pub fn get(self: StringTable, off: u32) []const u8 {288 pub fn get(table: StringTable, off: u32) []const u8 {
290 assert(off < self.string_data.items.len);289 assert(off < table.string_data.items.len);
291 return mem.sliceTo(@ptrCast([*:0]const u8, self.string_data.items.ptr + off), 0);290 return mem.sliceTo(@ptrCast([*:0]const u8, table.string_data.items.ptr + off), 0);
292 }291 }
293292
294 /// Returns the offset of a given string when it exists.293 /// Returns the offset of a given string when it exists.
295 /// Will return null if the given string does not yet exist within the string table.294 /// Will return null if the given string does not yet exist within the string table.
296 pub fn getOffset(self: *StringTable, string: []const u8) ?u32 {295 pub fn getOffset(table: *StringTable, string: []const u8) ?u32 {
297 return self.string_table.getKeyAdapted(296 return table.string_table.getKeyAdapted(
298 string,297 string,
299 std.hash_map.StringIndexAdapter{ .bytes = &self.string_data },298 std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
300 );299 );
301 }300 }
302301
303 /// Frees all resources of the string table. Any references pointing302 /// Frees all resources of the string table. Any references pointing
304 /// to the strings will be invalid.303 /// to the strings will be invalid.
305 pub fn deinit(self: *StringTable, allocator: Allocator) void {304 pub fn deinit(table: *StringTable, allocator: Allocator) void {
306 self.string_data.deinit(allocator);305 table.string_data.deinit(allocator);
307 self.string_table.deinit(allocator);306 table.string_table.deinit(allocator);
308 self.* = undefined;307 table.* = undefined;
309 }308 }
310};309};
311310
...@@ -324,8 +323,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -324,8 +323,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
324 wasm_bin.base.file = file;323 wasm_bin.base.file = file;
325 wasm_bin.name = sub_path;324 wasm_bin.name = sub_path;
326325
327 try file.writeAll(&(wasm.magic ++ wasm.version));
328
329 // As sym_index '0' is reserved, we use it for our stack pointer symbol326 // As sym_index '0' is reserved, we use it for our stack pointer symbol
330 const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer");327 const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer");
331 const symbol = try wasm_bin.symbols.addOne(allocator);328 const symbol = try wasm_bin.symbols.addOne(allocator);
...@@ -363,14 +360,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -363,14 +360,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
363 };360 };
364 }361 }
365362
366 try wasm_bin.initDebugSections();363 if (!options.strip and options.module != null) {
364 wasm_bin.dwarf = Dwarf.init(allocator, .wasm, options.target);
365 try wasm_bin.initDebugSections();
366 }
367
367 return wasm_bin;368 return wasm_bin;
368}369}
369370
370pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {371pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
371 const self = try gpa.create(Wasm);372 const wasm = try gpa.create(Wasm);
372 errdefer gpa.destroy(self);373 errdefer gpa.destroy(wasm);
373 self.* = .{374 wasm.* = .{
374 .base = .{375 .base = .{
375 .tag = .wasm,376 .tag = .wasm,
376 .options = options,377 .options = options,
...@@ -380,40 +381,36 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {...@@ -380,40 +381,36 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
380 .name = undefined,381 .name = undefined,
381 };382 };
382383
383 if (!options.strip and options.module != null) {
384 self.dwarf = Dwarf.init(gpa, .wasm, options.target);
385 }
386
387 const use_llvm = build_options.have_llvm and options.use_llvm;384 const use_llvm = build_options.have_llvm and options.use_llvm;
388 const use_stage1 = build_options.have_stage1 and options.use_stage1;385 const use_stage1 = build_options.have_stage1 and options.use_stage1;
389 if (use_llvm and !use_stage1) {386 if (use_llvm and !use_stage1) {
390 self.llvm_object = try LlvmObject.create(gpa, options);387 wasm.llvm_object = try LlvmObject.create(gpa, options);
391 }388 }
392 return self;389 return wasm;
393}390}
394391
395/// Initializes symbols and atoms for the debug sections392/// Initializes symbols and atoms for the debug sections
396/// Initialization is only done when compiling Zig code.393/// Initialization is only done when compiling Zig code.
397/// When Zig is invoked as a linker instead, the atoms394/// When Zig is invoked as a linker instead, the atoms
398/// and symbols come from the object files instead.395/// and symbols come from the object files instead.
399pub fn initDebugSections(self: *Wasm) !void {396pub fn initDebugSections(wasm: *Wasm) !void {
400 if (self.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections397 if (wasm.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections
401 assert(self.debug_info_index == null);398 assert(wasm.debug_info_index == null);
402 // this will create an Atom and set the index for us.399 // this will create an Atom and set the index for us.
403 self.debug_info_atom = try self.createDebugSectionForIndex(&self.debug_info_index, ".debug_info");400 wasm.debug_info_atom = try wasm.createDebugSectionForIndex(&wasm.debug_info_index, ".debug_info");
404 self.debug_line_atom = try self.createDebugSectionForIndex(&self.debug_line_index, ".debug_line");401 wasm.debug_line_atom = try wasm.createDebugSectionForIndex(&wasm.debug_line_index, ".debug_line");
405 self.debug_loc_atom = try self.createDebugSectionForIndex(&self.debug_loc_index, ".debug_loc");402 wasm.debug_loc_atom = try wasm.createDebugSectionForIndex(&wasm.debug_loc_index, ".debug_loc");
406 self.debug_abbrev_atom = try self.createDebugSectionForIndex(&self.debug_abbrev_index, ".debug_abbrev");403 wasm.debug_abbrev_atom = try wasm.createDebugSectionForIndex(&wasm.debug_abbrev_index, ".debug_abbrev");
407 self.debug_ranges_atom = try self.createDebugSectionForIndex(&self.debug_ranges_index, ".debug_ranges");404 wasm.debug_ranges_atom = try wasm.createDebugSectionForIndex(&wasm.debug_ranges_index, ".debug_ranges");
408 self.debug_str_atom = try self.createDebugSectionForIndex(&self.debug_str_index, ".debug_str");405 wasm.debug_str_atom = try wasm.createDebugSectionForIndex(&wasm.debug_str_index, ".debug_str");
409 self.debug_pubnames_atom = try self.createDebugSectionForIndex(&self.debug_pubnames_index, ".debug_pubnames");406 wasm.debug_pubnames_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubnames_index, ".debug_pubnames");
410 self.debug_pubtypes_atom = try self.createDebugSectionForIndex(&self.debug_pubtypes_index, ".debug_pubtypes");407 wasm.debug_pubtypes_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubtypes_index, ".debug_pubtypes");
411}408}
412409
413fn parseInputFiles(self: *Wasm, files: []const []const u8) !void {410fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void {
414 for (files) |path| {411 for (files) |path| {
415 if (try self.parseObjectFile(path)) continue;412 if (try wasm.parseObjectFile(path)) continue;
416 if (try self.parseArchive(path, false)) continue; // load archives lazily413 if (try wasm.parseArchive(path, false)) continue; // load archives lazily
417 log.warn("Unexpected file format at path: '{s}'", .{path});414 log.warn("Unexpected file format at path: '{s}'", .{path});
418 }415 }
419}416}
...@@ -421,16 +418,16 @@ fn parseInputFiles(self: *Wasm, files: []const []const u8) !void {...@@ -421,16 +418,16 @@ fn parseInputFiles(self: *Wasm, files: []const []const u8) !void {
421/// Parses the object file from given path. Returns true when the given file was an object418/// Parses the object file from given path. Returns true when the given file was an object
422/// file and parsed successfully. Returns false when file is not an object file.419/// file and parsed successfully. Returns false when file is not an object file.
423/// May return an error instead when parsing failed.420/// May return an error instead when parsing failed.
424fn parseObjectFile(self: *Wasm, path: []const u8) !bool {421fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool {
425 const file = try fs.cwd().openFile(path, .{});422 const file = try fs.cwd().openFile(path, .{});
426 errdefer file.close();423 errdefer file.close();
427424
428 var object = Object.create(self.base.allocator, file, path, null) catch |err| switch (err) {425 var object = Object.create(wasm.base.allocator, file, path, null) catch |err| switch (err) {
429 error.InvalidMagicByte, error.NotObjectFile => return false,426 error.InvalidMagicByte, error.NotObjectFile => return false,
430 else => |e| return e,427 else => |e| return e,
431 };428 };
432 errdefer object.deinit(self.base.allocator);429 errdefer object.deinit(wasm.base.allocator);
433 try self.objects.append(self.base.allocator, object);430 try wasm.objects.append(wasm.base.allocator, object);
434 return true;431 return true;
435}432}
436433
...@@ -442,7 +439,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {...@@ -442,7 +439,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
442/// When `force_load` is `true`, it will for link all object files in the archive.439/// When `force_load` is `true`, it will for link all object files in the archive.
443/// When false, it will only link with object files that contain symbols that440/// When false, it will only link with object files that contain symbols that
444/// are referenced by other object files or Zig code.441/// are referenced by other object files or Zig code.
445fn parseArchive(self: *Wasm, path: []const u8, force_load: bool) !bool {442fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool {
446 const file = try fs.cwd().openFile(path, .{});443 const file = try fs.cwd().openFile(path, .{});
447 errdefer file.close();444 errdefer file.close();
448445
...@@ -450,25 +447,25 @@ fn parseArchive(self: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -450,25 +447,25 @@ fn parseArchive(self: *Wasm, path: []const u8, force_load: bool) !bool {
450 .file = file,447 .file = file,
451 .name = path,448 .name = path,
452 };449 };
453 archive.parse(self.base.allocator) catch |err| switch (err) {450 archive.parse(wasm.base.allocator) catch |err| switch (err) {
454 error.EndOfStream, error.NotArchive => {451 error.EndOfStream, error.NotArchive => {
455 archive.deinit(self.base.allocator);452 archive.deinit(wasm.base.allocator);
456 return false;453 return false;
457 },454 },
458 else => |e| return e,455 else => |e| return e,
459 };456 };
460457
461 if (!force_load) {458 if (!force_load) {
462 errdefer archive.deinit(self.base.allocator);459 errdefer archive.deinit(wasm.base.allocator);
463 try self.archives.append(self.base.allocator, archive);460 try wasm.archives.append(wasm.base.allocator, archive);
464 return true;461 return true;
465 }462 }
466 defer archive.deinit(self.base.allocator);463 defer archive.deinit(wasm.base.allocator);
467464
468 // In this case we must force link all embedded object files within the archive465 // In this case we must force link all embedded object files within the archive
469 // We loop over all symbols, and then group them by offset as the offset466 // We loop over all symbols, and then group them by offset as the offset
470 // notates where the object file starts.467 // notates where the object file starts.
471 var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator);468 var offsets = std.AutoArrayHashMap(u32, void).init(wasm.base.allocator);
472 defer offsets.deinit();469 defer offsets.deinit();
473 for (archive.toc.values()) |symbol_offsets| {470 for (archive.toc.values()) |symbol_offsets| {
474 for (symbol_offsets.items) |sym_offset| {471 for (symbol_offsets.items) |sym_offset| {
...@@ -477,15 +474,15 @@ fn parseArchive(self: *Wasm, path: []const u8, force_load: bool) !bool {...@@ -477,15 +474,15 @@ fn parseArchive(self: *Wasm, path: []const u8, force_load: bool) !bool {
477 }474 }
478475
479 for (offsets.keys()) |file_offset| {476 for (offsets.keys()) |file_offset| {
480 const object = try self.objects.addOne(self.base.allocator);477 const object = try wasm.objects.addOne(wasm.base.allocator);
481 object.* = try archive.parseObject(self.base.allocator, file_offset);478 object.* = try archive.parseObject(wasm.base.allocator, file_offset);
482 }479 }
483480
484 return true;481 return true;
485}482}
486483
487fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {484fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
488 const object: Object = self.objects.items[object_index];485 const object: Object = wasm.objects.items[object_index];
489 log.debug("Resolving symbols in object: '{s}'", .{object.name});486 log.debug("Resolving symbols in object: '{s}'", .{object.name});
490487
491 for (object.symtable) |symbol, i| {488 for (object.symtable) |symbol, i| {
...@@ -498,7 +495,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -498,7 +495,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
498 if (mem.eql(u8, sym_name, "__indirect_function_table")) {495 if (mem.eql(u8, sym_name, "__indirect_function_table")) {
499 continue;496 continue;
500 }497 }
501 const sym_name_index = try self.string_table.put(self.base.allocator, sym_name);498 const sym_name_index = try wasm.string_table.put(wasm.base.allocator, sym_name);
502499
503 if (symbol.isLocal()) {500 if (symbol.isLocal()) {
504 if (symbol.isUndefined()) {501 if (symbol.isUndefined()) {
...@@ -506,27 +503,27 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -506,27 +503,27 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
506 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });503 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });
507 return error.undefinedLocal;504 return error.undefinedLocal;
508 }505 }
509 try self.resolved_symbols.putNoClobber(self.base.allocator, location, {});506 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});
510 continue;507 continue;
511 }508 }
512509
513 const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index);510 const maybe_existing = try wasm.globals.getOrPut(wasm.base.allocator, sym_name_index);
514 if (!maybe_existing.found_existing) {511 if (!maybe_existing.found_existing) {
515 maybe_existing.value_ptr.* = location;512 maybe_existing.value_ptr.* = location;
516 try self.resolved_symbols.putNoClobber(self.base.allocator, location, {});513 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});
517514
518 if (symbol.isUndefined()) {515 if (symbol.isUndefined()) {
519 try self.undefs.putNoClobber(self.base.allocator, sym_name, location);516 try wasm.undefs.putNoClobber(wasm.base.allocator, sym_name, location);
520 }517 }
521 continue;518 continue;
522 }519 }
523520
524 const existing_loc = maybe_existing.value_ptr.*;521 const existing_loc = maybe_existing.value_ptr.*;
525 const existing_sym: *Symbol = existing_loc.getSymbol(self);522 const existing_sym: *Symbol = existing_loc.getSymbol(wasm);
526523
527 const existing_file_path = if (existing_loc.file) |file| blk: {524 const existing_file_path = if (existing_loc.file) |file| blk: {
528 break :blk self.objects.items[file].name;525 break :blk wasm.objects.items[file].name;
529 } else self.name;526 } else wasm.name;
530527
531 if (!existing_sym.isUndefined()) outer: {528 if (!existing_sym.isUndefined()) outer: {
532 if (!symbol.isUndefined()) inner: {529 if (!symbol.isUndefined()) inner: {
...@@ -543,7 +540,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -543,7 +540,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
543 return error.SymbolCollision;540 return error.SymbolCollision;
544 }541 }
545542
546 try self.discarded.put(self.base.allocator, location, existing_loc);543 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);
547 continue; // Do not overwrite defined symbols with undefined symbols544 continue; // Do not overwrite defined symbols with undefined symbols
548 }545 }
549546
...@@ -556,12 +553,12 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -556,12 +553,12 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
556553
557 if (existing_sym.isUndefined() and symbol.isUndefined()) {554 if (existing_sym.isUndefined() and symbol.isUndefined()) {
558 const existing_name = if (existing_loc.file) |file_index| blk: {555 const existing_name = if (existing_loc.file) |file_index| blk: {
559 const obj = self.objects.items[file_index];556 const obj = wasm.objects.items[file_index];
560 const name_index = obj.findImport(symbol.tag.externalType(), existing_sym.index).module_name;557 const name_index = obj.findImport(symbol.tag.externalType(), existing_sym.index).module_name;
561 break :blk obj.string_table.get(name_index);558 break :blk obj.string_table.get(name_index);
562 } else blk: {559 } else blk: {
563 const name_index = self.imports.get(existing_loc).?.module_name;560 const name_index = wasm.imports.get(existing_loc).?.module_name;
564 break :blk self.string_table.get(name_index);561 break :blk wasm.string_table.get(name_index);
565 };562 };
566563
567 const module_index = object.findImport(symbol.tag.externalType(), symbol.index).module_name;564 const module_index = object.findImport(symbol.tag.externalType(), symbol.index).module_name;
...@@ -579,8 +576,8 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -579,8 +576,8 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
579 }576 }
580577
581 if (existing_sym.tag == .global) {578 if (existing_sym.tag == .global) {
582 const existing_ty = self.getGlobalType(existing_loc);579 const existing_ty = wasm.getGlobalType(existing_loc);
583 const new_ty = self.getGlobalType(location);580 const new_ty = wasm.getGlobalType(location);
584 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {581 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
585 log.err("symbol '{s}' mismatching global types", .{sym_name});582 log.err("symbol '{s}' mismatching global types", .{sym_name});
586 log.err(" first definition in '{s}'", .{existing_file_path});583 log.err(" first definition in '{s}'", .{existing_file_path});
...@@ -590,8 +587,8 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -590,8 +587,8 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
590 }587 }
591588
592 if (existing_sym.tag == .function) {589 if (existing_sym.tag == .function) {
593 const existing_ty = self.getFunctionSignature(existing_loc);590 const existing_ty = wasm.getFunctionSignature(existing_loc);
594 const new_ty = self.getFunctionSignature(location);591 const new_ty = wasm.getFunctionSignature(location);
595 if (!existing_ty.eql(new_ty)) {592 if (!existing_ty.eql(new_ty)) {
596 log.err("symbol '{s}' mismatching function signatures.", .{sym_name});593 log.err("symbol '{s}' mismatching function signatures.", .{sym_name});
597 log.err(" expected signature {}, but found signature {}", .{ existing_ty, new_ty });594 log.err(" expected signature {}, but found signature {}", .{ existing_ty, new_ty });
...@@ -603,7 +600,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -603,7 +600,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
603600
604 // when both symbols are weak, we skip overwriting601 // when both symbols are weak, we skip overwriting
605 if (existing_sym.isWeak() and symbol.isWeak()) {602 if (existing_sym.isWeak() and symbol.isWeak()) {
606 try self.discarded.put(self.base.allocator, location, existing_loc);603 try wasm.discarded.put(wasm.base.allocator, location, existing_loc);
607 continue;604 continue;
608 }605 }
609606
...@@ -611,27 +608,27 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -611,27 +608,27 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
611 log.debug("Overwriting symbol '{s}'", .{sym_name});608 log.debug("Overwriting symbol '{s}'", .{sym_name});
612 log.debug(" old definition in '{s}'", .{existing_file_path});609 log.debug(" old definition in '{s}'", .{existing_file_path});
613 log.debug(" new definition in '{s}'", .{object.name});610 log.debug(" new definition in '{s}'", .{object.name});
614 try self.discarded.putNoClobber(self.base.allocator, existing_loc, location);611 try wasm.discarded.putNoClobber(wasm.base.allocator, existing_loc, location);
615 maybe_existing.value_ptr.* = location;612 maybe_existing.value_ptr.* = location;
616 try self.globals.put(self.base.allocator, sym_name_index, location);613 try wasm.globals.put(wasm.base.allocator, sym_name_index, location);
617 try self.resolved_symbols.put(self.base.allocator, location, {});614 try wasm.resolved_symbols.put(wasm.base.allocator, location, {});
618 assert(self.resolved_symbols.swapRemove(existing_loc));615 assert(wasm.resolved_symbols.swapRemove(existing_loc));
619 if (existing_sym.isUndefined()) {616 if (existing_sym.isUndefined()) {
620 assert(self.undefs.swapRemove(sym_name));617 assert(wasm.undefs.swapRemove(sym_name));
621 }618 }
622 }619 }
623}620}
624621
625fn resolveSymbolsInArchives(self: *Wasm) !void {622fn resolveSymbolsInArchives(wasm: *Wasm) !void {
626 if (self.archives.items.len == 0) return;623 if (wasm.archives.items.len == 0) return;
627624
628 log.debug("Resolving symbols in archives", .{});625 log.debug("Resolving symbols in archives", .{});
629 var index: u32 = 0;626 var index: u32 = 0;
630 undef_loop: while (index < self.undefs.count()) {627 undef_loop: while (index < wasm.undefs.count()) {
631 const undef_sym_loc = self.undefs.values()[index];628 const undef_sym_loc = wasm.undefs.values()[index];
632 const sym_name = undef_sym_loc.getName(self);629 const sym_name = undef_sym_loc.getName(wasm);
633630
634 for (self.archives.items) |archive| {631 for (wasm.archives.items) |archive| {
635 const offset = archive.toc.get(sym_name) orelse {632 const offset = archive.toc.get(sym_name) orelse {
636 // symbol does not exist in this archive633 // symbol does not exist in this archive
637 continue;634 continue;
...@@ -641,10 +638,10 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {...@@ -641,10 +638,10 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
641 // Symbol is found in unparsed object file within current archive.638 // Symbol is found in unparsed object file within current archive.
642 // Parse object and and resolve symbols again before we check remaining639 // Parse object and and resolve symbols again before we check remaining
643 // undefined symbols.640 // undefined symbols.
644 const object_file_index = @intCast(u16, self.objects.items.len);641 const object_file_index = @intCast(u16, wasm.objects.items.len);
645 var object = try archive.parseObject(self.base.allocator, offset.items[0]);642 var object = try archive.parseObject(wasm.base.allocator, offset.items[0]);
646 try self.objects.append(self.base.allocator, object);643 try wasm.objects.append(wasm.base.allocator, object);
647 try self.resolveSymbolsInObject(object_file_index);644 try wasm.resolveSymbolsInObject(object_file_index);
648645
649 // continue loop for any remaining undefined symbols that still exist646 // continue loop for any remaining undefined symbols that still exist
650 // after resolving last object file647 // after resolving last object file
...@@ -654,16 +651,18 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {...@@ -654,16 +651,18 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
654 }651 }
655}652}
656653
657fn checkUndefinedSymbols(self: *const Wasm) !void {654fn checkUndefinedSymbols(wasm: *const Wasm) !void {
655 if (wasm.base.options.output_mode == .Obj) return;
656
658 var found_undefined_symbols = false;657 var found_undefined_symbols = false;
659 for (self.undefs.values()) |undef| {658 for (wasm.undefs.values()) |undef| {
660 const symbol = undef.getSymbol(self);659 const symbol = undef.getSymbol(wasm);
661 if (symbol.tag == .data) {660 if (symbol.tag == .data) {
662 found_undefined_symbols = true;661 found_undefined_symbols = true;
663 const file_name = if (undef.file) |file_index| name: {662 const file_name = if (undef.file) |file_index| name: {
664 break :name self.objects.items[file_index].name;663 break :name wasm.objects.items[file_index].name;
665 } else self.name;664 } else wasm.name;
666 log.err("could not resolve undefined symbol '{s}'", .{undef.getName(self)});665 log.err("could not resolve undefined symbol '{s}'", .{undef.getName(wasm)});
667 log.err(" defined in '{s}'", .{file_name});666 log.err(" defined in '{s}'", .{file_name});
668 }667 }
669 }668 }
...@@ -672,80 +671,80 @@ fn checkUndefinedSymbols(self: *const Wasm) !void {...@@ -672,80 +671,80 @@ fn checkUndefinedSymbols(self: *const Wasm) !void {
672 }671 }
673}672}
674673
675pub fn deinit(self: *Wasm) void {674pub fn deinit(wasm: *Wasm) void {
676 const gpa = self.base.allocator;675 const gpa = wasm.base.allocator;
677 if (build_options.have_llvm) {676 if (build_options.have_llvm) {
678 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);677 if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa);
679 }678 }
680679
681 if (self.base.options.module) |mod| {680 if (wasm.base.options.module) |mod| {
682 var decl_it = self.decls.keyIterator();681 var decl_it = wasm.decls.keyIterator();
683 while (decl_it.next()) |decl_index_ptr| {682 while (decl_it.next()) |decl_index_ptr| {
684 const decl = mod.declPtr(decl_index_ptr.*);683 const decl = mod.declPtr(decl_index_ptr.*);
685 decl.link.wasm.deinit(gpa);684 decl.link.wasm.deinit(gpa);
686 }685 }
687 } else {686 } else {
688 assert(self.decls.count() == 0);687 assert(wasm.decls.count() == 0);
689 }688 }
690689
691 for (self.func_types.items) |*func_type| {690 for (wasm.func_types.items) |*func_type| {
692 func_type.deinit(gpa);691 func_type.deinit(gpa);
693 }692 }
694 for (self.segment_info.values()) |segment_info| {693 for (wasm.segment_info.values()) |segment_info| {
695 gpa.free(segment_info.name);694 gpa.free(segment_info.name);
696 }695 }
697 for (self.objects.items) |*object| {696 for (wasm.objects.items) |*object| {
698 object.deinit(gpa);697 object.deinit(gpa);
699 }698 }
700699
701 for (self.archives.items) |*archive| {700 for (wasm.archives.items) |*archive| {
702 archive.deinit(gpa);701 archive.deinit(gpa);
703 }702 }
704703
705 self.decls.deinit(gpa);704 wasm.decls.deinit(gpa);
706 self.symbols.deinit(gpa);705 wasm.symbols.deinit(gpa);
707 self.symbols_free_list.deinit(gpa);706 wasm.symbols_free_list.deinit(gpa);
708 self.globals.deinit(gpa);707 wasm.globals.deinit(gpa);
709 self.resolved_symbols.deinit(gpa);708 wasm.resolved_symbols.deinit(gpa);
710 self.undefs.deinit(gpa);709 wasm.undefs.deinit(gpa);
711 self.discarded.deinit(gpa);710 wasm.discarded.deinit(gpa);
712 self.symbol_atom.deinit(gpa);711 wasm.symbol_atom.deinit(gpa);
713 self.export_names.deinit(gpa);712 wasm.export_names.deinit(gpa);
714 self.atoms.deinit(gpa);713 wasm.atoms.deinit(gpa);
715 for (self.managed_atoms.items) |managed_atom| {714 for (wasm.managed_atoms.items) |managed_atom| {
716 managed_atom.deinit(gpa);715 managed_atom.deinit(gpa);
717 gpa.destroy(managed_atom);716 gpa.destroy(managed_atom);
718 }717 }
719 self.managed_atoms.deinit(gpa);718 wasm.managed_atoms.deinit(gpa);
720 self.segments.deinit(gpa);719 wasm.segments.deinit(gpa);
721 self.data_segments.deinit(gpa);720 wasm.data_segments.deinit(gpa);
722 self.segment_info.deinit(gpa);721 wasm.segment_info.deinit(gpa);
723 self.objects.deinit(gpa);722 wasm.objects.deinit(gpa);
724 self.archives.deinit(gpa);723 wasm.archives.deinit(gpa);
725724
726 // free output sections725 // free output sections
727 self.imports.deinit(gpa);726 wasm.imports.deinit(gpa);
728 self.func_types.deinit(gpa);727 wasm.func_types.deinit(gpa);
729 self.functions.deinit(gpa);728 wasm.functions.deinit(gpa);
730 self.wasm_globals.deinit(gpa);729 wasm.wasm_globals.deinit(gpa);
731 self.function_table.deinit(gpa);730 wasm.function_table.deinit(gpa);
732 self.tables.deinit(gpa);731 wasm.tables.deinit(gpa);
733 self.exports.deinit(gpa);732 wasm.exports.deinit(gpa);
734733
735 self.string_table.deinit(gpa);734 wasm.string_table.deinit(gpa);
736735
737 if (self.dwarf) |*dwarf| {736 if (wasm.dwarf) |*dwarf| {
738 dwarf.deinit();737 dwarf.deinit();
739 }738 }
740}739}
741740
742pub fn allocateDeclIndexes(self: *Wasm, decl_index: Module.Decl.Index) !void {741pub fn allocateDeclIndexes(wasm: *Wasm, decl_index: Module.Decl.Index) !void {
743 if (self.llvm_object) |_| return;742 if (wasm.llvm_object) |_| return;
744 const decl = self.base.options.module.?.declPtr(decl_index);743 const decl = wasm.base.options.module.?.declPtr(decl_index);
745 if (decl.link.wasm.sym_index != 0) return;744 if (decl.link.wasm.sym_index != 0) return;
746745
747 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);746 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
748 try self.decls.putNoClobber(self.base.allocator, decl_index, {});747 try wasm.decls.putNoClobber(wasm.base.allocator, decl_index, {});
749748
750 const atom = &decl.link.wasm;749 const atom = &decl.link.wasm;
751750
...@@ -756,22 +755,22 @@ pub fn allocateDeclIndexes(self: *Wasm, decl_index: Module.Decl.Index) !void {...@@ -756,22 +755,22 @@ pub fn allocateDeclIndexes(self: *Wasm, decl_index: Module.Decl.Index) !void {
756 .index = undefined, // will be set after updateDecl755 .index = undefined, // will be set after updateDecl
757 };756 };
758757
759 if (self.symbols_free_list.popOrNull()) |index| {758 if (wasm.symbols_free_list.popOrNull()) |index| {
760 atom.sym_index = index;759 atom.sym_index = index;
761 self.symbols.items[index] = symbol;760 wasm.symbols.items[index] = symbol;
762 } else {761 } else {
763 atom.sym_index = @intCast(u32, self.symbols.items.len);762 atom.sym_index = @intCast(u32, wasm.symbols.items.len);
764 self.symbols.appendAssumeCapacity(symbol);763 wasm.symbols.appendAssumeCapacity(symbol);
765 }764 }
766 try self.symbol_atom.putNoClobber(self.base.allocator, atom.symbolLoc(), atom);765 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom);
767}766}
768767
769pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {768pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
770 if (build_options.skip_non_native and builtin.object_format != .wasm) {769 if (build_options.skip_non_native and builtin.object_format != .wasm) {
771 @panic("Attempted to compile for object format that was disabled by build configuration");770 @panic("Attempted to compile for object format that was disabled by build configuration");
772 }771 }
773 if (build_options.have_llvm) {772 if (build_options.have_llvm) {
774 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness);773 if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness);
775 }774 }
776775
777 const tracy = trace(@src());776 const tracy = trace(@src());
...@@ -783,13 +782,13 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -783,13 +782,13 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
783782
784 decl.link.wasm.clear();783 decl.link.wasm.clear();
785784
786 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl) else null;785 var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl) else null;
787 defer if (decl_state) |*ds| ds.deinit();786 defer if (decl_state) |*ds| ds.deinit();
788787
789 var code_writer = std.ArrayList(u8).init(self.base.allocator);788 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
790 defer code_writer.deinit();789 defer code_writer.deinit();
791 const result = try codegen.generateFunction(790 const result = try codegen.generateFunction(
792 &self.base,791 &wasm.base,
793 decl.srcLoc(),792 decl.srcLoc(),
794 func,793 func,
795 air,794 air,
...@@ -807,9 +806,9 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -807,9 +806,9 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
807 },806 },
808 };807 };
809808
810 if (self.dwarf) |*dwarf| {809 if (wasm.dwarf) |*dwarf| {
811 try dwarf.commitDeclState(810 try dwarf.commitDeclState(
812 &self.base,811 &wasm.base,
813 mod,812 mod,
814 decl,813 decl,
815 // Actual value will be written after relocation.814 // Actual value will be written after relocation.
...@@ -820,17 +819,17 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes...@@ -820,17 +819,17 @@ pub fn updateFunc(self: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes
820 &decl_state.?,819 &decl_state.?,
821 );820 );
822 }821 }
823 return self.finishUpdateDecl(decl, code);822 return wasm.finishUpdateDecl(decl, code);
824}823}
825824
826// Generate code for the Decl, storing it in memory to be later written to825// Generate code for the Decl, storing it in memory to be later written to
827// the file on flush().826// the file on flush().
828pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void {827pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !void {
829 if (build_options.skip_non_native and builtin.object_format != .wasm) {828 if (build_options.skip_non_native and builtin.object_format != .wasm) {
830 @panic("Attempted to compile for object format that was disabled by build configuration");829 @panic("Attempted to compile for object format that was disabled by build configuration");
831 }830 }
832 if (build_options.have_llvm) {831 if (build_options.have_llvm) {
833 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);832 if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
834 }833 }
835834
836 const tracy = trace(@src());835 const tracy = trace(@src());
...@@ -850,15 +849,15 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi...@@ -850,15 +849,15 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
850 if (decl.isExtern()) {849 if (decl.isExtern()) {
851 const variable = decl.getVariable().?;850 const variable = decl.getVariable().?;
852 const name = mem.sliceTo(decl.name, 0);851 const name = mem.sliceTo(decl.name, 0);
853 return self.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);852 return wasm.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);
854 }853 }
855 const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;854 const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
856855
857 var code_writer = std.ArrayList(u8).init(self.base.allocator);856 var code_writer = std.ArrayList(u8).init(wasm.base.allocator);
858 defer code_writer.deinit();857 defer code_writer.deinit();
859858
860 const res = try codegen.generateSymbol(859 const res = try codegen.generateSymbol(
861 &self.base,860 &wasm.base,
862 decl.srcLoc(),861 decl.srcLoc(),
863 .{ .ty = decl.ty, .val = val },862 .{ .ty = decl.ty, .val = val },
864 &code_writer,863 &code_writer,
...@@ -876,46 +875,46 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi...@@ -876,46 +875,46 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
876 },875 },
877 };876 };
878877
879 return self.finishUpdateDecl(decl, code);878 return wasm.finishUpdateDecl(decl, code);
880}879}
881880
882pub fn updateDeclLineNumber(self: *Wasm, mod: *Module, decl: *const Module.Decl) !void {881pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl: *const Module.Decl) !void {
883 if (self.llvm_object) |_| return;882 if (wasm.llvm_object) |_| return;
884 if (self.dwarf) |*dw| {883 if (wasm.dwarf) |*dw| {
885 const tracy = trace(@src());884 const tracy = trace(@src());
886 defer tracy.end();885 defer tracy.end();
887886
888 const decl_name = try decl.getFullyQualifiedName(mod);887 const decl_name = try decl.getFullyQualifiedName(mod);
889 defer self.base.allocator.free(decl_name);888 defer wasm.base.allocator.free(decl_name);
890889
891 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });890 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
892 try dw.updateDeclLineNumber(&self.base, decl);891 try dw.updateDeclLineNumber(&wasm.base, decl);
893 }892 }
894}893}
895894
896fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {895fn finishUpdateDecl(wasm: *Wasm, decl: *Module.Decl, code: []const u8) !void {
897 const mod = self.base.options.module.?;896 const mod = wasm.base.options.module.?;
898 const atom: *Atom = &decl.link.wasm;897 const atom: *Atom = &decl.link.wasm;
899 const symbol = &self.symbols.items[atom.sym_index];898 const symbol = &wasm.symbols.items[atom.sym_index];
900 const full_name = try decl.getFullyQualifiedName(mod);899 const full_name = try decl.getFullyQualifiedName(mod);
901 defer self.base.allocator.free(full_name);900 defer wasm.base.allocator.free(full_name);
902 symbol.name = try self.string_table.put(self.base.allocator, full_name);901 symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name);
903 try atom.code.appendSlice(self.base.allocator, code);902 try atom.code.appendSlice(wasm.base.allocator, code);
904 try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});903 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
905904
906 if (code.len == 0) return;905 if (code.len == 0) return;
907 atom.size = @intCast(u32, code.len);906 atom.size = @intCast(u32, code.len);
908 atom.alignment = decl.ty.abiAlignment(self.base.options.target);907 atom.alignment = decl.ty.abiAlignment(wasm.base.options.target);
909}908}
910909
911/// From a given symbol location, returns its `wasm.GlobalType`.910/// From a given symbol location, returns its `wasm.GlobalType`.
912/// Asserts the Symbol represents a global.911/// Asserts the Symbol represents a global.
913fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {912fn getGlobalType(wasm: *const Wasm, loc: SymbolLoc) std.wasm.GlobalType {
914 const symbol = loc.getSymbol(self);913 const symbol = loc.getSymbol(wasm);
915 assert(symbol.tag == .global);914 assert(symbol.tag == .global);
916 const is_undefined = symbol.isUndefined();915 const is_undefined = symbol.isUndefined();
917 if (loc.file) |file_index| {916 if (loc.file) |file_index| {
918 const obj: Object = self.objects.items[file_index];917 const obj: Object = wasm.objects.items[file_index];
919 if (is_undefined) {918 if (is_undefined) {
920 return obj.findImport(.global, symbol.index).kind.global;919 return obj.findImport(.global, symbol.index).kind.global;
921 }920 }
...@@ -923,19 +922,19 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {...@@ -923,19 +922,19 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {
923 return obj.globals[symbol.index - import_global_count].global_type;922 return obj.globals[symbol.index - import_global_count].global_type;
924 }923 }
925 if (is_undefined) {924 if (is_undefined) {
926 return self.imports.get(loc).?.kind.global;925 return wasm.imports.get(loc).?.kind.global;
927 }926 }
928 return self.wasm_globals.items[symbol.index].global_type;927 return wasm.wasm_globals.items[symbol.index].global_type;
929}928}
930929
931/// From a given symbol location, returns its `wasm.Type`.930/// From a given symbol location, returns its `wasm.Type`.
932/// Asserts the Symbol represents a function.931/// Asserts the Symbol represents a function.
933fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {932fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
934 const symbol = loc.getSymbol(self);933 const symbol = loc.getSymbol(wasm);
935 assert(symbol.tag == .function);934 assert(symbol.tag == .function);
936 const is_undefined = symbol.isUndefined();935 const is_undefined = symbol.isUndefined();
937 if (loc.file) |file_index| {936 if (loc.file) |file_index| {
938 const obj: Object = self.objects.items[file_index];937 const obj: Object = wasm.objects.items[file_index];
939 if (is_undefined) {938 if (is_undefined) {
940 const ty_index = obj.findImport(.function, symbol.index).kind.function;939 const ty_index = obj.findImport(.function, symbol.index).kind.function;
941 return obj.func_types[ty_index];940 return obj.func_types[ty_index];
...@@ -945,55 +944,55 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {...@@ -945,55 +944,55 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {
945 return obj.func_types[type_index];944 return obj.func_types[type_index];
946 }945 }
947 if (is_undefined) {946 if (is_undefined) {
948 const ty_index = self.imports.get(loc).?.kind.function;947 const ty_index = wasm.imports.get(loc).?.kind.function;
949 return self.func_types.items[ty_index];948 return wasm.func_types.items[ty_index];
950 }949 }
951 return self.func_types.items[self.functions.get(.{ .file = loc.file, .index = loc.index }).?.type_index];950 return wasm.func_types.items[wasm.functions.get(.{ .file = loc.file, .index = loc.index }).?.type_index];
952}951}
953952
954/// Lowers a constant typed value to a local symbol and atom.953/// Lowers a constant typed value to a local symbol and atom.
955/// Returns the symbol index of the local954/// Returns the symbol index of the local
956/// The given `decl` is the parent decl whom owns the constant.955/// The given `decl` is the parent decl whom owns the constant.
957pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {956pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
958 assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions957 assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
959958
960 const mod = self.base.options.module.?;959 const mod = wasm.base.options.module.?;
961 const decl = mod.declPtr(decl_index);960 const decl = mod.declPtr(decl_index);
962961
963 // Create and initialize a new local symbol and atom962 // Create and initialize a new local symbol and atom
964 const local_index = decl.link.wasm.locals.items.len;963 const local_index = decl.link.wasm.locals.items.len;
965 const fqdn = try decl.getFullyQualifiedName(mod);964 const fqdn = try decl.getFullyQualifiedName(mod);
966 defer self.base.allocator.free(fqdn);965 defer wasm.base.allocator.free(fqdn);
967 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });966 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index });
968 defer self.base.allocator.free(name);967 defer wasm.base.allocator.free(name);
969 var symbol: Symbol = .{968 var symbol: Symbol = .{
970 .name = try self.string_table.put(self.base.allocator, name),969 .name = try wasm.string_table.put(wasm.base.allocator, name),
971 .flags = 0,970 .flags = 0,
972 .tag = .data,971 .tag = .data,
973 .index = undefined,972 .index = undefined,
974 };973 };
975 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);974 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
976975
977 const atom = try decl.link.wasm.locals.addOne(self.base.allocator);976 const atom = try decl.link.wasm.locals.addOne(wasm.base.allocator);
978 atom.* = Atom.empty;977 atom.* = Atom.empty;
979 atom.alignment = tv.ty.abiAlignment(self.base.options.target);978 atom.alignment = tv.ty.abiAlignment(wasm.base.options.target);
980 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);979 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
981980
982 if (self.symbols_free_list.popOrNull()) |index| {981 if (wasm.symbols_free_list.popOrNull()) |index| {
983 atom.sym_index = index;982 atom.sym_index = index;
984 self.symbols.items[index] = symbol;983 wasm.symbols.items[index] = symbol;
985 } else {984 } else {
986 atom.sym_index = @intCast(u32, self.symbols.items.len);985 atom.sym_index = @intCast(u32, wasm.symbols.items.len);
987 self.symbols.appendAssumeCapacity(symbol);986 wasm.symbols.appendAssumeCapacity(symbol);
988 }987 }
989 try self.resolved_symbols.putNoClobber(self.base.allocator, atom.symbolLoc(), {});988 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {});
990 try self.symbol_atom.putNoClobber(self.base.allocator, atom.symbolLoc(), atom);989 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom);
991990
992 var value_bytes = std.ArrayList(u8).init(self.base.allocator);991 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
993 defer value_bytes.deinit();992 defer value_bytes.deinit();
994993
995 const result = try codegen.generateSymbol(994 const result = try codegen.generateSymbol(
996 &self.base,995 &wasm.base,
997 decl.srcLoc(),996 decl.srcLoc(),
998 tv,997 tv,
999 &value_bytes,998 &value_bytes,
...@@ -1014,7 +1013,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1014,7 +1013,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1014 };1013 };
10151014
1016 atom.size = @intCast(u32, code.len);1015 atom.size = @intCast(u32, code.len);
1017 try atom.code.appendSlice(self.base.allocator, code);1016 try atom.code.appendSlice(wasm.base.allocator, code);
1018 return atom.sym_index;1017 return atom.sym_index;
1019}1018}
10201019
...@@ -1022,9 +1021,9 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1022,9 +1021,9 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1022/// such as an exported or imported symbol.1021/// such as an exported or imported symbol.
1023/// If the symbol does not yet exist, creates a new one symbol instead1022/// If the symbol does not yet exist, creates a new one symbol instead
1024/// and then returns the index to it.1023/// and then returns the index to it.
1025pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 {1024pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8) !u32 {
1026 const name_index = try self.string_table.put(self.base.allocator, name);1025 const name_index = try wasm.string_table.put(wasm.base.allocator, name);
1027 const gop = try self.globals.getOrPut(self.base.allocator, name_index);1026 const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index);
1028 if (gop.found_existing) {1027 if (gop.found_existing) {
1029 return gop.value_ptr.*.index;1028 return gop.value_ptr.*.index;
1030 }1029 }
...@@ -1038,46 +1037,46 @@ pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 {...@@ -1038,46 +1037,46 @@ pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 {
1038 symbol.setGlobal(true);1037 symbol.setGlobal(true);
1039 symbol.setUndefined(true);1038 symbol.setUndefined(true);
10401039
1041 const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: {1040 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: {
1042 var index = @intCast(u32, self.symbols.items.len);1041 var index = @intCast(u32, wasm.symbols.items.len);
1043 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);1042 try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1);
1044 self.symbols.items.len += 1;1043 wasm.symbols.items.len += 1;
1045 break :blk index;1044 break :blk index;
1046 };1045 };
1047 self.symbols.items[sym_index] = symbol;1046 wasm.symbols.items[sym_index] = symbol;
1048 gop.value_ptr.* = .{ .index = sym_index, .file = null };1047 gop.value_ptr.* = .{ .index = sym_index, .file = null };
1049 try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {});1048 try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {});
1050 try self.undefs.putNoClobber(self.base.allocator, name, gop.value_ptr.*);1049 try wasm.undefs.putNoClobber(wasm.base.allocator, name, gop.value_ptr.*);
1051 return sym_index;1050 return sym_index;
1052}1051}
10531052
1054/// For a given decl, find the given symbol index's atom, and create a relocation for the type.1053/// For a given decl, find the given symbol index's atom, and create a relocation for the type.
1055/// Returns the given pointer address1054/// Returns the given pointer address
1056pub fn getDeclVAddr(1055pub fn getDeclVAddr(
1057 self: *Wasm,1056 wasm: *Wasm,
1058 decl_index: Module.Decl.Index,1057 decl_index: Module.Decl.Index,
1059 reloc_info: link.File.RelocInfo,1058 reloc_info: link.File.RelocInfo,
1060) !u64 {1059) !u64 {
1061 const mod = self.base.options.module.?;1060 const mod = wasm.base.options.module.?;
1062 const decl = mod.declPtr(decl_index);1061 const decl = mod.declPtr(decl_index);
1063 const target_symbol_index = decl.link.wasm.sym_index;1062 const target_symbol_index = decl.link.wasm.sym_index;
1064 assert(target_symbol_index != 0);1063 assert(target_symbol_index != 0);
1065 assert(reloc_info.parent_atom_index != 0);1064 assert(reloc_info.parent_atom_index != 0);
1066 const atom = self.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;1065 const atom = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1067 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;1066 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
1068 if (decl.ty.zigTypeTag() == .Fn) {1067 if (decl.ty.zigTypeTag() == .Fn) {
1069 assert(reloc_info.addend == 0); // addend not allowed for function relocations1068 assert(reloc_info.addend == 0); // addend not allowed for function relocations
1070 // We found a function pointer, so add it to our table,1069 // We found a function pointer, so add it to our table,
1071 // as function pointers are not allowed to be stored inside the data section.1070 // as function pointers are not allowed to be stored inside the data section.
1072 // They are instead stored in a function table which are called by index.1071 // They are instead stored in a function table which are called by index.
1073 try self.addTableFunction(target_symbol_index);1072 try wasm.addTableFunction(target_symbol_index);
1074 try atom.relocs.append(self.base.allocator, .{1073 try atom.relocs.append(wasm.base.allocator, .{
1075 .index = target_symbol_index,1074 .index = target_symbol_index,
1076 .offset = @intCast(u32, reloc_info.offset),1075 .offset = @intCast(u32, reloc_info.offset),
1077 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,1076 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1078 });1077 });
1079 } else {1078 } else {
1080 try atom.relocs.append(self.base.allocator, .{1079 try atom.relocs.append(wasm.base.allocator, .{
1081 .index = target_symbol_index,1080 .index = target_symbol_index,
1082 .offset = @intCast(u32, reloc_info.offset),1081 .offset = @intCast(u32, reloc_info.offset),
1083 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,1082 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
...@@ -1091,22 +1090,22 @@ pub fn getDeclVAddr(...@@ -1091,22 +1090,22 @@ pub fn getDeclVAddr(
1091 return target_symbol_index;1090 return target_symbol_index;
1092}1091}
10931092
1094pub fn deleteExport(self: *Wasm, exp: Export) void {1093pub fn deleteExport(wasm: *Wasm, exp: Export) void {
1095 if (self.llvm_object) |_| return;1094 if (wasm.llvm_object) |_| return;
1096 const sym_index = exp.sym_index orelse return;1095 const sym_index = exp.sym_index orelse return;
1097 const loc: SymbolLoc = .{ .file = null, .index = sym_index };1096 const loc: SymbolLoc = .{ .file = null, .index = sym_index };
1098 const symbol = loc.getSymbol(self);1097 const symbol = loc.getSymbol(wasm);
1099 const symbol_name = self.string_table.get(symbol.name);1098 const symbol_name = wasm.string_table.get(symbol.name);
1100 log.debug("Deleting export for decl '{s}'", .{symbol_name});1099 log.debug("Deleting export for decl '{s}'", .{symbol_name});
1101 if (self.export_names.fetchRemove(loc)) |kv| {1100 if (wasm.export_names.fetchRemove(loc)) |kv| {
1102 assert(self.globals.remove(kv.value));1101 assert(wasm.globals.remove(kv.value));
1103 } else {1102 } else {
1104 assert(self.globals.remove(symbol.name));1103 assert(wasm.globals.remove(symbol.name));
1105 }1104 }
1106}1105}
11071106
1108pub fn updateDeclExports(1107pub fn updateDeclExports(
1109 self: *Wasm,1108 wasm: *Wasm,
1110 mod: *Module,1109 mod: *Module,
1111 decl_index: Module.Decl.Index,1110 decl_index: Module.Decl.Index,
1112 exports: []const *Module.Export,1111 exports: []const *Module.Export,
...@@ -1115,7 +1114,7 @@ pub fn updateDeclExports(...@@ -1115,7 +1114,7 @@ pub fn updateDeclExports(
1115 @panic("Attempted to compile for object format that was disabled by build configuration");1114 @panic("Attempted to compile for object format that was disabled by build configuration");
1116 }1115 }
1117 if (build_options.have_llvm) {1116 if (build_options.have_llvm) {
1118 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);1117 if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
1119 }1118 }
11201119
1121 const decl = mod.declPtr(decl_index);1120 const decl = mod.declPtr(decl_index);
...@@ -1131,10 +1130,10 @@ pub fn updateDeclExports(...@@ -1131,10 +1130,10 @@ pub fn updateDeclExports(
1131 continue;1130 continue;
1132 }1131 }
11331132
1134 const export_name = try self.string_table.put(self.base.allocator, exp.options.name);1133 const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name);
1135 if (self.globals.getPtr(export_name)) |existing_loc| {1134 if (wasm.globals.getPtr(export_name)) |existing_loc| {
1136 if (existing_loc.index == decl.link.wasm.sym_index) continue;1135 if (existing_loc.index == decl.link.wasm.sym_index) continue;
1137 const existing_sym: Symbol = existing_loc.getSymbol(self).*;1136 const existing_sym: Symbol = existing_loc.getSymbol(wasm).*;
11381137
1139 const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;1138 const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak;
1140 // When both the to-bo-exported symbol and the already existing symbol1139 // When both the to-bo-exported symbol and the already existing symbol
...@@ -1148,7 +1147,7 @@ pub fn updateDeclExports(...@@ -1148,7 +1147,7 @@ pub fn updateDeclExports(
1148 \\ first definition in '{s}'1147 \\ first definition in '{s}'
1149 \\ next definition in '{s}'1148 \\ next definition in '{s}'
1150 ,1149 ,
1151 .{ exp.options.name, self.name, self.name },1150 .{ exp.options.name, wasm.name, wasm.name },
1152 ));1151 ));
1153 continue;1152 continue;
1154 } else if (exp_is_weak) {1153 } else if (exp_is_weak) {
...@@ -1163,7 +1162,7 @@ pub fn updateDeclExports(...@@ -1163,7 +1162,7 @@ pub fn updateDeclExports(
1163 const exported_decl = mod.declPtr(exp.exported_decl);1162 const exported_decl = mod.declPtr(exp.exported_decl);
1164 const sym_index = exported_decl.link.wasm.sym_index;1163 const sym_index = exported_decl.link.wasm.sym_index;
1165 const sym_loc = exported_decl.link.wasm.symbolLoc();1164 const sym_loc = exported_decl.link.wasm.symbolLoc();
1166 const symbol = sym_loc.getSymbol(self);1165 const symbol = sym_loc.getSymbol(wasm);
1167 switch (exp.options.linkage) {1166 switch (exp.options.linkage) {
1168 .Internal => {1167 .Internal => {
1169 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);1168 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
...@@ -1183,68 +1182,68 @@ pub fn updateDeclExports(...@@ -1183,68 +1182,68 @@ pub fn updateDeclExports(
1183 },1182 },
1184 }1183 }
1185 // Ensure the symbol will be exported using the given name1184 // Ensure the symbol will be exported using the given name
1186 if (!mem.eql(u8, exp.options.name, sym_loc.getName(self))) {1185 if (!mem.eql(u8, exp.options.name, sym_loc.getName(wasm))) {
1187 try self.export_names.put(self.base.allocator, sym_loc, export_name);1186 try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name);
1188 }1187 }
11891188
1190 symbol.setGlobal(true);1189 symbol.setGlobal(true);
1191 symbol.setUndefined(false);1190 symbol.setUndefined(false);
1192 try self.globals.put(1191 try wasm.globals.put(
1193 self.base.allocator,1192 wasm.base.allocator,
1194 export_name,1193 export_name,
1195 sym_loc,1194 sym_loc,
1196 );1195 );
11971196
1198 // if the symbol was previously undefined, remove it as an import1197 // if the symbol was previously undefined, remove it as an import
1199 _ = self.imports.remove(sym_loc);1198 _ = wasm.imports.remove(sym_loc);
1200 _ = self.undefs.swapRemove(exp.options.name);1199 _ = wasm.undefs.swapRemove(exp.options.name);
1201 exp.link.wasm.sym_index = sym_index;1200 exp.link.wasm.sym_index = sym_index;
1202 }1201 }
1203}1202}
12041203
1205pub fn freeDecl(self: *Wasm, decl_index: Module.Decl.Index) void {1204pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void {
1206 if (build_options.have_llvm) {1205 if (build_options.have_llvm) {
1207 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);1206 if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
1208 }1207 }
1209 const mod = self.base.options.module.?;1208 const mod = wasm.base.options.module.?;
1210 const decl = mod.declPtr(decl_index);1209 const decl = mod.declPtr(decl_index);
1211 const atom = &decl.link.wasm;1210 const atom = &decl.link.wasm;
1212 self.symbols_free_list.append(self.base.allocator, atom.sym_index) catch {};1211 wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {};
1213 _ = self.decls.remove(decl_index);1212 _ = wasm.decls.remove(decl_index);
1214 self.symbols.items[atom.sym_index].tag = .dead;1213 wasm.symbols.items[atom.sym_index].tag = .dead;
1215 for (atom.locals.items) |local_atom| {1214 for (atom.locals.items) |local_atom| {
1216 const local_symbol = &self.symbols.items[local_atom.sym_index];1215 const local_symbol = &wasm.symbols.items[local_atom.sym_index];
1217 local_symbol.tag = .dead; // also for any local symbol1216 local_symbol.tag = .dead; // also for any local symbol
1218 self.symbols_free_list.append(self.base.allocator, local_atom.sym_index) catch {};1217 wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {};
1219 assert(self.resolved_symbols.swapRemove(local_atom.symbolLoc()));1218 assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc()));
1220 assert(self.symbol_atom.remove(local_atom.symbolLoc()));1219 assert(wasm.symbol_atom.remove(local_atom.symbolLoc()));
1221 }1220 }
12221221
1223 if (decl.isExtern()) {1222 if (decl.isExtern()) {
1224 _ = self.imports.remove(atom.symbolLoc());1223 _ = wasm.imports.remove(atom.symbolLoc());
1225 }1224 }
1226 _ = self.resolved_symbols.swapRemove(atom.symbolLoc());1225 _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc());
1227 _ = self.symbol_atom.remove(atom.symbolLoc());1226 _ = wasm.symbol_atom.remove(atom.symbolLoc());
12281227
1229 if (self.dwarf) |*dwarf| {1228 if (wasm.dwarf) |*dwarf| {
1230 dwarf.freeDecl(decl);1229 dwarf.freeDecl(decl);
1231 dwarf.freeAtom(&atom.dbg_info_atom);1230 dwarf.freeAtom(&atom.dbg_info_atom);
1232 }1231 }
12331232
1234 atom.deinit(self.base.allocator);1233 atom.deinit(wasm.base.allocator);
1235}1234}
12361235
1237/// Appends a new entry to the indirect function table1236/// Appends a new entry to the indirect function table
1238pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {1237pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {
1239 const index = @intCast(u32, self.function_table.count());1238 const index = @intCast(u32, wasm.function_table.count());
1240 try self.function_table.put(self.base.allocator, .{ .file = null, .index = symbol_index }, index);1239 try wasm.function_table.put(wasm.base.allocator, .{ .file = null, .index = symbol_index }, index);
1241}1240}
12421241
1243/// Assigns indexes to all indirect functions.1242/// Assigns indexes to all indirect functions.
1244/// Starts at offset 1, where the value `0` represents an unresolved function pointer1243/// Starts at offset 1, where the value `0` represents an unresolved function pointer
1245/// or null-pointer1244/// or null-pointer
1246fn mapFunctionTable(self: *Wasm) void {1245fn mapFunctionTable(wasm: *Wasm) void {
1247 var it = self.function_table.valueIterator();1246 var it = wasm.function_table.valueIterator();
1248 var index: u32 = 1;1247 var index: u32 = 1;
1249 while (it.next()) |value_ptr| : (index += 1) {1248 while (it.next()) |value_ptr| : (index += 1) {
1250 value_ptr.* = index;1249 value_ptr.* = index;
...@@ -1255,7 +1254,7 @@ fn mapFunctionTable(self: *Wasm) void {...@@ -1255,7 +1254,7 @@ fn mapFunctionTable(self: *Wasm) void {
1255/// When `type_index` is non-null, we assume an external function.1254/// When `type_index` is non-null, we assume an external function.
1256/// In all other cases, a data-symbol will be created instead.1255/// In all other cases, a data-symbol will be created instead.
1257pub fn addOrUpdateImport(1256pub fn addOrUpdateImport(
1258 self: *Wasm,1257 wasm: *Wasm,
1259 /// Name of the import1258 /// Name of the import
1260 name: []const u8,1259 name: []const u8,
1261 /// Symbol index that is external1260 /// Symbol index that is external
...@@ -1268,28 +1267,28 @@ pub fn addOrUpdateImport(...@@ -1268,28 +1267,28 @@ pub fn addOrUpdateImport(
1268 type_index: ?u32,1267 type_index: ?u32,
1269) !void {1268) !void {
1270 assert(symbol_index != 0);1269 assert(symbol_index != 0);
1271 // For the import name itself, we use the decl's name, rather than the fully qualified name1270 // For the import name itwasm, we use the decl's name, rather than the fully qualified name
1272 const decl_name_index = try self.string_table.put(self.base.allocator, name);1271 const decl_name_index = try wasm.string_table.put(wasm.base.allocator, name);
1273 const symbol: *Symbol = &self.symbols.items[symbol_index];1272 const symbol: *Symbol = &wasm.symbols.items[symbol_index];
1274 symbol.setUndefined(true);1273 symbol.setUndefined(true);
1275 symbol.setGlobal(true);1274 symbol.setGlobal(true);
1276 symbol.name = decl_name_index;1275 symbol.name = decl_name_index;
1277 const global_gop = try self.globals.getOrPut(self.base.allocator, decl_name_index);1276 const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index);
1278 if (!global_gop.found_existing) {1277 if (!global_gop.found_existing) {
1279 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };1278 const loc: SymbolLoc = .{ .file = null, .index = symbol_index };
1280 global_gop.value_ptr.* = loc;1279 global_gop.value_ptr.* = loc;
1281 try self.resolved_symbols.put(self.base.allocator, loc, {});1280 try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});
1282 try self.undefs.putNoClobber(self.base.allocator, name, loc);1281 try wasm.undefs.putNoClobber(wasm.base.allocator, name, loc);
1283 }1282 }
12841283
1285 if (type_index) |ty_index| {1284 if (type_index) |ty_index| {
1286 const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });1285 const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null });
1287 const module_name = if (lib_name) |l_name| blk: {1286 const module_name = if (lib_name) |l_name| blk: {
1288 break :blk mem.sliceTo(l_name, 0);1287 break :blk mem.sliceTo(l_name, 0);
1289 } else self.host_name;1288 } else wasm.host_name;
1290 if (!gop.found_existing) {1289 if (!gop.found_existing) {
1291 gop.value_ptr.* = .{1290 gop.value_ptr.* = .{
1292 .module_name = try self.string_table.put(self.base.allocator, module_name),1291 .module_name = try wasm.string_table.put(wasm.base.allocator, module_name),
1293 .name = decl_name_index,1292 .name = decl_name_index,
1294 .kind = .{ .function = ty_index },1293 .kind = .{ .function = ty_index },
1295 };1294 };
...@@ -1326,36 +1325,36 @@ const Kind = union(enum) {...@@ -1326,36 +1325,36 @@ const Kind = union(enum) {
1326};1325};
13271326
1328/// Parses an Atom and inserts its metadata into the corresponding sections.1327/// Parses an Atom and inserts its metadata into the corresponding sections.
1329fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {1328fn parseAtom(wasm: *Wasm, atom: *Atom, kind: Kind) !void {
1330 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(self);1329 const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
1331 const final_index: u32 = switch (kind) {1330 const final_index: u32 = switch (kind) {
1332 .function => |fn_data| result: {1331 .function => |fn_data| result: {
1333 const index = @intCast(u32, self.functions.count() + self.imported_functions_count);1332 const index = @intCast(u32, wasm.functions.count() + wasm.imported_functions_count);
1334 try self.functions.putNoClobber(1333 try wasm.functions.putNoClobber(
1335 self.base.allocator,1334 wasm.base.allocator,
1336 .{ .file = null, .index = index },1335 .{ .file = null, .index = index },
1337 .{ .type_index = fn_data.type_index },1336 .{ .type_index = fn_data.type_index },
1338 );1337 );
1339 symbol.tag = .function;1338 symbol.tag = .function;
1340 symbol.index = index;1339 symbol.index = index;
13411340
1342 if (self.code_section_index == null) {1341 if (wasm.code_section_index == null) {
1343 self.code_section_index = @intCast(u32, self.segments.items.len);1342 wasm.code_section_index = @intCast(u32, wasm.segments.items.len);
1344 try self.segments.append(self.base.allocator, .{1343 try wasm.segments.append(wasm.base.allocator, .{
1345 .alignment = atom.alignment,1344 .alignment = atom.alignment,
1346 .size = atom.size,1345 .size = atom.size,
1347 .offset = 0,1346 .offset = 0,
1348 });1347 });
1349 }1348 }
13501349
1351 break :result self.code_section_index.?;1350 break :result wasm.code_section_index.?;
1352 },1351 },
1353 .data => result: {1352 .data => result: {
1354 const segment_name = try std.mem.concat(self.base.allocator, u8, &.{1353 const segment_name = try std.mem.concat(wasm.base.allocator, u8, &.{
1355 kind.segmentName(),1354 kind.segmentName(),
1356 self.string_table.get(symbol.name),1355 wasm.string_table.get(symbol.name),
1357 });1356 });
1358 errdefer self.base.allocator.free(segment_name);1357 errdefer wasm.base.allocator.free(segment_name);
1359 const segment_info: types.Segment = .{1358 const segment_info: types.Segment = .{
1360 .name = segment_name,1359 .name = segment_name,
1361 .alignment = atom.alignment,1360 .alignment = atom.alignment,
...@@ -1367,59 +1366,59 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {...@@ -1367,59 +1366,59 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
1367 // we set the entire region of it to zeroes.1366 // we set the entire region of it to zeroes.
1368 // We do not have to do this when exporting the memory (the default) because the runtime1367 // We do not have to do this when exporting the memory (the default) because the runtime
1369 // will do it for us, and we do not emit the bss segment at all.1368 // will do it for us, and we do not emit the bss segment at all.
1370 if ((self.base.options.output_mode == .Obj or self.base.options.import_memory) and kind.data == .uninitialized) {1369 if ((wasm.base.options.output_mode == .Obj or wasm.base.options.import_memory) and kind.data == .uninitialized) {
1371 std.mem.set(u8, atom.code.items, 0);1370 std.mem.set(u8, atom.code.items, 0);
1372 }1371 }
13731372
1374 const should_merge = self.base.options.output_mode != .Obj;1373 const should_merge = wasm.base.options.output_mode != .Obj;
1375 const gop = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(should_merge));1374 const gop = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(should_merge));
1376 if (gop.found_existing) {1375 if (gop.found_existing) {
1377 const index = gop.value_ptr.*;1376 const index = gop.value_ptr.*;
1378 self.segments.items[index].size += atom.size;1377 wasm.segments.items[index].size += atom.size;
13791378
1380 symbol.index = @intCast(u32, self.segment_info.getIndex(index).?);1379 symbol.index = @intCast(u32, wasm.segment_info.getIndex(index).?);
1381 // segment info already exists, so free its memory1380 // segment info already exists, so free its memory
1382 self.base.allocator.free(segment_name);1381 wasm.base.allocator.free(segment_name);
1383 break :result index;1382 break :result index;
1384 } else {1383 } else {
1385 const index = @intCast(u32, self.segments.items.len);1384 const index = @intCast(u32, wasm.segments.items.len);
1386 try self.segments.append(self.base.allocator, .{1385 try wasm.segments.append(wasm.base.allocator, .{
1387 .alignment = atom.alignment,1386 .alignment = atom.alignment,
1388 .size = 0,1387 .size = 0,
1389 .offset = 0,1388 .offset = 0,
1390 });1389 });
1391 gop.value_ptr.* = index;1390 gop.value_ptr.* = index;
13921391
1393 const info_index = @intCast(u32, self.segment_info.count());1392 const info_index = @intCast(u32, wasm.segment_info.count());
1394 try self.segment_info.put(self.base.allocator, index, segment_info);1393 try wasm.segment_info.put(wasm.base.allocator, index, segment_info);
1395 symbol.index = info_index;1394 symbol.index = info_index;
1396 break :result index;1395 break :result index;
1397 }1396 }
1398 },1397 },
1399 };1398 };
14001399
1401 const segment: *Segment = &self.segments.items[final_index];1400 const segment: *Segment = &wasm.segments.items[final_index];
1402 segment.alignment = std.math.max(segment.alignment, atom.alignment);1401 segment.alignment = std.math.max(segment.alignment, atom.alignment);
14031402
1404 try self.appendAtomAtIndex(final_index, atom);1403 try wasm.appendAtomAtIndex(final_index, atom);
1405}1404}
14061405
1407/// From a given index, append the given `Atom` at the back of the linked list.1406/// From a given index, append the given `Atom` at the back of the linked list.
1408/// Simply inserts it into the map of atoms when it doesn't exist yet.1407/// Simply inserts it into the map of atoms when it doesn't exist yet.
1409pub fn appendAtomAtIndex(self: *Wasm, index: u32, atom: *Atom) !void {1408pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom: *Atom) !void {
1410 if (self.atoms.getPtr(index)) |last| {1409 if (wasm.atoms.getPtr(index)) |last| {
1411 last.*.next = atom;1410 last.*.next = atom;
1412 atom.prev = last.*;1411 atom.prev = last.*;
1413 last.* = atom;1412 last.* = atom;
1414 } else {1413 } else {
1415 try self.atoms.putNoClobber(self.base.allocator, index, atom);1414 try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom);
1416 }1415 }
1417}1416}
14181417
1419/// Allocates debug atoms into their respective debug sections1418/// Allocates debug atoms into their respective debug sections
1420/// to merge them with maybe-existing debug atoms from object files.1419/// to merge them with maybe-existing debug atoms from object files.
1421fn allocateDebugAtoms(self: *Wasm) !void {1420fn allocateDebugAtoms(wasm: *Wasm) !void {
1422 if (self.dwarf == null) return;1421 if (wasm.dwarf == null) return;
14231422
1424 const allocAtom = struct {1423 const allocAtom = struct {
1425 fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void {1424 fn f(bin: *Wasm, maybe_index: *?u32, atom: *Atom) !void {
...@@ -1435,24 +1434,24 @@ fn allocateDebugAtoms(self: *Wasm) !void {...@@ -1435,24 +1434,24 @@ fn allocateDebugAtoms(self: *Wasm) !void {
1435 }1434 }
1436 }.f;1435 }.f;
14371436
1438 try allocAtom(self, &self.debug_info_index, self.debug_info_atom.?);1437 try allocAtom(wasm, &wasm.debug_info_index, wasm.debug_info_atom.?);
1439 try allocAtom(self, &self.debug_line_index, self.debug_line_atom.?);1438 try allocAtom(wasm, &wasm.debug_line_index, wasm.debug_line_atom.?);
1440 try allocAtom(self, &self.debug_loc_index, self.debug_loc_atom.?);1439 try allocAtom(wasm, &wasm.debug_loc_index, wasm.debug_loc_atom.?);
1441 try allocAtom(self, &self.debug_str_index, self.debug_str_atom.?);1440 try allocAtom(wasm, &wasm.debug_str_index, wasm.debug_str_atom.?);
1442 try allocAtom(self, &self.debug_ranges_index, self.debug_ranges_atom.?);1441 try allocAtom(wasm, &wasm.debug_ranges_index, wasm.debug_ranges_atom.?);
1443 try allocAtom(self, &self.debug_abbrev_index, self.debug_abbrev_atom.?);1442 try allocAtom(wasm, &wasm.debug_abbrev_index, wasm.debug_abbrev_atom.?);
1444 try allocAtom(self, &self.debug_pubnames_index, self.debug_pubnames_atom.?);1443 try allocAtom(wasm, &wasm.debug_pubnames_index, wasm.debug_pubnames_atom.?);
1445 try allocAtom(self, &self.debug_pubtypes_index, self.debug_pubtypes_atom.?);1444 try allocAtom(wasm, &wasm.debug_pubtypes_index, wasm.debug_pubtypes_atom.?);
1446}1445}
14471446
1448fn allocateAtoms(self: *Wasm) !void {1447fn allocateAtoms(wasm: *Wasm) !void {
1449 // first sort the data segments1448 // first sort the data segments
1450 try sortDataSegments(self);1449 try sortDataSegments(wasm);
1451 try allocateDebugAtoms(self);1450 try allocateDebugAtoms(wasm);
14521451
1453 var it = self.atoms.iterator();1452 var it = wasm.atoms.iterator();
1454 while (it.next()) |entry| {1453 while (it.next()) |entry| {
1455 const segment = &self.segments.items[entry.key_ptr.*];1454 const segment = &wasm.segments.items[entry.key_ptr.*];
1456 var atom: *Atom = entry.value_ptr.*.getFirst();1455 var atom: *Atom = entry.value_ptr.*.getFirst();
1457 var offset: u32 = 0;1456 var offset: u32 = 0;
1458 while (true) {1457 while (true) {
...@@ -1460,26 +1459,26 @@ fn allocateAtoms(self: *Wasm) !void {...@@ -1460,26 +1459,26 @@ fn allocateAtoms(self: *Wasm) !void {
1460 atom.offset = offset;1459 atom.offset = offset;
1461 const symbol_loc = atom.symbolLoc();1460 const symbol_loc = atom.symbolLoc();
1462 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{1461 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
1463 symbol_loc.getName(self),1462 symbol_loc.getName(wasm),
1464 offset,1463 offset,
1465 offset + atom.size,1464 offset + atom.size,
1466 atom.size,1465 atom.size,
1467 });1466 });
1468 offset += atom.size;1467 offset += atom.size;
1469 try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom); // Update atom pointers1468 try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom); // Update atom pointers
1470 atom = atom.next orelse break;1469 atom = atom.next orelse break;
1471 }1470 }
1472 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);1471 segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment);
1473 }1472 }
1474}1473}
14751474
1476fn sortDataSegments(self: *Wasm) !void {1475fn sortDataSegments(wasm: *Wasm) !void {
1477 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};1476 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
1478 try new_mapping.ensureUnusedCapacity(self.base.allocator, self.data_segments.count());1477 try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count());
1479 errdefer new_mapping.deinit(self.base.allocator);1478 errdefer new_mapping.deinit(wasm.base.allocator);
14801479
1481 const keys = try self.base.allocator.dupe([]const u8, self.data_segments.keys());1480 const keys = try wasm.base.allocator.dupe([]const u8, wasm.data_segments.keys());
1482 defer self.base.allocator.free(keys);1481 defer wasm.base.allocator.free(keys);
14831482
1484 const SortContext = struct {1483 const SortContext = struct {
1485 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {1484 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
...@@ -1496,63 +1495,63 @@ fn sortDataSegments(self: *Wasm) !void {...@@ -1496,63 +1495,63 @@ fn sortDataSegments(self: *Wasm) !void {
14961495
1497 std.sort.sort([]const u8, keys, {}, SortContext.sort);1496 std.sort.sort([]const u8, keys, {}, SortContext.sort);
1498 for (keys) |key| {1497 for (keys) |key| {
1499 const segment_index = self.data_segments.get(key).?;1498 const segment_index = wasm.data_segments.get(key).?;
1500 new_mapping.putAssumeCapacity(key, segment_index);1499 new_mapping.putAssumeCapacity(key, segment_index);
1501 }1500 }
1502 self.data_segments.deinit(self.base.allocator);1501 wasm.data_segments.deinit(wasm.base.allocator);
1503 self.data_segments = new_mapping;1502 wasm.data_segments = new_mapping;
1504}1503}
15051504
1506fn setupImports(self: *Wasm) !void {1505fn setupImports(wasm: *Wasm) !void {
1507 log.debug("Merging imports", .{});1506 log.debug("Merging imports", .{});
1508 var discarded_it = self.discarded.keyIterator();1507 var discarded_it = wasm.discarded.keyIterator();
1509 while (discarded_it.next()) |discarded| {1508 while (discarded_it.next()) |discarded| {
1510 if (discarded.file == null) {1509 if (discarded.file == null) {
1511 // remove an import if it was resolved1510 // remove an import if it was resolved
1512 if (self.imports.remove(discarded.*)) {1511 if (wasm.imports.remove(discarded.*)) {
1513 log.debug("Removed symbol '{s}' as an import", .{1512 log.debug("Removed symbol '{s}' as an import", .{
1514 discarded.getName(self),1513 discarded.getName(wasm),
1515 });1514 });
1516 }1515 }
1517 }1516 }
1518 }1517 }
15191518
1520 for (self.resolved_symbols.keys()) |symbol_loc| {1519 for (wasm.resolved_symbols.keys()) |symbol_loc| {
1521 if (symbol_loc.file == null) {1520 if (symbol_loc.file == null) {
1522 // imports generated by Zig code are already in the `import` section1521 // imports generated by Zig code are already in the `import` section
1523 continue;1522 continue;
1524 }1523 }
15251524
1526 const symbol = symbol_loc.getSymbol(self);1525 const symbol = symbol_loc.getSymbol(wasm);
1527 if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {1526 if (std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table")) {
1528 continue;1527 continue;
1529 }1528 }
1530 if (!symbol.requiresImport()) {1529 if (!symbol.requiresImport()) {
1531 continue;1530 continue;
1532 }1531 }
15331532
1534 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(self)});1533 log.debug("Symbol '{s}' will be imported from the host", .{symbol_loc.getName(wasm)});
1535 const object = self.objects.items[symbol_loc.file.?];1534 const object = wasm.objects.items[symbol_loc.file.?];
1536 const import = object.findImport(symbol.tag.externalType(), symbol.index);1535 const import = object.findImport(symbol.tag.externalType(), symbol.index);
15371536
1538 // We copy the import to a new import to ensure the names contain references1537 // We copy the import to a new import to ensure the names contain references
1539 // to the internal string table, rather than of the object file.1538 // to the internal string table, rather than of the object file.
1540 var new_imp: types.Import = .{1539 var new_imp: types.Import = .{
1541 .module_name = try self.string_table.put(self.base.allocator, object.string_table.get(import.module_name)),1540 .module_name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.module_name)),
1542 .name = try self.string_table.put(self.base.allocator, object.string_table.get(import.name)),1541 .name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.name)),
1543 .kind = import.kind,1542 .kind = import.kind,
1544 };1543 };
1545 // TODO: De-duplicate imports when they contain the same names and type1544 // TODO: De-duplicate imports when they contain the same names and type
1546 try self.imports.putNoClobber(self.base.allocator, symbol_loc, new_imp);1545 try wasm.imports.putNoClobber(wasm.base.allocator, symbol_loc, new_imp);
1547 }1546 }
15481547
1549 // Assign all indexes of the imports to their representing symbols1548 // Assign all indexes of the imports to their representing symbols
1550 var function_index: u32 = 0;1549 var function_index: u32 = 0;
1551 var global_index: u32 = 0;1550 var global_index: u32 = 0;
1552 var table_index: u32 = 0;1551 var table_index: u32 = 0;
1553 var it = self.imports.iterator();1552 var it = wasm.imports.iterator();
1554 while (it.next()) |entry| {1553 while (it.next()) |entry| {
1555 const symbol = entry.key_ptr.*.getSymbol(self);1554 const symbol = entry.key_ptr.*.getSymbol(wasm);
1556 const import: types.Import = entry.value_ptr.*;1555 const import: types.Import = entry.value_ptr.*;
1557 switch (import.kind) {1556 switch (import.kind) {
1558 .function => {1557 .function => {
...@@ -1570,9 +1569,9 @@ fn setupImports(self: *Wasm) !void {...@@ -1570,9 +1569,9 @@ fn setupImports(self: *Wasm) !void {
1570 else => unreachable,1569 else => unreachable,
1571 }1570 }
1572 }1571 }
1573 self.imported_functions_count = function_index;1572 wasm.imported_functions_count = function_index;
1574 self.imported_globals_count = global_index;1573 wasm.imported_globals_count = global_index;
1575 self.imported_tables_count = table_index;1574 wasm.imported_tables_count = table_index;
15761575
1577 log.debug("Merged ({d}) functions, ({d}) globals, and ({d}) tables into import section", .{1576 log.debug("Merged ({d}) functions, ({d}) globals, and ({d}) tables into import section", .{
1578 function_index,1577 function_index,
...@@ -1583,26 +1582,26 @@ fn setupImports(self: *Wasm) !void {...@@ -1583,26 +1582,26 @@ fn setupImports(self: *Wasm) !void {
15831582
1584/// Takes the global, function and table section from each linked object file1583/// Takes the global, function and table section from each linked object file
1585/// and merges it into a single section for each.1584/// and merges it into a single section for each.
1586fn mergeSections(self: *Wasm) !void {1585fn mergeSections(wasm: *Wasm) !void {
1587 // append the indirect function table if initialized1586 // append the indirect function table if initialized
1588 if (self.string_table.getOffset("__indirect_function_table")) |offset| {1587 if (wasm.string_table.getOffset("__indirect_function_table")) |offset| {
1589 const sym_loc = self.globals.get(offset).?;1588 const sym_loc = wasm.globals.get(offset).?;
1590 const table: wasm.Table = .{1589 const table: std.wasm.Table = .{
1591 .limits = .{ .min = @intCast(u32, self.function_table.count()), .max = null },1590 .limits = .{ .min = @intCast(u32, wasm.function_table.count()), .max = null },
1592 .reftype = .funcref,1591 .reftype = .funcref,
1593 };1592 };
1594 sym_loc.getSymbol(self).index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;1593 sym_loc.getSymbol(wasm).index = @intCast(u32, wasm.tables.items.len) + wasm.imported_tables_count;
1595 try self.tables.append(self.base.allocator, table);1594 try wasm.tables.append(wasm.base.allocator, table);
1596 }1595 }
15971596
1598 for (self.resolved_symbols.keys()) |sym_loc| {1597 for (wasm.resolved_symbols.keys()) |sym_loc| {
1599 if (sym_loc.file == null) {1598 if (sym_loc.file == null) {
1600 // Zig code-generated symbols are already within the sections and do not1599 // Zig code-generated symbols are already within the sections and do not
1601 // require to be merged1600 // require to be merged
1602 continue;1601 continue;
1603 }1602 }
16041603
1605 const object = self.objects.items[sym_loc.file.?];1604 const object = wasm.objects.items[sym_loc.file.?];
1606 const symbol = &object.symtable[sym_loc.index];1605 const symbol = &object.symtable[sym_loc.index];
1607 if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) {1606 if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) {
1608 // Skip undefined symbols as they go in the `import` section1607 // Skip undefined symbols as they go in the `import` section
...@@ -1615,51 +1614,51 @@ fn mergeSections(self: *Wasm) !void {...@@ -1615,51 +1614,51 @@ fn mergeSections(self: *Wasm) !void {
1615 switch (symbol.tag) {1614 switch (symbol.tag) {
1616 .function => {1615 .function => {
1617 const original_func = object.functions[index];1616 const original_func = object.functions[index];
1618 const gop = try self.functions.getOrPut(1617 const gop = try wasm.functions.getOrPut(
1619 self.base.allocator,1618 wasm.base.allocator,
1620 .{ .file = sym_loc.file, .index = symbol.index },1619 .{ .file = sym_loc.file, .index = symbol.index },
1621 );1620 );
1622 if (!gop.found_existing) {1621 if (!gop.found_existing) {
1623 gop.value_ptr.* = original_func;1622 gop.value_ptr.* = original_func;
1624 }1623 }
1625 symbol.index = @intCast(u32, gop.index) + self.imported_functions_count;1624 symbol.index = @intCast(u32, gop.index) + wasm.imported_functions_count;
1626 },1625 },
1627 .global => {1626 .global => {
1628 const original_global = object.globals[index];1627 const original_global = object.globals[index];
1629 symbol.index = @intCast(u32, self.wasm_globals.items.len) + self.imported_globals_count;1628 symbol.index = @intCast(u32, wasm.wasm_globals.items.len) + wasm.imported_globals_count;
1630 try self.wasm_globals.append(self.base.allocator, original_global);1629 try wasm.wasm_globals.append(wasm.base.allocator, original_global);
1631 },1630 },
1632 .table => {1631 .table => {
1633 const original_table = object.tables[index];1632 const original_table = object.tables[index];
1634 symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;1633 symbol.index = @intCast(u32, wasm.tables.items.len) + wasm.imported_tables_count;
1635 try self.tables.append(self.base.allocator, original_table);1634 try wasm.tables.append(wasm.base.allocator, original_table);
1636 },1635 },
1637 else => unreachable,1636 else => unreachable,
1638 }1637 }
1639 }1638 }
16401639
1641 log.debug("Merged ({d}) functions", .{self.functions.count()});1640 log.debug("Merged ({d}) functions", .{wasm.functions.count()});
1642 log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len});1641 log.debug("Merged ({d}) globals", .{wasm.wasm_globals.items.len});
1643 log.debug("Merged ({d}) tables", .{self.tables.items.len});1642 log.debug("Merged ({d}) tables", .{wasm.tables.items.len});
1644}1643}
16451644
1646/// Merges function types of all object files into the final1645/// Merges function types of all object files into the final
1647/// 'types' section, while assigning the type index to the representing1646/// 'types' section, while assigning the type index to the representing
1648/// section (import, export, function).1647/// section (import, export, function).
1649fn mergeTypes(self: *Wasm) !void {1648fn mergeTypes(wasm: *Wasm) !void {
1650 // A map to track which functions have already had their1649 // A map to track which functions have already had their
1651 // type inserted. If we do this for the same function multiple times,1650 // type inserted. If we do this for the same function multiple times,
1652 // it will be overwritten with the incorrect type.1651 // it will be overwritten with the incorrect type.
1653 var dirty = std.AutoHashMap(u32, void).init(self.base.allocator);1652 var dirty = std.AutoHashMap(u32, void).init(wasm.base.allocator);
1654 try dirty.ensureUnusedCapacity(@intCast(u32, self.functions.count()));1653 try dirty.ensureUnusedCapacity(@intCast(u32, wasm.functions.count()));
1655 defer dirty.deinit();1654 defer dirty.deinit();
16561655
1657 for (self.resolved_symbols.keys()) |sym_loc| {1656 for (wasm.resolved_symbols.keys()) |sym_loc| {
1658 if (sym_loc.file == null) {1657 if (sym_loc.file == null) {
1659 // zig code-generated symbols are already present in final type section1658 // zig code-generated symbols are already present in final type section
1660 continue;1659 continue;
1661 }1660 }
1662 const object = self.objects.items[sym_loc.file.?];1661 const object = wasm.objects.items[sym_loc.file.?];
1663 const symbol = object.symtable[sym_loc.index];1662 const symbol = object.symtable[sym_loc.index];
1664 if (symbol.tag != .function) {1663 if (symbol.tag != .function) {
1665 // Only functions have types1664 // Only functions have types
...@@ -1667,32 +1666,32 @@ fn mergeTypes(self: *Wasm) !void {...@@ -1667,32 +1666,32 @@ fn mergeTypes(self: *Wasm) !void {
1667 }1666 }
16681667
1669 if (symbol.isUndefined()) {1668 if (symbol.isUndefined()) {
1670 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(self)});1669 log.debug("Adding type from extern function '{s}'", .{sym_loc.getName(wasm)});
1671 const import: *types.Import = self.imports.getPtr(sym_loc).?;1670 const import: *types.Import = wasm.imports.getPtr(sym_loc).?;
1672 const original_type = object.func_types[import.kind.function];1671 const original_type = object.func_types[import.kind.function];
1673 import.kind.function = try self.putOrGetFuncType(original_type);1672 import.kind.function = try wasm.putOrGetFuncType(original_type);
1674 } else if (!dirty.contains(symbol.index)) {1673 } else if (!dirty.contains(symbol.index)) {
1675 log.debug("Adding type from function '{s}'", .{sym_loc.getName(self)});1674 log.debug("Adding type from function '{s}'", .{sym_loc.getName(wasm)});
1676 const func = &self.functions.values()[symbol.index - self.imported_functions_count];1675 const func = &wasm.functions.values()[symbol.index - wasm.imported_functions_count];
1677 func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]);1676 func.type_index = try wasm.putOrGetFuncType(object.func_types[func.type_index]);
1678 dirty.putAssumeCapacityNoClobber(symbol.index, {});1677 dirty.putAssumeCapacityNoClobber(symbol.index, {});
1679 }1678 }
1680 }1679 }
1681 log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len});1680 log.debug("Completed merging and deduplicating types. Total count: ({d})", .{wasm.func_types.items.len});
1682}1681}
16831682
1684fn setupExports(self: *Wasm) !void {1683fn setupExports(wasm: *Wasm) !void {
1685 if (self.base.options.output_mode == .Obj) return;1684 if (wasm.base.options.output_mode == .Obj) return;
1686 log.debug("Building exports from symbols", .{});1685 log.debug("Building exports from symbols", .{});
16871686
1688 for (self.resolved_symbols.keys()) |sym_loc| {1687 for (wasm.resolved_symbols.keys()) |sym_loc| {
1689 const symbol = sym_loc.getSymbol(self);1688 const symbol = sym_loc.getSymbol(wasm);
1690 if (!symbol.isExported()) continue;1689 if (!symbol.isExported()) continue;
16911690
1692 const sym_name = sym_loc.getName(self);1691 const sym_name = sym_loc.getName(wasm);
1693 const export_name = if (self.export_names.get(sym_loc)) |name| name else blk: {1692 const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: {
1694 if (sym_loc.file == null) break :blk symbol.name;1693 if (sym_loc.file == null) break :blk symbol.name;
1695 break :blk try self.string_table.put(self.base.allocator, sym_name);1694 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
1696 };1695 };
1697 const exp: types.Export = .{1696 const exp: types.Export = .{
1698 .name = export_name,1697 .name = export_name,
...@@ -1701,21 +1700,21 @@ fn setupExports(self: *Wasm) !void {...@@ -1701,21 +1700,21 @@ fn setupExports(self: *Wasm) !void {
1701 };1700 };
1702 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{1701 log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
1703 sym_name,1702 sym_name,
1704 self.string_table.get(exp.name),1703 wasm.string_table.get(exp.name),
1705 exp.index,1704 exp.index,
1706 });1705 });
1707 try self.exports.append(self.base.allocator, exp);1706 try wasm.exports.append(wasm.base.allocator, exp);
1708 }1707 }
17091708
1710 log.debug("Completed building exports. Total count: ({d})", .{self.exports.items.len});1709 log.debug("Completed building exports. Total count: ({d})", .{wasm.exports.items.len});
1711}1710}
17121711
1713fn setupStart(self: *Wasm) !void {1712fn setupStart(wasm: *Wasm) !void {
1714 const entry_name = self.base.options.entry orelse "_start";1713 const entry_name = wasm.base.options.entry orelse "_start";
17151714
1716 const symbol_name_offset = self.string_table.getOffset(entry_name) orelse {1715 const symbol_name_offset = wasm.string_table.getOffset(entry_name) orelse {
1717 if (self.base.options.output_mode == .Exe) {1716 if (wasm.base.options.output_mode == .Exe) {
1718 if (self.base.options.wasi_exec_model == .reactor) return; // Not required for reactors1717 if (wasm.base.options.wasi_exec_model == .reactor) return; // Not required for reactors
1719 } else {1718 } else {
1720 return; // No entry point needed for non-executable wasm files1719 return; // No entry point needed for non-executable wasm files
1721 }1720 }
...@@ -1723,45 +1722,45 @@ fn setupStart(self: *Wasm) !void {...@@ -1723,45 +1722,45 @@ fn setupStart(self: *Wasm) !void {
1723 return error.MissingSymbol;1722 return error.MissingSymbol;
1724 };1723 };
17251724
1726 const symbol_loc = self.globals.get(symbol_name_offset).?;1725 const symbol_loc = wasm.globals.get(symbol_name_offset).?;
1727 const symbol = symbol_loc.getSymbol(self);1726 const symbol = symbol_loc.getSymbol(wasm);
1728 if (symbol.tag != .function) {1727 if (symbol.tag != .function) {
1729 log.err("Entry symbol '{s}' is not a function", .{entry_name});1728 log.err("Entry symbol '{s}' is not a function", .{entry_name});
1730 return error.InvalidEntryKind;1729 return error.InvalidEntryKind;
1731 }1730 }
17321731
1733 // Ensure the symbol is exported so host environment can access it1732 // Ensure the symbol is exported so host environment can access it
1734 if (self.base.options.output_mode != .Obj) {1733 if (wasm.base.options.output_mode != .Obj) {
1735 symbol.setFlag(.WASM_SYM_EXPORTED);1734 symbol.setFlag(.WASM_SYM_EXPORTED);
1736 }1735 }
1737}1736}
17381737
1739/// Sets up the memory section of the wasm module, as well as the stack.1738/// Sets up the memory section of the wasm module, as well as the stack.
1740fn setupMemory(self: *Wasm) !void {1739fn setupMemory(wasm: *Wasm) !void {
1741 log.debug("Setting up memory layout", .{});1740 log.debug("Setting up memory layout", .{});
1742 const page_size = 64 * 1024;1741 const page_size = 64 * 1024;
1743 const stack_size = self.base.options.stack_size_override orelse page_size * 1;1742 const stack_size = wasm.base.options.stack_size_override orelse page_size * 1;
1744 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention1743 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention
1745 // Always place the stack at the start by default1744 // Always place the stack at the start by default
1746 // unless the user specified the global-base flag1745 // unless the user specified the global-base flag
1747 var place_stack_first = true;1746 var place_stack_first = true;
1748 var memory_ptr: u64 = if (self.base.options.global_base) |base| blk: {1747 var memory_ptr: u64 = if (wasm.base.options.global_base) |base| blk: {
1749 place_stack_first = false;1748 place_stack_first = false;
1750 break :blk base;1749 break :blk base;
1751 } else 0;1750 } else 0;
17521751
1753 const is_obj = self.base.options.output_mode == .Obj;1752 const is_obj = wasm.base.options.output_mode == .Obj;
17541753
1755 if (place_stack_first and !is_obj) {1754 if (place_stack_first and !is_obj) {
1756 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);1755 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);
1757 memory_ptr += stack_size;1756 memory_ptr += stack_size;
1758 // We always put the stack pointer global at index 01757 // We always put the stack pointer global at index 0
1759 self.wasm_globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));1758 wasm.wasm_globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));
1760 }1759 }
17611760
1762 var offset: u32 = @intCast(u32, memory_ptr);1761 var offset: u32 = @intCast(u32, memory_ptr);
1763 for (self.data_segments.values()) |segment_index| {1762 for (wasm.data_segments.values()) |segment_index| {
1764 const segment = &self.segments.items[segment_index];1763 const segment = &wasm.segments.items[segment_index];
1765 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment);1764 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, segment.alignment);
1766 memory_ptr += segment.size;1765 memory_ptr += segment.size;
1767 segment.offset = offset;1766 segment.offset = offset;
...@@ -1771,14 +1770,14 @@ fn setupMemory(self: *Wasm) !void {...@@ -1771,14 +1770,14 @@ fn setupMemory(self: *Wasm) !void {
1771 if (!place_stack_first and !is_obj) {1770 if (!place_stack_first and !is_obj) {
1772 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);1771 memory_ptr = std.mem.alignForwardGeneric(u64, memory_ptr, stack_alignment);
1773 memory_ptr += stack_size;1772 memory_ptr += stack_size;
1774 self.wasm_globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));1773 wasm.wasm_globals.items[0].init.i32_const = @bitCast(i32, @intCast(u32, memory_ptr));
1775 }1774 }
17761775
1777 // Setup the max amount of pages1776 // Setup the max amount of pages
1778 // For now we only support wasm32 by setting the maximum allowed memory size 2^32-11777 // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1
1779 const max_memory_allowed: u64 = (1 << 32) - 1;1778 const max_memory_allowed: u64 = (1 << 32) - 1;
17801779
1781 if (self.base.options.initial_memory) |initial_memory| {1780 if (wasm.base.options.initial_memory) |initial_memory| {
1782 if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) {1781 if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) {
1783 log.err("Initial memory must be {d}-byte aligned", .{page_size});1782 log.err("Initial memory must be {d}-byte aligned", .{page_size});
1784 return error.MissAlignment;1783 return error.MissAlignment;
...@@ -1796,10 +1795,10 @@ fn setupMemory(self: *Wasm) !void {...@@ -1796,10 +1795,10 @@ fn setupMemory(self: *Wasm) !void {
17961795
1797 // In case we do not import memory, but define it ourselves,1796 // In case we do not import memory, but define it ourselves,
1798 // set the minimum amount of pages on the memory section.1797 // set the minimum amount of pages on the memory section.
1799 self.memories.limits.min = @intCast(u32, std.mem.alignForwardGeneric(u64, memory_ptr, page_size) / page_size);1798 wasm.memories.limits.min = @intCast(u32, std.mem.alignForwardGeneric(u64, memory_ptr, page_size) / page_size);
1800 log.debug("Total memory pages: {d}", .{self.memories.limits.min});1799 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
18011800
1802 if (self.base.options.max_memory) |max_memory| {1801 if (wasm.base.options.max_memory) |max_memory| {
1803 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {1802 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {
1804 log.err("Maximum memory must be {d}-byte aligned", .{page_size});1803 log.err("Maximum memory must be {d}-byte aligned", .{page_size});
1805 return error.MissAlignment;1804 return error.MissAlignment;
...@@ -1812,83 +1811,83 @@ fn setupMemory(self: *Wasm) !void {...@@ -1812,83 +1811,83 @@ fn setupMemory(self: *Wasm) !void {
1812 log.err("Maximum memory exceeds maxmium amount {d}", .{max_memory_allowed});1811 log.err("Maximum memory exceeds maxmium amount {d}", .{max_memory_allowed});
1813 return error.MemoryTooBig;1812 return error.MemoryTooBig;
1814 }1813 }
1815 self.memories.limits.max = @intCast(u32, max_memory / page_size);1814 wasm.memories.limits.max = @intCast(u32, max_memory / page_size);
1816 log.debug("Maximum memory pages: {?d}", .{self.memories.limits.max});1815 log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});
1817 }1816 }
1818}1817}
18191818
1820/// From a given object's index and the index of the segment, returns the corresponding1819/// From a given object's index and the index of the segment, returns the corresponding
1821/// index of the segment within the final data section. When the segment does not yet1820/// index of the segment within the final data section. When the segment does not yet
1822/// exist, a new one will be initialized and appended. The new index will be returned in that case.1821/// exist, a new one will be initialized and appended. The new index will be returned in that case.
1823pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !?u32 {1822pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32) !?u32 {
1824 const object: Object = self.objects.items[object_index];1823 const object: Object = wasm.objects.items[object_index];
1825 const relocatable_data = object.relocatable_data[relocatable_index];1824 const relocatable_data = object.relocatable_data[relocatable_index];
1826 const index = @intCast(u32, self.segments.items.len);1825 const index = @intCast(u32, wasm.segments.items.len);
18271826
1828 switch (relocatable_data.type) {1827 switch (relocatable_data.type) {
1829 .data => {1828 .data => {
1830 const segment_info = object.segment_info[relocatable_data.index];1829 const segment_info = object.segment_info[relocatable_data.index];
1831 const merge_segment = self.base.options.output_mode != .Obj;1830 const merge_segment = wasm.base.options.output_mode != .Obj;
1832 const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(merge_segment));1831 const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
1833 if (!result.found_existing) {1832 if (!result.found_existing) {
1834 result.value_ptr.* = index;1833 result.value_ptr.* = index;
1835 try self.appendDummySegment();1834 try wasm.appendDummySegment();
1836 return index;1835 return index;
1837 } else return result.value_ptr.*;1836 } else return result.value_ptr.*;
1838 },1837 },
1839 .code => return self.code_section_index orelse blk: {1838 .code => return wasm.code_section_index orelse blk: {
1840 self.code_section_index = index;1839 wasm.code_section_index = index;
1841 try self.appendDummySegment();1840 try wasm.appendDummySegment();
1842 break :blk index;1841 break :blk index;
1843 },1842 },
1844 .debug => {1843 .debug => {
1845 const debug_name = object.getDebugName(relocatable_data);1844 const debug_name = object.getDebugName(relocatable_data);
1846 if (mem.eql(u8, debug_name, ".debug_info")) {1845 if (mem.eql(u8, debug_name, ".debug_info")) {
1847 return self.debug_info_index orelse blk: {1846 return wasm.debug_info_index orelse blk: {
1848 self.debug_info_index = index;1847 wasm.debug_info_index = index;
1849 try self.appendDummySegment();1848 try wasm.appendDummySegment();
1850 break :blk index;1849 break :blk index;
1851 };1850 };
1852 } else if (mem.eql(u8, debug_name, ".debug_line")) {1851 } else if (mem.eql(u8, debug_name, ".debug_line")) {
1853 return self.debug_line_index orelse blk: {1852 return wasm.debug_line_index orelse blk: {
1854 self.debug_line_index = index;1853 wasm.debug_line_index = index;
1855 try self.appendDummySegment();1854 try wasm.appendDummySegment();
1856 break :blk index;1855 break :blk index;
1857 };1856 };
1858 } else if (mem.eql(u8, debug_name, ".debug_loc")) {1857 } else if (mem.eql(u8, debug_name, ".debug_loc")) {
1859 return self.debug_loc_index orelse blk: {1858 return wasm.debug_loc_index orelse blk: {
1860 self.debug_loc_index = index;1859 wasm.debug_loc_index = index;
1861 try self.appendDummySegment();1860 try wasm.appendDummySegment();
1862 break :blk index;1861 break :blk index;
1863 };1862 };
1864 } else if (mem.eql(u8, debug_name, ".debug_ranges")) {1863 } else if (mem.eql(u8, debug_name, ".debug_ranges")) {
1865 return self.debug_line_index orelse blk: {1864 return wasm.debug_line_index orelse blk: {
1866 self.debug_ranges_index = index;1865 wasm.debug_ranges_index = index;
1867 try self.appendDummySegment();1866 try wasm.appendDummySegment();
1868 break :blk index;1867 break :blk index;
1869 };1868 };
1870 } else if (mem.eql(u8, debug_name, ".debug_pubnames")) {1869 } else if (mem.eql(u8, debug_name, ".debug_pubnames")) {
1871 return self.debug_pubnames_index orelse blk: {1870 return wasm.debug_pubnames_index orelse blk: {
1872 self.debug_pubnames_index = index;1871 wasm.debug_pubnames_index = index;
1873 try self.appendDummySegment();1872 try wasm.appendDummySegment();
1874 break :blk index;1873 break :blk index;
1875 };1874 };
1876 } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) {1875 } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) {
1877 return self.debug_pubtypes_index orelse blk: {1876 return wasm.debug_pubtypes_index orelse blk: {
1878 self.debug_pubtypes_index = index;1877 wasm.debug_pubtypes_index = index;
1879 try self.appendDummySegment();1878 try wasm.appendDummySegment();
1880 break :blk index;1879 break :blk index;
1881 };1880 };
1882 } else if (mem.eql(u8, debug_name, ".debug_abbrev")) {1881 } else if (mem.eql(u8, debug_name, ".debug_abbrev")) {
1883 return self.debug_abbrev_index orelse blk: {1882 return wasm.debug_abbrev_index orelse blk: {
1884 self.debug_abbrev_index = index;1883 wasm.debug_abbrev_index = index;
1885 try self.appendDummySegment();1884 try wasm.appendDummySegment();
1886 break :blk index;1885 break :blk index;
1887 };1886 };
1888 } else if (mem.eql(u8, debug_name, ".debug_str")) {1887 } else if (mem.eql(u8, debug_name, ".debug_str")) {
1889 return self.debug_str_index orelse blk: {1888 return wasm.debug_str_index orelse blk: {
1890 self.debug_str_index = index;1889 wasm.debug_str_index = index;
1891 try self.appendDummySegment();1890 try wasm.appendDummySegment();
1892 break :blk index;1891 break :blk index;
1893 };1892 };
1894 } else {1893 } else {
...@@ -1901,8 +1900,8 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32...@@ -1901,8 +1900,8 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32
1901}1900}
19021901
1903/// Appends a new segment with default field values1902/// Appends a new segment with default field values
1904fn appendDummySegment(self: *Wasm) !void {1903fn appendDummySegment(wasm: *Wasm) !void {
1905 try self.segments.append(self.base.allocator, .{1904 try wasm.segments.append(wasm.base.allocator, .{
1906 .alignment = 1,1905 .alignment = 1,
1907 .size = 0,1906 .size = 0,
1908 .offset = 0,1907 .offset = 0,
...@@ -1912,8 +1911,8 @@ fn appendDummySegment(self: *Wasm) !void {...@@ -1912,8 +1911,8 @@ fn appendDummySegment(self: *Wasm) !void {
1912/// Returns the symbol index of the error name table.1911/// Returns the symbol index of the error name table.
1913///1912///
1914/// When the symbol does not yet exist, it will create a new one instead.1913/// When the symbol does not yet exist, it will create a new one instead.
1915pub fn getErrorTableSymbol(self: *Wasm) !u32 {1914pub fn getErrorTableSymbol(wasm: *Wasm) !u32 {
1916 if (self.error_table_symbol) |symbol| {1915 if (wasm.error_table_symbol) |symbol| {
1917 return symbol;1916 return symbol;
1918 }1917 }
19191918
...@@ -1922,14 +1921,14 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {...@@ -1922,14 +1921,14 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {
1922 // during `flush` when we know all possible error names.1921 // during `flush` when we know all possible error names.
19231922
1924 // As sym_index '0' is reserved, we use it for our stack pointer symbol1923 // As sym_index '0' is reserved, we use it for our stack pointer symbol
1925 const symbol_index = self.symbols_free_list.popOrNull() orelse blk: {1924 const symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
1926 const index = @intCast(u32, self.symbols.items.len);1925 const index = @intCast(u32, wasm.symbols.items.len);
1927 _ = try self.symbols.addOne(self.base.allocator);1926 _ = try wasm.symbols.addOne(wasm.base.allocator);
1928 break :blk index;1927 break :blk index;
1929 };1928 };
19301929
1931 const sym_name = try self.string_table.put(self.base.allocator, "__zig_err_name_table");1930 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table");
1932 const symbol = &self.symbols.items[symbol_index];1931 const symbol = &wasm.symbols.items[symbol_index];
1933 symbol.* = .{1932 symbol.* = .{
1934 .name = sym_name,1933 .name = sym_name,
1935 .tag = .data,1934 .tag = .data,
...@@ -1940,17 +1939,17 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {...@@ -1940,17 +1939,17 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {
19401939
1941 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);1940 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
19421941
1943 const atom = try self.base.allocator.create(Atom);1942 const atom = try wasm.base.allocator.create(Atom);
1944 atom.* = Atom.empty;1943 atom.* = Atom.empty;
1945 atom.sym_index = symbol_index;1944 atom.sym_index = symbol_index;
1946 atom.alignment = slice_ty.abiAlignment(self.base.options.target);1945 atom.alignment = slice_ty.abiAlignment(wasm.base.options.target);
1947 try self.managed_atoms.append(self.base.allocator, atom);1946 try wasm.managed_atoms.append(wasm.base.allocator, atom);
1948 const loc = atom.symbolLoc();1947 const loc = atom.symbolLoc();
1949 try self.resolved_symbols.put(self.base.allocator, loc, {});1948 try wasm.resolved_symbols.put(wasm.base.allocator, loc, {});
1950 try self.symbol_atom.put(self.base.allocator, loc, atom);1949 try wasm.symbol_atom.put(wasm.base.allocator, loc, atom);
19511950
1952 log.debug("Error name table was created with symbol index: ({d})", .{symbol_index});1951 log.debug("Error name table was created with symbol index: ({d})", .{symbol_index});
1953 self.error_table_symbol = symbol_index;1952 wasm.error_table_symbol = symbol_index;
1954 return symbol_index;1953 return symbol_index;
1955}1954}
19561955
...@@ -1958,24 +1957,24 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {...@@ -1958,24 +1957,24 @@ pub fn getErrorTableSymbol(self: *Wasm) !u32 {
1958///1957///
1959/// This creates a table that consists of pointers and length to each error name.1958/// This creates a table that consists of pointers and length to each error name.
1960/// The table is what is being pointed to within the runtime bodies that are generated.1959/// The table is what is being pointed to within the runtime bodies that are generated.
1961fn populateErrorNameTable(self: *Wasm) !void {1960fn populateErrorNameTable(wasm: *Wasm) !void {
1962 const symbol_index = self.error_table_symbol orelse return;1961 const symbol_index = wasm.error_table_symbol orelse return;
1963 const atom: *Atom = self.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;1962 const atom: *Atom = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?;
1964 // Rather than creating a symbol for each individual error name,1963 // Rather than creating a symbol for each individual error name,
1965 // we create a symbol for the entire region of error names. We then calculate1964 // we create a symbol for the entire region of error names. We then calculate
1966 // the pointers into the list using addends which are appended to the relocation.1965 // the pointers into the list using addends which are appended to the relocation.
1967 const names_atom = try self.base.allocator.create(Atom);1966 const names_atom = try wasm.base.allocator.create(Atom);
1968 names_atom.* = Atom.empty;1967 names_atom.* = Atom.empty;
1969 try self.managed_atoms.append(self.base.allocator, names_atom);1968 try wasm.managed_atoms.append(wasm.base.allocator, names_atom);
1970 const names_symbol_index = self.symbols_free_list.popOrNull() orelse blk: {1969 const names_symbol_index = wasm.symbols_free_list.popOrNull() orelse blk: {
1971 const index = @intCast(u32, self.symbols.items.len);1970 const index = @intCast(u32, wasm.symbols.items.len);
1972 _ = try self.symbols.addOne(self.base.allocator);1971 _ = try wasm.symbols.addOne(wasm.base.allocator);
1973 break :blk index;1972 break :blk index;
1974 };1973 };
1975 names_atom.sym_index = names_symbol_index;1974 names_atom.sym_index = names_symbol_index;
1976 names_atom.alignment = 1;1975 names_atom.alignment = 1;
1977 const sym_name = try self.string_table.put(self.base.allocator, "__zig_err_names");1976 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
1978 const names_symbol = &self.symbols.items[names_symbol_index];1977 const names_symbol = &wasm.symbols.items[names_symbol_index];
1979 names_symbol.* = .{1978 names_symbol.* = .{
1980 .name = sym_name,1979 .name = sym_name,
1981 .tag = .data,1980 .tag = .data,
...@@ -1988,27 +1987,27 @@ fn populateErrorNameTable(self: *Wasm) !void {...@@ -1988,27 +1987,27 @@ fn populateErrorNameTable(self: *Wasm) !void {
19881987
1989 // Addend for each relocation to the table1988 // Addend for each relocation to the table
1990 var addend: u32 = 0;1989 var addend: u32 = 0;
1991 const mod = self.base.options.module.?;1990 const mod = wasm.base.options.module.?;
1992 for (mod.error_name_list.items) |error_name| {1991 for (mod.error_name_list.items) |error_name| {
1993 const len = @intCast(u32, error_name.len + 1); // names are 0-termianted1992 const len = @intCast(u32, error_name.len + 1); // names are 0-termianted
19941993
1995 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);1994 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
1996 const offset = @intCast(u32, atom.code.items.len);1995 const offset = @intCast(u32, atom.code.items.len);
1997 // first we create the data for the slice of the name1996 // first we create the data for the slice of the name
1998 try atom.code.appendNTimes(self.base.allocator, 0, 4); // ptr to name, will be relocated1997 try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated
1999 try atom.code.writer(self.base.allocator).writeIntLittle(u32, len - 1);1998 try atom.code.writer(wasm.base.allocator).writeIntLittle(u32, len - 1);
2000 // create relocation to the error name1999 // create relocation to the error name
2001 try atom.relocs.append(self.base.allocator, .{2000 try atom.relocs.append(wasm.base.allocator, .{
2002 .index = names_symbol_index,2001 .index = names_symbol_index,
2003 .relocation_type = .R_WASM_MEMORY_ADDR_I32,2002 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
2004 .offset = offset,2003 .offset = offset,
2005 .addend = addend,2004 .addend = addend,
2006 });2005 });
2007 atom.size += @intCast(u32, slice_ty.abiSize(self.base.options.target));2006 atom.size += @intCast(u32, slice_ty.abiSize(wasm.base.options.target));
2008 addend += len;2007 addend += len;
20092008
2010 // as we updated the error name table, we now store the actual name within the names atom2009 // as we updated the error name table, we now store the actual name within the names atom
2011 try names_atom.code.ensureUnusedCapacity(self.base.allocator, len);2010 try names_atom.code.ensureUnusedCapacity(wasm.base.allocator, len);
2012 names_atom.code.appendSliceAssumeCapacity(error_name);2011 names_atom.code.appendSliceAssumeCapacity(error_name);
2013 names_atom.code.appendAssumeCapacity(0);2012 names_atom.code.appendAssumeCapacity(0);
20142013
...@@ -2017,51 +2016,51 @@ fn populateErrorNameTable(self: *Wasm) !void {...@@ -2017,51 +2016,51 @@ fn populateErrorNameTable(self: *Wasm) !void {
2017 names_atom.size = addend;2016 names_atom.size = addend;
20182017
2019 const name_loc = names_atom.symbolLoc();2018 const name_loc = names_atom.symbolLoc();
2020 try self.resolved_symbols.put(self.base.allocator, name_loc, {});2019 try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {});
2021 try self.symbol_atom.put(self.base.allocator, name_loc, names_atom);2020 try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom);
20222021
2023 // link the atoms with the rest of the binary so they can be allocated2022 // link the atoms with the rest of the binary so they can be allocated
2024 // and relocations will be performed.2023 // and relocations will be performed.
2025 try self.parseAtom(atom, .{ .data = .read_only });2024 try wasm.parseAtom(atom, .{ .data = .read_only });
2026 try self.parseAtom(names_atom, .{ .data = .read_only });2025 try wasm.parseAtom(names_atom, .{ .data = .read_only });
2027}2026}
20282027
2029/// From a given index variable, creates a new debug section.2028/// From a given index variable, creates a new debug section.
2030/// This initializes the index, appends a new segment,2029/// This initializes the index, appends a new segment,
2031/// and finally, creates a managed `Atom`.2030/// and finally, creates a managed `Atom`.
2032pub fn createDebugSectionForIndex(self: *Wasm, index: *?u32, name: []const u8) !*Atom {2031pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !*Atom {
2033 const new_index = @intCast(u32, self.segments.items.len);2032 const new_index = @intCast(u32, wasm.segments.items.len);
2034 index.* = new_index;2033 index.* = new_index;
2035 try self.appendDummySegment();2034 try wasm.appendDummySegment();
2036 // _ = index;2035 // _ = index;
20372036
2038 const sym_index = self.symbols_free_list.popOrNull() orelse idx: {2037 const sym_index = wasm.symbols_free_list.popOrNull() orelse idx: {
2039 const tmp_index = @intCast(u32, self.symbols.items.len);2038 const tmp_index = @intCast(u32, wasm.symbols.items.len);
2040 _ = try self.symbols.addOne(self.base.allocator);2039 _ = try wasm.symbols.addOne(wasm.base.allocator);
2041 break :idx tmp_index;2040 break :idx tmp_index;
2042 };2041 };
2043 self.symbols.items[sym_index] = .{2042 wasm.symbols.items[sym_index] = .{
2044 .tag = .section,2043 .tag = .section,
2045 .name = try self.string_table.put(self.base.allocator, name),2044 .name = try wasm.string_table.put(wasm.base.allocator, name),
2046 .index = 0,2045 .index = 0,
2047 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),2046 .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
2048 };2047 };
20492048
2050 const atom = try self.base.allocator.create(Atom);2049 const atom = try wasm.base.allocator.create(Atom);
2051 atom.* = Atom.empty;2050 atom.* = Atom.empty;
2052 atom.alignment = 1; // debug sections are always 1-byte-aligned2051 atom.alignment = 1; // debug sections are always 1-byte-aligned
2053 atom.sym_index = sym_index;2052 atom.sym_index = sym_index;
2054 try self.managed_atoms.append(self.base.allocator, atom);2053 try wasm.managed_atoms.append(wasm.base.allocator, atom);
2055 try self.symbol_atom.put(self.base.allocator, atom.symbolLoc(), atom);2054 try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom);
2056 return atom;2055 return atom;
2057}2056}
20582057
2059fn resetState(self: *Wasm) void {2058fn resetState(wasm: *Wasm) void {
2060 for (self.segment_info.values()) |segment_info| {2059 for (wasm.segment_info.values()) |segment_info| {
2061 self.base.allocator.free(segment_info.name);2060 wasm.base.allocator.free(segment_info.name);
2062 }2061 }
2063 if (self.base.options.module) |mod| {2062 if (wasm.base.options.module) |mod| {
2064 var decl_it = self.decls.keyIterator();2063 var decl_it = wasm.decls.keyIterator();
2065 while (decl_it.next()) |decl_index_ptr| {2064 while (decl_it.next()) |decl_index_ptr| {
2066 const decl = mod.declPtr(decl_index_ptr.*);2065 const decl = mod.declPtr(decl_index_ptr.*);
2067 const atom = &decl.link.wasm;2066 const atom = &decl.link.wasm;
...@@ -2074,46 +2073,46 @@ fn resetState(self: *Wasm) void {...@@ -2074,46 +2073,46 @@ fn resetState(self: *Wasm) void {
2074 }2073 }
2075 }2074 }
2076 }2075 }
2077 self.functions.clearRetainingCapacity();2076 wasm.functions.clearRetainingCapacity();
2078 self.exports.clearRetainingCapacity();2077 wasm.exports.clearRetainingCapacity();
2079 self.segments.clearRetainingCapacity();2078 wasm.segments.clearRetainingCapacity();
2080 self.segment_info.clearRetainingCapacity();2079 wasm.segment_info.clearRetainingCapacity();
2081 self.data_segments.clearRetainingCapacity();2080 wasm.data_segments.clearRetainingCapacity();
2082 self.atoms.clearRetainingCapacity();2081 wasm.atoms.clearRetainingCapacity();
2083 self.symbol_atom.clearRetainingCapacity();2082 wasm.symbol_atom.clearRetainingCapacity();
2084 self.code_section_index = null;2083 wasm.code_section_index = null;
2085 self.debug_info_index = null;2084 wasm.debug_info_index = null;
2086 self.debug_line_index = null;2085 wasm.debug_line_index = null;
2087 self.debug_loc_index = null;2086 wasm.debug_loc_index = null;
2088 self.debug_str_index = null;2087 wasm.debug_str_index = null;
2089 self.debug_ranges_index = null;2088 wasm.debug_ranges_index = null;
2090 self.debug_abbrev_index = null;2089 wasm.debug_abbrev_index = null;
2091 self.debug_pubnames_index = null;2090 wasm.debug_pubnames_index = null;
2092 self.debug_pubtypes_index = null;2091 wasm.debug_pubtypes_index = null;
2093}2092}
20942093
2095pub fn flush(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {2094pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
2096 if (self.base.options.emit == null) {2095 if (wasm.base.options.emit == null) {
2097 if (build_options.have_llvm) {2096 if (build_options.have_llvm) {
2098 if (self.llvm_object) |llvm_object| {2097 if (wasm.llvm_object) |llvm_object| {
2099 return try llvm_object.flushModule(comp, prog_node);2098 return try llvm_object.flushModule(comp, prog_node);
2100 }2099 }
2101 }2100 }
2102 return;2101 return;
2103 }2102 }
2104 if (build_options.have_llvm and self.base.options.use_lld) {2103 if (build_options.have_llvm and wasm.base.options.use_lld) {
2105 return self.linkWithLLD(comp, prog_node);2104 return wasm.linkWithLLD(comp, prog_node);
2106 } else {2105 } else {
2107 return self.flushModule(comp, prog_node);2106 return wasm.flushModule(comp, prog_node);
2108 }2107 }
2109}2108}
21102109
2111pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {2110pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
2112 const tracy = trace(@src());2111 const tracy = trace(@src());
2113 defer tracy.end();2112 defer tracy.end();
21142113
2115 if (build_options.have_llvm) {2114 if (build_options.have_llvm) {
2116 if (self.llvm_object) |llvm_object| {2115 if (wasm.llvm_object) |llvm_object| {
2117 return try llvm_object.flushModule(comp, prog_node);2116 return try llvm_object.flushModule(comp, prog_node);
2118 }2117 }
2119 }2118 }
...@@ -2123,7 +2122,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2123,7 +2122,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2123 defer sub_prog_node.end();2122 defer sub_prog_node.end();
21242123
2125 // ensure the error names table is populated when an error name is referenced2124 // ensure the error names table is populated when an error name is referenced
2126 try self.populateErrorNameTable();2125 try wasm.populateErrorNameTable();
21272126
2128 // The amount of sections that will be written2127 // The amount of sections that will be written
2129 var section_count: u32 = 0;2128 var section_count: u32 = 0;
...@@ -2133,15 +2132,15 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2133,15 +2132,15 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2133 var data_section_index: ?u32 = null;2132 var data_section_index: ?u32 = null;
21342133
2135 // Used for all temporary memory allocated during flushin2134 // Used for all temporary memory allocated during flushin
2136 var arena_instance = std.heap.ArenaAllocator.init(self.base.allocator);2135 var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator);
2137 defer arena_instance.deinit();2136 defer arena_instance.deinit();
2138 const arena = arena_instance.allocator();2137 const arena = arena_instance.allocator();
21392138
2140 // Positional arguments to the linker such as object files and static archives.2139 // Positional arguments to the linker such as object files and static archives.
2141 var positionals = std.ArrayList([]const u8).init(arena);2140 var positionals = std.ArrayList([]const u8).init(arena);
2142 try positionals.ensureUnusedCapacity(self.base.options.objects.len);2141 try positionals.ensureUnusedCapacity(wasm.base.options.objects.len);
21432142
2144 for (self.base.options.objects) |object| {2143 for (wasm.base.options.objects) |object| {
2145 positionals.appendAssumeCapacity(object.path);2144 positionals.appendAssumeCapacity(object.path);
2146 }2145 }
21472146
...@@ -2153,180 +2152,186 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2153,180 +2152,186 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2153 try positionals.append(lib.full_object_path);2152 try positionals.append(lib.full_object_path);
2154 }2153 }
21552154
2156 try self.parseInputFiles(positionals.items);2155 try wasm.parseInputFiles(positionals.items);
21572156
2158 for (self.objects.items) |_, object_index| {2157 for (wasm.objects.items) |_, object_index| {
2159 try self.resolveSymbolsInObject(@intCast(u16, object_index));2158 try wasm.resolveSymbolsInObject(@intCast(u16, object_index));
2160 }2159 }
21612160
2162 try self.resolveSymbolsInArchives();2161 try wasm.resolveSymbolsInArchives();
2163 try self.checkUndefinedSymbols();2162 try wasm.checkUndefinedSymbols();
21642163
2165 // When we finish/error we reset the state of the linker2164 // When we finish/error we reset the state of the linker
2166 // So we can rebuild the binary file on each incremental update2165 // So we can rebuild the binary file on each incremental update
2167 defer self.resetState();2166 defer wasm.resetState();
2168 try self.setupStart();2167 try wasm.setupStart();
2169 try self.setupImports();2168 try wasm.setupImports();
2170 if (self.base.options.module) |mod| {2169 if (wasm.base.options.module) |mod| {
2171 var decl_it = self.decls.keyIterator();2170 var decl_it = wasm.decls.keyIterator();
2172 while (decl_it.next()) |decl_index_ptr| {2171 while (decl_it.next()) |decl_index_ptr| {
2173 const decl = mod.declPtr(decl_index_ptr.*);2172 const decl = mod.declPtr(decl_index_ptr.*);
2174 if (decl.isExtern()) continue;2173 if (decl.isExtern()) continue;
2175 const atom = &decl.*.link.wasm;2174 const atom = &decl.*.link.wasm;
2176 if (decl.ty.zigTypeTag() == .Fn) {2175 if (decl.ty.zigTypeTag() == .Fn) {
2177 try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });2176 try wasm.parseAtom(atom, .{ .function = decl.fn_link.wasm });
2178 } else if (decl.getVariable()) |variable| {2177 } else if (decl.getVariable()) |variable| {
2179 if (!variable.is_mutable) {2178 if (!variable.is_mutable) {
2180 try self.parseAtom(atom, .{ .data = .read_only });2179 try wasm.parseAtom(atom, .{ .data = .read_only });
2181 } else if (variable.init.isUndefDeep()) {2180 } else if (variable.init.isUndefDeep()) {
2182 try self.parseAtom(atom, .{ .data = .uninitialized });2181 try wasm.parseAtom(atom, .{ .data = .uninitialized });
2183 } else {2182 } else {
2184 try self.parseAtom(atom, .{ .data = .initialized });2183 try wasm.parseAtom(atom, .{ .data = .initialized });
2185 }2184 }
2186 } else {2185 } else {
2187 try self.parseAtom(atom, .{ .data = .read_only });2186 try wasm.parseAtom(atom, .{ .data = .read_only });
2188 }2187 }
21892188
2190 // also parse atoms for a decl's locals2189 // also parse atoms for a decl's locals
2191 for (atom.locals.items) |*local_atom| {2190 for (atom.locals.items) |*local_atom| {
2192 try self.parseAtom(local_atom, .{ .data = .read_only });2191 try wasm.parseAtom(local_atom, .{ .data = .read_only });
2193 }2192 }
2194 }2193 }
21952194
2196 if (self.dwarf) |*dwarf| {2195 if (wasm.dwarf) |*dwarf| {
2197 try dwarf.flushModule(&self.base, self.base.options.module.?);2196 try dwarf.flushModule(&wasm.base, wasm.base.options.module.?);
2198 }2197 }
2199 }2198 }
22002199
2201 for (self.objects.items) |*object, object_index| {2200 for (wasm.objects.items) |*object, object_index| {
2202 try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_index), self);2201 try object.parseIntoAtoms(wasm.base.allocator, @intCast(u16, object_index), wasm);
2203 }2202 }
22042203
2205 try self.allocateAtoms();2204 try wasm.allocateAtoms();
2206 try self.setupMemory();2205 try wasm.setupMemory();
2207 self.mapFunctionTable();2206 wasm.mapFunctionTable();
2208 try self.mergeSections();2207 try wasm.mergeSections();
2209 try self.mergeTypes();2208 try wasm.mergeTypes();
2210 try self.setupExports();2209 try wasm.setupExports();
22112210
2212 const file = self.base.file.?;
2213 const header_size = 5 + 1;2211 const header_size = 5 + 1;
2214 const is_obj = self.base.options.output_mode == .Obj;2212 const is_obj = wasm.base.options.output_mode == .Obj;
22152213
2216 // No need to rewrite the magic/version header2214 var binary_bytes = std.ArrayList(u8).init(wasm.base.allocator);
2217 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));2215 defer binary_bytes.deinit();
2218 try file.seekTo(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));2216 const binary_writer = binary_bytes.writer();
2217
2218 // We write the magic bytes at the end so they will only be written
2219 // if everything succeeded as expected. So populate with 0's for now.
2220 try binary_writer.writeAll(&[_]u8{0} ** 8);
2221 // (Re)set file pointer to 0
2222 try wasm.base.file.?.setEndPos(0);
2223 try wasm.base.file.?.seekTo(0);
22192224
2220 // Type section2225 // Type section
2221 if (self.func_types.items.len != 0) {2226 if (wasm.func_types.items.len != 0) {
2222 const header_offset = try reserveVecSectionHeader(file);2227 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2223 const writer = file.writer();2228 log.debug("Writing type section. Count: ({d})", .{wasm.func_types.items.len});
2224 log.debug("Writing type section. Count: ({d})", .{self.func_types.items.len});2229 for (wasm.func_types.items) |func_type| {
2225 for (self.func_types.items) |func_type| {2230 try leb.writeULEB128(binary_writer, std.wasm.function_type);
2226 try leb.writeULEB128(writer, wasm.function_type);2231 try leb.writeULEB128(binary_writer, @intCast(u32, func_type.params.len));
2227 try leb.writeULEB128(writer, @intCast(u32, func_type.params.len));2232 for (func_type.params) |param_ty| {
2228 for (func_type.params) |param_ty| try leb.writeULEB128(writer, wasm.valtype(param_ty));2233 try leb.writeULEB128(binary_writer, std.wasm.valtype(param_ty));
2229 try leb.writeULEB128(writer, @intCast(u32, func_type.returns.len));2234 }
2230 for (func_type.returns) |ret_ty| try leb.writeULEB128(writer, wasm.valtype(ret_ty));2235 try leb.writeULEB128(binary_writer, @intCast(u32, func_type.returns.len));
2236 for (func_type.returns) |ret_ty| {
2237 try leb.writeULEB128(binary_writer, std.wasm.valtype(ret_ty));
2238 }
2231 }2239 }
22322240
2233 try writeVecSectionHeader(2241 try writeVecSectionHeader(
2234 file,2242 binary_bytes.items,
2235 header_offset,2243 header_offset,
2236 .type,2244 .type,
2237 @intCast(u32, (try file.getPos()) - header_offset - header_size),2245 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2238 @intCast(u32, self.func_types.items.len),2246 @intCast(u32, wasm.func_types.items.len),
2239 );2247 );
2240 section_count += 1;2248 section_count += 1;
2241 }2249 }
22422250
2243 // Import section2251 // Import section
2244 const import_memory = self.base.options.import_memory or is_obj;2252 const import_memory = wasm.base.options.import_memory or is_obj;
2245 const import_table = self.base.options.import_table or is_obj;2253 const import_table = wasm.base.options.import_table or is_obj;
2246 if (self.imports.count() != 0 or import_memory or import_table) {2254 if (wasm.imports.count() != 0 or import_memory or import_table) {
2247 const header_offset = try reserveVecSectionHeader(file);2255 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2248 const writer = file.writer();
22492256
2250 // import table is always first table so emit that first2257 // import table is always first table so emit that first
2251 if (import_table) {2258 if (import_table) {
2252 const table_imp: types.Import = .{2259 const table_imp: types.Import = .{
2253 .module_name = try self.string_table.put(self.base.allocator, self.host_name),2260 .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name),
2254 .name = try self.string_table.put(self.base.allocator, "__indirect_function_table"),2261 .name = try wasm.string_table.put(wasm.base.allocator, "__indirect_function_table"),
2255 .kind = .{2262 .kind = .{
2256 .table = .{2263 .table = .{
2257 .limits = .{2264 .limits = .{
2258 .min = @intCast(u32, self.function_table.count()),2265 .min = @intCast(u32, wasm.function_table.count()),
2259 .max = null,2266 .max = null,
2260 },2267 },
2261 .reftype = .funcref,2268 .reftype = .funcref,
2262 },2269 },
2263 },2270 },
2264 };2271 };
2265 try self.emitImport(writer, table_imp);2272 try wasm.emitImport(binary_writer, table_imp);
2266 }2273 }
22672274
2268 var it = self.imports.iterator();2275 var it = wasm.imports.iterator();
2269 while (it.next()) |entry| {2276 while (it.next()) |entry| {
2270 assert(entry.key_ptr.*.getSymbol(self).isUndefined());2277 assert(entry.key_ptr.*.getSymbol(wasm).isUndefined());
2271 const import = entry.value_ptr.*;2278 const import = entry.value_ptr.*;
2272 try self.emitImport(writer, import);2279 try wasm.emitImport(binary_writer, import);
2273 }2280 }
22742281
2275 if (import_memory) {2282 if (import_memory) {
2276 const mem_name = if (is_obj) "__linear_memory" else "memory";2283 const mem_name = if (is_obj) "__linear_memory" else "memory";
2277 const mem_imp: types.Import = .{2284 const mem_imp: types.Import = .{
2278 .module_name = try self.string_table.put(self.base.allocator, self.host_name),2285 .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name),
2279 .name = try self.string_table.put(self.base.allocator, mem_name),2286 .name = try wasm.string_table.put(wasm.base.allocator, mem_name),
2280 .kind = .{ .memory = self.memories.limits },2287 .kind = .{ .memory = wasm.memories.limits },
2281 };2288 };
2282 try self.emitImport(writer, mem_imp);2289 try wasm.emitImport(binary_writer, mem_imp);
2283 }2290 }
22842291
2285 try writeVecSectionHeader(2292 try writeVecSectionHeader(
2286 file,2293 binary_bytes.items,
2287 header_offset,2294 header_offset,
2288 .import,2295 .import,
2289 @intCast(u32, (try file.getPos()) - header_offset - header_size),2296 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2290 @intCast(u32, self.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)),2297 @intCast(u32, wasm.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)),
2291 );2298 );
2292 section_count += 1;2299 section_count += 1;
2293 }2300 }
22942301
2295 // Function section2302 // Function section
2296 if (self.functions.count() != 0) {2303 if (wasm.functions.count() != 0) {
2297 const header_offset = try reserveVecSectionHeader(file);2304 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2298 const writer = file.writer();2305 for (wasm.functions.values()) |function| {
2299 for (self.functions.values()) |function| {2306 try leb.writeULEB128(binary_writer, function.type_index);
2300 try leb.writeULEB128(writer, function.type_index);
2301 }2307 }
23022308
2303 try writeVecSectionHeader(2309 try writeVecSectionHeader(
2304 file,2310 binary_bytes.items,
2305 header_offset,2311 header_offset,
2306 .function,2312 .function,
2307 @intCast(u32, (try file.getPos()) - header_offset - header_size),2313 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2308 @intCast(u32, self.functions.count()),2314 @intCast(u32, wasm.functions.count()),
2309 );2315 );
2310 section_count += 1;2316 section_count += 1;
2311 }2317 }
23122318
2313 // Table section2319 // Table section
2314 const export_table = self.base.options.export_table;2320 const export_table = wasm.base.options.export_table;
2315 if (!import_table and self.function_table.count() != 0) {2321 if (!import_table and wasm.function_table.count() != 0) {
2316 const header_offset = try reserveVecSectionHeader(file);2322 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2317 const writer = file.writer();2323
23182324 try leb.writeULEB128(binary_writer, std.wasm.reftype(.funcref));
2319 try leb.writeULEB128(writer, wasm.reftype(.funcref));2325 try emitLimits(binary_writer, .{
2320 try emitLimits(writer, .{2326 .min = @intCast(u32, wasm.function_table.count()) + 1,
2321 .min = @intCast(u32, self.function_table.count()) + 1,
2322 .max = null,2327 .max = null,
2323 });2328 });
23242329
2325 try writeVecSectionHeader(2330 try writeVecSectionHeader(
2326 file,2331 binary_bytes.items,
2327 header_offset,2332 header_offset,
2328 .table,2333 .table,
2329 @intCast(u32, (try file.getPos()) - header_offset - header_size),2334 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2330 @as(u32, 1),2335 @as(u32, 1),
2331 );2336 );
2332 section_count += 1;2337 section_count += 1;
...@@ -2334,98 +2339,95 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2334,98 +2339,95 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
23342339
2335 // Memory section2340 // Memory section
2336 if (!import_memory) {2341 if (!import_memory) {
2337 const header_offset = try reserveVecSectionHeader(file);2342 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2338 const writer = file.writer();
23392343
2340 try emitLimits(writer, self.memories.limits);2344 try emitLimits(binary_writer, wasm.memories.limits);
2341 try writeVecSectionHeader(2345 try writeVecSectionHeader(
2342 file,2346 binary_bytes.items,
2343 header_offset,2347 header_offset,
2344 .memory,2348 .memory,
2345 @intCast(u32, (try file.getPos()) - header_offset - header_size),2349 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2346 @as(u32, 1), // wasm currently only supports 1 linear memory segment2350 @as(u32, 1), // wasm currently only supports 1 linear memory segment
2347 );2351 );
2348 section_count += 1;2352 section_count += 1;
2349 }2353 }
23502354
2351 // Global section (used to emit stack pointer)2355 // Global section (used to emit stack pointer)
2352 if (self.wasm_globals.items.len > 0) {2356 if (wasm.wasm_globals.items.len > 0) {
2353 const header_offset = try reserveVecSectionHeader(file);2357 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2354 const writer = file.writer();
23552358
2356 for (self.wasm_globals.items) |global| {2359 for (wasm.wasm_globals.items) |global| {
2357 try writer.writeByte(wasm.valtype(global.global_type.valtype));2360 try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype));
2358 try writer.writeByte(@boolToInt(global.global_type.mutable));2361 try binary_writer.writeByte(@boolToInt(global.global_type.mutable));
2359 try emitInit(writer, global.init);2362 try emitInit(binary_writer, global.init);
2360 }2363 }
23612364
2362 try writeVecSectionHeader(2365 try writeVecSectionHeader(
2363 file,2366 binary_bytes.items,
2364 header_offset,2367 header_offset,
2365 .global,2368 .global,
2366 @intCast(u32, (try file.getPos()) - header_offset - header_size),2369 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2367 @intCast(u32, self.wasm_globals.items.len),2370 @intCast(u32, wasm.wasm_globals.items.len),
2368 );2371 );
2369 section_count += 1;2372 section_count += 1;
2370 }2373 }
23712374
2372 // Export section2375 // Export section
2373 if (self.exports.items.len != 0 or export_table or !import_memory) {2376 if (wasm.exports.items.len != 0 or export_table or !import_memory) {
2374 const header_offset = try reserveVecSectionHeader(file);2377 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2375 const writer = file.writer();2378
2376 for (self.exports.items) |exp| {2379 for (wasm.exports.items) |exp| {
2377 const name = self.string_table.get(exp.name);2380 const name = wasm.string_table.get(exp.name);
2378 try leb.writeULEB128(writer, @intCast(u32, name.len));2381 try leb.writeULEB128(binary_writer, @intCast(u32, name.len));
2379 try writer.writeAll(name);2382 try binary_writer.writeAll(name);
2380 try leb.writeULEB128(writer, @enumToInt(exp.kind));2383 try leb.writeULEB128(binary_writer, @enumToInt(exp.kind));
2381 try leb.writeULEB128(writer, exp.index);2384 try leb.writeULEB128(binary_writer, exp.index);
2382 }2385 }
23832386
2384 if (export_table) {2387 if (export_table) {
2385 try leb.writeULEB128(writer, @intCast(u32, "__indirect_function_table".len));2388 try leb.writeULEB128(binary_writer, @intCast(u32, "__indirect_function_table".len));
2386 try writer.writeAll("__indirect_function_table");2389 try binary_writer.writeAll("__indirect_function_table");
2387 try writer.writeByte(wasm.externalKind(.table));2390 try binary_writer.writeByte(std.wasm.externalKind(.table));
2388 try leb.writeULEB128(writer, @as(u32, 0)); // function table is always the first table2391 try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table
2389 }2392 }
23902393
2391 if (!import_memory) {2394 if (!import_memory) {
2392 try leb.writeULEB128(writer, @intCast(u32, "memory".len));2395 try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len));
2393 try writer.writeAll("memory");2396 try binary_writer.writeAll("memory");
2394 try writer.writeByte(wasm.externalKind(.memory));2397 try binary_writer.writeByte(std.wasm.externalKind(.memory));
2395 try leb.writeULEB128(writer, @as(u32, 0));2398 try leb.writeULEB128(binary_writer, @as(u32, 0));
2396 }2399 }
23972400
2398 try writeVecSectionHeader(2401 try writeVecSectionHeader(
2399 file,2402 binary_bytes.items,
2400 header_offset,2403 header_offset,
2401 .@"export",2404 .@"export",
2402 @intCast(u32, (try file.getPos()) - header_offset - header_size),2405 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2403 @intCast(u32, self.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory),2406 @intCast(u32, wasm.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory),
2404 );2407 );
2405 section_count += 1;2408 section_count += 1;
2406 }2409 }
24072410
2408 // element section (function table)2411 // element section (function table)
2409 if (self.function_table.count() > 0) {2412 if (wasm.function_table.count() > 0) {
2410 const header_offset = try reserveVecSectionHeader(file);2413 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2411 const writer = file.writer();
24122414
2413 var flags: u32 = 0x2; // Yes we have a table2415 var flags: u32 = 0x2; // Yes we have a table
2414 try leb.writeULEB128(writer, flags);2416 try leb.writeULEB128(binary_writer, flags);
2415 try leb.writeULEB128(writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols2417 try leb.writeULEB128(binary_writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols
2416 try emitInit(writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid2418 try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid
2417 try leb.writeULEB128(writer, @as(u8, 0));2419 try leb.writeULEB128(binary_writer, @as(u8, 0));
2418 try leb.writeULEB128(writer, @intCast(u32, self.function_table.count()));2420 try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count()));
2419 var symbol_it = self.function_table.keyIterator();2421 var symbol_it = wasm.function_table.keyIterator();
2420 while (symbol_it.next()) |symbol_loc_ptr| {2422 while (symbol_it.next()) |symbol_loc_ptr| {
2421 try leb.writeULEB128(writer, symbol_loc_ptr.*.getSymbol(self).index);2423 try leb.writeULEB128(binary_writer, symbol_loc_ptr.*.getSymbol(wasm).index);
2422 }2424 }
24232425
2424 try writeVecSectionHeader(2426 try writeVecSectionHeader(
2425 file,2427 binary_bytes.items,
2426 header_offset,2428 header_offset,
2427 .element,2429 .element,
2428 @intCast(u32, (try file.getPos()) - header_offset - header_size),2430 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2429 @as(u32, 1),2431 @as(u32, 1),
2430 );2432 );
2431 section_count += 1;2433 section_count += 1;
...@@ -2433,18 +2435,17 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2433,18 +2435,17 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
24332435
2434 // Code section2436 // Code section
2435 var code_section_size: u32 = 0;2437 var code_section_size: u32 = 0;
2436 if (self.code_section_index) |code_index| {2438 if (wasm.code_section_index) |code_index| {
2437 const header_offset = try reserveVecSectionHeader(file);2439 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2438 const writer = file.writer();2440 var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
2439 var atom: *Atom = self.atoms.get(code_index).?.getFirst();
24402441
2441 // The code section must be sorted in line with the function order.2442 // The code section must be sorted in line with the function order.
2442 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(self.base.allocator, self.functions.count());2443 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
2443 defer sorted_atoms.deinit();2444 defer sorted_atoms.deinit();
24442445
2445 while (true) {2446 while (true) {
2446 if (!is_obj) {2447 if (!is_obj) {
2447 atom.resolveRelocs(self);2448 atom.resolveRelocs(wasm);
2448 }2449 }
2449 sorted_atoms.appendAssumeCapacity(atom);2450 sorted_atoms.appendAssumeCapacity(atom);
2450 atom = atom.next orelse break;2451 atom = atom.next orelse break;
...@@ -2458,31 +2459,30 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2458,31 +2459,30 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2458 }2459 }
2459 }.sort;2460 }.sort;
24602461
2461 std.sort.sort(*Atom, sorted_atoms.items, self, atom_sort_fn);2462 std.sort.sort(*Atom, sorted_atoms.items, wasm, atom_sort_fn);
24622463
2463 for (sorted_atoms.items) |sorted_atom| {2464 for (sorted_atoms.items) |sorted_atom| {
2464 try leb.writeULEB128(writer, sorted_atom.size);2465 try leb.writeULEB128(binary_writer, sorted_atom.size);
2465 try writer.writeAll(sorted_atom.code.items);2466 try binary_writer.writeAll(sorted_atom.code.items);
2466 }2467 }
24672468
2468 code_section_size = @intCast(u32, (try file.getPos()) - header_offset - header_size);2469 code_section_size = @intCast(u32, binary_bytes.items.len - header_offset - header_size);
2469 try writeVecSectionHeader(2470 try writeVecSectionHeader(
2470 file,2471 binary_bytes.items,
2471 header_offset,2472 header_offset,
2472 .code,2473 .code,
2473 code_section_size,2474 code_section_size,
2474 @intCast(u32, self.functions.count()),2475 @intCast(u32, wasm.functions.count()),
2475 );2476 );
2476 code_section_index = section_count;2477 code_section_index = section_count;
2477 section_count += 1;2478 section_count += 1;
2478 }2479 }
24792480
2480 // Data section2481 // Data section
2481 if (self.data_segments.count() != 0) {2482 if (wasm.data_segments.count() != 0) {
2482 const header_offset = try reserveVecSectionHeader(file);2483 const header_offset = try reserveVecSectionHeader(&binary_bytes);
2483 const writer = file.writer();
24842484
2485 var it = self.data_segments.iterator();2485 var it = wasm.data_segments.iterator();
2486 var segment_count: u32 = 0;2486 var segment_count: u32 = 0;
2487 while (it.next()) |entry| {2487 while (it.next()) |entry| {
2488 // do not output 'bss' section unless we import memory and therefore2488 // do not output 'bss' section unless we import memory and therefore
...@@ -2490,31 +2490,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2490,31 +2490,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2490 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;2490 if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
2491 segment_count += 1;2491 segment_count += 1;
2492 const atom_index = entry.value_ptr.*;2492 const atom_index = entry.value_ptr.*;
2493 var atom: *Atom = self.atoms.getPtr(atom_index).?.*.getFirst();2493 var atom: *Atom = wasm.atoms.getPtr(atom_index).?.*.getFirst();
2494 const segment = self.segments.items[atom_index];2494 const segment = wasm.segments.items[atom_index];
24952495
2496 // flag and index to memory section (currently, there can only be 1 memory section in wasm)2496 // flag and index to memory section (currently, there can only be 1 memory section in wasm)
2497 try leb.writeULEB128(writer, @as(u32, 0));2497 try leb.writeULEB128(binary_writer, @as(u32, 0));
2498 // offset into data section2498 // offset into data section
2499 try emitInit(writer, .{ .i32_const = @bitCast(i32, segment.offset) });2499 try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) });
2500 try leb.writeULEB128(writer, segment.size);2500 try leb.writeULEB128(binary_writer, segment.size);
25012501
2502 // fill in the offset table and the data segments2502 // fill in the offset table and the data segments
2503 var current_offset: u32 = 0;2503 var current_offset: u32 = 0;
2504 while (true) {2504 while (true) {
2505 if (!is_obj) {2505 if (!is_obj) {
2506 atom.resolveRelocs(self);2506 atom.resolveRelocs(wasm);
2507 }2507 }
25082508
2509 // Pad with zeroes to ensure all segments are aligned2509 // Pad with zeroes to ensure all segments are aligned
2510 if (current_offset != atom.offset) {2510 if (current_offset != atom.offset) {
2511 const diff = atom.offset - current_offset;2511 const diff = atom.offset - current_offset;
2512 try writer.writeByteNTimes(0, diff);2512 try binary_writer.writeByteNTimes(0, diff);
2513 current_offset += diff;2513 current_offset += diff;
2514 }2514 }
2515 assert(current_offset == atom.offset);2515 assert(current_offset == atom.offset);
2516 assert(atom.code.items.len == atom.size);2516 assert(atom.code.items.len == atom.size);
2517 try writer.writeAll(atom.code.items);2517 try binary_writer.writeAll(atom.code.items);
25182518
2519 current_offset += atom.size;2519 current_offset += atom.size;
2520 if (atom.next) |next| {2520 if (atom.next) |next| {
...@@ -2523,7 +2523,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2523,7 +2523,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2523 // also pad with zeroes when last atom to ensure2523 // also pad with zeroes when last atom to ensure
2524 // segments are aligned.2524 // segments are aligned.
2525 if (current_offset != segment.size) {2525 if (current_offset != segment.size) {
2526 try writer.writeByteNTimes(0, segment.size - current_offset);2526 try binary_writer.writeByteNTimes(0, segment.size - current_offset);
2527 current_offset += segment.size - current_offset;2527 current_offset += segment.size - current_offset;
2528 }2528 }
2529 break;2529 break;
...@@ -2533,10 +2533,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2533,10 +2533,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2533 }2533 }
25342534
2535 try writeVecSectionHeader(2535 try writeVecSectionHeader(
2536 file,2536 binary_bytes.items,
2537 header_offset,2537 header_offset,
2538 .data,2538 .data,
2539 @intCast(u32, (try file.getPos()) - header_offset - header_size),2539 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2540 @intCast(u32, segment_count),2540 @intCast(u32, segment_count),
2541 );2541 );
2542 data_section_index = section_count;2542 data_section_index = section_count;
...@@ -2548,25 +2548,25 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2548,25 +2548,25 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2548 // we never store all symbols in a single table, but store a location reference instead.2548 // we never store all symbols in a single table, but store a location reference instead.
2549 // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections.2549 // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections.
2550 var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena);2550 var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena);
2551 try self.emitLinkSection(file, arena, &symbol_table);2551 try wasm.emitLinkSection(&binary_bytes, &symbol_table);
2552 if (code_section_index) |code_index| {2552 if (code_section_index) |code_index| {
2553 try self.emitCodeRelocations(file, arena, code_index, symbol_table);2553 try wasm.emitCodeRelocations(&binary_bytes, code_index, symbol_table);
2554 }2554 }
2555 if (data_section_index) |data_index| {2555 if (data_section_index) |data_index| {
2556 try self.emitDataRelocations(file, arena, data_index, symbol_table);2556 try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);
2557 }2557 }
2558 } else if (!self.base.options.strip) {2558 } else if (!wasm.base.options.strip) {
2559 if (self.dwarf) |*dwarf| {2559 if (wasm.dwarf) |*dwarf| {
2560 const mod = self.base.options.module.?;2560 const mod = wasm.base.options.module.?;
2561 try dwarf.writeDbgAbbrev(&self.base);2561 try dwarf.writeDbgAbbrev(&wasm.base);
2562 // for debug info and ranges, the address is always 0,2562 // for debug info and ranges, the address is always 0,
2563 // as locations are always offsets relative to 'code' section.2563 // as locations are always offsets relative to 'code' section.
2564 try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);2564 try dwarf.writeDbgInfoHeader(&wasm.base, mod, 0, code_section_size);
2565 try dwarf.writeDbgAranges(&self.base, 0, code_section_size);2565 try dwarf.writeDbgAranges(&wasm.base, 0, code_section_size);
2566 try dwarf.writeDbgLineHeader(&self.base, mod);2566 try dwarf.writeDbgLineHeader(&wasm.base, mod);
2567 }2567 }
25682568
2569 var debug_bytes = std.ArrayList(u8).init(self.base.allocator);2569 var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator);
2570 defer debug_bytes.deinit();2570 defer debug_bytes.deinit();
25712571
2572 const DebugSection = struct {2572 const DebugSection = struct {
...@@ -2575,54 +2575,63 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2575,54 +2575,63 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2575 };2575 };
25762576
2577 const debug_sections: []const DebugSection = &.{2577 const debug_sections: []const DebugSection = &.{
2578 .{ .name = ".debug_info", .index = self.debug_info_index },2578 .{ .name = ".debug_info", .index = wasm.debug_info_index },
2579 .{ .name = ".debug_pubtypes", .index = self.debug_pubtypes_index },2579 .{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index },
2580 .{ .name = ".debug_abbrev", .index = self.debug_abbrev_index },2580 .{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index },
2581 .{ .name = ".debug_line", .index = self.debug_line_index },2581 .{ .name = ".debug_line", .index = wasm.debug_line_index },
2582 .{ .name = ".debug_str", .index = self.debug_str_index },2582 .{ .name = ".debug_str", .index = wasm.debug_str_index },
2583 .{ .name = ".debug_pubnames", .index = self.debug_pubnames_index },2583 .{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index },
2584 .{ .name = ".debug_loc", .index = self.debug_loc_index },2584 .{ .name = ".debug_loc", .index = wasm.debug_loc_index },
2585 .{ .name = ".debug_ranges", .index = self.debug_ranges_index },2585 .{ .name = ".debug_ranges", .index = wasm.debug_ranges_index },
2586 };2586 };
25872587
2588 for (debug_sections) |item| {2588 for (debug_sections) |item| {
2589 if (item.index) |index| {2589 if (item.index) |index| {
2590 var atom = self.atoms.get(index).?.getFirst();2590 var atom = wasm.atoms.get(index).?.getFirst();
2591 while (true) {2591 while (true) {
2592 atom.resolveRelocs(self);2592 atom.resolveRelocs(wasm);
2593 try debug_bytes.appendSlice(atom.code.items);2593 try debug_bytes.appendSlice(atom.code.items);
2594 atom = atom.next orelse break;2594 atom = atom.next orelse break;
2595 }2595 }
2596 try emitDebugSection(file, debug_bytes.items, item.name);2596 try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
2597 debug_bytes.clearRetainingCapacity();2597 debug_bytes.clearRetainingCapacity();
2598 }2598 }
2599 }2599 }
2600 try self.emitNameSection(file, arena);2600 try wasm.emitNameSection(&binary_bytes, arena);
2601 }2601 }
2602
2603 // Only when writing all sections executed properly we write the magic
2604 // bytes. This allows us to easily detect what went wrong while generating
2605 // the final binary.
2606 mem.copy(u8, binary_bytes.items, &(std.wasm.magic ++ std.wasm.version));
2607
2608 // finally, write the entire binary into the file.
2609 var iovec = [_]std.os.iovec_const{.{
2610 .iov_base = binary_bytes.items.ptr,
2611 .iov_len = binary_bytes.items.len,
2612 }};
2613 try wasm.base.file.?.writevAll(&iovec);
2602}2614}
26032615
2604fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void {2616fn emitDebugSection(binary_bytes: *std.ArrayList(u8), data: []const u8, name: []const u8) !void {
2605 if (data.len == 0) return;2617 if (data.len == 0) return;
2606 const header_offset = try reserveCustomSectionHeader(file);2618 const header_offset = try reserveCustomSectionHeader(binary_bytes);
2607 const writer = file.writer();2619 const writer = binary_bytes.writer();
2608 try leb.writeULEB128(writer, @intCast(u32, name.len));2620 try leb.writeULEB128(writer, @intCast(u32, name.len));
2609 try writer.writeAll(name);2621 try writer.writeAll(name);
26102622
2611 try file.writevAll(&[_]std.os.iovec_const{.{2623 const start = binary_bytes.items.len - header_offset;
2612 .iov_base = data.ptr,
2613 .iov_len = data.len,
2614 }});
2615 const start = header_offset + 6 + name.len + getULEB128Size(@intCast(u32, name.len));
2616 log.debug("Emit debug section: '{s}' start=0x{x:0>8} end=0x{x:0>8}", .{ name, start, start + data.len });2624 log.debug("Emit debug section: '{s}' start=0x{x:0>8} end=0x{x:0>8}", .{ name, start, start + data.len });
2625 try writer.writeAll(data);
26172626
2618 try writeCustomSectionHeader(2627 try writeCustomSectionHeader(
2619 file,2628 binary_bytes.items,
2620 header_offset,2629 header_offset,
2621 @intCast(u32, (try file.getPos()) - header_offset - 6),2630 @intCast(u32, binary_bytes.items.len - header_offset - 6),
2622 );2631 );
2623}2632}
26242633
2625fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {2634fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {
2626 const Name = struct {2635 const Name = struct {
2627 index: u32,2636 index: u32,
2628 name: []const u8,2637 name: []const u8,
...@@ -2635,15 +2644,15 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -2635,15 +2644,15 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
26352644
2636 // we must de-duplicate symbols that point to the same function2645 // we must de-duplicate symbols that point to the same function
2637 var funcs = std.AutoArrayHashMap(u32, Name).init(arena);2646 var funcs = std.AutoArrayHashMap(u32, Name).init(arena);
2638 try funcs.ensureUnusedCapacity(self.functions.count() + self.imported_functions_count);2647 try funcs.ensureUnusedCapacity(wasm.functions.count() + wasm.imported_functions_count);
2639 var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count);2648 var globals = try std.ArrayList(Name).initCapacity(arena, wasm.wasm_globals.items.len + wasm.imported_globals_count);
2640 var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count());2649 var segments = try std.ArrayList(Name).initCapacity(arena, wasm.data_segments.count());
26412650
2642 for (self.resolved_symbols.keys()) |sym_loc| {2651 for (wasm.resolved_symbols.keys()) |sym_loc| {
2643 const symbol = sym_loc.getSymbol(self).*;2652 const symbol = sym_loc.getSymbol(wasm).*;
2644 const name = if (symbol.isUndefined()) blk: {2653 const name = if (symbol.isUndefined()) blk: {
2645 break :blk self.string_table.get(self.imports.get(sym_loc).?.name);2654 break :blk wasm.string_table.get(wasm.imports.get(sym_loc).?.name);
2646 } else sym_loc.getName(self);2655 } else sym_loc.getName(wasm);
2647 switch (symbol.tag) {2656 switch (symbol.tag) {
2648 .function => {2657 .function => {
2649 const gop = funcs.getOrPutAssumeCapacity(symbol.index);2658 const gop = funcs.getOrPutAssumeCapacity(symbol.index);
...@@ -2657,10 +2666,10 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -2657,10 +2666,10 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
2657 }2666 }
2658 // data segments are already 'ordered'2667 // data segments are already 'ordered'
2659 var data_segment_index: u32 = 0;2668 var data_segment_index: u32 = 0;
2660 for (self.data_segments.keys()) |key| {2669 for (wasm.data_segments.keys()) |key| {
2661 // bss section is not emitted when this condition holds true, so we also2670 // bss section is not emitted when this condition holds true, so we also
2662 // do not output a name for it.2671 // do not output a name for it.
2663 if (!self.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;2672 if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
2664 segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });2673 segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
2665 data_segment_index += 1;2674 data_segment_index += 1;
2666 }2675 }
...@@ -2668,25 +2677,25 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -2668,25 +2677,25 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
2668 std.sort.sort(Name, funcs.values(), {}, Name.lessThan);2677 std.sort.sort(Name, funcs.values(), {}, Name.lessThan);
2669 std.sort.sort(Name, globals.items, {}, Name.lessThan);2678 std.sort.sort(Name, globals.items, {}, Name.lessThan);
26702679
2671 const header_offset = try reserveCustomSectionHeader(file);2680 const header_offset = try reserveCustomSectionHeader(binary_bytes);
2672 const writer = file.writer();2681 const writer = binary_bytes.writer();
2673 try leb.writeULEB128(writer, @intCast(u32, "name".len));2682 try leb.writeULEB128(writer, @intCast(u32, "name".len));
2674 try writer.writeAll("name");2683 try writer.writeAll("name");
26752684
2676 try self.emitNameSubsection(.function, funcs.values(), writer);2685 try wasm.emitNameSubsection(.function, funcs.values(), writer);
2677 try self.emitNameSubsection(.global, globals.items, writer);2686 try wasm.emitNameSubsection(.global, globals.items, writer);
2678 try self.emitNameSubsection(.data_segment, segments.items, writer);2687 try wasm.emitNameSubsection(.data_segment, segments.items, writer);
26792688
2680 try writeCustomSectionHeader(2689 try writeCustomSectionHeader(
2681 file,2690 binary_bytes.items,
2682 header_offset,2691 header_offset,
2683 @intCast(u32, (try file.getPos()) - header_offset - 6),2692 @intCast(u32, binary_bytes.items.len - header_offset - 6),
2684 );2693 );
2685}2694}
26862695
2687fn emitNameSubsection(self: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {2696fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {
2688 // We must emit subsection size, so first write to a temporary list2697 // We must emit subsection size, so first write to a temporary list
2689 var section_list = std.ArrayList(u8).init(self.base.allocator);2698 var section_list = std.ArrayList(u8).init(wasm.base.allocator);
2690 defer section_list.deinit();2699 defer section_list.deinit();
2691 const sub_writer = section_list.writer();2700 const sub_writer = section_list.writer();
26922701
...@@ -2704,7 +2713,7 @@ fn emitNameSubsection(self: *Wasm, section_id: std.wasm.NameSubsection, names: a...@@ -2704,7 +2713,7 @@ fn emitNameSubsection(self: *Wasm, section_id: std.wasm.NameSubsection, names: a
2704 try writer.writeAll(section_list.items);2713 try writer.writeAll(section_list.items);
2705}2714}
27062715
2707fn emitLimits(writer: anytype, limits: wasm.Limits) !void {2716fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void {
2708 try leb.writeULEB128(writer, @boolToInt(limits.max != null));2717 try leb.writeULEB128(writer, @boolToInt(limits.max != null));
2709 try leb.writeULEB128(writer, limits.min);2718 try leb.writeULEB128(writer, limits.min);
2710 if (limits.max) |max| {2719 if (limits.max) |max| {
...@@ -2712,38 +2721,38 @@ fn emitLimits(writer: anytype, limits: wasm.Limits) !void {...@@ -2712,38 +2721,38 @@ fn emitLimits(writer: anytype, limits: wasm.Limits) !void {
2712 }2721 }
2713}2722}
27142723
2715fn emitInit(writer: anytype, init_expr: wasm.InitExpression) !void {2724fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
2716 switch (init_expr) {2725 switch (init_expr) {
2717 .i32_const => |val| {2726 .i32_const => |val| {
2718 try writer.writeByte(wasm.opcode(.i32_const));2727 try writer.writeByte(std.wasm.opcode(.i32_const));
2719 try leb.writeILEB128(writer, val);2728 try leb.writeILEB128(writer, val);
2720 },2729 },
2721 .i64_const => |val| {2730 .i64_const => |val| {
2722 try writer.writeByte(wasm.opcode(.i64_const));2731 try writer.writeByte(std.wasm.opcode(.i64_const));
2723 try leb.writeILEB128(writer, val);2732 try leb.writeILEB128(writer, val);
2724 },2733 },
2725 .f32_const => |val| {2734 .f32_const => |val| {
2726 try writer.writeByte(wasm.opcode(.f32_const));2735 try writer.writeByte(std.wasm.opcode(.f32_const));
2727 try writer.writeIntLittle(u32, @bitCast(u32, val));2736 try writer.writeIntLittle(u32, @bitCast(u32, val));
2728 },2737 },
2729 .f64_const => |val| {2738 .f64_const => |val| {
2730 try writer.writeByte(wasm.opcode(.f64_const));2739 try writer.writeByte(std.wasm.opcode(.f64_const));
2731 try writer.writeIntLittle(u64, @bitCast(u64, val));2740 try writer.writeIntLittle(u64, @bitCast(u64, val));
2732 },2741 },
2733 .global_get => |val| {2742 .global_get => |val| {
2734 try writer.writeByte(wasm.opcode(.global_get));2743 try writer.writeByte(std.wasm.opcode(.global_get));
2735 try leb.writeULEB128(writer, val);2744 try leb.writeULEB128(writer, val);
2736 },2745 },
2737 }2746 }
2738 try writer.writeByte(wasm.opcode(.end));2747 try writer.writeByte(std.wasm.opcode(.end));
2739}2748}
27402749
2741fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void {2750fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void {
2742 const module_name = self.string_table.get(import.module_name);2751 const module_name = wasm.string_table.get(import.module_name);
2743 try leb.writeULEB128(writer, @intCast(u32, module_name.len));2752 try leb.writeULEB128(writer, @intCast(u32, module_name.len));
2744 try writer.writeAll(module_name);2753 try writer.writeAll(module_name);
27452754
2746 const name = self.string_table.get(import.name);2755 const name = wasm.string_table.get(import.name);
2747 try leb.writeULEB128(writer, @intCast(u32, name.len));2756 try leb.writeULEB128(writer, @intCast(u32, name.len));
2748 try writer.writeAll(name);2757 try writer.writeAll(name);
27492758
...@@ -2751,11 +2760,11 @@ fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void {...@@ -2751,11 +2760,11 @@ fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void {
2751 switch (import.kind) {2760 switch (import.kind) {
2752 .function => |type_index| try leb.writeULEB128(writer, type_index),2761 .function => |type_index| try leb.writeULEB128(writer, type_index),
2753 .global => |global_type| {2762 .global => |global_type| {
2754 try leb.writeULEB128(writer, wasm.valtype(global_type.valtype));2763 try leb.writeULEB128(writer, std.wasm.valtype(global_type.valtype));
2755 try writer.writeByte(@boolToInt(global_type.mutable));2764 try writer.writeByte(@boolToInt(global_type.mutable));
2756 },2765 },
2757 .table => |table| {2766 .table => |table| {
2758 try leb.writeULEB128(writer, wasm.reftype(table.reftype));2767 try leb.writeULEB128(writer, std.wasm.reftype(table.reftype));
2759 try emitLimits(writer, table.limits);2768 try emitLimits(writer, table.limits);
2760 },2769 },
2761 .memory => |limits| {2770 .memory => |limits| {
...@@ -2764,28 +2773,28 @@ fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void {...@@ -2764,28 +2773,28 @@ fn emitImport(self: *Wasm, writer: anytype, import: types.Import) !void {
2764 }2773 }
2765}2774}
27662775
2767fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {2776fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
2768 const tracy = trace(@src());2777 const tracy = trace(@src());
2769 defer tracy.end();2778 defer tracy.end();
27702779
2771 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);2780 var arena_allocator = std.heap.ArenaAllocator.init(wasm.base.allocator);
2772 defer arena_allocator.deinit();2781 defer arena_allocator.deinit();
2773 const arena = arena_allocator.allocator();2782 const arena = arena_allocator.allocator();
27742783
2775 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.2784 const directory = wasm.base.options.emit.?.directory; // Just an alias to make it shorter to type.
2776 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});2785 const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.options.emit.?.sub_path});
27772786
2778 // If there is no Zig code to compile, then we should skip flushing the output file because it2787 // If there is no Zig code to compile, then we should skip flushing the output file because it
2779 // will not be part of the linker line anyway.2788 // will not be part of the linker line anyway.
2780 const module_obj_path: ?[]const u8 = if (self.base.options.module) |mod| blk: {2789 const module_obj_path: ?[]const u8 = if (wasm.base.options.module) |mod| blk: {
2781 const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1;2790 const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1;
2782 if (use_stage1) {2791 if (use_stage1) {
2783 const obj_basename = try std.zig.binNameAlloc(arena, .{2792 const obj_basename = try std.zig.binNameAlloc(arena, .{
2784 .root_name = self.base.options.root_name,2793 .root_name = wasm.base.options.root_name,
2785 .target = self.base.options.target,2794 .target = wasm.base.options.target,
2786 .output_mode = .Obj,2795 .output_mode = .Obj,
2787 });2796 });
2788 switch (self.base.options.cache_mode) {2797 switch (wasm.base.options.cache_mode) {
2789 .incremental => break :blk try mod.zig_cache_artifact_directory.join(2798 .incremental => break :blk try mod.zig_cache_artifact_directory.join(
2790 arena,2799 arena,
2791 &[_][]const u8{obj_basename},2800 &[_][]const u8{obj_basename},
...@@ -2796,12 +2805,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2796,12 +2805,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2796 }2805 }
2797 }2806 }
27982807
2799 try self.flushModule(comp, prog_node);2808 try wasm.flushModule(comp, prog_node);
28002809
2801 if (fs.path.dirname(full_out_path)) |dirname| {2810 if (fs.path.dirname(full_out_path)) |dirname| {
2802 break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? });2811 break :blk try fs.path.join(arena, &.{ dirname, wasm.base.intermediary_basename.? });
2803 } else {2812 } else {
2804 break :blk self.base.intermediary_basename.?;2813 break :blk wasm.base.intermediary_basename.?;
2805 }2814 }
2806 } else null;2815 } else null;
28072816
...@@ -2810,31 +2819,31 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2810,31 +2819,31 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2810 sub_prog_node.context.refresh();2819 sub_prog_node.context.refresh();
2811 defer sub_prog_node.end();2820 defer sub_prog_node.end();
28122821
2813 const is_obj = self.base.options.output_mode == .Obj;2822 const is_obj = wasm.base.options.output_mode == .Obj;
28142823
2815 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj)2824 const compiler_rt_path: ?[]const u8 = if (wasm.base.options.include_compiler_rt and !is_obj)
2816 comp.compiler_rt_lib.?.full_object_path2825 comp.compiler_rt_lib.?.full_object_path
2817 else2826 else
2818 null;2827 null;
28192828
2820 const target = self.base.options.target;2829 const target = wasm.base.options.target;
28212830
2822 const id_symlink_basename = "lld.id";2831 const id_symlink_basename = "lld.id";
28232832
2824 var man: Cache.Manifest = undefined;2833 var man: Cache.Manifest = undefined;
2825 defer if (!self.base.options.disable_lld_caching) man.deinit();2834 defer if (!wasm.base.options.disable_lld_caching) man.deinit();
28262835
2827 var digest: [Cache.hex_digest_len]u8 = undefined;2836 var digest: [Cache.hex_digest_len]u8 = undefined;
28282837
2829 if (!self.base.options.disable_lld_caching) {2838 if (!wasm.base.options.disable_lld_caching) {
2830 man = comp.cache_parent.obtain();2839 man = comp.cache_parent.obtain();
28312840
2832 // We are about to obtain this lock, so here we give other processes a chance first.2841 // We are about to obtain this lock, so here we give other processes a chance first.
2833 self.base.releaseLock();2842 wasm.base.releaseLock();
28342843
2835 comptime assert(Compilation.link_hash_implementation_version == 7);2844 comptime assert(Compilation.link_hash_implementation_version == 7);
28362845
2837 for (self.base.options.objects) |obj| {2846 for (wasm.base.options.objects) |obj| {
2838 _ = try man.addFile(obj.path, null);2847 _ = try man.addFile(obj.path, null);
2839 man.hash.add(obj.must_link);2848 man.hash.add(obj.must_link);
2840 }2849 }
...@@ -2843,18 +2852,18 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2843,18 +2852,18 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2843 }2852 }
2844 try man.addOptionalFile(module_obj_path);2853 try man.addOptionalFile(module_obj_path);
2845 try man.addOptionalFile(compiler_rt_path);2854 try man.addOptionalFile(compiler_rt_path);
2846 man.hash.addOptionalBytes(self.base.options.entry);2855 man.hash.addOptionalBytes(wasm.base.options.entry);
2847 man.hash.addOptional(self.base.options.stack_size_override);2856 man.hash.addOptional(wasm.base.options.stack_size_override);
2848 man.hash.add(self.base.options.import_memory);2857 man.hash.add(wasm.base.options.import_memory);
2849 man.hash.add(self.base.options.import_table);2858 man.hash.add(wasm.base.options.import_table);
2850 man.hash.add(self.base.options.export_table);2859 man.hash.add(wasm.base.options.export_table);
2851 man.hash.addOptional(self.base.options.initial_memory);2860 man.hash.addOptional(wasm.base.options.initial_memory);
2852 man.hash.addOptional(self.base.options.max_memory);2861 man.hash.addOptional(wasm.base.options.max_memory);
2853 man.hash.add(self.base.options.shared_memory);2862 man.hash.add(wasm.base.options.shared_memory);
2854 man.hash.addOptional(self.base.options.global_base);2863 man.hash.addOptional(wasm.base.options.global_base);
2855 man.hash.add(self.base.options.export_symbol_names.len);2864 man.hash.add(wasm.base.options.export_symbol_names.len);
2856 // strip does not need to go into the linker hash because it is part of the hash namespace2865 // strip does not need to go into the linker hash because it is part of the hash namespace
2857 for (self.base.options.export_symbol_names) |symbol_name| {2866 for (wasm.base.options.export_symbol_names) |symbol_name| {
2858 man.hash.addBytes(symbol_name);2867 man.hash.addBytes(symbol_name);
2859 }2868 }
28602869
...@@ -2875,7 +2884,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2875,7 +2884,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2875 if (mem.eql(u8, prev_digest, &digest)) {2884 if (mem.eql(u8, prev_digest, &digest)) {
2876 log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});2885 log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
2877 // Hot diggity dog! The output binary is already there.2886 // Hot diggity dog! The output binary is already there.
2878 self.base.lock = man.toOwnedLock();2887 wasm.base.lock = man.toOwnedLock();
2879 return;2888 return;
2880 }2889 }
2881 log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });2890 log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
...@@ -2892,8 +2901,8 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2892,8 +2901,8 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2892 // here. TODO: think carefully about how we can avoid this redundant operation when doing2901 // here. TODO: think carefully about how we can avoid this redundant operation when doing
2893 // build-obj. See also the corresponding TODO in linkAsArchive.2902 // build-obj. See also the corresponding TODO in linkAsArchive.
2894 const the_object_path = blk: {2903 const the_object_path = blk: {
2895 if (self.base.options.objects.len != 0)2904 if (wasm.base.options.objects.len != 0)
2896 break :blk self.base.options.objects[0].path;2905 break :blk wasm.base.options.objects[0].path;
28972906
2898 if (comp.c_object_table.count() != 0)2907 if (comp.c_object_table.count() != 0)
2899 break :blk comp.c_object_table.keys()[0].status.success.object_path;2908 break :blk comp.c_object_table.keys()[0].status.success.object_path;
...@@ -2912,7 +2921,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2912,7 +2921,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2912 }2921 }
2913 } else {2922 } else {
2914 // Create an LLD command line and invoke it.2923 // Create an LLD command line and invoke it.
2915 var argv = std.ArrayList([]const u8).init(self.base.allocator);2924 var argv = std.ArrayList([]const u8).init(wasm.base.allocator);
2916 defer argv.deinit();2925 defer argv.deinit();
2917 // We will invoke ourselves as a child process to gain access to LLD.2926 // We will invoke ourselves as a child process to gain access to LLD.
2918 // This is necessary because LLD does not behave properly as a library -2927 // This is necessary because LLD does not behave properly as a library -
...@@ -2920,47 +2929,47 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2920,47 +2929,47 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2920 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" });2929 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" });
2921 try argv.append("-error-limit=0");2930 try argv.append("-error-limit=0");
29222931
2923 if (self.base.options.lto) {2932 if (wasm.base.options.lto) {
2924 switch (self.base.options.optimize_mode) {2933 switch (wasm.base.options.optimize_mode) {
2925 .Debug => {},2934 .Debug => {},
2926 .ReleaseSmall => try argv.append("-O2"),2935 .ReleaseSmall => try argv.append("-O2"),
2927 .ReleaseFast, .ReleaseSafe => try argv.append("-O3"),2936 .ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
2928 }2937 }
2929 }2938 }
29302939
2931 if (self.base.options.import_memory) {2940 if (wasm.base.options.import_memory) {
2932 try argv.append("--import-memory");2941 try argv.append("--import-memory");
2933 }2942 }
29342943
2935 if (self.base.options.import_table) {2944 if (wasm.base.options.import_table) {
2936 assert(!self.base.options.export_table);2945 assert(!wasm.base.options.export_table);
2937 try argv.append("--import-table");2946 try argv.append("--import-table");
2938 }2947 }
29392948
2940 if (self.base.options.export_table) {2949 if (wasm.base.options.export_table) {
2941 assert(!self.base.options.import_table);2950 assert(!wasm.base.options.import_table);
2942 try argv.append("--export-table");2951 try argv.append("--export-table");
2943 }2952 }
29442953
2945 if (self.base.options.strip) {2954 if (wasm.base.options.strip) {
2946 try argv.append("-s");2955 try argv.append("-s");
2947 }2956 }
29482957
2949 if (self.base.options.initial_memory) |initial_memory| {2958 if (wasm.base.options.initial_memory) |initial_memory| {
2950 const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});2959 const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});
2951 try argv.append(arg);2960 try argv.append(arg);
2952 }2961 }
29532962
2954 if (self.base.options.max_memory) |max_memory| {2963 if (wasm.base.options.max_memory) |max_memory| {
2955 const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory});2964 const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory});
2956 try argv.append(arg);2965 try argv.append(arg);
2957 }2966 }
29582967
2959 if (self.base.options.shared_memory) {2968 if (wasm.base.options.shared_memory) {
2960 try argv.append("--shared-memory");2969 try argv.append("--shared-memory");
2961 }2970 }
29622971
2963 if (self.base.options.global_base) |global_base| {2972 if (wasm.base.options.global_base) |global_base| {
2964 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});2973 const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
2965 try argv.append(arg);2974 try argv.append(arg);
2966 } else {2975 } else {
...@@ -2973,29 +2982,29 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2973,29 +2982,29 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
29732982
2974 var auto_export_symbols = true;2983 var auto_export_symbols = true;
2975 // Users are allowed to specify which symbols they want to export to the wasm host.2984 // Users are allowed to specify which symbols they want to export to the wasm host.
2976 for (self.base.options.export_symbol_names) |symbol_name| {2985 for (wasm.base.options.export_symbol_names) |symbol_name| {
2977 const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});2986 const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
2978 try argv.append(arg);2987 try argv.append(arg);
2979 auto_export_symbols = false;2988 auto_export_symbols = false;
2980 }2989 }
29812990
2982 if (self.base.options.rdynamic) {2991 if (wasm.base.options.rdynamic) {
2983 try argv.append("--export-dynamic");2992 try argv.append("--export-dynamic");
2984 auto_export_symbols = false;2993 auto_export_symbols = false;
2985 }2994 }
29862995
2987 if (auto_export_symbols) {2996 if (auto_export_symbols) {
2988 if (self.base.options.module) |mod| {2997 if (wasm.base.options.module) |mod| {
2989 // when we use stage1, we use the exports that stage1 provided us.2998 // when we use stage1, we use the exports that stage1 provided us.
2990 // For stage2, we can directly retrieve them from the module.2999 // For stage2, we can directly retrieve them from the module.
2991 const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1;3000 const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1;
2992 if (use_stage1) {3001 if (use_stage1) {
2993 for (comp.export_symbol_names.items) |symbol_name| {3002 for (comp.export_symbol_names.items) |symbol_name| {
2994 try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));3003 try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));
2995 }3004 }
2996 } else {3005 } else {
2997 const skip_export_non_fn = target.os.tag == .wasi and3006 const skip_export_non_fn = target.os.tag == .wasi and
2998 self.base.options.wasi_exec_model == .command;3007 wasm.base.options.wasi_exec_model == .command;
2999 for (mod.decl_exports.values()) |exports| {3008 for (mod.decl_exports.values()) |exports| {
3000 for (exports) |exprt| {3009 for (exports) |exprt| {
3001 const exported_decl = mod.declPtr(exprt.exported_decl);3010 const exported_decl = mod.declPtr(exprt.exported_decl);
...@@ -3013,7 +3022,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3013,7 +3022,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3013 }3022 }
3014 }3023 }
30153024
3016 if (self.base.options.entry) |entry| {3025 if (wasm.base.options.entry) |entry| {
3017 try argv.append("--entry");3026 try argv.append("--entry");
3018 try argv.append(entry);3027 try argv.append(entry);
3019 }3028 }
...@@ -3021,16 +3030,16 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3021,16 +3030,16 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3021 // Increase the default stack size to a more reasonable value of 1MB instead of3030 // Increase the default stack size to a more reasonable value of 1MB instead of
3022 // the default of 1 Wasm page being 64KB, unless overridden by the user.3031 // the default of 1 Wasm page being 64KB, unless overridden by the user.
3023 try argv.append("-z");3032 try argv.append("-z");
3024 const stack_size = self.base.options.stack_size_override orelse wasm.page_size * 16;3033 const stack_size = wasm.base.options.stack_size_override orelse std.wasm.page_size * 16;
3025 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});3034 const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
3026 try argv.append(arg);3035 try argv.append(arg);
30273036
3028 if (self.base.options.output_mode == .Exe) {3037 if (wasm.base.options.output_mode == .Exe) {
3029 if (self.base.options.wasi_exec_model == .reactor) {3038 if (wasm.base.options.wasi_exec_model == .reactor) {
3030 // Reactor execution model does not have _start so lld doesn't look for it.3039 // Reactor execution model does not have _start so lld doesn't look for it.
3031 try argv.append("--no-entry");3040 try argv.append("--no-entry");
3032 }3041 }
3033 } else if (self.base.options.entry == null) {3042 } else if (wasm.base.options.entry == null) {
3034 try argv.append("--no-entry"); // So lld doesn't look for _start.3043 try argv.append("--no-entry"); // So lld doesn't look for _start.
3035 }3044 }
3036 try argv.appendSlice(&[_][]const u8{3045 try argv.appendSlice(&[_][]const u8{
...@@ -3044,10 +3053,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3044,10 +3053,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3044 }3053 }
30453054
3046 if (target.os.tag == .wasi) {3055 if (target.os.tag == .wasi) {
3047 const is_exe_or_dyn_lib = self.base.options.output_mode == .Exe or3056 const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or
3048 (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic);3057 (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic);
3049 if (is_exe_or_dyn_lib) {3058 if (is_exe_or_dyn_lib) {
3050 const wasi_emulated_libs = self.base.options.wasi_emulated_libs;3059 const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs;
3051 for (wasi_emulated_libs) |crt_file| {3060 for (wasi_emulated_libs) |crt_file| {
3052 try argv.append(try comp.get_libc_crt_file(3061 try argv.append(try comp.get_libc_crt_file(
3053 arena,3062 arena,
...@@ -3055,15 +3064,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3055,15 +3064,15 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3055 ));3064 ));
3056 }3065 }
30573066
3058 if (self.base.options.link_libc) {3067 if (wasm.base.options.link_libc) {
3059 try argv.append(try comp.get_libc_crt_file(3068 try argv.append(try comp.get_libc_crt_file(
3060 arena,3069 arena,
3061 wasi_libc.execModelCrtFileFullName(self.base.options.wasi_exec_model),3070 wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model),
3062 ));3071 ));
3063 try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));3072 try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
3064 }3073 }
30653074
3066 if (self.base.options.link_libcpp) {3075 if (wasm.base.options.link_libcpp) {
3067 try argv.append(comp.libcxx_static_lib.?.full_object_path);3076 try argv.append(comp.libcxx_static_lib.?.full_object_path);
3068 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);3077 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
3069 }3078 }
...@@ -3072,7 +3081,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3072,7 +3081,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
30723081
3073 // Positional arguments to the linker such as object files.3082 // Positional arguments to the linker such as object files.
3074 var whole_archive = false;3083 var whole_archive = false;
3075 for (self.base.options.objects) |obj| {3084 for (wasm.base.options.objects) |obj| {
3076 if (obj.must_link and !whole_archive) {3085 if (obj.must_link and !whole_archive) {
3077 try argv.append("-whole-archive");3086 try argv.append("-whole-archive");
3078 whole_archive = true;3087 whole_archive = true;
...@@ -3094,9 +3103,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3094,9 +3103,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3094 try argv.append(p);3103 try argv.append(p);
3095 }3104 }
30963105
3097 if (self.base.options.output_mode != .Obj and3106 if (wasm.base.options.output_mode != .Obj and
3098 !self.base.options.skip_linker_dependencies and3107 !wasm.base.options.skip_linker_dependencies and
3099 !self.base.options.link_libc)3108 !wasm.base.options.link_libc)
3100 {3109 {
3101 try argv.append(comp.libc_static_lib.?.full_object_path);3110 try argv.append(comp.libc_static_lib.?.full_object_path);
3102 }3111 }
...@@ -3105,7 +3114,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3105,7 +3114,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3105 try argv.append(p);3114 try argv.append(p);
3106 }3115 }
31073116
3108 if (self.base.options.verbose_link) {3117 if (wasm.base.options.verbose_link) {
3109 // Skip over our own name so that the LLD linker name is the first argv item.3118 // Skip over our own name so that the LLD linker name is the first argv item.
3110 Compilation.dump_argv(argv.items[1..]);3119 Compilation.dump_argv(argv.items[1..]);
3111 }3120 }
...@@ -3122,7 +3131,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3122,7 +3131,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
31223131
3123 const term = child.spawnAndWait() catch |err| {3132 const term = child.spawnAndWait() catch |err| {
3124 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });3133 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
3125 return error.UnableToSpawnSelf;3134 return error.UnableToSpawnwasm;
3126 };3135 };
3127 switch (term) {3136 switch (term) {
3128 .Exited => |code| {3137 .Exited => |code| {
...@@ -3143,7 +3152,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3143,7 +3152,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
31433152
3144 const term = child.wait() catch |err| {3153 const term = child.wait() catch |err| {
3145 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });3154 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
3146 return error.UnableToSpawnSelf;3155 return error.UnableToSpawnwasm;
3147 };3156 };
31483157
3149 switch (term) {3158 switch (term) {
...@@ -3177,7 +3186,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3177,7 +3186,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3177 }3186 }
3178 }3187 }
31793188
3180 if (!self.base.options.disable_lld_caching) {3189 if (!wasm.base.options.disable_lld_caching) {
3181 // Update the file with the digest. If it fails we can continue; it only3190 // Update the file with the digest. If it fails we can continue; it only
3182 // means that the next invocation will have an unnecessary cache miss.3191 // means that the next invocation will have an unnecessary cache miss.
3183 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {3192 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
...@@ -3189,58 +3198,44 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -3189,58 +3198,44 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
3189 };3198 };
3190 // We hang on to this lock so that the output file path can be used without3199 // We hang on to this lock so that the output file path can be used without
3191 // other processes clobbering it.3200 // other processes clobbering it.
3192 self.base.lock = man.toOwnedLock();3201 wasm.base.lock = man.toOwnedLock();
3193 }3202 }
3194}3203}
31953204
3196fn reserveVecSectionHeader(file: fs.File) !u64 {3205fn reserveVecSectionHeader(bytes: *std.ArrayList(u8)) !u32 {
3197 // section id + fixed leb contents size + fixed leb vector length3206 // section id + fixed leb contents size + fixed leb vector length
3198 const header_size = 1 + 5 + 5;3207 const header_size = 1 + 5 + 5;
3199 // TODO: this should be a single lseek(2) call, but fs.File does not3208 const offset = @intCast(u32, bytes.items.len);
3200 // currently provide a way to do this.3209 try bytes.appendSlice(&[_]u8{0} ** header_size);
3201 try file.seekBy(header_size);3210 return offset;
3202 return (try file.getPos()) - header_size;
3203}3211}
32043212
3205fn reserveCustomSectionHeader(file: fs.File) !u64 {3213fn reserveCustomSectionHeader(bytes: *std.ArrayList(u8)) !u32 {
3206 // unlike regular section, we don't emit the count3214 // unlike regular section, we don't emit the count
3207 const header_size = 1 + 5;3215 const header_size = 1 + 5;
3208 // TODO: this should be a single lseek(2) call, but fs.File does not3216 const offset = @intCast(u32, bytes.items.len);
3209 // currently provide a way to do this.3217 try bytes.appendSlice(&[_]u8{0} ** header_size);
3210 try file.seekBy(header_size);3218 return offset;
3211 return (try file.getPos()) - header_size;
3212}3219}
32133220
3214fn writeVecSectionHeader(file: fs.File, offset: u64, section: wasm.Section, size: u32, items: u32) !void {3221fn writeVecSectionHeader(buffer: []u8, offset: u32, section: std.wasm.Section, size: u32, items: u32) !void {
3215 var buf: [1 + 5 + 5]u8 = undefined;3222 var buf: [1 + 5 + 5]u8 = undefined;
3216 buf[0] = @enumToInt(section);3223 buf[0] = @enumToInt(section);
3217 leb.writeUnsignedFixed(5, buf[1..6], size);3224 leb.writeUnsignedFixed(5, buf[1..6], size);
3218 leb.writeUnsignedFixed(5, buf[6..], items);3225 leb.writeUnsignedFixed(5, buf[6..], items);
32193226 mem.copy(u8, buffer[offset..], &buf);
3220 if (builtin.target.os.tag == .windows) {
3221 // https://github.com/ziglang/zig/issues/12783
3222 const curr_pos = try file.getPos();
3223 try file.pwriteAll(&buf, offset);
3224 try file.seekTo(curr_pos);
3225 } else try file.pwriteAll(&buf, offset);
3226}3227}
32273228
3228fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void {3229fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void {
3229 var buf: [1 + 5]u8 = undefined;3230 var buf: [1 + 5]u8 = undefined;
3230 buf[0] = 0; // 0 = 'custom' section3231 buf[0] = 0; // 0 = 'custom' section
3231 leb.writeUnsignedFixed(5, buf[1..6], size);3232 leb.writeUnsignedFixed(5, buf[1..6], size);
32323233 mem.copy(u8, buffer[offset..], &buf);
3233 if (builtin.target.os.tag == .windows) {
3234 // https://github.com/ziglang/zig/issues/12783
3235 const curr_pos = try file.getPos();
3236 try file.pwriteAll(&buf, offset);
3237 try file.seekTo(curr_pos);
3238 } else try file.pwriteAll(&buf, offset);
3239}3234}
32403235
3241fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {3236fn emitLinkSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {
3242 const offset = try reserveCustomSectionHeader(file);3237 const offset = try reserveCustomSectionHeader(binary_bytes);
3243 const writer = file.writer();3238 const writer = binary_bytes.writer();
3244 // emit "linking" custom section name3239 // emit "linking" custom section name
3245 const section_name = "linking";3240 const section_name = "linking";
3246 try leb.writeULEB128(writer, section_name.len);3241 try leb.writeULEB128(writer, section_name.len);
...@@ -3251,25 +3246,22 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *...@@ -3251,25 +3246,22 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
32513246
3252 // For each subsection type (found in types.Subsection) we can emit a section.3247 // For each subsection type (found in types.Subsection) we can emit a section.
3253 // Currently, we only support emitting segment info and the symbol table.3248 // Currently, we only support emitting segment info and the symbol table.
3254 try self.emitSymbolTable(file, arena, symbol_table);3249 try wasm.emitSymbolTable(binary_bytes, symbol_table);
3255 try self.emitSegmentInfo(file, arena);3250 try wasm.emitSegmentInfo(binary_bytes);
32563251
3257 const size = @intCast(u32, (try file.getPos()) - offset - 6);3252 const size = @intCast(u32, binary_bytes.items.len - offset - 6);
3258 try writeCustomSectionHeader(file, offset, size);3253 try writeCustomSectionHeader(binary_bytes.items, offset, size);
3259}3254}
32603255
3261fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {3256fn emitSymbolTable(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void {
3262 // After emitting the subtype, we must emit the subsection's length3257 const writer = binary_bytes.writer();
3263 // so first write it to a temporary arraylist to calculate the length
3264 // and then write all data at once.
3265 var payload = std.ArrayList(u8).init(arena);
3266 const writer = payload.writer();
32673258
3268 try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE));3259 try leb.writeULEB128(writer, @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE));
3260 const table_offset = binary_bytes.items.len;
32693261
3270 var symbol_count: u32 = 0;3262 var symbol_count: u32 = 0;
3271 for (self.resolved_symbols.keys()) |sym_loc| {3263 for (wasm.resolved_symbols.keys()) |sym_loc| {
3272 const symbol = sym_loc.getSymbol(self).*;3264 const symbol = sym_loc.getSymbol(wasm).*;
3273 if (symbol.tag == .dead) continue; // Do not emit dead symbols3265 if (symbol.tag == .dead) continue; // Do not emit dead symbols
3274 try symbol_table.putNoClobber(sym_loc, symbol_count);3266 try symbol_table.putNoClobber(sym_loc, symbol_count);
3275 symbol_count += 1;3267 symbol_count += 1;
...@@ -3277,7 +3269,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *...@@ -3277,7 +3269,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
3277 try leb.writeULEB128(writer, @enumToInt(symbol.tag));3269 try leb.writeULEB128(writer, @enumToInt(symbol.tag));
3278 try leb.writeULEB128(writer, symbol.flags);3270 try leb.writeULEB128(writer, symbol.flags);
32793271
3280 const sym_name = if (self.export_names.get(sym_loc)) |exp_name| self.string_table.get(exp_name) else sym_loc.getName(self);3272 const sym_name = if (wasm.export_names.get(sym_loc)) |exp_name| wasm.string_table.get(exp_name) else sym_loc.getName(wasm);
3281 switch (symbol.tag) {3273 switch (symbol.tag) {
3282 .data => {3274 .data => {
3283 try leb.writeULEB128(writer, @intCast(u32, sym_name.len));3275 try leb.writeULEB128(writer, @intCast(u32, sym_name.len));
...@@ -3285,7 +3277,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *...@@ -3285,7 +3277,7 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
32853277
3286 if (symbol.isDefined()) {3278 if (symbol.isDefined()) {
3287 try leb.writeULEB128(writer, symbol.index);3279 try leb.writeULEB128(writer, symbol.index);
3288 const atom = self.symbol_atom.get(sym_loc).?;3280 const atom = wasm.symbol_atom.get(sym_loc).?;
3289 try leb.writeULEB128(writer, @as(u32, atom.offset));3281 try leb.writeULEB128(writer, @as(u32, atom.offset));
3290 try leb.writeULEB128(writer, @as(u32, atom.size));3282 try leb.writeULEB128(writer, @as(u32, atom.size));
3291 }3283 }
...@@ -3303,25 +3295,19 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *...@@ -3303,25 +3295,19 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *
3303 }3295 }
3304 }3296 }
33053297
3306 var buf: [5]u8 = undefined;3298 var buf: [10]u8 = undefined;
3307 leb.writeUnsignedFixed(5, &buf, symbol_count);3299 leb.writeUnsignedFixed(5, buf[0..5], @intCast(u32, binary_bytes.items.len - table_offset + 5));
3308 try payload.insertSlice(0, &buf);3300 leb.writeUnsignedFixed(5, buf[5..], symbol_count);
3309 try leb.writeULEB128(file.writer(), @intCast(u32, payload.items.len));3301 try binary_bytes.insertSlice(table_offset, &buf);
3310
3311 const iovec: std.os.iovec_const = .{
3312 .iov_base = payload.items.ptr,
3313 .iov_len = payload.items.len,
3314 };
3315 var iovecs = [_]std.os.iovec_const{iovec};
3316 try file.writevAll(&iovecs);
3317}3302}
33183303
3319fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {3304fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
3320 var payload = std.ArrayList(u8).init(arena);3305 const writer = binary_bytes.writer();
3321 const writer = payload.writer();3306 try leb.writeULEB128(writer, @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO));
3322 try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SEGMENT_INFO));3307 const segment_offset = binary_bytes.items.len;
3323 try leb.writeULEB128(writer, @intCast(u32, self.segment_info.count()));3308
3324 for (self.segment_info.values()) |segment_info| {3309 try leb.writeULEB128(writer, @intCast(u32, wasm.segment_info.count()));
3310 for (wasm.segment_info.values()) |segment_info| {
3325 log.debug("Emit segment: {s} align({d}) flags({b})", .{3311 log.debug("Emit segment: {s} align({d}) flags({b})", .{
3326 segment_info.name,3312 segment_info.name,
3327 @ctz(segment_info.alignment),3313 @ctz(segment_info.alignment),
...@@ -3333,13 +3319,9 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -3333,13 +3319,9 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {
3333 try leb.writeULEB128(writer, segment_info.flags);3319 try leb.writeULEB128(writer, segment_info.flags);
3334 }3320 }
33353321
3336 try leb.writeULEB128(file.writer(), @intCast(u32, payload.items.len));3322 var buf: [5]u8 = undefined;
3337 const iovec: std.os.iovec_const = .{3323 leb.writeUnsignedFixed(5, &buf, @intCast(u32, binary_bytes.items.len - segment_offset));
3338 .iov_base = payload.items.ptr,3324 try binary_bytes.insertSlice(segment_offset, &buf);
3339 .iov_len = payload.items.len,
3340 };
3341 var iovecs = [_]std.os.iovec_const{iovec};
3342 try file.writevAll(&iovecs);
3343}3325}
33443326
3345pub fn getULEB128Size(uint_value: anytype) u32 {3327pub fn getULEB128Size(uint_value: anytype) u32 {
...@@ -3356,25 +3338,24 @@ pub fn getULEB128Size(uint_value: anytype) u32 {...@@ -3356,25 +3338,24 @@ pub fn getULEB128Size(uint_value: anytype) u32 {
33563338
3357/// For each relocatable section, emits a custom "relocation.<section_name>" section3339/// For each relocatable section, emits a custom "relocation.<section_name>" section
3358fn emitCodeRelocations(3340fn emitCodeRelocations(
3359 self: *Wasm,3341 wasm: *Wasm,
3360 file: fs.File,3342 binary_bytes: *std.ArrayList(u8),
3361 arena: Allocator,
3362 section_index: u32,3343 section_index: u32,
3363 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),3344 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),
3364) !void {3345) !void {
3365 const code_index = self.code_section_index orelse return;3346 const code_index = wasm.code_section_index orelse return;
3366 var payload = std.ArrayList(u8).init(arena);3347 const writer = binary_bytes.writer();
3367 const writer = payload.writer();3348 const header_offset = try reserveCustomSectionHeader(binary_bytes);
33683349
3369 // write custom section information3350 // write custom section information
3370 const name = "reloc.CODE";3351 const name = "reloc.CODE";
3371 try leb.writeULEB128(writer, @intCast(u32, name.len));3352 try leb.writeULEB128(writer, @intCast(u32, name.len));
3372 try writer.writeAll(name);3353 try writer.writeAll(name);
3373 try leb.writeULEB128(writer, section_index);3354 try leb.writeULEB128(writer, section_index);
3374 const reloc_start = payload.items.len;3355 const reloc_start = binary_bytes.items.len;
33753356
3376 var count: u32 = 0;3357 var count: u32 = 0;
3377 var atom: *Atom = self.atoms.get(code_index).?.getFirst();3358 var atom: *Atom = wasm.atoms.get(code_index).?.getFirst();
3378 // for each atom, we calculate the uleb size and append that3359 // for each atom, we calculate the uleb size and append that
3379 var size_offset: u32 = 5; // account for code section size leb1283360 var size_offset: u32 = 5; // account for code section size leb128
3380 while (true) {3361 while (true) {
...@@ -3397,42 +3378,33 @@ fn emitCodeRelocations(...@@ -3397,42 +3378,33 @@ fn emitCodeRelocations(
3397 if (count == 0) return;3378 if (count == 0) return;
3398 var buf: [5]u8 = undefined;3379 var buf: [5]u8 = undefined;
3399 leb.writeUnsignedFixed(5, &buf, count);3380 leb.writeUnsignedFixed(5, &buf, count);
3400 try payload.insertSlice(reloc_start, &buf);3381 try binary_bytes.insertSlice(reloc_start, &buf);
3401 var iovecs = [_]std.os.iovec_const{3382 const size = @intCast(u32, binary_bytes.items.len - header_offset - 6);
3402 .{3383 try writeCustomSectionHeader(binary_bytes.items, header_offset, size);
3403 .iov_base = payload.items.ptr,
3404 .iov_len = payload.items.len,
3405 },
3406 };
3407 const header_offset = try reserveCustomSectionHeader(file);
3408 try file.writevAll(&iovecs);
3409 const size = @intCast(u32, payload.items.len);
3410 try writeCustomSectionHeader(file, header_offset, size);
3411}3384}
34123385
3413fn emitDataRelocations(3386fn emitDataRelocations(
3414 self: *Wasm,3387 wasm: *Wasm,
3415 file: fs.File,3388 binary_bytes: *std.ArrayList(u8),
3416 arena: Allocator,
3417 section_index: u32,3389 section_index: u32,
3418 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),3390 symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),
3419) !void {3391) !void {
3420 if (self.data_segments.count() == 0) return;3392 if (wasm.data_segments.count() == 0) return;
3421 var payload = std.ArrayList(u8).init(arena);3393 const writer = binary_bytes.writer();
3422 const writer = payload.writer();3394 const header_offset = try reserveCustomSectionHeader(binary_bytes);
34233395
3424 // write custom section information3396 // write custom section information
3425 const name = "reloc.DATA";3397 const name = "reloc.DATA";
3426 try leb.writeULEB128(writer, @intCast(u32, name.len));3398 try leb.writeULEB128(writer, @intCast(u32, name.len));
3427 try writer.writeAll(name);3399 try writer.writeAll(name);
3428 try leb.writeULEB128(writer, section_index);3400 try leb.writeULEB128(writer, section_index);
3429 const reloc_start = payload.items.len;3401 const reloc_start = binary_bytes.items.len;
34303402
3431 var count: u32 = 0;3403 var count: u32 = 0;
3432 // for each atom, we calculate the uleb size and append that3404 // for each atom, we calculate the uleb size and append that
3433 var size_offset: u32 = 5; // account for code section size leb1283405 var size_offset: u32 = 5; // account for code section size leb128
3434 for (self.data_segments.values()) |segment_index| {3406 for (wasm.data_segments.values()) |segment_index| {
3435 var atom: *Atom = self.atoms.get(segment_index).?.getFirst();3407 var atom: *Atom = wasm.atoms.get(segment_index).?.getFirst();
3436 while (true) {3408 while (true) {
3437 size_offset += getULEB128Size(atom.size);3409 size_offset += getULEB128Size(atom.size);
3438 for (atom.relocs.items) |relocation| {3410 for (atom.relocs.items) |relocation| {
...@@ -3458,33 +3430,25 @@ fn emitDataRelocations(...@@ -3458,33 +3430,25 @@ fn emitDataRelocations(
34583430
3459 var buf: [5]u8 = undefined;3431 var buf: [5]u8 = undefined;
3460 leb.writeUnsignedFixed(5, &buf, count);3432 leb.writeUnsignedFixed(5, &buf, count);
3461 try payload.insertSlice(reloc_start, &buf);3433 try binary_bytes.insertSlice(reloc_start, &buf);
3462 var iovecs = [_]std.os.iovec_const{3434 const size = @intCast(u32, binary_bytes.items.len - header_offset - 6);
3463 .{3435 try writeCustomSectionHeader(binary_bytes.items, header_offset, size);
3464 .iov_base = payload.items.ptr,
3465 .iov_len = payload.items.len,
3466 },
3467 };
3468 const header_offset = try reserveCustomSectionHeader(file);
3469 try file.writevAll(&iovecs);
3470 const size = @intCast(u32, payload.items.len);
3471 try writeCustomSectionHeader(file, header_offset, size);
3472}3436}
34733437
3474/// Searches for an a matching function signature, when not found3438/// Searches for an a matching function signature, when not found
3475/// a new entry will be made. The index of the existing/new signature will be returned.3439/// a new entry will be made. The index of the existing/new signature will be returned.
3476pub fn putOrGetFuncType(self: *Wasm, func_type: wasm.Type) !u32 {3440pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 {
3477 var index: u32 = 0;3441 var index: u32 = 0;
3478 while (index < self.func_types.items.len) : (index += 1) {3442 while (index < wasm.func_types.items.len) : (index += 1) {
3479 if (self.func_types.items[index].eql(func_type)) return index;3443 if (wasm.func_types.items[index].eql(func_type)) return index;
3480 }3444 }
34813445
3482 // functype does not exist.3446 // functype does not exist.
3483 const params = try self.base.allocator.dupe(wasm.Valtype, func_type.params);3447 const params = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.params);
3484 errdefer self.base.allocator.free(params);3448 errdefer wasm.base.allocator.free(params);
3485 const returns = try self.base.allocator.dupe(wasm.Valtype, func_type.returns);3449 const returns = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.returns);
3486 errdefer self.base.allocator.free(returns);3450 errdefer wasm.base.allocator.free(returns);
3487 try self.func_types.append(self.base.allocator, .{3451 try wasm.func_types.append(wasm.base.allocator, .{
3488 .params = params,3452 .params = params,
3489 .returns = returns,3453 .returns = returns,
3490 });3454 });
src/link/Wasm/Archive.zig-1
...@@ -4,7 +4,6 @@ const std = @import("std");...@@ -4,7 +4,6 @@ const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const fs = std.fs;5const fs = std.fs;
6const log = std.log.scoped(.archive);6const log = std.log.scoped(.archive);
7const macho = std.macho;
8const mem = std.mem;7const mem = std.mem;
98
10const Allocator = mem.Allocator;9const Allocator = mem.Allocator;
src/link/Wasm/Atom.zig+36-36
...@@ -55,37 +55,37 @@ pub const empty: Atom = .{...@@ -55,37 +55,37 @@ pub const empty: Atom = .{
55};55};
5656
57/// Frees all resources owned by this `Atom`.57/// Frees all resources owned by this `Atom`.
58pub fn deinit(self: *Atom, gpa: Allocator) void {58pub fn deinit(atom: *Atom, gpa: Allocator) void {
59 self.relocs.deinit(gpa);59 atom.relocs.deinit(gpa);
60 self.code.deinit(gpa);60 atom.code.deinit(gpa);
6161
62 for (self.locals.items) |*local| {62 for (atom.locals.items) |*local| {
63 local.deinit(gpa);63 local.deinit(gpa);
64 }64 }
65 self.locals.deinit(gpa);65 atom.locals.deinit(gpa);
66}66}
6767
68/// Sets the length of relocations and code to '0',68/// Sets the length of relocations and code to '0',
69/// effectively resetting them and allowing them to be re-populated.69/// effectively resetting them and allowing them to be re-populated.
70pub fn clear(self: *Atom) void {70pub fn clear(atom: *Atom) void {
71 self.relocs.clearRetainingCapacity();71 atom.relocs.clearRetainingCapacity();
72 self.code.clearRetainingCapacity();72 atom.code.clearRetainingCapacity();
73}73}
7474
75pub fn format(self: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {75pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
76 _ = fmt;76 _ = fmt;
77 _ = options;77 _ = options;
78 try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{78 try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{
79 self.sym_index,79 atom.sym_index,
80 self.alignment,80 atom.alignment,
81 self.size,81 atom.size,
82 self.offset,82 atom.offset,
83 });83 });
84}84}
8585
86/// Returns the first `Atom` from a given atom86/// Returns the first `Atom` from a given atom
87pub fn getFirst(self: *Atom) *Atom {87pub fn getFirst(atom: *Atom) *Atom {
88 var tmp = self;88 var tmp = atom;
89 while (tmp.prev) |prev| tmp = prev;89 while (tmp.prev) |prev| tmp = prev;
90 return tmp;90 return tmp;
91}91}
...@@ -94,9 +94,9 @@ pub fn getFirst(self: *Atom) *Atom {...@@ -94,9 +94,9 @@ pub fn getFirst(self: *Atom) *Atom {
94/// produced from Zig code, rather than an object file.94/// produced from Zig code, rather than an object file.
95/// This is useful for debug sections where we want to extend95/// This is useful for debug sections where we want to extend
96/// the bytes, and don't want to overwrite existing Atoms.96/// the bytes, and don't want to overwrite existing Atoms.
97pub fn getFirstZigAtom(self: *Atom) *Atom {97pub fn getFirstZigAtom(atom: *Atom) *Atom {
98 if (self.file == null) return self;98 if (atom.file == null) return atom;
99 var tmp = self;99 var tmp = atom;
100 return while (tmp.prev) |prev| {100 return while (tmp.prev) |prev| {
101 if (prev.file == null) break prev;101 if (prev.file == null) break prev;
102 tmp = prev;102 tmp = prev;
...@@ -104,24 +104,24 @@ pub fn getFirstZigAtom(self: *Atom) *Atom {...@@ -104,24 +104,24 @@ pub fn getFirstZigAtom(self: *Atom) *Atom {
104}104}
105105
106/// Returns the location of the symbol that represents this `Atom`106/// Returns the location of the symbol that represents this `Atom`
107pub fn symbolLoc(self: Atom) Wasm.SymbolLoc {107pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
108 return .{ .file = self.file, .index = self.sym_index };108 return .{ .file = atom.file, .index = atom.sym_index };
109}109}
110110
111/// Resolves the relocations within the atom, writing the new value111/// Resolves the relocations within the atom, writing the new value
112/// at the calculated offset.112/// at the calculated offset.
113pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {113pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
114 if (self.relocs.items.len == 0) return;114 if (atom.relocs.items.len == 0) return;
115 const symbol_name = self.symbolLoc().getName(wasm_bin);115 const symbol_name = atom.symbolLoc().getName(wasm_bin);
116 log.debug("Resolving relocs in atom '{s}' count({d})", .{116 log.debug("Resolving relocs in atom '{s}' count({d})", .{
117 symbol_name,117 symbol_name,
118 self.relocs.items.len,118 atom.relocs.items.len,
119 });119 });
120120
121 for (self.relocs.items) |reloc| {121 for (atom.relocs.items) |reloc| {
122 const value = self.relocationValue(reloc, wasm_bin);122 const value = atom.relocationValue(reloc, wasm_bin);
123 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{123 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
124 (Wasm.SymbolLoc{ .file = self.file, .index = reloc.index }).getName(wasm_bin),124 (Wasm.SymbolLoc{ .file = atom.file, .index = reloc.index }).getName(wasm_bin),
125 symbol_name,125 symbol_name,
126 reloc.offset,126 reloc.offset,
127 value,127 value,
...@@ -133,10 +133,10 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {...@@ -133,10 +133,10 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
133 .R_WASM_GLOBAL_INDEX_I32,133 .R_WASM_GLOBAL_INDEX_I32,
134 .R_WASM_MEMORY_ADDR_I32,134 .R_WASM_MEMORY_ADDR_I32,
135 .R_WASM_SECTION_OFFSET_I32,135 .R_WASM_SECTION_OFFSET_I32,
136 => std.mem.writeIntLittle(u32, self.code.items[reloc.offset..][0..4], @intCast(u32, value)),136 => std.mem.writeIntLittle(u32, atom.code.items[reloc.offset..][0..4], @intCast(u32, value)),
137 .R_WASM_TABLE_INDEX_I64,137 .R_WASM_TABLE_INDEX_I64,
138 .R_WASM_MEMORY_ADDR_I64,138 .R_WASM_MEMORY_ADDR_I64,
139 => std.mem.writeIntLittle(u64, self.code.items[reloc.offset..][0..8], value),139 => std.mem.writeIntLittle(u64, atom.code.items[reloc.offset..][0..8], value),
140 .R_WASM_GLOBAL_INDEX_LEB,140 .R_WASM_GLOBAL_INDEX_LEB,
141 .R_WASM_EVENT_INDEX_LEB,141 .R_WASM_EVENT_INDEX_LEB,
142 .R_WASM_FUNCTION_INDEX_LEB,142 .R_WASM_FUNCTION_INDEX_LEB,
...@@ -145,11 +145,11 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {...@@ -145,11 +145,11 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
145 .R_WASM_TABLE_INDEX_SLEB,145 .R_WASM_TABLE_INDEX_SLEB,
146 .R_WASM_TABLE_NUMBER_LEB,146 .R_WASM_TABLE_NUMBER_LEB,
147 .R_WASM_TYPE_INDEX_LEB,147 .R_WASM_TYPE_INDEX_LEB,
148 => leb.writeUnsignedFixed(5, self.code.items[reloc.offset..][0..5], @intCast(u32, value)),148 => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)),
149 .R_WASM_MEMORY_ADDR_LEB64,149 .R_WASM_MEMORY_ADDR_LEB64,
150 .R_WASM_MEMORY_ADDR_SLEB64,150 .R_WASM_MEMORY_ADDR_SLEB64,
151 .R_WASM_TABLE_INDEX_SLEB64,151 .R_WASM_TABLE_INDEX_SLEB64,
152 => leb.writeUnsignedFixed(10, self.code.items[reloc.offset..][0..10], value),152 => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),
153 }153 }
154 }154 }
155}155}
...@@ -157,8 +157,8 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {...@@ -157,8 +157,8 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
157/// From a given `relocation` will return the new value to be written.157/// From a given `relocation` will return the new value to be written.
158/// All values will be represented as a `u64` as all values can fit within it.158/// All values will be represented as a `u64` as all values can fit within it.
159/// The final value must be casted to the correct size.159/// The final value must be casted to the correct size.
160fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {160fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
161 const target_loc = (Wasm.SymbolLoc{ .file = self.file, .index = relocation.index }).finalLoc(wasm_bin);161 const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin);
162 const symbol = target_loc.getSymbol(wasm_bin).*;162 const symbol = target_loc.getSymbol(wasm_bin).*;
163 switch (relocation.relocation_type) {163 switch (relocation.relocation_type) {
164 .R_WASM_FUNCTION_INDEX_LEB => return symbol.index,164 .R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
...@@ -203,7 +203,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -203,7 +203,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
203 },203 },
204 .R_WASM_FUNCTION_OFFSET_I32 => {204 .R_WASM_FUNCTION_OFFSET_I32 => {
205 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;205 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
206 var atom = target_atom.getFirst();206 var current_atom = target_atom.getFirst();
207 var offset: u32 = 0;207 var offset: u32 = 0;
208 // TODO: Calculate this during atom allocation, rather than208 // TODO: Calculate this during atom allocation, rather than
209 // this linear calculation. For now it's done here as atoms209 // this linear calculation. For now it's done here as atoms
...@@ -211,8 +211,8 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -211,8 +211,8 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
211 // merged until later.211 // merged until later.
212 while (true) {212 while (true) {
213 offset += 5; // each atom uses 5 bytes to store its body's size213 offset += 5; // each atom uses 5 bytes to store its body's size
214 if (atom == target_atom) break;214 if (current_atom == target_atom) break;
215 atom = atom.next.?;215 current_atom = current_atom.next.?;
216 }216 }
217 return target_atom.offset + offset + (relocation.addend orelse 0);217 return target_atom.offset + offset + (relocation.addend orelse 0);
218 },218 },
src/link/Wasm/Object.zig+114-114
...@@ -88,28 +88,28 @@ const RelocatableData = struct {...@@ -88,28 +88,28 @@ const RelocatableData = struct {
88 /// meta data of the given object file.88 /// meta data of the given object file.
89 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's89 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
90 /// alignment to retrieve the natural alignment.90 /// alignment to retrieve the natural alignment.
91 pub fn getAlignment(self: RelocatableData, object: *const Object) u32 {91 pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 {
92 if (self.type != .data) return 1;92 if (relocatable_data.type != .data) return 1;
93 const data_alignment = object.segment_info[self.index].alignment;93 const data_alignment = object.segment_info[relocatable_data.index].alignment;
94 if (data_alignment == 0) return 1;94 if (data_alignment == 0) return 1;
95 // Decode from power of 2 to natural alignment95 // Decode from power of 2 to natural alignment
96 return @as(u32, 1) << @intCast(u5, data_alignment);96 return @as(u32, 1) << @intCast(u5, data_alignment);
97 }97 }
9898
99 /// Returns the symbol kind that corresponds to the relocatable section99 /// Returns the symbol kind that corresponds to the relocatable section
100 pub fn getSymbolKind(self: RelocatableData) Symbol.Tag {100 pub fn getSymbolKind(relocatable_data: RelocatableData) Symbol.Tag {
101 return switch (self.type) {101 return switch (relocatable_data.type) {
102 .data => .data,102 .data => .data,
103 .code => .function,103 .code => .function,
104 .debug => .section,104 .debug => .section,
105 };105 };
106 }106 }
107107
108 /// Returns the index within a section itself, or in case of a debug section,108 /// Returns the index within a section itrelocatable_data, or in case of a debug section,
109 /// returns the section index within the object file.109 /// returns the section index within the object file.
110 pub fn getIndex(self: RelocatableData) u32 {110 pub fn getIndex(relocatable_data: RelocatableData) u32 {
111 if (self.type == .debug) return self.section_index;111 if (relocatable_data.type == .debug) return relocatable_data.section_index;
112 return self.index;112 return relocatable_data.index;
113 }113 }
114};114};
115115
...@@ -153,51 +153,51 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz...@@ -153,51 +153,51 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
153153
154/// Frees all memory of `Object` at once. The given `Allocator` must be154/// Frees all memory of `Object` at once. The given `Allocator` must be
155/// the same allocator that was used when `init` was called.155/// the same allocator that was used when `init` was called.
156pub fn deinit(self: *Object, gpa: Allocator) void {156pub fn deinit(object: *Object, gpa: Allocator) void {
157 if (self.file) |file| {157 if (object.file) |file| {
158 file.close();158 file.close();
159 }159 }
160 for (self.func_types) |func_ty| {160 for (object.func_types) |func_ty| {
161 gpa.free(func_ty.params);161 gpa.free(func_ty.params);
162 gpa.free(func_ty.returns);162 gpa.free(func_ty.returns);
163 }163 }
164 gpa.free(self.func_types);164 gpa.free(object.func_types);
165 gpa.free(self.functions);165 gpa.free(object.functions);
166 gpa.free(self.imports);166 gpa.free(object.imports);
167 gpa.free(self.tables);167 gpa.free(object.tables);
168 gpa.free(self.memories);168 gpa.free(object.memories);
169 gpa.free(self.globals);169 gpa.free(object.globals);
170 gpa.free(self.exports);170 gpa.free(object.exports);
171 for (self.elements) |el| {171 for (object.elements) |el| {
172 gpa.free(el.func_indexes);172 gpa.free(el.func_indexes);
173 }173 }
174 gpa.free(self.elements);174 gpa.free(object.elements);
175 gpa.free(self.features);175 gpa.free(object.features);
176 for (self.relocations.values()) |val| {176 for (object.relocations.values()) |val| {
177 gpa.free(val);177 gpa.free(val);
178 }178 }
179 self.relocations.deinit(gpa);179 object.relocations.deinit(gpa);
180 gpa.free(self.symtable);180 gpa.free(object.symtable);
181 gpa.free(self.comdat_info);181 gpa.free(object.comdat_info);
182 gpa.free(self.init_funcs);182 gpa.free(object.init_funcs);
183 for (self.segment_info) |info| {183 for (object.segment_info) |info| {
184 gpa.free(info.name);184 gpa.free(info.name);
185 }185 }
186 gpa.free(self.segment_info);186 gpa.free(object.segment_info);
187 for (self.relocatable_data) |rel_data| {187 for (object.relocatable_data) |rel_data| {
188 gpa.free(rel_data.data[0..rel_data.size]);188 gpa.free(rel_data.data[0..rel_data.size]);
189 }189 }
190 gpa.free(self.relocatable_data);190 gpa.free(object.relocatable_data);
191 self.string_table.deinit(gpa);191 object.string_table.deinit(gpa);
192 gpa.free(self.name);192 gpa.free(object.name);
193 self.* = undefined;193 object.* = undefined;
194}194}
195195
196/// Finds the import within the list of imports from a given kind and index of that kind.196/// Finds the import within the list of imports from a given kind and index of that kind.
197/// Asserts the import exists197/// Asserts the import exists
198pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index: u32) types.Import {198pub fn findImport(object: *const Object, import_kind: std.wasm.ExternalKind, index: u32) types.Import {
199 var i: u32 = 0;199 var i: u32 = 0;
200 return for (self.imports) |import| {200 return for (object.imports) |import| {
201 if (std.meta.activeTag(import.kind) == import_kind) {201 if (std.meta.activeTag(import.kind) == import_kind) {
202 if (i == index) return import;202 if (i == index) return import;
203 i += 1;203 i += 1;
...@@ -206,16 +206,16 @@ pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index...@@ -206,16 +206,16 @@ pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index
206}206}
207207
208/// Counts the entries of imported `kind` and returns the result208/// Counts the entries of imported `kind` and returns the result
209pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32 {209pub fn importedCountByKind(object: *const Object, kind: std.wasm.ExternalKind) u32 {
210 var i: u32 = 0;210 var i: u32 = 0;
211 return for (self.imports) |imp| {211 return for (object.imports) |imp| {
212 if (@as(std.wasm.ExternalKind, imp.kind) == kind) i += 1;212 if (@as(std.wasm.ExternalKind, imp.kind) == kind) i += 1;
213 } else i;213 } else i;
214}214}
215215
216/// From a given `RelocatableDate`, find the corresponding debug section name216/// From a given `RelocatableDate`, find the corresponding debug section name
217pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []const u8 {217pub fn getDebugName(object: *const Object, relocatable_data: RelocatableData) []const u8 {
218 return self.string_table.get(relocatable_data.index);218 return object.string_table.get(relocatable_data.index);
219}219}
220220
221/// Checks if the object file is an MVP version.221/// Checks if the object file is an MVP version.
...@@ -224,13 +224,13 @@ pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []co...@@ -224,13 +224,13 @@ pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []co
224/// we initialize a new table symbol that corresponds to that import and return that symbol.224/// we initialize a new table symbol that corresponds to that import and return that symbol.
225///225///
226/// When the object file is *NOT* MVP, we return `null`.226/// When the object file is *NOT* MVP, we return `null`.
227fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {227fn checkLegacyIndirectFunctionTable(object: *Object) !?Symbol {
228 var table_count: usize = 0;228 var table_count: usize = 0;
229 for (self.symtable) |sym| {229 for (object.symtable) |sym| {
230 if (sym.tag == .table) table_count += 1;230 if (sym.tag == .table) table_count += 1;
231 }231 }
232232
233 const import_table_count = self.importedCountByKind(.table);233 const import_table_count = object.importedCountByKind(.table);
234234
235 // For each import table, we also have a symbol so this is not a legacy object file235 // For each import table, we also have a symbol so this is not a legacy object file
236 if (import_table_count == table_count) return null;236 if (import_table_count == table_count) return null;
...@@ -244,7 +244,7 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {...@@ -244,7 +244,7 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
244 }244 }
245245
246 // MVP object files cannot have any table definitions, only imports (for the indirect function table).246 // MVP object files cannot have any table definitions, only imports (for the indirect function table).
247 if (self.tables.len > 0) {247 if (object.tables.len > 0) {
248 log.err("Unexpected table definition without representing table symbols.", .{});248 log.err("Unexpected table definition without representing table symbols.", .{});
249 return error.UnexpectedTable;249 return error.UnexpectedTable;
250 }250 }
...@@ -254,14 +254,14 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {...@@ -254,14 +254,14 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
254 return error.MissingTableSymbols;254 return error.MissingTableSymbols;
255 }255 }
256256
257 var table_import: types.Import = for (self.imports) |imp| {257 var table_import: types.Import = for (object.imports) |imp| {
258 if (imp.kind == .table) {258 if (imp.kind == .table) {
259 break imp;259 break imp;
260 }260 }
261 } else unreachable;261 } else unreachable;
262262
263 if (!std.mem.eql(u8, self.string_table.get(table_import.name), "__indirect_function_table")) {263 if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {
264 log.err("Non-indirect function table import '{s}' is missing a corresponding symbol", .{self.string_table.get(table_import.name)});264 log.err("Non-indirect function table import '{s}' is missing a corresponding symbol", .{object.string_table.get(table_import.name)});
265 return error.MissingTableSymbols;265 return error.MissingTableSymbols;
266 }266 }
267267
...@@ -313,41 +313,41 @@ pub const ParseError = error{...@@ -313,41 +313,41 @@ pub const ParseError = error{
313 UnknownFeature,313 UnknownFeature,
314};314};
315315
316fn parse(self: *Object, gpa: Allocator, reader: anytype, is_object_file: *bool) Parser(@TypeOf(reader)).Error!void {316fn parse(object: *Object, gpa: Allocator, reader: anytype, is_object_file: *bool) Parser(@TypeOf(reader)).Error!void {
317 var parser = Parser(@TypeOf(reader)).init(self, reader);317 var parser = Parser(@TypeOf(reader)).init(object, reader);
318 return parser.parseObject(gpa, is_object_file);318 return parser.parseObject(gpa, is_object_file);
319}319}
320320
321fn Parser(comptime ReaderType: type) type {321fn Parser(comptime ReaderType: type) type {
322 return struct {322 return struct {
323 const Self = @This();323 const ObjectParser = @This();
324 const Error = ReaderType.Error || ParseError;324 const Error = ReaderType.Error || ParseError;
325325
326 reader: std.io.CountingReader(ReaderType),326 reader: std.io.CountingReader(ReaderType),
327 /// Object file we're building327 /// Object file we're building
328 object: *Object,328 object: *Object,
329329
330 fn init(object: *Object, reader: ReaderType) Self {330 fn init(object: *Object, reader: ReaderType) ObjectParser {
331 return .{ .object = object, .reader = std.io.countingReader(reader) };331 return .{ .object = object, .reader = std.io.countingReader(reader) };
332 }332 }
333333
334 /// Verifies that the first 4 bytes contains \0Asm334 /// Verifies that the first 4 bytes contains \0Asm
335 fn verifyMagicBytes(self: *Self) Error!void {335 fn verifyMagicBytes(parser: *ObjectParser) Error!void {
336 var magic_bytes: [4]u8 = undefined;336 var magic_bytes: [4]u8 = undefined;
337337
338 try self.reader.reader().readNoEof(&magic_bytes);338 try parser.reader.reader().readNoEof(&magic_bytes);
339 if (!std.mem.eql(u8, &magic_bytes, &std.wasm.magic)) {339 if (!std.mem.eql(u8, &magic_bytes, &std.wasm.magic)) {
340 log.debug("Invalid magic bytes '{s}'", .{&magic_bytes});340 log.debug("Invalid magic bytes '{s}'", .{&magic_bytes});
341 return error.InvalidMagicByte;341 return error.InvalidMagicByte;
342 }342 }
343 }343 }
344344
345 fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void {345 fn parseObject(parser: *ObjectParser, gpa: Allocator, is_object_file: *bool) Error!void {
346 errdefer self.object.deinit(gpa);346 errdefer parser.object.deinit(gpa);
347 try self.verifyMagicBytes();347 try parser.verifyMagicBytes();
348 const version = try self.reader.reader().readIntLittle(u32);348 const version = try parser.reader.reader().readIntLittle(u32);
349349
350 self.object.version = version;350 parser.object.version = version;
351 var relocatable_data = std.ArrayList(RelocatableData).init(gpa);351 var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
352 var debug_names = std.ArrayList(u8).init(gpa);352 var debug_names = std.ArrayList(u8).init(gpa);
353353
...@@ -360,9 +360,9 @@ fn Parser(comptime ReaderType: type) type {...@@ -360,9 +360,9 @@ fn Parser(comptime ReaderType: type) type {
360 }360 }
361361
362 var section_index: u32 = 0;362 var section_index: u32 = 0;
363 while (self.reader.reader().readByte()) |byte| : (section_index += 1) {363 while (parser.reader.reader().readByte()) |byte| : (section_index += 1) {
364 const len = try readLeb(u32, self.reader.reader());364 const len = try readLeb(u32, parser.reader.reader());
365 var limited_reader = std.io.limitedReader(self.reader.reader(), len);365 var limited_reader = std.io.limitedReader(parser.reader.reader(), len);
366 const reader = limited_reader.reader();366 const reader = limited_reader.reader();
367 switch (@intToEnum(std.wasm.Section, byte)) {367 switch (@intToEnum(std.wasm.Section, byte)) {
368 .custom => {368 .custom => {
...@@ -373,12 +373,12 @@ fn Parser(comptime ReaderType: type) type {...@@ -373,12 +373,12 @@ fn Parser(comptime ReaderType: type) type {
373373
374 if (std.mem.eql(u8, name, "linking")) {374 if (std.mem.eql(u8, name, "linking")) {
375 is_object_file.* = true;375 is_object_file.* = true;
376 self.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.376 parser.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
377 try self.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left));377 try parser.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left));
378 } else if (std.mem.startsWith(u8, name, "reloc")) {378 } else if (std.mem.startsWith(u8, name, "reloc")) {
379 try self.parseRelocations(gpa);379 try parser.parseRelocations(gpa);
380 } else if (std.mem.eql(u8, name, "target_features")) {380 } else if (std.mem.eql(u8, name, "target_features")) {
381 try self.parseFeatures(gpa);381 try parser.parseFeatures(gpa);
382 } else if (std.mem.startsWith(u8, name, ".debug")) {382 } else if (std.mem.startsWith(u8, name, ".debug")) {
383 const debug_size = @intCast(u32, reader.context.bytes_left);383 const debug_size = @intCast(u32, reader.context.bytes_left);
384 const debug_content = try gpa.alloc(u8, debug_size);384 const debug_content = try gpa.alloc(u8, debug_size);
...@@ -389,7 +389,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -389,7 +389,7 @@ fn Parser(comptime ReaderType: type) type {
389 .type = .debug,389 .type = .debug,
390 .data = debug_content.ptr,390 .data = debug_content.ptr,
391 .size = debug_size,391 .size = debug_size,
392 .index = try self.object.string_table.put(gpa, name),392 .index = try parser.object.string_table.put(gpa, name),
393 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset393 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
394 .section_index = section_index,394 .section_index = section_index,
395 });395 });
...@@ -398,7 +398,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -398,7 +398,7 @@ fn Parser(comptime ReaderType: type) type {
398 }398 }
399 },399 },
400 .type => {400 .type => {
401 for (try readVec(&self.object.func_types, reader, gpa)) |*type_val| {401 for (try readVec(&parser.object.func_types, reader, gpa)) |*type_val| {
402 if ((try reader.readByte()) != std.wasm.function_type) return error.ExpectedFuncType;402 if ((try reader.readByte()) != std.wasm.function_type) return error.ExpectedFuncType;
403403
404 for (try readVec(&type_val.params, reader, gpa)) |*param| {404 for (try readVec(&type_val.params, reader, gpa)) |*param| {
...@@ -412,7 +412,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -412,7 +412,7 @@ fn Parser(comptime ReaderType: type) type {
412 try assertEnd(reader);412 try assertEnd(reader);
413 },413 },
414 .import => {414 .import => {
415 for (try readVec(&self.object.imports, reader, gpa)) |*import| {415 for (try readVec(&parser.object.imports, reader, gpa)) |*import| {
416 const module_len = try readLeb(u32, reader);416 const module_len = try readLeb(u32, reader);
417 const module_name = try gpa.alloc(u8, module_len);417 const module_name = try gpa.alloc(u8, module_len);
418 defer gpa.free(module_name);418 defer gpa.free(module_name);
...@@ -438,21 +438,21 @@ fn Parser(comptime ReaderType: type) type {...@@ -438,21 +438,21 @@ fn Parser(comptime ReaderType: type) type {
438 };438 };
439439
440 import.* = .{440 import.* = .{
441 .module_name = try self.object.string_table.put(gpa, module_name),441 .module_name = try parser.object.string_table.put(gpa, module_name),
442 .name = try self.object.string_table.put(gpa, name),442 .name = try parser.object.string_table.put(gpa, name),
443 .kind = kind_value,443 .kind = kind_value,
444 };444 };
445 }445 }
446 try assertEnd(reader);446 try assertEnd(reader);
447 },447 },
448 .function => {448 .function => {
449 for (try readVec(&self.object.functions, reader, gpa)) |*func| {449 for (try readVec(&parser.object.functions, reader, gpa)) |*func| {
450 func.* = .{ .type_index = try readLeb(u32, reader) };450 func.* = .{ .type_index = try readLeb(u32, reader) };
451 }451 }
452 try assertEnd(reader);452 try assertEnd(reader);
453 },453 },
454 .table => {454 .table => {
455 for (try readVec(&self.object.tables, reader, gpa)) |*table| {455 for (try readVec(&parser.object.tables, reader, gpa)) |*table| {
456 table.* = .{456 table.* = .{
457 .reftype = try readEnum(std.wasm.RefType, reader),457 .reftype = try readEnum(std.wasm.RefType, reader),
458 .limits = try readLimits(reader),458 .limits = try readLimits(reader),
...@@ -461,13 +461,13 @@ fn Parser(comptime ReaderType: type) type {...@@ -461,13 +461,13 @@ fn Parser(comptime ReaderType: type) type {
461 try assertEnd(reader);461 try assertEnd(reader);
462 },462 },
463 .memory => {463 .memory => {
464 for (try readVec(&self.object.memories, reader, gpa)) |*memory| {464 for (try readVec(&parser.object.memories, reader, gpa)) |*memory| {
465 memory.* = .{ .limits = try readLimits(reader) };465 memory.* = .{ .limits = try readLimits(reader) };
466 }466 }
467 try assertEnd(reader);467 try assertEnd(reader);
468 },468 },
469 .global => {469 .global => {
470 for (try readVec(&self.object.globals, reader, gpa)) |*global| {470 for (try readVec(&parser.object.globals, reader, gpa)) |*global| {
471 global.* = .{471 global.* = .{
472 .global_type = .{472 .global_type = .{
473 .valtype = try readEnum(std.wasm.Valtype, reader),473 .valtype = try readEnum(std.wasm.Valtype, reader),
...@@ -479,13 +479,13 @@ fn Parser(comptime ReaderType: type) type {...@@ -479,13 +479,13 @@ fn Parser(comptime ReaderType: type) type {
479 try assertEnd(reader);479 try assertEnd(reader);
480 },480 },
481 .@"export" => {481 .@"export" => {
482 for (try readVec(&self.object.exports, reader, gpa)) |*exp| {482 for (try readVec(&parser.object.exports, reader, gpa)) |*exp| {
483 const name_len = try readLeb(u32, reader);483 const name_len = try readLeb(u32, reader);
484 const name = try gpa.alloc(u8, name_len);484 const name = try gpa.alloc(u8, name_len);
485 defer gpa.free(name);485 defer gpa.free(name);
486 try reader.readNoEof(name);486 try reader.readNoEof(name);
487 exp.* = .{487 exp.* = .{
488 .name = try self.object.string_table.put(gpa, name),488 .name = try parser.object.string_table.put(gpa, name),
489 .kind = try readEnum(std.wasm.ExternalKind, reader),489 .kind = try readEnum(std.wasm.ExternalKind, reader),
490 .index = try readLeb(u32, reader),490 .index = try readLeb(u32, reader),
491 };491 };
...@@ -493,11 +493,11 @@ fn Parser(comptime ReaderType: type) type {...@@ -493,11 +493,11 @@ fn Parser(comptime ReaderType: type) type {
493 try assertEnd(reader);493 try assertEnd(reader);
494 },494 },
495 .start => {495 .start => {
496 self.object.start = try readLeb(u32, reader);496 parser.object.start = try readLeb(u32, reader);
497 try assertEnd(reader);497 try assertEnd(reader);
498 },498 },
499 .element => {499 .element => {
500 for (try readVec(&self.object.elements, reader, gpa)) |*elem| {500 for (try readVec(&parser.object.elements, reader, gpa)) |*elem| {
501 elem.table_index = try readLeb(u32, reader);501 elem.table_index = try readLeb(u32, reader);
502 elem.offset = try readInit(reader);502 elem.offset = try readInit(reader);
503503
...@@ -521,7 +521,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -521,7 +521,7 @@ fn Parser(comptime ReaderType: type) type {
521 .type = .code,521 .type = .code,
522 .data = data.ptr,522 .data = data.ptr,
523 .size = code_len,523 .size = code_len,
524 .index = self.object.importedCountByKind(.function) + index,524 .index = parser.object.importedCountByKind(.function) + index,
525 .offset = offset,525 .offset = offset,
526 .section_index = section_index,526 .section_index = section_index,
527 });527 });
...@@ -551,22 +551,22 @@ fn Parser(comptime ReaderType: type) type {...@@ -551,22 +551,22 @@ fn Parser(comptime ReaderType: type) type {
551 });551 });
552 }552 }
553 },553 },
554 else => try self.reader.reader().skipBytes(len, .{}),554 else => try parser.reader.reader().skipBytes(len, .{}),
555 }555 }
556 } else |err| switch (err) {556 } else |err| switch (err) {
557 error.EndOfStream => {}, // finished parsing the file557 error.EndOfStream => {}, // finished parsing the file
558 else => |e| return e,558 else => |e| return e,
559 }559 }
560 self.object.relocatable_data = relocatable_data.toOwnedSlice();560 parser.object.relocatable_data = relocatable_data.toOwnedSlice();
561 }561 }
562562
563 /// Based on the "features" custom section, parses it into a list of563 /// Based on the "features" custom section, parses it into a list of
564 /// features that tell the linker what features were enabled and may be mandatory564 /// features that tell the linker what features were enabled and may be mandatory
565 /// to be able to link.565 /// to be able to link.
566 /// Logs an info message when an undefined feature is detected.566 /// Logs an info message when an undefined feature is detected.
567 fn parseFeatures(self: *Self, gpa: Allocator) !void {567 fn parseFeatures(parser: *ObjectParser, gpa: Allocator) !void {
568 const reader = self.reader.reader();568 const reader = parser.reader.reader();
569 for (try readVec(&self.object.features, reader, gpa)) |*feature| {569 for (try readVec(&parser.object.features, reader, gpa)) |*feature| {
570 const prefix = try readEnum(types.Feature.Prefix, reader);570 const prefix = try readEnum(types.Feature.Prefix, reader);
571 const name_len = try leb.readULEB128(u32, reader);571 const name_len = try leb.readULEB128(u32, reader);
572 const name = try gpa.alloc(u8, name_len);572 const name = try gpa.alloc(u8, name_len);
...@@ -587,8 +587,8 @@ fn Parser(comptime ReaderType: type) type {...@@ -587,8 +587,8 @@ fn Parser(comptime ReaderType: type) type {
587 /// Parses a "reloc" custom section into a list of relocations.587 /// Parses a "reloc" custom section into a list of relocations.
588 /// The relocations are mapped into `Object` where the key is the section588 /// The relocations are mapped into `Object` where the key is the section
589 /// they apply to.589 /// they apply to.
590 fn parseRelocations(self: *Self, gpa: Allocator) !void {590 fn parseRelocations(parser: *ObjectParser, gpa: Allocator) !void {
591 const reader = self.reader.reader();591 const reader = parser.reader.reader();
592 const section = try leb.readULEB128(u32, reader);592 const section = try leb.readULEB128(u32, reader);
593 const count = try leb.readULEB128(u32, reader);593 const count = try leb.readULEB128(u32, reader);
594 const relocations = try gpa.alloc(types.Relocation, count);594 const relocations = try gpa.alloc(types.Relocation, count);
...@@ -616,15 +616,15 @@ fn Parser(comptime ReaderType: type) type {...@@ -616,15 +616,15 @@ fn Parser(comptime ReaderType: type) type {
616 });616 });
617 }617 }
618618
619 try self.object.relocations.putNoClobber(gpa, section, relocations);619 try parser.object.relocations.putNoClobber(gpa, section, relocations);
620 }620 }
621621
622 /// Parses the "linking" custom section. Versions that are not622 /// Parses the "linking" custom section. Versions that are not
623 /// supported will be an error. `payload_size` is required to be able623 /// supported will be an error. `payload_size` is required to be able
624 /// to calculate the subsections we need to parse, as that data is not624 /// to calculate the subsections we need to parse, as that data is not
625 /// available within the section itself.625 /// available within the section itparser.
626 fn parseMetadata(self: *Self, gpa: Allocator, payload_size: usize) !void {626 fn parseMetadata(parser: *ObjectParser, gpa: Allocator, payload_size: usize) !void {
627 var limited = std.io.limitedReader(self.reader.reader(), payload_size);627 var limited = std.io.limitedReader(parser.reader.reader(), payload_size);
628 const limited_reader = limited.reader();628 const limited_reader = limited.reader();
629629
630 const version = try leb.readULEB128(u32, limited_reader);630 const version = try leb.readULEB128(u32, limited_reader);
...@@ -632,7 +632,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -632,7 +632,7 @@ fn Parser(comptime ReaderType: type) type {
632 if (version != 2) return error.UnsupportedVersion;632 if (version != 2) return error.UnsupportedVersion;
633633
634 while (limited.bytes_left > 0) {634 while (limited.bytes_left > 0) {
635 try self.parseSubsection(gpa, limited_reader);635 try parser.parseSubsection(gpa, limited_reader);
636 }636 }
637 }637 }
638638
...@@ -640,9 +640,9 @@ fn Parser(comptime ReaderType: type) type {...@@ -640,9 +640,9 @@ fn Parser(comptime ReaderType: type) type {
640 /// The `reader` param for this is to provide a `LimitedReader`, which allows640 /// The `reader` param for this is to provide a `LimitedReader`, which allows
641 /// us to only read until a max length.641 /// us to only read until a max length.
642 ///642 ///
643 /// `self` is used to provide access to other sections that may be needed,643 /// `parser` is used to provide access to other sections that may be needed,
644 /// such as access to the `import` section to find the name of a symbol.644 /// such as access to the `import` section to find the name of a symbol.
645 fn parseSubsection(self: *Self, gpa: Allocator, reader: anytype) !void {645 fn parseSubsection(parser: *ObjectParser, gpa: Allocator, reader: anytype) !void {
646 const sub_type = try leb.readULEB128(u8, reader);646 const sub_type = try leb.readULEB128(u8, reader);
647 log.debug("Found subsection: {s}", .{@tagName(@intToEnum(types.SubsectionType, sub_type))});647 log.debug("Found subsection: {s}", .{@tagName(@intToEnum(types.SubsectionType, sub_type))});
648 const payload_len = try leb.readULEB128(u32, reader);648 const payload_len = try leb.readULEB128(u32, reader);
...@@ -674,7 +674,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -674,7 +674,7 @@ fn Parser(comptime ReaderType: type) type {
674 segment.flags,674 segment.flags,
675 });675 });
676 }676 }
677 self.object.segment_info = segments;677 parser.object.segment_info = segments;
678 },678 },
679 .WASM_INIT_FUNCS => {679 .WASM_INIT_FUNCS => {
680 const funcs = try gpa.alloc(types.InitFunc, count);680 const funcs = try gpa.alloc(types.InitFunc, count);
...@@ -686,7 +686,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -686,7 +686,7 @@ fn Parser(comptime ReaderType: type) type {
686 };686 };
687 log.debug("Found function - prio: {d}, index: {d}", .{ func.priority, func.symbol_index });687 log.debug("Found function - prio: {d}, index: {d}", .{ func.priority, func.symbol_index });
688 }688 }
689 self.object.init_funcs = funcs;689 parser.object.init_funcs = funcs;
690 },690 },
691 .WASM_COMDAT_INFO => {691 .WASM_COMDAT_INFO => {
692 const comdats = try gpa.alloc(types.Comdat, count);692 const comdats = try gpa.alloc(types.Comdat, count);
...@@ -719,7 +719,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -719,7 +719,7 @@ fn Parser(comptime ReaderType: type) type {
719 };719 };
720 }720 }
721721
722 self.object.comdat_info = comdats;722 parser.object.comdat_info = comdats;
723 },723 },
724 .WASM_SYMBOL_TABLE => {724 .WASM_SYMBOL_TABLE => {
725 var symbols = try std.ArrayList(Symbol).initCapacity(gpa, count);725 var symbols = try std.ArrayList(Symbol).initCapacity(gpa, count);
...@@ -727,22 +727,22 @@ fn Parser(comptime ReaderType: type) type {...@@ -727,22 +727,22 @@ fn Parser(comptime ReaderType: type) type {
727 var i: usize = 0;727 var i: usize = 0;
728 while (i < count) : (i += 1) {728 while (i < count) : (i += 1) {
729 const symbol = symbols.addOneAssumeCapacity();729 const symbol = symbols.addOneAssumeCapacity();
730 symbol.* = try self.parseSymbol(gpa, reader);730 symbol.* = try parser.parseSymbol(gpa, reader);
731 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{731 log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
732 @tagName(symbol.tag),732 @tagName(symbol.tag),
733 self.object.string_table.get(symbol.name),733 parser.object.string_table.get(symbol.name),
734 symbol.flags,734 symbol.flags,
735 });735 });
736 }736 }
737737
738 // we found all symbols, check for indirect function table738 // we found all symbols, check for indirect function table
739 // in case of an MVP object file739 // in case of an MVP object file
740 if (try self.object.checkLegacyIndirectFunctionTable()) |symbol| {740 if (try parser.object.checkLegacyIndirectFunctionTable()) |symbol| {
741 try symbols.append(symbol);741 try symbols.append(symbol);
742 log.debug("Found legacy indirect function table. Created symbol", .{});742 log.debug("Found legacy indirect function table. Created symbol", .{});
743 }743 }
744744
745 self.object.symtable = symbols.toOwnedSlice();745 parser.object.symtable = symbols.toOwnedSlice();
746 },746 },
747 }747 }
748 }748 }
...@@ -750,7 +750,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -750,7 +750,7 @@ fn Parser(comptime ReaderType: type) type {
750 /// Parses the symbol information based on its kind,750 /// Parses the symbol information based on its kind,
751 /// requires access to `Object` to find the name of a symbol when it's751 /// requires access to `Object` to find the name of a symbol when it's
752 /// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.752 /// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.
753 fn parseSymbol(self: *Self, gpa: Allocator, reader: anytype) !Symbol {753 fn parseSymbol(parser: *ObjectParser, gpa: Allocator, reader: anytype) !Symbol {
754 const tag = @intToEnum(Symbol.Tag, try leb.readULEB128(u8, reader));754 const tag = @intToEnum(Symbol.Tag, try leb.readULEB128(u8, reader));
755 const flags = try leb.readULEB128(u32, reader);755 const flags = try leb.readULEB128(u32, reader);
756 var symbol: Symbol = .{756 var symbol: Symbol = .{
...@@ -766,7 +766,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -766,7 +766,7 @@ fn Parser(comptime ReaderType: type) type {
766 const name = try gpa.alloc(u8, name_len);766 const name = try gpa.alloc(u8, name_len);
767 defer gpa.free(name);767 defer gpa.free(name);
768 try reader.readNoEof(name);768 try reader.readNoEof(name);
769 symbol.name = try self.object.string_table.put(gpa, name);769 symbol.name = try parser.object.string_table.put(gpa, name);
770770
771 // Data symbols only have the following fields if the symbol is defined771 // Data symbols only have the following fields if the symbol is defined
772 if (symbol.isDefined()) {772 if (symbol.isDefined()) {
...@@ -778,7 +778,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -778,7 +778,7 @@ fn Parser(comptime ReaderType: type) type {
778 },778 },
779 .section => {779 .section => {
780 symbol.index = try leb.readULEB128(u32, reader);780 symbol.index = try leb.readULEB128(u32, reader);
781 for (self.object.relocatable_data) |data| {781 for (parser.object.relocatable_data) |data| {
782 if (data.section_index == symbol.index) {782 if (data.section_index == symbol.index) {
783 symbol.name = data.index;783 symbol.name = data.index;
784 break;784 break;
...@@ -791,7 +791,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -791,7 +791,7 @@ fn Parser(comptime ReaderType: type) type {
791791
792 const is_undefined = symbol.isUndefined();792 const is_undefined = symbol.isUndefined();
793 if (is_undefined) {793 if (is_undefined) {
794 maybe_import = self.object.findImport(symbol.tag.externalType(), symbol.index);794 maybe_import = parser.object.findImport(symbol.tag.externalType(), symbol.index);
795 }795 }
796 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);796 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
797 if (!(is_undefined and !explicit_name)) {797 if (!(is_undefined and !explicit_name)) {
...@@ -799,7 +799,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -799,7 +799,7 @@ fn Parser(comptime ReaderType: type) type {
799 const name = try gpa.alloc(u8, name_len);799 const name = try gpa.alloc(u8, name_len);
800 defer gpa.free(name);800 defer gpa.free(name);
801 try reader.readNoEof(name);801 try reader.readNoEof(name);
802 symbol.name = try self.object.string_table.put(gpa, name);802 symbol.name = try parser.object.string_table.put(gpa, name);
803 } else {803 } else {
804 symbol.name = maybe_import.?.name;804 symbol.name = maybe_import.?.name;
805 }805 }
...@@ -872,7 +872,7 @@ fn assertEnd(reader: anytype) !void {...@@ -872,7 +872,7 @@ fn assertEnd(reader: anytype) !void {
872}872}
873873
874/// Parses an object file into atoms, for code and data sections874/// Parses an object file into atoms, for code and data sections
875pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {875pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {
876 const Key = struct {876 const Key = struct {
877 kind: Symbol.Tag,877 kind: Symbol.Tag,
878 index: u32,878 index: u32,
...@@ -882,7 +882,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -882,7 +882,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
882 list.deinit();882 list.deinit();
883 } else symbol_for_segment.deinit();883 } else symbol_for_segment.deinit();
884884
885 for (self.symtable) |symbol, symbol_index| {885 for (object.symtable) |symbol, symbol_index| {
886 switch (symbol.tag) {886 switch (symbol.tag) {
887 .function, .data, .section => if (!symbol.isUndefined()) {887 .function, .data, .section => if (!symbol.isUndefined()) {
888 const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });888 const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
...@@ -896,7 +896,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -896,7 +896,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
896 }896 }
897 }897 }
898898
899 for (self.relocatable_data) |relocatable_data, index| {899 for (object.relocatable_data) |relocatable_data, index| {
900 const final_index = (try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index))) orelse {900 const final_index = (try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index))) orelse {
901 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.901 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
902 };902 };
...@@ -911,12 +911,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -911,12 +911,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
911 try wasm_bin.managed_atoms.append(gpa, atom);911 try wasm_bin.managed_atoms.append(gpa, atom);
912 atom.file = object_index;912 atom.file = object_index;
913 atom.size = relocatable_data.size;913 atom.size = relocatable_data.size;
914 atom.alignment = relocatable_data.getAlignment(self);914 atom.alignment = relocatable_data.getAlignment(object);
915915
916 const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};916 const relocations: []types.Relocation = object.relocations.get(relocatable_data.section_index) orelse &.{};
917 for (relocations) |relocation| {917 for (relocations) |relocation| {
918 if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {918 if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {
919 // set the offset relative to the offset of the segment itself,919 // set the offset relative to the offset of the segment itobject,
920 // rather than within the entire section.920 // rather than within the entire section.
921 var reloc = relocation;921 var reloc = relocation;
922 reloc.offset -= relocatable_data.offset;922 reloc.offset -= relocatable_data.offset;
...@@ -942,8 +942,8 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -942,8 +942,8 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
942 // symbols referencing the same atom will be added as alias942 // symbols referencing the same atom will be added as alias
943 // or as 'parent' when they are global.943 // or as 'parent' when they are global.
944 while (symbols.popOrNull()) |idx| {944 while (symbols.popOrNull()) |idx| {
945 const alias_symbol = self.symtable[idx];945 const alias_symbol = object.symtable[idx];
946 const symbol = self.symtable[atom.sym_index];946 const symbol = object.symtable[atom.sym_index];
947 if (alias_symbol.isGlobal() and symbol.isLocal()) {947 if (alias_symbol.isGlobal() and symbol.isLocal()) {
948 atom.sym_index = idx;948 atom.sym_index = idx;
949 }949 }
...@@ -957,7 +957,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -957,7 +957,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
957 }957 }
958958
959 try wasm_bin.appendAtomAtIndex(final_index, atom);959 try wasm_bin.appendAtomAtIndex(final_index, atom);
960 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ self.string_table.get(self.symtable[atom.sym_index].name), final_index });960 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
961 }961 }
962}962}
963963
src/link/Wasm/Symbol.zig+44-44
...@@ -34,8 +34,8 @@ pub const Tag = enum {...@@ -34,8 +34,8 @@ pub const Tag = enum {
3434
35 /// From a given symbol tag, returns the `ExternalType`35 /// From a given symbol tag, returns the `ExternalType`
36 /// Asserts the given tag can be represented as an external type.36 /// Asserts the given tag can be represented as an external type.
37 pub fn externalType(self: Tag) std.wasm.ExternalKind {37 pub fn externalType(tag: Tag) std.wasm.ExternalKind {
38 return switch (self) {38 return switch (tag) {
39 .function => .function,39 .function => .function,
40 .global => .global,40 .global => .global,
41 .data => .memory,41 .data => .memory,
...@@ -78,85 +78,85 @@ pub const Flag = enum(u32) {...@@ -78,85 +78,85 @@ pub const Flag = enum(u32) {
7878
79/// Verifies if the given symbol should be imported from the79/// Verifies if the given symbol should be imported from the
80/// host environment or not80/// host environment or not
81pub fn requiresImport(self: Symbol) bool {81pub fn requiresImport(symbol: Symbol) bool {
82 if (self.tag == .data) return false;82 if (symbol.tag == .data) return false;
83 if (!self.isUndefined()) return false;83 if (!symbol.isUndefined()) return false;
84 if (self.isWeak()) return false;84 if (symbol.isWeak()) return false;
85 // if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib85 // if (symbol.isDefined() and symbol.isWeak()) return true; //TODO: Only when building shared lib
8686
87 return true;87 return true;
88}88}
8989
90pub fn hasFlag(self: Symbol, flag: Flag) bool {90pub fn hasFlag(symbol: Symbol, flag: Flag) bool {
91 return self.flags & @enumToInt(flag) != 0;91 return symbol.flags & @enumToInt(flag) != 0;
92}92}
9393
94pub fn setFlag(self: *Symbol, flag: Flag) void {94pub fn setFlag(symbol: *Symbol, flag: Flag) void {
95 self.flags |= @enumToInt(flag);95 symbol.flags |= @enumToInt(flag);
96}96}
9797
98pub fn isUndefined(self: Symbol) bool {98pub fn isUndefined(symbol: Symbol) bool {
99 return self.flags & @enumToInt(Flag.WASM_SYM_UNDEFINED) != 0;99 return symbol.flags & @enumToInt(Flag.WASM_SYM_UNDEFINED) != 0;
100}100}
101101
102pub fn setUndefined(self: *Symbol, is_undefined: bool) void {102pub fn setUndefined(symbol: *Symbol, is_undefined: bool) void {
103 if (is_undefined) {103 if (is_undefined) {
104 self.setFlag(.WASM_SYM_UNDEFINED);104 symbol.setFlag(.WASM_SYM_UNDEFINED);
105 } else {105 } else {
106 self.flags &= ~@enumToInt(Flag.WASM_SYM_UNDEFINED);106 symbol.flags &= ~@enumToInt(Flag.WASM_SYM_UNDEFINED);
107 }107 }
108}108}
109109
110pub fn setGlobal(self: *Symbol, is_global: bool) void {110pub fn setGlobal(symbol: *Symbol, is_global: bool) void {
111 if (is_global) {111 if (is_global) {
112 self.flags &= ~@enumToInt(Flag.WASM_SYM_BINDING_LOCAL);112 symbol.flags &= ~@enumToInt(Flag.WASM_SYM_BINDING_LOCAL);
113 } else {113 } else {
114 self.setFlag(.WASM_SYM_BINDING_LOCAL);114 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
115 }115 }
116}116}
117117
118pub fn isDefined(self: Symbol) bool {118pub fn isDefined(symbol: Symbol) bool {
119 return !self.isUndefined();119 return !symbol.isUndefined();
120}120}
121121
122pub fn isVisible(self: Symbol) bool {122pub fn isVisible(symbol: Symbol) bool {
123 return self.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) == 0;123 return symbol.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) == 0;
124}124}
125125
126pub fn isLocal(self: Symbol) bool {126pub fn isLocal(symbol: Symbol) bool {
127 return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) != 0;127 return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) != 0;
128}128}
129129
130pub fn isGlobal(self: Symbol) bool {130pub fn isGlobal(symbol: Symbol) bool {
131 return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) == 0;131 return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) == 0;
132}132}
133133
134pub fn isHidden(self: Symbol) bool {134pub fn isHidden(symbol: Symbol) bool {
135 return self.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) != 0;135 return symbol.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) != 0;
136}136}
137137
138pub fn isNoStrip(self: Symbol) bool {138pub fn isNoStrip(symbol: Symbol) bool {
139 return self.flags & @enumToInt(Flag.WASM_SYM_NO_STRIP) != 0;139 return symbol.flags & @enumToInt(Flag.WASM_SYM_NO_STRIP) != 0;
140}140}
141141
142pub fn isExported(self: Symbol) bool {142pub fn isExported(symbol: Symbol) bool {
143 if (self.isUndefined() or self.isLocal()) return false;143 if (symbol.isUndefined() or symbol.isLocal()) return false;
144 if (self.isHidden()) return false;144 if (symbol.isHidden()) return false;
145 if (self.hasFlag(.WASM_SYM_EXPORTED)) return true;145 if (symbol.hasFlag(.WASM_SYM_EXPORTED)) return true;
146 if (self.hasFlag(.WASM_SYM_BINDING_WEAK)) return false;146 if (symbol.hasFlag(.WASM_SYM_BINDING_WEAK)) return false;
147 return true;147 return true;
148}148}
149149
150pub fn isWeak(self: Symbol) bool {150pub fn isWeak(symbol: Symbol) bool {
151 return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_WEAK) != 0;151 return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_WEAK) != 0;
152}152}
153153
154/// Formats the symbol into human-readable text154/// Formats the symbol into human-readable text
155pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {155pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
156 _ = fmt;156 _ = fmt;
157 _ = options;157 _ = options;
158158
159 const kind_fmt: u8 = switch (self.tag) {159 const kind_fmt: u8 = switch (symbol.tag) {
160 .function => 'F',160 .function => 'F',
161 .data => 'D',161 .data => 'D',
162 .global => 'G',162 .global => 'G',
...@@ -165,12 +165,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt...@@ -165,12 +165,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt
165 .table => 'T',165 .table => 'T',
166 .dead => '-',166 .dead => '-',
167 };167 };
168 const visible: []const u8 = if (self.isVisible()) "yes" else "no";168 const visible: []const u8 = if (symbol.isVisible()) "yes" else "no";
169 const binding: []const u8 = if (self.isLocal()) "local" else "global";169 const binding: []const u8 = if (symbol.isLocal()) "local" else "global";
170 const undef: []const u8 = if (self.isUndefined()) "undefined" else "";170 const undef: []const u8 = if (symbol.isUndefined()) "undefined" else "";
171171
172 try writer.print(172 try writer.print(
173 "{c} binding={s} visible={s} id={d} name_offset={d} {s}",173 "{c} binding={s} visible={s} id={d} name_offset={d} {s}",
174 .{ kind_fmt, binding, visible, self.index, self.name, undef },174 .{ kind_fmt, binding, visible, symbol.index, symbol.name, undef },
175 );175 );
176}176}
src/link/Wasm/types.zig+5-5
...@@ -202,22 +202,22 @@ pub const Feature = struct {...@@ -202,22 +202,22 @@ pub const Feature = struct {
202 required = '=',202 required = '=',
203 };203 };
204204
205 pub fn toString(self: Feature) []const u8 {205 pub fn toString(feature: Feature) []const u8 {
206 return switch (self.tag) {206 return switch (feature.tag) {
207 .bulk_memory => "bulk-memory",207 .bulk_memory => "bulk-memory",
208 .exception_handling => "exception-handling",208 .exception_handling => "exception-handling",
209 .mutable_globals => "mutable-globals",209 .mutable_globals => "mutable-globals",
210 .nontrapping_fptoint => "nontrapping-fptoint",210 .nontrapping_fptoint => "nontrapping-fptoint",
211 .sign_ext => "sign-ext",211 .sign_ext => "sign-ext",
212 .tail_call => "tail-call",212 .tail_call => "tail-call",
213 else => @tagName(self),213 else => @tagName(feature),
214 };214 };
215 }215 }
216216
217 pub fn format(self: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {217 pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
218 _ = opt;218 _ = opt;
219 _ = fmt;219 _ = fmt;
220 try writer.print("{c} {s}", .{ self.prefix, self.toString() });220 try writer.print("{c} {s}", .{ feature.prefix, feature.toString() });
221 }221 }
222};222};
223223