Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 14 additions & 2 deletions core/01_core.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@
op_add_main_module_handler,
op_set_handled_promise_rejection_handler,
op_set_has_tick_scheduled,
op_set_has_immediate_scheduled,
op_set_promise_hooks,
op_set_wasm_streaming_callback,
op_str_byte_length,
op_timer_cancel,
op_timer_queue,
op_timer_queue_system,
op_timer_queue_immediate,
op_timer_ref,
op_timer_unref,
op_unref_op,
Expand Down Expand Up @@ -148,6 +148,7 @@

const macrotaskCallbacks = [];
const nextTickCallbacks = [];
const immediateCallbacks = [];

function setMacrotaskCallback(cb) {
ArrayPrototypePush(macrotaskCallbacks, cb);
Expand All @@ -157,6 +158,10 @@
ArrayPrototypePush(nextTickCallbacks, cb);
}

function setImmediateCallback(cb) {
ArrayPrototypePush(immediateCallbacks, cb);
}

// This function has variable number of arguments. The last argument describes
// if there's a "next tick" scheduled by the Node.js compat layer. Arguments
// before last are alternating integers and any values that describe the
Expand All @@ -179,6 +184,12 @@
op_run_microtasks();
}

// Drain immediates queue.
// TODO: might do it recursively
for (let i = 0; i < immediateCallbacks.length; i++) {
immediateCallbacks[i]();
}

