authorchloe caruso <git@paperclover.net> 2024-05-20 13:45:39-07:00
committerchloe caruso <git@paperclover.net> 2024-05-20 13:46:36-07:00
logf102fe93319b8fcc9b88bdef0fa69bda967d15a7
treeb7ed26e4570086a94fb865e70f76176583a46e54
parentcf749893b592c342cd21fe524c7c45456876cae3

perf: use more buffered writers


9 files changed, 175 insertions(+), 29 deletions(-)

CHANGELOG.md+1-1
......@@ -1,6 +1,6 @@
11## 0.1.1-alpha
22
3- introduce `Report` and show errors during Transform.
3- introduce `Report` and show errors during Tokenize, Parse, and Transform.
44- add flag --dump-ir for enabling ir dumps
55
66## 0.1.0-alpha
build.zig+12
......@@ -6,12 +6,23 @@ pub fn build(b: *std.Build) void {
66 const target = b.standardTargetOptions(.{});
77 const optimize = b.standardOptimizeOption(.{});
88
9 const tracing = b.option(enum {
10 none,
11 spall,
12 chrome,
13 log,
14 }, "trace", "Enable tracing") orelse .none;
15
916 const dep_opts = .{ .target = target, .optimize = optimize };
1017
1118 const zg = b.dependency("zg", dep_opts);
1219 const tracer = b.dependency("tracer", dep_opts);
1320 // const ada = b.dependency("ada", dep_opts);
1421
22 const opts = b.addOptions();
23 opts.addOption([]const u8, "tracing", @tagName(tracing));
24 const opts_mod = opts.createModule();
25
1526 const exe = b.addExecutable(.{
1627 .name = "compiler",
1728 .root_source_file = b.path("src/compiler/main.zig"),
......@@ -20,6 +31,7 @@ pub fn build(b: *std.Build) void {
2031 });
2132 b.installArtifact(exe);
2233
34 exe.root_module.addImport("build_options", opts_mod);
2335 exe.root_module.addImport("zg:PropsData", zg.module("PropsData"));
2436 exe.root_module.addImport("tracer", tracer.module("tracer"));
2537 // if (!target.result.isWasm()) {
demo.txt+25-1
......@@ -1 +1,25 @@
1no "waay
1let print = @js("console").log;
2
3fn doThing(x: float, y: float) -> float {
4 let math = if x < y {
5 x - y
6 } else b: {
7 let sum = x + y;
8 if sum > 100 {
9 break :b sum;
10 }
11 if x == y {
12 return 5;
13 }
14 sum * -sum
15 };
16 if x == y {
17 return 5;
18 }
19 let divisor = if x > 10 { 2 } else { 3 };
20 math / divisor
21}
22
23print(doThing(1, 6));
24print(doThing(6, 4));
25print(doThing(100, 52));
src/compiler/JsLink.zig+37
......@@ -19,6 +19,8 @@ pub fn linkJsCode(
1919 decls: []const Decl.Index,
2020 writer: anytype,
2121) !void {
22 var t = tracer.trace(@src());
23 defer t.end();
2224
2325 // Arena allocator is used for the main flow
2426 var link: JsLink = .{ .comp = comp };
......@@ -79,6 +81,9 @@ pub fn linkJsCode(
7981}
8082
8183fn deinit(link: *JsLink) void {
84 var t = tracer.trace(@src());
85 defer t.end();
86
8287 defer link.* = undefined;
8388 link.decls.deinit(link.comp.gpa);
8489 link.link_strings.deinit(link.comp.gpa);
......@@ -86,6 +91,9 @@ fn deinit(link: *JsLink) void {
8691}
8792
8893fn reserveExternSymbol(link: *JsLink, extern_symbol: String.WithLen) !void {
94 var t = tracer.trace(@src());
95 defer t.end();
96
8997 const name = extern_symbol.toSlice(&link.comp.intern_pool);
9098 const gop = try link.link_strings.getOrPutContextAdapted(
9199 link.comp.gpa,
......@@ -104,12 +112,18 @@ fn reserveExternSymbol(link: *JsLink, extern_symbol: String.WithLen) !void {
104112}
105113
106114fn appendLinkString(link: *JsLink, string: []const u8) !LinkString {
115 var t = tracer.trace(@src());
116 defer t.end();
117
107118 const start = link.string_bytes.items.len;
108119 try link.string_bytes.appendSlice(link.comp.gpa, string);
109120 return .{ .start = @intCast(start), .len = @intCast(string.len) };
110121}
111122
112123fn declIdentifier(link: *const JsLink, decl: Decl.Index) []const u8 {
124 var t = tracer.trace(@src());
125 defer t.end();
126
113127 return (link.decls.get(decl) orelse if (std.debug.runtime_safety) {
114128 std.debug.panic("Decl {d} ({}) is not present in link decl map", .{
115129 @intFromEnum(decl),
......@@ -119,6 +133,9 @@ fn declIdentifier(link: *const JsLink, decl: Decl.Index) []const u8 {
119133}
120134
121135fn printDecl(link: *JsLink, decl_index: Decl.Index, writer: anytype) !void {
136 var t = tracer.trace(@src());
137 defer t.end();
138
122139 try writer.writeAll("let ");
123140 try writer.writeAll(link.declIdentifier(decl_index));
124141 try writer.writeAll(" = ");
......@@ -137,6 +154,9 @@ fn printDecl(link: *JsLink, decl_index: Decl.Index, writer: anytype) !void {
137154}
138155
139156fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void {
157 var t = tracer.trace(@src());
158 defer t.end();
159
140160 for (tree.mainStatements()) |stmt| {
141161 try link.printExpr(tree, stmt, writer);
142162 try writer.writeAll(";\n");
......@@ -144,6 +164,9 @@ fn printDeclContents(link: *JsLink, tree: *const JsTree, writer: anytype) !void
144164}
145165
146166fn printBlockContents(link: *JsLink, tree: *const JsTree, list: JsTree.IndexList, writer: anytype) !void {
167 var t = tracer.trace(@src());
168 defer t.end();
169
147170 assert(list.slice(tree).len > 0);
148171 for (list.slice(tree)) |stmt| {
149172 try link.printExpr(tree, stmt, writer);
......@@ -158,6 +181,9 @@ fn printBlockContents(link: *JsLink, tree: *const JsTree, list: JsTree.IndexList
158181}
159182
160183fn printBlock(link: *JsLink, tree: *const JsTree, list: JsTree.IndexList, writer: anytype) !void {
184 var t = tracer.trace(@src());
185 defer t.end();
186
161187 if (list.len != 1) {
162188 try writer.writeAll("{");
163189 try link.printBlockContents(tree, list, writer);
......@@ -168,6 +194,9 @@ fn printBlock(link: *JsLink, tree: *const JsTree, list: JsTree.IndexList, writer
168194}
169195
170196fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anytype) @TypeOf(writer).Error!void {
197 var t = tracer.trace(@src());
198 defer t.end();
199
171200 switch (tree.nodeTag(node)) {
172201 else => |tag| std.debug.panic("TODO: printExpr .{s}", .{@tagName(tag)}),
173202 .root => unreachable,
......@@ -328,11 +357,17 @@ fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anyty
328357}
329358
330359fn printLocal(link: *JsLink, local: JsTree.LocalIndex, writer: anytype) !void {
360 var t = tracer.trace(@src());
361 defer t.end();
362
331363 _ = link; // todo: be smarter about this
332364 try writer.print("v{d}", .{local});
333365}
334366
335367fn printLabelIdentifier(link: *JsLink, local: JsTree.LocalIndex, writer: anytype) !void {
368 var t = tracer.trace(@src());
369 defer t.end();
370
336371 _ = link; // todo: be smarter about this
337372 try writer.print("label{d}", .{local});
338373}
......@@ -452,3 +487,5 @@ const Node = JsTree.Node;
452487
453488const InternPool = @import("InternPool.zig");
454489const String = InternPool.String;
490
491const tracer = @import("tracer");
src/compiler/JsNodeGen.zig+46
......@@ -29,6 +29,9 @@ const MapEntry = union {
2929};
3030
3131pub fn init(gpa: Allocator, arena: Allocator, ip: *const InternPool, air: *const Air) !JsNodeGen {
32 const t = tracer.trace(@src());
33 defer t.end();
34
3235 const air_node_map = try arena.alloc(MapEntry, air.insts.len);
3336 if (std.debug.runtime_safety) {
3437 @memset(air_node_map, .{ .none = {} });
......@@ -52,6 +55,9 @@ pub fn init(gpa: Allocator, arena: Allocator, ip: *const InternPool, air: *const
5255}
5356
5457pub fn deinit(c: *JsNodeGen) void {
58 const t = tracer.trace(@src());
59 defer t.end();
60
5561 defer c.* = undefined;
5662 c.nodes.deinit(c.gpa);
5763 c.extra.deinit(c.gpa);
......@@ -62,6 +68,9 @@ pub fn deinit(c: *JsNodeGen) void {
6268}
6369
6470pub fn finalize(c: *JsNodeGen) !JsTree {
71 const t = tracer.trace(@src());
72 defer t.end();
73
6574 // todo: errdefer will probably leave memory in a fully invalid state
6675 try c.nodes.setCapacity(c.gpa, c.nodes.len);
6776
......@@ -87,6 +96,9 @@ pub fn finalize(c: *JsNodeGen) !JsTree {
8796}
8897
8998pub fn build(c: *JsNodeGen) !void {
99 const t = tracer.trace(@src());
100 defer t.end();
101
90102 assert(c.air.instTag(.main_block) == .block);
91103 const statements = c.air.instData(.block, .main_block).slice(c.air);
92104
......@@ -117,6 +129,9 @@ pub fn build(c: *JsNodeGen) !void {
117129}
118130
119131fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
132 const t = tracer.traceFmt(@src(), "#{d} {s}", .{ @intFromEnum(inst), @tagName(c.air.instTag(inst)) });
133 defer t.end();
134
120135 switch (c.air.instTag(inst)) {
121136 .arg => unreachable, // codegen must skip over these instructions.
122137
......@@ -290,6 +305,9 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
290305}
291306
292307fn markExpression(c: *JsNodeGen, inst: Air.Inst.Index, node: Node.Index) !void {
308 const t = tracer.trace(@src());
309 defer t.end();
310
293311 const flags: Air.Flags = c.air.instFlags(inst);
294312 const i = @intFromEnum(inst);
295313 switch (flags.uses) {
......@@ -314,6 +332,9 @@ fn markExpression(c: *JsNodeGen, inst: Air.Inst.Index, node: Node.Index) !void {
314332}
315333
316334fn fetchExpression(c: *JsNodeGen, inst: Air.Inst.Ref) !Node.Index {
335 const t = tracer.trace(@src());
336 defer t.end();
337
317338 return switch (inst.unwrap()) {
318339 .value => |v| c.valueToExpression(v),
319340 .inst => |index| {
......@@ -332,6 +353,9 @@ fn fetchExpression(c: *JsNodeGen, inst: Air.Inst.Ref) !Node.Index {
332353}
333354
334355fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index {
356 const t = tracer.trace(@src());
357 defer t.end();
358
335359 const intern_tag = c.ip.items.items(.tag)[@intFromEnum(v.toIntern())];
336360 switch (intern_tag) {
337361 .removed => unreachable, // UAF
......@@ -352,6 +376,9 @@ fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index {
352376}
353377
354378fn addTemporary(c: *JsNodeGen) !Node.Index {
379 const t = tracer.trace(@src());
380 defer t.end();
381
355382 try c.addStmt(try c.add(.stmt_declare_local, .{
356383 .identifier_index = c.next_id,
357384 .init = .none,
......@@ -367,6 +394,9 @@ const Branch = struct {
367394};
368395
369396fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Branch {
397 const t = tracer.trace(@src());
398 defer t.end();
399
370400 const scratch_top = c.scratch.items.len;
371401 defer c.scratch.shrinkRetainingCapacity(scratch_top);
372402
......@@ -430,6 +460,9 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br
430460}
431461
432462fn codeGenBlock(c: *JsNodeGen, inst: Air.Inst.Index) !void {
463 const t = tracer.trace(@src());
464 defer t.end();
465
433466 const scratch_top = c.scratch.items.len;
434467 errdefer c.scratch.shrinkRetainingCapacity(scratch_top);
435468
......@@ -467,6 +500,9 @@ fn codeGenBlock(c: *JsNodeGen, inst: Air.Inst.Index) !void {
467500}
468501
469502fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {
503 const t = tracer.trace(@src());
504 defer t.end();
505
470506 return switch (inst.unwrap()) {
471507 .value => true,
472508 .inst => |index| switch (c.air.instTag(index)) {
......@@ -493,6 +529,9 @@ fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {
493529}
494530
495531fn lowerToExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {
532 const t = tracer.trace(@src());
533 defer t.end();
534
496535 assert(c.canLowerToExpression(ref));
497536 return switch (ref.unwrap()) {
498537 .value => |v| try c.valueToExpression(v),
......@@ -504,6 +543,9 @@ fn lowerToExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {
504543}
505544
506545fn add(c: *JsNodeGen, comptime tag: JsTree.Tag, data: tag.Data()) !Node.Index {
546 const t = tracer.trace(@src());
547 defer t.end();
548
507549 try c.nodes.append(c.gpa, .{
508550 .tag = tag,
509551 .data = EncodedData.encode(tag, data),
......@@ -512,6 +554,9 @@ fn add(c: *JsNodeGen, comptime tag: JsTree.Tag, data: tag.Data()) !Node.Index {
512554}
513555
514556fn addStmt(c: *JsNodeGen, stmt: Node.Index) !void {
557 const t = tracer.trace(@src());
558 defer t.end();
559
515560 try c.scratch.append(c.arena, @intFromEnum(stmt));
516561}
517562
......@@ -537,3 +582,4 @@ const Air = @import("Air.zig");
537582const Value = @import("Value.zig");
538583
539584const dod = @import("dod.zig");
585const tracer = @import("tracer");
src/compiler/Report.zig+16-9
......@@ -183,8 +183,7 @@ pub fn deinit(report: Report, gpa: Allocator) void {
183183 gpa.free(report.string_bytes);
184184}
185185
186pub fn dumpToWriter(report: Report, comp: *Comp, writer: anytype) !void {
187 const tty = util.detectTTYFromWriter(writer);
186pub fn dumpToWriter(report: Report, comp: *Comp, writer: anytype, tty: std.io.tty.Config) !void {
188187 try writer.print("{d} errors, {d} warnings\n", .{ report.errors.len, report.warnings.len });
189188 for (report.errors) |item| {
190189 try report.formatItem(item, .@"error", comp, writer, tty);
......@@ -348,13 +347,21 @@ pub fn formatItem(
348347}
349348
350349pub fn dumpToStdErr(report: Report, comp: *Comp) !void {
351 const stderr = std.io.getStdErr().writer();
352
353 // Disabled because of coloring issues.
354 // var buf = std.io.bufferedWriter(stderr);
355 // const writer = buf.writer();
356 try dumpToWriter(report, comp, stderr);
357 // try buf.flush();
350 const builtin = @import("builtin");
351
352 const stderr = std.io.getStdErr();
353 const tty = std.io.tty.detectConfig(stderr);
354
355 if (builtin.os.tag == .windows and tty == .windows_api) {
356 // Windows API uses it's own API calls, so a buffered writer
357 // cannot be used :/
358 try dumpToWriter(report, comp, stderr.writer(), tty);
359 } else {
360 var buf = std.io.bufferedWriter(stderr.writer());
361 const writer = buf.writer();
362 try dumpToWriter(report, comp, writer, tty);
363 try buf.flush();
364 }
358365}
359366
360367pub const Builder = struct {
src/compiler/Sema.zig+5-3
......@@ -92,9 +92,11 @@ pub fn deinit(s: *Sema) void {
9292pub fn finalize(s: *Sema) !void {
9393 const air: Air = s.tempAir();
9494
95 std.debug.print("=" ** 20, .{});
96 std.debug.print("\nAir for @ {d}\n", .{@intFromEnum(s.decl.teg_decl_index)});
97 air.dumpToWriter(s.ip, std.io.getStdErr().writer()) catch {};
95 if (s.comp.options.dump_ir) {
96 std.debug.print("=" ** 20, .{});
97 std.debug.print("\nAir for @ {d}\n", .{@intFromEnum(s.decl.teg_decl_index)});
98 air.dumpToWriter(s.ip, std.io.getStdErr().writer()) catch {};
99 }
98100
99101 try s.comp.codeGenDecl(s.decl, &air);
100102}
src/compiler/Transform.zig+4-2
......@@ -603,6 +603,8 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
603603 return .void_value;
604604 };
605605
606 lookup.mutated = true;
607
606608 return switch (lookup.data) {
607609 .declaration => try t.addInstRef(.{
608610 .tag = .load_decl,
......@@ -1235,11 +1237,11 @@ fn scratchToIndexList(t: *Transform, scratch_top: usize) !IndexList {
12351237 };
12361238}
12371239
1238fn lookupId(t: *Transform, id: []const u8) ?Scope.Symbol {
1240fn lookupId(t: *Transform, id: []const u8) ?*Scope.Symbol {
12391241 var i = t.scopes.items.len;
12401242 while (i > 0) {
12411243 i -= 1;
1242 if (t.scopes.items[i].symbols.get(id)) |sym| {
1244 if (t.scopes.items[i].symbols.getPtr(id)) |sym| {
12431245 return sym;
12441246 }
12451247 }
src/compiler/main.zig+29-13
......@@ -1,30 +1,40 @@
11const std = @import("std");
2const builtin = @import("builtin");
3
24const Tokenizer = @import("Tokenizer.zig");
35const Parse = @import("Parse.zig");
46const Transform = @import("Transform.zig");
57const Comp = @import("Comp.zig");
68const unicode_props = @import("unicode_props.zig");
7const T = @import("tracer");
8pub const tracer_impl = @field(T, "none");
9
10const tracer = @import("tracer");
11
12pub const tracer_impl = @field(tracer, @import("build_options").tracing);
913
1014pub const Report = @import("Report.zig");
1115
1216pub fn main() !void {
17 try tracer.init();
18 defer tracer.deinit();
19 try tracer.init_thread(null);
20 defer tracer.deinit_thread();
21
1322 try unicode_props.init();
1423
1524 std.debug.print("\r\x1b[K", .{});
1625
17 try T.init();
18 defer T.deinit();
19
20 try T.init_thread(null);
21 defer T.deinit_thread();
26 const use_gpa = builtin.mode == .Debug;
2227
23 var gpa: std.heap.GeneralPurposeAllocator(.{
28 var gpa: if (use_gpa) std.heap.GeneralPurposeAllocator(.{
2429 .stack_trace_frames = 100,
25 }) = .{};
26 defer _ = gpa.deinit();
27 const alloc = gpa.allocator();
30 }) else struct {} = .{};
31 defer if (use_gpa) {
32 _ = gpa.deinit();
33 };
34 const alloc = if (use_gpa)
35 gpa.allocator()
36 else
37 std.heap.c_allocator;
2838
2939 var maybe_file_path: ?[]const u8 = null;
3040 defer if (maybe_file_path) |path| alloc.free(path);
......@@ -60,7 +70,7 @@ pub fn main() !void {
6070 std.process.exit(1);
6171 };
6272
63 var comp: Comp = .{ .gpa = T.tracingAllocator(&alloc) };
73 var comp: Comp = .{ .gpa = tracer.tracingAllocator(&alloc) };
6474 try comp.init();
6575 defer comp.deinit();
6676 const main_file = try comp.getFile(file_path);
......@@ -72,10 +82,14 @@ pub fn main() !void {
7282 try fail_report.dumpToStdErr(&comp);
7383 std.process.exit(1);
7484 },
85 error.ParseFail => {
86 // Already printed.
87 std.process.exit(1);
88 },
7589 else => return err,
7690 };
7791
78 {
92 if (comp.options.dump_ir) {
7993 const stderr = std.io.getStdErr().writer();
8094 try teg.dumpToWriter(stderr);
8195 }
......@@ -88,6 +102,8 @@ pub fn main() !void {
88102 try comp.link(writer);
89103 try bufw.flush();
90104
105 std.process.cleanExit();
106
91107 // var error_pos: u32 = 0;
92108 // var tokens = Tokenizer.tokenize(source, alloc.allocator(), &error_pos) catch |err| {
93109 // var line: usize = 1;