Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2025-05-06 20:17:23 -07:00
committed by GitHub
parent 920b3dc8de
commit d291b56f8b
7 changed files with 112 additions and 61 deletions

View File

@@ -164,12 +164,13 @@ pub const WatchEvent = struct {
};
}
pub const Op = packed struct {
pub const Op = packed struct(u8) {
delete: bool = false,
metadata: bool = false,
rename: bool = false,
write: bool = false,
move_to: bool = false,
_padding: u3 = 0,
pub fn merge(before: Op, after: Op) Op {
return .{
@@ -185,6 +186,7 @@ pub const WatchEvent = struct {
try w.writeAll("{");
var first = true;
inline for (comptime std.meta.fieldNames(Op)) |name| {
if (comptime std.mem.eql(u8, name, "_padding")) continue;
if (@field(op, name)) {
if (!first) {
try w.writeAll(",");

View File

@@ -1917,9 +1917,8 @@ fn startAsyncBundle(
errdefer heap.deinit();
const allocator = heap.allocator();
const ast_memory_allocator = try allocator.create(bun.JSAst.ASTMemoryAllocator);
ast_memory_allocator.* = .{ .allocator = allocator };
ast_memory_allocator.reset();
ast_memory_allocator.push();
var ast_scope = ast_memory_allocator.enter(allocator);
defer ast_scope.exit();
const bv2 = try BundleV2.init(
&dev.server_transpiler,

View File

@@ -595,14 +595,15 @@ pub const Framework = struct {
bundler_options: *const BuildConfigSubset,
) !void {
const JSAst = bun.JSAst;
const prev_alloc_stmt = JSAst.Stmt.Data.Store.memory_allocator;
const prev_alloc_expr = JSAst.Expr.Data.Store.memory_allocator;
defer JSAst.Stmt.Data.Store.memory_allocator = prev_alloc_stmt;
defer JSAst.Expr.Data.Store.memory_allocator = prev_alloc_expr;
var ast_memory_allocator: JSAst.ASTMemoryAllocator = undefined;
ast_memory_allocator.initWithoutStack(arena);
JSAst.Stmt.Data.Store.memory_allocator = &ast_memory_allocator;
JSAst.Expr.Data.Store.memory_allocator = &ast_memory_allocator;
var ast_scope = JSAst.ASTMemoryAllocator.Scope{
.previous = JSAst.Stmt.Data.Store.memory_allocator,
.current = &ast_memory_allocator,
};
ast_scope.enter();
defer ast_scope.exit();
out.* = try bun.Transpiler.init(
arena,

View File

@@ -845,6 +845,11 @@ pub fn transpileSourceCode(
switch (loader) {
.js, .jsx, .ts, .tsx, .json, .jsonc, .toml, .text => {
// Ensure that if there was an ASTMemoryAllocator in use, it's not used anymore.
var ast_scope = js_ast.ASTMemoryAllocator.Scope{};
ast_scope.enter();
defer ast_scope.exit();
jsc_vm.transpiled_count += 1;
jsc_vm.transpiler.resetStore();
const hash = bun.Watcher.getHash(path.text);
@@ -2320,9 +2325,8 @@ pub const RuntimeTranspilerStore = struct {
};
}
ast_memory_store.?.allocator = allocator;
ast_memory_store.?.reset();
ast_memory_store.?.push();
var ast_scope = ast_memory_store.?.enter(allocator);
defer ast_scope.exit();
const path = this.path;
const specifier = this.path.text;

View File

@@ -117,30 +117,13 @@ pub const TransformTask = struct {
const name = this.loader.stdinName();
const source = logger.Source.initPathString(name, this.input_code.slice());
const prev_memory_allocators = .{ JSAst.Stmt.Data.Store.memory_allocator, JSAst.Expr.Data.Store.memory_allocator };
defer {
JSAst.Stmt.Data.Store.memory_allocator = prev_memory_allocators[0];
JSAst.Expr.Data.Store.memory_allocator = prev_memory_allocators[1];
}
var arena = Mimalloc.Arena.init() catch unreachable;
defer arena.deinit();
const allocator = arena.allocator();
var ast_memory_allocator = allocator.create(JSAst.ASTMemoryAllocator) catch bun.outOfMemory();
ast_memory_allocator.* = .{
.allocator = allocator,
};
ast_memory_allocator.reset();
JSAst.Stmt.Data.Store.memory_allocator = ast_memory_allocator;
JSAst.Expr.Data.Store.memory_allocator = ast_memory_allocator;
defer {
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
arena.deinit();
}
var ast_scope = ast_memory_allocator.enter(allocator);
defer ast_scope.exit();
this.transpiler.setAllocator(allocator);
this.transpiler.setLog(&this.log);
@@ -847,7 +830,8 @@ pub fn scan(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JS
var arena = Mimalloc.Arena.init() catch unreachable;
const prev_allocator = this.transpiler.allocator;
this.transpiler.setAllocator(arena.allocator());
const allocator = arena.allocator();
this.transpiler.setAllocator(allocator);
var log = logger.Log.init(arena.backingAllocator());
defer log.deinit();
this.transpiler.setLog(&log);
@@ -856,13 +840,11 @@ pub fn scan(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callframe: *JS
this.transpiler.setAllocator(prev_allocator);
arena.deinit();
}
var ast_memory_allocator = allocator.create(JSAst.ASTMemoryAllocator) catch bun.outOfMemory();
var ast_scope = ast_memory_allocator.enter(allocator);
defer ast_scope.exit();
defer {
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
}
var parse_result = getParseResult(this, arena.allocator(), code, loader, Transpiler.MacroJSValueType.zero) orelse {
var parse_result = getParseResult(this, allocator, code, loader, Transpiler.MacroJSValueType.zero) orelse {
if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) {
return globalThis.throwValue(try this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error"));
}
@@ -991,15 +973,14 @@ pub fn transformSync(
}
}
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
defer {
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
}
const allocator = arena.allocator();
var ast_memory_allocator = allocator.create(JSAst.ASTMemoryAllocator) catch bun.outOfMemory();
var ast_scope = ast_memory_allocator.enter(allocator);
defer ast_scope.exit();
const prev_bundler = this.transpiler;
this.transpiler.setAllocator(arena.allocator());
this.transpiler.setAllocator(allocator);
this.transpiler.macro_context = null;
var log = logger.Log.init(arena.backingAllocator());
log.level = this.transpiler_options.log.level;
@@ -1010,7 +991,7 @@ pub fn transformSync(
}
const parse_result = getParseResult(
this,
arena.allocator(),
allocator,
code,
loader,
js_ctx_value,
@@ -1132,7 +1113,12 @@ pub fn scanImports(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callfra
var arena = Mimalloc.Arena.init() catch unreachable;
const prev_allocator = this.transpiler.allocator;
this.transpiler.setAllocator(arena.allocator());
const allocator = arena.allocator();
var ast_memory_allocator = allocator.create(JSAst.ASTMemoryAllocator) catch bun.outOfMemory();
var ast_scope = ast_memory_allocator.enter(allocator);
defer ast_scope.exit();
this.transpiler.setAllocator(allocator);
var log = logger.Log.init(arena.backingAllocator());
defer log.deinit();
this.transpiler.setLog(&log);
@@ -1155,14 +1141,6 @@ pub fn scanImports(this: *JSTranspiler, globalThis: *JSC.JSGlobalObject, callfra
}
opts.macro_context = &this.transpiler.macro_context.?;
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
defer {
JSAst.Stmt.Data.Store.reset();
JSAst.Expr.Data.Store.reset();
}
transpiler.resolver.caches.js.scan(
transpiler.allocator,
&this.scan_pass_result,

View File

@@ -119,7 +119,7 @@ pub fn NewStore(comptime types: []const type, comptime count: usize) type {
log("deinit", .{});
var it = store.firstBlock().next; // do not free `store.head`
while (it) |next| {
if (Environment.isDebug)
if (Environment.isDebug or Environment.enable_asan)
@memset(next.buffer, undefined);
it = next.next;
backing_allocator.destroy(next);
@@ -133,7 +133,7 @@ pub fn NewStore(comptime types: []const type, comptime count: usize) type {
pub fn reset(store: *Store) void {
log("reset", .{});
if (Environment.isDebug) {
if (Environment.isDebug or Environment.enable_asan) {
var it: ?*Block = store.firstBlock();
while (it) |next| : (it = next.next) {
next.bytes_used = undefined;
@@ -3214,6 +3214,18 @@ pub const Stmt = struct {
instance = StoreType.init();
}
/// create || reset
pub fn begin() void {
if (memory_allocator != null) return;
if (instance == null) {
create();
return;
}
if (!disable_reset)
instance.?.reset();
}
pub fn reset() void {
if (disable_reset or memory_allocator != null) return;
instance.?.reset();
@@ -6322,12 +6334,24 @@ pub const Expr = struct {
}
pub inline fn assert() void {
if (comptime Environment.allow_assert) {
if (comptime Environment.isDebug or Environment.enable_asan) {
if (instance == null and memory_allocator == null)
bun.unreachablePanic("Store must be init'd", .{});
}
}
/// create || reset
pub fn begin() void {
if (memory_allocator != null) return;
if (instance == null) {
create();
return;
}
if (!disable_reset)
instance.?.reset();
}
pub fn append(comptime T: type, value: T) *T {
if (memory_allocator) |allocator| {
return allocator.append(T, value);
@@ -8554,6 +8578,48 @@ pub const ASTMemoryAllocator = struct {
allocator: std.mem.Allocator,
previous: ?*ASTMemoryAllocator = null,
pub fn enter(this: *ASTMemoryAllocator, allocator: std.mem.Allocator) ASTMemoryAllocator.Scope {
this.allocator = allocator;
this.stack_allocator = SFA{
.buffer = undefined,
.fallback_allocator = allocator,
.fixed_buffer_allocator = undefined,
};
this.bump_allocator = this.stack_allocator.get();
this.previous = null;
var ast_scope = ASTMemoryAllocator.Scope{
.current = this,
.previous = Stmt.Data.Store.memory_allocator,
};
ast_scope.enter();
return ast_scope;
}
pub const Scope = struct {
current: ?*ASTMemoryAllocator = null,
previous: ?*ASTMemoryAllocator = null,
pub fn enter(this: *@This()) void {
bun.debugAssert(Expr.Data.Store.memory_allocator == Stmt.Data.Store.memory_allocator);
this.previous = Expr.Data.Store.memory_allocator;
const current = this.current;
Expr.Data.Store.memory_allocator = current;
Stmt.Data.Store.memory_allocator = current;
if (current == null) {
Stmt.Data.Store.begin();
Expr.Data.Store.begin();
}
}
pub fn exit(this: *const @This()) void {
Expr.Data.Store.memory_allocator = this.previous;
Stmt.Data.Store.memory_allocator = this.previous;
}
};
pub fn reset(this: *ASTMemoryAllocator) void {
this.stack_allocator = SFA{
.buffer = undefined,

View File

@@ -292,7 +292,8 @@ pub fn watchLoopCycle(this: *bun.Watcher) bun.JSC.Maybe(void) {
this.mutex.lock();
defer this.mutex.unlock();
if (this.running) {
this.onFileUpdate(this.ctx, all_events[0 .. last_event_index + 1], this.changed_filepaths[0 .. name_off + 1], this.watchlist);
// all_events.len == 0 is checked above, so last_event_index + 1 is safe
this.onFileUpdate(this.ctx, all_events[0 .. last_event_index + 1], this.changed_filepaths[0..name_off], this.watchlist);
} else {
break;
}