From d1e817fcce0c2bf88a95d7271ab6da4bf3ddef0c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:48:02 +0000 Subject: [PATCH] [autofix.ci] apply automated fixes --- src/bun.js/SavedSourceMap.zig | 14 ++-- src/sourcemap/JSSourceMap.zig | 3 +- src/sourcemap/LineOffsetTable.zig | 76 +++++++++---------- .../bun/sourcemap/compact-sourcemap.test.ts | 50 ++++++------ .../bun/sourcemap/memory-comparison.test.ts | 42 +++++----- 5 files changed, 92 insertions(+), 93 deletions(-) diff --git a/src/bun.js/SavedSourceMap.zig b/src/bun.js/SavedSourceMap.zig index 2c0a7ff3a2..c3b1487f90 100644 --- a/src/bun.js/SavedSourceMap.zig +++ b/src/bun.js/SavedSourceMap.zig @@ -82,25 +82,25 @@ pub const SavedMappings = struct { /// Compact variant that uses LineOffsetTable.Compact for reduced memory usage pub const SavedMappingsCompact = struct { compact_table: SourceMap.LineOffsetTable.Compact, - + pub fn init(allocator: Allocator, vlq_mappings: []const u8) !SavedMappingsCompact { return SavedMappingsCompact{ .compact_table = try SourceMap.LineOffsetTable.Compact.init(allocator, vlq_mappings), }; } - + pub fn deinit(this: *SavedMappingsCompact) void { this.compact_table.deinit(); } - + pub fn toMapping(this: *SavedMappingsCompact, allocator: Allocator, path: string) anyerror!ParsedSourceMap { // Parse the VLQ mappings using the existing parser but keep the compact table const result = SourceMap.Mapping.parse( allocator, this.compact_table.vlq_mappings, null, // estimated mapping count - 1, // sources count - this.compact_table.line_offsets.len, // input line count + 1, // sources count + this.compact_table.line_offsets.len, // input line count .{}, ); switch (result) { @@ -223,11 +223,11 @@ pub fn deinit(this: *SavedSourceMap) void { pub fn putMappings(this: *SavedSourceMap, source: *const logger.Source, mappings: MutableString) !void { // Always use compact format for memory efficiency const mappings_data = mappings.list.items; - + // Extract VLQ mappings (starts after header if present) const vlq_start: usize = if (mappings_data.len >= vlq_offset) vlq_offset else 0; const vlq_data = mappings_data[vlq_start..]; - + const compact = try bun.default_allocator.create(SavedMappingsCompact); compact.* = try SavedMappingsCompact.init(bun.default_allocator, vlq_data); try this.putValue(source.path.text, Value.init(compact)); diff --git a/src/sourcemap/JSSourceMap.zig b/src/sourcemap/JSSourceMap.zig index 78a87ffc20..e20c4b89d6 100644 --- a/src/sourcemap/JSSourceMap.zig +++ b/src/sourcemap/JSSourceMap.zig @@ -141,7 +141,7 @@ pub fn constructor( error.OutOfMemory => return error.OutOfMemory, else => return globalObject.throwValue(globalObject.createSyntaxErrorInstance("Failed to parse compact sourcemap: {s}", .{@errorName(err)})), }; - + const source_map = bun.new(JSSourceMap, .{ .sourcemap = bun.new(bun.sourcemap.ParsedSourceMap, parsed_map), .sources = sources.items, @@ -158,7 +158,6 @@ pub fn constructor( return source_map; } - pub fn memoryCost(this: *const JSSourceMap) usize { return @sizeOf(JSSourceMap) + this.sources.len * @sizeOf(bun.String) + this.sourcemap.memoryCost(); } diff --git a/src/sourcemap/LineOffsetTable.zig b/src/sourcemap/LineOffsetTable.zig index 6a9b5a9999..d2d4486943 100644 --- a/src/sourcemap/LineOffsetTable.zig +++ b/src/sourcemap/LineOffsetTable.zig @@ -22,111 +22,111 @@ pub const List = bun.MultiArrayList(LineOffsetTable); pub const Compact = struct { /// VLQ-encoded sourcemap mappings string vlq_mappings: []const u8, - /// Index of positions where ';' (line separators) occur in vlq_mappings + /// Index of positions where ';' (line separators) occur in vlq_mappings line_offsets: []const u32, allocator: std.mem.Allocator, - + pub fn init(allocator: std.mem.Allocator, vlq_mappings: []const u8) !Compact { // Find all line separator positions var line_positions = std.ArrayList(u32).init(allocator); defer line_positions.deinit(); - + // Start with implicit position 0 for first line try line_positions.append(0); - + for (vlq_mappings, 0..) |char, i| { if (char == ';') { try line_positions.append(@intCast(i + 1)); } } - + const owned_mappings = try allocator.dupe(u8, vlq_mappings); const owned_offsets = try allocator.dupe(u32, line_positions.items); - + return Compact{ .vlq_mappings = owned_mappings, .line_offsets = owned_offsets, .allocator = allocator, }; } - + pub fn deinit(self: *Compact) void { self.allocator.free(self.vlq_mappings); self.allocator.free(self.line_offsets); } - + /// Find mapping for a given line/column by decoding VLQ on demand pub fn findMapping(self: *const Compact, target_line: i32, target_column: i32) ?SourceMapping { if (target_line < 0 or target_line >= self.line_offsets.len - 1) { return null; } - + const line_start = self.line_offsets[@intCast(target_line)]; - const line_end = if (target_line + 1 < self.line_offsets.len) - self.line_offsets[@intCast(target_line + 1)] - 1 // -1 to exclude the ';' - else + const line_end = if (target_line + 1 < self.line_offsets.len) + self.line_offsets[@intCast(target_line + 1)] - 1 // -1 to exclude the ';' + else @as(u32, @intCast(self.vlq_mappings.len)); - + if (line_start >= line_end) return null; - + const line_mappings = self.vlq_mappings[line_start..line_end]; - + // Decode VLQ mappings for this line var generated_column: i32 = 0; - var source_index: i32 = 0; + var source_index: i32 = 0; var original_line: i32 = 0; var original_column: i32 = 0; - + var pos: usize = 0; var best_mapping: ?SourceMapping = null; - + while (pos < line_mappings.len) { // Skip commas if (line_mappings[pos] == ',') { pos += 1; continue; } - + // Decode generated column delta const gen_col_result = VLQ.decode(line_mappings, pos); if (gen_col_result.start == pos) break; // Invalid VLQ generated_column += gen_col_result.value; pos = gen_col_result.start; - + // If we've passed the target column, return the last good mapping if (generated_column > target_column and best_mapping != null) { return best_mapping; } - + if (pos >= line_mappings.len) break; if (line_mappings[pos] == ',') { // Only generated column - no source info pos += 1; continue; } - + // Decode source index delta const src_idx_result = VLQ.decode(line_mappings, pos); if (src_idx_result.start == pos) break; source_index += src_idx_result.value; pos = src_idx_result.start; - + if (pos >= line_mappings.len) break; - - // Decode original line delta + + // Decode original line delta const orig_line_result = VLQ.decode(line_mappings, pos); if (orig_line_result.start == pos) break; original_line += orig_line_result.value; pos = orig_line_result.start; - + if (pos >= line_mappings.len) break; - + // Decode original column delta const orig_col_result = VLQ.decode(line_mappings, pos); if (orig_col_result.start == pos) break; original_column += orig_col_result.value; pos = orig_col_result.start; - + // Skip name index if present if (pos < line_mappings.len and line_mappings[pos] != ',' and line_mappings[pos] != ';') { const name_result = VLQ.decode(line_mappings, pos); @@ -134,7 +134,7 @@ pub const Compact = struct { pos = name_result.start; } } - + // Update best mapping if this column is <= target if (generated_column <= target_column) { best_mapping = SourceMapping{ @@ -146,22 +146,22 @@ pub const Compact = struct { }; } } - + return best_mapping; } - + /// Compatible API with regular LineOffsetTable for findLine pub fn findLine(self: *const Compact, loc: Logger.Loc) i32 { // For compact version, we need to search through mappings to find the line - // This is a simplified version - in practice you'd want to maintain + // This is a simplified version - in practice you'd want to maintain // generated line->original line mapping - + // For now, return a basic implementation that assumes 1:1 line mapping // This can be optimized by maintaining a separate line mapping cache return @max(0, @min(@as(i32, @intCast(self.line_offsets.len)) - 2, loc.start)); } - - /// Compatible API with regular LineOffsetTable for findIndex + + /// Compatible API with regular LineOffsetTable for findIndex pub fn findIndex(self: *const Compact, loc: Logger.Loc) ?usize { const line = self.findLine(loc); if (line >= 0 and line < self.line_offsets.len - 1) { @@ -169,10 +169,10 @@ pub const Compact = struct { } return null; } - + const SourceMapping = struct { generated_line: i32, - generated_column: i32, + generated_column: i32, source_index: i32, original_line: i32, original_column: i32, @@ -385,6 +385,7 @@ pub fn generate(allocator: std.mem.Allocator, contents: []const u8, approximate_ return list; } +const VLQ = @import("./VLQ.zig"); const std = @import("std"); const bun = @import("bun"); @@ -392,4 +393,3 @@ const BabyList = bun.BabyList; const Logger = bun.logger; const assert = bun.assert; const strings = bun.strings; -const VLQ = @import("./VLQ.zig"); diff --git a/test/js/bun/sourcemap/compact-sourcemap.test.ts b/test/js/bun/sourcemap/compact-sourcemap.test.ts index c9829a493e..25b9aa0220 100644 --- a/test/js/bun/sourcemap/compact-sourcemap.test.ts +++ b/test/js/bun/sourcemap/compact-sourcemap.test.ts @@ -1,5 +1,5 @@ -import { test, expect } from "bun:test"; -import { tempDirWithFiles, bunExe, bunEnv } from "harness"; +import { expect, test } from "bun:test"; +import { bunEnv, bunExe, tempDirWithFiles } from "harness"; // Test the compact sourcemap implementation using the SourceMap class from Node.js test("SourceMap with compact mappings handles basic cases", () => { @@ -9,7 +9,7 @@ test("SourceMap with compact mappings handles basic cases", () => { sources: ["input.js"], sourcesContent: ["console.log('hello');\nconsole.log('world');"], mappings: "AAAA;AACA", // Simple VLQ mappings - names: [] + names: [], }; const { SourceMap } = require("module"); @@ -22,7 +22,7 @@ test("SourceMap with compact mappings handles basic cases", () => { expect(origin.column).toBe(0); expect(origin.fileName || origin.source).toBe("input.js"); - // Test findEntry method + // Test findEntry method const entry = sourceMap.findEntry(0, 0); expect(entry).toBeObject(); expect(entry.generatedLine).toBe(0); @@ -36,16 +36,16 @@ test("SourceMap with complex VLQ mappings", () => { sources: ["input.js"], sourcesContent: ["function test() { console.log('test'); }"], mappings: "AAAA,SAAS,KAAK,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC", // Complex VLQ - names: ["test", "console", "log"] + names: ["test", "console", "log"], }; const { SourceMap } = require("module"); const sourceMap = new SourceMap(payload); // Test various positions - const origin1 = sourceMap.findOrigin(0, 9); // Should map to function name + const origin1 = sourceMap.findOrigin(0, 9); // Should map to function name expect(origin1).toBeObject(); - + const origin2 = sourceMap.findOrigin(0, 20); // Should map to console.log expect(origin2).toBeObject(); }); @@ -55,8 +55,8 @@ test("SourceMap with non-ASCII characters in VLQ", () => { version: 3, sources: ["unicode.js"], sourcesContent: ["console.log('你好');"], - mappings: "AAAA,QAAQ,GAAG,CAAC,IAAI,CAAC", - names: [] + mappings: "AAAA,QAAQ,GAAG,CAAC,IAAI,CAAC", + names: [], }; const { SourceMap } = require("module"); @@ -73,7 +73,7 @@ test("SourceMap handles empty and sparse mappings", () => { sources: ["sparse.js"], sourcesContent: ["line1\n\n\nline4"], mappings: "AAAA;;;AAEA", // Empty lines represented by ;;; - names: [] + names: [], }; const { SourceMap } = require("module"); @@ -83,24 +83,24 @@ test("SourceMap handles empty and sparse mappings", () => { expect(origin1).toBeObject(); // Test mapping to line with empty content - const origin4 = sourceMap.findOrigin(3, 0); + const origin4 = sourceMap.findOrigin(3, 0); expect(origin4).toBeObject(); }); test("SourceMap with large number of mappings for memory test", () => { // Generate a large number of VLQ mappings to test memory efficiency const sources = ["large.js"]; - const sourcesContent = [Array.from({ length: 100 }, (_, i) => `console.log(${i});`).join('\n')]; - + const sourcesContent = [Array.from({ length: 100 }, (_, i) => `console.log(${i});`).join("\n")]; + // Generate simple mappings for each line - const mappings = Array.from({ length: 100 }, () => "AAAA").join(';'); - + const mappings = Array.from({ length: 100 }, () => "AAAA").join(";"); + const payload = { version: 3, sources, sourcesContent, mappings, - names: [] + names: [], }; const { SourceMap } = require("module"); @@ -145,7 +145,7 @@ throwError(); const [stdout, stderr, exitCode2] = await Promise.all([ proc2.stdout.text(), - proc2.stderr?.text() || Promise.resolve(""), + proc2.stderr?.text() || Promise.resolve(""), proc2.exited, ]); @@ -160,31 +160,31 @@ throwError(); test("compact sourcemap performance vs regular sourcemap", () => { // Test to ensure compact variant doesn't significantly impact performance const startTime = Date.now(); - + // Create many SourceMap instances with complex mappings - const mappings = Array.from({ length: 50 }, () => "AAAA,CAAC,CAAC,CAAC,CAAC").join(';'); - + const mappings = Array.from({ length: 50 }, () => "AAAA,CAAC,CAAC,CAAC,CAAC").join(";"); + for (let i = 0; i < 100; i++) { const payload = { version: 3, sources: [`file${i}.js`], sourcesContent: [`// File ${i}\nconsole.log(${i});`], mappings, - names: [] + names: [], }; const { SourceMap } = require("module"); const sourceMap = new SourceMap(payload); - + // Perform some lookups sourceMap.findOrigin(0, 0); sourceMap.findOrigin(1, 0); } - + const endTime = Date.now(); const duration = endTime - startTime; - + // Should complete reasonably quickly (< 1 second) expect(duration).toBeLessThan(1000); console.log(`Performance test completed in ${duration}ms`); -}); \ No newline at end of file +}); diff --git a/test/js/bun/sourcemap/memory-comparison.test.ts b/test/js/bun/sourcemap/memory-comparison.test.ts index cfc613503a..184024e07a 100644 --- a/test/js/bun/sourcemap/memory-comparison.test.ts +++ b/test/js/bun/sourcemap/memory-comparison.test.ts @@ -1,32 +1,32 @@ -import { test, expect } from "bun:test"; +import { expect, test } from "bun:test"; test("Compact vs Regular SourceMap memory comparison conceptual test", () => { // This test demonstrates the memory savings concept - + // Regular sourcemap storage: // - Each mapping = 4 x i32 (16 bytes) for generated_line, generated_column, original_line, original_column // - Plus source_index, name_index etc. // - For 1000 mappings: ~20KB+ in unpacked form - + const mappingCount = 1000; const regularMemoryPerMapping = 20; // bytes per mapping in unpacked form const regularTotalMemory = mappingCount * regularMemoryPerMapping; // ~20KB - + // Compact sourcemap storage: // - VLQ encoded strings are much smaller // - A simple mapping like "AAAA" (4 chars) represents the same data as 16+ bytes // - Line index overhead is minimal (one u32 per line) - + const vlqBytesPerMapping = 4; // Average VLQ encoding size const lineIndexOverhead = Math.ceil(mappingCount / 10) * 4; // Assume ~10 mappings per line - const compactTotalMemory = (mappingCount * vlqBytesPerMapping) + lineIndexOverhead; // ~4KB - + const compactTotalMemory = mappingCount * vlqBytesPerMapping + lineIndexOverhead; // ~4KB + const memoryReduction = ((regularTotalMemory - compactTotalMemory) / regularTotalMemory) * 100; - + console.log(`Regular sourcemap memory: ${regularTotalMemory} bytes`); - console.log(`Compact sourcemap memory: ${compactTotalMemory} bytes`); + console.log(`Compact sourcemap memory: ${compactTotalMemory} bytes`); console.log(`Memory reduction: ${memoryReduction.toFixed(1)}%`); - + // We expect significant memory reduction expect(memoryReduction).toBeGreaterThan(70); // At least 70% reduction expect(compactTotalMemory).toBeLessThan(regularTotalMemory); @@ -34,20 +34,20 @@ test("Compact vs Regular SourceMap memory comparison conceptual test", () => { test("VLQ encoding efficiency demonstration", () => { // Test that shows VLQ encoding is more efficient than storing raw i32 values - + // Example: mapping with generated_column=5, source_index=0, original_line=2, original_column=8 // In regular form: 4 x i32 = 16 bytes // In VLQ form: "KAEA,G" = 6 bytes (including separators) - + const regularSize = 4 * 4; // 4 i32 values = 16 bytes const vlqSize = 6; // "KAEA,G" = 6 bytes - + const savings = ((regularSize - vlqSize) / regularSize) * 100; - + console.log(`Regular mapping size: ${regularSize} bytes`); console.log(`VLQ mapping size: ${vlqSize} bytes`); console.log(`Space savings per mapping: ${savings.toFixed(1)}%`); - + expect(vlqSize).toBeLessThan(regularSize); expect(savings).toBeGreaterThan(50); // At least 50% savings per mapping }); @@ -55,19 +55,19 @@ test("VLQ encoding efficiency demonstration", () => { test("Line index efficiency", () => { // The line index in our compact format adds minimal overhead // but enables fast line-based lookups - + const lineCount = 100; const indexSize = lineCount * 4; // u32 per line = 400 bytes - const mappingCount = 1000; + const mappingCount = 1000; const vlqMappingsSize = mappingCount * 4; // Average 4 bytes per mapping = 4000 bytes - + const totalCompactSize = indexSize + vlqMappingsSize; const indexOverheadPercent = (indexSize / totalCompactSize) * 100; - + console.log(`Line index size: ${indexSize} bytes`); console.log(`VLQ mappings size: ${vlqMappingsSize} bytes`); console.log(`Index overhead: ${indexOverheadPercent.toFixed(1)}%`); - + // Index overhead should be minimal expect(indexOverheadPercent).toBeLessThan(15); // Less than 15% overhead -}); \ No newline at end of file +});