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

experiment with moving eventLoopTick to rust #998

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 31 additions & 40 deletions core/00_infra.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
let nextPromiseId = 0;
const promiseMap = new SafeMap();
const RING_SIZE = 4 * 1024;
const outArray = [null, null];
const NO_PROMISE = null; // Alias to null is faster than plain nulls
const promiseRing = ArrayPrototypeFill(new Array(RING_SIZE), NO_PROMISE);
// TODO(bartlomieju): in the future use `v8::Private` so it's not visible
Expand Down Expand Up @@ -198,192 +199,182 @@
/* DO NOT MODIFY: use rebuild_async_stubs.js to regenerate */
case 0:
fn = function async_op_0() {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id);
const maybeResult = originalOp(outArray);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_0);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 1:
fn = function async_op_1(a) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a);
const maybeResult = originalOp(outArray, a);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_1);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 2:
fn = function async_op_2(a, b) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b);
const maybeResult = originalOp(outArray, a, b);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_2);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 3:
fn = function async_op_3(a, b, c) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c);
const maybeResult = originalOp(outArray, a, b, c);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_3);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 4:
fn = function async_op_4(a, b, c, d) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d);
const maybeResult = originalOp(outArray, a, b, c, d);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_4);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 5:
fn = function async_op_5(a, b, c, d, e) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d, e);
const maybeResult = originalOp(outArray, a, b, c, d, e);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_5);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 6:
fn = function async_op_6(a, b, c, d, e, f) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d, e, f);
const maybeResult = originalOp(outArray, a, b, c, d, e, f);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_6);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 7:
fn = function async_op_7(a, b, c, d, e, f, g) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d, e, f, g);
const maybeResult = originalOp(outArray, a, b, c, d, e, f, g);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_7);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 8:
fn = function async_op_8(a, b, c, d, e, f, g, h) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d, e, f, g, h);
const maybeResult = originalOp(outArray, a, b, c, d, e, f, g, h);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_8);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
case 9:
fn = function async_op_9(a, b, c, d, e, f, g, h, i) {
const id = nextPromiseId;
try {
const maybeResult = originalOp(id, a, b, c, d, e, f, g, h, i);
const maybeResult = originalOp(outArray, a, b, c, d, e, f, g, h, i);
if (maybeResult !== undefined) {
return PromiseResolve(maybeResult);
}
} catch (err) {
ErrorCaptureStackTrace(err, async_op_9);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
};
break;
/* END TEMPLATE */
Expand Down
6 changes: 0 additions & 6 deletions core/01_core.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,6 @@
// before last are alternating integers and any values that describe the
// responses of async ops.
function eventLoopTick() {
// First respond to all pending ops.
for (let i = 0; i < arguments.length - 3; i += 2) {
const promiseId = arguments[i];
const res = arguments[i + 1];
__resolvePromise(promiseId, res);
}
// Drain nextTick queue if there's a tick scheduled.
if (arguments[arguments.length - 1]) {
for (let i = 0; i < nextTickCallbacks.length; i++) {
Expand Down
9 changes: 4 additions & 5 deletions core/rebuild_async_stubs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const doNotModify =

// The template function we build op_async_N functions from
function __TEMPLATE__(__ARGS_PARAM__) {
const id = nextPromiseId;
try {
const maybeResult = __OP__(__ARGS__);
if (maybeResult !== undefined) {
Expand All @@ -17,11 +16,11 @@ function __TEMPLATE__(__ARGS_PARAM__) {
ErrorCaptureStackTrace(err, __TEMPLATE__);
return PromiseReject(err);
}
const id = outArray[0];
if (isLeakTracingEnabled) {
submitLeakTrace(id);
}
nextPromiseId = (id + 1) & 0xffffffff;
return setPromise(id);
return outArray[1];
}

const infraJsPath = new URL("00_infra.js", import.meta.url);
Expand All @@ -36,7 +35,7 @@ let asyncStubCases = "/* BEGIN TEMPLATE setUpAsyncStub */\n";
asyncStubCases += doNotModify;
const vars = "abcdefghijklm";
for (let i = 0; i < 10; i++) {
let args = "id";
let args = "outArray";
for (let j = 0; j < i; j++) {
args += `, ${vars[j]}`;
}
Expand All @@ -45,7 +44,7 @@ for (let i = 0; i < 10; i++) {
const func = `fn = ${templateString}`
.replaceAll(/__TEMPLATE__/g, name)
.replaceAll(/__ARGS__/g, args)
.replaceAll(/__ARGS_PARAM__/g, args.replace(/id(, )?/, ""))
.replaceAll(/__ARGS_PARAM__/g, args.replace(/outArray(, )?/, ""))
.replaceAll(/__OP__/g, "originalOp")
.replaceAll(/[\s]*__ERR__;/g, "")
.replaceAll(/^/gm, " ");
Expand Down
32 changes: 32 additions & 0 deletions core/runtime/jsrealm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use anyhow::Error;
use futures::stream::StreamExt;
use std::cell::Cell;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::hash::BuildHasherDefault;
use std::hash::Hasher;
Expand Down Expand Up @@ -74,6 +75,34 @@ pub struct ContextState {
pub(crate) has_next_tick_scheduled: Cell<bool>,
pub(crate) get_error_class_fn: GetErrorClassFn,
pub(crate) external_ops_tracker: ExternalOpsTracker,
pub(crate) promises: Promises,
pub(crate) internal_promise_sym: RefCell<Option<Rc<v8::Global<v8::Symbol>>>>,
}

type PromiseId = i32;
#[derive(Default)]
pub(crate) struct Promises {
next_id: Cell<PromiseId>,
promises: RefCell<BTreeMap<PromiseId, v8::Global<v8::PromiseResolver>>>,
}
impl Promises {
pub(crate) fn register_new(
&self,
promise: v8::Global<v8::PromiseResolver>,
) -> PromiseId {
let id = self.next_id.get();
self.next_id.set(id + 1);
self.promises.borrow_mut().insert(id, promise);
id
}

pub(crate) fn complete(
&self,
promise_id: PromiseId,
) -> v8::Global<v8::PromiseResolver> {
let promise = self.promises.borrow_mut().remove(&promise_id).unwrap();
promise
}
}

impl ContextState {
Expand Down Expand Up @@ -101,6 +130,8 @@ impl ContextState {
timers: Default::default(),
unrefed_ops: Default::default(),
external_ops_tracker,
promises: Default::default(),
internal_promise_sym: Default::default(),
}
}
}
Expand Down Expand Up @@ -190,6 +221,7 @@ impl JsRealmInner {
state.exception_state.prepare_to_destroy();
std::mem::take(&mut *state.js_event_loop_tick_cb.borrow_mut());
std::mem::take(&mut *state.js_wasm_streaming_cb.borrow_mut());
std::mem::take(&mut *state.internal_promise_sym.borrow_mut());

{
let ctx = self.context().open(isolate);
Expand Down
Loading
Loading