| ... | ... | @@ -6,9 +6,9 @@ |
| 6 | 6 | path: []const u8, |
| 7 | 7 | /// Index within the list of relocatable objects of the linker driver. |
| 8 | 8 | index: File.Index, |
| 9 | | /// List of all `Decl` that are currently alive. |
| 10 | | /// Each index maps to the corresponding `Atom.Index`. |
| 11 | | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, |
| 9 | /// Map of all `Decl` that are currently alive. |
| 10 | /// Each index maps to the corresponding `DeclInfo`. |
| 11 | decls_map: std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclInfo) = .{}, |
| 12 | 12 | /// List of function type signatures for this Zig module. |
| 13 | 13 | func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 14 | 14 | /// List of `std.wasm.Func`. Each entry contains the function signature, |
| ... | ... | @@ -80,6 +80,26 @@ debug_str_index: ?u32 = null, |
| 80 | 80 | /// The index of the segment representing the custom '.debug_pubtypes' section. |
| 81 | 81 | debug_abbrev_index: ?u32 = null, |
| 82 | 82 | |
| 83 | const DeclInfo = struct { |
| 84 | atom: Atom.Index = std.math.maxInt(Atom.Index), |
| 85 | exports: std.ArrayListUnmanaged(u32) = .{}, |
| 86 | |
| 87 | fn @"export"(di: DeclInfo, zig_object: *const ZigObject, name: []const u8) ?u32 { |
| 88 | for (di.exports.items) |sym_index| { |
| 89 | const sym_name_index = zig_object.symbol(sym_index).name; |
| 90 | const sym_name = zig_object.string_table.getAssumeExists(sym_name_index); |
| 91 | if (std.mem.eql(u8, name, sym_name)) { |
| 92 | return sym_index; |
| 93 | } |
| 94 | } |
| 95 | return null; |
| 96 | } |
| 97 | |
| 98 | fn appendExport(di: *DeclInfo, gpa: std.mem.Allocator, sym_index: u32) !void { |
| 99 | return di.exports.append(gpa, sym_index); |
| 100 | } |
| 101 | }; |
| 102 | |
| 83 | 103 | /// Initializes the `ZigObject` with initial symbols. |
| 84 | 104 | pub fn init(zig_object: *ZigObject, wasm_file: *Wasm) !void { |
| 85 | 105 | // Initialize an undefined global with the name __stack_pointer. Codegen will use |
| ... | ... | @@ -122,14 +142,15 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void { |
| 122 | 142 | // The memory of atoms parsed from object files is managed by |
| 123 | 143 | // the object file itself, and therefore we can skip those. |
| 124 | 144 | { |
| 125 | | var it = zig_object.decls.valueIterator(); |
| 126 | | while (it.next()) |atom_index_ptr| { |
| 127 | | const atom = wasm_file.getAtomPtr(atom_index_ptr.*); |
| 145 | var it = zig_object.decls_map.valueIterator(); |
| 146 | while (it.next()) |decl_info| { |
| 147 | const atom = wasm_file.getAtomPtr(decl_info.atom); |
| 128 | 148 | for (atom.locals.items) |local_index| { |
| 129 | 149 | const local_atom = wasm_file.getAtomPtr(local_index); |
| 130 | 150 | local_atom.deinit(gpa); |
| 131 | 151 | } |
| 132 | 152 | atom.deinit(gpa); |
| 153 | decl_info.exports.deinit(gpa); |
| 133 | 154 | } |
| 134 | 155 | } |
| 135 | 156 | { |
| ... | ... | @@ -142,7 +163,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void { |
| 142 | 163 | atom.deinit(gpa); |
| 143 | 164 | } |
| 144 | 165 | } |
| 145 | | zig_object.decls.deinit(gpa); |
| 166 | zig_object.decls_map.deinit(gpa); |
| 146 | 167 | zig_object.anon_decls.deinit(gpa); |
| 147 | 168 | zig_object.symbols.deinit(gpa); |
| 148 | 169 | zig_object.symbols_free_list.deinit(gpa); |
| ... | ... | @@ -278,7 +299,8 @@ fn finishUpdateDecl( |
| 278 | 299 | const gpa = wasm_file.base.comp.gpa; |
| 279 | 300 | const mod = wasm_file.base.comp.module.?; |
| 280 | 301 | const decl = mod.declPtr(decl_index); |
| 281 | | const atom_index = zig_object.decls.get(decl_index).?; |
| 302 | const decl_info = zig_object.decls_map.get(decl_index).?; |
| 303 | const atom_index = decl_info.atom; |
| 282 | 304 | const atom = wasm_file.getAtomPtr(atom_index); |
| 283 | 305 | const sym = zig_object.symbol(atom.sym_index); |
| 284 | 306 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| ... | ... | @@ -337,6 +359,8 @@ fn finishUpdateDecl( |
| 337 | 359 | atom.alignment = decl.getAlignment(mod); |
| 338 | 360 | } |
| 339 | 361 | |
| 362 | /// Creates and initializes a new segment in the 'Data' section. |
| 363 | /// Reuses free slots in the list of segments and returns the index. |
| 340 | 364 | fn createDataSegment( |
| 341 | 365 | zig_object: *ZigObject, |
| 342 | 366 | gpa: std.mem.Allocator, |
| ... | ... | @@ -355,6 +379,7 @@ fn createDataSegment( |
| 355 | 379 | .flags = 0, |
| 356 | 380 | .name = name, |
| 357 | 381 | }; |
| 382 | return segment_index; |
| 358 | 383 | } |
| 359 | 384 | |
| 360 | 385 | /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. |
| ... | ... | @@ -362,17 +387,17 @@ fn createDataSegment( |
| 362 | 387 | /// The newly created Atom is empty with default fields as specified by `Atom.empty`. |
| 363 | 388 | pub fn getOrCreateAtomForDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index { |
| 364 | 389 | const gpa = wasm_file.base.comp.gpa; |
| 365 | | const gop = try zig_object.decls.getOrPut(gpa, decl_index); |
| 390 | const gop = try zig_object.decls_map.getOrPut(gpa, decl_index); |
| 366 | 391 | if (!gop.found_existing) { |
| 367 | 392 | const sym_index = try zig_object.allocateSymbol(gpa); |
| 368 | | gop.value_ptr.* = try wasm_file.createAtom(sym_index, zig_object.index); |
| 393 | gop.value_ptr.* = .{ .atom = try wasm_file.createAtom(sym_index, zig_object.index) }; |
| 369 | 394 | const mod = wasm_file.base.comp.module.?; |
| 370 | 395 | const decl = mod.declPtr(decl_index); |
| 371 | 396 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 372 | 397 | const sym = zig_object.symbol(sym_index); |
| 373 | 398 | sym.name = try zig_object.string_table.insert(gpa, full_name); |
| 374 | 399 | } |
| 375 | | return gop.value_ptr.*; |
| 400 | return gop.value_ptr.atom; |
| 376 | 401 | } |
| 377 | 402 | |
| 378 | 403 | pub fn lowerAnonDecl( |
| ... | ... | @@ -459,11 +484,17 @@ fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: Ty |
| 459 | 484 | const code = code: { |
| 460 | 485 | const atom = wasm_file.getAtomPtr(atom_index); |
| 461 | 486 | atom.alignment = tv.ty.abiAlignment(mod); |
| 487 | const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name }); |
| 488 | errdefer gpa.free(segment_name); |
| 462 | 489 | zig_object.symbols.items[sym_index] = .{ |
| 463 | 490 | .name = try zig_object.string_table.insert(gpa, name), |
| 464 | 491 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 465 | 492 | .tag = .data, |
| 466 | | .index = undefined, |
| 493 | .index = try zig_object.createDataSegment( |
| 494 | gpa, |
| 495 | segment_name, |
| 496 | tv.ty.abiAlignment(mod), |
| 497 | ), |
| 467 | 498 | .virtual_address = undefined, |
| 468 | 499 | }; |
| 469 | 500 | |
| ... | ... | @@ -770,8 +801,8 @@ pub fn deleteDeclExport( |
| 770 | 801 | wasm_file: *Wasm, |
| 771 | 802 | decl_index: InternPool.DeclIndex, |
| 772 | 803 | ) void { |
| 773 | | const atom_index = zig_object.decls.get(decl_index) orelse return; |
| 774 | | const sym_index = wasm_file.getAtom(atom_index).sym_index; |
| 804 | const decl_info = zig_object.decls_map.get(decl_index) orelse return; |
| 805 | const sym_index = wasm_file.getAtom(decl_info.atom).sym_index; |
| 775 | 806 | const loc: Wasm.SymbolLoc = .{ .file = zig_object.index, .index = sym_index }; |
| 776 | 807 | const sym = loc.getSymbol(wasm_file); |
| 777 | 808 | std.debug.assert(zig_object.global_syms.remove(sym.name)); |
| ... | ... | @@ -793,6 +824,7 @@ pub fn updateExports( |
| 793 | 824 | }; |
| 794 | 825 | const decl = mod.declPtr(decl_index); |
| 795 | 826 | const atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index); |
| 827 | const decl_info = zig_object.decls_map.getPtr(decl_index).?; |
| 796 | 828 | const atom = wasm_file.getAtom(atom_index); |
| 797 | 829 | const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*; |
| 798 | 830 | const gpa = mod.gpa; |
| ... | ... | @@ -808,33 +840,26 @@ pub fn updateExports( |
| 808 | 840 | continue; |
| 809 | 841 | } |
| 810 | 842 | |
| 811 | | const exported_decl_index = switch (exp.exported) { |
| 812 | | .value => { |
| 813 | | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 814 | | gpa, |
| 815 | | decl.srcLoc(mod), |
| 816 | | "Unimplemented: exporting a named constant value", |
| 817 | | .{}, |
| 818 | | )); |
| 819 | | continue; |
| 820 | | }, |
| 821 | | .decl_index => |i| i, |
| 843 | const export_string = mod.intern_pool.stringToSlice(exp.opts.name); |
| 844 | const sym_index = if (decl_info.@"export"(zig_object, export_string)) |idx| |
| 845 | idx |
| 846 | else index: { |
| 847 | const sym_index = try zig_object.allocateSymbol(gpa); |
| 848 | try decl_info.appendExport(gpa, sym_index); |
| 849 | break :index sym_index; |
| 822 | 850 | }; |
| 823 | | const exported_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, exported_decl_index); |
| 824 | | const exported_atom = wasm_file.getAtom(exported_atom_index); |
| 825 | | // const export_name = try zig_object.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 826 | | const sym_loc = exported_atom.symbolLoc(); |
| 827 | | const sym = sym_loc.getSymbol(wasm_file); |
| 851 | |
| 852 | const export_name = try zig_object.string_table.insert(gpa, export_string); |
| 853 | const sym = zig_object.symbol(sym_index); |
| 828 | 854 | sym.setGlobal(true); |
| 829 | 855 | sym.setUndefined(false); |
| 830 | 856 | sym.index = atom_sym.index; |
| 831 | 857 | sym.tag = atom_sym.tag; |
| 832 | | sym.name = atom_sym.name; |
| 858 | sym.name = export_name; |
| 833 | 859 | |
| 834 | 860 | switch (exp.opts.linkage) { |
| 835 | 861 | .Internal => { |
| 836 | 862 | sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 837 | | sym.setFlag(.WASM_SYM_BINDING_WEAK); |
| 838 | 863 | }, |
| 839 | 864 | .Weak => { |
| 840 | 865 | sym.setFlag(.WASM_SYM_BINDING_WEAK); |
| ... | ... | @@ -850,53 +875,10 @@ pub fn updateExports( |
| 850 | 875 | continue; |
| 851 | 876 | }, |
| 852 | 877 | } |
| 853 | | |
| 854 | | // TODO: Revisit this |
| 855 | | // if (zig_object.global_syms.get(export_name)) |existing_loc| { |
| 856 | | // if (existing_loc.index == atom.sym_index) continue; |
| 857 | | // const existing_sym: Symbol = existing_loc.getSymbol(wasm_file).*; |
| 858 | | |
| 859 | | // if (!existing_sym.isUndefined()) blk: { |
| 860 | | // if (symbol.isWeak()) { |
| 861 | | // try wasm_file.discarded.put(gpa, existing_loc, sym_loc); |
| 862 | | // continue; // to-be-exported symbol is weak, so we keep the existing symbol |
| 863 | | // } |
| 864 | | |
| 865 | | // // new symbol is not weak while existing is, replace existing symbol |
| 866 | | // if (existing_sym.isWeak()) { |
| 867 | | // break :blk; |
| 868 | | // } |
| 869 | | // // When both the to-be-exported symbol and the already existing symbol |
| 870 | | // // are strong symbols, we have a linker error. |
| 871 | | // // In the other case we replace one with the other. |
| 872 | | // try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( |
| 873 | | // gpa, |
| 874 | | // decl.srcLoc(mod), |
| 875 | | // \\LinkError: symbol '{}' defined multiple times |
| 876 | | // \\ first definition in '{s}' |
| 877 | | // \\ next definition in '{s}' |
| 878 | | // , |
| 879 | | // .{ exp.opts.name.fmt(&mod.intern_pool), wasm_file.name, wasm_file.name }, |
| 880 | | // )); |
| 881 | | // continue; |
| 882 | | // } |
| 883 | | |
| 884 | | // // in this case the existing symbol must be replaced either because it's weak or undefined. |
| 885 | | // try wasm.discarded.put(gpa, existing_loc, sym_loc); |
| 886 | | // _ = wasm.imports.remove(existing_loc); |
| 887 | | // _ = wasm.undefs.swapRemove(existing_sym.name); |
| 888 | | // } |
| 889 | | |
| 890 | | // // Ensure the symbol will be exported using the given name |
| 891 | | // if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 892 | | // try wasm.export_names.put(gpa, sym_loc, export_name); |
| 893 | | // } |
| 894 | | |
| 895 | | // try wasm.globals.put( |
| 896 | | // gpa, |
| 897 | | // export_name, |
| 898 | | // sym_loc, |
| 899 | | // ); |
| 878 | if (exp.opts.visibility == .hidden) { |
| 879 | sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 880 | } |
| 881 | try zig_object.global_syms.put(gpa, export_name, sym_index); |
| 900 | 882 | } |
| 901 | 883 | } |
| 902 | 884 | |
| ... | ... | @@ -904,10 +886,17 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool |
| 904 | 886 | const gpa = wasm_file.base.comp.gpa; |
| 905 | 887 | const mod = wasm_file.base.comp.module.?; |
| 906 | 888 | const decl = mod.declPtr(decl_index); |
| 907 | | const atom_index = zig_object.decls.get(decl_index).?; |
| 889 | const decl_info = zig_object.decls_map.getPtr(decl_index).?; |
| 890 | const atom_index = decl_info.atom; |
| 908 | 891 | const atom = wasm_file.getAtomPtr(atom_index); |
| 909 | 892 | zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {}; |
| 910 | | std.debug.assert(zig_object.decls.remove(decl_index)); |
| 893 | for (decl_info.exports.items) |exp_sym_index| { |
| 894 | const exp_sym = zig_object.symbol(exp_sym_index); |
| 895 | exp_sym.tag = .dead; |
| 896 | zig_object.symbols_free_list.append(exp_sym_index) catch {}; |
| 897 | } |
| 898 | decl_info.exports.deinit(gpa); |
| 899 | std.debug.assert(zig_object.decls_map.remove(decl_index)); |
| 911 | 900 | const sym = &zig_object.symbols.items[atom.sym_index]; |
| 912 | 901 | for (atom.locals.items) |local_atom_index| { |
| 913 | 902 | const local_atom = wasm_file.getAtom(local_atom_index); |
| ... | ... | @@ -942,6 +931,9 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool |
| 942 | 931 | } |
| 943 | 932 | |
| 944 | 933 | sym.tag = .dead; |
| 934 | if (sym.isGlobal()) { |
| 935 | std.debug.assert(zig_object.global_syms.remove(atom.sym_index)); |
| 936 | } |
| 945 | 937 | switch (decl.ty.zigTypeTag(mod)) { |
| 946 | 938 | .Fn => { |
| 947 | 939 | std.debug.assert(zig_object.functions.remove(atom.sym_index)); |
| ... | ... | @@ -1016,100 +1008,6 @@ pub fn parseAtom(zig_object: *ZigObject, wasm_file: *Wasm, atom_index: Atom.Inde |
| 1016 | 1008 | _ = wasm_file; |
| 1017 | 1009 | _ = atom_index; |
| 1018 | 1010 | _ = kind; |
| 1019 | | // const comp = wasm.base.comp; |
| 1020 | | // const gpa = comp.gpa; |
| 1021 | | // const shared_memory = comp.config.shared_memory; |
| 1022 | | // const import_memory = comp.config.import_memory; |
| 1023 | | // const atom = wasm.getAtomPtr(atom_index); |
| 1024 | | // const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); |
| 1025 | | // const do_garbage_collect = wasm.base.gc_sections; |
| 1026 | | |
| 1027 | | // if (symbol.isDead() and do_garbage_collect) { |
| 1028 | | // // Prevent unreferenced symbols from being parsed. |
| 1029 | | // return; |
| 1030 | | // } |
| 1031 | | |
| 1032 | | // const final_index: u32 = switch (kind) { |
| 1033 | | // .function => result: { |
| 1034 | | // const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); |
| 1035 | | // const type_index = wasm.atom_types.get(atom_index).?; |
| 1036 | | // try wasm.functions.putNoClobber( |
| 1037 | | // gpa, |
| 1038 | | // .{ .file = null, .index = index }, |
| 1039 | | // .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 1040 | | // ); |
| 1041 | | // symbol.tag = .function; |
| 1042 | | // symbol.index = index; |
| 1043 | | |
| 1044 | | // if (wasm.code_section_index == null) { |
| 1045 | | // wasm.code_section_index = @intCast(wasm.segments.items.len); |
| 1046 | | // try wasm.segments.append(gpa, .{ |
| 1047 | | // .alignment = atom.alignment, |
| 1048 | | // .size = atom.size, |
| 1049 | | // .offset = 0, |
| 1050 | | // .flags = 0, |
| 1051 | | // }); |
| 1052 | | // } |
| 1053 | | |
| 1054 | | // break :result wasm.code_section_index.?; |
| 1055 | | // }, |
| 1056 | | // .data => result: { |
| 1057 | | // const segment_name = try std.mem.concat(gpa, u8, &.{ |
| 1058 | | // kind.segmentName(), |
| 1059 | | // wasm.string_table.get(symbol.name), |
| 1060 | | // }); |
| 1061 | | // errdefer gpa.free(segment_name); |
| 1062 | | // const segment_info: types.Segment = .{ |
| 1063 | | // .name = segment_name, |
| 1064 | | // .alignment = atom.alignment, |
| 1065 | | // .flags = 0, |
| 1066 | | // }; |
| 1067 | | // symbol.tag = .data; |
| 1068 | | |
| 1069 | | // // when creating an object file, or importing memory and the data belongs in the .bss segment |
| 1070 | | // // we set the entire region of it to zeroes. |
| 1071 | | // // We do not have to do this when exporting the memory (the default) because the runtime |
| 1072 | | // // will do it for us, and we do not emit the bss segment at all. |
| 1073 | | // if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { |
| 1074 | | // @memset(atom.code.items, 0); |
| 1075 | | // } |
| 1076 | | |
| 1077 | | // const should_merge = wasm.base.comp.config.output_mode != .Obj; |
| 1078 | | // const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge)); |
| 1079 | | // if (gop.found_existing) { |
| 1080 | | // const index = gop.value_ptr.*; |
| 1081 | | // wasm.segments.items[index].size += atom.size; |
| 1082 | | |
| 1083 | | // symbol.index = @intCast(wasm.segment_info.getIndex(index).?); |
| 1084 | | // // segment info already exists, so free its memory |
| 1085 | | // gpa.free(segment_name); |
| 1086 | | // break :result index; |
| 1087 | | // } else { |
| 1088 | | // const index: u32 = @intCast(wasm.segments.items.len); |
| 1089 | | // var flags: u32 = 0; |
| 1090 | | // if (shared_memory) { |
| 1091 | | // flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 1092 | | // } |
| 1093 | | // try wasm.segments.append(gpa, .{ |
| 1094 | | // .alignment = atom.alignment, |
| 1095 | | // .size = 0, |
| 1096 | | // .offset = 0, |
| 1097 | | // .flags = flags, |
| 1098 | | // }); |
| 1099 | | // gop.value_ptr.* = index; |
| 1100 | | |
| 1101 | | // const info_index: u32 = @intCast(wasm.segment_info.count()); |
| 1102 | | // try wasm.segment_info.put(gpa, index, segment_info); |
| 1103 | | // symbol.index = info_index; |
| 1104 | | // break :result index; |
| 1105 | | // } |
| 1106 | | // }, |
| 1107 | | // }; |
| 1108 | | |
| 1109 | | // const segment: *Segment = &wasm.segments.items[final_index]; |
| 1110 | | // segment.alignment = segment.alignment.max(atom.alignment); |
| 1111 | | |
| 1112 | | // try wasm.appendAtomAtIndex(final_index, atom_index); |
| 1113 | 1011 | } |
| 1114 | 1012 | |
| 1115 | 1013 | /// Generates an atom containing the global error set' size. |
| ... | ... | @@ -1235,9 +1133,9 @@ fn allocateDebugAtoms(zig_object: *ZigObject) !void { |
| 1235 | 1133 | /// Asserts declaration has an associated `Atom`. |
| 1236 | 1134 | /// Returns the index into the list of types. |
| 1237 | 1135 | pub fn storeDeclType(zig_object: *ZigObject, gpa: std.mem.Allocator, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 { |
| 1238 | | const atom_index = zig_object.decls.get(decl_index).?; |
| 1136 | const decl_info = zig_object.decls_map.get(decl_index).?; |
| 1239 | 1137 | const index = try zig_object.putOrGetFuncType(gpa, func_type); |
| 1240 | | try zig_object.atom_types.put(gpa, atom_index, index); |
| 1138 | try zig_object.atom_types.put(gpa, decl_info.atom, index); |
| 1241 | 1139 | return index; |
| 1242 | 1140 | } |
| 1243 | 1141 | |