Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make GC smarter #17919

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
17 changes: 13 additions & 4 deletions packages/bun-usockets/src/eventing/epoll_kqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ void us_loop_run(struct us_loop_t *loop) {
}

extern void Bun__JSC_onBeforeWait(void*);
extern void Bun__JSC_onAfterWait(void*);
extern void Bun__JSC_onAfterWait(void*, bool hasMoreEventLoopWorkToDo);
extern void Bun__JSC_onDidRunCallbacks(void*);

void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout) {
if (loop->num_polls == 0)
Expand All @@ -265,8 +266,10 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
/* Emit pre callback */
us_internal_loop_pre(loop);

/* Safe if jsc_vm is NULL */
Bun__JSC_onBeforeWait(loop->data.jsc_vm);
void* jsc_vm = loop->data.jsc_vm;
if (jsc_vm) {
Bun__JSC_onBeforeWait(jsc_vm);
}

/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
Expand All @@ -278,7 +281,9 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
} while (IS_EINTR(loop->num_ready_polls));
#endif

Bun__JSC_onAfterWait(loop->data.jsc_vm);
if (jsc_vm) {
Bun__JSC_onAfterWait(jsc_vm, loop->num_ready_polls > 0);
}

/* Iterate ready polls, dispatching them by type */
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {
Expand Down Expand Up @@ -318,6 +323,10 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
}
}

if (jsc_vm) {
Bun__JSC_onDidRunCallbacks(jsc_vm);
}

/* Emit post callback */
us_internal_loop_post(loop);
}
Expand Down
2 changes: 1 addition & 1 deletion src/bake/BakeGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ extern "C" GlobalObject* BakeCreateProdGlobal(void* console)
vm.heap.acquireAccess();
JSC::JSLockHolder locker(vm);
BunVirtualMachine* bunVM = Bun__getVM();
WebCore::JSVMClientData::create(&vm, bunVM);
WebCore::JSVMClientData::create(vm, bunVM, JSC::HeapType::Large);

