1use crate::Context;
3use crate::HandleScope;
4use crate::Local;
5use crate::MicrotaskQueue;
6use crate::Object;
7use crate::ObjectTemplate;
8use crate::Value;
9use crate::Weak;
10use crate::handle::UnsafeRefHandle;
11use crate::isolate::BuildTypeIdHasher;
12use crate::isolate::Isolate;
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 Isolate,
24 templ: *const ObjectTemplate,
25 global_object: *const Value,
26 microtask_queue: *mut MicrotaskQueue,
27 ) -> *const Context;
28 fn v8__Context__GetIsolate(this: *const Context) -> *mut Isolate;
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 Isolate,
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 = 1;
99
100 #[inline(always)]
102 pub fn new<'s>(
103 scope: &mut HandleScope<'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: &mut HandleScope<'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>(
142 &self,
143 scope: &mut HandleScope<'s, ()>,
144 ) -> Local<'s, Object> {
145 unsafe { scope.cast_local(|_| v8__Context__Global(self)) }.unwrap()
146 }
147
148 #[inline(always)]
149 pub fn get_microtask_queue(&self) -> &MicrotaskQueue {
150 unsafe { &*v8__Context__GetMicrotaskQueue(self) }
151 }
152
153 #[inline(always)]
154 pub fn set_microtask_queue(&self, microtask_queue: &MicrotaskQueue) {
155 unsafe {
156 v8__Context__SetMicrotaskQueue(self, microtask_queue);
157 }
158 }
159
160 #[inline]
161 fn get_annex_mut(
162 &self,
163 create_if_not_present: bool,
164 ) -> Option<&mut ContextAnnex> {
165 let isolate = unsafe { &mut *v8__Context__GetIsolate(self) };
166
167 let num_data_fields =
168 unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int;
169 if num_data_fields > Self::ANNEX_SLOT {
170 let annex_ptr = unsafe {
171 v8__Context__GetAlignedPointerFromEmbedderData(self, Self::ANNEX_SLOT)
172 } as *mut ContextAnnex;
173 if !annex_ptr.is_null() {
174 return Some(unsafe { &mut *annex_ptr });
180 }
181 }
182
183 if !create_if_not_present {
184 return None;
185 }
186
187 let annex = Box::new(ContextAnnex {
188 slots: Default::default(),
189 self_weak: Weak::empty(isolate),
191 });
192 let annex_ptr = Box::into_raw(annex);
193 unsafe {
194 v8__Context__SetAlignedPointerInEmbedderData(
195 self,
196 Self::ANNEX_SLOT,
197 annex_ptr as *mut _,
198 );
199 };
200 assert!(
201 unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int
202 > Self::ANNEX_SLOT
203 );
204
205 let weak = {
209 let self_ref_handle = unsafe { UnsafeRefHandle::new(self, isolate) };
214
215 Weak::with_guaranteed_finalizer(
216 isolate,
217 self_ref_handle,
218 Box::new(move || {
219 let _ = unsafe { Box::from_raw(annex_ptr) };
225 }),
226 )
227 };
228
229 let annex_mut = unsafe { &mut *annex_ptr };
235 annex_mut.self_weak = weak;
236 Some(annex_mut)
237 }
238
239 #[inline(always)]
241 pub fn get_slot<T: 'static>(&self) -> Option<Rc<T>> {
242 if let Some(annex) = self.get_annex_mut(false) {
243 annex.slots.get(&TypeId::of::<T>()).map(|slot| {
244 unsafe { slot.borrow::<Rc<T>>().clone() }
247 })
248 } else {
249 None
250 }
251 }
252
253 #[inline(always)]
265 pub fn set_slot<T: 'static>(&self, value: Rc<T>) -> Option<Rc<T>> {
266 self
267 .get_annex_mut(true)
268 .unwrap()
269 .slots
270 .insert(TypeId::of::<T>(), RawSlot::new(value))
271 .map(|slot| {
272 unsafe { slot.into_inner::<Rc<T>>() }
275 })
276 }
277
278 #[inline(always)]
281 pub fn remove_slot<T: 'static>(&self) -> Option<Rc<T>> {
282 if let Some(annex) = self.get_annex_mut(false) {
283 annex.slots.remove(&TypeId::of::<T>()).map(|slot| {
284 unsafe { slot.into_inner::<Rc<T>>() }
287 })
288 } else {
289 None
290 }
291 }
292
293 #[inline(always)]
301 pub fn clear_all_slots(&self) {
302 if let Some(annex_mut) = self.get_annex_mut(false) {
303 let annex_ptr = annex_mut as *mut ContextAnnex;
304 let _ = unsafe { Box::from_raw(annex_ptr) };
305 unsafe {
306 v8__Context__SetAlignedPointerInEmbedderData(
307 self,
308 Self::ANNEX_SLOT,
309 null_mut(),
310 );
311 };
312 }
313 }
314
315 #[inline(always)]
319 pub fn set_embedder_data(&self, slot: i32, data: Local<'_, Value>) {
320 unsafe {
321 v8__Context__SetEmbedderData(self, slot, &*data);
322 }
323 }
324
325 #[inline(always)]
328 pub fn get_embedder_data<'s>(
329 &self,
330 scope: &mut HandleScope<'s, ()>,
331 slot: i32,
332 ) -> Option<Local<'s, Value>> {
333 unsafe { scope.cast_local(|_| v8__Context__GetEmbedderData(self, slot)) }
334 }
335
336 #[inline(always)]
337 pub unsafe fn set_aligned_pointer_in_embedder_data(
338 &self,
339 slot: i32,
340 data: *mut c_void,
341 ) {
342 self.get_annex_mut(true);
344
345 unsafe {
346 v8__Context__SetAlignedPointerInEmbedderData(
347 self,
348 slot + Self::INTERNAL_SLOT_COUNT,
349 data,
350 );
351 }
352 }
353
354 #[inline(always)]
355 pub fn get_aligned_pointer_from_embedder_data(
356 &self,
357 slot: i32,
358 ) -> *mut c_void {
359 unsafe {
360 v8__Context__GetAlignedPointerFromEmbedderData(
361 self,
362 slot + Self::INTERNAL_SLOT_COUNT,
363 )
364 }
365 }
366
367 pub fn from_snapshot<'s>(
371 scope: &mut HandleScope<'s, ()>,
372 context_snapshot_index: usize,
373 options: ContextOptions,
374 ) -> Option<Local<'s, Context>> {
375 unsafe {
376 scope.cast_local(|sd| {
377 v8__Context__FromSnapshot(
378 sd.get_isolate_mut(),
379 context_snapshot_index,
380 options.global_object.map_or_else(null, |o| &*o as *const _),
381 options.microtask_queue.unwrap_or_else(null_mut),
382 )
383 })
384 }
385 }
386
387 #[inline(always)]
388 pub fn get_security_token<'s>(
389 &self,
390 scope: &mut HandleScope<'s, ()>,
391 ) -> Local<'s, Value> {
392 unsafe { scope.cast_local(|_| v8__Context__GetSecurityToken(self)) }
393 .unwrap()
394 }
395
396 #[inline(always)]
397 pub fn set_security_token(&self, token: Local<Value>) {
398 unsafe {
399 v8__Context__SetSecurityToken(self, &*token);
400 }
401 }
402
403 #[inline(always)]
404 pub fn use_default_security_token(&self) {
405 unsafe {
406 v8__Context__UseDefaultSecurityToken(self);
407 }
408 }
409
410 pub fn set_allow_generation_from_strings(&self, allow: bool) {
411 unsafe {
412 v8__Context__AllowCodeGenerationFromStrings(self, allow);
413 }
414 }
415
416 pub fn is_code_generation_from_strings_allowed(&self) -> bool {
417 unsafe { v8__Context_IsCodeGenerationFromStringsAllowed(self) }
418 }
419}
420
421struct ContextAnnex {
422 slots: HashMap<TypeId, RawSlot, BuildTypeIdHasher>,
423 self_weak: Weak<Context>,
426}