Skip to main content

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