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