mozjs/
rust.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5//! Rust wrappers around the raw JS apis
6
7use std::cell::Cell;
8use std::char;
9use std::default::Default;
10use std::ffi::{CStr, CString};
11use std::marker::PhantomData;
12use std::mem::MaybeUninit;
13use std::ops::{Deref, DerefMut};
14use std::ptr::{self, NonNull};
15use std::slice;
16use std::str;
17use std::sync::atomic::{AtomicU32, Ordering};
18use std::sync::{Arc, Mutex, RwLock};
19
20use self::wrappers::{
21    StackGCVectorStringAtIndex, StackGCVectorStringLength, StackGCVectorValueAtIndex,
22    StackGCVectorValueLength,
23};
24use crate::consts::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_RESERVED_SLOTS_MASK};
25use crate::consts::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
26use crate::conversions::jsstr_to_string;
27use crate::default_heapsize;
28pub use crate::gc::*;
29use crate::glue::AppendToRootedObjectVector;
30use crate::glue::{CreateRootedIdVector, CreateRootedObjectVector};
31use crate::glue::{
32    DeleteCompileOptions, DeleteRootedObjectVector, DescribeScriptedCaller, DestroyRootedIdVector,
33};
34use crate::glue::{DeleteJSAutoStructuredCloneBuffer, NewJSAutoStructuredCloneBuffer};
35use crate::glue::{
36    GetIdVectorAddress, GetObjectVectorAddress, NewCompileOptions, SliceRootedIdVector,
37};
38use crate::jsapi;
39use crate::jsapi::glue::{DeleteRealmOptions, JS_Init, JS_NewRealmOptions};
40use crate::jsapi::js;
41use crate::jsapi::js::frontend::InitialStencilAndDelazifications;
42use crate::jsapi::mozilla::Utf8Unit;
43use crate::jsapi::shadow::BaseShape;
44use crate::jsapi::HandleObjectVector as RawHandleObjectVector;
45use crate::jsapi::HandleValue as RawHandleValue;
46use crate::jsapi::JS_AddExtraGCRootsTracer;
47use crate::jsapi::MutableHandleIdVector as RawMutableHandleIdVector;
48use crate::jsapi::{already_AddRefed, jsid};
49use crate::jsapi::{BuildStackString, CaptureCurrentStack, StackFormat};
50use crate::jsapi::{Evaluate2, HandleValueArray, StencilRelease};
51use crate::jsapi::{InitSelfHostedCode, IsWindowSlow};
52use crate::jsapi::{
53    JSAutoRealm, JS_SetGCParameter, JS_SetNativeStackQuota, JS_WrapObject, JS_WrapValue,
54};
55use crate::jsapi::{JSAutoStructuredCloneBuffer, JSStructuredCloneCallbacks, StructuredCloneScope};
56use crate::jsapi::{JSClass, JSClassOps, JSContext, Realm, JSCLASS_RESERVED_SLOTS_SHIFT};
57use crate::jsapi::{JSErrorReport, JSFunctionSpec, JSGCParamKey};
58use crate::jsapi::{JSObject, JSPropertySpec, JSRuntime};
59use crate::jsapi::{JSString, Object, PersistentRootedIdVector};
60use crate::jsapi::{JS_DefineFunctions, JS_DefineProperties, JS_DestroyContext, JS_ShutDown};
61use crate::jsapi::{JS_EnumerateStandardClasses, JS_GetRuntime, JS_GlobalObjectTraceHook};
62use crate::jsapi::{JS_MayResolveStandardClass, JS_NewContext, JS_ResolveStandardClass};
63use crate::jsapi::{JS_RequestInterruptCallback, JS_RequestInterruptCallbackCanWait};
64use crate::jsapi::{JS_StackCapture_AllFrames, JS_StackCapture_MaxFrames};
65use crate::jsapi::{PersistentRootedObjectVector, ReadOnlyCompileOptions, RootingContext};
66use crate::jsapi::{SetWarningReporter, SourceText, ToBooleanSlow};
67use crate::jsapi::{ToInt32Slow, ToInt64Slow, ToNumberSlow, ToStringSlow, ToUint16Slow};
68use crate::jsapi::{ToUint32Slow, ToUint64Slow, ToWindowProxyIfWindowSlow};
69use crate::jsval::{JSVal, ObjectValue};
70use crate::panic::maybe_resume_unwind;
71use log::{debug, warn};
72use mozjs_sys::jsapi::JS::SavedFrameResult;
73pub use mozjs_sys::jsgc::{GCMethods, IntoHandle, IntoMutableHandle};
74pub use mozjs_sys::trace::Traceable as Trace;
75
76use crate::rooted;
77
78// From Gecko:
79// Our "default" stack is what we use in configurations where we don't have a compelling reason to
80// do things differently. This is effectively 1MB on 64-bit platforms.
81const STACK_QUOTA: usize = 128 * 8 * 1024;
82
83// From Gecko:
84// The JS engine permits us to set different stack limits for system code,
85// trusted script, and untrusted script. We have tests that ensure that
86// we can always execute 10 "heavy" (eval+with) stack frames deeper in
87// privileged code. Our stack sizes vary greatly in different configurations,
88// so satisfying those tests requires some care. Manual measurements of the
89// number of heavy stack frames achievable gives us the following rough data,
90// ordered by the effective categories in which they are grouped in the
91// JS_SetNativeStackQuota call (which predates this analysis).
92//
93// (NB: These numbers may have drifted recently - see bug 938429)
94// OSX 64-bit Debug: 7MB stack, 636 stack frames => ~11.3k per stack frame
95// OSX64 Opt: 7MB stack, 2440 stack frames => ~3k per stack frame
96//
97// Linux 32-bit Debug: 2MB stack, 426 stack frames => ~4.8k per stack frame
98// Linux 64-bit Debug: 4MB stack, 455 stack frames => ~9.0k per stack frame
99//
100// Windows (Opt+Debug): 900K stack, 235 stack frames => ~3.4k per stack frame
101//
102// Linux 32-bit Opt: 1MB stack, 272 stack frames => ~3.8k per stack frame
103// Linux 64-bit Opt: 2MB stack, 316 stack frames => ~6.5k per stack frame
104//
105// We tune the trusted/untrusted quotas for each configuration to achieve our
106// invariants while attempting to minimize overhead. In contrast, our buffer
107// between system code and trusted script is a very unscientific 10k.
108const SYSTEM_CODE_BUFFER: usize = 10 * 1024;
109
110// Gecko's value on 64-bit.
111const TRUSTED_SCRIPT_BUFFER: usize = 8 * 12800;
112
113trait ToResult {
114    fn to_result(self) -> Result<(), ()>;
115}
116
117impl ToResult for bool {
118    fn to_result(self) -> Result<(), ()> {
119        if self {
120            Ok(())
121        } else {
122            Err(())
123        }
124    }
125}
126
127// ___________________________________________________________________________
128// friendly Rustic API to runtimes
129
130pub struct RealmOptions(*mut jsapi::RealmOptions);
131
132impl Deref for RealmOptions {
133    type Target = jsapi::RealmOptions;
134    fn deref(&self) -> &Self::Target {
135        unsafe { &*self.0 }
136    }
137}
138
139impl DerefMut for RealmOptions {
140    fn deref_mut(&mut self) -> &mut Self::Target {
141        unsafe { &mut *self.0 }
142    }
143}
144
145impl Default for RealmOptions {
146    fn default() -> RealmOptions {
147        RealmOptions(unsafe { JS_NewRealmOptions() })
148    }
149}
150
151impl Drop for RealmOptions {
152    fn drop(&mut self) {
153        unsafe { DeleteRealmOptions(self.0) }
154    }
155}
156
157thread_local!(static CONTEXT: Cell<Option<NonNull<JSContext>>> = Cell::new(None));
158
159#[derive(PartialEq)]
160enum EngineState {
161    Uninitialized,
162    InitFailed,
163    Initialized,
164    ShutDown,
165}
166
167static ENGINE_STATE: Mutex<EngineState> = Mutex::new(EngineState::Uninitialized);
168
169#[derive(Debug)]
170pub enum JSEngineError {
171    AlreadyInitialized,
172    AlreadyShutDown,
173    InitFailed,
174}
175
176/// A handle that must be kept alive in order to create new Runtimes.
177/// When this handle is dropped, the engine is shut down and cannot
178/// be reinitialized.
179pub struct JSEngine {
180    /// The count of alive handles derived from this initialized instance.
181    outstanding_handles: Arc<AtomicU32>,
182    // Ensure this type cannot be sent between threads.
183    marker: PhantomData<*mut ()>,
184}
185
186pub struct JSEngineHandle(Arc<AtomicU32>);
187
188impl Clone for JSEngineHandle {
189    fn clone(&self) -> JSEngineHandle {
190        self.0.fetch_add(1, Ordering::SeqCst);
191        JSEngineHandle(self.0.clone())
192    }
193}
194
195impl Drop for JSEngineHandle {
196    fn drop(&mut self) {
197        self.0.fetch_sub(1, Ordering::SeqCst);
198    }
199}
200
201impl JSEngine {
202    /// Initialize the JS engine to prepare for creating new JS runtimes.
203    pub fn init() -> Result<JSEngine, JSEngineError> {
204        let mut state = ENGINE_STATE.lock().unwrap();
205        match *state {
206            EngineState::Initialized => return Err(JSEngineError::AlreadyInitialized),
207            EngineState::InitFailed => return Err(JSEngineError::InitFailed),
208            EngineState::ShutDown => return Err(JSEngineError::AlreadyShutDown),
209            EngineState::Uninitialized => (),
210        }
211        if unsafe { !JS_Init() } {
212            *state = EngineState::InitFailed;
213            Err(JSEngineError::InitFailed)
214        } else {
215            *state = EngineState::Initialized;
216            Ok(JSEngine {
217                outstanding_handles: Arc::new(AtomicU32::new(0)),
218                marker: PhantomData,
219            })
220        }
221    }
222
223    pub fn can_shutdown(&self) -> bool {
224        self.outstanding_handles.load(Ordering::SeqCst) == 0
225    }
226
227    /// Create a handle to this engine.
228    pub fn handle(&self) -> JSEngineHandle {
229        self.outstanding_handles.fetch_add(1, Ordering::SeqCst);
230        JSEngineHandle(self.outstanding_handles.clone())
231    }
232}
233
234/// Shut down the JS engine, invalidating any existing runtimes and preventing
235/// any new ones from being created.
236impl Drop for JSEngine {
237    fn drop(&mut self) {
238        let mut state = ENGINE_STATE.lock().unwrap();
239        if *state == EngineState::Initialized {
240            assert_eq!(
241                self.outstanding_handles.load(Ordering::SeqCst),
242                0,
243                "There are outstanding JS engine handles"
244            );
245            *state = EngineState::ShutDown;
246            unsafe {
247                JS_ShutDown();
248            }
249        }
250    }
251}
252
253pub fn transform_str_to_source_text(source: &str) -> SourceText<Utf8Unit> {
254    SourceText {
255        units_: source.as_ptr() as *const _,
256        length_: source.len() as u32,
257        ownsUnits_: false,
258        _phantom_0: PhantomData,
259    }
260}
261
262pub fn transform_u16_to_source_text(source: &[u16]) -> SourceText<u16> {
263    SourceText {
264        units_: source.as_ptr() as *const _,
265        length_: source.len() as u32,
266        ownsUnits_: false,
267        _phantom_0: PhantomData,
268    }
269}
270
271/// A handle to a Runtime that will be used to create a new runtime in another
272/// thread. This handle and the new runtime must be destroyed before the original
273/// runtime can be dropped.
274pub struct ParentRuntime {
275    /// Raw pointer to the underlying SpiderMonkey runtime.
276    parent: *mut JSRuntime,
277    /// Handle to ensure the JS engine remains running while this handle exists.
278    engine: JSEngineHandle,
279    /// The number of children of the runtime that created this ParentRuntime value.
280    children_of_parent: Arc<()>,
281}
282unsafe impl Send for ParentRuntime {}
283
284/// A wrapper for the `JSContext` structure in SpiderMonkey.
285pub struct Runtime {
286    /// Safe SpiderMonkey context.
287    cx: crate::context::JSContext,
288    /// The engine that this runtime is associated with.
289    engine: JSEngineHandle,
290    /// If this Runtime was created with a parent, this member exists to ensure
291    /// that that parent's count of outstanding children (see [outstanding_children])
292    /// remains accurate and will be automatically decreased when this Runtime value
293    /// is dropped.
294    _parent_child_count: Option<Arc<()>>,
295    /// The strong references to this value represent the number of child runtimes
296    /// that have been created using this Runtime as a parent. Since Runtime values
297    /// must be associated with a particular thread, we cannot simply use Arc<Runtime>
298    /// to represent the resulting ownership graph and risk destroying a Runtime on
299    /// the wrong thread.
300    outstanding_children: Arc<()>,
301    /// An `Option` that holds the same pointer as `cx`.
302    /// This is shared with all [`ThreadSafeJSContext`]s, so
303    /// they can detect when it's destroyed on the main thread.
304    thread_safe_handle: Arc<RwLock<Option<NonNull<JSContext>>>>,
305}
306
307impl Runtime {
308    /// Get the `JSContext` for this thread.
309    ///
310    /// This will eventually be removed for in favour of [crate::context::JSContext]
311    pub fn get() -> Option<NonNull<JSContext>> {
312        CONTEXT.with(|context| context.get())
313    }
314
315    /// Create a [`ThreadSafeJSContext`] that can detect when this `Runtime` is destroyed.
316    pub fn thread_safe_js_context(&self) -> ThreadSafeJSContext {
317        // Existence of `ThreadSafeJSContext` does not actually break invariant of
318        // JSContext, because it can be used for limited subset of methods and they do not trigger GC
319        ThreadSafeJSContext(self.thread_safe_handle.clone())
320    }
321
322    /// Creates a new `JSContext`.
323    pub fn new(engine: JSEngineHandle) -> Runtime {
324        unsafe { Self::create(engine, None) }
325    }
326
327    /// Signal that a new child runtime will be created in the future, and ensure
328    /// that this runtime will not allow itself to be destroyed before the new
329    /// child runtime. Returns a handle that can be passed to `create_with_parent`
330    /// in order to create a new runtime on another thread that is associated with
331    /// this runtime.
332    pub fn prepare_for_new_child(&self) -> ParentRuntime {
333        ParentRuntime {
334            parent: self.rt(),
335            engine: self.engine.clone(),
336            children_of_parent: self.outstanding_children.clone(),
337        }
338    }
339
340    /// Creates a new `JSContext` with a parent runtime. If the parent does not outlive
341    /// the new runtime, its destructor will assert.
342    ///
343    /// Unsafety:
344    /// If panicking does not abort the program, any threads with child runtimes will
345    /// continue executing after the thread with the parent runtime panics, but they
346    /// will be in an invalid and undefined state.
347    pub unsafe fn create_with_parent(parent: ParentRuntime) -> Runtime {
348        Self::create(parent.engine.clone(), Some(parent))
349    }
350
351    unsafe fn create(engine: JSEngineHandle, parent: Option<ParentRuntime>) -> Runtime {
352        let parent_runtime = parent.as_ref().map_or(ptr::null_mut(), |r| r.parent);
353        let js_context = NonNull::new(JS_NewContext(
354            default_heapsize + (ChunkSize as u32),
355            parent_runtime,
356        ))
357        .unwrap();
358
359        // Unconstrain the runtime's threshold on nominal heap size, to avoid
360        // triggering GC too often if operating continuously near an arbitrary
361        // finite threshold. This leaves the maximum-JS_malloc-bytes threshold
362        // still in effect to cause periodical, and we hope hygienic,
363        // last-ditch GCs from within the GC's allocator.
364        JS_SetGCParameter(js_context.as_ptr(), JSGCParamKey::JSGC_MAX_BYTES, u32::MAX);
365
366        JS_AddExtraGCRootsTracer(js_context.as_ptr(), Some(trace_traceables), ptr::null_mut());
367
368        JS_SetNativeStackQuota(
369            js_context.as_ptr(),
370            STACK_QUOTA,
371            STACK_QUOTA - SYSTEM_CODE_BUFFER,
372            STACK_QUOTA - SYSTEM_CODE_BUFFER - TRUSTED_SCRIPT_BUFFER,
373        );
374
375        CONTEXT.with(|context| {
376            assert!(context.get().is_none());
377            context.set(Some(js_context));
378        });
379
380        #[cfg(target_pointer_width = "64")]
381        let cache = crate::jsapi::__BindgenOpaqueArray::<u64, 2>::default();
382        #[cfg(target_pointer_width = "32")]
383        let cache = crate::jsapi::__BindgenOpaqueArray::<u32, 2>::default();
384
385        InitSelfHostedCode(js_context.as_ptr(), cache, None);
386
387        SetWarningReporter(js_context.as_ptr(), Some(report_warning));
388
389        Runtime {
390            engine,
391            _parent_child_count: parent.map(|p| p.children_of_parent),
392            cx: crate::context::JSContext::from_ptr(js_context),
393            outstanding_children: Arc::new(()),
394            thread_safe_handle: Arc::new(RwLock::new(Some(js_context))),
395        }
396    }
397
398    /// Returns the `JSRuntime` object.
399    pub fn rt(&self) -> *mut JSRuntime {
400        // SAFETY: JS_GetRuntime does not trigger GC
401        unsafe { JS_GetRuntime(self.cx.raw_cx_no_gc()) }
402    }
403
404    /// Returns the `JSContext` object.
405    pub fn cx<'rt>(&'rt mut self) -> &'rt mut crate::context::JSContext {
406        &mut self.cx
407    }
408
409    /// Returns the `JSContext` object.
410    pub fn cx_no_gc<'rt>(&'rt self) -> &'rt crate::context::JSContext {
411        &self.cx
412    }
413
414    pub fn evaluate_script(
415        &mut self,
416        glob: HandleObject,
417        script: &str,
418        rval: MutableHandleValue,
419        options: CompileOptionsWrapper,
420    ) -> Result<(), ()> {
421        evaluate_script(self.cx(), glob, script, rval, options)
422    }
423
424    pub fn new_compile_options(&self, filename: &str, line: u32) -> CompileOptionsWrapper {
425        // SAFETY: `cx` argument points to a non-null, valid JSContext
426        unsafe { CompileOptionsWrapper::new(self.cx_no_gc().raw_cx_no_gc(), filename, line) }
427    }
428}
429
430pub fn evaluate_script(
431    cx: &mut crate::context::JSContext,
432    glob: HandleObject,
433    script: &str,
434    rval: MutableHandleValue,
435    options: CompileOptionsWrapper,
436) -> Result<(), ()> {
437    debug!(
438        "Evaluating script from {} with content {}",
439        options.filename(),
440        script
441    );
442
443    let _ac = JSAutoRealm::new(unsafe { cx.raw_cx() }, glob.get());
444
445    unsafe {
446        let mut source = transform_str_to_source_text(&script);
447        if !Evaluate2(cx.raw_cx(), options.ptr, &mut source, rval.into()) {
448            debug!("...err!");
449            maybe_resume_unwind();
450            Err(())
451        } else {
452            // we could return the script result but then we'd have
453            // to root it and so forth and, really, who cares?
454            debug!("...ok!");
455            Ok(())
456        }
457    }
458}
459
460impl Drop for Runtime {
461    fn drop(&mut self) {
462        self.thread_safe_handle.write().unwrap().take();
463        assert!(
464            Arc::get_mut(&mut self.outstanding_children).is_some(),
465            "This runtime still has live children."
466        );
467        unsafe {
468            JS_DestroyContext(self.cx.raw_cx());
469
470            CONTEXT.with(|context| {
471                assert!(context.take().is_some());
472            });
473        }
474    }
475}
476
477/// A version of the [`JSContext`] that can be used from other threads and is thus
478/// `Send` and `Sync`. This should only ever expose operations that are marked as
479/// thread-safe by the SpiderMonkey API, ie ones that only atomic fields in JSContext.
480#[derive(Clone)]
481pub struct ThreadSafeJSContext(Arc<RwLock<Option<NonNull<JSContext>>>>);
482
483unsafe impl Send for ThreadSafeJSContext {}
484unsafe impl Sync for ThreadSafeJSContext {}
485
486impl ThreadSafeJSContext {
487    /// Call `JS_RequestInterruptCallback` from the SpiderMonkey API.
488    /// This is thread-safe according to
489    /// <https://searchfox.org/mozilla-central/rev/7a85a111b5f42cdc07f438e36f9597c4c6dc1d48/js/public/Interrupt.h#19>
490    pub fn request_interrupt_callback(&self) {
491        if let Some(cx) = self.0.read().unwrap().as_ref() {
492            unsafe {
493                JS_RequestInterruptCallback(cx.as_ptr());
494            }
495        }
496    }
497
498    /// Call `JS_RequestInterruptCallbackCanWait` from the SpiderMonkey API.
499    /// This is thread-safe according to
500    /// <https://searchfox.org/mozilla-central/rev/7a85a111b5f42cdc07f438e36f9597c4c6dc1d48/js/public/Interrupt.h#19>
501    pub fn request_interrupt_callback_can_wait(&self) {
502        if let Some(cx) = self.0.read().unwrap().as_ref() {
503            unsafe {
504                JS_RequestInterruptCallbackCanWait(cx.as_ptr());
505            }
506        }
507    }
508}
509
510const ChunkShift: usize = 20;
511const ChunkSize: usize = 1 << ChunkShift;
512
513#[cfg(target_pointer_width = "32")]
514const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8;
515
516// ___________________________________________________________________________
517// Wrappers around things in jsglue.cpp
518
519pub struct RootedObjectVectorWrapper {
520    pub ptr: *mut PersistentRootedObjectVector,
521}
522
523impl RootedObjectVectorWrapper {
524    pub fn new(cx: *mut JSContext) -> RootedObjectVectorWrapper {
525        RootedObjectVectorWrapper {
526            ptr: unsafe { CreateRootedObjectVector(cx) },
527        }
528    }
529
530    pub fn append(&self, obj: *mut JSObject) -> bool {
531        unsafe { AppendToRootedObjectVector(self.ptr, obj) }
532    }
533
534    pub fn handle(&self) -> RawHandleObjectVector {
535        RawHandleObjectVector {
536            ptr: unsafe { GetObjectVectorAddress(self.ptr) },
537        }
538    }
539}
540
541impl Drop for RootedObjectVectorWrapper {
542    fn drop(&mut self) {
543        unsafe { DeleteRootedObjectVector(self.ptr) }
544    }
545}
546
547pub struct CompileOptionsWrapper {
548    pub ptr: *mut ReadOnlyCompileOptions,
549    filename: CString,
550}
551
552impl CompileOptionsWrapper {
553    /// # Safety
554    /// `cx` must point to a non-null, valid [`JSContext`].
555    /// To create an instance from safe code, use [`Runtime::new_compile_options`].
556    pub unsafe fn new(cx: *mut JSContext, filename: &str, line: u32) -> Self {
557        let filename = CString::new(filename.as_bytes()).unwrap();
558        let ptr = NewCompileOptions(cx, filename.as_ptr(), line);
559        assert!(!ptr.is_null());
560        Self { ptr, filename }
561    }
562
563    pub fn filename(&self) -> &str {
564        self.filename.to_str().expect("Guaranteed by new")
565    }
566
567    pub fn set_introduction_type(&mut self, introduction_type: &'static CStr) {
568        unsafe {
569            (*self.ptr)._base.introductionType = introduction_type.as_ptr();
570        }
571    }
572}
573
574impl Drop for CompileOptionsWrapper {
575    fn drop(&mut self) {
576        unsafe { DeleteCompileOptions(self.ptr) }
577    }
578}
579
580pub struct JSAutoStructuredCloneBufferWrapper {
581    ptr: NonNull<JSAutoStructuredCloneBuffer>,
582}
583
584impl JSAutoStructuredCloneBufferWrapper {
585    pub unsafe fn new(
586        scope: StructuredCloneScope,
587        callbacks: *const JSStructuredCloneCallbacks,
588    ) -> Self {
589        let raw_ptr = NewJSAutoStructuredCloneBuffer(scope, callbacks);
590        Self {
591            ptr: NonNull::new(raw_ptr).unwrap(),
592        }
593    }
594
595    pub fn as_raw_ptr(&self) -> *mut JSAutoStructuredCloneBuffer {
596        self.ptr.as_ptr()
597    }
598}
599
600impl Drop for JSAutoStructuredCloneBufferWrapper {
601    fn drop(&mut self) {
602        unsafe {
603            DeleteJSAutoStructuredCloneBuffer(self.ptr.as_ptr());
604        }
605    }
606}
607
608pub struct Stencil {
609    inner: already_AddRefed<InitialStencilAndDelazifications>,
610}
611
612/*unsafe impl Send for Stencil {}
613unsafe impl Sync for Stencil {}*/
614
615impl Drop for Stencil {
616    fn drop(&mut self) {
617        if self.is_null() {
618            return;
619        }
620        unsafe {
621            StencilRelease(self.inner.mRawPtr);
622        }
623    }
624}
625
626impl Deref for Stencil {
627    type Target = *mut InitialStencilAndDelazifications;
628
629    fn deref(&self) -> &Self::Target {
630        &self.inner.mRawPtr
631    }
632}
633
634impl Stencil {
635    pub fn is_null(&self) -> bool {
636        self.inner.mRawPtr.is_null()
637    }
638}
639
640// ___________________________________________________________________________
641// Fast inline converters
642
643#[inline]
644pub unsafe fn ToBoolean(v: HandleValue) -> bool {
645    let val = *v.ptr;
646
647    if val.is_boolean() {
648        return val.to_boolean();
649    }
650
651    if val.is_int32() {
652        return val.to_int32() != 0;
653    }
654
655    if val.is_null_or_undefined() {
656        return false;
657    }
658
659    if val.is_double() {
660        let d = val.to_double();
661        return !d.is_nan() && d != 0f64;
662    }
663
664    if val.is_symbol() {
665        return true;
666    }
667
668    ToBooleanSlow(v.into())
669}
670
671#[inline]
672pub unsafe fn ToNumber(cx: *mut JSContext, v: HandleValue) -> Result<f64, ()> {
673    let val = *v.ptr;
674    if val.is_number() {
675        return Ok(val.to_number());
676    }
677
678    let mut out = Default::default();
679    if ToNumberSlow(cx, v.into_handle(), &mut out) {
680        Ok(out)
681    } else {
682        Err(())
683    }
684}
685
686#[inline]
687unsafe fn convert_from_int32<T: Default + Copy>(
688    cx: *mut JSContext,
689    v: HandleValue,
690    conv_fn: unsafe extern "C" fn(*mut JSContext, RawHandleValue, *mut T) -> bool,
691) -> Result<T, ()> {
692    let val = *v.ptr;
693    if val.is_int32() {
694        let intval: i64 = val.to_int32() as i64;
695        // TODO: do something better here that works on big endian
696        let intval = *(&intval as *const i64 as *const T);
697        return Ok(intval);
698    }
699
700    let mut out = Default::default();
701    if conv_fn(cx, v.into(), &mut out) {
702        Ok(out)
703    } else {
704        Err(())
705    }
706}
707
708#[inline]
709pub unsafe fn ToInt32(cx: *mut JSContext, v: HandleValue) -> Result<i32, ()> {
710    convert_from_int32::<i32>(cx, v, ToInt32Slow)
711}
712
713#[inline]
714pub unsafe fn ToUint32(cx: *mut JSContext, v: HandleValue) -> Result<u32, ()> {
715    convert_from_int32::<u32>(cx, v, ToUint32Slow)
716}
717
718#[inline]
719pub unsafe fn ToUint16(cx: *mut JSContext, v: HandleValue) -> Result<u16, ()> {
720    convert_from_int32::<u16>(cx, v, ToUint16Slow)
721}
722
723#[inline]
724pub unsafe fn ToInt64(cx: *mut JSContext, v: HandleValue) -> Result<i64, ()> {
725    convert_from_int32::<i64>(cx, v, ToInt64Slow)
726}
727
728#[inline]
729pub unsafe fn ToUint64(cx: *mut JSContext, v: HandleValue) -> Result<u64, ()> {
730    convert_from_int32::<u64>(cx, v, ToUint64Slow)
731}
732
733#[inline]
734pub unsafe fn ToString(cx: *mut JSContext, v: HandleValue) -> *mut JSString {
735    let val = *v.ptr;
736    if val.is_string() {
737        return val.to_string();
738    }
739
740    ToStringSlow(cx, v.into())
741}
742
743pub unsafe fn ToWindowProxyIfWindow(obj: *mut JSObject) -> *mut JSObject {
744    if is_window(obj) {
745        ToWindowProxyIfWindowSlow(obj)
746    } else {
747        obj
748    }
749}
750
751pub unsafe extern "C" fn report_warning(_cx: *mut JSContext, report: *mut JSErrorReport) {
752    fn latin1_to_string(bytes: &[u8]) -> String {
753        bytes
754            .iter()
755            .map(|c| char::from_u32(*c as u32).unwrap())
756            .collect()
757    }
758
759    let fnptr = (*report)._base.filename.data_;
760    let fname = if !fnptr.is_null() {
761        let c_str = CStr::from_ptr(fnptr);
762        latin1_to_string(c_str.to_bytes())
763    } else {
764        "none".to_string()
765    };
766
767    let lineno = (*report)._base.lineno;
768    let column = (*report)._base.column._base;
769
770    let msg_ptr = (*report)._base.message_.data_ as *const u8;
771    let msg_len = (0usize..)
772        .find(|&i| *msg_ptr.offset(i as isize) == 0)
773        .unwrap();
774    let msg_slice = slice::from_raw_parts(msg_ptr, msg_len);
775    let msg = str::from_utf8_unchecked(msg_slice);
776
777    warn!("Warning at {}:{}:{}: {}\n", fname, lineno, column, msg);
778}
779
780pub struct IdVector(*mut PersistentRootedIdVector);
781
782impl IdVector {
783    pub unsafe fn new(cx: *mut JSContext) -> IdVector {
784        let vector = CreateRootedIdVector(cx);
785        assert!(!vector.is_null());
786        IdVector(vector)
787    }
788
789    pub fn handle_mut(&mut self) -> RawMutableHandleIdVector {
790        RawMutableHandleIdVector {
791            ptr: unsafe { GetIdVectorAddress(self.0) },
792        }
793    }
794}
795
796impl Drop for IdVector {
797    fn drop(&mut self) {
798        unsafe { DestroyRootedIdVector(self.0) }
799    }
800}
801
802impl Deref for IdVector {
803    type Target = [jsid];
804
805    fn deref(&self) -> &[jsid] {
806        unsafe {
807            let mut length = 0;
808            let pointer = SliceRootedIdVector(self.0, &mut length);
809            slice::from_raw_parts(pointer, length)
810        }
811    }
812}
813
814/// Defines methods on `obj`. The last entry of `methods` must contain zeroed
815/// memory.
816///
817/// # Failures
818///
819/// Returns `Err` on JSAPI failure.
820///
821/// # Panics
822///
823/// Panics if the last entry of `methods` does not contain zeroed memory.
824///
825/// # Safety
826///
827/// - `cx` must be valid.
828/// - This function calls into unaudited C++ code.
829pub unsafe fn define_methods(
830    cx: *mut JSContext,
831    obj: HandleObject,
832    methods: &'static [JSFunctionSpec],
833) -> Result<(), ()> {
834    assert!({
835        match methods.last() {
836            Some(&JSFunctionSpec {
837                name,
838                call,
839                nargs,
840                flags,
841                selfHostedName,
842            }) => {
843                name.string_.is_null()
844                    && call.is_zeroed()
845                    && nargs == 0
846                    && flags == 0
847                    && selfHostedName.is_null()
848            }
849            None => false,
850        }
851    });
852
853    JS_DefineFunctions(cx, obj.into(), methods.as_ptr()).to_result()
854}
855
856/// Defines attributes on `obj`. The last entry of `properties` must contain
857/// zeroed memory.
858///
859/// # Failures
860///
861/// Returns `Err` on JSAPI failure.
862///
863/// # Panics
864///
865/// Panics if the last entry of `properties` does not contain zeroed memory.
866///
867/// # Safety
868///
869/// - `cx` must be valid.
870/// - This function calls into unaudited C++ code.
871pub unsafe fn define_properties(
872    cx: *mut JSContext,
873    obj: HandleObject,
874    properties: &'static [JSPropertySpec],
875) -> Result<(), ()> {
876    assert!({
877        match properties.last() {
878            Some(spec) => spec.is_zeroed(),
879            None => false,
880        }
881    });
882
883    JS_DefineProperties(cx, obj.into(), properties.as_ptr()).to_result()
884}
885
886static SIMPLE_GLOBAL_CLASS_OPS: JSClassOps = JSClassOps {
887    addProperty: None,
888    delProperty: None,
889    enumerate: Some(JS_EnumerateStandardClasses),
890    newEnumerate: None,
891    resolve: Some(JS_ResolveStandardClass),
892    mayResolve: Some(JS_MayResolveStandardClass),
893    finalize: None,
894    call: None,
895    construct: None,
896    trace: Some(JS_GlobalObjectTraceHook),
897};
898
899/// This is a simple `JSClass` for global objects, primarily intended for tests.
900pub static SIMPLE_GLOBAL_CLASS: JSClass = JSClass {
901    name: c"Global".as_ptr(),
902    flags: JSCLASS_IS_GLOBAL
903        | ((JSCLASS_GLOBAL_SLOT_COUNT & JSCLASS_RESERVED_SLOTS_MASK)
904            << JSCLASS_RESERVED_SLOTS_SHIFT),
905    cOps: &SIMPLE_GLOBAL_CLASS_OPS as *const JSClassOps,
906    spec: ptr::null(),
907    ext: ptr::null(),
908    oOps: ptr::null(),
909};
910
911#[inline]
912unsafe fn get_object_group(obj: *mut JSObject) -> *mut BaseShape {
913    assert!(!obj.is_null());
914    let obj = obj as *mut Object;
915    (*(*obj).shape).base
916}
917
918#[inline]
919pub unsafe fn get_object_class(obj: *mut JSObject) -> *const JSClass {
920    (*get_object_group(obj)).clasp as *const _
921}
922
923#[inline]
924pub unsafe fn get_object_realm(obj: *mut JSObject) -> *mut Realm {
925    (*get_object_group(obj)).realm
926}
927
928#[inline]
929pub unsafe fn get_context_realm(cx: *mut JSContext) -> *mut Realm {
930    let cx = cx as *mut RootingContext;
931    (*cx).realm_
932}
933
934#[inline]
935pub fn is_dom_class(class: &JSClass) -> bool {
936    class.flags & JSCLASS_IS_DOMJSCLASS != 0
937}
938
939#[inline]
940pub unsafe fn is_dom_object(obj: *mut JSObject) -> bool {
941    is_dom_class(&*get_object_class(obj))
942}
943
944#[inline]
945pub unsafe fn is_window(obj: *mut JSObject) -> bool {
946    (*get_object_class(obj)).flags & JSCLASS_IS_GLOBAL != 0 && IsWindowSlow(obj)
947}
948
949#[inline]
950pub unsafe fn try_to_outerize(mut rval: MutableHandleValue) {
951    let obj = rval.to_object();
952    if is_window(obj) {
953        let obj = ToWindowProxyIfWindowSlow(obj);
954        assert!(!obj.is_null());
955        rval.set(ObjectValue(&mut *obj));
956    }
957}
958
959#[inline]
960pub unsafe fn try_to_outerize_object(mut rval: MutableHandleObject) {
961    if is_window(*rval) {
962        let obj = ToWindowProxyIfWindowSlow(*rval);
963        assert!(!obj.is_null());
964        rval.set(obj);
965    }
966}
967
968#[inline]
969pub unsafe fn maybe_wrap_object(cx: *mut JSContext, mut obj: MutableHandleObject) {
970    if get_object_realm(*obj) != get_context_realm(cx) {
971        assert!(JS_WrapObject(cx, obj.reborrow().into()));
972    }
973    try_to_outerize_object(obj);
974}
975
976#[inline]
977pub unsafe fn maybe_wrap_object_value(cx: *mut JSContext, rval: MutableHandleValue) {
978    assert!(rval.is_object());
979    let obj = rval.to_object();
980    if get_object_realm(obj) != get_context_realm(cx) {
981        assert!(JS_WrapValue(cx, rval.into()));
982    } else if is_dom_object(obj) {
983        try_to_outerize(rval);
984    }
985}
986
987#[inline]
988pub unsafe fn maybe_wrap_object_or_null_value(cx: *mut JSContext, rval: MutableHandleValue) {
989    assert!(rval.is_object_or_null());
990    if !rval.is_null() {
991        maybe_wrap_object_value(cx, rval);
992    }
993}
994
995#[inline]
996pub unsafe fn maybe_wrap_value(cx: *mut JSContext, rval: MutableHandleValue) {
997    if rval.is_string() {
998        assert!(JS_WrapValue(cx, rval.into()));
999    } else if rval.is_object() {
1000        maybe_wrap_object_value(cx, rval);
1001    }
1002}
1003
1004/// Like `JSJitInfo::new_bitfield_1`, but usable in `const` contexts.
1005#[macro_export]
1006macro_rules! new_jsjitinfo_bitfield_1 {
1007    (
1008        $type_: expr,
1009        $aliasSet_: expr,
1010        $returnType_: expr,
1011        $isInfallible: expr,
1012        $isMovable: expr,
1013        $isEliminatable: expr,
1014        $isAlwaysInSlot: expr,
1015        $isLazilyCachedInSlot: expr,
1016        $isTypedMethod: expr,
1017        $slotIndex: expr,
1018    ) => {
1019        0 | (($type_ as u32) << 0u32)
1020            | (($aliasSet_ as u32) << 4u32)
1021            | (($returnType_ as u32) << 8u32)
1022            | (($isInfallible as u32) << 16u32)
1023            | (($isMovable as u32) << 17u32)
1024            | (($isEliminatable as u32) << 18u32)
1025            | (($isAlwaysInSlot as u32) << 19u32)
1026            | (($isLazilyCachedInSlot as u32) << 20u32)
1027            | (($isTypedMethod as u32) << 21u32)
1028            | (($slotIndex as u32) << 22u32)
1029    };
1030}
1031
1032#[derive(Debug, Default)]
1033pub struct ScriptedCaller {
1034    pub filename: String,
1035    pub line: u32,
1036    pub col: u32,
1037}
1038
1039pub unsafe fn describe_scripted_caller(cx: *mut JSContext) -> Result<ScriptedCaller, ()> {
1040    let mut buf = [0; 1024];
1041    let mut line = 0;
1042    let mut col = 0;
1043    if !DescribeScriptedCaller(cx, buf.as_mut_ptr(), buf.len(), &mut line, &mut col) {
1044        return Err(());
1045    }
1046    let filename = CStr::from_ptr((&buf) as *const _ as *const _);
1047    Ok(ScriptedCaller {
1048        filename: String::from_utf8_lossy(filename.to_bytes()).into_owned(),
1049        line,
1050        col,
1051    })
1052}
1053
1054pub struct CapturedJSStack<'a> {
1055    cx: *mut JSContext,
1056    stack: RootedGuard<'a, *mut JSObject>,
1057}
1058
1059impl<'a> CapturedJSStack<'a> {
1060    pub unsafe fn new(
1061        cx: *mut JSContext,
1062        mut guard: RootedGuard<'a, *mut JSObject>,
1063        max_frame_count: Option<u32>,
1064    ) -> Option<Self> {
1065        let ref mut stack_capture = MaybeUninit::uninit();
1066        match max_frame_count {
1067            None => JS_StackCapture_AllFrames(stack_capture.as_mut_ptr()),
1068            Some(count) => JS_StackCapture_MaxFrames(count, stack_capture.as_mut_ptr()),
1069        };
1070        let ref mut stack_capture = stack_capture.assume_init();
1071
1072        if !CaptureCurrentStack(
1073            cx,
1074            guard.handle_mut().raw(),
1075            stack_capture,
1076            HandleObject::null().into(),
1077        ) {
1078            None
1079        } else {
1080            Some(CapturedJSStack { cx, stack: guard })
1081        }
1082    }
1083
1084    pub fn as_string(&self, indent: Option<usize>, format: StackFormat) -> Option<String> {
1085        unsafe {
1086            let stack_handle = self.stack.handle();
1087            rooted!(in(self.cx) let mut js_string = ptr::null_mut::<JSString>());
1088            let mut string_handle = js_string.handle_mut();
1089
1090            if !BuildStackString(
1091                self.cx,
1092                ptr::null_mut(),
1093                stack_handle.into(),
1094                string_handle.raw(),
1095                indent.unwrap_or(0),
1096                format,
1097            ) {
1098                return None;
1099            }
1100
1101            Some(jsstr_to_string(self.cx, NonNull::new(string_handle.get())?))
1102        }
1103    }
1104
1105    /// Executes the provided closure for each frame on the js stack
1106    pub fn for_each_stack_frame<F>(&self, mut f: F)
1107    where
1108        F: FnMut(Handle<*mut JSObject>),
1109    {
1110        rooted!(in(self.cx) let mut current_element = self.stack.clone());
1111        rooted!(in(self.cx) let mut next_element = ptr::null_mut::<JSObject>());
1112
1113        loop {
1114            f(current_element.handle());
1115
1116            unsafe {
1117                let result = jsapi::GetSavedFrameParent(
1118                    self.cx,
1119                    ptr::null_mut(),
1120                    current_element.handle().into_handle(),
1121                    next_element.handle_mut().into_handle_mut(),
1122                    jsapi::SavedFrameSelfHosted::Include,
1123                );
1124
1125                if result != SavedFrameResult::Ok || next_element.is_null() {
1126                    return;
1127                }
1128            }
1129            current_element.set(next_element.get());
1130        }
1131    }
1132}
1133
1134#[macro_export]
1135macro_rules! capture_stack {
1136    (&in($cx:expr) $($t:tt)*) => {
1137        capture_stack!(in(unsafe {$cx.raw_cx_no_gc()}) $($t)*);
1138    };
1139    (in($cx:expr) let $name:ident = with max depth($max_frame_count:expr)) => {
1140        rooted!(in($cx) let mut __obj = ::std::ptr::null_mut());
1141        let $name = $crate::rust::CapturedJSStack::new($cx, __obj, Some($max_frame_count));
1142    };
1143    (in($cx:expr) let $name:ident ) => {
1144        rooted!(in($cx) let mut __obj = ::std::ptr::null_mut());
1145        let $name = $crate::rust::CapturedJSStack::new($cx, __obj, None);
1146    }
1147}
1148
1149pub struct EnvironmentChain {
1150    chain: *mut crate::jsapi::JS::EnvironmentChain,
1151}
1152
1153impl EnvironmentChain {
1154    pub fn new(
1155        cx: *mut JSContext,
1156        support_unscopeables: crate::jsapi::JS::SupportUnscopables,
1157    ) -> Self {
1158        unsafe {
1159            Self {
1160                chain: crate::jsapi::glue::NewEnvironmentChain(cx, support_unscopeables),
1161            }
1162        }
1163    }
1164
1165    pub fn append(&self, obj: *mut JSObject) {
1166        unsafe {
1167            assert!(crate::jsapi::glue::AppendToEnvironmentChain(
1168                self.chain, obj
1169            ));
1170        }
1171    }
1172
1173    pub fn get(&self) -> *mut crate::jsapi::JS::EnvironmentChain {
1174        self.chain
1175    }
1176}
1177
1178impl Drop for EnvironmentChain {
1179    fn drop(&mut self) {
1180        unsafe {
1181            crate::jsapi::glue::DeleteEnvironmentChain(self.chain);
1182        }
1183    }
1184}
1185
1186impl<'a> Handle<'a, StackGCVector<JSVal, js::TempAllocPolicy>> {
1187    pub fn at(&'a self, index: u32) -> Option<Handle<'a, JSVal>> {
1188        if index >= self.len() {
1189            return None;
1190        }
1191        let handle =
1192            unsafe { Handle::from_marked_location(StackGCVectorValueAtIndex(*self, index)) };
1193        Some(handle)
1194    }
1195
1196    pub fn len(&self) -> u32 {
1197        unsafe { StackGCVectorValueLength(*self) }
1198    }
1199}
1200
1201impl<'a> Handle<'a, StackGCVector<*mut JSString, js::TempAllocPolicy>> {
1202    pub fn at(&'a self, index: u32) -> Option<Handle<'a, *mut JSString>> {
1203        if index >= self.len() {
1204            return None;
1205        }
1206        let handle =
1207            unsafe { Handle::from_marked_location(StackGCVectorStringAtIndex(*self, index)) };
1208        Some(handle)
1209    }
1210
1211    pub fn len(&self) -> u32 {
1212        unsafe { StackGCVectorStringLength(*self) }
1213    }
1214}
1215
1216/// Wrappers for JSAPI methods that accept lifetimed Handle and MutableHandle arguments
1217pub mod wrappers {
1218    macro_rules! wrap {
1219        // The invocation of @inner has the following form:
1220        // @inner (input args) <> (accumulator) <> unparsed tokens
1221        // when `unparsed tokens == \eps`, accumulator contains the final result
1222
1223        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: *const Handle<$gentype:ty>, $($rest:tt)*) => {
1224            wrap!(@inner $saved <> ($($acc,)* if $arg.is_null() { std::ptr::null() } else { &(*$arg).into() },) <> $($rest)*);
1225        };
1226        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: Handle<$gentype:ty>, $($rest:tt)*) => {
1227            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1228        };
1229        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandle<$gentype:ty>, $($rest:tt)*) => {
1230            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1231        };
1232        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: Handle, $($rest:tt)*) => {
1233            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1234        };
1235        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandle, $($rest:tt)*) => {
1236            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1237        };
1238        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleFunction , $($rest:tt)*) => {
1239            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1240        };
1241        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleId , $($rest:tt)*) => {
1242            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1243        };
1244        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleObject , $($rest:tt)*) => {
1245            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1246        };
1247        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleScript , $($rest:tt)*) => {
1248            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1249        };
1250        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleString , $($rest:tt)*) => {
1251            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1252        };
1253        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleSymbol , $($rest:tt)*) => {
1254            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1255        };
1256        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: HandleValue , $($rest:tt)*) => {
1257            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1258        };
1259        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleFunction , $($rest:tt)*) => {
1260            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1261        };
1262        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleId , $($rest:tt)*) => {
1263            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1264        };
1265        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleObject , $($rest:tt)*) => {
1266            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1267        };
1268        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleScript , $($rest:tt)*) => {
1269            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1270        };
1271        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleString , $($rest:tt)*) => {
1272            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1273        };
1274        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleSymbol , $($rest:tt)*) => {
1275            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1276        };
1277        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: MutableHandleValue , $($rest:tt)*) => {
1278            wrap!(@inner $saved <> ($($acc,)* $arg.into(),) <> $($rest)*);
1279        };
1280        (@inner $saved:tt <> ($($acc:expr,)*) <> $arg:ident: $type:ty, $($rest:tt)*) => {
1281            wrap!(@inner $saved <> ($($acc,)* $arg,) <> $($rest)*);
1282        };
1283        (@inner ($module:tt: $func_name:ident ($($args:tt)*) -> $outtype:ty) <> ($($argexprs:expr,)*) <> ) => {
1284            #[inline]
1285            pub unsafe fn $func_name($($args)*) -> $outtype {
1286                $module::$func_name($($argexprs),*)
1287            }
1288        };
1289        ($module:tt: pub fn $func_name:ident($($args:tt)*) -> $outtype:ty) => {
1290            wrap!(@inner ($module: $func_name ($($args)*) -> $outtype) <> () <> $($args)* ,);
1291        };
1292        ($module:tt: pub fn $func_name:ident($($args:tt)*)) => {
1293            wrap!($module: pub fn $func_name($($args)*) -> ());
1294        }
1295    }
1296
1297    use super::*;
1298    use crate::glue;
1299    use crate::glue::EncodedStringCallback;
1300    use crate::jsapi;
1301    use crate::jsapi::js::TempAllocPolicy;
1302    use crate::jsapi::jsid;
1303    use crate::jsapi::mozilla::Utf8Unit;
1304    use crate::jsapi::BigInt;
1305    use crate::jsapi::CallArgs;
1306    use crate::jsapi::CloneDataPolicy;
1307    use crate::jsapi::ColumnNumberOneOrigin;
1308    use crate::jsapi::CompartmentTransplantCallback;
1309    use crate::jsapi::EnvironmentChain;
1310    use crate::jsapi::JSONParseHandler;
1311    use crate::jsapi::Latin1Char;
1312    use crate::jsapi::PropertyKey;
1313    use crate::jsapi::TaggedColumnNumberOneOrigin;
1314    //use jsapi::DynamicImportStatus;
1315    use crate::jsapi::ESClass;
1316    use crate::jsapi::ExceptionStackBehavior;
1317    use crate::jsapi::ForOfIterator;
1318    use crate::jsapi::ForOfIterator_NonIterableBehavior;
1319    use crate::jsapi::HandleObjectVector;
1320    use crate::jsapi::InstantiateOptions;
1321    use crate::jsapi::JSClass;
1322    use crate::jsapi::JSErrorReport;
1323    use crate::jsapi::JSExnType;
1324    use crate::jsapi::JSFunctionSpecWithHelp;
1325    use crate::jsapi::JSJitInfo;
1326    use crate::jsapi::JSONWriteCallback;
1327    use crate::jsapi::JSPrincipals;
1328    use crate::jsapi::JSPropertySpec;
1329    use crate::jsapi::JSPropertySpec_Name;
1330    use crate::jsapi::JSProtoKey;
1331    use crate::jsapi::JSScript;
1332    use crate::jsapi::JSStructuredCloneData;
1333    use crate::jsapi::JSType;
1334    use crate::jsapi::ModuleErrorBehaviour;
1335    use crate::jsapi::ModuleType;
1336    use crate::jsapi::MutableHandleIdVector;
1337    use crate::jsapi::PromiseState;
1338    use crate::jsapi::PromiseUserInputEventHandlingState;
1339    use crate::jsapi::ReadOnlyCompileOptions;
1340    use crate::jsapi::Realm;
1341    use crate::jsapi::RefPtr;
1342    use crate::jsapi::RegExpFlags;
1343    use crate::jsapi::ScriptEnvironmentPreparer_Closure;
1344    use crate::jsapi::SourceText;
1345    use crate::jsapi::StackCapture;
1346    use crate::jsapi::Stencil;
1347    use crate::jsapi::StructuredCloneScope;
1348    use crate::jsapi::Symbol;
1349    use crate::jsapi::SymbolCode;
1350    use crate::jsapi::TranscodeBuffer;
1351    use crate::jsapi::TwoByteChars;
1352    use crate::jsapi::UniqueChars;
1353    use crate::jsapi::Value;
1354    use crate::jsapi::WasmModule;
1355    use crate::jsapi::{ElementAdder, IsArrayAnswer, PropertyDescriptor};
1356    use crate::jsapi::{JSContext, JSFunction, JSNative, JSObject, JSString};
1357    use crate::jsapi::{
1358        JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter,
1359    };
1360    use crate::jsapi::{MallocSizeOf, ObjectOpResult, ObjectPrivateVisitor, TabSizes};
1361    use crate::jsapi::{SavedFrameResult, SavedFrameSelfHosted};
1362    include!("jsapi_wrappers.in.rs");
1363    include!("glue_wrappers.in.rs");
1364}
1365
1366/// Wrappers for JSAPI/glue methods that accept lifetimed [crate::rust::Handle] and [crate::rust::MutableHandle] arguments and [crate::context::JSContext]
1367pub mod wrappers2 {
1368    macro_rules! wrap {
1369        // The invocation of @inner has the following form:
1370        // @inner (input args) <> (arg signture accumulator) <> (arg expr accumulator) <> unparsed tokens
1371        // when `unparsed tokens == \eps`, accumulator contains the final result
1372
1373        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: *const Handle<$gentype:ty>, $($rest:tt)*) => {
1374            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: *const Handle<$gentype>) <> ($($arg_expr_acc,)* if $arg.is_null() { ::std::ptr::null() } else { &(*$arg).into() },) <> $($rest)*);
1375        };
1376        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: Handle<$gentype:ty>, $($rest:tt)*) => {
1377            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: Handle<$gentype>) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1378        };
1379        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandle<$gentype:ty>, $($rest:tt)*) => {
1380            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandle<$gentype>) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1381        };
1382        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: Handle, $($rest:tt)*) => {
1383            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: Handle) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1384        };
1385        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandle, $($rest:tt)*) => {
1386            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandle) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1387        };
1388        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleFunction , $($rest:tt)*) => {
1389            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleFunction) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1390        };
1391        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleId , $($rest:tt)*) => {
1392            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleId) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1393        };
1394        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleObject , $($rest:tt)*) => {
1395            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleObject) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1396        };
1397        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleScript , $($rest:tt)*) => {
1398            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleScript) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1399        };
1400        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleString , $($rest:tt)*) => {
1401            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleString) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1402        };
1403        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleSymbol , $($rest:tt)*) => {
1404            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleSymbol) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1405        };
1406        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: HandleValue , $($rest:tt)*) => {
1407            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: HandleValue) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1408        };
1409        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleFunction , $($rest:tt)*) => {
1410            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleFunction) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1411        };
1412        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleId , $($rest:tt)*) => {
1413            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleId) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1414        };
1415        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleObject , $($rest:tt)*) => {
1416            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleObject) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1417        };
1418        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleScript , $($rest:tt)*) => {
1419            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleScript) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1420        };
1421        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleString , $($rest:tt)*) => {
1422            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleString) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1423        };
1424        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleSymbol , $($rest:tt)*) => {
1425            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleSymbol) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1426        };
1427        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: MutableHandleValue , $($rest:tt)*) => {
1428            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: MutableHandleValue) <> ($($arg_expr_acc,)* $arg.into(),) <> $($rest)*);
1429        };
1430        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: &mut JSContext , $($rest:tt)*) => {
1431            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: &mut JSContext) <> ($($arg_expr_acc,)* $arg.raw_cx(),) <> $($rest)*);
1432        };
1433        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: &JSContext , $($rest:tt)*) => {
1434            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: &JSContext) <> ($($arg_expr_acc,)* $arg.raw_cx_no_gc(),) <> $($rest)*);
1435        };
1436        // functions that take *const AutoRequireNoGC already have &JSContext, so we can remove this mareker argument
1437        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: *const AutoRequireNoGC , $($rest:tt)*) => {
1438            wrap!(@inner $saved <> ($($arg_sig_acc)*) <> ($($arg_expr_acc,)* ::std::ptr::null(),) <> $($rest)*);
1439        };
1440        (@inner $saved:tt <> ($($arg_sig_acc:tt)*) <> ($($arg_expr_acc:expr,)*) <> $arg:ident: $type:ty, $($rest:tt)*) => {
1441            wrap!(@inner $saved <> ($($arg_sig_acc)* , $arg: $type) <> ($($arg_expr_acc,)* $arg,) <> $($rest)*);
1442        };
1443        (@inner ($module:tt: $func_name:ident -> $outtype:ty) <> (, $($args:tt)*) <> ($($argexprs:expr,)*) <> ) => {
1444            #[inline]
1445            pub unsafe fn $func_name($($args)*) -> $outtype {
1446                $module::$func_name($($argexprs),*)
1447            }
1448        };
1449        ($module:tt: pub fn $func_name:ident($($args:tt)*) -> $outtype:ty) => {
1450            wrap!(@inner ($module: $func_name -> $outtype) <> () <> () <> $($args)* ,);
1451        };
1452        ($module:tt: pub fn $func_name:ident($($args:tt)*)) => {
1453            wrap!($module: pub fn $func_name($($args)*) -> ());
1454        }
1455    }
1456
1457    use super::*;
1458    use super::{
1459        Handle, HandleFunction, HandleId, HandleObject, HandleScript, HandleString, HandleValue,
1460        HandleValueArray, MutableHandle, MutableHandleId, MutableHandleObject, MutableHandleString,
1461        MutableHandleValue, StackGCVector,
1462    };
1463    use crate::context::JSContext;
1464    use crate::glue;
1465    use crate::glue::*;
1466    use crate::jsapi;
1467    use crate::jsapi::js::TempAllocPolicy;
1468    use crate::jsapi::mozilla::Utf8Unit;
1469    use crate::jsapi::mozilla::*;
1470    use crate::jsapi::BigInt;
1471    use crate::jsapi::CallArgs;
1472    use crate::jsapi::CloneDataPolicy;
1473    use crate::jsapi::ColumnNumberOneOrigin;
1474    use crate::jsapi::CompartmentTransplantCallback;
1475    use crate::jsapi::ESClass;
1476    use crate::jsapi::EnvironmentChain;
1477    use crate::jsapi::ExceptionStackBehavior;
1478    use crate::jsapi::ForOfIterator;
1479    use crate::jsapi::ForOfIterator_NonIterableBehavior;
1480    use crate::jsapi::HandleObjectVector;
1481    use crate::jsapi::InstantiateOptions;
1482    use crate::jsapi::JSClass;
1483    use crate::jsapi::JSErrorReport;
1484    use crate::jsapi::JSExnType;
1485    use crate::jsapi::JSFunctionSpecWithHelp;
1486    use crate::jsapi::JSJitInfo;
1487    use crate::jsapi::JSONParseHandler;
1488    use crate::jsapi::JSONWriteCallback;
1489    use crate::jsapi::JSPrincipals;
1490    use crate::jsapi::JSPropertySpec;
1491    use crate::jsapi::JSPropertySpec_Name;
1492    use crate::jsapi::JSProtoKey;
1493    use crate::jsapi::JSScript;
1494    use crate::jsapi::JSStructuredCloneData;
1495    use crate::jsapi::JSType;
1496    use crate::jsapi::Latin1Char;
1497    use crate::jsapi::ModuleErrorBehaviour;
1498    use crate::jsapi::ModuleType;
1499    use crate::jsapi::MutableHandleIdVector;
1500    use crate::jsapi::PromiseState;
1501    use crate::jsapi::PromiseUserInputEventHandlingState;
1502    use crate::jsapi::PropertyKey;
1503    use crate::jsapi::ReadOnlyCompileOptions;
1504    use crate::jsapi::Realm;
1505    use crate::jsapi::RealmOptions;
1506    use crate::jsapi::RefPtr;
1507    use crate::jsapi::RegExpFlags;
1508    use crate::jsapi::ScriptEnvironmentPreparer_Closure;
1509    use crate::jsapi::SourceText;
1510    use crate::jsapi::StackCapture;
1511    use crate::jsapi::Stencil;
1512    use crate::jsapi::StructuredCloneScope;
1513    use crate::jsapi::Symbol;
1514    use crate::jsapi::SymbolCode;
1515    use crate::jsapi::TaggedColumnNumberOneOrigin;
1516    use crate::jsapi::TranscodeBuffer;
1517    use crate::jsapi::TwoByteChars;
1518    use crate::jsapi::UniqueChars;
1519    use crate::jsapi::Value;
1520    use crate::jsapi::WasmModule;
1521    use crate::jsapi::*;
1522    use crate::jsapi::{ElementAdder, IsArrayAnswer, PropertyDescriptor};
1523    use crate::jsapi::{JSFunction, JSNative, JSObject, JSString};
1524    use crate::jsapi::{
1525        JSStructuredCloneCallbacks, JSStructuredCloneReader, JSStructuredCloneWriter,
1526    };
1527    use crate::jsapi::{MallocSizeOf, ObjectOpResult, ObjectPrivateVisitor, TabSizes};
1528    use crate::jsapi::{SavedFrameResult, SavedFrameSelfHosted};
1529    include!("jsapi2_wrappers.in.rs");
1530    include!("glue2_wrappers.in.rs");
1531}