authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 10:04:33-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-10 11:20:08-04:00
log3d2dfbe8289c2ecb45e1ba1fe79c4d7e21dd26c3
tree921e81c14c12e84cf4970a299b37d2a659c63c2f
parentf93a10f664fbbb67aeda031583a790e2a842fb01

InternPool: add `FileIndex` to `*File` mapping


7 files changed, 314 insertions(+), 251 deletions(-)

src/Compilation.zig+22-19
......@@ -2119,12 +2119,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21192119 }
21202120
21212121 if (comp.module) |zcu| {
2122 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
2123
21222124 zcu.compile_log_text.shrinkAndFree(gpa, 0);
21232125
21242126 // Make sure std.zig is inside the import_table. We unconditionally need
21252127 // it for start.zig.
21262128 const std_mod = zcu.std_mod;
2127 _ = try zcu.importPkg(std_mod);
2129 _ = try pt.importPkg(std_mod);
21282130
21292131 // Normally we rely on importing std to in turn import the root source file
21302132 // in the start code, but when using the stage1 backend that won't happen,
......@@ -2133,20 +2135,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21332135 // Likewise, in the case of `zig test`, the test runner is the root source file,
21342136 // and so there is nothing to import the main file.
21352137 if (comp.config.is_test) {
2136 _ = try zcu.importPkg(zcu.main_mod);
2138 _ = try pt.importPkg(zcu.main_mod);
21372139 }
21382140
21392141 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2140 _ = try zcu.importPkg(compiler_rt_mod);
2142 _ = try pt.importPkg(compiler_rt_mod);
21412143 }
21422144
21432145 // Put a work item in for every known source file to detect if
21442146 // it changed, and, if so, re-compute ZIR and then queue the job
21452147 // to update it.
21462148 try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
2147 for (zcu.import_table.values(), 0..) |file, file_index_usize| {
2148 const file_index: Zcu.File.Index = @enumFromInt(file_index_usize);
2149 if (file.mod.isBuiltin()) continue;
2149 for (zcu.import_table.values()) |file_index| {
2150 if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
21502151 comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
21512152 }
21522153
......@@ -2641,7 +2642,8 @@ fn resolveEmitLoc(
26412642 return slice.ptr;
26422643}
26432644
2644fn reportMultiModuleErrors(zcu: *Zcu) !void {
2645fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2646 const zcu = pt.zcu;
26452647 const gpa = zcu.gpa;
26462648 const ip = &zcu.intern_pool;
26472649 // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to
......@@ -2651,14 +2653,13 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
26512653 // Attach the "some omitted" note to the final error message
26522654 var last_err: ?*Zcu.ErrorMsg = null;
26532655
2654 for (zcu.import_table.values(), 0..) |file, file_index_usize| {
2656 for (zcu.import_table.values()) |file_index| {
2657 const file = zcu.fileByIndex(file_index);
26552658 if (!file.multi_pkg) continue;
26562659
26572660 num_errors += 1;
26582661 if (num_errors > max_errors) continue;
26592662
2660 const file_index: Zcu.File.Index = @enumFromInt(file_index_usize);
2661
26622663 const err = err_blk: {
26632664 // Like with errors, let's cap the number of notes to prevent a huge error spew.
26642665 const max_notes = 5;
......@@ -2749,8 +2750,9 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
27492750 // to add this flag after reporting the errors however, as otherwise
27502751 // we'd get an error for every single downstream file, which wouldn't be
27512752 // very useful.
2752 for (zcu.import_table.values()) |file| {
2753 if (file.multi_pkg) file.recursiveMarkMultiPkg(zcu);
2753 for (zcu.import_table.values()) |file_index| {
2754 const file = zcu.fileByIndex(file_index);
2755 if (file.multi_pkg) file.recursiveMarkMultiPkg(pt);
27542756 }
27552757}
27562758
......@@ -3443,11 +3445,12 @@ fn performAllTheWorkInner(
34433445 }
34443446 }
34453447
3446 if (comp.module) |mod| {
3447 try reportMultiModuleErrors(mod);
3448 try mod.flushRetryableFailures();
3449 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
3450 mod.codegen_prog_node = main_progress_node.start("Code Generation", 0);
3448 if (comp.module) |zcu| {
3449 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = .main };
3450 try reportMultiModuleErrors(pt);
3451 try zcu.flushRetryableFailures();
3452 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
3453 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
34513454 }
34523455
34533456 if (!InternPool.single_threaded) comp.thread_pool.spawnWgId(&comp.work_queue_wait_group, codegenThread, .{comp});
......@@ -4189,9 +4192,9 @@ fn workerAstGenFile(
41894192 comp.mutex.lock();
41904193 defer comp.mutex.unlock();
41914194
4192 const res = pt.zcu.importFile(file, import_path) catch continue;
4195 const res = pt.importFile(file, import_path) catch continue;
41934196 if (!res.is_pkg) {
4194 res.file.addReference(pt.zcu.*, .{ .import = .{
4197 res.file.addReference(pt.zcu, .{ .import = .{
41954198 .file = file_index,
41964199 .token = item.data.token,
41974200 } }) catch continue;
src/InternPool.zig+76-26
......@@ -1,6 +1,5 @@
11//! All interned objects have both a value and a type.
2//! This data structure is self-contained, with the following exceptions:
3//! * Module.Namespace has a pointer to Module.File
2//! This data structure is self-contained.
43
54/// One item per thread, indexed by `tid`, which is dense and unique per thread.
65locals: []Local = &.{},
......@@ -79,10 +78,6 @@ const want_multi_threaded = false;
7978/// Whether a single-threaded intern pool impl is in use.
8079pub const single_threaded = builtin.single_threaded or !want_multi_threaded;
8180
82pub const FileIndex = enum(u32) {
83 _,
84};
85
8681pub const TrackedInst = extern struct {
8782 file: FileIndex,
8883 inst: Zir.Inst.Index,
......@@ -340,6 +335,7 @@ const Local = struct {
340335 extra: ListMutate,
341336 limbs: ListMutate,
342337 strings: ListMutate,
338 files: ListMutate,
343339
344340 decls: BucketListMutate,
345341 namespaces: BucketListMutate,
......@@ -350,6 +346,7 @@ const Local = struct {
350346 extra: Extra,
351347 limbs: Limbs,
352348 strings: Strings,
349 files: Files,
353350
354351 decls: Decls,
355352 namespaces: Namespaces,
......@@ -370,16 +367,17 @@ const Local = struct {
370367 else => @compileError("unsupported host"),
371368 };
372369 const Strings = List(struct { u8 });
370 const Files = List(struct { *Zcu.File });
373371
374372 const decls_bucket_width = 8;
375373 const decls_bucket_mask = (1 << decls_bucket_width) - 1;
376374 const decl_next_free_field = "src_namespace";
377 const Decls = List(struct { *[1 << decls_bucket_width]Module.Decl });
375 const Decls = List(struct { *[1 << decls_bucket_width]Zcu.Decl });
378376
379377 const namespaces_bucket_width = 8;
380378 const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1;
381379 const namespace_next_free_field = "decl_index";
382 const Namespaces = List(struct { *[1 << namespaces_bucket_width]Module.Namespace });
380 const Namespaces = List(struct { *[1 << namespaces_bucket_width]Zcu.Namespace });
383381
384382 const ListMutate = struct {
385383 len: u32,
......@@ -677,6 +675,15 @@ const Local = struct {
677675 };
678676 }
679677
678 pub fn getMutableFiles(local: *Local, gpa: std.mem.Allocator) Files.Mutable {
679 return .{
680 .gpa = gpa,
681 .arena = &local.mutate.arena,
682 .mutate = &local.mutate.files,
683 .list = &local.shared.files,
684 };
685 }
686
680687 /// Rather than allocating Decl objects with an Allocator, we instead allocate
681688 /// them with this BucketList. This provides four advantages:
682689 /// * Stable memory so that one thread can access a Decl object while another
......@@ -812,8 +819,6 @@ const Hash = std.hash.Wyhash;
812819
813820const InternPool = @This();
814821const Zcu = @import("Zcu.zig");
815/// Deprecated.
816const Module = Zcu;
817822const Zir = std.zig.Zir;
818823
819824/// An index into `maps` which might be `none`.
......@@ -938,6 +943,28 @@ pub const OptionalNamespaceIndex = enum(u32) {
938943 }
939944};
940945
946pub const FileIndex = enum(u32) {
947 _,
948
949 const Unwrapped = struct {
950 tid: Zcu.PerThread.Id,
951 index: u32,
952
953 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) FileIndex {
954 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
955 assert(unwrapped.index <= ip.getIndexMask(u32));
956 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
957 unwrapped.index);
958 }
959 };
960 fn unwrap(file_index: FileIndex, ip: *const InternPool) Unwrapped {
961 return .{
962 .tid = @enumFromInt(@intFromEnum(file_index) >> ip.tid_shift_32 & ip.getTidMask()),
963 .index = @intFromEnum(file_index) & ip.getIndexMask(u32),
964 };
965 }
966};
967
941968/// An index into `strings`.
942969pub const String = enum(u32) {
943970 /// An empty string.
......@@ -4608,12 +4635,12 @@ pub const FuncAnalysis = packed struct(u32) {
46084635 /// inline, which means no runtime version of the function will be generated.
46094636 inline_only,
46104637 in_progress,
4611 /// There will be a corresponding ErrorMsg in Module.failed_decls
4638 /// There will be a corresponding ErrorMsg in Zcu.failed_decls
46124639 sema_failure,
46134640 /// This function might be OK but it depends on another Decl which did not
46144641 /// successfully complete semantic analysis.
46154642 dependency_failure,
4616 /// There will be a corresponding ErrorMsg in Module.failed_decls.
4643 /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
46174644 /// Indicates that semantic analysis succeeded, but code generation for
46184645 /// this function failed.
46194646 codegen_failure,
......@@ -5210,6 +5237,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
52105237 .extra = Local.Extra.empty,
52115238 .limbs = Local.Limbs.empty,
52125239 .strings = Local.Strings.empty,
5240 .files = Local.Files.empty,
52135241
52145242 .decls = Local.Decls.empty,
52155243 .namespaces = Local.Namespaces.empty,
......@@ -5221,6 +5249,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
52215249 .extra = Local.ListMutate.empty,
52225250 .limbs = Local.ListMutate.empty,
52235251 .strings = Local.ListMutate.empty,
5252 .files = Local.ListMutate.empty,
52245253
52255254 .decls = Local.BucketListMutate.empty,
52265255 .namespaces = Local.BucketListMutate.empty,
......@@ -9213,7 +9242,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
92139242 const items_size = (1 + 4) * items_len;
92149243 const extra_size = 4 * extra_len;
92159244 const limbs_size = 8 * limbs_len;
9216 const decls_size = @sizeOf(Module.Decl) * decls_len;
9245 const decls_size = @sizeOf(Zcu.Decl) * decls_len;
92179246
92189247 // TODO: map overhead size is not taken into account
92199248 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + decls_size;
......@@ -9640,29 +9669,22 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
96409669 try bw.flush();
96419670}
96429671
9643pub fn declPtr(ip: *InternPool, decl_index: DeclIndex) *Module.Decl {
9672pub fn declPtr(ip: *InternPool, decl_index: DeclIndex) *Zcu.Decl {
96449673 return @constCast(ip.declPtrConst(decl_index));
96459674}
96469675
9647pub fn declPtrConst(ip: *const InternPool, decl_index: DeclIndex) *const Module.Decl {
9676pub fn declPtrConst(ip: *const InternPool, decl_index: DeclIndex) *const Zcu.Decl {
96489677 const unwrapped_decl_index = decl_index.unwrap(ip);
96499678 const decls = ip.getLocalShared(unwrapped_decl_index.tid).decls.acquire();
96509679 const decls_bucket = decls.view().items(.@"0")[unwrapped_decl_index.bucket_index];
96519680 return &decls_bucket[unwrapped_decl_index.index];
96529681}
96539682
9654pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Module.Namespace {
9655 const unwrapped_namespace_index = namespace_index.unwrap(ip);
9656 const namespaces = ip.getLocalShared(unwrapped_namespace_index.tid).namespaces.acquire();
9657 const namespaces_bucket = namespaces.view().items(.@"0")[unwrapped_namespace_index.bucket_index];
9658 return &namespaces_bucket[unwrapped_namespace_index.index];
9659}
9660
96619683pub fn createDecl(
96629684 ip: *InternPool,
96639685 gpa: Allocator,
96649686 tid: Zcu.PerThread.Id,
9665 initialization: Module.Decl,
9687 initialization: Zcu.Decl,
96669688) Allocator.Error!DeclIndex {
96679689 const local = ip.getLocal(tid);
96689690 const free_list_next = local.mutate.decls.free_list;
......@@ -9679,7 +9701,7 @@ pub fn createDecl(
96799701 var arena = decls.arena.promote(decls.gpa);
96809702 defer decls.arena.* = arena.state;
96819703 decls.appendAssumeCapacity(.{try arena.allocator().create(
9682 [1 << Local.decls_bucket_width]Module.Decl,
9704 [1 << Local.decls_bucket_width]Zcu.Decl,
96839705 )});
96849706 }
96859707 const unwrapped_decl_index: DeclIndex.Unwrapped = .{
......@@ -9702,11 +9724,18 @@ pub fn destroyDecl(ip: *InternPool, tid: Zcu.PerThread.Id, decl_index: DeclIndex
97029724 local.mutate.decls.free_list = @intFromEnum(decl_index);
97039725}
97049726
9727pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Namespace {
9728 const unwrapped_namespace_index = namespace_index.unwrap(ip);
9729 const namespaces = ip.getLocalShared(unwrapped_namespace_index.tid).namespaces.acquire();
9730 const namespaces_bucket = namespaces.view().items(.@"0")[unwrapped_namespace_index.bucket_index];
9731 return &namespaces_bucket[unwrapped_namespace_index.index];
9732}
9733
97059734pub fn createNamespace(
97069735 ip: *InternPool,
97079736 gpa: Allocator,
97089737 tid: Zcu.PerThread.Id,
9709 initialization: Module.Namespace,
9738 initialization: Zcu.Namespace,
97109739) Allocator.Error!NamespaceIndex {
97119740 const local = ip.getLocal(tid);
97129741 const free_list_next = local.mutate.namespaces.free_list;
......@@ -9724,7 +9753,7 @@ pub fn createNamespace(
97249753 var arena = namespaces.arena.promote(namespaces.gpa);
97259754 defer namespaces.arena.* = arena.state;
97269755 namespaces.appendAssumeCapacity(.{try arena.allocator().create(
9727 [1 << Local.namespaces_bucket_width]Module.Namespace,
9756 [1 << Local.namespaces_bucket_width]Zcu.Namespace,
97289757 )});
97299758 }
97309759 const unwrapped_namespace_index: NamespaceIndex.Unwrapped = .{
......@@ -9756,6 +9785,27 @@ pub fn destroyNamespace(
97569785 local.mutate.namespaces.free_list = @intFromEnum(namespace_index);
97579786}
97589787
9788pub fn filePtr(ip: *InternPool, file_index: FileIndex) *Zcu.File {
9789 const file_index_unwrapped = file_index.unwrap(ip);
9790 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire();
9791 return files.view().items(.@"0")[file_index_unwrapped.index];
9792}
9793
9794pub fn createFile(
9795 ip: *InternPool,
9796 gpa: Allocator,
9797 tid: Zcu.PerThread.Id,
9798 file: *Zcu.File,
9799) Allocator.Error!FileIndex {
9800 const files = ip.getLocal(tid).getMutableFiles(gpa);
9801 const file_index_unwrapped: FileIndex.Unwrapped = .{
9802 .tid = tid,
9803 .index = files.mutate.len,
9804 };
9805 try files.append(.{file});
9806 return file_index_unwrapped.wrap(ip);
9807}
9808
97599809const EmbeddedNulls = enum {
97609810 no_embedded_nulls,
97619811 maybe_embedded_nulls,
src/Sema.zig+2-2
......@@ -6056,7 +6056,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
60566056 else => |e| return e,
60576057 };
60586058
6059 const result = zcu.importPkg(c_import_mod) catch |err|
6059 const result = pt.importPkg(c_import_mod) catch |err|
60606060 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
60616061
60626062 const path_digest = zcu.filePathDigest(result.file_index);
......@@ -13950,7 +13950,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1395013950 const operand_src = block.tokenOffset(inst_data.src_tok);
1395113951 const operand = inst_data.get(sema.code);
1395213952
13953 const result = zcu.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
13953 const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
1395413954 error.ImportOutsideModulePath => {
1395513955 return sema.fail(block, operand_src, "import of file outside module path: '{s}'", .{operand});
1395613956 },
src/Type.zig+1-1
......@@ -3451,7 +3451,7 @@ pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
34513451 };
34523452}
34533453
3454pub fn typeDeclSrcLine(ty: Type, zcu: *const Zcu) ?u32 {
3454pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
34553455 const ip = &zcu.intern_pool;
34563456 const tracked = switch (ip.indexToKey(ty.toIntern())) {
34573457 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
src/Zcu.zig+9-184
......@@ -102,7 +102,7 @@ multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
102102/// `Compilation.update` of the process for a given `Compilation`.
103103///
104104/// Indexes correspond 1:1 to `files`.
105import_table: std.StringArrayHashMapUnmanaged(*File) = .{},
105import_table: std.StringArrayHashMapUnmanaged(File.Index) = .{},
106106
107107/// The set of all the files which have been loaded with `@embedFile` in the Module.
108108/// We keep track of this in order to iterate over it and check which files have been
......@@ -892,7 +892,7 @@ pub const File = struct {
892892 }
893893
894894 /// Add a reference to this file during AstGen.
895 pub fn addReference(file: *File, zcu: Zcu, ref: File.Reference) !void {
895 pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
896896 // Don't add the same module root twice. Note that since we always add module roots at the
897897 // front of the references array (see below), this loop is actually O(1) on valid code.
898898 if (ref == .root) {
......@@ -924,7 +924,7 @@ pub const File = struct {
924924
925925 /// Mark this file and every file referenced by it as multi_pkg and report an
926926 /// astgen_failure error for them. AstGen must have completed in its entirety.
927 pub fn recursiveMarkMultiPkg(file: *File, mod: *Module) void {
927 pub fn recursiveMarkMultiPkg(file: *File, pt: Zcu.PerThread) void {
928928 file.multi_pkg = true;
929929 file.status = .astgen_failure;
930930
......@@ -944,9 +944,9 @@ pub const File = struct {
944944 const import_path = file.zir.nullTerminatedString(item.data.name);
945945 if (mem.eql(u8, import_path, "builtin")) continue;
946946
947 const res = mod.importFile(file, import_path) catch continue;
947 const res = pt.importFile(file, import_path) catch continue;
948948 if (!res.is_pkg and !res.file.multi_pkg) {
949 res.file.recursiveMarkMultiPkg(mod);
949 res.file.recursiveMarkMultiPkg(pt);
950950 }
951951 }
952952 }
......@@ -3002,183 +3002,7 @@ pub const ImportFileResult = struct {
30023002 is_pkg: bool,
30033003};
30043004
3005pub fn importPkg(zcu: *Zcu, mod: *Package.Module) !ImportFileResult {
3006 const gpa = zcu.gpa;
3007
3008 // The resolved path is used as the key in the import table, to detect if
3009 // an import refers to the same as another, despite different relative paths
3010 // or differently mapped package names.
3011 const resolved_path = try std.fs.path.resolve(gpa, &.{
3012 mod.root.root_dir.path orelse ".",
3013 mod.root.sub_path,
3014 mod.root_src_path,
3015 });
3016 var keep_resolved_path = false;
3017 defer if (!keep_resolved_path) gpa.free(resolved_path);
3018
3019 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
3020 errdefer _ = zcu.import_table.pop();
3021 if (gop.found_existing) {
3022 try gop.value_ptr.*.addReference(zcu.*, .{ .root = mod });
3023 return .{
3024 .file = gop.value_ptr.*,
3025 .file_index = @enumFromInt(gop.index),
3026 .is_new = false,
3027 .is_pkg = true,
3028 };
3029 }
3030
3031 const ip = &zcu.intern_pool;
3032
3033 try ip.files.ensureUnusedCapacity(gpa, 1);
3034
3035 if (mod.builtin_file) |builtin_file| {
3036 keep_resolved_path = true; // It's now owned by import_table.
3037 gop.value_ptr.* = builtin_file;
3038 try builtin_file.addReference(zcu.*, .{ .root = mod });
3039 const path_digest = computePathDigest(zcu, mod, builtin_file.sub_file_path);
3040 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
3041 return .{
3042 .file = builtin_file,
3043 .file_index = @enumFromInt(ip.files.entries.len - 1),
3044 .is_new = false,
3045 .is_pkg = true,
3046 };
3047 }
3048
3049 const sub_file_path = try gpa.dupe(u8, mod.root_src_path);
3050 errdefer gpa.free(sub_file_path);
3051
3052 const new_file = try gpa.create(File);
3053 errdefer gpa.destroy(new_file);
3054
3055 keep_resolved_path = true; // It's now owned by import_table.
3056 gop.value_ptr.* = new_file;
3057 new_file.* = .{
3058 .sub_file_path = sub_file_path,
3059 .source = undefined,
3060 .source_loaded = false,
3061 .tree_loaded = false,
3062 .zir_loaded = false,
3063 .stat = undefined,
3064 .tree = undefined,
3065 .zir = undefined,
3066 .status = .never_loaded,
3067 .mod = mod,
3068 };
3069
3070 const path_digest = computePathDigest(zcu, mod, sub_file_path);
3071
3072 try new_file.addReference(zcu.*, .{ .root = mod });
3073 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
3074 return .{
3075 .file = new_file,
3076 .file_index = @enumFromInt(ip.files.entries.len - 1),
3077 .is_new = true,
3078 .is_pkg = true,
3079 };
3080}
3081
3082/// Called from a worker thread during AstGen.
3083/// Also called from Sema during semantic analysis.
3084pub fn importFile(
3085 zcu: *Zcu,
3086 cur_file: *File,
3087 import_string: []const u8,
3088) !ImportFileResult {
3089 const mod = cur_file.mod;
3090
3091 if (std.mem.eql(u8, import_string, "std")) {
3092 return zcu.importPkg(zcu.std_mod);
3093 }
3094 if (std.mem.eql(u8, import_string, "root")) {
3095 return zcu.importPkg(zcu.root_mod);
3096 }
3097 if (mod.deps.get(import_string)) |pkg| {
3098 return zcu.importPkg(pkg);
3099 }
3100 if (!mem.endsWith(u8, import_string, ".zig")) {
3101 return error.ModuleNotFound;
3102 }
3103 const gpa = zcu.gpa;
3104
3105 // The resolved path is used as the key in the import table, to detect if
3106 // an import refers to the same as another, despite different relative paths
3107 // or differently mapped package names.
3108 const resolved_path = try std.fs.path.resolve(gpa, &.{
3109 mod.root.root_dir.path orelse ".",
3110 mod.root.sub_path,
3111 cur_file.sub_file_path,
3112 "..",
3113 import_string,
3114 });
3115
3116 var keep_resolved_path = false;
3117 defer if (!keep_resolved_path) gpa.free(resolved_path);
3118
3119 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
3120 errdefer _ = zcu.import_table.pop();
3121 if (gop.found_existing) return .{
3122 .file = gop.value_ptr.*,
3123 .file_index = @enumFromInt(gop.index),
3124 .is_new = false,
3125 .is_pkg = false,
3126 };
3127
3128 const ip = &zcu.intern_pool;
3129
3130 try ip.files.ensureUnusedCapacity(gpa, 1);
3131
3132 const new_file = try gpa.create(File);
3133 errdefer gpa.destroy(new_file);
3134
3135 const resolved_root_path = try std.fs.path.resolve(gpa, &.{
3136 mod.root.root_dir.path orelse ".",
3137 mod.root.sub_path,
3138 });
3139 defer gpa.free(resolved_root_path);
3140
3141 const sub_file_path = p: {
3142 const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);
3143 errdefer gpa.free(relative);
3144
3145 if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
3146 break :p relative;
3147 }
3148 return error.ImportOutsideModulePath;
3149 };
3150 errdefer gpa.free(sub_file_path);
3151
3152 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
3153 resolved_root_path, resolved_path, sub_file_path, import_string,
3154 });
3155
3156 keep_resolved_path = true; // It's now owned by import_table.
3157 gop.value_ptr.* = new_file;
3158 new_file.* = .{
3159 .sub_file_path = sub_file_path,
3160 .source = undefined,
3161 .source_loaded = false,
3162 .tree_loaded = false,
3163 .zir_loaded = false,
3164 .stat = undefined,
3165 .tree = undefined,
3166 .zir = undefined,
3167 .status = .never_loaded,
3168 .mod = mod,
3169 };
3170
3171 const path_digest = computePathDigest(zcu, mod, sub_file_path);
3172 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
3173 return .{
3174 .file = new_file,
3175 .file_index = @enumFromInt(ip.files.entries.len - 1),
3176 .is_new = true,
3177 .is_pkg = false,
3178 };
3179}
3180
3181fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8) Cache.BinDigest {
3005pub fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8) Cache.BinDigest {
31823006 const want_local_cache = mod == zcu.main_mod;
31833007 var path_hash: Cache.HashHelper = .{};
31843008 path_hash.addBytes(build_options.version);
......@@ -3710,8 +3534,9 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, Resolved
37103534 return result;
37113535}
37123536
3713pub fn fileByIndex(zcu: *const Zcu, i: File.Index) *File {
3714 return zcu.import_table.values()[@intFromEnum(i)];
3537pub fn fileByIndex(zcu: *Zcu, i: File.Index) *File {
3538 const ip = &zcu.intern_pool;
3539 return ip.filePtr(i);
37153540}
37163541
37173542/// Returns the `Decl` of the struct that represents this `File`.
src/Zcu/PerThread.zig+203-18
......@@ -817,7 +817,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
817817
818818/// https://github.com/ziglang/zig/issues/14307
819819pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void {
820 const import_file_result = try pt.zcu.importPkg(pkg);
820 const import_file_result = try pt.importPkg(pkg);
821821 const root_decl_index = pt.zcu.fileRootDecl(import_file_result.file_index);
822822 if (root_decl_index == .none) {
823823 return pt.semaFile(import_file_result.file_index);
......@@ -1081,7 +1081,7 @@ fn semaDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.SemaDeclResult {
10811081 const std_mod = zcu.std_mod;
10821082 if (decl.getFileScope(zcu).mod != std_mod) break :ip_index .none;
10831083 // We're in the std module.
1084 const std_file_imported = try zcu.importPkg(std_mod);
1084 const std_file_imported = try pt.importPkg(std_mod);
10851085 const std_file_root_decl_index = zcu.fileRootDecl(std_file_imported.file_index);
10861086 const std_decl = zcu.declPtr(std_file_root_decl_index.unwrap().?);
10871087 const std_namespace = std_decl.getInnerNamespace(zcu).?;
......@@ -1356,6 +1356,191 @@ pub fn semaAnonOwnerDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) !Zcu.Sem
13561356 };
13571357}
13581358
1359pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1360 const zcu = pt.zcu;
1361 const gpa = zcu.gpa;
1362
1363 // The resolved path is used as the key in the import table, to detect if
1364 // an import refers to the same as another, despite different relative paths
1365 // or differently mapped package names.
1366 const resolved_path = try std.fs.path.resolve(gpa, &.{
1367 mod.root.root_dir.path orelse ".",
1368 mod.root.sub_path,
1369 mod.root_src_path,
1370 });
1371 var keep_resolved_path = false;
1372 defer if (!keep_resolved_path) gpa.free(resolved_path);
1373
1374 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
1375 errdefer _ = zcu.import_table.pop();
1376 if (gop.found_existing) {
1377 const file_index = gop.value_ptr.*;
1378 const file = zcu.fileByIndex(file_index);
1379 try file.addReference(zcu, .{ .root = mod });
1380 return .{
1381 .file = file,
1382 .file_index = file_index,
1383 .is_new = false,
1384 .is_pkg = true,
1385 };
1386 }
1387
1388 const ip = &zcu.intern_pool;
1389 try ip.files.ensureUnusedCapacity(gpa, 1);
1390
1391 if (mod.builtin_file) |builtin_file| {
1392 const file_index = try ip.createFile(gpa, pt.tid, builtin_file);
1393 keep_resolved_path = true; // It's now owned by import_table.
1394 gop.value_ptr.* = file_index;
1395 try builtin_file.addReference(zcu, .{ .root = mod });
1396 const path_digest = Zcu.computePathDigest(zcu, mod, builtin_file.sub_file_path);
1397 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1398 return .{
1399 .file = builtin_file,
1400 .file_index = file_index,
1401 .is_new = false,
1402 .is_pkg = true,
1403 };
1404 }
1405
1406 const sub_file_path = try gpa.dupe(u8, mod.root_src_path);
1407 errdefer gpa.free(sub_file_path);
1408
1409 const new_file = try gpa.create(Zcu.File);
1410 errdefer gpa.destroy(new_file);
1411
1412 const new_file_index = try ip.createFile(gpa, pt.tid, new_file);
1413 keep_resolved_path = true; // It's now owned by import_table.
1414 gop.value_ptr.* = new_file_index;
1415 new_file.* = .{
1416 .sub_file_path = sub_file_path,
1417 .source = undefined,
1418 .source_loaded = false,
1419 .tree_loaded = false,
1420 .zir_loaded = false,
1421 .stat = undefined,
1422 .tree = undefined,
1423 .zir = undefined,
1424 .status = .never_loaded,
1425 .mod = mod,
1426 };
1427
1428 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1429
1430 try new_file.addReference(zcu, .{ .root = mod });
1431 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1432 return .{
1433 .file = new_file,
1434 .file_index = new_file_index,
1435 .is_new = true,
1436 .is_pkg = true,
1437 };
1438}
1439
1440/// Called from a worker thread during AstGen.
1441/// Also called from Sema during semantic analysis.
1442pub fn importFile(
1443 pt: Zcu.PerThread,
1444 cur_file: *Zcu.File,
1445 import_string: []const u8,
1446) !Zcu.ImportFileResult {
1447 const zcu = pt.zcu;
1448 const mod = cur_file.mod;
1449
1450 if (std.mem.eql(u8, import_string, "std")) {
1451 return pt.importPkg(zcu.std_mod);
1452 }
1453 if (std.mem.eql(u8, import_string, "root")) {
1454 return pt.importPkg(zcu.root_mod);
1455 }
1456 if (mod.deps.get(import_string)) |pkg| {
1457 return pt.importPkg(pkg);
1458 }
1459 if (!std.mem.endsWith(u8, import_string, ".zig")) {
1460 return error.ModuleNotFound;
1461 }
1462 const gpa = zcu.gpa;
1463
1464 // The resolved path is used as the key in the import table, to detect if
1465 // an import refers to the same as another, despite different relative paths
1466 // or differently mapped package names.
1467 const resolved_path = try std.fs.path.resolve(gpa, &.{
1468 mod.root.root_dir.path orelse ".",
1469 mod.root.sub_path,
1470 cur_file.sub_file_path,
1471 "..",
1472 import_string,
1473 });
1474
1475 var keep_resolved_path = false;
1476 defer if (!keep_resolved_path) gpa.free(resolved_path);
1477
1478 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
1479 errdefer _ = zcu.import_table.pop();
1480 if (gop.found_existing) {
1481 const file_index = gop.value_ptr.*;
1482 return .{
1483 .file = zcu.fileByIndex(file_index),
1484 .file_index = file_index,
1485 .is_new = false,
1486 .is_pkg = false,
1487 };
1488 }
1489
1490 const ip = &zcu.intern_pool;
1491
1492 try ip.files.ensureUnusedCapacity(gpa, 1);
1493
1494 const new_file = try gpa.create(Zcu.File);
1495 errdefer gpa.destroy(new_file);
1496
1497 const resolved_root_path = try std.fs.path.resolve(gpa, &.{
1498 mod.root.root_dir.path orelse ".",
1499 mod.root.sub_path,
1500 });
1501 defer gpa.free(resolved_root_path);
1502
1503 const sub_file_path = p: {
1504 const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);
1505 errdefer gpa.free(relative);
1506
1507 if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
1508 break :p relative;
1509 }
1510 return error.ImportOutsideModulePath;
1511 };
1512 errdefer gpa.free(sub_file_path);
1513
1514 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
1515 resolved_root_path, resolved_path, sub_file_path, import_string,
1516 });
1517
1518 const new_file_index = try ip.createFile(gpa, pt.tid, new_file);
1519 keep_resolved_path = true; // It's now owned by import_table.
1520 gop.value_ptr.* = new_file_index;
1521 new_file.* = .{
1522 .sub_file_path = sub_file_path,
1523 .source = undefined,
1524 .source_loaded = false,
1525 .tree_loaded = false,
1526 .zir_loaded = false,
1527 .stat = undefined,
1528 .tree = undefined,
1529 .zir = undefined,
1530 .status = .never_loaded,
1531 .mod = mod,
1532 };
1533
1534 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1535 ip.files.putAssumeCapacityNoClobber(path_digest, .none);
1536 return .{
1537 .file = new_file,
1538 .file_index = new_file_index,
1539 .is_new = true,
1540 .is_pkg = false,
1541 };
1542}
1543
13591544pub fn embedFile(
13601545 pt: Zcu.PerThread,
13611546 cur_file: *Zcu.File,
......@@ -1429,20 +1614,6 @@ pub fn embedFile(
14291614 return pt.newEmbedFile(cur_file.mod, sub_file_path, resolved_path, gop.value_ptr, src_loc);
14301615}
14311616
1432/// Cancel the creation of an anon decl and delete any references to it.
1433/// If other decls depend on this decl, they must be aborted first.
1434pub fn abortAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) void {
1435 assert(!pt.zcu.declIsRoot(decl_index));
1436 pt.destroyDecl(decl_index);
1437}
1438
1439/// Finalize the creation of an anon decl.
1440pub fn finalizeAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Allocator.Error!void {
1441 if (pt.zcu.declPtr(decl_index).typeOf(pt.zcu).isFnOrHasRuntimeBits(pt)) {
1442 try pt.zcu.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
1443 }
1444}
1445
14461617/// https://github.com/ziglang/zig/issues/14307
14471618fn newEmbedFile(
14481619 pt: Zcu.PerThread,
......@@ -1792,6 +1963,20 @@ const ScanDeclIter = struct {
17921963 }
17931964};
17941965
1966/// Cancel the creation of an anon decl and delete any references to it.
1967/// If other decls depend on this decl, they must be aborted first.
1968pub fn abortAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) void {
1969 assert(!pt.zcu.declIsRoot(decl_index));
1970 pt.destroyDecl(decl_index);
1971}
1972
1973/// Finalize the creation of an anon decl.
1974pub fn finalizeAnonDecl(pt: Zcu.PerThread, decl_index: Zcu.Decl.Index) Allocator.Error!void {
1975 if (pt.zcu.declPtr(decl_index).typeOf(pt.zcu).isFnOrHasRuntimeBits(pt)) {
1976 try pt.zcu.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
1977 }
1978}
1979
17951980pub fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index, arena: Allocator) Zcu.SemaError!Air {
17961981 const tracy = trace(@src());
17971982 defer tracy.end();
......@@ -2255,7 +2440,7 @@ pub fn populateTestFunctions(
22552440 const gpa = zcu.gpa;
22562441 const ip = &zcu.intern_pool;
22572442 const builtin_mod = zcu.root_mod.getBuiltinDependency();
2258 const builtin_file_index = (zcu.importPkg(builtin_mod) catch unreachable).file_index;
2443 const builtin_file_index = (pt.importPkg(builtin_mod) catch unreachable).file_index;
22592444 const root_decl_index = zcu.fileRootDecl(builtin_file_index);
22602445 const root_decl = zcu.declPtr(root_decl_index.unwrap().?);
22612446 const builtin_namespace = zcu.namespacePtr(root_decl.src_namespace);
......@@ -2923,7 +3108,7 @@ pub fn getBuiltinDecl(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Inter
29233108 const zcu = pt.zcu;
29243109 const gpa = zcu.gpa;
29253110 const ip = &zcu.intern_pool;
2926 const std_file_imported = zcu.importPkg(zcu.std_mod) catch @panic("failed to import lib/std.zig");
3111 const std_file_imported = pt.importPkg(zcu.std_mod) catch @panic("failed to import lib/std.zig");
29273112 const std_file_root_decl = zcu.fileRootDecl(std_file_imported.file_index).unwrap().?;
29283113 const std_namespace = zcu.declPtr(std_file_root_decl).getOwnedInnerNamespace(zcu).?;
29293114 const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
src/codegen/llvm.zig+1-1
......@@ -2811,7 +2811,7 @@ pub const Object = struct {
28112811 const zcu = pt.zcu;
28122812
28132813 const std_mod = zcu.std_mod;
2814 const std_file_imported = zcu.importPkg(std_mod) catch unreachable;
2814 const std_file_imported = pt.importPkg(std_mod) catch unreachable;
28152815
28162816 const builtin_str = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, "builtin", .no_embedded_nulls);
28172817 const std_file_root_decl = zcu.fileRootDecl(std_file_imported.file_index);