diff options
author | 2021-09-12 00:37:59 -0700 | |
---|---|---|
committer | 2021-09-12 00:37:59 -0700 | |
commit | dfb65ef1ca0406e9679f21ae316b6a0878b56271 (patch) | |
tree | 1a99326014d40b68de8f66454605b45c2dc1233d | |
parent | 57ca04444b0397c5fd92177382627cf5113282b5 (diff) | |
download | bun-dfb65ef1ca0406e9679f21ae316b6a0878b56271.tar.gz bun-dfb65ef1ca0406e9679f21ae316b6a0878b56271.tar.zst bun-dfb65ef1ca0406e9679f21ae316b6a0878b56271.zip |
Reduce number of allocations for serializing error messages
-rw-r--r-- | src/logger.zig | 108 | ||||
-rw-r--r-- | src/string_builder.zig | 32 | ||||
-rw-r--r-- | src/strings.zig | 38 |
3 files changed, 125 insertions, 53 deletions
diff --git a/src/logger.zig b/src/logger.zig index 397a49a11..b693584a4 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -10,6 +10,7 @@ const unicode = std.unicode; const expect = std.testing.expect; const assert = std.debug.assert; const ArrayList = std.ArrayList; +const StringBuilder = @import("./string_builder.zig"); pub const Kind = enum(i8) { err, @@ -122,13 +123,18 @@ pub const Location = struct { pub fn init_or_nil(_source: ?*const Source, r: Range) ?Location { if (_source) |source| { var data = source.initErrorPosition(r.loc); + var full_line = source.contents[data.line_start..data.line_end]; + if (full_line.len > 80 + data.column_count) { + full_line = full_line[std.math.max(data.column_count, 40) - 40 .. std.math.min(data.column_count + 40, full_line.len - 40) + 40]; + } + return Location{ .file = source.path.pretty, .namespace = source.path.namespace, .line = usize2Loc(data.line_count).start, .column = usize2Loc(data.column_count).start, - .length = source.contents.len, - .line_text = source.contents[data.line_start..data.line_end], + .length = full_line.len, + .line_text = full_line, .offset = @intCast(usize, std.math.max(r.loc.start, 0)), }; } else { @@ -404,6 +410,32 @@ pub const Log = struct { } pub fn appendTo(self: *Log, other: *Log) !void { + var notes_count: usize = 0; + + for (self.msgs.items) |msg_| { + const msg: Msg = msg_; + if (msg.notes) |notes| { + for (notes) |note| { + notes_count += @intCast(usize, @boolToInt(note.text.len > 0)); + } + } + } + + if (notes_count > 0) { + var notes = try other.msgs.allocator.alloc(Data, notes_count); + var note_i: usize = 0; + for (self.msgs.items) |*msg| { + if (msg.notes) |current_notes| { + var start_note_i: usize = note_i; + for (current_notes) |note| { + notes[note_i] = note; + note_i += 1; + } + msg.notes = notes[start_note_i..note_i]; + } + } + } + try other.msgs.appendSlice(self.msgs.items); other.warnings += self.warnings; other.errors += self.errors; @@ -416,22 +448,67 @@ pub const Log = struct { other.errors += self.errors; if (source.contents_is_recycled) { - var i: usize = 0; - var j: usize = other.msgs.items.len - self.msgs.items.len; + var string_builder = StringBuilder{}; + var notes_count: usize = 0; + { + var i: usize = 0; + var j: usize = other.msgs.items.len - self.msgs.items.len; + + while (i < self.msgs.items.len) : ({ + i += 1; + j += 1; + }) { + const msg = self.msgs.items[i]; + if (msg.data.location) |location| { + if (location.line_text) |line_text| { - while (i < self.msgs.items.len) : ({ - i += 1; - j += 1; - }) { - const msg = self.msgs.items[i]; - if (msg.data.location) |location| { - if (location.line_text) |line_text| { - other.msgs.items[j].data.location.?.line_text = try other.msgs.allocator.dupe( - u8, // Naively truncate to 690 characters per line. // This doesn't catch where an error occurred for extremely long, minified lines. - line_text[0..std.math.min(line_text.len, 690)], - ); + string_builder.count(line_text[0..std.math.min(line_text.len, 690)]); + } + } + + if (msg.notes) |notes| { + notes_count += notes.len; + for (notes) |note| { + string_builder.count(note.text); + } + } + } + } + + try string_builder.allocate(other.msgs.allocator); + var notes_buf = try other.msgs.allocator.alloc(Data, notes_count); + var note_i: usize = 0; + + { + var i: usize = 0; + var j: usize = other.msgs.items.len - self.msgs.items.len; + + while (i < self.msgs.items.len) : ({ + i += 1; + j += 1; + }) { + const msg = self.msgs.items[i]; + + if (msg.data.location) |location| { + if (location.line_text) |line_text| { + other.msgs.items[j].data.location.?.line_text = string_builder.append( + // Naively truncate to 690 characters per line. + // This doesn't catch where an error occurred for extremely long, minified lines. + line_text[0..std.math.min(line_text.len, 690)], + ); + } + } + + if (msg.notes) |notes| { + var start_notes_i: usize = note_i; + for (notes) |note| { + notes_buf[note_i] = note; + notes_buf[note_i].text = string_builder.append(note.text); + note_i += 1; + } + other.msgs.items[j].notes = notes_buf[start_notes_i..note_i]; } } } @@ -833,6 +910,7 @@ pub const Source = struct { else => {}, } } + return ErrorPosition{ .line_start = if (line_start > 0) line_start - 1 else line_start, .line_end = line_end, diff --git a/src/string_builder.zig b/src/string_builder.zig new file mode 100644 index 000000000..26782b896 --- /dev/null +++ b/src/string_builder.zig @@ -0,0 +1,32 @@ +usingnamespace @import("string_types.zig"); +const Allocator = @import("std").mem.Allocator; +const assert = @import("std").debug.assert; +const copy = @import("std").mem.copy; + +const StringBuilder = @This(); + +len: usize = 0, +cap: usize = 0, +ptr: ?[*]u8 = null, + +pub fn count(this: *StringBuilder, slice: string) void { + this.cap += slice.len; +} + +pub fn allocate(this: *StringBuilder, allocator: *Allocator) !void { + var slice = try allocator.alloc(u8, this.cap); + this.ptr = slice.ptr; + this.len = 0; +} + +pub fn append(this: *StringBuilder, slice: string) string { + assert(this.len <= this.cap); // didn't count everything + assert(this.ptr != null); // must call allocate first + + copy(u8, this.ptr.?[this.len..this.cap], slice); + const result = this.ptr.?[this.len..this.cap][0..slice.len]; + this.len += slice.len; + + assert(this.len <= this.cap); + return result; +} diff --git a/src/strings.zig b/src/strings.zig index 189116b2b..4813c1f91 100644 --- a/src/strings.zig +++ b/src/strings.zig @@ -9,44 +9,6 @@ pub const MutableString = mutable.MutableString; pub const eql = std.meta.eql; -pub fn NewStringBuilder(comptime size: usize) type { - return struct { - const This = @This(); - buffer: [*]u8 = undefined, - remain: []u8 = undefined, - - pub fn init() This { - return This{}; - } - - pub fn load(this: *This) void { - this.remain = (&this.buffer)[0..size]; - } - - pub fn append(this: *This, _str: string) void { - std.mem.copy(u8, this.remain, _str); - this.remain = this.remain[_str.len..]; - } - - pub fn str(this: *This) string { - var buf = this.buffer[0 .. @ptrToInt(this.remain.ptr) - @ptrToInt(&this.buffer)]; - // Always leave a sentinel so that anything that expects a sentinel Just Works - // specifically, the reason for this is so C-based APIs can be used without an extra copy. - // one byte is cheap...right? - this.buffer[buf.len] = 0; - return buf; - } - - pub fn pop(this: *This, count: usize) string { - this.remain = this.buffer[0 .. @ptrToInt(this.remain.ptr) - @ptrToInt(&this.buffer) - count]; - } - - pub fn reset(this: *This) void { - this.load(); - } - }; -} - pub fn nql(a: anytype, b: @TypeOf(a)) bool { return !eql(a, b); } |