| ... | ... | @@ -34,6 +34,8 @@ pub const base_tag = link.File.Tag.wasm; |
| 34 | 34 | pub const DeclBlock = Atom; |
| 35 | 35 | |
| 36 | 36 | base: link.File, |
| 37 | /// Output name of the file |
| 38 | name: []const u8, |
| 37 | 39 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| 38 | 40 | llvm_object: ?*LlvmObject = null, |
| 39 | 41 | /// When importing objects from the host environment, a name must be supplied. |
| ... | ... | @@ -156,6 +158,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 156 | 158 | // TODO: read the file and keep valid parts instead of truncating |
| 157 | 159 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); |
| 158 | 160 | wasm_bin.base.file = file; |
| 161 | wasm_bin.name = sub_path; |
| 159 | 162 | |
| 160 | 163 | try file.writeAll(&(wasm.magic ++ wasm.version)); |
| 161 | 164 | |
| ... | ... | @@ -170,7 +173,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 170 | 173 | }; |
| 171 | 174 | const symbol = try wasm_bin.symbols.addOne(allocator); |
| 172 | 175 | symbol.* = .{ |
| 173 | | .name = "__stack_pointer", |
| 176 | .name = try allocator.dupeZ(u8, "__stack_pointer"), |
| 174 | 177 | .tag = .global, |
| 175 | 178 | .flags = 0, |
| 176 | 179 | .index = 0, |
| ... | ... | @@ -188,6 +191,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 188 | 191 | .file = null, |
| 189 | 192 | .allocator = gpa, |
| 190 | 193 | }, |
| 194 | .name = undefined, |
| 191 | 195 | }; |
| 192 | 196 | const use_llvm = build_options.have_llvm and options.use_llvm; |
| 193 | 197 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| ... | ... | @@ -233,6 +237,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 233 | 237 | .file = object_index, |
| 234 | 238 | .index = sym_index, |
| 235 | 239 | }; |
| 240 | const sym_name = std.mem.sliceTo(symbol.name, 0); |
| 236 | 241 | |
| 237 | 242 | if (symbol.isLocal()) { |
| 238 | 243 | if (symbol.isUndefined()) { |
| ... | ... | @@ -247,21 +252,23 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 247 | 252 | // TODO: locals are allowed to have duplicate symbol names |
| 248 | 253 | // TODO: Store undefined symbols so we can verify at the end if they've all been found |
| 249 | 254 | // if not, emit an error (unless --allow-undefined is enabled). |
| 250 | | const maybe_existing = try self.globals.getOrPut(self.base.allocator, std.mem.sliceTo(symbol.name, 0)); |
| 255 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name); |
| 251 | 256 | if (!maybe_existing.found_existing) { |
| 252 | 257 | maybe_existing.value_ptr.* = location; |
| 253 | | |
| 254 | | try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location); |
| 255 | 258 | continue; |
| 256 | 259 | } |
| 257 | 260 | |
| 258 | 261 | const existing_loc = maybe_existing.value_ptr.*; |
| 259 | 262 | const existing_sym: *Symbol = existing_loc.getSymbol(self); |
| 260 | 263 | |
| 264 | const existing_file_path = if (existing_loc.file) |file| blk: { |
| 265 | break :blk self.objects.items[file].name; |
| 266 | } else self.name; |
| 267 | |
| 261 | 268 | if (!existing_sym.isUndefined()) { |
| 262 | 269 | if (!symbol.isUndefined()) { |
| 263 | 270 | log.err("symbol '{s}' defined multiple times", .{existing_sym.name}); |
| 264 | | log.err(" first definition in '{s}'", .{self.objects.items[existing_loc.file.?].name}); |
| 271 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 265 | 272 | log.err(" next definition in '{s}'", .{object.name}); |
| 266 | 273 | return error.SymbolCollision; |
| 267 | 274 | } |
| ... | ... | @@ -271,11 +278,11 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 271 | 278 | |
| 272 | 279 | // simply overwrite with the new symbol |
| 273 | 280 | log.info("Overwriting symbol '{s}'", .{symbol.name}); |
| 274 | | log.info(" first definition in '{s}'", .{self.objects.items[existing_loc.file.?].name}); |
| 275 | | log.info(" next definition in '{s}'", .{object.name}); |
| 281 | log.info(" old definition in '{s}'", .{existing_file_path}); |
| 282 | log.info(" new definition in '{s}'", .{object.name}); |
| 276 | 283 | try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location); |
| 277 | 284 | maybe_existing.value_ptr.* = location; |
| 278 | | try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location); |
| 285 | try self.globals.put(self.base.allocator, sym_name, location); |
| 279 | 286 | } |
| 280 | 287 | } |
| 281 | 288 | |
| ... | ... | @@ -302,6 +309,12 @@ pub fn deinit(self: *Wasm) void { |
| 302 | 309 | object.deinit(gpa); |
| 303 | 310 | } |
| 304 | 311 | |
| 312 | for (self.symbols.items) |symbol| { |
| 313 | if (symbol.tag != .dead) { |
| 314 | gpa.free(mem.sliceTo(symbol.name, 0)); |
| 315 | } |
| 316 | } |
| 317 | |
| 305 | 318 | self.decls.deinit(gpa); |
| 306 | 319 | self.symbols.deinit(gpa); |
| 307 | 320 | self.symbols_free_list.deinit(gpa); |
| ... | ... | @@ -441,7 +454,7 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 441 | 454 | const atom: *Atom = &decl.link.wasm; |
| 442 | 455 | atom.size = @intCast(u32, code.len); |
| 443 | 456 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); |
| 444 | | self.symbols.items[atom.sym_index].name = decl.name; |
| 457 | self.symbols.items[atom.sym_index].name = try self.base.allocator.dupeZ(u8, std.mem.sliceTo(decl.name, 0)); |
| 445 | 458 | try atom.code.appendSlice(self.base.allocator, code); |
| 446 | 459 | } |
| 447 | 460 | |
| ... | ... | @@ -449,8 +462,10 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 449 | 462 | /// and then append it as a 'contained' atom onto the Decl. |
| 450 | 463 | pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 { |
| 451 | 464 | assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions |
| 465 | const local_index = decl.link.wasm.locals.items.len; |
| 466 | const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index }); |
| 452 | 467 | var symbol: Symbol = .{ |
| 453 | | .name = "unnamed_local", |
| 468 | .name = name, |
| 454 | 469 | .flags = 0, |
| 455 | 470 | .tag = .data, |
| 456 | 471 | .index = undefined, |
| ... | ... | @@ -494,7 +509,7 @@ pub fn getDeclVAddr( |
| 494 | 509 | const atom = decl.link.wasm.symbolAtom(symbol_index); |
| 495 | 510 | const is_wasm32 = self.base.options.target.cpu.arch == .wasm32; |
| 496 | 511 | if (ty.zigTypeTag() == .Fn) { |
| 497 | | std.debug.assert(addend == 0); // addend not allowed for function relocations |
| 512 | assert(addend == 0); // addend not allowed for function relocations |
| 498 | 513 | // We found a function pointer, so add it to our table, |
| 499 | 514 | // as function pointers are not allowed to be stored inside the data section. |
| 500 | 515 | // They are instead stored in a function table which are called by index. |
| ... | ... | @@ -543,15 +558,13 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 543 | 558 | self.symbols.items[atom.sym_index].tag = .dead; // to ensure it does not end in the names section |
| 544 | 559 | for (atom.locals.items) |local_atom| { |
| 545 | 560 | self.symbols.items[local_atom.sym_index].tag = .dead; // also for any local symbol |
| 561 | // self.base.allocator.free(mem.sliceTo(self.symbols.items[local_atom.sym_index].name, 0)); |
| 546 | 562 | self.symbols_free_list.append(self.base.allocator, local_atom.sym_index) catch {}; |
| 547 | 563 | } |
| 564 | // self.base.allocator.free(mem.sliceTo(self.symbols.items[atom.sym_index].name, 0)); |
| 548 | 565 | |
| 549 | 566 | if (decl.isExtern()) { |
| 550 | | const import = self.imports.fetchRemove(.{ .file = null, .index = atom.sym_index }).?.value; |
| 551 | | switch (import.kind) { |
| 552 | | .function => self.imported_functions_count -= 1, |
| 553 | | else => unreachable, |
| 554 | | } |
| 567 | assert(self.imports.remove(.{ .file = null, .index = atom.sym_index })); |
| 555 | 568 | } |
| 556 | 569 | |
| 557 | 570 | atom.deinit(self.base.allocator); |
| ... | ... | @@ -577,16 +590,18 @@ fn mapFunctionTable(self: *Wasm) void { |
| 577 | 590 | fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 578 | 591 | const symbol_index = decl.link.wasm.sym_index; |
| 579 | 592 | const symbol: *Symbol = &self.symbols.items[symbol_index]; |
| 580 | | symbol.name = decl.name; |
| 593 | const decl_name = mem.sliceTo(decl.name, 0); |
| 594 | symbol.name = try self.base.allocator.dupeZ(u8, decl_name); |
| 581 | 595 | symbol.setUndefined(true); |
| 596 | // also add it as a global so it can be resolved |
| 597 | try self.globals.put(self.base.allocator, decl_name, .{ .file = null, .index = symbol_index }); |
| 582 | 598 | switch (decl.ty.zigTypeTag()) { |
| 583 | 599 | .Fn => { |
| 584 | 600 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); |
| 585 | 601 | const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: { |
| 586 | | break :blk std.mem.sliceTo(lib_name, 0); |
| 602 | break :blk mem.sliceTo(lib_name, 0); |
| 587 | 603 | } else self.host_name; |
| 588 | 604 | if (!gop.found_existing) { |
| 589 | | self.imported_functions_count += 1; |
| 590 | 605 | gop.value_ptr.* = .{ |
| 591 | 606 | .module_name = module_name, |
| 592 | 607 | .name = std.mem.span(symbol.name), |
| ... | ... | @@ -608,9 +623,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 608 | 623 | const symbol: *Symbol = &self.symbols.items[atom.sym_index]; |
| 609 | 624 | const final_index: u32 = switch (kind) { |
| 610 | 625 | .function => |fn_data| result: { |
| 611 | | const type_index = fn_data.type_index; |
| 612 | 626 | const index = @intCast(u32, self.functions.items.len + self.imported_functions_count); |
| 613 | | try self.functions.append(self.base.allocator, .{ .type_index = type_index }); |
| 627 | try self.functions.append(self.base.allocator, .{ .type_index = fn_data.type_index }); |
| 614 | 628 | symbol.tag = .function; |
| 615 | 629 | symbol.index = index; |
| 616 | 630 | |
| ... | ... | @@ -641,6 +655,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 641 | 655 | break :blk index; |
| 642 | 656 | }; |
| 643 | 657 | const info_index = @intCast(u32, self.segment_info.items.len); |
| 658 | // TODO: Add mutables global decls to .bss section instead |
| 644 | 659 | const segment_name = try std.mem.concat(self.base.allocator, u8, &.{ |
| 645 | 660 | ".rodata.", |
| 646 | 661 | std.mem.span(symbol.name), |
| ... | ... | @@ -684,7 +699,7 @@ fn allocateAtoms(self: *Wasm) !void { |
| 684 | 699 | offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment); |
| 685 | 700 | atom.offset = offset; |
| 686 | 701 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 687 | | self.symbols.items[atom.sym_index].name, |
| 702 | (SymbolLoc{ .file = atom.file, .index = atom.sym_index }).getSymbol(self).name, |
| 688 | 703 | offset, |
| 689 | 704 | offset + atom.size, |
| 690 | 705 | atom.size, |
| ... | ... | @@ -695,7 +710,7 @@ fn allocateAtoms(self: *Wasm) !void { |
| 695 | 710 | } |
| 696 | 711 | } |
| 697 | 712 | |
| 698 | | fn setupImports(self: *Wasm) void { |
| 713 | fn setupImports(self: *Wasm) !void { |
| 699 | 714 | for (self.resolved_symbols.items) |symbol_loc| { |
| 700 | 715 | if (symbol_loc.file == null) { |
| 701 | 716 | // imports generated by Zig code are already in the `import` section |
| ... | ... | @@ -708,7 +723,7 @@ fn setupImports(self: *Wasm) void { |
| 708 | 723 | } |
| 709 | 724 | |
| 710 | 725 | log.debug("Symbol '{s}' will be imported from the host", .{symbol.name}); |
| 711 | | const import = self.objects.items[symbol_loc.file.?].findImport(symbol.externalType(), symbol.index); |
| 726 | const import = self.objects.items[symbol_loc.file.?].findImport(symbol.tag.externalType(), symbol.index); |
| 712 | 727 | // TODO: De-duplicate imports |
| 713 | 728 | try self.imports.putNoClobber(self.base.allocator, symbol_loc, import); |
| 714 | 729 | } |
| ... | ... | @@ -737,6 +752,9 @@ fn setupImports(self: *Wasm) void { |
| 737 | 752 | else => unreachable, |
| 738 | 753 | } |
| 739 | 754 | } |
| 755 | self.imported_functions_count = function_index; |
| 756 | self.imported_globals_count = global_index; |
| 757 | self.imported_tables_count = table_index; |
| 740 | 758 | } |
| 741 | 759 | |
| 742 | 760 | /// Takes the global, function and table section from each linked object file |
| ... | ... | @@ -761,12 +779,13 @@ fn mergeSections(self: *Wasm) !void { |
| 761 | 779 | |
| 762 | 780 | const object = self.objects.items[sym_loc.file.?]; |
| 763 | 781 | const symbol = &object.symtable[sym_loc.index]; |
| 764 | | if (symbol.isUndefined()) { |
| 782 | if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) { |
| 765 | 783 | // Skip undefined symbols as they go in the `import` section |
| 784 | // Also skip symbols that do not need to have a section merged. |
| 766 | 785 | continue; |
| 767 | 786 | } |
| 768 | 787 | |
| 769 | | const offset = object.importedCountByKind(symbol.externalType()); |
| 788 | const offset = object.importedCountByKind(symbol.tag.externalType()); |
| 770 | 789 | const index = symbol.index - offset; |
| 771 | 790 | switch (symbol.tag) { |
| 772 | 791 | .function => { |
| ... | ... | @@ -776,7 +795,7 @@ fn mergeSections(self: *Wasm) !void { |
| 776 | 795 | }, |
| 777 | 796 | .global => { |
| 778 | 797 | const original_global = object.globals[index]; |
| 779 | | symbol.index = @intCast(u32, self.globals.items.len) + self.imported_globals_count; |
| 798 | symbol.index = @intCast(u32, self.wasm_globals.items.len) + self.imported_globals_count; |
| 780 | 799 | try self.wasm_globals.append(self.base.allocator, original_global); |
| 781 | 800 | }, |
| 782 | 801 | .table => { |
| ... | ... | @@ -790,7 +809,7 @@ fn mergeSections(self: *Wasm) !void { |
| 790 | 809 | |
| 791 | 810 | log.debug("Merged ({d}) functions", .{self.functions.items.len}); |
| 792 | 811 | log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len}); |
| 793 | | log.debug("Merged ({d}) tables", .{self.tables.tems.len}); |
| 812 | log.debug("Merged ({d}) tables", .{self.tables.items.len}); |
| 794 | 813 | } |
| 795 | 814 | |
| 796 | 815 | /// Merges function types of all object files into the final |
| ... | ... | @@ -811,13 +830,13 @@ fn mergeTypes(self: *Wasm) !void { |
| 811 | 830 | |
| 812 | 831 | if (symbol.isUndefined()) { |
| 813 | 832 | log.debug("Adding type from extern function '{s}'", .{symbol.name}); |
| 814 | | const import: *wasm.Import = self.imports.getPtr(sym_loc); |
| 815 | | const original_type = object.types[import.kind.function]; |
| 833 | const import: *wasm.Import = self.imports.getPtr(sym_loc).?; |
| 834 | const original_type = object.func_types[import.kind.function]; |
| 816 | 835 | import.kind.function = try self.putOrGetFuncType(original_type); |
| 817 | 836 | } else { |
| 818 | 837 | log.debug("Adding type from function '{s}'", .{symbol.name}); |
| 819 | 838 | const func = &self.functions.items[symbol.index - self.imported_functions_count]; |
| 820 | | func.type_index = try self.putOrGetFuncType(object.types[func.type_index]); |
| 839 | func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]); |
| 821 | 840 | } |
| 822 | 841 | } |
| 823 | 842 | log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len}); |
| ... | ... | @@ -835,7 +854,11 @@ fn setupExports(self: *Wasm) !void { |
| 835 | 854 | const symbol = sym_loc.getSymbol(self); |
| 836 | 855 | if (!symbol.isExported()) continue; |
| 837 | 856 | |
| 838 | | const exp: wasm.Export = .{ .name = symbol.name, .kind = symbol.externalType(), .index = symbol.index }; |
| 857 | const exp: wasm.Export = .{ |
| 858 | .name = mem.sliceTo(symbol.name, 0), |
| 859 | .kind = symbol.tag.externalType(), |
| 860 | .index = symbol.index, |
| 861 | }; |
| 839 | 862 | log.debug("Appending export for symbol '{s}' at index: ({d})", .{ exp.name, exp.index }); |
| 840 | 863 | try self.exports.append(self.base.allocator, exp); |
| 841 | 864 | } |
| ... | ... | @@ -948,6 +971,41 @@ fn setupMemory(self: *Wasm) !void { |
| 948 | 971 | } |
| 949 | 972 | } |
| 950 | 973 | |
| 974 | /// From a given object's index and the index of the segment, returns the corresponding |
| 975 | /// index of the segment within the final data section. When the segment does not yet |
| 976 | /// exist, a new one will be initialized and appended. The new index will be returned in that case. |
| 977 | pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !u32 { |
| 978 | const object: Object = self.objects.items[object_index]; |
| 979 | const relocatable_data = object.relocatable_data[relocatable_index]; |
| 980 | const index = @intCast(u32, self.segments.items.len); |
| 981 | |
| 982 | switch (relocatable_data.type) { |
| 983 | .data => { |
| 984 | const segment_info = object.segment_info[relocatable_data.index]; |
| 985 | const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName()); |
| 986 | if (!result.found_existing) { |
| 987 | result.value_ptr.* = index; |
| 988 | try self.segments.append(self.base.allocator, .{ |
| 989 | .alignment = 1, |
| 990 | .size = 0, |
| 991 | .offset = 0, |
| 992 | }); |
| 993 | return index; |
| 994 | } else return result.value_ptr.*; |
| 995 | }, |
| 996 | .code => return self.code_section_index orelse blk: { |
| 997 | self.code_section_index = index; |
| 998 | try self.segments.append(self.base.allocator, .{ |
| 999 | .alignment = 1, |
| 1000 | .size = 0, |
| 1001 | .offset = 0, |
| 1002 | }); |
| 1003 | break :blk index; |
| 1004 | }, |
| 1005 | .custom => return error.@"TODO: Custom section relocations for wasm", |
| 1006 | } |
| 1007 | } |
| 1008 | |
| 951 | 1009 | fn resetState(self: *Wasm) void { |
| 952 | 1010 | for (self.segment_info.items) |*segment_info| { |
| 953 | 1011 | self.base.allocator.free(segment_info.name); |
| ... | ... | @@ -1015,7 +1073,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1015 | 1073 | // When we finish/error we reset the state of the linker |
| 1016 | 1074 | // So we can rebuild the binary file on each incremental update |
| 1017 | 1075 | defer self.resetState(); |
| 1018 | | self.setupImports(); |
| 1076 | try self.setupImports(); |
| 1019 | 1077 | var decl_it = self.decls.keyIterator(); |
| 1020 | 1078 | while (decl_it.next()) |decl| { |
| 1021 | 1079 | if (decl.*.isExtern()) continue; |
| ... | ... | @@ -1050,7 +1108,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1050 | 1108 | { |
| 1051 | 1109 | const header_offset = try reserveVecSectionHeader(file); |
| 1052 | 1110 | const writer = file.writer(); |
| 1053 | | |
| 1111 | log.debug("Writing type section. Count: ({d})", .{self.func_types.items.len}); |
| 1054 | 1112 | for (self.func_types.items) |func_type| { |
| 1055 | 1113 | try leb.writeULEB128(writer, wasm.function_type); |
| 1056 | 1114 | try leb.writeULEB128(writer, @intCast(u32, func_type.params.len)); |
| ... | ... | @@ -1095,8 +1153,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1095 | 1153 | |
| 1096 | 1154 | var it = self.imports.iterator(); |
| 1097 | 1155 | while (it.next()) |entry| { |
| 1098 | | const import_symbol = self.symbols.items[entry.key_ptr.*]; |
| 1099 | | std.debug.assert(import_symbol.isUndefined()); |
| 1156 | assert(entry.key_ptr.*.getSymbol(self).isUndefined()); |
| 1100 | 1157 | const import = entry.value_ptr.*; |
| 1101 | 1158 | try emitImport(writer, import); |
| 1102 | 1159 | } |
| ... | ... | @@ -1207,7 +1264,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1207 | 1264 | .Fn => { |
| 1208 | 1265 | const target = exprt.exported_decl.link.wasm.sym_index; |
| 1209 | 1266 | const target_symbol = self.symbols.items[target]; |
| 1210 | | std.debug.assert(target_symbol.tag == .function); |
| 1267 | assert(target_symbol.tag == .function); |
| 1211 | 1268 | // Type of the export |
| 1212 | 1269 | try writer.writeByte(wasm.externalKind(.function)); |
| 1213 | 1270 | // Exported function index |
| ... | ... | @@ -1323,8 +1380,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1323 | 1380 | try writer.writeByteNTimes(0, diff); |
| 1324 | 1381 | current_offset += diff; |
| 1325 | 1382 | } |
| 1326 | | std.debug.assert(current_offset == atom.offset); |
| 1327 | | std.debug.assert(atom.code.items.len == atom.size); |
| 1383 | assert(current_offset == atom.offset); |
| 1384 | assert(atom.code.items.len == atom.size); |
| 1328 | 1385 | try writer.writeAll(atom.code.items); |
| 1329 | 1386 | |
| 1330 | 1387 | current_offset += atom.size; |
| ... | ... | @@ -1335,10 +1392,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1335 | 1392 | // segments are aligned. |
| 1336 | 1393 | if (current_offset != segment.size) { |
| 1337 | 1394 | try writer.writeByteNTimes(0, segment.size - current_offset); |
| 1395 | current_offset += segment.size - current_offset; |
| 1338 | 1396 | } |
| 1339 | 1397 | break; |
| 1340 | 1398 | } |
| 1341 | 1399 | } |
| 1400 | assert(current_offset == segment.size); |
| 1342 | 1401 | } |
| 1343 | 1402 | |
| 1344 | 1403 | try writeVecSectionHeader( |
| ... | ... | @@ -1371,8 +1430,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1371 | 1430 | |
| 1372 | 1431 | for (self.symbols.items) |symbol| { |
| 1373 | 1432 | switch (symbol.tag) { |
| 1374 | | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }), |
| 1375 | | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }), |
| 1433 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |
| 1434 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }), |
| 1376 | 1435 | else => {}, |
| 1377 | 1436 | } |
| 1378 | 1437 | } |