// Finally drain macrotask queue.
for (let i = 0; i < macrotaskCallbacks.length; i++) {
const cb = macrotaskCallbacks[i];
Expand Down Expand Up @@ -690,9 +701,11 @@
op_leak_tracing_get(0, promise[promiseIdSymbol]),
setMacrotaskCallback,
setNextTickCallback,
setImmediateCallback,
runMicrotasks: () => op_run_microtasks(),
hasTickScheduled: () => op_has_tick_scheduled(),
setHasTickScheduled: (bool) => op_set_has_tick_scheduled(bool),
setHasImmediateScheduled: (bool) => op_set_has_immediate_scheduled(bool),
evalContext: (
source,
specifier,
Expand Down Expand Up @@ -799,7 +812,6 @@
// TODO(mmastrac): Hook up associatedOp to tracing
queueSystemTimer: (_associatedOp, repeat, timeout, task) =>
op_timer_queue_system(repeat, timeout, task),
queueImmediate: (task) => op_timer_queue_immediate(task),
cancelTimer: (id) => {
if (timersRunning) {
cancelledTimers.add(id);
Expand Down
2 changes: 1 addition & 1 deletion core/ops_builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ builtin_ops! {
ops_builtin_v8::op_set_handled_promise_rejection_handler,
ops_builtin_v8::op_timer_queue,
ops_builtin_v8::op_timer_queue_system,
ops_builtin_v8::op_timer_queue_immediate,
ops_builtin_v8::op_timer_cancel,
ops_builtin_v8::op_timer_ref,
ops_builtin_v8::op_timer_unref,
Expand All @@ -111,6 +110,7 @@ builtin_ops! {
ops_builtin_v8::op_run_microtasks,
ops_builtin_v8::op_has_tick_scheduled,
ops_builtin_v8::op_set_has_tick_scheduled,
ops_builtin_v8::op_set_has_immediate_scheduled,
ops_builtin_v8::op_eval_context,
ops_builtin_v8::op_queue_microtask,
ops_builtin_v8::op_encode,
Expand Down
19 changes: 7 additions & 12 deletions core/ops_builtin_v8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,6 @@ pub fn op_timer_queue_system(
.queue_system_timer(repeat, timeout_ms as _, (task, 0)) as _
}

/// Queue a timer. We return a "large integer" timer ID in an f64 which allows for up
/// to `MAX_SAFE_INTEGER` (2^53) timers to exist, versus 2^32 timers if we used
/// `u32`.
#[op2]
pub fn op_timer_queue_immediate(
scope: &mut v8::HandleScope,
#[global] task: v8::Global<v8::Function>,
) -> f64 {
let context_state = JsRealm::state_from_scope(scope);
context_state.timers.queue_timer(0, (task, 0)) as _
}

#[op2(fast)]
pub fn op_timer_cancel(scope: &mut v8::HandleScope, id: f64) {
let context_state = JsRealm::state_from_scope(scope);
Expand Down Expand Up @@ -240,6 +228,13 @@ pub fn op_set_has_tick_scheduled(scope: &mut v8::HandleScope, v: bool) {
.set(v);
}

#[op2(fast)]
pub fn op_set_has_immediate_scheduled(scope: &mut v8::HandleScope, v: bool) {
JsRealm::state_from_scope(scope)
.has_immediate_scheduled
.set(v);
}

pub struct EvalContextError<'s> {
thrown: v8::Local<'s, v8::Value>,
is_native_error: bool,
Expand Down
2 changes: 2 additions & 0 deletions core/runtime/jsrealm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub struct ContextState {
pub(crate) isolate: Option<*mut v8::Isolate>,
pub(crate) exception_state: Rc<ExceptionState>,
pub(crate) has_next_tick_scheduled: Cell<bool>,
pub(crate) has_immediate_scheduled: Cell<bool>,
pub(crate) external_ops_tracker: ExternalOpsTracker,
pub(crate) ext_import_meta_proto: RefCell<Option<v8::Global<v8::Object>>>,
}
Expand All @@ -97,6 +98,7 @@ impl ContextState {
isolate: Some(isolate_ptr),
exception_state: Default::default(),
has_next_tick_scheduled: Default::default(),
has_immediate_scheduled: Default::default(),
js_event_loop_tick_cb: Default::default(),
js_wasm_streaming_cb: Default::default(),
wasm_instance_fn: Default::default(),
Expand Down
8 changes: 8 additions & 0 deletions core/runtime/jsruntime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,7 @@ impl JsRuntime {
{
if pending_state.has_pending_background_tasks
|| pending_state.has_tick_scheduled
|| pending_state.has_immediate_scheduled
|| pending_state.has_pending_promise_events
{
self.inner.state.waker.wake();
Expand All @@ -2094,6 +2095,7 @@ impl JsRuntime {
|| pending_state.has_pending_background_tasks
|| pending_state.has_pending_external_ops
|| pending_state.has_tick_scheduled
|| pending_state.has_immediate_scheduled
{
// pass, will be polled again
} else {
Expand All @@ -2112,6 +2114,7 @@ impl JsRuntime {
|| pending_state.has_pending_background_tasks
|| pending_state.has_pending_external_ops
|| pending_state.has_tick_scheduled
|| pending_state.has_immediate_scheduled
{
// pass, will be polled again
} else if realm.modules_idle() {
Expand Down Expand Up @@ -2331,6 +2334,7 @@ pub(crate) struct EventLoopPendingState {
has_pending_module_evaluation: bool,
has_pending_background_tasks: bool,
has_tick_scheduled: bool,
has_immediate_scheduled: bool,
has_pending_promise_events: bool,
has_pending_external_ops: bool,
}
Expand Down Expand Up @@ -2374,6 +2378,7 @@ impl EventLoopPendingState {
has_pending_module_evaluation,
has_pending_background_tasks: scope.has_pending_background_tasks(),
has_tick_scheduled: state.has_next_tick_scheduled.get(),
has_immediate_scheduled: state.has_immediate_scheduled.get(),
has_pending_promise_events,
has_pending_external_ops: state.external_ops_tracker.has_pending_ops(),
}
Expand All @@ -2393,6 +2398,7 @@ impl EventLoopPendingState {
|| self.has_pending_module_evaluation
|| self.has_pending_background_tasks
|| self.has_tick_scheduled
|| self.has_immediate_scheduled
|| self.has_pending_promise_events
|| self.has_pending_external_ops
}
Expand Down Expand Up @@ -2683,7 +2689,9 @@ impl JsRuntime {

let undefined: v8::Local<v8::Value> = v8::undefined(scope).into();
let has_tick_scheduled = context_state.has_next_tick_scheduled.get();
let has_immediate_scheduled = context_state.has_immediate_scheduled.get();
dispatched_ops |= has_tick_scheduled;
dispatched_ops |= has_immediate_scheduled;

while let Some((promise, result)) = exception_state
.pending_handled_promise_rejections
Expand Down
Loading