| author | |
| committer | |
| log | ac14b52e85f857f7f70846d22ea18ea265acb91a |
| tree | bceefa15a211ba323fe7645dd69ab6b768f59555 |
| parent | e85cd616ef6439fdb9e7ac118251bb7c2296e553 |
This adds a simplified start2.zig that the current stage2 compiler is
able to generate code for.6 files changed, 136 insertions(+), 34 deletions(-)
lib/std/start2.zig created+58| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | const root = @import("root"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | ||
| 4 | comptime { | |
| 5 | if (builtin.output_mode == 0) { // OutputMode.Exe | |
| 6 | if (builtin.link_libc or builtin.object_format == 5) { // ObjectFormat.c | |
| 7 | if (!@hasDecl(root, "main")) { | |
| 8 | @export(otherMain, "main"); | |
| 9 | } | |
| 10 | } else { | |
| 11 | if (!@hasDecl(root, "_start")) { | |
| 12 | @export(otherStart, "_start"); | |
| 13 | } | |
| 14 | } | |
| 15 | } | |
| 16 | } | |
| 17 | ||
| 18 | // FIXME: Cannot call this function `main`, because `fully qualified names` | |
| 19 | // have not been implemented yet. | |
| 20 | fn otherMain() callconv(.C) c_int { | |
| 21 | root.zigMain(); | |
| 22 | return 0; | |
| 23 | } | |
| 24 | ||
| 25 | // FIXME: Cannot call this function `_start`, because `fully qualified names` | |
| 26 | // have not been implemented yet. | |
| 27 | fn otherStart() callconv(.Naked) noreturn { | |
| 28 | root.zigMain(); | |
| 29 | otherExit(); | |
| 30 | } | |
| 31 | ||
| 32 | // FIXME: Cannot call this function `exit`, because `fully qualified names` | |
| 33 | // have not been implemented yet. | |
| 34 | fn otherExit() noreturn { | |
| 35 | if (builtin.arch == 31) { // x86_64 | |
| 36 | asm volatile ("syscall" | |
| 37 | : | |
| 38 | : [number] "{rax}" (231), | |
| 39 | [arg1] "{rdi}" (0) | |
| 40 | : "rcx", "r11", "memory" | |
| 41 | ); | |
| 42 | } else if (builtin.arch == 0) { // arm | |
| 43 | asm volatile ("svc #0" | |
| 44 | : | |
| 45 | : [number] "{r7}" (1), | |
| 46 | [arg1] "{r0}" (0) | |
| 47 | : "memory" | |
| 48 | ); | |
| 49 | } else if (builtin.arch == 2) { // aarch64 | |
| 50 | asm volatile ("svc #0" | |
| 51 | : | |
| 52 | : [number] "{x8}" (93), | |
| 53 | [arg1] "{x0}" (0) | |
| 54 | : "memory", "cc" | |
| 55 | ); | |
| 56 | } else @compileError("not yet supported!"); | |
| 57 | unreachable; | |
| 58 | } |
src/Compilation.zig+40-30| ... | ... | @@ -908,41 +908,45 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 908 | 908 | }; |
| 909 | 909 | |
| 910 | 910 | const builtin_pkg = try Package.create(gpa, zig_cache_artifact_directory.path.?, "builtin2.zig"); |
| 911 | ||
| 912 | const std_dir_path = try options.zig_lib_directory.join(gpa, &[_][]const u8{"std"}); | |
| 913 | defer gpa.free(std_dir_path); | |
| 914 | const start_pkg = try Package.create(gpa, std_dir_path, "start2.zig"); | |
| 915 | ||
| 911 | 916 | try root_pkg.add(gpa, "builtin", builtin_pkg); |
| 912 | 917 | try root_pkg.add(gpa, "root", root_pkg); |
| 913 | 918 | |
| 919 | try start_pkg.add(gpa, "builtin", builtin_pkg); | |
| 920 | try start_pkg.add(gpa, "root", root_pkg); | |
| 921 | ||
| 914 | 922 | // TODO when we implement serialization and deserialization of incremental compilation metadata, |
| 915 | 923 | // this is where we would load it. We have open a handle to the directory where |
| 916 | 924 | // the output either already is, or will be. |
| 917 | 925 | // However we currently do not have serialization of such metadata, so for now |
| 918 | 926 | // we set up an empty Module that does the entire compilation fresh. |
| 919 | 927 | |
| 920 | const root_scope = rs: { | |
| 921 | if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) { | |
| 922 | const root_scope = try gpa.create(Module.Scope.File); | |
| 923 | const struct_ty = try Type.Tag.empty_struct.create( | |
| 924 | gpa, | |
| 925 | &root_scope.root_container, | |
| 926 | ); | |
| 927 | root_scope.* = .{ | |
| 928 | // TODO this is duped so it can be freed in Container.deinit | |
| 929 | .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path), | |
| 930 | .source = .{ .unloaded = {} }, | |
| 931 | .tree = undefined, | |
| 932 | .status = .never_loaded, | |
| 933 | .pkg = root_pkg, | |
| 934 | .root_container = .{ | |
| 935 | .file_scope = root_scope, | |
| 936 | .decls = .{}, | |
| 937 | .ty = struct_ty, | |
| 938 | }, | |
| 939 | }; | |
| 940 | break :rs root_scope; | |
| 941 | } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) { | |
| 942 | return error.ZirFilesUnsupported; | |
| 943 | } else { | |
| 944 | unreachable; | |
| 945 | } | |
| 928 | if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported; | |
| 929 | ||
| 930 | const start_scope = ss: { | |
| 931 | const start_scope = try gpa.create(Module.Scope.File); | |
| 932 | const struct_ty = try Type.Tag.empty_struct.create( | |
| 933 | gpa, | |
| 934 | &start_scope.root_container, | |
| 935 | ); | |
| 936 | start_scope.* = .{ | |
| 937 | // TODO this is duped so it can be freed in Container.deinit | |
| 938 | .sub_file_path = try gpa.dupe(u8, start_pkg.root_src_path), | |
| 939 | .source = .{ .unloaded = {} }, | |
| 940 | .tree = undefined, | |
| 941 | .status = .never_loaded, | |
| 942 | .pkg = start_pkg, | |
| 943 | .root_container = .{ | |
| 944 | .file_scope = start_scope, | |
| 945 | .decls = .{}, | |
| 946 | .ty = struct_ty, | |
| 947 | }, | |
| 948 | }; | |
| 949 | break :ss start_scope; | |
| 946 | 950 | }; |
| 947 | 951 | |
| 948 | 952 | const module = try arena.create(Module); |
| ... | ... | @@ -951,7 +955,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 951 | 955 | .gpa = gpa, |
| 952 | 956 | .comp = comp, |
| 953 | 957 | .root_pkg = root_pkg, |
| 954 | .root_scope = root_scope, | |
| 958 | .root_scope = null, | |
| 959 | .start_pkg = start_pkg, | |
| 960 | .start_scope = start_scope, | |
| 955 | 961 | .zig_cache_artifact_directory = zig_cache_artifact_directory, |
| 956 | 962 | .emit_h = options.emit_h, |
| 957 | 963 | .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), |
| ... | ... | @@ -1353,9 +1359,9 @@ pub fn update(self: *Compilation) !void { |
| 1353 | 1359 | // TODO Detect which source files changed. |
| 1354 | 1360 | // Until then we simulate a full cache miss. Source files could have been loaded |
| 1355 | 1361 | // for any reason; to force a refresh we unload now. |
| 1356 | module.unloadFile(module.root_scope); | |
| 1362 | module.unloadFile(module.start_scope); | |
| 1357 | 1363 | module.failed_root_src_file = null; |
| 1358 | module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) { | |
| 1364 | module.analyzeContainer(&module.start_scope.root_container) catch |err| switch (err) { | |
| 1359 | 1365 | error.AnalysisFail => { |
| 1360 | 1366 | assert(self.totalErrorCount() != 0); |
| 1361 | 1367 | }, |
| ... | ... | @@ -1416,7 +1422,7 @@ pub fn update(self: *Compilation) !void { |
| 1416 | 1422 | // to report error messages. Otherwise we unload all source files to save memory. |
| 1417 | 1423 | if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { |
| 1418 | 1424 | if (self.bin_file.options.module) |module| { |
| 1419 | module.root_scope.unload(self.gpa); | |
| 1425 | module.start_scope.unload(self.gpa); | |
| 1420 | 1426 | } |
| 1421 | 1427 | } |
| 1422 | 1428 | } |
| ... | ... | @@ -2851,11 +2857,15 @@ fn generateBuiltin2ZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 { |
| 2851 | 2857 | \\pub const link_libc = {}; |
| 2852 | 2858 | \\pub const arch = {}; |
| 2853 | 2859 | \\pub const os = {}; |
| 2860 | \\pub const output_mode = {}; | |
| 2861 | \\pub const object_format = {}; | |
| 2854 | 2862 | \\ |
| 2855 | 2863 | , .{ |
| 2856 | 2864 | comp.bin_file.options.link_libc, |
| 2857 | 2865 | @enumToInt(target.cpu.arch), |
| 2858 | 2866 | @enumToInt(target.os.tag), |
| 2867 | @enumToInt(comp.bin_file.options.output_mode), | |
| 2868 | @enumToInt(comp.bin_file.options.object_format), | |
| 2859 | 2869 | }); |
| 2860 | 2870 | |
| 2861 | 2871 | return buffer.toOwnedSlice(); |
src/Module.zig+7-2| ... | ... | @@ -35,8 +35,11 @@ comp: *Compilation, |
| 35 | 35 | zig_cache_artifact_directory: Compilation.Directory, |
| 36 | 36 | /// Pointer to externally managed resource. `null` if there is no zig file being compiled. |
| 37 | 37 | root_pkg: *Package, |
| 38 | /// This is populated when `@import("root")` is analysed. | |
| 39 | root_scope: ?*Scope.File, | |
| 40 | start_pkg: *Package, | |
| 38 | 41 | /// Module owns this resource. |
| 39 | root_scope: *Scope.File, | |
| 42 | start_scope: *Scope.File, | |
| 40 | 43 | /// It's rare for a decl to be exported, so we save memory by having a sparse map of |
| 41 | 44 | /// Decl pointers to details about them being exported. |
| 42 | 45 | /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. |
| ... | ... | @@ -2341,7 +2344,9 @@ pub fn deinit(mod: *Module) void { |
| 2341 | 2344 | mod.export_owners.deinit(gpa); |
| 2342 | 2345 | |
| 2343 | 2346 | mod.symbol_exports.deinit(gpa); |
| 2344 | mod.root_scope.destroy(gpa); | |
| 2347 | ||
| 2348 | mod.start_scope.destroy(gpa); | |
| 2349 | mod.start_pkg.destroy(gpa); | |
| 2345 | 2350 | |
| 2346 | 2351 | var it = mod.global_error_set.iterator(); |
| 2347 | 2352 | while (it.next()) |entry| { |
src/Package.zig+25| ... | ... | @@ -15,6 +15,9 @@ root_src_path: []const u8, |
| 15 | 15 | table: Table = .{}, |
| 16 | 16 | parent: ?*Package = null, |
| 17 | 17 | |
| 18 | // Used when freeing packages | |
| 19 | seen: bool = false, | |
| 20 | ||
| 18 | 21 | /// Allocate a Package. No references to the slices passed are kept. |
| 19 | 22 | pub fn create( |
| 20 | 23 | gpa: *Allocator, |
| ... | ... | @@ -55,6 +58,14 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void { |
| 55 | 58 | pkg.root_src_directory.handle.close(); |
| 56 | 59 | } |
| 57 | 60 | |
| 61 | // First we recurse into all the packages and remove packages from the tables | |
| 62 | // once we have seen it before. We do this to make sure that that | |
| 63 | // a package can only be found once in the whole tree. | |
| 64 | if (!pkg.seen) { | |
| 65 | pkg.seen = true; | |
| 66 | pkg.markSeen(gpa); | |
| 67 | } | |
| 68 | ||
| 58 | 69 | { |
| 59 | 70 | var it = pkg.table.iterator(); |
| 60 | 71 | while (it.next()) |kv| { |
| ... | ... | @@ -69,6 +80,20 @@ pub fn destroy(pkg: *Package, gpa: *Allocator) void { |
| 69 | 80 | gpa.destroy(pkg); |
| 70 | 81 | } |
| 71 | 82 | |
| 83 | fn markSeen(pkg: *Package, gpa: *Allocator) void { | |
| 84 | var it = pkg.table.iterator(); | |
| 85 | while (it.next()) |kv| { | |
| 86 | if (pkg != kv.value) { | |
| 87 | if (kv.value.seen) { | |
| 88 | pkg.table.removeAssertDiscard(kv.key); | |
| 89 | } else { | |
| 90 | kv.value.seen = true; | |
| 91 | kv.value.markSeen(gpa); | |
| 92 | } | |
| 93 | } | |
| 94 | } | |
| 95 | } | |
| 96 | ||
| 72 | 97 | pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) !void { |
| 73 | 98 | try pkg.table.ensureCapacity(gpa, pkg.table.count() + 1); |
| 74 | 99 | const name_dupe = try mem.dupe(gpa, u8, name); |
src/Sema.zig+4-1| ... | ... | @@ -4699,7 +4699,7 @@ fn namedFieldPtr( |
| 4699 | 4699 | } |
| 4700 | 4700 | |
| 4701 | 4701 | // TODO this will give false positives for structs inside the root file |
| 4702 | if (container_scope.file_scope == mod.root_scope) { | |
| 4702 | if (container_scope.file_scope == mod.root_scope.?) { | |
| 4703 | 4703 | return mod.fail( |
| 4704 | 4704 | &block.base, |
| 4705 | 4705 | src, |
| ... | ... | @@ -5338,6 +5338,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin |
| 5338 | 5338 | .ty = struct_ty, |
| 5339 | 5339 | }, |
| 5340 | 5340 | }; |
| 5341 | if (mem.eql(u8, target_string, "root")) { | |
| 5342 | sema.mod.root_scope = file_scope; | |
| 5343 | } | |
| 5341 | 5344 | sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) { |
| 5342 | 5345 | error.AnalysisFail => { |
| 5343 | 5346 | assert(sema.mod.comp.totalErrorCount() != 0); |
src/main.zig+2-1| ... | ... | @@ -1732,6 +1732,8 @@ fn buildOutputType( |
| 1732 | 1732 | }, |
| 1733 | 1733 | } |
| 1734 | 1734 | |
| 1735 | // This gets cleaned up, because root_pkg becomes part of the | |
| 1736 | // package table of the start_pkg. | |
| 1735 | 1737 | const root_pkg: ?*Package = if (root_src_file) |src_path| blk: { |
| 1736 | 1738 | if (main_pkg_path) |p| { |
| 1737 | 1739 | const rel_src_path = try fs.path.relative(gpa, p, src_path); |
| ... | ... | @@ -1741,7 +1743,6 @@ fn buildOutputType( |
| 1741 | 1743 | break :blk try Package.create(gpa, fs.path.dirname(src_path), fs.path.basename(src_path)); |
| 1742 | 1744 | } |
| 1743 | 1745 | } else null; |
| 1744 | defer if (root_pkg) |p| p.destroy(gpa); | |
| 1745 | 1746 | |
| 1746 | 1747 | // Transfer packages added with --pkg-begin/--pkg-end to the root package |
| 1747 | 1748 | if (root_pkg) |pkg| { |