mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
[autofix.ci] apply automated fixes
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user