1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
use crate::Function;
use crate::Isolate;
use crate::Local;
use crate::MicrotasksPolicy;
use crate::isolate::RealIsolate;
use crate::support::Opaque;
use crate::support::int;
use std::ops::Deref;
use std::ptr::NonNull;
#[repr(C)]
struct MicrotaskQueueHandleRaw(Opaque);
unsafe extern "C" {
fn v8__MicrotaskQueueHandle__New(
isolate: *mut RealIsolate,
policy: MicrotasksPolicy,
) -> *mut MicrotaskQueueHandleRaw;
fn v8__MicrotaskQueueHandle__DELETE(handle: *mut MicrotaskQueueHandleRaw);
fn v8__MicrotaskQueueHandle__Get(
handle: *const MicrotaskQueueHandleRaw,
) -> *mut MicrotaskQueue;
fn v8__MicrotaskQueue__PerformCheckpoint(
isolate: *mut RealIsolate,
queue: *const MicrotaskQueue,
);
fn v8__MicrotaskQueue__IsRunningMicrotasks(
queue: *const MicrotaskQueue,
) -> bool;
fn v8__MicrotaskQueue__GetMicrotasksScopeDepth(
queue: *const MicrotaskQueue,
) -> int;
fn v8__MicrotaskQueue__EnqueueMicrotask(
isolate: *mut RealIsolate,
queue: *const MicrotaskQueue,
microtask: *const Function,
);
}
/// Represents the microtask queue, where microtasks are stored and processed.
/// https://html.spec.whatwg.org/multipage/webappapis.html#microtask-queue
/// https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments)
/// https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
///
/// A MicrotaskQueue instance may be associated to multiple Contexts by passing
/// it to Context::New(), and they can be detached by Context::DetachGlobal().
///
/// Use the same instance of MicrotaskQueue for all Contexts that may access each
/// other synchronously. E.g. for Web embedding, use the same instance for all
/// origins that share the same URL scheme and eTLD+1.
#[repr(C)]
#[derive(Debug)]
pub struct MicrotaskQueue(Opaque);
impl MicrotaskQueue {
#[allow(clippy::new_ret_no_self)]
pub fn new(
isolate: &mut Isolate,
policy: MicrotasksPolicy,
) -> MicrotaskQueueHandle {
let handle =
unsafe { v8__MicrotaskQueueHandle__New(isolate.as_real_ptr(), policy) };
MicrotaskQueueHandle(NonNull::new(handle).unwrap())
}
pub fn enqueue_microtask(
&self,
isolate: &mut Isolate,
microtask: Local<Function>,
) {
unsafe {
v8__MicrotaskQueue__EnqueueMicrotask(
isolate.as_real_ptr(),
self,
&*microtask,
)
}
}
/// Adds a callback to notify the embedder after microtasks were run. The
/// callback is triggered by explicit RunMicrotasks call or automatic
/// microtasks execution (see Isolate::SetMicrotasksPolicy).
///
/// Callback will trigger even if microtasks were attempted to run,
/// but the microtasks queue was empty and no single microtask was actually
/// executed.
///
/// Executing scripts inside the callback will not re-trigger microtasks and
/// the callback.
pub fn perform_checkpoint(&self, isolate: &mut Isolate) {
unsafe {
v8__MicrotaskQueue__PerformCheckpoint(isolate.as_real_ptr(), self);
}
}
/// Removes callback that was installed by AddMicrotasksCompletedCallback.
pub fn is_running_microtasks(&self) -> bool {
unsafe { v8__MicrotaskQueue__IsRunningMicrotasks(self) }
}
/// Returns the current depth of nested MicrotasksScope that has kRunMicrotasks.
pub fn get_microtasks_scope_depth(&self) -> i32 {
unsafe { v8__MicrotaskQueue__GetMicrotasksScopeDepth(self) }
}
}
/// A rooted handle to a [`MicrotaskQueue`].
///
/// This handle must be dropped before its isolate is disposed because dropping
/// it releases a root through the isolate's heap.
///
/// With the default `v8_cppgc_microtask_queue` GN setting, contexts associated
/// with the queue keep it alive after this handle is dropped. If that setting
/// is disabled through `EXTRA_GN_ARGS`, this handle owns the queue and must
/// outlive every associated context.
#[derive(Debug)]
pub struct MicrotaskQueueHandle(NonNull<MicrotaskQueueHandleRaw>);
impl Deref for MicrotaskQueueHandle {
type Target = MicrotaskQueue;
fn deref(&self) -> &Self::Target {
unsafe { &*v8__MicrotaskQueueHandle__Get(self.0.as_ptr()) }
}
}
impl AsRef<MicrotaskQueue> for MicrotaskQueueHandle {
fn as_ref(&self) -> &MicrotaskQueue {
self
}
}
impl Drop for MicrotaskQueueHandle {
fn drop(&mut self) {
unsafe { v8__MicrotaskQueueHandle__DELETE(self.0.as_ptr()) }
}
}