mozjs_sys/
jsimpls.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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::jsapi::glue::JS_ForOfIteratorInit;
6use crate::jsapi::glue::JS_ForOfIteratorNext;
7use crate::jsapi::jsid;
8use crate::jsapi::mozilla;
9use crate::jsapi::JSAutoRealm;
10use crate::jsapi::JSContext;
11use crate::jsapi::JSErrNum;
12use crate::jsapi::JSFunctionSpec;
13use crate::jsapi::JSJitGetterCallArgs;
14use crate::jsapi::JSJitMethodCallArgs;
15use crate::jsapi::JSJitSetterCallArgs;
16use crate::jsapi::JSNativeWrapper;
17use crate::jsapi::JSObject;
18use crate::jsapi::JSPropertySpec;
19use crate::jsapi::JSPropertySpec_Kind;
20use crate::jsapi::JSPropertySpec_Name;
21use crate::jsapi::JS;
22use crate::jsapi::JS::Scalar::Type;
23use crate::jsgc::{RootKind, Rooted, RootedBase, ValueArray};
24use crate::jsid::VoidId;
25use crate::jsval::{JSVal, UndefinedValue};
26
27use std::marker::PhantomData;
28use std::ops::Deref;
29use std::ptr;
30
31impl<T> Deref for JS::Handle<T> {
32    type Target = T;
33
34    fn deref<'a>(&'a self) -> &'a T {
35        unsafe { &*self.ptr }
36    }
37}
38
39impl<T> Deref for JS::MutableHandle<T> {
40    type Target = T;
41
42    fn deref<'a>(&'a self) -> &'a T {
43        unsafe { &*self.ptr }
44    }
45}
46
47impl Default for jsid {
48    fn default() -> Self {
49        VoidId()
50    }
51}
52
53impl Default for JS::PropertyDescriptor {
54    fn default() -> Self {
55        JS::PropertyDescriptor {
56            _bitfield_align_1: [],
57            _bitfield_1: Default::default(),
58            getter_: ptr::null_mut(),
59            setter_: ptr::null_mut(),
60            value_: UndefinedValue(),
61        }
62    }
63}
64
65impl Drop for JSAutoRealm {
66    fn drop(&mut self) {
67        unsafe {
68            JS::LeaveRealm(self.cx_, self.oldRealm_);
69        }
70    }
71}
72
73impl<T> JS::Handle<T> {
74    pub fn get(&self) -> T
75    where
76        T: Copy,
77    {
78        unsafe { *self.ptr }
79    }
80
81    pub unsafe fn from_marked_location(ptr: *const T) -> JS::Handle<T> {
82        JS::Handle {
83            ptr: ptr as *mut T,
84            _phantom_0: PhantomData,
85        }
86    }
87}
88
89impl<T> JS::MutableHandle<T> {
90    pub unsafe fn from_marked_location(ptr: *mut T) -> JS::MutableHandle<T> {
91        JS::MutableHandle {
92            ptr,
93            _phantom_0: PhantomData,
94        }
95    }
96
97    pub fn handle(&self) -> JS::Handle<T> {
98        unsafe { JS::Handle::from_marked_location(self.ptr as *const _) }
99    }
100
101    pub fn get(&self) -> T
102    where
103        T: Copy,
104    {
105        unsafe { *self.ptr }
106    }
107
108    pub fn set(&self, v: T)
109    where
110        T: Copy,
111    {
112        unsafe { *self.ptr = v }
113    }
114
115    /// The returned pointer is aliased by a pointer that the GC will read
116    /// through, and thus `&mut` references created from it must not be held
117    /// across GC pauses.
118    pub fn as_ptr(self) -> *mut T {
119        self.ptr
120    }
121}
122
123impl JS::HandleValue {
124    pub fn null() -> JS::HandleValue {
125        unsafe { JS::NullHandleValue }
126    }
127
128    pub fn undefined() -> JS::HandleValue {
129        unsafe { JS::UndefinedHandleValue }
130    }
131}
132
133impl JS::HandleValueArray {
134    pub fn empty() -> JS::HandleValueArray {
135        JS::HandleValueArray {
136            length_: 0,
137            elements_: ptr::null(),
138        }
139    }
140}
141
142impl<const N: usize> From<&Rooted<ValueArray<N>>> for JS::HandleValueArray {
143    fn from(array: &Rooted<ValueArray<N>>) -> JS::HandleValueArray {
144        JS::HandleValueArray {
145            length_: N,
146            elements_: array.data.get_ptr(),
147        }
148    }
149}
150
151impl From<&JS::CallArgs> for JS::HandleValueArray {
152    fn from(args: &JS::CallArgs) -> JS::HandleValueArray {
153        JS::HandleValueArray {
154            length_: args.argc_ as usize,
155            elements_: args.argv_ as *const _,
156        }
157    }
158}
159
160impl From<JS::Handle<JSVal>> for JS::HandleValueArray {
161    fn from(handle: JS::Handle<JSVal>) -> JS::HandleValueArray {
162        JS::HandleValueArray {
163            length_: 1,
164            elements_: handle.ptr,
165        }
166    }
167}
168
169const NULL_OBJECT: *mut JSObject = 0 as *mut JSObject;
170
171impl JS::HandleObject {
172    pub fn null() -> JS::HandleObject {
173        unsafe { JS::HandleObject::from_marked_location(&NULL_OBJECT) }
174    }
175}
176
177// ___________________________________________________________________________
178// Implementations for various things in jsapi.rs
179
180impl JSAutoRealm {
181    pub fn new(cx: *mut JSContext, target: *mut JSObject) -> JSAutoRealm {
182        JSAutoRealm {
183            cx_: cx,
184            oldRealm_: unsafe { JS::EnterRealm(cx, target) },
185        }
186    }
187}
188
189impl JS::AutoGCRooter {
190    pub fn new_unrooted(kind: JS::AutoGCRooterKind) -> JS::AutoGCRooter {
191        JS::AutoGCRooter {
192            down: ptr::null_mut(),
193            kind_: kind,
194            stackTop: ptr::null_mut(),
195        }
196    }
197
198    pub unsafe fn add_to_root_stack(&mut self, cx: *mut JSContext) {
199        #[allow(non_snake_case)]
200        let autoGCRooters: *mut _ = {
201            let rooting_cx = cx as *mut JS::RootingContext;
202            &mut (*rooting_cx).autoGCRooters_.0[self.kind_ as usize]
203        };
204        self.stackTop = autoGCRooters as *mut *mut _;
205        self.down = *autoGCRooters as *mut _;
206
207        assert!(*self.stackTop != self);
208        *autoGCRooters = self as *mut _ as _;
209    }
210
211    pub unsafe fn remove_from_root_stack(&mut self) {
212        assert!(*self.stackTop == self);
213        *self.stackTop = self.down;
214    }
215}
216
217impl JSJitMethodCallArgs {
218    #[inline]
219    pub fn get(&self, i: u32) -> JS::HandleValue {
220        unsafe {
221            if i < self.argc_ {
222                JS::HandleValue::from_marked_location(self.argv_.offset(i as isize))
223            } else {
224                JS::UndefinedHandleValue
225            }
226        }
227    }
228
229    #[inline]
230    pub fn index(&self, i: u32) -> JS::HandleValue {
231        assert!(i < self.argc_);
232        unsafe { JS::HandleValue::from_marked_location(self.argv_.offset(i as isize)) }
233    }
234
235    #[inline]
236    pub fn index_mut(&self, i: u32) -> JS::MutableHandleValue {
237        assert!(i < self.argc_);
238        unsafe { JS::MutableHandleValue::from_marked_location(self.argv_.offset(i as isize)) }
239    }
240
241    #[inline]
242    pub fn rval(&self) -> JS::MutableHandleValue {
243        unsafe { JS::MutableHandleValue::from_marked_location(self.argv_.offset(-2)) }
244    }
245}
246
247impl JSJitGetterCallArgs {
248    #[inline]
249    pub fn rval(&self) -> JS::MutableHandleValue {
250        self._base
251    }
252}
253
254// XXX need to hack up bindgen to convert this better so we don't have
255//     to duplicate so much code here
256impl JS::CallArgs {
257    #[inline]
258    pub unsafe fn from_vp(vp: *mut JS::Value, argc: u32) -> JS::CallArgs {
259        // For some reason, with debugmozjs, calling
260        // JS_CallArgsFromVp(argc, vp)
261        // produces a SEGV caused by the vp being overwritten by the argc.
262        // TODO: debug this!
263        JS::CallArgs {
264            _bitfield_align_1: Default::default(),
265            _bitfield_1: JS::CallArgs::new_bitfield_1((*vp.offset(1)).is_magic(), false),
266            argc_: argc,
267            argv_: vp.offset(2),
268            #[cfg(not(feature = "debugmozjs"))]
269            __bindgen_padding_0: [0, 0, 0],
270            #[cfg(feature = "debugmozjs")]
271            wantUsedRval_: JS::detail::IncludeUsedRval { usedRval_: false },
272        }
273    }
274
275    #[inline]
276    pub fn index(&self, i: u32) -> JS::HandleValue {
277        assert!(i < self.argc_);
278        unsafe { JS::HandleValue::from_marked_location(self.argv_.offset(i as isize)) }
279    }
280
281    #[inline]
282    pub fn index_mut(&self, i: u32) -> JS::MutableHandleValue {
283        assert!(i < self.argc_);
284        unsafe { JS::MutableHandleValue::from_marked_location(self.argv_.offset(i as isize)) }
285    }
286
287    #[inline]
288    pub fn get(&self, i: u32) -> JS::HandleValue {
289        unsafe {
290            if i < self.argc_ {
291                JS::HandleValue::from_marked_location(self.argv_.offset(i as isize))
292            } else {
293                JS::UndefinedHandleValue
294            }
295        }
296    }
297
298    #[inline]
299    pub fn rval(&self) -> JS::MutableHandleValue {
300        unsafe { JS::MutableHandleValue::from_marked_location(self.argv_.offset(-2)) }
301    }
302
303    #[inline]
304    pub fn thisv(&self) -> JS::HandleValue {
305        unsafe { JS::HandleValue::from_marked_location(self.argv_.offset(-1)) }
306    }
307
308    #[inline]
309    pub fn calleev(&self) -> JS::HandleValue {
310        unsafe { JS::HandleValue::from_marked_location(self.argv_.offset(-2)) }
311    }
312
313    #[inline]
314    pub fn callee(&self) -> *mut JSObject {
315        self.calleev().to_object()
316    }
317
318    #[inline]
319    pub fn new_target(&self) -> JS::MutableHandleValue {
320        assert!(self.constructing_());
321        unsafe {
322            JS::MutableHandleValue::from_marked_location(self.argv_.offset(self.argc_ as isize))
323        }
324    }
325
326    #[inline]
327    pub fn is_constructing(&self) -> bool {
328        unsafe { (*self.argv_.offset(-1)).is_magic() }
329    }
330}
331
332impl JSJitSetterCallArgs {
333    #[inline]
334    pub fn get(&self, i: u32) -> JS::HandleValue {
335        assert!(i == 0);
336        self._base.handle()
337    }
338}
339
340impl JSFunctionSpec {
341    pub const ZERO: Self = JSFunctionSpec {
342        name: JSPropertySpec_Name {
343            string_: ptr::null(),
344        },
345        selfHostedName: 0 as *const _,
346        flags: 0,
347        nargs: 0,
348        call: JSNativeWrapper::ZERO,
349    };
350
351    pub fn is_zeroed(&self) -> bool {
352        (unsafe { self.name.string_.is_null() })
353            && self.selfHostedName.is_null()
354            && self.flags == 0
355            && self.nargs == 0
356            && self.call.is_zeroed()
357    }
358}
359
360impl JSPropertySpec {
361    pub const ZERO: Self = JSPropertySpec {
362        name: JSPropertySpec_Name {
363            string_: ptr::null(),
364        },
365        attributes_: 0,
366        kind_: JSPropertySpec_Kind::NativeAccessor,
367        u: crate::jsapi::JSPropertySpec_AccessorsOrValue {
368            accessors: crate::jsapi::JSPropertySpec_AccessorsOrValue_Accessors {
369                getter: crate::jsapi::JSPropertySpec_Accessor {
370                    native: JSNativeWrapper::ZERO,
371                },
372                setter: crate::jsapi::JSPropertySpec_Accessor {
373                    native: JSNativeWrapper::ZERO,
374                },
375            },
376        },
377    };
378
379    /// https://searchfox.org/mozilla-central/rev/2bdaa395cb841b28f8ef74882a61df5efeedb42b/js/public/PropertySpec.h#305-307
380    pub fn is_accessor(&self) -> bool {
381        self.kind_ == JSPropertySpec_Kind::NativeAccessor
382            || self.kind_ == JSPropertySpec_Kind::SelfHostedAccessor
383    }
384
385    pub fn is_zeroed(&self) -> bool {
386        (unsafe { self.name.string_.is_null() })
387            && self.attributes_ == 0
388            && self.is_accessor()
389            && unsafe { self.u.accessors.getter.native.is_zeroed() }
390            && unsafe { self.u.accessors.setter.native.is_zeroed() }
391    }
392}
393
394impl JSNativeWrapper {
395    pub const ZERO: Self = JSNativeWrapper {
396        info: 0 as *const _,
397        op: None,
398    };
399
400    pub fn is_zeroed(&self) -> bool {
401        self.op.is_none() && self.info.is_null()
402    }
403}
404
405impl RootedBase {
406    unsafe fn add_to_root_stack(this: *mut Self, cx: *mut JSContext, kind: JS::RootKind) {
407        let stack = Self::get_root_stack(cx, kind);
408        (*this).stack = stack;
409        (*this).prev = *stack;
410
411        *stack = this as usize as _;
412    }
413
414    unsafe fn remove_from_root_stack(&mut self) {
415        assert!(*self.stack == self as *mut _ as usize as _);
416        *self.stack = self.prev;
417    }
418
419    unsafe fn get_root_stack(cx: *mut JSContext, kind: JS::RootKind) -> *mut *mut RootedBase {
420        let kind = kind as usize;
421        let rooting_cx = Self::get_rooting_context(cx);
422        &mut (*rooting_cx).stackRoots_.0[kind] as *mut _ as *mut _
423    }
424
425    unsafe fn get_rooting_context(cx: *mut JSContext) -> *mut JS::RootingContext {
426        cx as *mut JS::RootingContext
427    }
428}
429
430impl<T: RootKind> JS::Rooted<T> {
431    pub fn new_unrooted(initial: T) -> JS::Rooted<T> {
432        JS::Rooted {
433            vtable: T::VTABLE,
434            base: RootedBase {
435                stack: ptr::null_mut(),
436                prev: ptr::null_mut(),
437            },
438            data: initial,
439        }
440    }
441
442    pub unsafe fn add_to_root_stack(this: *mut Self, cx: *mut JSContext) {
443        let base = unsafe { &raw mut (*this).base };
444        RootedBase::add_to_root_stack(base, cx, T::KIND)
445    }
446
447    pub unsafe fn remove_from_root_stack(&mut self) {
448        self.base.remove_from_root_stack()
449    }
450}
451
452impl JS::ObjectOpResult {
453    pub fn ok(&self) -> bool {
454        assert_ne!(
455            self.code_,
456            JS::ObjectOpResult_SpecialCodes::Uninitialized as usize
457        );
458        self.code_ == JS::ObjectOpResult_SpecialCodes::OkCode as usize
459    }
460
461    /// Set this ObjectOpResult to true and return true.
462    pub fn succeed(&mut self) -> bool {
463        self.code_ = JS::ObjectOpResult_SpecialCodes::OkCode as usize;
464        true
465    }
466
467    pub fn fail(&mut self, code: JSErrNum) -> bool {
468        assert_ne!(
469            code as usize,
470            JS::ObjectOpResult_SpecialCodes::OkCode as usize
471        );
472        self.code_ = code as usize;
473        true
474    }
475
476    pub fn fail_cant_redefine_prop(&mut self) -> bool {
477        self.fail(JSErrNum::JSMSG_CANT_REDEFINE_PROP)
478    }
479
480    pub fn fail_read_only(&mut self) -> bool {
481        self.fail(JSErrNum::JSMSG_READ_ONLY)
482    }
483
484    pub fn fail_getter_only(&mut self) -> bool {
485        self.fail(JSErrNum::JSMSG_GETTER_ONLY)
486    }
487
488    pub fn fail_cant_delete(&mut self) -> bool {
489        self.fail(JSErrNum::JSMSG_CANT_DELETE)
490    }
491
492    pub fn fail_cant_set_interposed(&mut self) -> bool {
493        self.fail(JSErrNum::JSMSG_CANT_SET_INTERPOSED)
494    }
495
496    pub fn fail_cant_define_window_element(&mut self) -> bool {
497        self.fail(JSErrNum::JSMSG_CANT_DEFINE_WINDOW_ELEMENT)
498    }
499
500    pub fn fail_cant_delete_window_element(&mut self) -> bool {
501        self.fail(JSErrNum::JSMSG_CANT_DELETE_WINDOW_ELEMENT)
502    }
503
504    pub fn fail_cant_define_window_named_property(&mut self) -> bool {
505        self.fail(JSErrNum::JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY)
506    }
507
508    pub fn fail_cant_delete_window_named_property(&mut self) -> bool {
509        self.fail(JSErrNum::JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY)
510    }
511
512    pub fn fail_cant_define_window_non_configurable(&mut self) -> bool {
513        self.fail(JSErrNum::JSMSG_CANT_DEFINE_WINDOW_NC)
514    }
515
516    pub fn fail_cant_prevent_extensions(&mut self) -> bool {
517        self.fail(JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS)
518    }
519
520    pub fn fail_cant_set_proto(&mut self) -> bool {
521        self.fail(JSErrNum::JSMSG_CANT_SET_PROTO)
522    }
523
524    pub fn fail_no_named_setter(&mut self) -> bool {
525        self.fail(JSErrNum::JSMSG_NO_NAMED_SETTER)
526    }
527
528    pub fn fail_no_indexed_setter(&mut self) -> bool {
529        self.fail(JSErrNum::JSMSG_NO_INDEXED_SETTER)
530    }
531
532    pub fn fail_not_data_descriptor(&mut self) -> bool {
533        self.fail(JSErrNum::JSMSG_NOT_DATA_DESCRIPTOR)
534    }
535
536    pub fn fail_invalid_descriptor(&mut self) -> bool {
537        self.fail(JSErrNum::JSMSG_INVALID_DESCRIPTOR)
538    }
539
540    pub fn fail_bad_array_length(&mut self) -> bool {
541        self.fail(JSErrNum::JSMSG_BAD_ARRAY_LENGTH)
542    }
543
544    pub fn fail_bad_index(&mut self) -> bool {
545        self.fail(JSErrNum::JSMSG_BAD_INDEX)
546    }
547
548    pub fn failure_code(&self) -> u32 {
549        assert!(!self.ok());
550        self.code_ as u32
551    }
552
553    #[deprecated]
554    #[allow(non_snake_case)]
555    pub fn failNoNamedSetter(&mut self) -> bool {
556        self.fail_no_named_setter()
557    }
558}
559
560impl Default for JS::ObjectOpResult {
561    fn default() -> JS::ObjectOpResult {
562        JS::ObjectOpResult {
563            code_: JS::ObjectOpResult_SpecialCodes::Uninitialized as usize,
564        }
565    }
566}
567
568impl JS::ForOfIterator {
569    pub unsafe fn init(
570        &mut self,
571        iterable: JS::HandleValue,
572        non_iterable_behavior: JS::ForOfIterator_NonIterableBehavior,
573    ) -> bool {
574        JS_ForOfIteratorInit(self, iterable, non_iterable_behavior)
575    }
576
577    pub unsafe fn next(&mut self, val: JS::MutableHandleValue, done: *mut bool) -> bool {
578        JS_ForOfIteratorNext(self, val, done)
579    }
580}
581
582impl<T> mozilla::Range<T> {
583    pub fn new(start: &mut T, end: &mut T) -> mozilla::Range<T> {
584        mozilla::Range {
585            mStart: mozilla::RangedPtr {
586                mPtr: start,
587                #[cfg(feature = "debugmozjs")]
588                mRangeStart: start,
589                #[cfg(feature = "debugmozjs")]
590                mRangeEnd: end,
591                _phantom_0: PhantomData,
592            },
593            mEnd: mozilla::RangedPtr {
594                mPtr: end,
595                #[cfg(feature = "debugmozjs")]
596                mRangeStart: start,
597                #[cfg(feature = "debugmozjs")]
598                mRangeEnd: end,
599                _phantom_0: PhantomData,
600            },
601            _phantom_0: PhantomData,
602        }
603    }
604}
605
606impl Type {
607    /// Returns byte size of Type (if possible to determine)
608    ///
609    /// <https://searchfox.org/mozilla-central/rev/396a6123691f7ab3ffb449dcbe95304af6f9df3c/js/public/ScalarType.h#66>
610    pub const fn byte_size(&self) -> Option<usize> {
611        match self {
612            Type::Int8 | Type::Uint8 | Type::Uint8Clamped => Some(1),
613            Type::Int16 | Type::Uint16 | Type::Float16 => Some(2),
614            Type::Int32 | Type::Uint32 | Type::Float32 => Some(4),
615            Type::Int64 | Type::Float64 | Type::BigInt64 | Type::BigUint64 => Some(8),
616            Type::Simd128 => Some(16),
617            Type::MaxTypedArrayViewType => None,
618        }
619    }
620}