Skip to main content

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