aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/api/bun.zig6
-rw-r--r--src/bun.js/api/server.zig2
-rw-r--r--src/bun.js/event_loop.zig24
-rw-r--r--src/bun.js/javascript.zig48
-rw-r--r--src/bun.js/test/jest.zig27
-rw-r--r--src/bun_js.zig7
-rw-r--r--src/cli/test_command.zig7
7 files changed, 83 insertions, 38 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 49143ec5c..131e08b6e 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -894,11 +894,7 @@ pub fn runGC(
arguments: []const js.JSValueRef,
_: js.ExceptionRef,
) js.JSValueRef {
- // it should only force cleanup on thread exit
-
- Global.mimalloc_cleanup(false);
-
- return ctx.ptr().vm().runGC(arguments.len > 0 and JSValue.fromRef(arguments[0]).toBoolean()).asRef();
+ return ctx.bunVM().garbageCollect(arguments.len > 0 and JSC.JSValue.c(arguments[0]).toBoolean()).asObjectRef();
}
pub fn shrink(
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 866b08e34..92a3c23d0 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -4490,7 +4490,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
this.config.hostname;
this.ref();
-
+ this.vm.autoGarbageCollect();
this.app.listenWithConfig(*ThisServer, this, onListen, .{
.port = this.config.port,
.host = host,
diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig
index b62ac0123..28e12fb84 100644
--- a/src/bun.js/event_loop.zig
+++ b/src/bun.js/event_loop.zig
@@ -31,7 +31,7 @@ pub fn ConcurrentPromiseTask(comptime Context: type) type {
task: WorkPoolTask = .{ .callback = runFromThreadPool },
event_loop: *JSC.EventLoop,
allocator: std.mem.Allocator,
- promise: JSValue,
+ promise: JSC.JSPromise.Strong = .{},
globalThis: *JSGlobalObject,
concurrent_task: JSC.ConcurrentTask = .{},
@@ -44,10 +44,10 @@ pub fn ConcurrentPromiseTask(comptime Context: type) type {
.event_loop = VirtualMachine.vm.event_loop,
.ctx = value,
.allocator = allocator,
- .promise = JSValue.createInternalPromise(globalThis),
.globalThis = globalThis,
};
- this.promise.protect();
+ var promise = JSC.JSPromise.create(globalThis);
+ this.promise.strong.set(globalThis, promise.asValue(globalThis));
this.ref.ref(this.event_loop.virtual_machine);
return this;
@@ -60,19 +60,9 @@ pub fn ConcurrentPromiseTask(comptime Context: type) type {
}
pub fn runFromJS(this: *This) void {
- var promise_value = this.promise;
+ var promise = this.promise.swap();
this.ref.unref(this.event_loop.virtual_machine);
- promise_value.ensureStillAlive();
- promise_value.unprotect();
-
- var promise = promise_value.asInternalPromise() orelse {
- if (comptime @hasDecl(Context, "deinit")) {
- @call(.{}, Context.deinit, .{this.ctx});
- }
- return;
- };
-
var ctx = this.ctx;
ctx.then(promise);
@@ -340,8 +330,9 @@ pub const EventLoop = struct {
}
pub fn autoTick(this: *EventLoop) void {
- if (this.virtual_machine.uws_event_loop.?.num_polls > 0 or this.virtual_machine.uws_event_loop.?.active > 0) {
- this.virtual_machine.uws_event_loop.?.tick();
+ var loop = this.virtual_machine.uws_event_loop.?;
+ if (loop.num_polls > 0 or loop.active > 0) {
+ loop.tick();
// this.afterUSocketsTick();
}
}
@@ -392,6 +383,7 @@ pub const EventLoop = struct {
this.start_server_on_next_tick = false;
ctx.enterUWSLoop();
ctx.is_us_loop_entered = false;
+ ctx.autoGarbageCollect();
}
}
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index fe559fac8..24633eea7 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -314,6 +314,7 @@ pub export fn Bun__handleRejectedPromise(global: *JSGlobalObject, promise: *JSC.
const result = promise.result(global.vm());
var jsc_vm = global.bunVM();
jsc_vm.onUnhandledError(global, result);
+ jsc_vm.autoGarbageCollect();
}
pub export fn Bun__onDidAppendPlugin(jsc_vm: *VirtualMachine, globalObject: *JSGlobalObject) void {
@@ -428,6 +429,13 @@ pub const VirtualMachine = struct {
unhandled_error_counter: usize = 0,
modules: ModuleLoader.AsyncModule.Queue = .{},
+ aggressive_garbage_collection: GCLevel = GCLevel.none,
+
+ pub const GCLevel = enum {
+ none,
+ mild,
+ aggressive,
+ };
pub threadlocal var is_main_thread_vm: bool = false;
@@ -435,6 +443,27 @@ pub const VirtualMachine = struct {
this.onUnhandledRejection = defaultOnUnhandledRejection;
}
+ pub fn loadExtraEnv(this: *VirtualMachine) void {
+ var map = this.bundler.env.map;
+
+ if (map.get("BUN_SHOW_BUN_STACKFRAMES") != null)
+ this.hide_bun_stackframes = false;
+
+ if (map.get("BUN_OVERRIDE_MODULE_PATH")) |override_path| {
+ if (override_path.len > 0) {
+ this.load_builtins_from_path = override_path;
+ }
+ }
+
+ if (map.get("BUN_GARBAGE_COLLECTOR_LEVEL")) |gc_level| {
+ if (strings.eqlComptime(gc_level, "1")) {
+ this.aggressive_garbage_collection = .mild;
+ } else if (strings.eqlComptime(gc_level, "2")) {
+ this.aggressive_garbage_collection = .aggressive;
+ }
+ }
+ }
+
pub fn onUnhandledError(this: *JSC.VirtualMachine, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
this.unhandled_error_counter += 1;
this.onUnhandledRejection(this, globalObject, value);
@@ -448,6 +477,22 @@ pub const VirtualMachine = struct {
return this.bundler.getPackageManager();
}
+ pub fn garbageCollect(this: *const VirtualMachine, sync: bool) JSValue {
+ @setCold(true);
+ Global.mimalloc_cleanup(false);
+ if (sync)
+ return this.global.vm().runGC(true);
+
+ this.global.vm().collectAsync();
+ return JSValue.jsNumber(this.global.vm().heapSize());
+ }
+
+ pub inline fn autoGarbageCollect(this: *const VirtualMachine) void {
+ if (this.aggressive_garbage_collection != .none) {
+ _ = this.garbageCollect(this.aggressive_garbage_collection == .aggressive);
+ }
+ }
+
pub fn reload(this: *VirtualMachine) void {
Output.debug("Reloading...", .{});
this.global.reload();
@@ -677,9 +722,6 @@ pub const VirtualMachine = struct {
VirtualMachine.vm.bundler.configureLinker();
try VirtualMachine.vm.bundler.configureFramework(false);
- if (VirtualMachine.vm.bundler.env.get("BUN_SHOW_BUN_STACKFRAMES") != null)
- VirtualMachine.vm.hide_bun_stackframes = false;
-
vm.bundler.macro_context = js_ast.Macro.MacroContext.init(&vm.bundler);
if (_args.serve orelse false) {
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 3439e46a4..a9f4b13ac 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -275,7 +275,10 @@ pub const Expect = struct {
.test_id = Jest.runner.?.pending_test.?.test_id,
};
const expect_js_value = expect.toJS(globalObject);
+ expect_js_value.ensureStillAlive();
JSC.Jest.Expect.capturedValueSetCached(expect_js_value, globalObject, value);
+ expect_js_value.ensureStillAlive();
+ expect.postMatch(globalObject);
return expect_js_value;
}
@@ -294,6 +297,7 @@ pub const Expect = struct {
globalObject: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
const thisValue = callframe.this();
const arguments_ = callframe.arguments(1);
const arguments = arguments_.ptr[0..arguments_.len];
@@ -346,6 +350,7 @@ pub const Expect = struct {
globalObject: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
const thisValue = callframe.this();
const arguments_ = callframe.arguments(1);
const arguments = arguments_.ptr[0..arguments_.len];
@@ -431,6 +436,7 @@ pub const Expect = struct {
globalObject: *JSC.JSGlobalObject,
callFrame: *JSC.CallFrame,
) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
const thisValue = callFrame.this();
const arguments_ = callFrame.arguments(1);
const arguments = arguments_.ptr[0..arguments_.len];
@@ -491,6 +497,7 @@ pub const Expect = struct {
}
pub fn toBeTruthy(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Internal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -525,6 +532,7 @@ pub const Expect = struct {
}
pub fn toBeUndefined(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -552,6 +560,8 @@ pub const Expect = struct {
}
pub fn toBeNaN(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
+
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -582,6 +592,8 @@ pub const Expect = struct {
}
pub fn toBeNull(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
+
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -607,6 +619,8 @@ pub const Expect = struct {
}
pub fn toBeDefined(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
+
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
globalObject.throw("Interal consistency error: the expect(value) was garbage collected but it should not have been!", .{});
@@ -632,6 +646,8 @@ pub const Expect = struct {
}
pub fn toBeFalsy(this: *Expect, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ defer this.postMatch(globalObject);
+
const thisValue = callFrame.this();
const value: JSValue = Expect.capturedValueGetCached(thisValue) orelse {
@@ -733,6 +749,11 @@ pub const Expect = struct {
globalObject.throw("Not implemented", .{});
return .zero;
}
+
+ pub fn postMatch(_: *Expect, globalObject: *JSC.JSGlobalObject) void {
+ var vm = globalObject.bunVM();
+ vm.autoGarbageCollect();
+ }
};
pub const TestScope = struct {
@@ -824,13 +845,15 @@ pub const TestScope = struct {
globalThis.bunVM().runErrorHandler(err, null);
var task: *TestRunnerTask = arguments.ptr[1].asPromisePtr(TestRunnerTask);
task.handleResult(.{ .fail = active_test_expectation_counter.actual }, .promise);
+ globalThis.bunVM().autoGarbageCollect();
return JSValue.jsUndefined();
}
- pub fn onResolve(_: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ pub fn onResolve(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
const arguments = callframe.arguments(2);
var task: *TestRunnerTask = arguments.ptr[1].asPromisePtr(TestRunnerTask);
task.handleResult(.{ .pass = active_test_expectation_counter.actual }, .promise);
+ globalThis.bunVM().autoGarbageCollect();
return JSValue.jsUndefined();
}
@@ -840,6 +863,7 @@ pub const TestScope = struct {
) callconv(.C) JSValue {
const function = callframe.callee();
const args = callframe.arguments(1);
+ defer globalThis.bunVM().autoGarbageCollect();
if (JSC.getFunctionData(function)) |data| {
var task = bun.cast(*TestRunnerTask, data);
@@ -866,6 +890,7 @@ pub const TestScope = struct {
defer {
js.JSValueUnprotect(vm.global, callback);
this.callback = null;
+ vm.autoGarbageCollect();
}
JSC.markBinding(@src());
diff --git a/src/bun_js.zig b/src/bun_js.zig
index 2510183aa..07d7e4adf 100644
--- a/src/bun_js.zig
+++ b/src/bun_js.zig
@@ -120,12 +120,7 @@ pub const Run = struct {
}
}
- if (run.vm.bundler.env.map.get("BUN_OVERRIDE_MODULE_PATH")) |override_path| {
- if (override_path.len > 0) {
- run.vm.load_builtins_from_path = override_path;
- }
- }
-
+ run.vm.loadExtraEnv();
run.vm.is_main_thread = true;
JSC.VirtualMachine.is_main_thread_vm = true;
diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig
index 3f0082940..9211be7f3 100644
--- a/src/cli/test_command.zig
+++ b/src/cli/test_command.zig
@@ -332,12 +332,7 @@ pub const TestCommand = struct {
try vm.bundler.configureDefines();
vm.bundler.options.rewrite_jest_for_tests = true;
- if (vm.bundler.env.map.get("BUN_OVERRIDE_MODULE_PATH")) |override_path| {
- if (override_path.len > 0) {
- vm.load_builtins_from_path = override_path;
- }
- }
-
+ vm.loadExtraEnv();
vm.is_main_thread = true;
JSC.VirtualMachine.is_main_thread_vm = true;