| ... | ... | @@ -37,12 +37,22 @@ pub const Relocation = types.Relocation; |
| 37 | 37 | pub const base_tag: link.File.Tag = .wasm; |
| 38 | 38 | |
| 39 | 39 | base: link.File, |
| 40 | /// Symbol name of the entry function to export |
| 40 | 41 | entry_name: ?[]const u8, |
| 42 | /// When true, will allow undefined symbols |
| 41 | 43 | import_symbols: bool, |
| 44 | /// List of *global* symbol names to export to the host environment. |
| 42 | 45 | export_symbol_names: []const []const u8, |
| 46 | /// When defined, sets the start of the data section. |
| 43 | 47 | global_base: ?u64, |
| 48 | /// When defined, sets the initial memory size of the memory. |
| 44 | 49 | initial_memory: ?u64, |
| 50 | /// When defined, sets the maximum memory size of the memory. |
| 45 | 51 | max_memory: ?u64, |
| 52 | /// When true, will import the function table from the host environment. |
| 53 | import_table: bool, |
| 54 | /// When true, will export the function table to the host environment. |
| 55 | export_table: bool, |
| 46 | 56 | /// Output name of the file |
| 47 | 57 | name: []const u8, |
| 48 | 58 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| ... | ... | @@ -52,16 +62,8 @@ llvm_object: ?*LlvmObject = null, |
| 52 | 62 | /// to support existing code. |
| 53 | 63 | /// TODO: Allow setting this through a flag? |
| 54 | 64 | host_name: []const u8 = "env", |
| 55 | | /// List of all `Decl` that are currently alive. |
| 56 | | /// Each index maps to the corresponding `Atom.Index`. |
| 57 | | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, |
| 58 | | /// Mapping between an `Atom` and its type index representing the Wasm |
| 59 | | /// type of the function signature. |
| 60 | | atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .{}, |
| 61 | 65 | /// List of all symbols generated by Zig code. |
| 62 | | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 63 | | /// List of symbol indexes which are free to be used. |
| 64 | | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 66 | synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 65 | 67 | /// Maps atoms to their segment index |
| 66 | 68 | atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, |
| 67 | 69 | /// List of all atoms. |
| ... | ... | @@ -107,8 +109,6 @@ data_segments: std.StringArrayHashMapUnmanaged(u32) = .{}, |
| 107 | 109 | segment_info: std.AutoArrayHashMapUnmanaged(u32, types.Segment) = .{}, |
| 108 | 110 | /// Deduplicated string table for strings used by symbols, imports and exports. |
| 109 | 111 | string_table: StringTable = .{}, |
| 110 | | /// Debug information for wasm |
| 111 | | dwarf: ?Dwarf = null, |
| 112 | 112 | |
| 113 | 113 | // Output sections |
| 114 | 114 | /// Output type section |
| ... | ... | @@ -170,36 +170,10 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .{}, |
| 170 | 170 | /// Note: The value represents the offset into the string table, rather than the actual string. |
| 171 | 171 | export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, |
| 172 | 172 | |
| 173 | | /// Represents the symbol index of the error name table |
| 174 | | /// When this is `null`, no code references an error using runtime `@errorName`. |
| 175 | | /// During initializion, a symbol with corresponding atom will be created that is |
| 176 | | /// used to perform relocations to the pointer of this table. |
| 177 | | /// The actual table is populated during `flush`. |
| 178 | | error_table_symbol: ?u32 = null, |
| 179 | | |
| 180 | | // Debug section atoms. These are only set when the current compilation |
| 181 | | // unit contains Zig code. The lifetime of these atoms are extended |
| 182 | | // until the end of the compiler's lifetime. Meaning they're not freed |
| 183 | | // during `flush()` in incremental-mode. |
| 184 | | debug_info_atom: ?Atom.Index = null, |
| 185 | | debug_line_atom: ?Atom.Index = null, |
| 186 | | debug_loc_atom: ?Atom.Index = null, |
| 187 | | debug_ranges_atom: ?Atom.Index = null, |
| 188 | | debug_abbrev_atom: ?Atom.Index = null, |
| 189 | | debug_str_atom: ?Atom.Index = null, |
| 190 | | debug_pubnames_atom: ?Atom.Index = null, |
| 191 | | debug_pubtypes_atom: ?Atom.Index = null, |
| 192 | | |
| 193 | 173 | /// List of atom indexes of functions that are generated by the backend, |
| 194 | 174 | /// rather than by the linker. |
| 195 | 175 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 196 | 176 | |
| 197 | | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. |
| 198 | | anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, |
| 199 | | |
| 200 | | import_table: bool, |
| 201 | | export_table: bool, |
| 202 | | |
| 203 | 177 | pub const Alignment = types.Alignment; |
| 204 | 178 | |
| 205 | 179 | pub const Segment = struct { |
| ... | ... | @@ -238,27 +212,27 @@ pub const SymbolLoc = struct { |
| 238 | 212 | file: ?u16, |
| 239 | 213 | |
| 240 | 214 | /// From a given location, returns the corresponding symbol in the wasm binary |
| 241 | | pub fn getSymbol(loc: SymbolLoc, wasm_bin: *const Wasm) *Symbol { |
| 242 | | if (wasm_bin.discarded.get(loc)) |new_loc| { |
| 243 | | return new_loc.getSymbol(wasm_bin); |
| 215 | pub fn getSymbol(loc: SymbolLoc, wasm_file: *const Wasm) *Symbol { |
| 216 | if (wasm_file.discarded.get(loc)) |new_loc| { |
| 217 | return new_loc.getSymbol(wasm_file); |
| 244 | 218 | } |
| 245 | 219 | if (loc.file) |object_index| { |
| 246 | | const object = wasm_bin.objects.items[object_index]; |
| 220 | const object = wasm_file.objects.items[object_index]; |
| 247 | 221 | return &object.symtable[loc.index]; |
| 248 | 222 | } |
| 249 | | return &wasm_bin.symbols.items[loc.index]; |
| 223 | return &wasm_file.synthetic_symbols.items[loc.index]; |
| 250 | 224 | } |
| 251 | 225 | |
| 252 | 226 | /// From a given location, returns the name of the symbol. |
| 253 | | pub fn getName(loc: SymbolLoc, wasm_bin: *const Wasm) []const u8 { |
| 254 | | if (wasm_bin.discarded.get(loc)) |new_loc| { |
| 255 | | return new_loc.getName(wasm_bin); |
| 227 | pub fn getName(loc: SymbolLoc, wasm_file: *const Wasm) []const u8 { |
| 228 | if (wasm_file.discarded.get(loc)) |new_loc| { |
| 229 | return new_loc.getName(wasm_file); |
| 256 | 230 | } |
| 257 | 231 | if (loc.file) |object_index| { |
| 258 | | const object = wasm_bin.objects.items[object_index]; |
| 232 | const object = wasm_file.objects.items[object_index]; |
| 259 | 233 | return object.string_table.get(object.symtable[loc.index].name); |
| 260 | 234 | } |
| 261 | | return wasm_bin.string_table.get(wasm_bin.symbols.items[loc.index].name); |
| 235 | return wasm_file.string_table.get(wasm_file.synthetic_symbols.items[loc.index].name); |
| 262 | 236 | } |
| 263 | 237 | |
| 264 | 238 | /// From a given symbol location, returns the final location. |
| ... | ... | @@ -266,9 +240,9 @@ pub const SymbolLoc = struct { |
| 266 | 240 | /// in a different file, this will return said location. |
| 267 | 241 | /// If the symbol wasn't replaced by another, this will return |
| 268 | 242 | /// the given location itwasm. |
| 269 | | pub fn finalLoc(loc: SymbolLoc, wasm_bin: *const Wasm) SymbolLoc { |
| 270 | | if (wasm_bin.discarded.get(loc)) |new_loc| { |
| 271 | | return new_loc.finalLoc(wasm_bin); |
| 243 | pub fn finalLoc(loc: SymbolLoc, wasm_file: *const Wasm) SymbolLoc { |
| 244 | if (wasm_file.discarded.get(loc)) |new_loc| { |
| 245 | return new_loc.finalLoc(wasm_file); |
| 272 | 246 | } |
| 273 | 247 | return loc; |
| 274 | 248 | } |
| ... | ... | @@ -594,10 +568,10 @@ fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !Symbol |
| 594 | 568 | } |
| 595 | 569 | |
| 596 | 570 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { |
| 597 | | const sym_index = @as(u32, @intCast(wasm.symbols.items.len)); |
| 571 | const sym_index = @as(u32, @intCast(wasm.synthetic_symbols.items.len)); |
| 598 | 572 | const loc: SymbolLoc = .{ .index = sym_index, .file = null }; |
| 599 | 573 | const gpa = wasm.base.comp.gpa; |
| 600 | | try wasm.symbols.append(gpa, .{ |
| 574 | try wasm.synthetic_symbols.append(gpa, .{ |
| 601 | 575 | .name = name_offset, |
| 602 | 576 | .flags = 0, |
| 603 | 577 | .tag = tag, |
| ... | ... | @@ -609,24 +583,6 @@ fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) ! |
| 609 | 583 | return loc; |
| 610 | 584 | } |
| 611 | 585 | |
| 612 | | /// Initializes symbols and atoms for the debug sections |
| 613 | | /// Initialization is only done when compiling Zig code. |
| 614 | | /// When Zig is invoked as a linker instead, the atoms |
| 615 | | /// and symbols come from the object files instead. |
| 616 | | pub fn initDebugSections(wasm: *Wasm) !void { |
| 617 | | if (wasm.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections |
| 618 | | assert(wasm.debug_info_index == null); |
| 619 | | // this will create an Atom and set the index for us. |
| 620 | | wasm.debug_info_atom = try wasm.createDebugSectionForIndex(&wasm.debug_info_index, ".debug_info"); |
| 621 | | wasm.debug_line_atom = try wasm.createDebugSectionForIndex(&wasm.debug_line_index, ".debug_line"); |
| 622 | | wasm.debug_loc_atom = try wasm.createDebugSectionForIndex(&wasm.debug_loc_index, ".debug_loc"); |
| 623 | | wasm.debug_abbrev_atom = try wasm.createDebugSectionForIndex(&wasm.debug_abbrev_index, ".debug_abbrev"); |
| 624 | | wasm.debug_ranges_atom = try wasm.createDebugSectionForIndex(&wasm.debug_ranges_index, ".debug_ranges"); |
| 625 | | wasm.debug_str_atom = try wasm.createDebugSectionForIndex(&wasm.debug_str_index, ".debug_str"); |
| 626 | | wasm.debug_pubnames_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubnames_index, ".debug_pubnames"); |
| 627 | | wasm.debug_pubtypes_atom = try wasm.createDebugSectionForIndex(&wasm.debug_pubtypes_index, ".debug_pubtypes"); |
| 628 | | } |
| 629 | | |
| 630 | 586 | fn parseInputFiles(wasm: *Wasm, files: []const []const u8) !void { |
| 631 | 587 | for (files) |path| { |
| 632 | 588 | if (try wasm.parseObjectFile(path)) continue; |
| ... | ... | @@ -652,33 +608,14 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { |
| 652 | 608 | return true; |
| 653 | 609 | } |
| 654 | 610 | |
| 655 | | /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. |
| 656 | | /// When the index was not found, a new `Atom` will be created, and its index will be returned. |
| 657 | | /// The newly created Atom is empty with default fields as specified by `Atom.empty`. |
| 658 | | pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index { |
| 659 | | const gpa = wasm.base.comp.gpa; |
| 660 | | const gop = try wasm.decls.getOrPut(gpa, decl_index); |
| 661 | | if (!gop.found_existing) { |
| 662 | | const atom_index = try wasm.createAtom(); |
| 663 | | gop.value_ptr.* = atom_index; |
| 664 | | const atom = wasm.getAtom(atom_index); |
| 665 | | const symbol = atom.symbolLoc().getSymbol(wasm); |
| 666 | | const mod = wasm.base.comp.module.?; |
| 667 | | const decl = mod.declPtr(decl_index); |
| 668 | | const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); |
| 669 | | symbol.name = try wasm.string_table.put(gpa, full_name); |
| 670 | | } |
| 671 | | return gop.value_ptr.*; |
| 672 | | } |
| 673 | | |
| 674 | 611 | /// Creates a new empty `Atom` and returns its `Atom.Index` |
| 675 | | fn createAtom(wasm: *Wasm) !Atom.Index { |
| 612 | pub fn createAtom(wasm: *Wasm, sym_index: u32) !Atom.Index { |
| 676 | 613 | const gpa = wasm.base.comp.gpa; |
| 677 | 614 | const index: Atom.Index = @intCast(wasm.managed_atoms.items.len); |
| 678 | 615 | const atom = try wasm.managed_atoms.addOne(gpa); |
| 679 | 616 | atom.* = Atom.empty; |
| 680 | | atom.sym_index = try wasm.allocateSymbol(); |
| 681 | | try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = atom.sym_index }, index); |
| 617 | atom.sym_index = sym_index; |
| 618 | try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = sym_index }, index); |
| 682 | 619 | |
| 683 | 620 | return index; |
| 684 | 621 | } |
| ... | ... | @@ -1386,40 +1323,12 @@ pub fn deinit(wasm: *Wasm) void { |
| 1386 | 1323 | archive.deinit(gpa); |
| 1387 | 1324 | } |
| 1388 | 1325 | |
| 1389 | | // For decls and anon decls we free the memory of its atoms. |
| 1390 | | // The memory of atoms parsed from object files is managed by |
| 1391 | | // the object file itself, and therefore we can skip those. |
| 1392 | | { |
| 1393 | | var it = wasm.decls.valueIterator(); |
| 1394 | | while (it.next()) |atom_index_ptr| { |
| 1395 | | const atom = wasm.getAtomPtr(atom_index_ptr.*); |
| 1396 | | for (atom.locals.items) |local_index| { |
| 1397 | | const local_atom = wasm.getAtomPtr(local_index); |
| 1398 | | local_atom.deinit(gpa); |
| 1399 | | } |
| 1400 | | atom.deinit(gpa); |
| 1401 | | } |
| 1402 | | } |
| 1403 | | { |
| 1404 | | for (wasm.anon_decls.values()) |atom_index| { |
| 1405 | | const atom = wasm.getAtomPtr(atom_index); |
| 1406 | | for (atom.locals.items) |local_index| { |
| 1407 | | const local_atom = wasm.getAtomPtr(local_index); |
| 1408 | | local_atom.deinit(gpa); |
| 1409 | | } |
| 1410 | | atom.deinit(gpa); |
| 1411 | | } |
| 1412 | | } |
| 1413 | 1326 | for (wasm.synthetic_functions.items) |atom_index| { |
| 1414 | 1327 | const atom = wasm.getAtomPtr(atom_index); |
| 1415 | 1328 | atom.deinit(gpa); |
| 1416 | 1329 | } |
| 1417 | 1330 | |
| 1418 | | wasm.decls.deinit(gpa); |
| 1419 | | wasm.anon_decls.deinit(gpa); |
| 1420 | | wasm.atom_types.deinit(gpa); |
| 1421 | | wasm.symbols.deinit(gpa); |
| 1422 | | wasm.symbols_free_list.deinit(gpa); |
| 1331 | wasm.synthetic_symbols.deinit(gpa); |
| 1423 | 1332 | wasm.globals.deinit(gpa); |
| 1424 | 1333 | wasm.resolved_symbols.deinit(gpa); |
| 1425 | 1334 | wasm.undefs.deinit(gpa); |
| ... | ... | @@ -1446,32 +1355,6 @@ pub fn deinit(wasm: *Wasm) void { |
| 1446 | 1355 | |
| 1447 | 1356 | wasm.string_table.deinit(gpa); |
| 1448 | 1357 | wasm.synthetic_functions.deinit(gpa); |
| 1449 | | |
| 1450 | | if (wasm.dwarf) |*dwarf| { |
| 1451 | | dwarf.deinit(); |
| 1452 | | } |
| 1453 | | } |
| 1454 | | |
| 1455 | | /// Allocates a new symbol and returns its index. |
| 1456 | | /// Will re-use slots when a symbol was freed at an earlier stage. |
| 1457 | | pub fn allocateSymbol(wasm: *Wasm) !u32 { |
| 1458 | | const gpa = wasm.base.comp.gpa; |
| 1459 | | |
| 1460 | | try wasm.symbols.ensureUnusedCapacity(gpa, 1); |
| 1461 | | const symbol: Symbol = .{ |
| 1462 | | .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls |
| 1463 | | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 1464 | | .tag = .undefined, // will be set after updateDecl |
| 1465 | | .index = std.math.maxInt(u32), // will be set during atom parsing |
| 1466 | | .virtual_address = std.math.maxInt(u32), // will be set during atom allocation |
| 1467 | | }; |
| 1468 | | if (wasm.symbols_free_list.popOrNull()) |index| { |
| 1469 | | wasm.symbols.items[index] = symbol; |
| 1470 | | return index; |
| 1471 | | } |
| 1472 | | const index = @as(u32, @intCast(wasm.symbols.items.len)); |
| 1473 | | wasm.symbols.appendAssumeCapacity(symbol); |
| 1474 | | return index; |
| 1475 | 1358 | } |
| 1476 | 1359 | |
| 1477 | 1360 | pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| ... | ... | @@ -1546,84 +1429,12 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) ! |
| 1546 | 1429 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1547 | 1430 | } |
| 1548 | 1431 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index); |
| 1549 | | |
| 1550 | | const tracy = trace(@src()); |
| 1551 | | defer tracy.end(); |
| 1552 | | |
| 1553 | | const decl = mod.declPtr(decl_index); |
| 1554 | | if (decl.val.getFunction(mod)) |_| { |
| 1555 | | return; |
| 1556 | | } else if (decl.val.getExternFunc(mod)) |_| { |
| 1557 | | return; |
| 1558 | | } |
| 1559 | | |
| 1560 | | const gpa = wasm.base.comp.gpa; |
| 1561 | | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1562 | | const atom = wasm.getAtomPtr(atom_index); |
| 1563 | | atom.clear(); |
| 1564 | | |
| 1565 | | if (decl.isExtern(mod)) { |
| 1566 | | const variable = decl.getOwnedVariable(mod).?; |
| 1567 | | const name = mod.intern_pool.stringToSlice(decl.name); |
| 1568 | | const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); |
| 1569 | | return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null); |
| 1570 | | } |
| 1571 | | const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; |
| 1572 | | |
| 1573 | | var code_writer = std.ArrayList(u8).init(gpa); |
| 1574 | | defer code_writer.deinit(); |
| 1575 | | |
| 1576 | | const res = try codegen.generateSymbol( |
| 1577 | | &wasm.base, |
| 1578 | | decl.srcLoc(mod), |
| 1579 | | .{ .ty = decl.ty, .val = val }, |
| 1580 | | &code_writer, |
| 1581 | | .none, |
| 1582 | | .{ .parent_atom_index = atom.sym_index }, |
| 1583 | | ); |
| 1584 | | |
| 1585 | | const code = switch (res) { |
| 1586 | | .ok => code_writer.items, |
| 1587 | | .fail => |em| { |
| 1588 | | decl.analysis = .codegen_failure; |
| 1589 | | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1590 | | return; |
| 1591 | | }, |
| 1592 | | }; |
| 1593 | | |
| 1594 | | return wasm.finishUpdateDecl(decl_index, code, .data); |
| 1595 | 1432 | } |
| 1596 | 1433 | |
| 1597 | 1434 | pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !void { |
| 1598 | 1435 | if (wasm.llvm_object) |_| return; |
| 1599 | | if (wasm.dwarf) |*dw| { |
| 1600 | | const tracy = trace(@src()); |
| 1601 | | defer tracy.end(); |
| 1602 | | |
| 1603 | | const decl = mod.declPtr(decl_index); |
| 1604 | | const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); |
| 1605 | | |
| 1606 | | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); |
| 1607 | | try dw.updateDeclLineNumber(mod, decl_index); |
| 1608 | | } |
| 1609 | | } |
| 1610 | | |
| 1611 | | fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void { |
| 1612 | | const gpa = wasm.base.comp.gpa; |
| 1613 | | const mod = wasm.base.comp.module.?; |
| 1614 | | const decl = mod.declPtr(decl_index); |
| 1615 | | const atom_index = wasm.decls.get(decl_index).?; |
| 1616 | | const atom = wasm.getAtomPtr(atom_index); |
| 1617 | | const symbol = &wasm.symbols.items[atom.sym_index]; |
| 1618 | | const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); |
| 1619 | | symbol.name = try wasm.string_table.put(gpa, full_name); |
| 1620 | | symbol.tag = symbol_tag; |
| 1621 | | try atom.code.appendSlice(gpa, code); |
| 1622 | | try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); |
| 1623 | | |
| 1624 | | atom.size = @intCast(code.len); |
| 1625 | | if (code.len == 0) return; |
| 1626 | | atom.alignment = decl.getAlignment(mod); |
| 1436 | _ = mod; |
| 1437 | _ = decl_index; |
| 1627 | 1438 | } |
| 1628 | 1439 | |
| 1629 | 1440 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| ... | ... | @@ -1673,82 +1484,9 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1673 | 1484 | /// Returns the symbol index of the local |
| 1674 | 1485 | /// The given `decl` is the parent decl whom owns the constant. |
| 1675 | 1486 | pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { |
| 1676 | | const gpa = wasm.base.comp.gpa; |
| 1677 | | const mod = wasm.base.comp.module.?; |
| 1678 | | assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions |
| 1679 | | const decl = mod.declPtr(decl_index); |
| 1680 | | |
| 1681 | | const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1682 | | const parent_atom = wasm.getAtom(parent_atom_index); |
| 1683 | | const local_index = parent_atom.locals.items.len; |
| 1684 | | const fqn = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); |
| 1685 | | const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{ |
| 1686 | | fqn, local_index, |
| 1687 | | }); |
| 1688 | | defer gpa.free(name); |
| 1689 | | |
| 1690 | | switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) { |
| 1691 | | .ok => |atom_index| { |
| 1692 | | try wasm.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); |
| 1693 | | return wasm.getAtom(atom_index).getSymbolIndex().?; |
| 1694 | | }, |
| 1695 | | .fail => |em| { |
| 1696 | | decl.analysis = .codegen_failure; |
| 1697 | | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1698 | | return error.CodegenFail; |
| 1699 | | }, |
| 1700 | | } |
| 1701 | | } |
| 1702 | | |
| 1703 | | const LowerConstResult = union(enum) { |
| 1704 | | ok: Atom.Index, |
| 1705 | | fail: *Module.ErrorMsg, |
| 1706 | | }; |
| 1707 | | |
| 1708 | | fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { |
| 1709 | | const gpa = wasm.base.comp.gpa; |
| 1710 | | const mod = wasm.base.comp.module.?; |
| 1711 | | |
| 1712 | | // Create and initialize a new local symbol and atom |
| 1713 | | const atom_index = try wasm.createAtom(); |
| 1714 | | var value_bytes = std.ArrayList(u8).init(gpa); |
| 1715 | | defer value_bytes.deinit(); |
| 1716 | | |
| 1717 | | const code = code: { |
| 1718 | | const atom = wasm.getAtomPtr(atom_index); |
| 1719 | | atom.alignment = tv.ty.abiAlignment(mod); |
| 1720 | | wasm.symbols.items[atom.sym_index] = .{ |
| 1721 | | .name = try wasm.string_table.put(gpa, name), |
| 1722 | | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 1723 | | .tag = .data, |
| 1724 | | .index = undefined, |
| 1725 | | .virtual_address = undefined, |
| 1726 | | }; |
| 1727 | | try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {}); |
| 1728 | | |
| 1729 | | const result = try codegen.generateSymbol( |
| 1730 | | &wasm.base, |
| 1731 | | src_loc, |
| 1732 | | tv, |
| 1733 | | &value_bytes, |
| 1734 | | .none, |
| 1735 | | .{ |
| 1736 | | .parent_atom_index = atom.sym_index, |
| 1737 | | .addend = null, |
| 1738 | | }, |
| 1739 | | ); |
| 1740 | | break :code switch (result) { |
| 1741 | | .ok => value_bytes.items, |
| 1742 | | .fail => |em| { |
| 1743 | | return .{ .fail = em }; |
| 1744 | | }, |
| 1745 | | }; |
| 1746 | | }; |
| 1747 | | |
| 1748 | | const atom = wasm.getAtomPtr(atom_index); |
| 1749 | | atom.size = @intCast(code.len); |
| 1750 | | try atom.code.appendSlice(gpa, code); |
| 1751 | | return .{ .ok = atom_index }; |
| 1487 | _ = wasm; |
| 1488 | _ = tv; |
| 1489 | _ = decl_index; |
| 1752 | 1490 | } |
| 1753 | 1491 | |
| 1754 | 1492 | /// Returns the symbol index from a symbol of which its flag is set global, |
| ... | ... | @@ -1757,34 +1495,8 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src |
| 1757 | 1495 | /// and then returns the index to it. |
| 1758 | 1496 | pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 { |
| 1759 | 1497 | _ = lib_name; |
| 1760 | | const gpa = wasm.base.comp.gpa; |
| 1761 | | const name_index = try wasm.string_table.put(gpa, name); |
| 1762 | | const gop = try wasm.globals.getOrPut(gpa, name_index); |
| 1763 | | if (gop.found_existing) { |
| 1764 | | return gop.value_ptr.*.index; |
| 1765 | | } |
| 1766 | | |
| 1767 | | var symbol: Symbol = .{ |
| 1768 | | .name = name_index, |
| 1769 | | .flags = 0, |
| 1770 | | .index = undefined, // index to type will be set after merging function symbols |
| 1771 | | .tag = .function, |
| 1772 | | .virtual_address = undefined, |
| 1773 | | }; |
| 1774 | | symbol.setGlobal(true); |
| 1775 | | symbol.setUndefined(true); |
| 1776 | | |
| 1777 | | const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: { |
| 1778 | | const index: u32 = @intCast(wasm.symbols.items.len); |
| 1779 | | try wasm.symbols.ensureUnusedCapacity(gpa, 1); |
| 1780 | | wasm.symbols.items.len += 1; |
| 1781 | | break :blk index; |
| 1782 | | }; |
| 1783 | | wasm.symbols.items[sym_index] = symbol; |
| 1784 | | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 1785 | | try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {}); |
| 1786 | | try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*); |
| 1787 | | return sym_index; |
| 1498 | _ = name; |
| 1499 | _ = wasm; |
| 1788 | 1500 | } |
| 1789 | 1501 | |
| 1790 | 1502 | /// For a given decl, find the given symbol index's atom, and create a relocation for the type. |
| ... | ... | @@ -1794,42 +1506,9 @@ pub fn getDeclVAddr( |
| 1794 | 1506 | decl_index: InternPool.DeclIndex, |
| 1795 | 1507 | reloc_info: link.File.RelocInfo, |
| 1796 | 1508 | ) !u64 { |
| 1797 | | const target = wasm.base.comp.root_mod.resolved_target.result; |
| 1798 | | const gpa = wasm.base.comp.gpa; |
| 1799 | | const mod = wasm.base.comp.module.?; |
| 1800 | | const decl = mod.declPtr(decl_index); |
| 1801 | | |
| 1802 | | const target_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1803 | | const target_symbol_index = wasm.getAtom(target_atom_index).sym_index; |
| 1804 | | |
| 1805 | | assert(reloc_info.parent_atom_index != 0); |
| 1806 | | const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 1807 | | const atom = wasm.getAtomPtr(atom_index); |
| 1808 | | const is_wasm32 = target.cpu.arch == .wasm32; |
| 1809 | | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 1810 | | assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 1811 | | // We found a function pointer, so add it to our table, |
| 1812 | | // as function pointers are not allowed to be stored inside the data section. |
| 1813 | | // They are instead stored in a function table which are called by index. |
| 1814 | | try wasm.addTableFunction(target_symbol_index); |
| 1815 | | try atom.relocs.append(gpa, .{ |
| 1816 | | .index = target_symbol_index, |
| 1817 | | .offset = @intCast(reloc_info.offset), |
| 1818 | | .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, |
| 1819 | | }); |
| 1820 | | } else { |
| 1821 | | try atom.relocs.append(gpa, .{ |
| 1822 | | .index = target_symbol_index, |
| 1823 | | .offset = @intCast(reloc_info.offset), |
| 1824 | | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, |
| 1825 | | .addend = @intCast(reloc_info.addend), |
| 1826 | | }); |
| 1827 | | } |
| 1828 | | // we do not know the final address at this point, |
| 1829 | | // as atom allocation will determine the address and relocations |
| 1830 | | // will calculate and rewrite this. Therefore, we simply return the symbol index |
| 1831 | | // that was targeted. |
| 1832 | | return target_symbol_index; |
| 1509 | _ = wasm; |
| 1510 | _ = decl_index; |
| 1511 | _ = reloc_info; |
| 1833 | 1512 | } |
| 1834 | 1513 | |
| 1835 | 1514 | pub fn lowerAnonDecl( |
| ... | ... | @@ -1838,70 +1517,16 @@ pub fn lowerAnonDecl( |
| 1838 | 1517 | explicit_alignment: Alignment, |
| 1839 | 1518 | src_loc: Module.SrcLoc, |
| 1840 | 1519 | ) !codegen.Result { |
| 1841 | | const gpa = wasm.base.comp.gpa; |
| 1842 | | const gop = try wasm.anon_decls.getOrPut(gpa, decl_val); |
| 1843 | | if (!gop.found_existing) { |
| 1844 | | const mod = wasm.base.comp.module.?; |
| 1845 | | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 1846 | | const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) }; |
| 1847 | | var name_buf: [32]u8 = undefined; |
| 1848 | | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 1849 | | @intFromEnum(decl_val), |
| 1850 | | }) catch unreachable; |
| 1851 | | |
| 1852 | | switch (try wasm.lowerConst(name, tv, src_loc)) { |
| 1853 | | .ok => |atom_index| wasm.anon_decls.values()[gop.index] = atom_index, |
| 1854 | | .fail => |em| return .{ .fail = em }, |
| 1855 | | } |
| 1856 | | } |
| 1857 | | |
| 1858 | | const atom = wasm.getAtomPtr(wasm.anon_decls.values()[gop.index]); |
| 1859 | | atom.alignment = switch (atom.alignment) { |
| 1860 | | .none => explicit_alignment, |
| 1861 | | else => switch (explicit_alignment) { |
| 1862 | | .none => atom.alignment, |
| 1863 | | else => atom.alignment.maxStrict(explicit_alignment), |
| 1864 | | }, |
| 1865 | | }; |
| 1866 | | return .ok; |
| 1520 | _ = wasm; |
| 1521 | _ = decl_val; |
| 1522 | _ = explicit_alignment; |
| 1523 | _ = src_loc; |
| 1867 | 1524 | } |
| 1868 | 1525 | |
| 1869 | 1526 | pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 1870 | | const gpa = wasm.base.comp.gpa; |
| 1871 | | const target = wasm.base.comp.root_mod.resolved_target.result; |
| 1872 | | const atom_index = wasm.anon_decls.get(decl_val).?; |
| 1873 | | const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?; |
| 1874 | | |
| 1875 | | const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 1876 | | const parent_atom = wasm.getAtomPtr(parent_atom_index); |
| 1877 | | const is_wasm32 = target.cpu.arch == .wasm32; |
| 1878 | | const mod = wasm.base.comp.module.?; |
| 1879 | | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 1880 | | if (ty.zigTypeTag(mod) == .Fn) { |
| 1881 | | assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 1882 | | // We found a function pointer, so add it to our table, |
| 1883 | | // as function pointers are not allowed to be stored inside the data section. |
| 1884 | | // They are instead stored in a function table which are called by index. |
| 1885 | | try wasm.addTableFunction(target_symbol_index); |
| 1886 | | try parent_atom.relocs.append(gpa, .{ |
| 1887 | | .index = target_symbol_index, |
| 1888 | | .offset = @intCast(reloc_info.offset), |
| 1889 | | .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, |
| 1890 | | }); |
| 1891 | | } else { |
| 1892 | | try parent_atom.relocs.append(gpa, .{ |
| 1893 | | .index = target_symbol_index, |
| 1894 | | .offset = @intCast(reloc_info.offset), |
| 1895 | | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, |
| 1896 | | .addend = @intCast(reloc_info.addend), |
| 1897 | | }); |
| 1898 | | } |
| 1899 | | |
| 1900 | | // we do not know the final address at this point, |
| 1901 | | // as atom allocation will determine the address and relocations |
| 1902 | | // will calculate and rewrite this. Therefore, we simply return the symbol index |
| 1903 | | // that was targeted. |
| 1904 | | return target_symbol_index; |
| 1527 | _ = wasm; |
| 1528 | _ = decl_val; |
| 1529 | _ = reloc_info; |
| 1905 | 1530 | } |
| 1906 | 1531 | |
| 1907 | 1532 | pub fn deleteDeclExport( |
| ... | ... | @@ -1909,19 +1534,9 @@ pub fn deleteDeclExport( |
| 1909 | 1534 | decl_index: InternPool.DeclIndex, |
| 1910 | 1535 | name: InternPool.NullTerminatedString, |
| 1911 | 1536 | ) void { |
| 1912 | | _ = name; |
| 1913 | 1537 | if (wasm.llvm_object) |_| return; |
| 1914 | | const atom_index = wasm.decls.get(decl_index) orelse return; |
| 1915 | | const sym_index = wasm.getAtom(atom_index).sym_index; |
| 1916 | | const loc: SymbolLoc = .{ .file = null, .index = sym_index }; |
| 1917 | | const symbol = loc.getSymbol(wasm); |
| 1918 | | const symbol_name = wasm.string_table.get(symbol.name); |
| 1919 | | log.debug("Deleting export for decl '{s}'", .{symbol_name}); |
| 1920 | | if (wasm.export_names.fetchRemove(loc)) |kv| { |
| 1921 | | assert(wasm.globals.remove(kv.value)); |
| 1922 | | } else { |
| 1923 | | assert(wasm.globals.remove(symbol.name)); |
| 1924 | | } |
| 1538 | _ = name; |
| 1539 | _ = decl_index; |
| 1925 | 1540 | } |
| 1926 | 1541 | |
| 1927 | 1542 | pub fn updateExports( |
| ... | ... | @@ -1934,159 +1549,10 @@ pub fn updateExports( |
| 1934 | 1549 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1935 | 1550 | } |
| 1936 | 1551 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); |
| 1937 | | |
| 1938 | | const decl_index = switch (exported) { |
| 1939 | | .decl_index => |i| i, |
| 1940 | | .value => |val| { |
| 1941 | | _ = val; |
| 1942 | | @panic("TODO: implement Wasm linker code for exporting a constant value"); |
| 1943 | | }, |
| 1944 | | }; |
| 1945 | | const decl = mod.declPtr(decl_index); |
| 1946 | | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1947 | | const atom = wasm.getAtom(atom_index); |
| 1948 | | const atom_sym = atom.symbolLoc().getSymbol(wasm).*; |
| 1949 | | const gpa = mod.gpa; |
| 1950 | | |
| 1951 | | for (exports) |exp| { |
| 1952 | | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| { |
| 1953 | | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 1954 | | gpa, |
| 1955 | | decl.srcLoc(mod), |
| 1956 | | "Unimplemented: ExportOptions.section '{s}'", |
| 1957 | | .{section}, |
| 1958 | | )); |
| 1959 | | continue; |
| 1960 | | } |
| 1961 | | |
| 1962 | | const exported_decl_index = switch (exp.exported) { |
| 1963 | | .value => { |
| 1964 | | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 1965 | | gpa, |
| 1966 | | decl.srcLoc(mod), |
| 1967 | | "Unimplemented: exporting a named constant value", |
| 1968 | | .{}, |
| 1969 | | )); |
| 1970 | | continue; |
| 1971 | | }, |
| 1972 | | .decl_index => |i| i, |
| 1973 | | }; |
| 1974 | | const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index); |
| 1975 | | const exported_atom = wasm.getAtom(exported_atom_index); |
| 1976 | | const export_name = try wasm.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 1977 | | const sym_loc = exported_atom.symbolLoc(); |
| 1978 | | const symbol = sym_loc.getSymbol(wasm); |
| 1979 | | symbol.setGlobal(true); |
| 1980 | | symbol.setUndefined(false); |
| 1981 | | symbol.index = atom_sym.index; |
| 1982 | | symbol.tag = atom_sym.tag; |
| 1983 | | symbol.name = atom_sym.name; |
| 1984 | | |
| 1985 | | switch (exp.opts.linkage) { |
| 1986 | | .Internal => { |
| 1987 | | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 1988 | | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 1989 | | }, |
| 1990 | | .Weak => { |
| 1991 | | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 1992 | | }, |
| 1993 | | .Strong => {}, // symbols are strong by default |
| 1994 | | .LinkOnce => { |
| 1995 | | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 1996 | | gpa, |
| 1997 | | decl.srcLoc(mod), |
| 1998 | | "Unimplemented: LinkOnce", |
| 1999 | | .{}, |
| 2000 | | )); |
| 2001 | | continue; |
| 2002 | | }, |
| 2003 | | } |
| 2004 | | |
| 2005 | | if (wasm.globals.get(export_name)) |existing_loc| { |
| 2006 | | if (existing_loc.index == atom.sym_index) continue; |
| 2007 | | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; |
| 2008 | | |
| 2009 | | if (!existing_sym.isUndefined()) blk: { |
| 2010 | | if (symbol.isWeak()) { |
| 2011 | | try wasm.discarded.put(gpa, existing_loc, sym_loc); |
| 2012 | | continue; // to-be-exported symbol is weak, so we keep the existing symbol |
| 2013 | | } |
| 2014 | | |
| 2015 | | // new symbol is not weak while existing is, replace existing symbol |
| 2016 | | if (existing_sym.isWeak()) { |
| 2017 | | break :blk; |
| 2018 | | } |
| 2019 | | // When both the to-be-exported symbol and the already existing symbol |
| 2020 | | // are strong symbols, we have a linker error. |
| 2021 | | // In the other case we replace one with the other. |
| 2022 | | try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( |
| 2023 | | gpa, |
| 2024 | | decl.srcLoc(mod), |
| 2025 | | \\LinkError: symbol '{}' defined multiple times |
| 2026 | | \\ first definition in '{s}' |
| 2027 | | \\ next definition in '{s}' |
| 2028 | | , |
| 2029 | | .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, |
| 2030 | | )); |
| 2031 | | continue; |
| 2032 | | } |
| 2033 | | |
| 2034 | | // in this case the existing symbol must be replaced either because it's weak or undefined. |
| 2035 | | try wasm.discarded.put(gpa, existing_loc, sym_loc); |
| 2036 | | _ = wasm.imports.remove(existing_loc); |
| 2037 | | _ = wasm.undefs.swapRemove(existing_sym.name); |
| 2038 | | } |
| 2039 | | |
| 2040 | | // Ensure the symbol will be exported using the given name |
| 2041 | | if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 2042 | | try wasm.export_names.put(gpa, sym_loc, export_name); |
| 2043 | | } |
| 2044 | | |
| 2045 | | try wasm.globals.put( |
| 2046 | | gpa, |
| 2047 | | export_name, |
| 2048 | | sym_loc, |
| 2049 | | ); |
| 2050 | | } |
| 2051 | 1552 | } |
| 2052 | 1553 | |
| 2053 | 1554 | pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { |
| 2054 | 1555 | if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); |
| 2055 | | const gpa = wasm.base.comp.gpa; |
| 2056 | | const mod = wasm.base.comp.module.?; |
| 2057 | | const decl = mod.declPtr(decl_index); |
| 2058 | | const atom_index = wasm.decls.get(decl_index).?; |
| 2059 | | const atom = wasm.getAtomPtr(atom_index); |
| 2060 | | atom.prev = null; |
| 2061 | | wasm.symbols_free_list.append(gpa, atom.sym_index) catch {}; |
| 2062 | | _ = wasm.decls.remove(decl_index); |
| 2063 | | wasm.symbols.items[atom.sym_index].tag = .dead; |
| 2064 | | for (atom.locals.items) |local_atom_index| { |
| 2065 | | const local_atom = wasm.getAtom(local_atom_index); |
| 2066 | | const local_symbol = &wasm.symbols.items[local_atom.sym_index]; |
| 2067 | | local_symbol.tag = .dead; // also for any local symbol |
| 2068 | | wasm.symbols_free_list.append(gpa, local_atom.sym_index) catch {}; |
| 2069 | | assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc())); |
| 2070 | | assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); |
| 2071 | | } |
| 2072 | | |
| 2073 | | if (decl.isExtern(mod)) { |
| 2074 | | _ = wasm.imports.remove(atom.symbolLoc()); |
| 2075 | | } |
| 2076 | | _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); |
| 2077 | | _ = wasm.symbol_atom.remove(atom.symbolLoc()); |
| 2078 | | |
| 2079 | | // if (wasm.dwarf) |*dwarf| { |
| 2080 | | // dwarf.freeDecl(decl_index); |
| 2081 | | // } |
| 2082 | | |
| 2083 | | } |
| 2084 | | |
| 2085 | | /// Appends a new entry to the indirect function table |
| 2086 | | pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void { |
| 2087 | | const gpa = wasm.base.comp.gpa; |
| 2088 | | const index: u32 = @intCast(wasm.function_table.count()); |
| 2089 | | try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index); |
| 2090 | 1556 | } |
| 2091 | 1557 | |
| 2092 | 1558 | /// Assigns indexes to all indirect functions. |
| ... | ... | @@ -2118,203 +1584,6 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 2118 | 1584 | } |
| 2119 | 1585 | } |
| 2120 | 1586 | |
| 2121 | | /// Either creates a new import, or updates one if existing. |
| 2122 | | /// When `type_index` is non-null, we assume an external function. |
| 2123 | | /// In all other cases, a data-symbol will be created instead. |
| 2124 | | pub fn addOrUpdateImport( |
| 2125 | | wasm: *Wasm, |
| 2126 | | /// Name of the import |
| 2127 | | name: []const u8, |
| 2128 | | /// Symbol index that is external |
| 2129 | | symbol_index: u32, |
| 2130 | | /// Optional library name (i.e. `extern "c" fn foo() void` |
| 2131 | | lib_name: ?[:0]const u8, |
| 2132 | | /// The index of the type that represents the function signature |
| 2133 | | /// when the extern is a function. When this is null, a data-symbol |
| 2134 | | /// is asserted instead. |
| 2135 | | type_index: ?u32, |
| 2136 | | ) !void { |
| 2137 | | const gpa = wasm.base.comp.gpa; |
| 2138 | | assert(symbol_index != 0); |
| 2139 | | // For the import name, we use the decl's name, rather than the fully qualified name |
| 2140 | | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| 2141 | | // name but different module can be resolved correctly. |
| 2142 | | const mangle_name = lib_name != null and |
| 2143 | | !std.mem.eql(u8, lib_name.?, "c"); |
| 2144 | | const full_name = if (mangle_name) full_name: { |
| 2145 | | break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? }); |
| 2146 | | } else name; |
| 2147 | | defer if (mangle_name) gpa.free(full_name); |
| 2148 | | |
| 2149 | | const decl_name_index = try wasm.string_table.put(gpa, full_name); |
| 2150 | | const symbol: *Symbol = &wasm.symbols.items[symbol_index]; |
| 2151 | | symbol.setUndefined(true); |
| 2152 | | symbol.setGlobal(true); |
| 2153 | | symbol.name = decl_name_index; |
| 2154 | | if (mangle_name) { |
| 2155 | | // we specified a specific name for the symbol that does not match the import name |
| 2156 | | symbol.setFlag(.WASM_SYM_EXPLICIT_NAME); |
| 2157 | | } |
| 2158 | | const global_gop = try wasm.globals.getOrPut(gpa, decl_name_index); |
| 2159 | | if (!global_gop.found_existing) { |
| 2160 | | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; |
| 2161 | | global_gop.value_ptr.* = loc; |
| 2162 | | try wasm.resolved_symbols.put(gpa, loc, {}); |
| 2163 | | try wasm.undefs.putNoClobber(gpa, decl_name_index, loc); |
| 2164 | | } else if (global_gop.value_ptr.*.index != symbol_index) { |
| 2165 | | // We are not updating a symbol, but found an existing global |
| 2166 | | // symbol with the same name. This means we always favor the |
| 2167 | | // existing symbol, regardless whether it's defined or not. |
| 2168 | | // We can also skip storing the import as we will not output |
| 2169 | | // this symbol. |
| 2170 | | return wasm.discarded.put( |
| 2171 | | gpa, |
| 2172 | | .{ .file = null, .index = symbol_index }, |
| 2173 | | global_gop.value_ptr.*, |
| 2174 | | ); |
| 2175 | | } |
| 2176 | | |
| 2177 | | if (type_index) |ty_index| { |
| 2178 | | const gop = try wasm.imports.getOrPut(gpa, .{ .index = symbol_index, .file = null }); |
| 2179 | | const module_name = if (lib_name) |l_name| blk: { |
| 2180 | | break :blk l_name; |
| 2181 | | } else wasm.host_name; |
| 2182 | | if (!gop.found_existing) { |
| 2183 | | gop.value_ptr.* = .{ |
| 2184 | | .module_name = try wasm.string_table.put(gpa, module_name), |
| 2185 | | .name = try wasm.string_table.put(gpa, name), |
| 2186 | | .kind = .{ .function = ty_index }, |
| 2187 | | }; |
| 2188 | | } |
| 2189 | | } else { |
| 2190 | | // non-functions will not be imported from the runtime, but only resolved during link-time |
| 2191 | | symbol.tag = .data; |
| 2192 | | } |
| 2193 | | } |
| 2194 | | |
| 2195 | | /// Kind represents the type of an Atom, which is only |
| 2196 | | /// used to parse a decl into an Atom to define in which section |
| 2197 | | /// or segment it should be placed. |
| 2198 | | const Kind = union(enum) { |
| 2199 | | /// Represents the segment the data symbol should |
| 2200 | | /// be inserted into. |
| 2201 | | /// TODO: Add TLS segments |
| 2202 | | data: enum { |
| 2203 | | read_only, |
| 2204 | | uninitialized, |
| 2205 | | initialized, |
| 2206 | | }, |
| 2207 | | function: void, |
| 2208 | | |
| 2209 | | /// Returns the segment name the data kind represents. |
| 2210 | | /// Asserts `kind` has its active tag set to `data`. |
| 2211 | | fn segmentName(kind: Kind) []const u8 { |
| 2212 | | switch (kind.data) { |
| 2213 | | .read_only => return ".rodata.", |
| 2214 | | .uninitialized => return ".bss.", |
| 2215 | | .initialized => return ".data.", |
| 2216 | | } |
| 2217 | | } |
| 2218 | | }; |
| 2219 | | |
| 2220 | | /// Parses an Atom and inserts its metadata into the corresponding sections. |
| 2221 | | fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2222 | | const comp = wasm.base.comp; |
| 2223 | | const gpa = comp.gpa; |
| 2224 | | const shared_memory = comp.config.shared_memory; |
| 2225 | | const import_memory = comp.config.import_memory; |
| 2226 | | const atom = wasm.getAtomPtr(atom_index); |
| 2227 | | const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); |
| 2228 | | const do_garbage_collect = wasm.base.gc_sections; |
| 2229 | | |
| 2230 | | if (symbol.isDead() and do_garbage_collect) { |
| 2231 | | // Prevent unreferenced symbols from being parsed. |
| 2232 | | return; |
| 2233 | | } |
| 2234 | | |
| 2235 | | const final_index: u32 = switch (kind) { |
| 2236 | | .function => result: { |
| 2237 | | const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); |
| 2238 | | const type_index = wasm.atom_types.get(atom_index).?; |
| 2239 | | try wasm.functions.putNoClobber( |
| 2240 | | gpa, |
| 2241 | | .{ .file = null, .index = index }, |
| 2242 | | .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 2243 | | ); |
| 2244 | | symbol.tag = .function; |
| 2245 | | symbol.index = index; |
| 2246 | | |
| 2247 | | if (wasm.code_section_index == null) { |
| 2248 | | wasm.code_section_index = @intCast(wasm.segments.items.len); |
| 2249 | | try wasm.segments.append(gpa, .{ |
| 2250 | | .alignment = atom.alignment, |
| 2251 | | .size = atom.size, |
| 2252 | | .offset = 0, |
| 2253 | | .flags = 0, |
| 2254 | | }); |
| 2255 | | } |
| 2256 | | |
| 2257 | | break :result wasm.code_section_index.?; |
| 2258 | | }, |
| 2259 | | .data => result: { |
| 2260 | | const segment_name = try std.mem.concat(gpa, u8, &.{ |
| 2261 | | kind.segmentName(), |
| 2262 | | wasm.string_table.get(symbol.name), |
| 2263 | | }); |
| 2264 | | errdefer gpa.free(segment_name); |
| 2265 | | const segment_info: types.Segment = .{ |
| 2266 | | .name = segment_name, |
| 2267 | | .alignment = atom.alignment, |
| 2268 | | .flags = 0, |
| 2269 | | }; |
| 2270 | | symbol.tag = .data; |
| 2271 | | |
| 2272 | | // when creating an object file, or importing memory and the data belongs in the .bss segment |
| 2273 | | // we set the entire region of it to zeroes. |
| 2274 | | // We do not have to do this when exporting the memory (the default) because the runtime |
| 2275 | | // will do it for us, and we do not emit the bss segment at all. |
| 2276 | | if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { |
| 2277 | | @memset(atom.code.items, 0); |
| 2278 | | } |
| 2279 | | |
| 2280 | | const should_merge = wasm.base.comp.config.output_mode != .Obj; |
| 2281 | | const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge)); |
| 2282 | | if (gop.found_existing) { |
| 2283 | | const index = gop.value_ptr.*; |
| 2284 | | wasm.segments.items[index].size += atom.size; |
| 2285 | | |
| 2286 | | symbol.index = @intCast(wasm.segment_info.getIndex(index).?); |
| 2287 | | // segment info already exists, so free its memory |
| 2288 | | gpa.free(segment_name); |
| 2289 | | break :result index; |
| 2290 | | } else { |
| 2291 | | const index: u32 = @intCast(wasm.segments.items.len); |
| 2292 | | var flags: u32 = 0; |
| 2293 | | if (shared_memory) { |
| 2294 | | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 2295 | | } |
| 2296 | | try wasm.segments.append(gpa, .{ |
| 2297 | | .alignment = atom.alignment, |
| 2298 | | .size = 0, |
| 2299 | | .offset = 0, |
| 2300 | | .flags = flags, |
| 2301 | | }); |
| 2302 | | gop.value_ptr.* = index; |
| 2303 | | |
| 2304 | | const info_index: u32 = @intCast(wasm.segment_info.count()); |
| 2305 | | try wasm.segment_info.put(gpa, index, segment_info); |
| 2306 | | symbol.index = info_index; |
| 2307 | | break :result index; |
| 2308 | | } |
| 2309 | | }, |
| 2310 | | }; |
| 2311 | | |
| 2312 | | const segment: *Segment = &wasm.segments.items[final_index]; |
| 2313 | | segment.alignment = segment.alignment.max(atom.alignment); |
| 2314 | | |
| 2315 | | try wasm.appendAtomAtIndex(final_index, atom_index); |
| 2316 | | } |
| 2317 | | |
| 2318 | 1587 | /// From a given index, append the given `Atom` at the back of the linked list. |
| 2319 | 1588 | /// Simply inserts it into the map of atoms when it doesn't exist yet. |
| 2320 | 1589 | pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void { |
| ... | ... | @@ -2328,40 +1597,9 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void |
| 2328 | 1597 | } |
| 2329 | 1598 | } |
| 2330 | 1599 | |
| 2331 | | /// Allocates debug atoms into their respective debug sections |
| 2332 | | /// to merge them with maybe-existing debug atoms from object files. |
| 2333 | | fn allocateDebugAtoms(wasm: *Wasm) !void { |
| 2334 | | if (wasm.dwarf == null) return; |
| 2335 | | |
| 2336 | | const allocAtom = struct { |
| 2337 | | fn f(bin: *Wasm, maybe_index: *?u32, atom_index: Atom.Index) !void { |
| 2338 | | const index = maybe_index.* orelse idx: { |
| 2339 | | const index = @as(u32, @intCast(bin.segments.items.len)); |
| 2340 | | try bin.appendDummySegment(); |
| 2341 | | maybe_index.* = index; |
| 2342 | | break :idx index; |
| 2343 | | }; |
| 2344 | | const atom = bin.getAtomPtr(atom_index); |
| 2345 | | atom.size = @as(u32, @intCast(atom.code.items.len)); |
| 2346 | | bin.symbols.items[atom.sym_index].index = index; |
| 2347 | | try bin.appendAtomAtIndex(index, atom_index); |
| 2348 | | } |
| 2349 | | }.f; |
| 2350 | | |
| 2351 | | try allocAtom(wasm, &wasm.debug_info_index, wasm.debug_info_atom.?); |
| 2352 | | try allocAtom(wasm, &wasm.debug_line_index, wasm.debug_line_atom.?); |
| 2353 | | try allocAtom(wasm, &wasm.debug_loc_index, wasm.debug_loc_atom.?); |
| 2354 | | try allocAtom(wasm, &wasm.debug_str_index, wasm.debug_str_atom.?); |
| 2355 | | try allocAtom(wasm, &wasm.debug_ranges_index, wasm.debug_ranges_atom.?); |
| 2356 | | try allocAtom(wasm, &wasm.debug_abbrev_index, wasm.debug_abbrev_atom.?); |
| 2357 | | try allocAtom(wasm, &wasm.debug_pubnames_index, wasm.debug_pubnames_atom.?); |
| 2358 | | try allocAtom(wasm, &wasm.debug_pubtypes_index, wasm.debug_pubtypes_atom.?); |
| 2359 | | } |
| 2360 | | |
| 2361 | 1600 | fn allocateAtoms(wasm: *Wasm) !void { |
| 2362 | 1601 | // first sort the data segments |
| 2363 | 1602 | try sortDataSegments(wasm); |
| 2364 | | try allocateDebugAtoms(wasm); |
| 2365 | 1603 | |
| 2366 | 1604 | var it = wasm.atoms.iterator(); |
| 2367 | 1605 | while (it.next()) |entry| { |
| ... | ... | @@ -2382,7 +1620,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2382 | 1620 | const sym = if (symbol_loc.file) |object_index| sym: { |
| 2383 | 1621 | const object = wasm.objects.items[object_index]; |
| 2384 | 1622 | break :sym object.symtable[symbol_loc.index]; |
| 2385 | | } else wasm.symbols.items[symbol_loc.index]; |
| 1623 | } else wasm.synthetic_symbols.items[symbol_loc.index]; |
| 2386 | 1624 | |
| 2387 | 1625 | // Dead symbols must be unlinked from the linked-list to prevent them |
| 2388 | 1626 | // from being emit into the binary. |
| ... | ... | @@ -2521,34 +1759,6 @@ fn setupInitFunctions(wasm: *Wasm) !void { |
| 2521 | 1759 | } |
| 2522 | 1760 | } |
| 2523 | 1761 | |
| 2524 | | /// Generates an atom containing the global error set' size. |
| 2525 | | /// This will only be generated if the symbol exists. |
| 2526 | | fn setupErrorsLen(wasm: *Wasm) !void { |
| 2527 | | const gpa = wasm.base.comp.gpa; |
| 2528 | | const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return; |
| 2529 | | |
| 2530 | | const errors_len = wasm.base.comp.module.?.global_error_set.count(); |
| 2531 | | // overwrite existing atom if it already exists (maybe the error set has increased) |
| 2532 | | // if not, allcoate a new atom. |
| 2533 | | const atom_index = if (wasm.symbol_atom.get(loc)) |index| blk: { |
| 2534 | | const atom = wasm.getAtomPtr(index); |
| 2535 | | atom.deinit(gpa); |
| 2536 | | break :blk index; |
| 2537 | | } else new_atom: { |
| 2538 | | const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); |
| 2539 | | try wasm.symbol_atom.put(gpa, loc, atom_index); |
| 2540 | | try wasm.managed_atoms.append(gpa, undefined); |
| 2541 | | break :new_atom atom_index; |
| 2542 | | }; |
| 2543 | | const atom = wasm.getAtomPtr(atom_index); |
| 2544 | | atom.* = Atom.empty; |
| 2545 | | atom.sym_index = loc.index; |
| 2546 | | atom.size = 2; |
| 2547 | | try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little); |
| 2548 | | |
| 2549 | | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 2550 | | } |
| 2551 | | |
| 2552 | 1762 | /// Creates a function body for the `__wasm_call_ctors` symbol. |
| 2553 | 1763 | /// Loops over all constructors found in `init_funcs` and calls them |
| 2554 | 1764 | /// respectively based on their priority which was sorted by `setupInitFunctions`. |
| ... | ... | @@ -3278,139 +2488,6 @@ fn appendDummySegment(wasm: *Wasm) !void { |
| 3278 | 2488 | }); |
| 3279 | 2489 | } |
| 3280 | 2490 | |
| 3281 | | /// Returns the symbol index of the error name table. |
| 3282 | | /// |
| 3283 | | /// When the symbol does not yet exist, it will create a new one instead. |
| 3284 | | pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 3285 | | if (wasm.error_table_symbol) |symbol| { |
| 3286 | | return symbol; |
| 3287 | | } |
| 3288 | | |
| 3289 | | // no error was referenced yet, so create a new symbol and atom for it |
| 3290 | | // and then return said symbol's index. The final table will be populated |
| 3291 | | // during `flush` when we know all possible error names. |
| 3292 | | |
| 3293 | | const gpa = wasm.base.comp.gpa; |
| 3294 | | const atom_index = try wasm.createAtom(); |
| 3295 | | const atom = wasm.getAtomPtr(atom_index); |
| 3296 | | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 3297 | | const mod = wasm.base.comp.module.?; |
| 3298 | | atom.alignment = slice_ty.abiAlignment(mod); |
| 3299 | | const sym_index = atom.sym_index; |
| 3300 | | |
| 3301 | | const sym_name = try wasm.string_table.put(gpa, "__zig_err_name_table"); |
| 3302 | | const symbol = &wasm.symbols.items[sym_index]; |
| 3303 | | symbol.* = .{ |
| 3304 | | .name = sym_name, |
| 3305 | | .tag = .data, |
| 3306 | | .flags = 0, |
| 3307 | | .index = 0, |
| 3308 | | .virtual_address = undefined, |
| 3309 | | }; |
| 3310 | | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 3311 | | symbol.mark(); |
| 3312 | | |
| 3313 | | try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); |
| 3314 | | |
| 3315 | | log.debug("Error name table was created with symbol index: ({d})", .{sym_index}); |
| 3316 | | wasm.error_table_symbol = sym_index; |
| 3317 | | return sym_index; |
| 3318 | | } |
| 3319 | | |
| 3320 | | /// Populates the error name table, when `error_table_symbol` is not null. |
| 3321 | | /// |
| 3322 | | /// This creates a table that consists of pointers and length to each error name. |
| 3323 | | /// The table is what is being pointed to within the runtime bodies that are generated. |
| 3324 | | fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3325 | | const gpa = wasm.base.comp.gpa; |
| 3326 | | const symbol_index = wasm.error_table_symbol orelse return; |
| 3327 | | const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; |
| 3328 | | |
| 3329 | | // Rather than creating a symbol for each individual error name, |
| 3330 | | // we create a symbol for the entire region of error names. We then calculate |
| 3331 | | // the pointers into the list using addends which are appended to the relocation. |
| 3332 | | const names_atom_index = try wasm.createAtom(); |
| 3333 | | const names_atom = wasm.getAtomPtr(names_atom_index); |
| 3334 | | names_atom.alignment = .@"1"; |
| 3335 | | const sym_name = try wasm.string_table.put(gpa, "__zig_err_names"); |
| 3336 | | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; |
| 3337 | | names_symbol.* = .{ |
| 3338 | | .name = sym_name, |
| 3339 | | .tag = .data, |
| 3340 | | .flags = 0, |
| 3341 | | .index = 0, |
| 3342 | | .virtual_address = undefined, |
| 3343 | | }; |
| 3344 | | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 3345 | | names_symbol.mark(); |
| 3346 | | |
| 3347 | | log.debug("Populating error names", .{}); |
| 3348 | | |
| 3349 | | // Addend for each relocation to the table |
| 3350 | | var addend: u32 = 0; |
| 3351 | | const mod = wasm.base.comp.module.?; |
| 3352 | | for (mod.global_error_set.keys()) |error_name_nts| { |
| 3353 | | const atom = wasm.getAtomPtr(atom_index); |
| 3354 | | |
| 3355 | | const error_name = mod.intern_pool.stringToSlice(error_name_nts); |
| 3356 | | const len = @as(u32, @intCast(error_name.len + 1)); // names are 0-termianted |
| 3357 | | |
| 3358 | | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 3359 | | const offset = @as(u32, @intCast(atom.code.items.len)); |
| 3360 | | // first we create the data for the slice of the name |
| 3361 | | try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated |
| 3362 | | try atom.code.writer(gpa).writeInt(u32, len - 1, .little); |
| 3363 | | // create relocation to the error name |
| 3364 | | try atom.relocs.append(gpa, .{ |
| 3365 | | .index = names_atom.sym_index, |
| 3366 | | .relocation_type = .R_WASM_MEMORY_ADDR_I32, |
| 3367 | | .offset = offset, |
| 3368 | | .addend = @as(i32, @intCast(addend)), |
| 3369 | | }); |
| 3370 | | atom.size += @as(u32, @intCast(slice_ty.abiSize(mod))); |
| 3371 | | addend += len; |
| 3372 | | |
| 3373 | | // as we updated the error name table, we now store the actual name within the names atom |
| 3374 | | try names_atom.code.ensureUnusedCapacity(gpa, len); |
| 3375 | | names_atom.code.appendSliceAssumeCapacity(error_name); |
| 3376 | | names_atom.code.appendAssumeCapacity(0); |
| 3377 | | |
| 3378 | | log.debug("Populated error name: '{s}'", .{error_name}); |
| 3379 | | } |
| 3380 | | names_atom.size = addend; |
| 3381 | | |
| 3382 | | const name_loc = names_atom.symbolLoc(); |
| 3383 | | try wasm.resolved_symbols.put(gpa, name_loc, {}); |
| 3384 | | try wasm.symbol_atom.put(gpa, name_loc, names_atom_index); |
| 3385 | | |
| 3386 | | // link the atoms with the rest of the binary so they can be allocated |
| 3387 | | // and relocations will be performed. |
| 3388 | | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3389 | | try wasm.parseAtom(names_atom_index, .{ .data = .read_only }); |
| 3390 | | } |
| 3391 | | |
| 3392 | | /// From a given index variable, creates a new debug section. |
| 3393 | | /// This initializes the index, appends a new segment, |
| 3394 | | /// and finally, creates a managed `Atom`. |
| 3395 | | pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index { |
| 3396 | | const gpa = wasm.base.comp.gpa; |
| 3397 | | const new_index: u32 = @intCast(wasm.segments.items.len); |
| 3398 | | index.* = new_index; |
| 3399 | | try wasm.appendDummySegment(); |
| 3400 | | |
| 3401 | | const atom_index = try wasm.createAtom(); |
| 3402 | | const atom = wasm.getAtomPtr(atom_index); |
| 3403 | | wasm.symbols.items[atom.sym_index] = .{ |
| 3404 | | .tag = .section, |
| 3405 | | .name = try wasm.string_table.put(gpa, name), |
| 3406 | | .index = 0, |
| 3407 | | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 3408 | | }; |
| 3409 | | |
| 3410 | | atom.alignment = .@"1"; // debug sections are always 1-byte-aligned |
| 3411 | | return atom_index; |
| 3412 | | } |
| 3413 | | |
| 3414 | 2491 | fn resetState(wasm: *Wasm) void { |
| 3415 | 2492 | const gpa = wasm.base.comp.gpa; |
| 3416 | 2493 | |
| ... | ... | @@ -3418,16 +2495,19 @@ fn resetState(wasm: *Wasm) void { |
| 3418 | 2495 | gpa.free(segment_info.name); |
| 3419 | 2496 | } |
| 3420 | 2497 | |
| 3421 | | var atom_it = wasm.decls.valueIterator(); |
| 3422 | | while (atom_it.next()) |atom_index| { |
| 3423 | | const atom = wasm.getAtomPtr(atom_index.*); |
| 3424 | | atom.prev = null; |
| 2498 | // TODO: Revisit |
| 2499 | // var atom_it = wasm.decls.valueIterator(); |
| 2500 | // while (atom_it.next()) |atom_index| { |
| 2501 | // const atom = wasm.getAtomPtr(atom_index.*); |
| 2502 | // atom.next = null; |
| 2503 | // atom.prev = null; |
| 3425 | 2504 | |
| 3426 | | for (atom.locals.items) |local_atom_index| { |
| 3427 | | const local_atom = wasm.getAtomPtr(local_atom_index); |
| 3428 | | local_atom.prev = null; |
| 3429 | | } |
| 3430 | | } |
| 2505 | // for (atom.locals.items) |local_atom_index| { |
| 2506 | // const local_atom = wasm.getAtomPtr(local_atom_index); |
| 2507 | // local_atom.next = null; |
| 2508 | // local_atom.prev = null; |
| 2509 | // } |
| 2510 | // } |
| 3431 | 2511 | |
| 3432 | 2512 | wasm.functions.clearRetainingCapacity(); |
| 3433 | 2513 | wasm.exports.clearRetainingCapacity(); |
| ... | ... | @@ -3684,7 +2764,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) |
| 3684 | 2764 | defer sub_prog_node.end(); |
| 3685 | 2765 | |
| 3686 | 2766 | // ensure the error names table is populated when an error name is referenced |
| 3687 | | try wasm.populateErrorNameTable(); |
| 2767 | // try wasm.populateErrorNameTable(); |
| 3688 | 2768 | |
| 3689 | 2769 | const objects = comp.objects; |
| 3690 | 2770 | |
| ... | ... | @@ -3722,66 +2802,66 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) |
| 3722 | 2802 | try wasm.setupInitFunctions(); |
| 3723 | 2803 | try wasm.setupStart(); |
| 3724 | 2804 | try wasm.markReferences(); |
| 3725 | | try wasm.setupErrorsLen(); |
| 2805 | // try wasm.setupErrorsLen(); |
| 3726 | 2806 | try wasm.setupImports(); |
| 3727 | | if (comp.module) |mod| { |
| 3728 | | var decl_it = wasm.decls.iterator(); |
| 3729 | | while (decl_it.next()) |entry| { |
| 3730 | | const decl = mod.declPtr(entry.key_ptr.*); |
| 3731 | | if (decl.isExtern(mod)) continue; |
| 3732 | | const atom_index = entry.value_ptr.*; |
| 3733 | | const atom = wasm.getAtomPtr(atom_index); |
| 3734 | | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 3735 | | try wasm.parseAtom(atom_index, .function); |
| 3736 | | } else if (decl.getOwnedVariable(mod)) |variable| { |
| 3737 | | if (variable.is_const) { |
| 3738 | | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3739 | | } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { |
| 3740 | | // for safe build modes, we store the atom in the data segment, |
| 3741 | | // whereas for unsafe build modes we store it in bss. |
| 3742 | | const decl_namespace = mod.namespacePtr(decl.src_namespace); |
| 3743 | | const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; |
| 3744 | | const is_initialized = switch (optimize_mode) { |
| 3745 | | .Debug, .ReleaseSafe => true, |
| 3746 | | .ReleaseFast, .ReleaseSmall => false, |
| 3747 | | }; |
| 3748 | | try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); |
| 3749 | | } else { |
| 3750 | | // when the decl is all zeroes, we store the atom in the bss segment, |
| 3751 | | // in all other cases it will be in the data segment. |
| 3752 | | const is_zeroes = for (atom.code.items) |byte| { |
| 3753 | | if (byte != 0) break false; |
| 3754 | | } else true; |
| 3755 | | try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized }); |
| 3756 | | } |
| 3757 | | } else { |
| 3758 | | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3759 | | } |
| 3760 | | |
| 3761 | | // also parse atoms for a decl's locals |
| 3762 | | for (atom.locals.items) |local_atom_index| { |
| 3763 | | try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); |
| 3764 | | } |
| 3765 | | } |
| 3766 | | // parse anonymous declarations |
| 3767 | | for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { |
| 3768 | | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 3769 | | if (ty.zigTypeTag(mod) == .Fn) { |
| 3770 | | try wasm.parseAtom(atom_index, .function); |
| 3771 | | } else { |
| 3772 | | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3773 | | } |
| 3774 | | } |
| 3775 | | |
| 3776 | | // also parse any backend-generated functions |
| 3777 | | for (wasm.synthetic_functions.items) |atom_index| { |
| 3778 | | try wasm.parseAtom(atom_index, .function); |
| 3779 | | } |
| 3780 | | |
| 3781 | | if (wasm.dwarf) |*dwarf| { |
| 3782 | | try dwarf.flushModule(comp.module.?); |
| 3783 | | } |
| 3784 | | } |
| 2807 | // if (comp.module) |mod| { |
| 2808 | // var decl_it = wasm.decls.iterator(); |
| 2809 | // while (decl_it.next()) |entry| { |
| 2810 | // const decl = mod.declPtr(entry.key_ptr.*); |
| 2811 | // if (decl.isExtern(mod)) continue; |
| 2812 | // const atom_index = entry.value_ptr.*; |
| 2813 | // const atom = wasm.getAtomPtr(atom_index); |
| 2814 | // if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 2815 | // try wasm.parseAtom(atom_index, .function); |
| 2816 | // } else if (decl.getOwnedVariable(mod)) |variable| { |
| 2817 | // if (variable.is_const) { |
| 2818 | // try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 2819 | // } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { |
| 2820 | // // for safe build modes, we store the atom in the data segment, |
| 2821 | // // whereas for unsafe build modes we store it in bss. |
| 2822 | // const decl_namespace = mod.namespacePtr(decl.src_namespace); |
| 2823 | // const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; |
| 2824 | // const is_initialized = switch (optimize_mode) { |
| 2825 | // .Debug, .ReleaseSafe => true, |
| 2826 | // .ReleaseFast, .ReleaseSmall => false, |
| 2827 | // }; |
| 2828 | // try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); |
| 2829 | // } else { |
| 2830 | // // when the decl is all zeroes, we store the atom in the bss segment, |
| 2831 | // // in all other cases it will be in the data segment. |
| 2832 | // const is_zeroes = for (atom.code.items) |byte| { |
| 2833 | // if (byte != 0) break false; |
| 2834 | // } else true; |
| 2835 | // try wasm.parseAtom(atom_index, .{ .data = if (is_zeroes) .uninitialized else .initialized }); |
| 2836 | // } |
| 2837 | // } else { |
| 2838 | // try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 2839 | // } |
| 2840 | |
| 2841 | // // also parse atoms for a decl's locals |
| 2842 | // for (atom.locals.items) |local_atom_index| { |
| 2843 | // try wasm.parseAtom(local_atom_index, .{ .data = .read_only }); |
| 2844 | // } |
| 2845 | // } |
| 2846 | // // parse anonymous declarations |
| 2847 | // for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| { |
| 2848 | // const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 2849 | // if (ty.zigTypeTag(mod) == .Fn) { |
| 2850 | // try wasm.parseAtom(atom_index, .function); |
| 2851 | // } else { |
| 2852 | // try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 2853 | // } |
| 2854 | // } |
| 2855 | |
| 2856 | // // also parse any backend-generated functions |
| 2857 | // for (wasm.synthetic_functions.items) |atom_index| { |
| 2858 | // try wasm.parseAtom(atom_index, .function); |
| 2859 | // } |
| 2860 | |
| 2861 | // if (wasm.dwarf) |*dwarf| { |
| 2862 | // try dwarf.flushModule(comp.module.?); |
| 2863 | // } |
| 2864 | // } |
| 3785 | 2865 | |
| 3786 | 2866 | try wasm.mergeSections(); |
| 3787 | 2867 | try wasm.mergeTypes(); |
| ... | ... | @@ -4194,16 +3274,6 @@ fn writeToFile( |
| 4194 | 3274 | else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), |
| 4195 | 3275 | } |
| 4196 | 3276 | |
| 4197 | | // if (wasm.dwarf) |*dwarf| { |
| 4198 | | // const mod = comp.module.?; |
| 4199 | | // try dwarf.writeDbgAbbrev(); |
| 4200 | | // // for debug info and ranges, the address is always 0, |
| 4201 | | // // as locations are always offsets relative to 'code' section. |
| 4202 | | // try dwarf.writeDbgInfoHeader(mod, 0, code_section_size); |
| 4203 | | // try dwarf.writeDbgAranges(0, code_section_size); |
| 4204 | | // try dwarf.writeDbgLineHeader(); |
| 4205 | | // } |
| 4206 | | |
| 4207 | 3277 | var debug_bytes = std.ArrayList(u8).init(gpa); |
| 4208 | 3278 | defer debug_bytes.deinit(); |
| 4209 | 3279 | |
| ... | ... | @@ -5185,44 +4255,25 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { |
| 5185 | 4255 | return false; |
| 5186 | 4256 | } |
| 5187 | 4257 | |
| 5188 | | pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 { |
| 5189 | | var index: u32 = 0; |
| 5190 | | while (index < wasm.func_types.items.len) : (index += 1) { |
| 5191 | | if (wasm.func_types.items[index].eql(func_type)) return index; |
| 5192 | | } |
| 5193 | | return null; |
| 5194 | | } |
| 5195 | | |
| 5196 | 4258 | /// Searches for a matching function signature. When no matching signature is found, |
| 5197 | 4259 | /// a new entry will be made. The value returned is the index of the type within `wasm.func_types`. |
| 5198 | 4260 | pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { |
| 5199 | | if (wasm.getTypeIndex(func_type)) |index| { |
| 5200 | | return index; |
| 5201 | | } |
| 5202 | | const gpa = wasm.base.comp.gpa; |
| 5203 | | |
| 5204 | | // functype does not exist. |
| 5205 | | const index: u32 = @intCast(wasm.func_types.items.len); |
| 5206 | | const params = try gpa.dupe(std.wasm.Valtype, func_type.params); |
| 5207 | | errdefer gpa.free(params); |
| 5208 | | const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns); |
| 5209 | | errdefer gpa.free(returns); |
| 5210 | | try wasm.func_types.append(gpa, .{ |
| 5211 | | .params = params, |
| 5212 | | .returns = returns, |
| 5213 | | }); |
| 5214 | | return index; |
| 4261 | _ = wasm; |
| 4262 | _ = func_type; |
| 5215 | 4263 | } |
| 5216 | 4264 | |
| 5217 | 4265 | /// For the given `decl_index`, stores the corresponding type representing the function signature. |
| 5218 | 4266 | /// Asserts declaration has an associated `Atom`. |
| 5219 | 4267 | /// Returns the index into the list of types. |
| 5220 | 4268 | pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 { |
| 5221 | | const gpa = wasm.base.comp.gpa; |
| 5222 | | const atom_index = wasm.decls.get(decl_index).?; |
| 5223 | | const index = try wasm.putOrGetFuncType(func_type); |
| 5224 | | try wasm.atom_types.put(gpa, atom_index, index); |
| 5225 | | return index; |
| 4269 | _ = wasm; |
| 4270 | _ = decl_index; |
| 4271 | _ = func_type; |
| 4272 | // const gpa = wasm.base.comp.gpa; |
| 4273 | // const atom_index = wasm.decls.get(decl_index).?; |
| 4274 | // const index = try wasm.putOrGetFuncType(func_type); |
| 4275 | // try wasm.atom_types.put(gpa, atom_index, index); |
| 4276 | // return index; |
| 5226 | 4277 | } |
| 5227 | 4278 | |
| 5228 | 4279 | /// Verifies all resolved symbols and checks whether itself needs to be marked alive, |