| ... | @@ -63,8 +63,29 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( | ... | @@ -63,8 +63,29 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( |
| 63 | ) = .{}, | 63 | ) = .{}, |
| 64 | data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = .{}, | 64 | data_decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, []const u8) = .{}, |
| 65 | | 65 | |
| | 66 | /// Table of unnamed constants associated with a parent `Decl`. |
| | 67 | /// We store them here so that we can free the constants whenever the `Decl` |
| | 68 | /// needs updating or is freed. |
| | 69 | /// |
| | 70 | /// For example, |
| | 71 | /// |
| | 72 | /// ```zig |
| | 73 | /// const Foo = struct{ |
| | 74 | /// a: u8, |
| | 75 | /// }; |
| | 76 | /// |
| | 77 | /// pub fn main() void { |
| | 78 | /// var foo = Foo{ .a = 1 }; |
| | 79 | /// _ = foo; |
| | 80 | /// } |
| | 81 | /// ``` |
| | 82 | /// |
| | 83 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| | 84 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| | 85 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 66 | hdr: aout.ExecHdr = undefined, | 86 | hdr: aout.ExecHdr = undefined, |
| 67 | | 87 | |
| | 88 | // relocs: std. |
| 68 | magic: u32, | 89 | magic: u32, |
| 69 | | 90 | |
| 70 | entry_val: ?u64 = null, | 91 | entry_val: ?u64 = null, |
| ... | @@ -82,6 +103,8 @@ const Bases = struct { | ... | @@ -82,6 +103,8 @@ const Bases = struct { |
| 82 | data: u64, | 103 | data: u64, |
| 83 | }; | 104 | }; |
| 84 | | 105 | |
| | 106 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(struct { info: DeclBlock, code: []const u8 })); |
| | 107 | |
| 85 | fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { | 108 | fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { |
| 86 | return addr + switch (t) { | 109 | return addr + switch (t) { |
| 87 | .T, .t, .l, .L => self.bases.text, | 110 | .T, .t, .l, .L => self.bases.text, |
| ... | @@ -233,6 +256,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -233,6 +256,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 233 | | 256 | |
| 234 | const decl_index = func.owner_decl; | 257 | const decl_index = func.owner_decl; |
| 235 | const decl = module.declPtr(decl_index); | 258 | const decl = module.declPtr(decl_index); |
| | 259 | self.freeUnnamedConsts(decl_index); |
| 236 | | 260 | |
| 237 | try self.seeDecl(decl_index); | 261 | try self.seeDecl(decl_index); |
| 238 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); | 262 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); |
| ... | @@ -280,11 +304,62 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -280,11 +304,62 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 280 | } | 304 | } |
| 281 | | 305 | |
| 282 | pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { | 306 | pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 283 | _ = self; | 307 | try self.seeDecl(decl_index); |
| 284 | _ = tv; | 308 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 285 | _ = decl_index; | 309 | defer code_buffer.deinit(); |
| 286 | log.debug("TODO lowerUnnamedConst for Plan9", .{}); | 310 | |
| 287 | return error.AnalysisFail; | 311 | const mod = self.base.options.module.?; |
| | 312 | const decl = mod.declPtr(decl_index); |
| | 313 | |
| | 314 | const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index); |
| | 315 | if (!gop.found_existing) { |
| | 316 | gop.value_ptr.* = .{}; |
| | 317 | } |
| | 318 | const unnamed_consts = gop.value_ptr; |
| | 319 | |
| | 320 | const decl_name = try decl.getFullyQualifiedName(mod); |
| | 321 | defer self.base.allocator.free(decl_name); |
| | 322 | |
| | 323 | const index = unnamed_consts.items.len; |
| | 324 | // name is freed when the unnamed const is freed |
| | 325 | const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| | 326 | |
| | 327 | const sym_index = try self.allocateSymbolIndex(); |
| | 328 | |
| | 329 | const info: DeclBlock = .{ |
| | 330 | .type = .d, |
| | 331 | .offset = null, |
| | 332 | .sym_index = sym_index, |
| | 333 | .got_index = self.allocateGotIndex(), |
| | 334 | }; |
| | 335 | const sym: aout.Sym = .{ |
| | 336 | .value = undefined, |
| | 337 | .type = info.type, |
| | 338 | .name = name, |
| | 339 | }; |
| | 340 | self.syms.items[info.sym_index.?] = sym; |
| | 341 | |
| | 342 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{ |
| | 343 | .none = {}, |
| | 344 | }, .{ |
| | 345 | .parent_atom_index = undefined, |
| | 346 | }); |
| | 347 | const code = switch (res) { |
| | 348 | .externally_managed => |x| x, |
| | 349 | .appended => code_buffer.items, |
| | 350 | .fail => |em| { |
| | 351 | decl.analysis = .codegen_failure; |
| | 352 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| | 353 | log.err("{s}", .{em.msg}); |
| | 354 | return error.AnalysisFail; |
| | 355 | }, |
| | 356 | }; |
| | 357 | // duped_code is freed when the unnamed const is freed |
| | 358 | var duped_code = try self.base.allocator.dupe(u8, code); |
| | 359 | errdefer self.base.allocator.free(duped_code); |
| | 360 | try unnamed_consts.append(self.base.allocator, .{ .info = info, .code = duped_code }); |
| | 361 | // we return the got_index to codegen so that it can reference to the place of the data in the got |
| | 362 | return @intCast(u32, info.got_index.?); |
| 288 | } | 363 | } |
| 289 | | 364 | |
| 290 | pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) !void { | 365 | pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) !void { |
| ... | @@ -347,12 +422,26 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { | ... | @@ -347,12 +422,26 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void { |
| 347 | if (decl.link.plan9.sym_index) |s| { | 422 | if (decl.link.plan9.sym_index) |s| { |
| 348 | self.syms.items[s] = sym; | 423 | self.syms.items[s] = sym; |
| 349 | } else { | 424 | } else { |
| 350 | if (self.syms_index_free_list.popOrNull()) |i| { | 425 | const s = try self.allocateSymbolIndex(); |
| 351 | decl.link.plan9.sym_index = i; | 426 | decl.link.plan9.sym_index = s; |
| 352 | } else { | 427 | self.syms.items[s] = sym; |
| 353 | try self.syms.append(self.base.allocator, sym); | 428 | } |
| 354 | decl.link.plan9.sym_index = self.syms.items.len - 1; | 429 | } |
| 355 | } | 430 | |
| | 431 | fn allocateSymbolIndex(self: *Plan9) !usize { |
| | 432 | if (self.syms_index_free_list.popOrNull()) |i| { |
| | 433 | return i; |
| | 434 | } else { |
| | 435 | _ = try self.syms.addOne(self.base.allocator); |
| | 436 | return self.syms.items.len - 1; |
| | 437 | } |
| | 438 | } |
| | 439 | fn allocateGotIndex(self: *Plan9) usize { |
| | 440 | if (self.got_index_free_list.popOrNull()) |i| { |
| | 441 | return i; |
| | 442 | } else { |
| | 443 | self.got_len += 1; |
| | 444 | return self.got_len - 1; |
| 356 | } | 445 | } |
| 357 | } | 446 | } |
| 358 | | 447 | |
| ... | @@ -381,7 +470,8 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { | ... | @@ -381,7 +470,8 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { |
| 381 | } | 470 | } |
| 382 | } | 471 | } |
| 383 | | 472 | |
| 384 | fn declCount(self: *Plan9) usize { | 473 | // counts decls and unnamed consts |
| | 474 | fn atomCount(self: *Plan9) usize { |
| 385 | var fn_decl_count: usize = 0; | 475 | var fn_decl_count: usize = 0; |
| 386 | var itf_files = self.fn_decl_table.iterator(); | 476 | var itf_files = self.fn_decl_table.iterator(); |
| 387 | while (itf_files.next()) |ent| { | 477 | while (itf_files.next()) |ent| { |
| ... | @@ -389,7 +479,13 @@ fn declCount(self: *Plan9) usize { | ... | @@ -389,7 +479,13 @@ fn declCount(self: *Plan9) usize { |
| 389 | var submap = ent.value_ptr.functions; | 479 | var submap = ent.value_ptr.functions; |
| 390 | fn_decl_count += submap.count(); | 480 | fn_decl_count += submap.count(); |
| 391 | } | 481 | } |
| 392 | return self.data_decl_table.count() + fn_decl_count; | 482 | const data_decl_count = self.data_decl_table.count(); |
| | 483 | var unnamed_const_count: usize = 0; |
| | 484 | var it_unc = self.unnamed_const_atoms.iterator(); |
| | 485 | while (it_unc.next()) |unnamed_consts| { |
| | 486 | unnamed_const_count += unnamed_consts.value_ptr.items.len; |
| | 487 | } |
| | 488 | return data_decl_count + fn_decl_count + unnamed_const_count; |
| 393 | } | 489 | } |
| 394 | | 490 | |
| 395 | pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 491 | pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| ... | @@ -411,13 +507,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -411,13 +507,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 411 | | 507 | |
| 412 | const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 508 | const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 413 | | 509 | |
| 414 | assert(self.got_len == self.declCount() + self.got_index_free_list.items.len); | 510 | assert(self.got_len == self.atomCount() + self.got_index_free_list.items.len); |
| 415 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; | 511 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 416 | var got_table = try self.base.allocator.alloc(u8, got_size); | 512 | var got_table = try self.base.allocator.alloc(u8, got_size); |
| 417 | defer self.base.allocator.free(got_table); | 513 | defer self.base.allocator.free(got_table); |
| 418 | | 514 | |
| 419 | // + 4 for header, got, symbols, linecountinfo | 515 | // + 4 for header, got, symbols, linecountinfo |
| 420 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.declCount() + 4); | 516 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4); |
| 421 | defer self.base.allocator.free(iovecs); | 517 | defer self.base.allocator.free(iovecs); |
| 422 | | 518 | |
| 423 | const file = self.base.file.?; | 519 | const file = self.base.file.?; |
| ... | @@ -509,6 +605,26 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -509,6 +605,26 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 509 | try self.addDeclExports(mod, decl, exports); | 605 | try self.addDeclExports(mod, decl, exports); |
| 510 | } | 606 | } |
| 511 | } | 607 | } |
| | 608 | // write the unnamed constants after the other data decls |
| | 609 | var it_unc = self.unnamed_const_atoms.iterator(); |
| | 610 | while (it_unc.next()) |unnamed_consts| { |
| | 611 | for (unnamed_consts.value_ptr.items) |*unnamed_const| { |
| | 612 | const code = unnamed_const.code; |
| | 613 | log.debug("write unnamed const: ({s})", .{self.syms.items[unnamed_const.info.sym_index.?].name}); |
| | 614 | foff += code.len; |
| | 615 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; |
| | 616 | iovecs_i += 1; |
| | 617 | const off = self.getAddr(data_i, .d); |
| | 618 | data_i += code.len; |
| | 619 | unnamed_const.info.offset = off; |
| | 620 | if (!self.sixtyfour_bit) { |
| | 621 | mem.writeInt(u32, got_table[unnamed_const.info.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian()); |
| | 622 | } else { |
| | 623 | mem.writeInt(u64, got_table[unnamed_const.info.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian()); |
| | 624 | } |
| | 625 | self.syms.items[unnamed_const.info.sym_index.?].value = off; |
| | 626 | } |
| | 627 | } |
| 512 | // edata symbol | 628 | // edata symbol |
| 513 | self.syms.items[0].value = self.getAddr(data_i, .b); | 629 | self.syms.items[0].value = self.getAddr(data_i, .b); |
| 514 | } | 630 | } |
| ... | @@ -518,7 +634,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -518,7 +634,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 518 | try self.writeSyms(&sym_buf); | 634 | try self.writeSyms(&sym_buf); |
| 519 | const syms = sym_buf.toOwnedSlice(); | 635 | const syms = sym_buf.toOwnedSlice(); |
| 520 | defer self.base.allocator.free(syms); | 636 | defer self.base.allocator.free(syms); |
| 521 | assert(2 + self.declCount() == iovecs_i); // we didn't write all the decls | 637 | assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls |
| 522 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; | 638 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; |
| 523 | iovecs_i += 1; | 639 | iovecs_i += 1; |
| 524 | iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len }; | 640 | iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len }; |
| ... | @@ -599,18 +715,24 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { | ... | @@ -599,18 +715,24 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 599 | self.syms_index_free_list.append(self.base.allocator, i) catch {}; | 715 | self.syms_index_free_list.append(self.base.allocator, i) catch {}; |
| 600 | self.syms.items[i] = aout.Sym.undefined_symbol; | 716 | self.syms.items[i] = aout.Sym.undefined_symbol; |
| 601 | } | 717 | } |
| | 718 | self.freeUnnamedConsts(decl_index); |
| | 719 | } |
| | 720 | fn freeUnnamedConsts(self: *Plan9, decl_index: Module.Decl.Index) void { |
| | 721 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; |
| | 722 | for (unnamed_consts.items) |c| { |
| | 723 | self.base.allocator.free(self.syms.items[c.info.sym_index.?].name); |
| | 724 | self.base.allocator.free(c.code); |
| | 725 | self.syms.items[c.info.sym_index.?] = aout.Sym.undefined_symbol; |
| | 726 | self.syms_index_free_list.append(self.base.allocator, c.info.sym_index.?) catch {}; |
| | 727 | } |
| | 728 | unnamed_consts.clearAndFree(self.base.allocator); |
| 602 | } | 729 | } |
| 603 | | 730 | |
| 604 | pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void { | 731 | pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void { |
| 605 | const mod = self.base.options.module.?; | 732 | const mod = self.base.options.module.?; |
| 606 | const decl = mod.declPtr(decl_index); | 733 | const decl = mod.declPtr(decl_index); |
| 607 | if (decl.link.plan9.got_index == null) { | 734 | if (decl.link.plan9.got_index == null) { |
| 608 | if (self.got_index_free_list.popOrNull()) |i| { | 735 | decl.link.plan9.got_index = self.allocateGotIndex(); |
| 609 | decl.link.plan9.got_index = i; | | |
| 610 | } else { | | |
| 611 | self.got_len += 1; | | |
| 612 | decl.link.plan9.got_index = self.got_len - 1; | | |
| 613 | } | | |
| 614 | } | 736 | } |
| 615 | } | 737 | } |
| 616 | | 738 | |
| ... | @@ -627,6 +749,12 @@ pub fn updateDeclExports( | ... | @@ -627,6 +749,12 @@ pub fn updateDeclExports( |
| 627 | } | 749 | } |
| 628 | pub fn deinit(self: *Plan9) void { | 750 | pub fn deinit(self: *Plan9) void { |
| 629 | const gpa = self.base.allocator; | 751 | const gpa = self.base.allocator; |
| | 752 | // free the unnamed consts |
| | 753 | var it_unc = self.unnamed_const_atoms.iterator(); |
| | 754 | while (it_unc.next()) |kv| { |
| | 755 | self.freeUnnamedConsts(kv.key_ptr.*); |
| | 756 | } |
| | 757 | self.unnamed_const_atoms.deinit(gpa); |
| 630 | var itf_files = self.fn_decl_table.iterator(); | 758 | var itf_files = self.fn_decl_table.iterator(); |
| 631 | while (itf_files.next()) |ent| { | 759 | while (itf_files.next()) |ent| { |
| 632 | // get the submap | 760 | // get the submap |
| ... | @@ -790,7 +918,9 @@ pub fn getDeclVAddr( | ... | @@ -790,7 +918,9 @@ pub fn getDeclVAddr( |
| 790 | start += entry.value_ptr.code.len; | 918 | start += entry.value_ptr.code.len; |
| 791 | } | 919 | } |
| 792 | } | 920 | } |
| 793 | unreachable; | 921 | // TODO |
| | 922 | return undefined; |
| | 923 | // unreachable; |
| 794 | } else { | 924 | } else { |
| 795 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; | 925 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 796 | var it = self.data_decl_table.iterator(); | 926 | var it = self.data_decl_table.iterator(); |
| ... | @@ -798,6 +928,8 @@ pub fn getDeclVAddr( | ... | @@ -798,6 +928,8 @@ pub fn getDeclVAddr( |
| 798 | if (decl_index == kv.key_ptr.*) return start; | 928 | if (decl_index == kv.key_ptr.*) return start; |
| 799 | start += kv.value_ptr.len; | 929 | start += kv.value_ptr.len; |
| 800 | } | 930 | } |
| 801 | unreachable; | 931 | // TODO |
| | 932 | return undefined; |
| | 933 | // unreachable; |
| 802 | } | 934 | } |
| 803 | } | 935 | } |