1use crate::isolate::RealIsolate;
2use crate::scope::PinScope;
3use crate::Context;
5use crate::Local;
6use crate::MicrotaskQueue;
7use crate::Object;
8use crate::ObjectTemplate;
9use crate::Value;
10use crate::Weak;
11use crate::handle::UnsafeRefHandle;
12use crate::isolate::BuildTypeIdHasher;
13use crate::isolate::RawSlot;
14use crate::support::int;
15use std::any::TypeId;
16use std::collections::HashMap;
17use std::ffi::c_void;
18use std::ptr::{null, null_mut};
19use std::rc::Rc;
20
21unsafe extern "C" {
22 fn v8__Context__New(
23 isolate: *mut RealIsolate,
24 templ: *const ObjectTemplate,
25 global_object: *const Value,
26 microtask_queue: *mut MicrotaskQueue,
27 ) -> *const Context;
28 fn v8__Isolate__GetCurrent() -> *mut RealIsolate;
29 fn v8__Context__Global(this: *const Context) -> *const Object;
30 fn v8__Context__GetExtrasBindingObject(this: *const Context)
31 -> *const Object;
32 fn v8__Context__GetNumberOfEmbedderDataFields(this: *const Context) -> u32;
33 fn v8__Context__GetAlignedPointerFromEmbedderData(
34 this: *const Context,
35 index: int,
36 ) -> *mut c_void;
37 fn v8__Context__SetAlignedPointerInEmbedderData(
38 this: *const Context,
39 index: int,
40 value: *mut c_void,
41 );
42 fn v8__Context__GetEmbedderData(
43 this: *const Context,
44 index: int,
45 ) -> *const Value;
46 fn v8__Context__SetEmbedderData(
47 this: *const Context,
48 index: int,
49 value: *const Value,
50 );
51 fn v8__Context__FromSnapshot(
52 isolate: *mut RealIsolate,
53 context_snapshot_index: usize,
54 global_object: *const Value,
55 microtask_queue: *mut MicrotaskQueue,
56 ) -> *const Context;
57 pub(super) fn v8__Context__GetSecurityToken(
58 this: *const Context,
59 ) -> *const Value;
60 pub(super) fn v8__Context__SetSecurityToken(
61 this: *const Context,
62 value: *const Value,
63 );
64 pub(super) fn v8__Context__UseDefaultSecurityToken(this: *const Context);
65 pub(super) fn v8__Context__AllowCodeGenerationFromStrings(
66 this: *const Context,
67 allow: bool,
68 );
69 pub(super) fn v8__Context_IsCodeGenerationFromStringsAllowed(
70 this: *const Context,
71 ) -> bool;
72 fn v8__Context__GetMicrotaskQueue(
73 this: *const Context,
74 ) -> *const MicrotaskQueue;
75 fn v8__Context__SetMicrotaskQueue(
76 this: *const Context,
77 microtask_queue: *const MicrotaskQueue,
78 );
79}
80
81#[derive(Default)]
82pub struct ContextOptions<'s> {
83 pub global_template: Option<Local<'s, ObjectTemplate>>,
86 pub global_object: Option<Local<'s, Value>>,
91 pub microtask_queue: Option<*mut MicrotaskQueue>,
94}
95
96impl Context {
97 const ANNEX_SLOT: int = 1;
98 const INTERNAL_SLOT_COUNT: int = 2;
99
100 #[inline(always)]
102 pub fn new<'s>(
103 scope: &PinScope<'s, '_, ()>,
104 options: ContextOptions,
105 ) -> Local<'s, Context> {
106 unsafe {
107 scope.cast_local(|sd| {
108 v8__Context__New(
109 sd.get_isolate_ptr(),
110 options
111 .global_template
112 .map_or_else(null, |t| &*t as *const _),
113 options.global_object.map_or_else(null, |o| &*o as *const _),
114 options.microtask_queue.unwrap_or_else(null_mut),
115 )
116 })
117 }
118 .unwrap()
119 }
120
121 #[inline(always)]
122 pub fn get_extras_binding_object<'s>(
123 &self,
124 scope: &PinScope<'s, '_, ()>,
125 ) -> Local<'s, Object> {
126 unsafe { scope.cast_local(|_| v8__Context__GetExtrasBindingObject(self)) }
127 .unwrap()
128 }
129
130 #[inline(always)]
141 pub fn global<'s>(&self, scope: &PinScope<'s, '_, ()>) -> Local<'s, Object> {
142 unsafe { scope.cast_local(|_| v8__Context__Global(self)) }.unwrap()
143 }
144
145 #[inline(always)]
146 pub fn get_microtask_queue(&self) -> &MicrotaskQueue {
147 unsafe { &*v8__Context__GetMicrotaskQueue(self) }
148 }
149
150 #[inline(always)]
151 pub fn set_microtask_queue(&self, microtask_queue: &MicrotaskQueue) {
152 unsafe {
153 v8__Context__SetMicrotaskQueue(self, microtask_queue);
154 }
155 }
156
157 #[inline]
158 #[allow(clippy::mut_from_ref)]
159 fn get_annex_mut(
160 &self,
161 create_if_not_present: bool,
162 ) -> Option<&mut ContextAnnex> {
163 let isolate = unsafe { v8__Isolate__GetCurrent() };
164 let mut isolate = unsafe { crate::isolate::Isolate::from_raw_ptr(isolate) };
165
166 let num_data_fields =
167 unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int;
168 if num_data_fields > Self::ANNEX_SLOT {
169 let annex_ptr = unsafe {
170 v8__Context__GetAlignedPointerFromEmbedderData(self, Self::ANNEX_SLOT)
171 } as *mut ContextAnnex;
172 if !annex_ptr.is_null() {
173 return Some(unsafe { &mut *annex_ptr });
179 }
180 }
181
182 if !create_if_not_present {
183 return None;
184 }
185
186 let annex = Box::new(ContextAnnex {
187 slots: Default::default(),
188 self_weak: Weak::empty(&mut isolate),
190 });
191 let annex_ptr = Box::into_raw(annex);
192 unsafe {
193 v8__Context__SetAlignedPointerInEmbedderData(
194 self,
195 Self::ANNEX_SLOT,
196 annex_ptr as *mut _,
197 );
198 };
199 assert!(
200 unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int
201 > Self::ANNEX_SLOT
202 );
203
204 let weak = {
208 let self_ref_handle = unsafe { UnsafeRefHandle::new(self, &mut isolate) };
213
214 Weak::with_guaranteed_finalizer(
215 &mut isolate,
216 self_ref_handle,
217 Box::new(move || {
218 let _ = unsafe { Box::from_raw(annex_ptr) };
224 }),
225 )
226 };
227
228 let annex_mut = unsafe { &mut *annex_ptr };
234 annex_mut.self_weak = weak;
235 Some(annex_mut)
236 }
237
238 #[inline(always)]
240 pub fn get_slot<T: 'static>(&self) -> Option<Rc<T>> {
241 if let Some(annex) = self.get_annex_mut(false) {
242 annex.slots.get(&TypeId::of::<T>()).map(|slot| {
243 unsafe { slot.borrow::<Rc<T>>().clone() }
246 })
247 } else {
248 None
249 }
250 }
251
252 #[inline(always)]
264 pub fn set_slot<T: 'static>(&self, value: Rc<T>) -> Option<Rc<T>> {
265 self
266 .get_annex_mut(true)
267 .unwrap()
268 .slots
269 .insert(TypeId::of::<T>(), RawSlot::new(value))
270 .map(|slot| {
271 unsafe { slot.into_inner::<Rc<T>>() }
274 })
275 }
276
277 #[inline(always)]
280 pub fn remove_slot<T: 'static>(&self) -> Option<Rc<T>> {
281 if let Some(annex) = self.get_annex_mut(false) {
282 annex.slots.remove(&TypeId::of::<T>()).map(|slot| {
283 unsafe { slot.into_inner::<Rc<T>>() }
286 })
287 } else {
288 None
289 }
290 }
291
292 #[inline(always)]
300 pub fn clear_all_slots(&self) {
301 if let Some(annex_mut) = self.get_annex_mut(false) {
302 let annex_ptr = annex_mut as *mut ContextAnnex;
303 let _ = unsafe { Box::from_raw(annex_ptr) };
304 unsafe {
305 v8__Context__SetAlignedPointerInEmbedderData(
306 self,
307 Self::ANNEX_SLOT,
308 null_mut(),
309 );
310 };
311 }
312 }
313
314 #[inline(always)]
318 pub fn set_embedder_data(&self, slot: i32, data: Local<'_, Value>) {
319 self.get_annex_mut(true);
321
322 unsafe {
323 v8__Context__SetEmbedderData(
324 self,
325 slot + Self::INTERNAL_SLOT_COUNT,
326 &*data,
327 );
328 }
329 }
330
331 #[inline(always)]
334 pub fn get_embedder_data<'s>(
335 &self,
336 scope: &PinScope<'s, '_, ()>,
337 slot: i32,
338 ) -> Option<Local<'s, Value>> {
339 unsafe {
340 scope.cast_local(|_| {
341 v8__Context__GetEmbedderData(self, slot + Self::INTERNAL_SLOT_COUNT)
342 })
343 }
344 }
345
346 #[inline(always)]
347 pub unsafe fn set_aligned_pointer_in_embedder_data(
348 &self,
349 slot: i32,
350 data: *mut c_void,
351 ) {
352 self.get_annex_mut(true);
354
355 unsafe {
356 v8__Context__SetAlignedPointerInEmbedderData(
357 self,
358 slot + Self::INTERNAL_SLOT_COUNT,
359 data,
360 );
361 }
362 }
363
364 #[inline(always)]
365 pub fn get_aligned_pointer_from_embedder_data(
366 &self,
367 slot: i32,
368 ) -> *mut c_void {
369 unsafe {
370 v8__Context__GetAlignedPointerFromEmbedderData(
371 self,
372 slot + Self::INTERNAL_SLOT_COUNT,
373 )
374 }
375 }
376
377 pub fn from_snapshot<'s>(
381 scope: &PinScope<'s, '_, ()>,
382 context_snapshot_index: usize,
383 options: ContextOptions,
384 ) -> Option<Local<'s, Context>> {
385 unsafe {
386 scope.cast_local(|sd| {
387 v8__Context__FromSnapshot(
388 sd.get_isolate_ptr(),
389 context_snapshot_index,
390 options.global_object.map_or_else(null, |o| &*o as *const _),
391 options.microtask_queue.unwrap_or_else(null_mut),
392 )
393 })
394 }
395 }
396
397 #[inline(always)]
398 pub fn get_security_token<'s>(
399 &self,
400 scope: &PinScope<'s, '_, ()>,
401 ) -> Local<'s, Value> {
402 unsafe { scope.cast_local(|_| v8__Context__GetSecurityToken(self)) }
403 .unwrap()
404 }
405
406 #[inline(always)]
407 pub fn set_security_token(&self, token: Local<Value>) {
408 unsafe {
409 v8__Context__SetSecurityToken(self, &*token);
410 }
411 }
412
413 #[inline(always)]
414 pub fn use_default_security_token(&self) {
415 unsafe {
416 v8__Context__UseDefaultSecurityToken(self);
417 }
418 }
419
420 pub fn set_allow_generation_from_strings(&self, allow: bool) {
421 unsafe {
422 v8__Context__AllowCodeGenerationFromStrings(self, allow);
423 }
424 }
425
426 pub fn is_code_generation_from_strings_allowed(&self) -> bool {
427 unsafe { v8__Context_IsCodeGenerationFromStringsAllowed(self) }
428 }
429}
430
431struct ContextAnnex {
432 slots: HashMap<TypeId, RawSlot, BuildTypeIdHasher>,
433 self_weak: Weak<Context>,
436}