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