diff options
author | 2023-05-01 12:04:34 -0700 | |
---|---|---|
committer | 2023-05-01 12:04:34 -0700 | |
commit | 07048661f3537956b7b882c6efcf7571b11c1fab (patch) | |
tree | 3248f3fe407c5119f7c740b23764d6add9eed25a | |
parent | c2a223802b5a20a1f68c10d1f66797ba620e470c (diff) | |
download | bun-dylan/source-map-names-property.tar.gz bun-dylan/source-map-names-property.tar.zst bun-dylan/source-map-names-property.zip |
include `first_name_offset` in source map bufferdylan/source-map-names-property
-rw-r--r-- | src/bun.js/javascript.zig | 4 | ||||
-rw-r--r-- | src/bundler/bundle_v2.zig | 2 | ||||
-rw-r--r-- | src/js_printer.zig | 33 | ||||
-rw-r--r-- | src/sourcemap/sourcemap.zig | 167 |
4 files changed, 145 insertions, 61 deletions
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 06f833e3b..0e22367ca 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -193,7 +193,7 @@ pub const SavedSourceMap = struct { pub const SourceMapHandler = js_printer.SourceMapHandler.For(SavedSourceMap, onSourceMapChunk); - pub fn putMappings(this: *SavedSourceMap, source: logger.Source, mappings: MutableString) !void { + pub fn putMappings(this: *SavedSourceMap, source: logger.Source, mappings: SourceMap.MappingsBuffer) !void { var entry = try this.map.getOrPut(std.hash.Wyhash.hash(0, source.path.text)); if (entry.found_existing) { var value = Value.from(entry.value_ptr.*); @@ -207,7 +207,7 @@ pub const SavedSourceMap = struct { } } - entry.value_ptr.* = Value.init(bun.cast(*SavedMappings, mappings.list.items.ptr)).ptr(); + entry.value_ptr.* = Value.init(bun.cast(*SavedMappings, mappings.data.list.items.ptr)).ptr(); } pub fn get(this: *SavedSourceMap, path: string) ?MappingList { diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index c1dafc0ff..f3a9fdca6 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -6303,7 +6303,7 @@ const LinkerContext = struct { start_state.generated_column += prev_column_offset; } - try sourcemap.appendSourceMapChunk(&j, worker.allocator, prev_end_state, start_state, chunk.buffer.list.items); + try sourcemap.appendSourceMapChunk(&j, c.allocator, prev_end_state, start_state, chunk.buffer); prev_end_state = chunk.end_state; prev_end_state.source_index = source_index; diff --git a/src/js_printer.zig b/src/js_printer.zig index 718632ef6..3ba10e55e 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -1178,21 +1178,22 @@ fn NewPrinter( return; } - printer.source_map_builder.addSourceMapping(location, printer.writer.slice()); + printer.source_map_builder.addSourceMapping(location, "", printer.writer.slice()); } - // pub inline fn addSourceMappingForName(printer: *Printer, location: logger.Loc, name: string, ref: Ref) void { - // _ = location; - // if (comptime !generate_source_map) { - // return; - // } + pub inline fn addSourceMappingForName(printer: *Printer, location: logger.Loc, name: string, ref: Ref) void { + if (comptime !generate_source_map) { + return; + } - // if (printer.symbols().get(printer.symbols().follow(ref))) |symbol| { - // if (!strings.eqlLong(symbol.original_name, name)) { - // printer.source_map_builder.addSourceMapping() - // } - // } - // } + if (printer.symbols().get(printer.symbols().follow(ref))) |symbol| { + if (!strings.eqlLong(symbol.original_name, name, true)) { + printer.source_map_builder.addSourceMapping(location, symbol.original_name, printer.writer.slice()); + } else { + printer.source_map_builder.addSourceMapping(location, "", printer.writer.slice()); + } + } + } pub fn printSymbol(p: *Printer, ref: Ref) void { std.debug.assert(!ref.isNull()); @@ -3362,9 +3363,10 @@ fn NewPrinter( switch (binding.data) { .b_missing => {}, .b_identifier => |b| { + const name = p.renamer.nameForSymbol(b.ref); p.printSpaceBeforeIdentifier(); - p.addSourceMapping(binding.loc); - p.printSymbol(b.ref); + p.addSourceMappingForName(binding.loc, name, b.ref); + p.printIdentifier(name); }, .b_array => |b| { p.print("["); @@ -3459,7 +3461,8 @@ fn NewPrinter( // Use a shorthand property if the names are the same switch (property.value.data) { .b_identifier => |id| { - if (str.eql(string, p.renamer.nameForSymbol(id.ref))) { + const name = p.renamer.nameForSymbol(id.ref); + if (str.eql(string, name)) { p.maybePrintDefaultBindingValue(property); continue; } diff --git a/src/sourcemap/sourcemap.zig b/src/sourcemap/sourcemap.zig index b7441ccc9..4bda94dce 100644 --- a/src/sourcemap/sourcemap.zig +++ b/src/sourcemap/sourcemap.zig @@ -15,6 +15,7 @@ const Joiner = @import("../string_joiner.zig"); const JSPrinter = bun.js_printer; const URL = bun.URL; const FileSystem = bun.fs.FileSystem; +const Index = @import("../ast/base.zig").Index; const SourceMap = @This(); @@ -32,17 +33,21 @@ pub const SourceMapState = struct { source_index: i32 = 0, original_line: i32 = 0, original_column: i32 = 0, + original_name: u32 = 0, + has_original_name: bool = false, }; sources: [][]const u8 = &[_][]u8{}, sources_content: [][]SourceContent, mapping: Mapping.List = .{}, +names: std.ArrayList(string), allocator: std.mem.Allocator, pub const Mapping = struct { generated: LineColumnOffset, original: LineColumnOffset, source_index: i32, + original_name: Index = Index.invalid, pub const List = std.MultiArrayList(Mapping); @@ -66,6 +71,10 @@ pub const Mapping = struct { return mapping.original.columns; } + pub inline fn originalName(mapping: Mapping) Index { + return mapping.original_name; + } + pub fn find(mappings: Mapping.List, line: i32, column: i32) ?Mapping { if (findIndex(mappings, line, column)) |i| { return mappings.get(i); @@ -518,19 +527,19 @@ pub const SourceMapPieces = struct { // After all chunks are computed, they are joined together in a second pass. // This rewrites the first mapping in each chunk to be relative to the end // state of the previous chunk. -pub fn appendSourceMapChunk(j: *Joiner, allocator: std.mem.Allocator, prev_end_state_: SourceMapState, start_state_: SourceMapState, source_map_: bun.string) !void { - var prev_end_state = prev_end_state_; - var start_state = start_state_; +pub fn appendSourceMapChunk(j: *Joiner, allocator: std.mem.Allocator, _prev_end_state: SourceMapState, _start_state: SourceMapState, _buffer: MappingsBuffer) !void { + var prev_end_state = _prev_end_state; + var start_state = _start_state; // Handle line breaks in between this mapping and the previous one if (start_state.generated_line > 0) { j.append(try strings.repeatingAlloc(allocator, @intCast(usize, start_state.generated_line), ';'), 0, allocator); prev_end_state.generated_column = 0; } - var source_map = source_map_; - if (strings.indexOfNotChar(source_map, ';')) |semicolons| { - j.append(source_map[0..semicolons], 0, null); - source_map = source_map[semicolons..]; + var buffer = _buffer.data.list.items; + if (strings.indexOfNotChar(buffer, ';')) |semicolons| { + j.append(buffer[0..semicolons], 0, null); + buffer = buffer[semicolons..]; prev_end_state.generated_column = 0; start_state.generated_column = 0; } @@ -539,16 +548,16 @@ pub fn appendSourceMapChunk(j: *Joiner, allocator: std.mem.Allocator, prev_end_s // for the start of the original file (the printer always generates one for // the start of the file). var i: usize = 0; - const generated_column_ = decodeVLQ(source_map, 0); + const generated_column_ = decodeVLQ(buffer, 0); i = generated_column_.start; - const source_index_ = decodeVLQ(source_map, i); + const source_index_ = decodeVLQ(buffer, i); i = source_index_.start; - const original_line_ = decodeVLQ(source_map, i); + const original_line_ = decodeVLQ(buffer, i); i = original_line_.start; - const original_column_ = decodeVLQ(source_map, i); + const original_column_ = decodeVLQ(buffer, i); i = original_column_.start; - source_map = source_map[i..]; + buffer = buffer[i..]; // Rewrite the first mapping to be relative to the end state of the previous // chunk. We now know what the end state is because we're in the second pass @@ -557,15 +566,29 @@ pub fn appendSourceMapChunk(j: *Joiner, allocator: std.mem.Allocator, prev_end_s start_state.generated_column += generated_column_.value; start_state.original_line += original_line_.value; start_state.original_column += original_column_.value; + prev_end_state.has_original_name = false; j.append( - appendMappingToBuffer(MutableString.initEmpty(allocator), j.lastByte(), prev_end_state, start_state).list.items, + appendMappingToBuffer(MutableString.initEmpty(allocator), j.lastByte(), prev_end_state, start_state).buffer.list.items, 0, allocator, ); + // Next, if there's an original name, we need to rewrite that as well to be + // relative to that of the previous chunk + if (_buffer.first_name_offset.isValid()) { + const before = _buffer.first_name_offset.get(); + var name_decode_res = decodeVLQ(buffer, before); + name_decode_res.value += @intCast(i32, start_state.original_name - prev_end_state.original_name); + j.push(buffer[0..before]); + const encode_name_res = encodeVLQWithLookupTable(name_decode_res.value); + j.push(encode_name_res.bytes[0..encode_name_res.len]); + j.push(buffer[name_decode_res.start..]); + return; + } + // Then append everything after that without modification. - j.push(source_map); + j.push(buffer); } const vlq_lookup_table: [256]VLQ = brk: { @@ -939,7 +962,12 @@ pub fn appendSourceMappingURLRemote( try writer.writeAll(".map"); } -pub fn appendMappingToBuffer(buffer_: MutableString, last_byte: u8, prev_state: SourceMapState, current_state: SourceMapState) MutableString { +pub const AppendMappingToBufferResult = struct { + buffer: MutableString, + name_offset: Index, +}; + +pub fn appendMappingToBuffer(buffer_: MutableString, last_byte: u8, prev_state: SourceMapState, current_state: SourceMapState) AppendMappingToBufferResult { var buffer = buffer_; const needs_comma = last_byte != 0 and last_byte != ';' and last_byte != '"'; @@ -971,11 +999,26 @@ pub fn appendMappingToBuffer(buffer_: MutableString, last_byte: u8, prev_state: buffer.appendAssumeCapacity(vlq[i].bytes[0..vlq[i].len]); } - return buffer; + var name_offset = Index.invalid; + if (current_state.has_original_name) { + name_offset = Index.init(buffer.list.items.len); + const name_vlq = encodeVLQWithLookupTable(@intCast(i32, current_state.original_name - prev_state.original_name)); + buffer.append(name_vlq.bytes[0..name_vlq.len]) catch unreachable; + } + + return .{ + .buffer = buffer, + .name_offset = name_offset, + }; } +pub const MappingsBuffer = struct { + data: MutableString, + first_name_offset: Index = Index.invalid, +}; + pub const Chunk = struct { - buffer: MutableString, + buffer: MappingsBuffer, mappings_count: usize = 0, @@ -1013,7 +1056,7 @@ pub const Chunk = struct { } output.growIfNeeded( - filename.len + 2 + (source.contents.len * @as(usize, @boolToInt(include_sources_contents))) + chunk.buffer.list.items.len + 32 + 39 + 29 + 22 + 20, + filename.len + 2 + (source.contents.len * @as(usize, @boolToInt(include_sources_contents))) + chunk.buffer.data.list.items.len + 32 + 39 + 29 + 22 + 20, ) catch unreachable; try output.append("{\n \"version\":3,\n \"sources\": ["); @@ -1025,7 +1068,7 @@ pub const Chunk = struct { } try output.append("],\n \"mappings\": "); - output = try JSPrinter.quoteForJSON(chunk.buffer.list.items, output, ascii_only); + output = try JSPrinter.quoteForJSON(chunk.buffer.data.list.items, output, ascii_only); try output.append(", \"names\": []\n}"); return output; @@ -1044,15 +1087,15 @@ pub const Chunk = struct { try this.ctx.appendLineSeparator(); } - pub inline fn append(this: *Format, current_state: SourceMapState, prev_state: SourceMapState) anyerror!void { - try this.ctx.append(current_state, prev_state); + pub inline fn append(this: *Format, current_state: SourceMapState, prev_state: *SourceMapState, first_name_offset: *Index) anyerror!void { + try this.ctx.append(current_state, prev_state, first_name_offset); } pub inline fn shouldIgnore(this: Format) bool { return this.ctx.shouldIgnore(); } - pub inline fn getBuffer(this: Format) MutableString { + pub inline fn getBuffer(this: Format) MappingsBuffer { return this.ctx.getBuffer(); } @@ -1063,7 +1106,7 @@ pub const Chunk = struct { } pub const VLQSourceMap = struct { - data: MutableString, + buffer: MappingsBuffer, count: usize = 0, offset: usize = 0, @@ -1071,38 +1114,49 @@ pub const Chunk = struct { pub fn init(allocator: std.mem.Allocator, prepend_count: bool) VLQSourceMap { var map = VLQSourceMap{ - .data = MutableString.initEmpty(allocator), + .buffer = MappingsBuffer{ + .data = MutableString.initEmpty(allocator), + }, }; // For bun.js, we store the number of mappings and how many bytes the final list is at the beginning of the array if (prepend_count) { map.offset = 16; - map.data.append(&[16]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) catch unreachable; + map.buffer.data.append(&[16]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) catch unreachable; } return map; } pub fn appendLineSeparator(this: *VLQSourceMap) anyerror!void { - try this.data.appendChar(';'); + try this.buffer.data.appendChar(';'); } - pub fn append(this: *VLQSourceMap, current_state: SourceMapState, prev_state: SourceMapState) anyerror!void { - const last_byte: u8 = if (this.data.list.items.len > this.offset) - this.data.list.items[this.data.list.items.len - 1] + pub fn append(this: *VLQSourceMap, current_state: SourceMapState, prev_state: *SourceMapState, first_name_offset: *Index) anyerror!void { + const last_byte: u8 = if (this.buffer.data.list.items.len > this.offset) + this.buffer.data.list.items[this.buffer.data.list.items.len - 1] else 0; - this.data = appendMappingToBuffer(this.data, last_byte, prev_state, current_state); + const append_res = appendMappingToBuffer(this.buffer.data, last_byte, prev_state.*, current_state); + this.buffer.data = append_res.buffer; this.count += 1; + + const prev_original_name = prev_state.original_name; + prev_state.* = current_state; + if (!current_state.has_original_name) { + prev_state.original_name = prev_original_name; + } else if (!first_name_offset.isValid()) { + first_name_offset.set(append_res.name_offset.get()); + } } pub fn shouldIgnore(this: VLQSourceMap) bool { return this.count == 0; } - pub fn getBuffer(this: VLQSourceMap) MutableString { - return this.data; + pub fn getBuffer(this: VLQSourceMap) MappingsBuffer { + return this.buffer; } pub fn getCount(this: VLQSourceMap) usize { @@ -1110,17 +1164,23 @@ pub const Chunk = struct { } }; - pub fn NewBuilder(comptime SourceMapFormatType: type) type { + pub fn NewBuilder(comptime SourceMapFormatType: type, comptime allocator: std.mem.Allocator, comptime ascii_only: bool) type { return struct { const ThisBuilder = @This(); input_source_map: ?*SourceMap = null, source_map: SourceMapper, + names_map: bun.StringHashMap(Index) = bun.StringHashMap(Index).init(allocator), + quoted_names: std.ArrayList(string) = std.ArrayList(string).init(allocator), line_offset_tables: LineOffsetTable.List = .{}, prev_state: SourceMapState = SourceMapState{}, + prev_original_name: string = "", + prev_generated_len: usize = 0, + first_name_offset: Index = Index.invalid, last_generated_update: u32 = 0, generated_column: i32 = 0, prev_loc: Logger.Loc = Logger.Loc.Empty, has_prev_state: bool = false, + allocator: std.mem.Allocator = allocator, line_offset_table_byte_offset_list: []const u32 = &.{}, @@ -1143,8 +1203,8 @@ pub const Chunk = struct { pub noinline fn generateChunk(b: *ThisBuilder, output: []const u8) Chunk { b.updateGeneratedLineAndColumn(output); if (b.prepend_count) { - b.source_map.getBuffer().list.items[0..8].* = @bitCast([8]u8, b.source_map.getBuffer().list.items.len); - b.source_map.getBuffer().list.items[8..16].* = @bitCast([8]u8, b.source_map.getCount()); + b.source_map.getBuffer().data.list.items[0..8].* = @bitCast([8]u8, b.source_map.getBuffer().data.list.items.len); + b.source_map.getBuffer().data.list.items[8..16].* = @bitCast([8]u8, b.source_map.getCount()); } return Chunk{ .buffer = b.source_map.getBuffer(), @@ -1223,35 +1283,56 @@ pub const Chunk = struct { b.last_generated_update = @truncate(u32, output.len); } - pub fn appendMapping(b: *ThisBuilder, current_state_: SourceMapState) void { - var current_state = current_state_; + pub fn appendMapping(b: *ThisBuilder, _original_name: string, _current_state: SourceMapState) void { + var current_state = _current_state; + var original_name = _original_name; // If the input file had a source map, map all the way back to the original if (b.input_source_map) |input| { if (input.find(current_state.original_line, current_state.original_column)) |mapping| { current_state.source_index = mapping.sourceIndex(); current_state.original_line = mapping.originalLine(); current_state.original_column = mapping.originalColumn(); + + if (mapping.original_name.isValid()) { + original_name = input.names.items[mapping.original_name.get()]; + } } } + if (original_name.len > 0) { + var res = b.names_map.getOrPut(original_name) catch unreachable; + if (!res.found_existing) { + const i = b.quoted_names.items.len; + var quote_buf = MutableString.init(b.allocator, original_name.len) catch unreachable; + quote_buf = JSPrinter.quoteForJSON(original_name, quote_buf, ascii_only) catch unreachable; + b.quoted_names.append(quote_buf.toOwnedSliceLeaky()) catch unreachable; + res.value_ptr.* = Index.init(i); + } + + current_state.original_name = res.value_ptr.get(); + current_state.has_original_name = true; + } + b.appendMappingWithoutRemapping(current_state); } pub fn appendMappingWithoutRemapping(b: *ThisBuilder, current_state: SourceMapState) void { - b.source_map.append(current_state, b.prev_state) catch unreachable; - b.prev_state = current_state; + b.source_map.append(current_state, &b.prev_state, &b.first_name_offset) catch unreachable; b.has_prev_state = true; } - pub fn addSourceMapping(b: *ThisBuilder, loc: Logger.Loc, output: []const u8) void { + pub fn addSourceMapping(b: *ThisBuilder, loc: Logger.Loc, original_name: string, output: string) void { if ( // exclude generated code from source b.prev_loc.eql(loc) or // don't insert mappings for same location twice - loc.start == Logger.Loc.Empty.start) + loc.start == Logger.Loc.Empty.start or strings.eqlLong(b.prev_original_name, original_name, true) or b.prev_generated_len == output.len) return; b.prev_loc = loc; + b.prev_generated_len = output.len; + b.prev_original_name = original_name; + const list = b.line_offset_tables; const original_line = LineOffsetTable.findLine(b.line_offset_table_byte_offset_list, loc); const line = list.get(@intCast(usize, @max(original_line, 0))); @@ -1276,7 +1357,7 @@ pub const Chunk = struct { }); } - b.appendMapping(.{ + b.appendMapping(original_name, .{ .generated_line = b.prev_state.generated_line, .generated_column = b.generated_column, .source_index = b.prev_state.source_index, @@ -1290,7 +1371,7 @@ pub const Chunk = struct { }; } - pub const Builder = NewBuilder(VLQSourceMap); + pub const Builder = NewBuilder(VLQSourceMap, bun.default_allocator, false); }; /// https://sentry.engineering/blog/the-case-for-debug-ids |