1use crate::error::AnyError;
4use crate::error::GetErrorClassFn;
5use crate::gotham_state::GothamState;
6use crate::io::ResourceTable;
7use crate::ops_metrics::OpMetricsFn;
8use crate::runtime::JsRuntimeState;
9use crate::runtime::OpDriverImpl;
10use crate::FeatureChecker;
11use crate::OpDecl;
12use futures::task::AtomicWaker;
13use std::cell::RefCell;
14use std::cell::UnsafeCell;
15use std::ops::Deref;
16use std::ops::DerefMut;
17use std::ptr::NonNull;
18use std::rc::Rc;
19use std::sync::Arc;
20use v8::fast_api::CFunctionInfo;
21use v8::fast_api::CTypeInfo;
22use v8::Isolate;
23
24pub type PromiseId = i32;
25pub type OpId = u16;
26
27#[cfg(debug_assertions)]
28thread_local! {
29 static CURRENT_OP: std::cell::Cell<Option<&'static OpDecl>> = None.into();
30}
31
32#[cfg(debug_assertions)]
33pub struct ReentrancyGuard {}
34
35#[cfg(debug_assertions)]
36impl Drop for ReentrancyGuard {
37 fn drop(&mut self) {
38 CURRENT_OP.with(|f| f.set(None));
39 }
40}
41
42#[cfg(debug_assertions)]
44#[doc(hidden)]
45pub fn reentrancy_check(decl: &'static OpDecl) -> Option<ReentrancyGuard> {
46 if decl.is_reentrant {
47 return None;
48 }
49
50 let current = CURRENT_OP.with(|f| f.get());
51 if let Some(current) = current {
52 panic!("op {} was not marked as #[op2(reentrant)], but re-entrantly invoked op {}", current.name, decl.name);
53 }
54 CURRENT_OP.with(|f| f.set(Some(decl)));
55 Some(ReentrancyGuard {})
56}
57
58#[derive(Clone, Copy)]
59pub struct OpMetadata {
60 pub sanitizer_details: Option<&'static str>,
62 pub sanitizer_fix: Option<&'static str>,
64}
65
66impl OpMetadata {
67 pub const fn default() -> Self {
68 Self {
69 sanitizer_details: None,
70 sanitizer_fix: None,
71 }
72 }
73}
74
75pub struct OpCtx {
80 pub id: OpId,
82
83 pub isolate: *mut Isolate,
86
87 #[doc(hidden)]
88 pub state: Rc<RefCell<OpState>>,
89 #[doc(hidden)]
90 pub get_error_class_fn: GetErrorClassFn,
91
92 pub(crate) decl: OpDecl,
93 pub(crate) fast_fn_c_info: Option<NonNull<v8::fast_api::CFunctionInfo>>,
94 pub(crate) metrics_fn: Option<OpMetricsFn>,
95 pub(crate) last_fast_error: UnsafeCell<Option<AnyError>>,
97
98 op_driver: Rc<OpDriverImpl>,
99 runtime_state: Rc<JsRuntimeState>,
100}
101
102impl OpCtx {
103 #[allow(clippy::too_many_arguments)]
104 pub(crate) fn new(
105 id: OpId,
106 isolate: *mut Isolate,
107 op_driver: Rc<OpDriverImpl>,
108 decl: OpDecl,
109 state: Rc<RefCell<OpState>>,
110 runtime_state: Rc<JsRuntimeState>,
111 get_error_class_fn: GetErrorClassFn,
112 metrics_fn: Option<OpMetricsFn>,
113 ) -> Self {
114 let mut fast_fn_c_info = None;
115
116 let fast_fn = if metrics_fn.is_some() {
121 &decl.fast_fn_with_metrics
122 } else {
123 &decl.fast_fn
124 };
125
126 if let Some(fast_fn) = fast_fn {
127 let args = CTypeInfo::new_from_slice(fast_fn.args);
128 let ret = CTypeInfo::new(fast_fn.return_type);
129
130 let c_fn = unsafe {
133 CFunctionInfo::new(
134 args.as_ptr(),
135 fast_fn.args.len(),
136 ret.as_ptr(),
137 fast_fn.repr,
138 )
139 };
140 fast_fn_c_info = Some(c_fn);
141 }
142
143 Self {
144 id,
145 state,
146 get_error_class_fn,
147 runtime_state,
148 decl,
149 op_driver,
150 fast_fn_c_info,
151 last_fast_error: UnsafeCell::new(None),
152 isolate,
153 metrics_fn,
154 }
155 }
156
157 #[inline(always)]
158 pub const fn decl(&self) -> &OpDecl {
159 &self.decl
160 }
161
162 #[inline(always)]
163 pub const fn metrics_enabled(&self) -> bool {
164 self.metrics_fn.is_some()
165 }
166
167 pub const fn external_references(&self) -> [v8::ExternalReference; 4] {
170 extern "C" fn placeholder() {}
171
172 let ctx_ptr = v8::ExternalReference {
173 pointer: self as *const OpCtx as _,
174 };
175 let null = v8::ExternalReference {
176 pointer: placeholder as _,
177 };
178
179 if self.metrics_enabled() {
180 let slow_fn = v8::ExternalReference {
181 function: self.decl.slow_fn_with_metrics,
182 };
183 if let (Some(fast_fn), Some(fast_fn_c_info)) =
184 (&self.decl.fast_fn_with_metrics, &self.fast_fn_c_info)
185 {
186 let fast_fn = v8::ExternalReference {
187 pointer: fast_fn.function as _,
188 };
189 let fast_info = v8::ExternalReference {
190 pointer: fast_fn_c_info.as_ptr() as _,
191 };
192 [ctx_ptr, slow_fn, fast_fn, fast_info]
193 } else {
194 [ctx_ptr, slow_fn, null, null]
195 }
196 } else {
197 let slow_fn = v8::ExternalReference {
198 function: self.decl.slow_fn,
199 };
200 if let (Some(fast_fn), Some(fast_fn_c_info)) =
201 (&self.decl.fast_fn, &self.fast_fn_c_info)
202 {
203 let fast_fn = v8::ExternalReference {
204 pointer: fast_fn.function as _,
205 };
206 let fast_info = v8::ExternalReference {
207 pointer: fast_fn_c_info.as_ptr() as _,
208 };
209 [ctx_ptr, slow_fn, fast_fn, fast_info]
210 } else {
211 [ctx_ptr, slow_fn, null, null]
212 }
213 }
214 }
215
216 #[inline(always)]
223 pub unsafe fn unsafely_take_last_error_for_ops_only(
224 &self,
225 ) -> Option<AnyError> {
226 let opt_mut = &mut *self.last_fast_error.get();
227 opt_mut.take()
228 }
229
230 #[inline(always)]
237 pub unsafe fn unsafely_set_last_error_for_ops_only(&self, error: AnyError) {
238 let opt_mut = &mut *self.last_fast_error.get();
239 *opt_mut = Some(error);
240 }
241
242 pub(crate) fn op_driver(&self) -> &OpDriverImpl {
243 &self.op_driver
244 }
245
246 pub(crate) fn runtime_state(&self) -> &JsRuntimeState {
248 &self.runtime_state
249 }
250
251 pub fn metadata(&self) -> OpMetadata {
252 self.decl.metadata
253 }
254}
255
256pub struct OpState {
258 pub resource_table: ResourceTable,
259 pub(crate) gotham_state: GothamState,
260 pub waker: Arc<AtomicWaker>,
261 pub feature_checker: Arc<FeatureChecker>,
262}
263
264impl OpState {
265 pub fn new(maybe_feature_checker: Option<Arc<FeatureChecker>>) -> OpState {
266 OpState {
267 resource_table: Default::default(),
268 gotham_state: Default::default(),
269 waker: Arc::new(AtomicWaker::new()),
270 feature_checker: maybe_feature_checker.unwrap_or_default(),
271 }
272 }
273
274 pub(crate) fn clear(&mut self) {
276 std::mem::take(&mut self.gotham_state);
277 std::mem::take(&mut self.resource_table);
278 }
279}
280
281impl Deref for OpState {
282 type Target = GothamState;
283
284 fn deref(&self) -> &Self::Target {
285 &self.gotham_state
286 }
287}
288
289impl DerefMut for OpState {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 &mut self.gotham_state
292 }
293}