Commit 5ff45b3f44

Andrew Kelley <andrew@ziglang.org>
2021-04-17 02:28:28
stage2: use import list from ZIR to queue up more AstGen tasks
1 parent a271f12
src/Compilation.zig
@@ -30,6 +30,7 @@ const c_codegen = @import("codegen/c.zig");
 const ThreadPool = @import("ThreadPool.zig");
 const WaitGroup = @import("WaitGroup.zig");
 const libtsan = @import("libtsan.zig");
+const Zir = @import("Zir.zig");
 
 /// General-purpose allocator. Used for both temporary and long-term storage.
 gpa: *Allocator,
@@ -431,7 +432,6 @@ pub const AllErrors = struct {
     ) !void {
         assert(file.zir_loaded);
         assert(file.tree_loaded);
-        const Zir = @import("Zir.zig");
         const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
         assert(payload_index != 0);
 
@@ -2120,6 +2120,35 @@ fn workerAstGenFile(
             };
         },
     };
+
+    // Pre-emptively look for `@import` paths and queue them up.
+    // If we experience an error preemptively fetching the
+    // file, just ignore it and let it happen again later during Sema.
+    assert(file.zir_loaded);
+    const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
+    if (imports_index != 0) {
+        const imports_len = file.zir.extra[imports_index];
+
+        for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
+            const import_path = file.zir.nullTerminatedString(str_index);
+
+            const import_result = blk: {
+                const lock = comp.mutex.acquire();
+                defer lock.release();
+
+                break :blk mod.importFile(file.pkg, import_path) catch continue;
+            };
+            if (import_result.is_new) {
+                wg.start();
+                comp.thread_pool.spawn(workerAstGenFile, .{
+                    comp, import_result.file, prog_node, wg,
+                }) catch {
+                    wg.finish();
+                    continue;
+                };
+            }
+        }
+    }
 }
 
 pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
src/Module.zig
@@ -2628,7 +2628,16 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !vo
     depender.dependencies.putAssumeCapacity(dependee, {});
 }
 
-pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File {
+pub const ImportFileResult = struct {
+    file: *Scope.File,
+    is_new: bool,
+};
+
+pub fn importFile(
+    mod: *Module,
+    cur_pkg: *Package,
+    import_string: []const u8,
+) !ImportFileResult {
     const gpa = mod.gpa;
 
     const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
@@ -2642,7 +2651,10 @@ pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*
     defer if (!keep_resolved_path) gpa.free(resolved_path);
 
     const gop = try mod.import_table.getOrPut(gpa, resolved_path);
-    if (gop.found_existing) return gop.entry.value;
+    if (gop.found_existing) return ImportFileResult{
+        .file = gop.entry.value,
+        .is_new = false,
+    };
 
     if (found_pkg == null) {
         const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
@@ -2671,7 +2683,10 @@ pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*
         .namespace = undefined,
     };
     keep_resolved_path = true;
-    return new_file;
+    return ImportFileResult{
+        .file = new_file,
+        .is_new = true,
+    };
 }
 
 pub fn analyzeNamespace(
src/Sema.zig
@@ -3904,7 +3904,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
     const src = inst_data.src();
     const operand = inst_data.get(sema.code);
 
-    const file = mod.importFile(block.getFileScope().pkg, operand) catch |err| switch (err) {
+    const result = mod.importFile(block.getFileScope().pkg, operand) catch |err| switch (err) {
         error.ImportOutsidePkgPath => {
             return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
         },
@@ -3914,7 +3914,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
             return mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
         },
     };
-    return mod.constType(sema.arena, src, file.namespace.ty);
+    return mod.constType(sema.arena, src, result.file.namespace.ty);
 }
 
 fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
BRANCH_TODO
@@ -1,6 +1,5 @@
  * look for cached zir code
  * save zir code to cache
- * use list of imported strings to queue up more astgen tasks
  * keep track of file dependencies/dependants
  * unload files from memory when a dependency is dropped
  * implement zir error notes