JSC::Structure* structure = Bake::GlobalObject::createStructure(vm);
Bake::GlobalObject* global = Bake::GlobalObject::create(
Expand Down
41 changes: 41 additions & 0 deletions src/bun.js/GCController.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const std = @import("std");
const bun = @import("root").bun;
const JSC = bun.JSC;
const VM = JSC.VM;

pub export fn Bun__isBusyDoingImportantWork(vm: *JSC.VirtualMachine) bool {
const loop = vm.eventLoop();
return loop.is_doing_something_important or
loop.tasks.count > 0 or
loop.immediate_tasks.count > 0 or loop.next_immediate_tasks.count > 0 or
loop.concurrent_tasks.peek() > 0;
}

// Wrapper for the Bun::GCController C++ class
pub const GCController = opaque {
pub export fn Bun__GCController__setup(ptr: *GCController) void {
const vm = JSC.VirtualMachine.get();
vm.gc_controller = ptr;
}

pub fn performGC(this: *GCController) void {
this.performOpportunisticGC();
}

extern "c" fn Bun__GCController__initialize(controller: *GCController) void;
extern "c" fn Bun__GCController__get(vm: *VM) *GCController;
extern "c" fn Bun__GCController__performOpportunisticGC(controller: *GCController) void;
extern "c" fn Bun__GCController__getMetrics(controller: *GCController, incrementalSweepCount: ?*usize, edenGCCount: ?*usize, fullGCCount: ?*usize, totalSweepTimeMs: ?*f64, maxSweepTimeMs: ?*f64) void;

fn get(vm: *VM) *GCController {
return Bun__GCController__get(vm);
}

pub fn performOpportunisticGC(this: *GCController) void {
Bun__GCController__performOpportunisticGC(this);
}

pub fn getMetrics(this: *GCController, incrementalSweepCount: ?*usize, edenGCCount: ?*usize, fullGCCount: ?*usize, totalSweepTimeMs: ?*f64, maxSweepTimeMs: ?*f64) void {
Bun__GCController__getMetrics(this, incrementalSweepCount, edenGCCount, fullGCCount, totalSweepTimeMs, maxSweepTimeMs);
}
};
12 changes: 11 additions & 1 deletion src/bun.js/api/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7556,7 +7556,11 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp

pub fn onUserRouteRequest(user_route: *UserRoute, req: *uws.Request, resp: *App.Response) void {
const server = user_route.server;
const vm = server.vm;
const index = user_route.id;
const important = vm.eventLoop().important();
important.enter();
defer important.exit();

var should_deinit_context = false;
var prepared = server.prepareJsRequestContext(req, resp, &should_deinit_context, false) orelse return;
Expand Down Expand Up @@ -7603,7 +7607,9 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp
pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
var should_deinit_context = false;
const prepared = this.prepareJsRequestContext(req, resp, &should_deinit_context, true) orelse return;

const important = this.vm.eventLoop().important();
important.enter();
defer important.exit();
bun.assert(this.config.onRequest != .zero);

const js_value = this.jsValueAssertAlive();
Expand Down Expand Up @@ -7804,6 +7810,10 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp
fn upgradeWebSocketUserRoute(this: *UserRoute, resp: *App.Response, req: *uws.Request, upgrade_ctx: *uws.uws_socket_context_t) void {
const server = this.server;
const index = this.id;
const vm = server.vm;
const important = vm.eventLoop().important();
important.enter();
defer important.exit();

var should_deinit_context = false;
var prepared = server.prepareJsRequestContext(req, resp, &should_deinit_context, false) orelse return;
Expand Down
23 changes: 12 additions & 11 deletions src/bun.js/bindings/BunClientData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,16 @@ JSHeapData::JSHeapData(Heap& heap)

#define CLIENT_ISO_SUBSPACE_INIT(subspace) subspace(m_heapData->subspace)

JSVMClientData::JSVMClientData(VM& vm, RefPtr<SourceProvider> sourceProvider)
JSVMClientData::JSVMClientData(VM& vm, void* bunVM, RefPtr<SourceProvider> sourceProvider, JSC::HeapType heapType)
: m_builtinNames(vm)
, m_builtinFunctions(vm, sourceProvider, m_builtinNames)
, m_heapData(JSHeapData::ensureHeapData(vm.heap))
, CLIENT_ISO_SUBSPACE_INIT(m_domBuiltinConstructorSpace)
, CLIENT_ISO_SUBSPACE_INIT(m_domConstructorSpace)
, CLIENT_ISO_SUBSPACE_INIT(m_domNamespaceObjectSpace)
, m_clientSubspaces(makeUnique<ExtendedDOMClientIsoSubspaces>())
, m_gcController(vm, bunVM, heapType)
, bunVM(bunVM)
{
}

Expand All @@ -77,26 +79,25 @@ JSVMClientData::~JSVMClientData()
ASSERT(m_normalWorld->hasOneRef());
m_normalWorld = nullptr;
}
void JSVMClientData::create(VM* vm, void* bunVM)
void JSVMClientData::create(VM& vm, void* bunVM, JSC::HeapType heapType)
{
auto provider = WebCore::createBuiltinsSourceProvider();
JSVMClientData* clientData = new JSVMClientData(*vm, provider);
clientData->bunVM = bunVM;
vm->deferredWorkTimer->onAddPendingWork = [clientData](Ref<JSC::DeferredWorkTimer::TicketData>&& ticket, JSC::DeferredWorkTimer::WorkType kind) -> void {
JSVMClientData* clientData = new JSVMClientData(vm, bunVM, provider, heapType);
vm.deferredWorkTimer->onAddPendingWork = [clientData](Ref<JSC::DeferredWorkTimer::TicketData>&& ticket, JSC::DeferredWorkTimer::WorkType kind) -> void {
Bun::JSCTaskScheduler::onAddPendingWork(clientData, WTFMove(ticket), kind);
};
vm->deferredWorkTimer->onScheduleWorkSoon = [clientData](JSC::DeferredWorkTimer::Ticket ticket, JSC::DeferredWorkTimer::Task&& task) -> void {
vm.deferredWorkTimer->onScheduleWorkSoon = [clientData](JSC::DeferredWorkTimer::Ticket ticket, JSC::DeferredWorkTimer::Task&& task) -> void {
Bun::JSCTaskScheduler::onScheduleWorkSoon(clientData, ticket, WTFMove(task));
};
vm->deferredWorkTimer->onCancelPendingWork = [clientData](JSC::DeferredWorkTimer::Ticket ticket) -> void {
vm.deferredWorkTimer->onCancelPendingWork = [clientData](JSC::DeferredWorkTimer::Ticket ticket) -> void {
Bun::JSCTaskScheduler::onCancelPendingWork(clientData, ticket);
};

vm->clientData = clientData; // ~VM deletes this pointer.
clientData->m_normalWorld = DOMWrapperWorld::create(*vm, DOMWrapperWorld::Type::Normal);
vm.clientData = clientData; // ~VM deletes this pointer.
clientData->m_normalWorld = DOMWrapperWorld::create(vm, DOMWrapperWorld::Type::Normal);

vm->heap.addMarkingConstraint(makeUnique<WebCore::DOMGCOutputConstraint>(*vm, clientData->heapData()));
vm->m_typedArrayController = adoptRef(new WebCoreTypedArrayController(true));
vm.heap.addMarkingConstraint(makeUnique<WebCore::DOMGCOutputConstraint>(vm, clientData->heapData()));
vm.m_typedArrayController = adoptRef(new WebCoreTypedArrayController(true));
clientData->builtinFunctions().exportNames();
}

Expand Down
12 changes: 8 additions & 4 deletions src/bun.js/bindings/BunClientData.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class DOMWrapperWorld;
#include <wtf/StdLibExtras.h>
#include "WebCoreJSBuiltins.h"
#include "JSCTaskScheduler.h"

#include "BunGCController.h"
namespace Zig {
}

Expand Down Expand Up @@ -79,11 +79,9 @@ class JSVMClientData : public JSC::VM::ClientData {
WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(JSVMClientData);

public:
explicit JSVMClientData(JSC::VM&, RefPtr<JSC::SourceProvider>);

virtual ~JSVMClientData();

static void create(JSC::VM*, void*);
static void create(JSC::VM& vm, void* bunVM, JSC::HeapType heapType);

JSHeapData& heapData() { return *m_heapData; }
BunBuiltinNames& builtinNames() { return m_builtinNames; }
Expand Down Expand Up @@ -113,7 +111,11 @@ class JSVMClientData : public JSC::VM::ClientData {
void* bunVM;
Bun::JSCTaskScheduler deferredWorkTimer;

Bun::GCController& gcController() { return m_gcController; }

private:
explicit JSVMClientData(JSC::VM&, void* bunVM, RefPtr<JSC::SourceProvider>, JSC::HeapType heapType);

bool isWebCoreJSClientData() const final { return true; }

BunBuiltinNames m_builtinNames;
Expand All @@ -128,6 +130,8 @@ class JSVMClientData : public JSC::VM::ClientData {

std::unique_ptr<ExtendedDOMClientIsoSubspaces> m_clientSubspaces;
Vector<JSC::IsoSubspace*> m_outputConstraintSpaces;

Bun::GCController m_gcController;
};

} // namespace WebCore
Expand Down
Loading