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