| ... | ... | @@ -63,8 +63,29 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged( |
| 63 | 63 | ) = .{}, |
| 64 | 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 | 86 | hdr: aout.ExecHdr = undefined, |
| 67 | 87 | |
| 88 | // relocs: std. |
| 68 | 89 | magic: u32, |
| 69 | 90 | |
| 70 | 91 | entry_val: ?u64 = null, |
| ... | ... | @@ -82,6 +103,8 @@ const Bases = struct { |
| 82 | 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 | 108 | fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 { |
| 86 | 109 | return addr + switch (t) { |
| 87 | 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 | 256 | |
| 234 | 257 | const decl_index = func.owner_decl; |
| 235 | 258 | const decl = module.declPtr(decl_index); |
| 259 | self.freeUnnamedConsts(decl_index); |
| 236 | 260 | |
| 237 | 261 | try self.seeDecl(decl_index); |
| 238 | 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 | 304 | } |
| 281 | 305 | |
| 282 | 306 | pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 283 | | _ = self; |
| 284 | | _ = tv; |
| 285 | | _ = decl_index; |
| 286 | | log.debug("TODO lowerUnnamedConst for Plan9", .{}); |
| 287 | | return error.AnalysisFail; |
| 307 | try self.seeDecl(decl_index); |
| 308 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 309 | defer code_buffer.deinit(); |
| 310 | |
| 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 | 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 | 422 | if (decl.link.plan9.sym_index) |s| { |
| 348 | 423 | self.syms.items[s] = sym; |
| 349 | 424 | } else { |
| 350 | | if (self.syms_index_free_list.popOrNull()) |i| { |
| 351 | | decl.link.plan9.sym_index = i; |
| 352 | | } else { |
| 353 | | try self.syms.append(self.base.allocator, sym); |
| 354 | | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| 355 | | } |
| 425 | const s = try self.allocateSymbolIndex(); |
| 426 | decl.link.plan9.sym_index = s; |
| 427 | self.syms.items[s] = sym; |
| 428 | } |
| 429 | } |
| 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 | 470 | } |
| 382 | 471 | } |
| 383 | 472 | |
| 384 | | fn declCount(self: *Plan9) usize { |
| 473 | // counts decls and unnamed consts |
| 474 | fn atomCount(self: *Plan9) usize { |
| 385 | 475 | var fn_decl_count: usize = 0; |
| 386 | 476 | var itf_files = self.fn_decl_table.iterator(); |
| 387 | 477 | while (itf_files.next()) |ent| { |
| ... | ... | @@ -389,7 +479,13 @@ fn declCount(self: *Plan9) usize { |
| 389 | 479 | var submap = ent.value_ptr.functions; |
| 390 | 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 | 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 | 507 | |
| 412 | 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 | 511 | const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 416 | 512 | var got_table = try self.base.allocator.alloc(u8, got_size); |
| 417 | 513 | defer self.base.allocator.free(got_table); |
| 418 | 514 | |
| 419 | 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 | 517 | defer self.base.allocator.free(iovecs); |
| 422 | 518 | |
| 423 | 519 | const file = self.base.file.?; |
| ... | ... | @@ -509,6 +605,26 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 509 | 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 | 628 | // edata symbol |
| 513 | 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 | 634 | try self.writeSyms(&sym_buf); |
| 519 | 635 | const syms = sym_buf.toOwnedSlice(); |
| 520 | 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 | 638 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; |
| 523 | 639 | iovecs_i += 1; |
| 524 | 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 | 715 | self.syms_index_free_list.append(self.base.allocator, i) catch {}; |
| 600 | 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 | 731 | pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !void { |
| 605 | 732 | const mod = self.base.options.module.?; |
| 606 | 733 | const decl = mod.declPtr(decl_index); |
| 607 | 734 | if (decl.link.plan9.got_index == null) { |
| 608 | | if (self.got_index_free_list.popOrNull()) |i| { |
| 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 | | } |
| 735 | decl.link.plan9.got_index = self.allocateGotIndex(); |
| 614 | 736 | } |
| 615 | 737 | } |
| 616 | 738 | |
| ... | ... | @@ -627,6 +749,12 @@ pub fn updateDeclExports( |
| 627 | 749 | } |
| 628 | 750 | pub fn deinit(self: *Plan9) void { |
| 629 | 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 | 758 | var itf_files = self.fn_decl_table.iterator(); |
| 631 | 759 | while (itf_files.next()) |ent| { |
| 632 | 760 | // get the submap |
| ... | ... | @@ -790,7 +918,9 @@ pub fn getDeclVAddr( |
| 790 | 918 | start += entry.value_ptr.code.len; |
| 791 | 919 | } |
| 792 | 920 | } |
| 793 | | unreachable; |
| 921 | // TODO |
| 922 | return undefined; |
| 923 | // unreachable; |
| 794 | 924 | } else { |
| 795 | 925 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; |
| 796 | 926 | var it = self.data_decl_table.iterator(); |
| ... | ... | @@ -798,6 +928,8 @@ pub fn getDeclVAddr( |
| 798 | 928 | if (decl_index == kv.key_ptr.*) return start; |
| 799 | 929 | start += kv.value_ptr.len; |
| 800 | 930 | } |
| 801 | | unreachable; |
| 931 | // TODO |
| 932 | return undefined; |
| 933 | // unreachable; |
| 802 | 934 | } |
| 803 | 935 | } |