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