| ... | @@ -259,12 +259,47 @@ pub fn lowerAnonDecl( | ... | @@ -259,12 +259,47 @@ pub fn lowerAnonDecl( |
| 259 | explicit_alignment: InternPool.Alignment, | 259 | explicit_alignment: InternPool.Alignment, |
| 260 | src_loc: Module.SrcLoc, | 260 | src_loc: Module.SrcLoc, |
| 261 | ) !codegen.Result { | 261 | ) !codegen.Result { |
| 262 | _ = self; | 262 | const gpa = macho_file.base.comp.gpa; |
| 263 | _ = macho_file; | 263 | const mod = macho_file.base.comp.module.?; |
| 264 | _ = decl_val; | 264 | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 265 | _ = explicit_alignment; | 265 | const decl_alignment = switch (explicit_alignment) { |
| 266 | _ = src_loc; | 266 | .none => ty.abiAlignment(mod), |
| 267 | @panic("TODO lowerAnonDecl"); | 267 | else => explicit_alignment, |
| | 268 | }; |
| | 269 | if (self.anon_decls.get(decl_val)) |metadata| { |
| | 270 | const existing_alignment = macho_file.getSymbol(metadata.symbol_index).getAtom(macho_file).?.alignment; |
| | 271 | if (decl_alignment.order(existing_alignment).compare(.lte)) |
| | 272 | return .ok; |
| | 273 | } |
| | 274 | |
| | 275 | const val = Value.fromInterned(decl_val); |
| | 276 | const tv = TypedValue{ .ty = ty, .val = val }; |
| | 277 | var name_buf: [32]u8 = undefined; |
| | 278 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| | 279 | @intFromEnum(decl_val), |
| | 280 | }) catch unreachable; |
| | 281 | const res = self.lowerConst( |
| | 282 | macho_file, |
| | 283 | name, |
| | 284 | tv, |
| | 285 | decl_alignment, |
| | 286 | macho_file.zig_const_section_index.?, |
| | 287 | src_loc, |
| | 288 | ) catch |err| switch (err) { |
| | 289 | error.OutOfMemory => return error.OutOfMemory, |
| | 290 | else => |e| return .{ .fail = try Module.ErrorMsg.create( |
| | 291 | gpa, |
| | 292 | src_loc, |
| | 293 | "unable to lower constant value: {s}", |
| | 294 | .{@errorName(e)}, |
| | 295 | ) }, |
| | 296 | }; |
| | 297 | const sym_index = switch (res) { |
| | 298 | .ok => |sym_index| sym_index, |
| | 299 | .fail => |em| return .{ .fail = em }, |
| | 300 | }; |
| | 301 | try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index }); |
| | 302 | return .ok; |
| 268 | } | 303 | } |
| 269 | | 304 | |
| 270 | fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void { | 305 | fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void { |
| ... | @@ -591,11 +626,100 @@ pub fn lowerUnnamedConst( | ... | @@ -591,11 +626,100 @@ pub fn lowerUnnamedConst( |
| 591 | typed_value: TypedValue, | 626 | typed_value: TypedValue, |
| 592 | decl_index: InternPool.DeclIndex, | 627 | decl_index: InternPool.DeclIndex, |
| 593 | ) !u32 { | 628 | ) !u32 { |
| 594 | _ = self; | 629 | const gpa = macho_file.base.comp.gpa; |
| 595 | _ = macho_file; | 630 | const mod = macho_file.base.comp.module.?; |
| 596 | _ = typed_value; | 631 | const gop = try self.unnamed_consts.getOrPut(gpa, decl_index); |
| 597 | _ = decl_index; | 632 | if (!gop.found_existing) { |
| 598 | @panic("TODO lowerUnnamedConst"); | 633 | gop.value_ptr.* = .{}; |
| | 634 | } |
| | 635 | const unnamed_consts = gop.value_ptr; |
| | 636 | const decl = mod.declPtr(decl_index); |
| | 637 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| | 638 | const index = unnamed_consts.items.len; |
| | 639 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| | 640 | defer gpa.free(name); |
| | 641 | const sym_index = switch (try self.lowerConst( |
| | 642 | macho_file, |
| | 643 | name, |
| | 644 | typed_value, |
| | 645 | typed_value.ty.abiAlignment(mod), |
| | 646 | macho_file.zig_const_section_index.?, |
| | 647 | decl.srcLoc(mod), |
| | 648 | )) { |
| | 649 | .ok => |sym_index| sym_index, |
| | 650 | .fail => |em| { |
| | 651 | decl.analysis = .codegen_failure; |
| | 652 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| | 653 | log.err("{s}", .{em.msg}); |
| | 654 | return error.CodegenFail; |
| | 655 | }, |
| | 656 | }; |
| | 657 | const sym = macho_file.getSymbol(sym_index); |
| | 658 | try unnamed_consts.append(gpa, sym.atom); |
| | 659 | return sym_index; |
| | 660 | } |
| | 661 | |
| | 662 | const LowerConstResult = union(enum) { |
| | 663 | ok: Symbol.Index, |
| | 664 | fail: *Module.ErrorMsg, |
| | 665 | }; |
| | 666 | |
| | 667 | fn lowerConst( |
| | 668 | self: *ZigObject, |
| | 669 | macho_file: *MachO, |
| | 670 | name: []const u8, |
| | 671 | tv: TypedValue, |
| | 672 | required_alignment: InternPool.Alignment, |
| | 673 | output_section_index: u8, |
| | 674 | src_loc: Module.SrcLoc, |
| | 675 | ) !LowerConstResult { |
| | 676 | const gpa = macho_file.base.comp.gpa; |
| | 677 | |
| | 678 | var code_buffer = std.ArrayList(u8).init(gpa); |
| | 679 | defer code_buffer.deinit(); |
| | 680 | |
| | 681 | const sym_index = try self.addAtom(macho_file); |
| | 682 | |
| | 683 | const res = try codegen.generateSymbol(&macho_file.base, src_loc, tv, &code_buffer, .{ |
| | 684 | .none = {}, |
| | 685 | }, .{ |
| | 686 | .parent_atom_index = sym_index, |
| | 687 | }); |
| | 688 | const code = switch (res) { |
| | 689 | .ok => code_buffer.items, |
| | 690 | .fail => |em| return .{ .fail = em }, |
| | 691 | }; |
| | 692 | |
| | 693 | const sym = macho_file.getSymbol(sym_index); |
| | 694 | const name_str_index = try macho_file.strings.insert(gpa, name); |
| | 695 | sym.name = name_str_index; |
| | 696 | sym.out_n_sect = output_section_index; |
| | 697 | |
| | 698 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| | 699 | nlist.n_strx = name_str_index; |
| | 700 | nlist.n_type = macho.N_SECT; |
| | 701 | nlist.n_sect = output_section_index + 1; |
| | 702 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| | 703 | |
| | 704 | const atom = sym.getAtom(macho_file).?; |
| | 705 | atom.flags.alive = true; |
| | 706 | atom.name = name_str_index; |
| | 707 | atom.alignment = required_alignment; |
| | 708 | atom.size = code.len; |
| | 709 | atom.out_n_sect = output_section_index; |
| | 710 | |
| | 711 | try atom.allocate(macho_file); |
| | 712 | // TODO rename and re-audit this method |
| | 713 | errdefer self.freeDeclMetadata(macho_file, sym_index); |
| | 714 | |
| | 715 | sym.value = 0; |
| | 716 | nlist.n_value = 0; |
| | 717 | |
| | 718 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| | 719 | const file_offset = sect.offset + atom.value - sect.addr; |
| | 720 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| | 721 | |
| | 722 | return .{ .ok = sym_index }; |
| 599 | } | 723 | } |
| 600 | | 724 | |
| 601 | pub fn updateExports( | 725 | pub fn updateExports( |
| ... | @@ -692,6 +816,91 @@ pub fn updateExports( | ... | @@ -692,6 +816,91 @@ pub fn updateExports( |
| 692 | } | 816 | } |
| 693 | } | 817 | } |
| 694 | | 818 | |
| | 819 | fn updateLazySymbol( |
| | 820 | self: *ZigObject, |
| | 821 | macho_file: *MachO, |
| | 822 | lazy_sym: link.File.LazySymbol, |
| | 823 | symbol_index: Symbol.Index, |
| | 824 | ) !void { |
| | 825 | const gpa = macho_file.base.comp.gpa; |
| | 826 | const mod = macho_file.base.comp.module.?; |
| | 827 | |
| | 828 | var required_alignment: InternPool.Alignment = .none; |
| | 829 | var code_buffer = std.ArrayList(u8).init(gpa); |
| | 830 | defer code_buffer.deinit(); |
| | 831 | |
| | 832 | const name_str_index = blk: { |
| | 833 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ |
| | 834 | @tagName(lazy_sym.kind), |
| | 835 | lazy_sym.ty.fmt(mod), |
| | 836 | }); |
| | 837 | defer gpa.free(name); |
| | 838 | break :blk try macho_file.strings.insert(gpa, name); |
| | 839 | }; |
| | 840 | |
| | 841 | const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| | 842 | mod.declPtr(owner_decl).srcLoc(mod) |
| | 843 | else |
| | 844 | Module.SrcLoc{ |
| | 845 | .file_scope = undefined, |
| | 846 | .parent_decl_node = undefined, |
| | 847 | .lazy = .unneeded, |
| | 848 | }; |
| | 849 | const res = try codegen.generateLazySymbol( |
| | 850 | &macho_file.base, |
| | 851 | src, |
| | 852 | lazy_sym, |
| | 853 | &required_alignment, |
| | 854 | &code_buffer, |
| | 855 | .none, |
| | 856 | .{ .parent_atom_index = symbol_index }, |
| | 857 | ); |
| | 858 | const code = switch (res) { |
| | 859 | .ok => code_buffer.items, |
| | 860 | .fail => |em| { |
| | 861 | log.err("{s}", .{em.msg}); |
| | 862 | return error.CodegenFail; |
| | 863 | }, |
| | 864 | }; |
| | 865 | |
| | 866 | const output_section_index = switch (lazy_sym.kind) { |
| | 867 | .code => macho_file.zig_text_section_index.?, |
| | 868 | .const_data => macho_file.zig_const_section_index.?, |
| | 869 | }; |
| | 870 | const sym = macho_file.getSymbol(symbol_index); |
| | 871 | sym.name = name_str_index; |
| | 872 | sym.out_n_sect = output_section_index; |
| | 873 | |
| | 874 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| | 875 | nlist.n_strx = name_str_index; |
| | 876 | nlist.n_type = macho.N_SECT; |
| | 877 | nlist.n_sect = output_section_index + 1; |
| | 878 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| | 879 | |
| | 880 | const atom = sym.getAtom(macho_file).?; |
| | 881 | atom.flags.alive = true; |
| | 882 | atom.name = name_str_index; |
| | 883 | atom.alignment = required_alignment; |
| | 884 | atom.size = code.len; |
| | 885 | atom.out_n_sect = output_section_index; |
| | 886 | |
| | 887 | try atom.allocate(macho_file); |
| | 888 | errdefer self.freeDeclMetadata(macho_file, symbol_index); |
| | 889 | |
| | 890 | sym.value = 0; |
| | 891 | sym.flags.needs_zig_got = true; |
| | 892 | nlist.st_value = 0; |
| | 893 | |
| | 894 | if (!macho_file.base.isRelocatable()) { |
| | 895 | const gop = try sym.getOrCreateZigGotEntry(symbol_index, macho_file); |
| | 896 | try macho_file.zig_got.writeOne(macho_file, gop.index); |
| | 897 | } |
| | 898 | |
| | 899 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| | 900 | const file_offset = sect.offset + atom.value - sect.addr; |
| | 901 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| | 902 | } |
| | 903 | |
| 695 | /// Must be called only after a successful call to `updateDecl`. | 904 | /// Must be called only after a successful call to `updateDecl`. |
| 696 | pub fn updateDeclLineNumber( | 905 | pub fn updateDeclLineNumber( |
| 697 | self: *ZigObject, | 906 | self: *ZigObject, |
| ... | @@ -701,7 +910,7 @@ pub fn updateDeclLineNumber( | ... | @@ -701,7 +910,7 @@ pub fn updateDeclLineNumber( |
| 701 | _ = self; | 910 | _ = self; |
| 702 | _ = mod; | 911 | _ = mod; |
| 703 | _ = decl_index; | 912 | _ = decl_index; |
| 704 | @panic("TODO updateDeclLineNumber"); | 913 | // TODO: Dwarf |
| 705 | } | 914 | } |
| 706 | | 915 | |
| 707 | pub fn deleteDeclExport( | 916 | pub fn deleteDeclExport( |
| ... | @@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl( | ... | @@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl( |
| 751 | return gop.value_ptr.symbol_index; | 960 | return gop.value_ptr.symbol_index; |
| 752 | } | 961 | } |
| 753 | | 962 | |
| | 963 | pub fn getOrCreateMetadataForLazySymbol( |
| | 964 | self: *ZigObject, |
| | 965 | macho_file: *MachO, |
| | 966 | lazy_sym: link.File.LazySymbol, |
| | 967 | ) !Symbol.Index { |
| | 968 | const gpa = macho_file.base.comp.gpa; |
| | 969 | const mod = macho_file.base.comp.module.?; |
| | 970 | const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod)); |
| | 971 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| | 972 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| | 973 | const metadata: struct { |
| | 974 | symbol_index: *Symbol.Index, |
| | 975 | state: *LazySymbolMetadata.State, |
| | 976 | } = switch (lazy_sym.kind) { |
| | 977 | .code => .{ |
| | 978 | .symbol_index = &gop.value_ptr.text_symbol_index, |
| | 979 | .state = &gop.value_ptr.text_state, |
| | 980 | }, |
| | 981 | .const_data => .{ |
| | 982 | .symbol_index = &gop.value_ptr.const_symbol_index, |
| | 983 | .state = &gop.value_ptr.const_state, |
| | 984 | }, |
| | 985 | }; |
| | 986 | switch (metadata.state.*) { |
| | 987 | .unused => { |
| | 988 | const symbol_index = try self.addAtom(macho_file); |
| | 989 | const sym = macho_file.getSymbol(symbol_index); |
| | 990 | sym.flags.needs_zig_got = true; |
| | 991 | metadata.symbol_index.* = symbol_index; |
| | 992 | }, |
| | 993 | .pending_flush => return metadata.symbol_index.*, |
| | 994 | .flushed => {}, |
| | 995 | } |
| | 996 | metadata.state.* = .pending_flush; |
| | 997 | const symbol_index = metadata.symbol_index.*; |
| | 998 | // anyerror needs to be deferred until flushModule |
| | 999 | if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(macho_file, lazy_sym, symbol_index); |
| | 1000 | return symbol_index; |
| | 1001 | } |
| | 1002 | |
| 754 | pub fn asFile(self: *ZigObject) File { | 1003 | pub fn asFile(self: *ZigObject) File { |
| 755 | return .{ .zig_object = self }; | 1004 | return .{ .zig_object = self }; |
| 756 | } | 1005 | } |
| ... | @@ -822,9 +1071,9 @@ const DeclMetadata = struct { | ... | @@ -822,9 +1071,9 @@ const DeclMetadata = struct { |
| 822 | const LazySymbolMetadata = struct { | 1071 | const LazySymbolMetadata = struct { |
| 823 | const State = enum { unused, pending_flush, flushed }; | 1072 | const State = enum { unused, pending_flush, flushed }; |
| 824 | text_symbol_index: Symbol.Index = undefined, | 1073 | text_symbol_index: Symbol.Index = undefined, |
| 825 | data_const_symbol_index: Symbol.Index = undefined, | 1074 | const_symbol_index: Symbol.Index = undefined, |
| 826 | text_state: State = .unused, | 1075 | text_state: State = .unused, |
| 827 | rodata_state: State = .unused, | 1076 | const_state: State = .unused, |
| 828 | }; | 1077 | }; |
| 829 | | 1078 | |
| 830 | const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata); | 1079 | const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata); |