From d6a58d4938d497d6569e7cffecd565ba7270aaf2 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 1 Jul 2026 17:05:10 -0700 Subject: [PATCH 1/4] perf(v8-runtime): drain setImmediate in-isolate instead of kernel-timer round trips --- crates/execution/tests/javascript_v8.rs | 110 +++++++++++++- crates/v8-runtime/src/session.rs | 141 ++++++++++++++++-- .../build-tools/bridge-src/builtins/timers.ts | 75 ++++++++-- .../build-tools/bridge-src/global-exposure.ts | 10 ++ .../build-tools/scripts/build-v8-bridge.mjs | 2 + 5 files changed, 317 insertions(+), 21 deletions(-) diff --git a/crates/execution/tests/javascript_v8.rs b/crates/execution/tests/javascript_v8.rs index 4ae27b199..4fd9e884b 100644 --- a/crates/execution/tests/javascript_v8.rs +++ b/crates/execution/tests/javascript_v8.rs @@ -2462,7 +2462,7 @@ fn javascript_execution_v8_timer_callbacks_fire_and_clear_correctly() { limits: Default::default(), guest_runtime: Default::default(), vm_id: String::from("vm-js"), - context_id: context.context_id, + context_id: context.context_id.clone(), argv: vec![String::from("./entry.js")], env: BTreeMap::new(), cwd: temp.path().to_path_buf(), @@ -2494,6 +2494,62 @@ fn javascript_execution_v8_timer_callbacks_fire_and_clear_correctly() { if (intervalTicks !== 2) { throw new Error(`interval tick count mismatch: ${intervalTicks}`); } + + let immediateFired = false; + await new Promise((resolve) => { + setImmediate(() => { + immediateFired = true; + resolve(); + }); + }); + if (!immediateFired) { + throw new Error("setImmediate callback did not fire"); + } + + const order = []; + setImmediate(() => order.push("immediate")); + queueMicrotask(() => order.push("microtask")); + await new Promise((resolve) => setImmediate(resolve)); + if (order.join(",") !== "microtask,immediate") { + throw new Error(`unexpected immediate order: ${order.join(",")}`); + } + + for (let i = 0; i < 100; i += 1) { + await new Promise((resolve) => setImmediate(resolve)); + } + + let clearedImmediateFired = false; + const clearedImmediate = setImmediate(() => { + clearedImmediateFired = true; + }); + clearImmediate(clearedImmediate); + await new Promise((resolve) => setImmediate(resolve)); + if (clearedImmediateFired) { + throw new Error("cleared immediate fired"); + } + + const { setImmediate: promiseImmediate } = await import("node:timers/promises"); + const promiseImmediateValue = await promiseImmediate("promise-value"); + if (promiseImmediateValue !== "promise-value") { + throw new Error(`timers/promises setImmediate mismatch: ${promiseImmediateValue}`); + } + + const t0 = Date.now(); + let chainCount = 0; + const immediateChainMs = await new Promise((resolve) => { + function tick() { + if (++chainCount < 1000) { + setImmediate(tick); + } else { + resolve(Date.now() - t0); + } + } + setImmediate(tick); + }); + if (immediateChainMs >= 500) { + throw new Error(`setImmediate chain too slow: ${immediateChainMs}ms`); + } + console.log(`setImmediate-chain-ms=${immediateChainMs}`); })().catch((error) => { process.exitCode = 1; throw error; @@ -2508,6 +2564,58 @@ fn javascript_execution_v8_timer_callbacks_fire_and_clear_correctly() { let stderr = String::from_utf8(result.stderr.clone()).expect("stderr utf8"); assert_eq!(result.exit_code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); assert!(stderr.is_empty(), "unexpected stderr: {stderr}"); + let chain_ms_line = stdout + .lines() + .find(|line| line.starts_with("setImmediate-chain-ms=")) + .expect("setImmediate timing line"); + let chain_ms: u64 = chain_ms_line + .trim_start_matches("setImmediate-chain-ms=") + .parse() + .expect("parse setImmediate timing"); + println!("setImmediate 1000-chain elapsed ms: {chain_ms}"); + assert!( + chain_ms < 500, + "setImmediate 1000-chain elapsed too high: {chain_ms}ms" + ); + + let only_immediate_execution = engine + .start_execution(StartJavascriptExecutionRequest { + limits: Default::default(), + guest_runtime: Default::default(), + vm_id: String::from("vm-js"), + context_id: context.context_id.clone(), + argv: vec![String::from("./entry.js")], + env: BTreeMap::new(), + cwd: temp.path().to_path_buf(), + inline_code: Some(String::from( + r#" +setImmediate(() => { + console.log("only-immediate-fired"); +}); +"#, + )), + }) + .expect("start only-immediate JavaScript execution"); + + let only_immediate_result = only_immediate_execution + .wait() + .expect("wait for only-immediate JavaScript execution"); + let only_immediate_stdout = + String::from_utf8(only_immediate_result.stdout.clone()).expect("stdout utf8"); + let only_immediate_stderr = + String::from_utf8(only_immediate_result.stderr.clone()).expect("stderr utf8"); + assert_eq!( + only_immediate_result.exit_code, 0, + "stdout:\n{only_immediate_stdout}\nstderr:\n{only_immediate_stderr}" + ); + assert!( + only_immediate_stdout.contains("only-immediate-fired"), + "only pending setImmediate did not fire; stdout:\n{only_immediate_stdout}" + ); + assert!( + only_immediate_stderr.is_empty(), + "unexpected stderr: {only_immediate_stderr}" + ); } fn javascript_execution_v8_readline_polyfill_emits_lines() { diff --git a/crates/v8-runtime/src/session.rs b/crates/v8-runtime/src/session.rs index 27363ee6e..877290fdb 100644 --- a/crates/v8-runtime/src/session.rs +++ b/crates/v8-runtime/src/session.rs @@ -1618,6 +1618,7 @@ pub fn run_event_loop( || execution::pending_module_evaluation_needs_wait(scope) || execution::pending_script_evaluation_needs_wait(scope) || pending_guest_timer_count(scope) > 0 + || pending_guest_immediate_count(scope) > 0 || deferred .map(|dq| !dq.lock().unwrap().is_empty()) .unwrap_or(false) @@ -1637,6 +1638,7 @@ pub fn run_event_loop( && !execution::pending_module_evaluation_needs_wait(scope) && !execution::pending_script_evaluation_needs_wait(scope) && pending_guest_timer_count(scope) == 0 + && pending_guest_immediate_count(scope) == 0 { break; } @@ -1656,12 +1658,33 @@ pub fn run_event_loop( } } + if pending_guest_immediate_count(scope) > 0 { + match try_recv_session_command(scope, rx, abort_rx) { + Ok(Some(cmd)) => { + let status = dispatch_session_command(scope, cmd, pending); + if !matches!(status, EventLoopStatus::Completed) { + return status; + } + } + Ok(None) => { + let status = drain_guest_immediates(scope); + if !matches!(status, EventLoopStatus::Completed) { + return status; + } + } + Err(status) => return status, + } + scope.perform_microtask_checkpoint(); + pump_v8_message_loop(scope); + } + // Re-check exit conditions after microtask flush — the microtask may // have resolved all pending promises or registered new handles. if pending.is_empty() && !execution::pending_module_evaluation_needs_wait(scope) && !execution::pending_script_evaluation_needs_wait(scope) && pending_guest_timer_count(scope) == 0 + && pending_guest_immediate_count(scope) == 0 && deferred .map(|dq| dq.lock().unwrap().is_empty()) .unwrap_or(true) @@ -1673,6 +1696,21 @@ pub fn run_event_loop( // Instead of blocking indefinitely, use a short timeout so we can // periodically flush microtasks (like Node.js's libuv + DrainTasks pattern). let cmd = loop { + if pending_guest_immediate_count(scope) > 0 { + match try_recv_session_command(scope, rx, abort_rx) { + Ok(Some(cmd)) => break cmd, + Ok(None) => { + let status = drain_guest_immediates(scope); + if !matches!(status, EventLoopStatus::Completed) { + return status; + } + scope.perform_microtask_checkpoint(); + pump_v8_message_loop(scope); + continue; + } + Err(status) => return status, + } + } let recv_result = if let Some(abort) = abort_rx { crossbeam_channel::select! { recv(rx) -> result => result.ok(), @@ -1708,6 +1746,7 @@ pub fn run_event_loop( && !execution::pending_module_evaluation_needs_wait(scope) && !execution::pending_script_evaluation_needs_wait(scope) && pending_guest_timer_count(scope) == 0 + && pending_guest_immediate_count(scope) == 0 && deferred .map(|dq| dq.lock().unwrap().is_empty()) .unwrap_or(true) @@ -1716,22 +1755,52 @@ pub fn run_event_loop( } }; - match cmd { - SessionCommand::Message(frame) => { - let status = dispatch_event_loop_frame(scope, frame, pending); - if !matches!(status, EventLoopStatus::Completed) { - return status; - } - } - SessionCommand::SetModuleReader(reader) => { - execution::install_session_guest_reader(Some(reader)); - } - SessionCommand::Shutdown => return EventLoopStatus::Terminated, + let status = dispatch_session_command(scope, cmd, pending); + if !matches!(status, EventLoopStatus::Completed) { + return status; } } EventLoopStatus::Completed } +fn try_recv_session_command( + scope: &mut v8::HandleScope, + rx: &Receiver, + abort_rx: Option<&crossbeam_channel::Receiver<()>>, +) -> Result, EventLoopStatus> { + if let Some(abort) = abort_rx { + crossbeam_channel::select! { + recv(abort) -> _ => { + scope.terminate_execution(); + Err(EventLoopStatus::Terminated) + }, + recv(rx) -> result => Ok(result.ok()), + default => Ok(None), + } + } else { + match rx.try_recv() { + Ok(cmd) => Ok(Some(cmd)), + Err(crossbeam_channel::TryRecvError::Empty) => Ok(None), + Err(crossbeam_channel::TryRecvError::Disconnected) => Ok(None), + } + } +} + +fn dispatch_session_command( + scope: &mut v8::HandleScope, + cmd: SessionCommand, + pending: &crate::bridge::PendingPromises, +) -> EventLoopStatus { + match cmd { + SessionCommand::Message(frame) => dispatch_event_loop_frame(scope, frame, pending), + SessionCommand::SetModuleReader(reader) => { + execution::install_session_guest_reader(Some(reader)); + EventLoopStatus::Completed + } + SessionCommand::Shutdown => EventLoopStatus::Terminated, + } +} + fn pending_guest_timer_count(scope: &mut v8::HandleScope) -> usize { let tc = &mut v8::TryCatch::new(scope); let context = tc.get_current_context(); @@ -1756,6 +1825,56 @@ fn pending_guest_timer_count(scope: &mut v8::HandleScope) -> usize { .unwrap_or(0) } +fn pending_guest_immediate_count(scope: &mut v8::HandleScope) -> usize { + let tc = &mut v8::TryCatch::new(scope); + let context = tc.get_current_context(); + let global = context.global(tc); + let key = match v8::String::new(tc, "_getPendingImmediateCount") { + Some(key) => key, + None => return 0, + }; + let Some(func_value) = global.get(tc, key.into()) else { + return 0; + }; + let Ok(func) = v8::Local::::try_from(func_value) else { + return 0; + }; + let Some(result) = func.call(tc, global.into(), &[]) else { + return 0; + }; + + result + .integer_value(tc) + .and_then(|count| usize::try_from(count).ok()) + .unwrap_or(0) +} + +fn drain_guest_immediates(scope: &mut v8::HandleScope) -> EventLoopStatus { + let tc = &mut v8::TryCatch::new(scope); + let context = tc.get_current_context(); + let global = context.global(tc); + let key = match v8::String::new(tc, "_drainImmediates") { + Some(key) => key, + None => return EventLoopStatus::Completed, + }; + let Some(func_value) = global.get(tc, key.into()) else { + return EventLoopStatus::Completed; + }; + let Ok(func) = v8::Local::::try_from(func_value) else { + return EventLoopStatus::Completed; + }; + let _ = func.call(tc, global.into(), &[]); + tc.perform_microtask_checkpoint(); + if let Some(exception) = tc.exception() { + let (code, err) = execution::exception_to_result(tc, exception); + return EventLoopStatus::Failed(code, err); + } + if let Some(err) = execution::take_unhandled_promise_rejection(tc) { + return EventLoopStatus::Failed(1, err); + } + EventLoopStatus::Completed +} + fn pump_v8_message_loop(scope: &mut v8::HandleScope) { let platform = v8::V8::get_current_platform(); while v8::Platform::pump_message_loop(&platform, scope, false) { diff --git a/packages/build-tools/bridge-src/builtins/timers.ts b/packages/build-tools/bridge-src/builtins/timers.ts index 3f8c5d43d..350b94464 100644 --- a/packages/build-tools/bridge-src/builtins/timers.ts +++ b/packages/build-tools/bridge-src/builtins/timers.ts @@ -337,6 +337,10 @@ var TimerHandle = class { var _timerEntries = /* @__PURE__ */ new Map(); +var _immediateEntries = /* @__PURE__ */ new Map(); + +var _nextImmediateId = -1; + var _timerDrainResolvers = []; function getRefedTimerCount() { @@ -352,8 +356,19 @@ function getRefedTimerCount() { return count; } +function getPendingImmediateCount() { + if (typeof _exited !== "undefined" && _exited) { + return 0; + } + return _immediateEntries.size; +} + +function getPendingTimerDrainCount() { + return getRefedTimerCount() + getPendingImmediateCount(); +} + function checkTimerDrain() { - if (getRefedTimerCount() === 0 && _timerDrainResolvers.length > 0) { + if (getPendingTimerDrainCount() === 0 && _timerDrainResolvers.length > 0) { const resolvers = _timerDrainResolvers; _timerDrainResolvers = []; resolvers.forEach((r) => r()); @@ -361,11 +376,15 @@ function checkTimerDrain() { } function _getPendingTimerCount() { - return getRefedTimerCount(); + return getPendingTimerDrainCount(); +} + +function _getPendingImmediateCount() { + return getPendingImmediateCount(); } function _waitForTimerDrain() { - if (getRefedTimerCount() === 0) return Promise.resolve(); + if (getPendingTimerDrainCount() === 0) return Promise.resolve(); return new Promise((resolve) => { _timerDrainResolvers.push(resolve); checkTimerDrain(); @@ -488,25 +507,63 @@ function clearInterval(timer) { exposeCustomGlobal("_timerDispatch", timerDispatch); +function _drainImmediates() { + const entries = Array.from(_immediateEntries.entries()); + for (const [immediateId, entry] of entries) { + if (_immediateEntries.get(immediateId) !== entry) { + continue; + } + entry.handle._destroyed = true; + _immediateEntries.delete(immediateId); + try { + entry.callback(...entry.args); + } catch (error) { + const outcome = routeAsyncCallbackError(error); + if (!outcome.handled && outcome.rethrow !== null) { + throw outcome.rethrow; + } + return; + } + if (typeof _exited !== "undefined" && _exited) { + checkTimerDrain(); + return; + } + } + checkTimerDrain(); +} + exposeCustomGlobal("_getPendingTimerCount", _getPendingTimerCount); +exposeCustomGlobal("_drainImmediates", _drainImmediates); + +exposeCustomGlobal("_getPendingImmediateCount", _getPendingImmediateCount); + exposeCustomGlobal("_waitForTimerDrain", _waitForTimerDrain); function setImmediate(callback, ...args) { - const id = createKernelTimer(0, false); + const id = _nextImmediateId--; const handle = new TimerHandle(id); const asyncLocalStorageSnapshot = snapshotAsyncLocalStorageStores(); - _timerEntries.set(id, { + _immediateEntries.set(id, { handle, callback: wrapAsyncLocalStorageCallback(callback, asyncLocalStorageSnapshot), args, repeat: false }); - armKernelTimer(id); return handle; } -function clearImmediate(id) { - clearTimeout2(id); +function clearImmediate(timer) { + const id = getTimerId(timer); + if (id === void 0) return; + const entry = _immediateEntries.get(id); + if (entry) { + entry.handle._destroyed = true; + _immediateEntries.delete(id); + checkTimerDrain(); + return; + } + if (id < 0) return; + clearTimeout2(timer); } -export { TIMER_DISPATCH, TimerHandle, _getPendingTimerCount, _nextTickQueue, _nextTickScheduled, _queueMicrotask, _timerDrainResolvers, _timerEntries, _waitForTimerDrain, applyAsyncLocalStorageSnapshot, armKernelTimer, asyncLocalStorageInstances, builtinAsyncHooksModule, builtinTimersPromisesModule, checkTimerDrain, clearImmediate, clearInterval, clearTimeout2, createKernelTimer, flushNextTickQueue, getRefedTimerCount, getTimerId, normalizeTimerDelay, runWithAsyncLocalStorageSnapshot, scheduleNextTickFlush, setImmediate, setInterval, setTimeout2, snapshotAsyncLocalStorageStores, timerDispatch, wrapAsyncLocalStorageCallback }; +export { TIMER_DISPATCH, TimerHandle, _drainImmediates, _getPendingImmediateCount, _getPendingTimerCount, _immediateEntries, _nextImmediateId, _nextTickQueue, _nextTickScheduled, _queueMicrotask, _timerDrainResolvers, _timerEntries, _waitForTimerDrain, applyAsyncLocalStorageSnapshot, armKernelTimer, asyncLocalStorageInstances, builtinAsyncHooksModule, builtinTimersPromisesModule, checkTimerDrain, clearImmediate, clearInterval, clearTimeout2, createKernelTimer, flushNextTickQueue, getPendingImmediateCount, getPendingTimerDrainCount, getRefedTimerCount, getTimerId, normalizeTimerDelay, runWithAsyncLocalStorageSnapshot, scheduleNextTickFlush, setImmediate, setInterval, setTimeout2, snapshotAsyncLocalStorageStores, timerDispatch, wrapAsyncLocalStorageCallback }; diff --git a/packages/build-tools/bridge-src/global-exposure.ts b/packages/build-tools/bridge-src/global-exposure.ts index cf3dc9159..4fec6138a 100644 --- a/packages/build-tools/bridge-src/global-exposure.ts +++ b/packages/build-tools/bridge-src/global-exposure.ts @@ -165,6 +165,16 @@ var NODE_CUSTOM_GLOBAL_INVENTORY = [ classification: "hardened", rationale: "Host-to-sandbox timer callback dispatch entrypoint." }, + { + name: "_drainImmediates", + classification: "hardened", + rationale: "Runtime-owned setImmediate queue drain entrypoint." + }, + { + name: "_getPendingImmediateCount", + classification: "hardened", + rationale: "Runtime-owned setImmediate pending-work counter." + }, { name: "_upgradeSocketData", classification: "hardened", diff --git a/packages/build-tools/scripts/build-v8-bridge.mjs b/packages/build-tools/scripts/build-v8-bridge.mjs index 54718a21f..21b430886 100644 --- a/packages/build-tools/scripts/build-v8-bridge.mjs +++ b/packages/build-tools/scripts/build-v8-bridge.mjs @@ -216,6 +216,8 @@ async function validateBridgeContractGlobals(sourceText) { "_httpServerConnectDispatch", "_http2Dispatch", "_timerDispatch", + "_drainImmediates", + "_getPendingImmediateCount", "_upgradeSocketData", "_upgradeSocketEnd", "ProcessExitError", From 1dc0dd43d79318b1e14dcb338377a11d1d8cbd4c Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 1 Jul 2026 17:29:52 -0700 Subject: [PATCH 2/4] perf(v8-runtime): same-isolate wake parity for unix-domain sockets and dgram --- crates/execution/tests/javascript_v8.rs | 2 +- .../build-tools/bridge-src/builtins/dgram.ts | 106 +++++++++++++++++- .../build-tools/bridge-src/builtins/net.ts | 87 ++++++++++++-- 3 files changed, 183 insertions(+), 12 deletions(-) diff --git a/crates/execution/tests/javascript_v8.rs b/crates/execution/tests/javascript_v8.rs index 4fd9e884b..8d983d68c 100644 --- a/crates/execution/tests/javascript_v8.rs +++ b/crates/execution/tests/javascript_v8.rs @@ -2165,7 +2165,7 @@ if (summary.rinfo.address !== "127.0.0.1" || summary.rinfo.port !== 7) { let request = expect_next_sync_rpc(&mut execution, "poll dgram.poll request"); assert_eq!(request.method, "dgram.poll"); - assert_eq!(request.args, vec![json!("udp-1"), json!(10)]); + assert_eq!(request.args, vec![json!("udp-1"), json!(0)]); execution .respond_sync_rpc_success(request.id, json!(null)) .expect("respond to initial dgram.poll"); diff --git a/packages/build-tools/bridge-src/builtins/dgram.ts b/packages/build-tools/bridge-src/builtins/dgram.ts index 3bfdc3521..196af7c60 100644 --- a/packages/build-tools/bridge-src/builtins/dgram.ts +++ b/packages/build-tools/bridge-src/builtins/dgram.ts @@ -1,10 +1,69 @@ import { exposeCustomGlobal } from "../global-exposure.js"; import { createErrorWithCode, createInvalidArgTypeError2, createTypeErrorWithCode, formatReceivedType } from "./http.js"; -import { NET_BRIDGE_POLL_DELAY_MS, NET_BRIDGE_TIMEOUT_SENTINEL, createFunctionArgTypeError, createSocketBadPortError, isIPv4String, isIPv6String, isValidTcpPort } from "./net.js"; +import { NET_BRIDGE_POLL_DELAY_MS, NET_BRIDGE_TIMEOUT_SENTINEL, countNetBridgeMetric, createFunctionArgTypeError, createSocketBadPortError, isIPv4String, isIPv6String, isValidTcpPort } from "./net.js"; import { tlsModule } from "./tls.js"; var DGRAM_HANDLE_PREFIX = "dgram-socket:"; +var registeredDgramSocketsByPort = /* @__PURE__ */ new Map(); + +function registerDgramSocket(socket) { + const port = socket?._localPort; + if (typeof port !== "number") { + return; + } + let sockets = registeredDgramSocketsByPort.get(port); + if (!sockets) { + sockets = /* @__PURE__ */ new Set(); + registeredDgramSocketsByPort.set(port, sockets); + } + sockets.add(socket); +} + +function unregisterDgramSocket(socket) { + const port = socket?._localPort; + if (typeof port !== "number") { + return; + } + const sockets = registeredDgramSocketsByPort.get(port); + if (!sockets) { + return; + } + sockets.delete(socket); + if (sockets.size === 0) { + registeredDgramSocketsByPort.delete(port); + } +} + +function isDgramLoopbackAddress(address) { + return address === "127.0.0.1" || address === "::1" || address === "localhost"; +} + +function wakeDgramSocketReads(socket) { + countNetBridgeMetric("dgramWakeAttempts"); + if (!socket || socket._closed || !socket._bound) { + countNetBridgeMetric("dgramWakeInvalidTargets"); + return; + } + if (socket._receiveLoopRunning) { + countNetBridgeMetric("dgramWakeAlreadyRunning"); + return; + } + if (!socket._receivePollTimer) { + countNetBridgeMetric("dgramWakeNoTimer"); + return; + } + clearTimeout(socket._receivePollTimer); + socket._receivePollTimer = null; + countNetBridgeMetric("dgramEventWakeups"); + queueMicrotask(() => { + if (!socket._closed && socket._bound) { + socket._nextReceivePumpOrigin = "eventWake"; + void socket._pumpMessages(); + } + }); +} + function createBadDgramSocketTypeError() { return createTypeErrorWithCode( "Bad socket type specified. Valid types are: udp4, udp6", @@ -374,10 +433,14 @@ var DgramSocket = class { _bindPromise = null; _receiveLoopRunning = false; _receivePollTimer = null; + _nextReceivePumpOrigin = null; _refed = true; _closed = false; _bound = false; _handleRefId = null; + _localAddress; + _localPort; + _localFamily; _recvBufferSize; _sendBufferSize; _memberships = /* @__PURE__ */ new Set(); @@ -441,6 +504,7 @@ var DgramSocket = class { return this; } this._closed = true; + unregisterDgramSocket(this); this._bound = false; this._clearReceivePollTimer(); this._syncHandleRef(); @@ -672,11 +736,13 @@ var DgramSocket = class { } this._bindPromise = (async () => { try { - normalizeDgramBridgeResult(_dgramSocketBindRaw.applySyncPromise(void 0, [ + const result = normalizeDgramBridgeResult(_dgramSocketBindRaw.applySyncPromise(void 0, [ this._socketId, { port, address } ])); + this._applyBoundAddress(result); this._bound = true; + registerDgramSocket(this); this._applyInitialBufferSizes(); this._syncHandleRef(); queueMicrotask(() => { @@ -685,6 +751,7 @@ var DgramSocket = class { } this._emit("listening"); callback?.call(this); + this._nextReceivePumpOrigin = "bind"; void this._pumpMessages(); }); } catch (error) { @@ -719,6 +786,18 @@ var DgramSocket = class { data, { port, address } ])); + this._applyBoundAddress(result); + if (isDgramLoopbackAddress(address)) { + const sockets = registeredDgramSocketsByPort.get(port); + if (sockets) { + countNetBridgeMetric("dgramWakeLoopbackHits"); + for (const socket of sockets) { + wakeDgramSocketReads(socket); + } + } else { + countNetBridgeMetric("dgramWakeLoopbackMisses"); + } + } if (callback) { queueMicrotask(() => { callback(null, typeof result?.bytes === "number" ? result.bytes : data.length); @@ -743,15 +822,19 @@ var DgramSocket = class { if (typeof _dgramSocketRecvRaw === "undefined") { return; } + const pumpOrigin = this._nextReceivePumpOrigin; + this._nextReceivePumpOrigin = null; + const waitMs = pumpOrigin === "timer" ? NET_BRIDGE_POLL_DELAY_MS : 0; this._receiveLoopRunning = true; try { while (!this._closed && this._bound) { const payload = normalizeDgramBridgeResult( - _dgramSocketRecvRaw.applySync(void 0, [this._socketId, NET_BRIDGE_POLL_DELAY_MS]) + _dgramSocketRecvRaw.applySync(void 0, [this._socketId, waitMs]) ); if (payload === NET_BRIDGE_TIMEOUT_SENTINEL || !payload) { this._receivePollTimer = setTimeout(() => { this._receivePollTimer = null; + this._nextReceivePumpOrigin = "timer"; void this._pumpMessages(); }, NET_BRIDGE_POLL_DELAY_MS); if (!this._refed && typeof this._receivePollTimer.unref === "function") { @@ -785,6 +868,23 @@ var DgramSocket = class { this._receiveLoopRunning = false; } } + _applyBoundAddress(info) { + if (!info || typeof info !== "object") { + return; + } + const port = typeof info.localPort === "number" ? info.localPort : info.port; + if (typeof port === "number") { + this._localPort = port; + } + const address = typeof info.localAddress === "string" ? info.localAddress : info.address; + if (typeof address === "string") { + this._localAddress = address; + } + const family = typeof info.localFamily === "string" ? info.localFamily : info.family; + if (typeof family === "string") { + this._localFamily = family; + } + } _clearReceivePollTimer() { if (this._receivePollTimer) { clearTimeout(this._receivePollTimer); diff --git a/packages/build-tools/bridge-src/builtins/net.ts b/packages/build-tools/bridge-src/builtins/net.ts index c0aafb733..f3f1379eb 100644 --- a/packages/build-tools/bridge-src/builtins/net.ts +++ b/packages/build-tools/bridge-src/builtins/net.ts @@ -11,6 +11,8 @@ var registeredNetSockets = /* @__PURE__ */ new Map(); var registeredNetServersByPort = /* @__PURE__ */ new Map(); +var registeredNetServersByPath = /* @__PURE__ */ new Map(); + function getRegisteredNetSocket(socketId) { return globalThis[`${NET_SOCKET_REGISTRY_PREFIX}${socketId}`]; } @@ -25,11 +27,24 @@ function unregisterNetSocket(socketId) { registeredNetSockets.delete(socketId); } +function netServerUnixPath(server) { + const address = server?._address; + if (typeof address === "string") { + return address; + } + const path = address?.path; + return typeof path === "string" ? path : void 0; +} + function registerNetServer(server) { const port = server?._address?.port; if (typeof port === "number") { registeredNetServersByPort.set(port, server); } + const path = netServerUnixPath(server); + if (typeof path === "string") { + registeredNetServersByPath.set(path, server); + } } function unregisterNetServer(server) { @@ -37,6 +52,10 @@ function unregisterNetServer(server) { if (typeof port === "number" && registeredNetServersByPort.get(port) === server) { registeredNetServersByPort.delete(port); } + const path = netServerUnixPath(server); + if (typeof path === "string" && registeredNetServersByPath.get(path) === server) { + registeredNetServersByPath.delete(path); + } } function wakeSocketBridgeReads(socket) { @@ -140,21 +159,49 @@ function wakeSocketBridgeReads(socket) { function wakePeerBridgeReads(socket) { countNetBridgeMetric("peerWakeScans"); - if (!socket || socket._socketId === 0 || socket.remotePort === void 0 || socket.localPort === void 0) { + if (!socket || socket._socketId === 0) { countNetBridgeMetric("peerWakeInvalidTargets"); return; } + if (typeof socket.remotePort === "number" && typeof socket.localPort === "number") { + for (const peer of registeredNetSockets.values()) { + if (peer === socket || peer.destroyed) { + continue; + } + if (peer.localPort === socket.remotePort && peer.remotePort === socket.localPort) { + countNetBridgeMetric("peerWakeFound"); + wakeSocketBridgeReads(peer); + return; + } + } + countNetBridgeMetric("peerWakeMiss"); + return; + } + const localPath = typeof socket.localPath === "string" ? socket.localPath : void 0; + const remotePath = typeof socket.remotePath === "string" ? socket.remotePath : void 0; + if (localPath === void 0 && remotePath === void 0) { + countNetBridgeMetric("peerWakeInvalidTargets"); + return; + } + let foundUnixPeer = false; for (const peer of registeredNetSockets.values()) { if (peer === socket || peer.destroyed) { continue; } - if (peer.localPort === socket.remotePort && peer.remotePort === socket.localPort) { - countNetBridgeMetric("peerWakeFound"); + const peerLocalPath = typeof peer.localPath === "string" ? peer.localPath : void 0; + const peerRemotePath = typeof peer.remotePath === "string" ? peer.remotePath : void 0; + const fullPathMirror = localPath !== void 0 && remotePath !== void 0 && peerLocalPath !== void 0 && peerRemotePath !== void 0 && peerLocalPath === remotePath && peerRemotePath === localPath; + const remoteToPeerLocal = remotePath !== void 0 && peerLocalPath !== void 0 && peerLocalPath === remotePath; + const localToPeerRemote = localPath !== void 0 && peerRemotePath !== void 0 && peerRemotePath === localPath; + if (fullPathMirror || remoteToPeerLocal || localToPeerRemote) { + foundUnixPeer = true; + countNetBridgeMetric("peerWakeUnixFound"); wakeSocketBridgeReads(peer); - return; } } - countNetBridgeMetric("peerWakeMiss"); + if (!foundUnixPeer) { + countNetBridgeMetric("peerWakeUnixMiss"); + } } function wakeNetServerAccept(server) { @@ -201,15 +248,28 @@ function wakeNetServerAccept(server) { function wakeNetServerAcceptForSocket(socket) { countNetBridgeMetric("acceptWakeSocketScans"); const port = socket?.remotePort; - if (typeof port !== "number") { + if (typeof port === "number") { + const server = registeredNetServersByPort.get(port); + if (server) { + countNetBridgeMetric("acceptWakeSocketFound"); + } else { + countNetBridgeMetric("acceptWakeSocketMiss"); + } + wakeNetServerAccept(server); + return; + } + const path = socket?.remotePath; + if (typeof path !== "string") { countNetBridgeMetric("acceptWakeSocketInvalidTargets"); return; } - const server = registeredNetServersByPort.get(port); + const server = registeredNetServersByPath.get(path); if (server) { countNetBridgeMetric("acceptWakeSocketFound"); + countNetBridgeMetric("acceptWakeSocketUnixFound"); } else { countNetBridgeMetric("acceptWakeSocketMiss"); + countNetBridgeMetric("acceptWakeSocketUnixMiss"); } wakeNetServerAccept(server); } @@ -1117,6 +1177,8 @@ function createNetBridgeMetrics() { peerWakeInvalidTargets: 0, peerWakeFound: 0, peerWakeMiss: 0, + peerWakeUnixFound: 0, + peerWakeUnixMiss: 0, acceptEventWakeups: 0, acceptWakeAttempts: 0, acceptWakeInvalidTargets: 0, @@ -1144,7 +1206,16 @@ function createNetBridgeMetrics() { acceptWakeSocketScans: 0, acceptWakeSocketInvalidTargets: 0, acceptWakeSocketFound: 0, - acceptWakeSocketMiss: 0 + acceptWakeSocketMiss: 0, + acceptWakeSocketUnixFound: 0, + acceptWakeSocketUnixMiss: 0, + dgramWakeAttempts: 0, + dgramWakeInvalidTargets: 0, + dgramWakeAlreadyRunning: 0, + dgramWakeNoTimer: 0, + dgramEventWakeups: 0, + dgramWakeLoopbackHits: 0, + dgramWakeLoopbackMisses: 0 }; } From d0d5ce3d7e44cca03ef85875e5bb7870208da119 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 1 Jul 2026 17:46:35 -0700 Subject: [PATCH 3/4] perf(sidecar): raw-byte fast path for guest fs reads and writes --- crates/bridge/bridge-contract.json | 15 ++++ crates/execution/src/javascript.rs | 8 +- crates/sidecar/src/execution.rs | 8 +- crates/sidecar/src/filesystem.rs | 76 +++++++++++-------- .../build-tools/bridge-src/builtins/fs.ts | 64 +++++++++------- .../build-tools/bridge-src/global-exposure.ts | 15 ++++ 6 files changed, 125 insertions(+), 61 deletions(-) diff --git a/crates/bridge/bridge-contract.json b/crates/bridge/bridge-contract.json index 015d2af2d..f5fb51ef8 100644 --- a/crates/bridge/bridge-contract.json +++ b/crates/bridge/bridge-contract.json @@ -122,6 +122,7 @@ "_fsWriteFile", "_fsReadFileBinary", "_fsWriteFileBinary", + "_fsWriteFileBinaryRaw", "_fsReadDir", "_fsMkdir", "_fsRmdir", @@ -141,7 +142,9 @@ "fs.openSync", "fs.closeSync", "fs.readSync", + "_fsReadRaw", "fs.writeSync", + "_fsWriteRaw", "fs.fstatSync", "fs.futimesSync" ] @@ -697,6 +700,10 @@ "method": "fs.writeFileSync", "translateArgs": true }, + "_fsWriteFileBinaryRaw": { + "method": "fs.writeFileSync", + "translateArgs": false + }, "_fsWriteFileBinaryAsync": { "method": "fs.promises.writeFile", "translateArgs": true @@ -1061,9 +1068,17 @@ "method": "fs.readSync", "translateArgs": false }, + "_fsReadRaw": { + "method": "fs.readSync", + "translateArgs": false + }, "fs.writeSync": { "method": "fs.writeSync", "translateArgs": false + }, + "_fsWriteRaw": { + "method": "fs.writeSync", + "translateArgs": false } } } diff --git a/crates/execution/src/javascript.rs b/crates/execution/src/javascript.rs index 0e2bba5e6..47cabc4ac 100644 --- a/crates/execution/src/javascript.rs +++ b/crates/execution/src/javascript.rs @@ -3119,12 +3119,18 @@ fn spawn_v8_event_bridge( let phase_start = Instant::now(); let request_args = translate_request_args_for_legacy(sidecar_method, &args); let mut raw_bytes_args = HashMap::new(); - if sidecar_method == "net.write" { + if sidecar_method == "net.write" + || sidecar_method == "fs.writeSync" + || sidecar_method == "fs.writeFileSync" + { if let Ok(Some(bytes)) = v8_runtime::cbor_payload_raw_byte_arg(&payload, 1) { raw_bytes_args.insert(1, bytes); } } + if method == "_fsReadRaw" { + raw_bytes_args.insert(usize::MAX, Vec::new()); + } record_sync_bridge_phase( &method, "event_translate_args", diff --git a/crates/sidecar/src/execution.rs b/crates/sidecar/src/execution.rs index 2503bffea..a2142fc49 100644 --- a/crates/sidecar/src/execution.rs +++ b/crates/sidecar/src/execution.rs @@ -4,7 +4,8 @@ use secure_exec_vm_config as vm_config; use crate::filesystem::{ handle_python_vfs_rpc_request as filesystem_handle_python_vfs_rpc_request, - service_javascript_fs_sync_rpc, service_javascript_module_sync_rpc, + service_javascript_fs_read_sync_rpc, service_javascript_fs_sync_rpc, + service_javascript_module_sync_rpc, }; use crate::protocol::{ CloseStdinRequest, EventFrame, EventPayload, ExecuteRequest, FindBoundUdpRequest, @@ -15082,6 +15083,11 @@ where resource_limits, network_counts, } = request; + if request.raw_bytes_args.contains_key(&usize::MAX) && request.method == "fs.readSync" { + let kernel_pid = process.kernel_pid; + let bytes = service_javascript_fs_read_sync_rpc(kernel, process, kernel_pid, request)?; + return Ok(JavascriptSyncRpcServiceResponse::Raw(bytes)); + } let response = match request.method.as_str() { "__bench.noop" => Ok(Value::Null), "__bench.net_tcp_metrics_reset" => { diff --git a/crates/sidecar/src/filesystem.rs b/crates/sidecar/src/filesystem.rs index 1eb84522f..e346ea3df 100644 --- a/crates/sidecar/src/filesystem.rs +++ b/crates/sidecar/src/filesystem.rs @@ -984,6 +984,38 @@ fn fs_sync_request_marks_host_write_dirty( }) } +pub(crate) fn service_javascript_fs_read_sync_rpc( + kernel: &mut SidecarKernel, + process: &mut ActiveProcess, + kernel_pid: u32, + request: &JavascriptSyncRpcRequest, +) -> Result, SidecarError> { + let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem read fd")?; + let length = usize::try_from(javascript_sync_rpc_arg_u64( + &request.args, + 1, + "filesystem read length", + )?) + .map_err(|_| { + SidecarError::InvalidState("filesystem read length must fit within usize".to_string()) + })?; + let position = + javascript_sync_rpc_arg_u64_optional(&request.args, 2, "filesystem read position")?; + if let Some(mapped) = process.mapped_host_fd_mut(fd) { + let value = read_mapped_host_fd(mapped, fd, length, position)?; + return javascript_sync_rpc_bytes_arg( + std::slice::from_ref(&value), + 0, + "filesystem mapped read response", + ); + } + match position { + Some(offset) => kernel.fd_pread(EXECUTION_DRIVER_NAME, kernel_pid, fd, length, offset), + None => kernel.fd_read(EXECUTION_DRIVER_NAME, kernel_pid, fd, length), + } + .map_err(kernel_error) +} + pub(crate) fn service_javascript_fs_sync_rpc( kernel: &mut SidecarKernel, process: &mut ActiveProcess, @@ -1034,36 +1066,17 @@ pub(crate) fn service_javascript_fs_sync_rpc( .map(|fd| json!(fd)) .map_err(|error| kernel_path_error("fs.open", path, error)) } - "fs.read" | "fs.readSync" => { - let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem read fd")?; - let length = usize::try_from(javascript_sync_rpc_arg_u64( - &request.args, - 1, - "filesystem read length", - )?) - .map_err(|_| { - SidecarError::InvalidState( - "filesystem read length must fit within usize".to_string(), - ) - })?; - let position = - javascript_sync_rpc_arg_u64_optional(&request.args, 2, "filesystem read position")?; - if let Some(mapped) = process.mapped_host_fd_mut(fd) { - return read_mapped_host_fd(mapped, fd, length, position); - } - let bytes = match position { - Some(offset) => { - kernel.fd_pread(EXECUTION_DRIVER_NAME, kernel_pid, fd, length, offset) - } - None => kernel.fd_read(EXECUTION_DRIVER_NAME, kernel_pid, fd, length), - } - .map_err(kernel_error)?; - Ok(javascript_sync_rpc_bytes_value(&bytes)) - } + "fs.read" | "fs.readSync" => service_javascript_fs_read_sync_rpc( + kernel, process, kernel_pid, request, + ) + .map(|bytes| javascript_sync_rpc_bytes_value(&bytes)), "fs.write" | "fs.writeSync" => { let fd = javascript_sync_rpc_arg_u32(&request.args, 0, "filesystem write fd")?; - let contents = - javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem write contents")?; + let contents = if let Some(bytes) = request.raw_bytes_args.get(&1) { + bytes.clone() + } else { + javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem write contents")? + }; let position = javascript_sync_rpc_arg_u64_optional( &request.args, 2, @@ -1226,8 +1239,11 @@ pub(crate) fn service_javascript_fs_sync_rpc( "filesystem writeFile path", )?; let path = path.as_str(); - let contents = - javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem writeFile contents")?; + let contents = if let Some(bytes) = request.raw_bytes_args.get(&1) { + bytes.clone() + } else { + javascript_sync_rpc_bytes_arg(&request.args, 1, "filesystem writeFile contents")? + }; match mapped_runtime_host_path(process, path, true) { Some(MappedRuntimeHostAccess::Writable(mapped_host)) => { let opened = open_mapped_runtime_beneath( diff --git a/packages/build-tools/bridge-src/builtins/fs.ts b/packages/build-tools/bridge-src/builtins/fs.ts index 790b3f27b..d30e5fec2 100644 --- a/packages/build-tools/bridge-src/builtins/fs.ts +++ b/packages/build-tools/bridge-src/builtins/fs.ts @@ -1795,11 +1795,11 @@ var WriteStream = class { chunk.copy(output, cursor); cursor += chunk.length; } - fs.writeFileSync(pathStr, output.toString(this._options?.encoding ?? "utf8")); + fs.writeFileSync(pathStr, output); } else { fs.writeFileSync( pathStr, - import_buffer.Buffer.concat(chunks).toString(this._options?.encoding ?? "utf8") + import_buffer.Buffer.concat(chunks) ); } if (this.autoClose && this.fd !== null && this.fd >= 0) { @@ -2159,6 +2159,10 @@ function createBridgeSyncFacade(name) { } }; } +function hasBridgeSyncFn(name) { + const fn = getBridgeSyncFn(name); + return typeof fn === "function" || !!(fn && (typeof fn.applySync === "function" || typeof fn.applySyncPromise === "function")); +} function createBridgeAsyncFacade(name) { return { apply(_thisArg, args) { @@ -2178,6 +2182,7 @@ var _fs = { writeFile: createBridgeSyncFacade("_fsWriteFile"), readFileBinary: createBridgeSyncFacade("_fsReadFileBinary"), writeFileBinary: createBridgeSyncFacade("_fsWriteFileBinary"), + writeFileBinaryRaw: createBridgeSyncFacade("_fsWriteFileBinaryRaw"), readDir: createBridgeSyncFacade("_fsReadDir"), mkdir: createBridgeSyncFacade("_fsMkdir"), rmdir: createBridgeSyncFacade("_fsRmdir"), @@ -2220,7 +2225,9 @@ var _fsAsync = { var _fdOpen = createBridgeSyncFacade("fs.openSync"); var _fdClose = createBridgeSyncFacade("fs.closeSync"); var _fdRead = createBridgeSyncFacade("fs.readSync"); +var _fsReadRaw = createBridgeSyncFacade("_fsReadRaw"); var _fdWrite = createBridgeSyncFacade("fs.writeSync"); +var _fsWriteRaw = createBridgeSyncFacade("_fsWriteRaw"); var _fdFstat = createBridgeSyncFacade("fs.fstatSync"); var _fdFtruncate = createBridgeSyncFacade("fs.ftruncateSync"); var _fdFsync = createBridgeSyncFacade("fs.fsyncSync"); @@ -2325,6 +2332,9 @@ async function fsWriteFileAsync(file, data, options) { } if (ArrayBuffer.isView(data)) { const uint8 = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + if (hasBridgeSyncFn("_fsWriteFileBinaryRaw")) { + return _fs.writeFileBinaryRaw.applySyncPromise(void 0, [pathStr, uint8]); + } return await _fsAsync.writeFileBinary.apply(void 0, [pathStr, encodeBridgeBytes(uint8)]); } return await _fsAsync.writeFile.apply(void 0, [pathStr, String(data)]); @@ -2595,6 +2605,9 @@ var fs = { return _fs.writeFile.applySyncPromise(void 0, [pathStr, data]); } else if (ArrayBuffer.isView(data)) { const uint8 = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + if (hasBridgeSyncFn("_fsWriteFileBinaryRaw")) { + return _fs.writeFileBinaryRaw.applySyncPromise(void 0, [pathStr, uint8]); + } return _fs.writeFileBinary.applySyncPromise(void 0, [pathStr, encodeBridgeBytes(uint8)]); } else { return _fs.writeFile.applySyncPromise(void 0, [pathStr, String(data)]); @@ -2872,24 +2885,28 @@ var fs = { }, readSync(fd, buffer, offset, length, position) { const normalized = normalizeReadSyncArgs(buffer, offset, length, position); - let base64; + let bytes; try { - base64 = _fdRead.applySyncPromise(void 0, [fd, normalized.length, normalized.position ?? null]); + if (hasBridgeSyncFn("_fsReadRaw")) { + const rawBytes = _fsReadRaw.applySyncPromise(void 0, [fd, normalized.length, normalized.position ?? null]); + bytes = rawBytes instanceof Uint8Array ? rawBytes : import_buffer.Buffer.from(rawBytes); + } else { + const base64 = _fdRead.applySyncPromise(void 0, [fd, normalized.length, normalized.position ?? null]); + bytes = import_buffer.Buffer.from(base64, "base64"); + } } catch (e) { const msg = e?.message ?? String(e); if (msg.includes("EBADF")) throw createFsError("EBADF", msg, "read"); throw e; } - const bytes = import_buffer.Buffer.from(base64, "base64"); const targetBuffer = new Uint8Array( normalized.buffer.buffer, normalized.buffer.byteOffset, normalized.buffer.byteLength ); - for (let i = 0; i < bytes.length && i < normalized.length; i++) { - targetBuffer[normalized.offset + i] = bytes[i]; - } - return bytes.length; + const bytesRead = Math.min(bytes.length, normalized.length); + targetBuffer.set(bytes.subarray(0, bytesRead), normalized.offset); + return bytesRead; }, writeSync(fd, buffer, offsetOrPosition, lengthOrEncoding, position) { const normalized = normalizeWriteSyncArgs(buffer, offsetOrPosition, lengthOrEncoding, position); @@ -2905,6 +2922,9 @@ var fs = { } const pos = normalized.position ?? null; try { + if (hasBridgeSyncFn("_fsWriteRaw")) { + return _fsWriteRaw.applySyncPromise(void 0, [fd, dataBytes, pos]); + } return _fdWrite.applySyncPromise(void 0, [fd, encodeBridgeBytes(dataBytes), pos]); } catch (e) { const msg = e?.message ?? String(e); @@ -3489,26 +3509,12 @@ var fs = { ); const cb = callback; try { - const bytesWritten = typeof normalized.buffer === "string" ? _fdWrite.applySyncPromise( - void 0, - [ - fd, - encodeBridgeBytes(import_buffer.Buffer.from(normalized.buffer, normalized.encoding)), - normalized.position ?? null - ] - ) : _fdWrite.applySyncPromise( - void 0, - [ - fd, - encodeBridgeBytes(import_buffer.Buffer.from( - new Uint8Array( - normalized.buffer.buffer, - normalized.buffer.byteOffset + normalized.offset, - normalized.length - ) - )), - normalized.position ?? null - ] + const bytesWritten = fs.writeSync( + fd, + buffer, + offset, + length, + position ); queueMicrotask(() => cb(null, bytesWritten)); } catch (e) { diff --git a/packages/build-tools/bridge-src/global-exposure.ts b/packages/build-tools/bridge-src/global-exposure.ts index 4fec6138a..76a7559c1 100644 --- a/packages/build-tools/bridge-src/global-exposure.ts +++ b/packages/build-tools/bridge-src/global-exposure.ts @@ -405,6 +405,11 @@ var NODE_CUSTOM_GLOBAL_INVENTORY = [ classification: "hardened", rationale: "Host filesystem bridge reference." }, + { + name: "_fsWriteFileBinaryRaw", + classification: "hardened", + rationale: "Raw-byte host filesystem binary write bridge reference." + }, { name: "_fsWriteFileBinaryAsync", classification: "hardened", @@ -590,11 +595,21 @@ var NODE_CUSTOM_GLOBAL_INVENTORY = [ classification: "hardened", rationale: "Host file-descriptor read bridge reference." }, + { + name: "_fsReadRaw", + classification: "hardened", + rationale: "Raw-byte host file-descriptor read bridge reference." + }, { name: "fs.writeSync", classification: "hardened", rationale: "Host file-descriptor write bridge reference." }, + { + name: "_fsWriteRaw", + classification: "hardened", + rationale: "Raw-byte host file-descriptor write bridge reference." + }, { name: "fs.fstatSync", classification: "hardened", From 0e09364363e07fc072433d046ba2b9625a16d3b8 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Wed, 1 Jul 2026 19:03:21 -0700 Subject: [PATCH 4/4] perf(v8-runtime): wake loopback peer on FIN/close --- packages/build-tools/bridge-src/builtins/net.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/build-tools/bridge-src/builtins/net.ts b/packages/build-tools/bridge-src/builtins/net.ts index f3f1379eb..d4e78fc65 100644 --- a/packages/build-tools/bridge-src/builtins/net.ts +++ b/packages/build-tools/bridge-src/builtins/net.ts @@ -1179,6 +1179,8 @@ function createNetBridgeMetrics() { peerWakeMiss: 0, peerWakeUnixFound: 0, peerWakeUnixMiss: 0, + peerWakeOnShutdown: 0, + peerWakeOnDestroy: 0, acceptEventWakeups: 0, acceptWakeAttempts: 0, acceptWakeInvalidTargets: 0, @@ -1641,6 +1643,8 @@ var NetSocket = class _NetSocket { this._flushBridgeWrites(); debugBridgeNetwork("socket end", this._socketId); _netSocketEndRaw.applySync(void 0, [this._socketId]); + countNetBridgeMetric("peerWakeOnShutdown"); + wakePeerBridgeReads(this); this._touchTimeout(); } return this; @@ -1672,6 +1676,8 @@ var NetSocket = class _NetSocket { } if (typeof _netSocketDestroyRaw !== "undefined" && this._socketId) { _netSocketDestroyRaw.applySync(void 0, [this._socketId]); + countNetBridgeMetric("peerWakeOnDestroy"); + wakePeerBridgeReads(this); } if (error) { this._emitNet("error", error); @@ -2627,6 +2633,14 @@ var NetServer = class { remoteFamily: clientHandle.info.remoteFamily }); _netSocketDestroyRaw?.applySync(void 0, [clientHandle.socketId]); + countNetBridgeMetric("peerWakeOnDestroy"); + wakePeerBridgeReads({ + _socketId: clientHandle.socketId, + localPort: clientHandle.info.localPort, + remotePort: clientHandle.info.remotePort, + localPath: clientHandle.info.localPath, + remotePath: clientHandle.info.remotePath + }); return; } if (this.keepAlive) {