diff --git a/mozjs-sys/src/jsgc.rs b/mozjs-sys/src/jsgc.rs index a80ab14c21f..ece0a06d4a7 100644 --- a/mozjs-sys/src/jsgc.rs +++ b/mozjs-sys/src/jsgc.rs @@ -8,7 +8,6 @@ use crate::jsapi::{jsid, JSFunction, JSObject, JSScript, JSString, JSTracer}; use crate::jsid::VoidId; use std::cell::UnsafeCell; use std::ffi::c_void; -use std::mem; use std::ptr; /// A trait for JS types that can be registered as roots. @@ -116,9 +115,9 @@ impl GCMethods for *mut JSFunction { } unsafe fn post_barrier(v: *mut *mut JSFunction, prev: *mut JSFunction, next: *mut JSFunction) { JS::HeapObjectWriteBarriers( - mem::transmute(v), - mem::transmute(prev), - mem::transmute(next), + v as *mut *mut JSObject, + prev as *mut JSObject, + next as *mut JSObject, ); } } diff --git a/mozjs-sys/src/jsid.rs b/mozjs-sys/src/jsid.rs index d0c22daa2f4..1a3e0e33130 100644 --- a/mozjs-sys/src/jsid.rs +++ b/mozjs-sys/src/jsid.rs @@ -6,7 +6,8 @@ use crate::jsapi::JS::Symbol; use crate::jsapi::{jsid, JSString}; -use libc::c_void; + +use std::ffi::c_void; #[deprecated] pub const JSID_VOID: jsid = VoidId(); diff --git a/mozjs-sys/src/jsval.rs b/mozjs-sys/src/jsval.rs index 07575e954ee..0a1228bae7d 100644 --- a/mozjs-sys/src/jsval.rs +++ b/mozjs-sys/src/jsval.rs @@ -14,95 +14,100 @@ use crate::jsapi::JS::Symbol; use crate::jsapi::JS::TraceKind; use crate::jsapi::JS::Value; -use libc::c_void; use std::default::Default; -use std::mem; +use std::ffi::c_void; pub type JSVal = Value; #[cfg(target_pointer_width = "64")] const JSVAL_TAG_SHIFT: usize = 47; -#[cfg(target_pointer_width = "64")] -const JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32; +#[cfg(target_pointer_width = "32")] +const JSVAL_TAG_SHIFT: usize = 32; + +const JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0; #[cfg(target_pointer_width = "32")] const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80; #[cfg(target_pointer_width = "64")] -#[repr(u32)] -#[allow(dead_code)] -enum ValueTag { - INT32 = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32), - UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), - STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32), - SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32), - BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32), - BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), - MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32), - NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32), - OBJECT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32), -} +const JSVAL_TAG_BOX: u32 = JSVAL_TAG_MAX_DOUBLE; #[cfg(target_pointer_width = "32")] +const JSVAL_TAG_BOX: u32 = JSVAL_TAG_CLEAR; + +const CELL_ALIGN_MASK: u64 = (1 << 3) - 1; + #[repr(u32)] #[allow(dead_code)] enum ValueTag { - PRIVATE = 0, - INT32 = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32), - UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), - STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32), - SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32), - BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32), - BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), - MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32), - NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32), - OBJECT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32), + INT32 = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_INT32 as u32), + UNDEFINED = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), + NULL = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_NULL as u32), + BOOLEAN = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), + MAGIC = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_MAGIC as u32), + STRING = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_STRING as u32), + SYMBOL = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_SYMBOL as u32), + PRIVATE_GCTHING = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_PRIVATE_GCTHING as u32), + BIGINT = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_BIGINT as u32), + OBJECT = JSVAL_TAG_BOX | (JSValueType::JSVAL_TYPE_OBJECT as u32), } -#[cfg(target_pointer_width = "64")] #[repr(u64)] #[allow(dead_code)] enum ValueShiftedTag { - MAX_DOUBLE = ((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64, + MAX_DOUBLE = ((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF, INT32 = (ValueTag::INT32 as u64) << JSVAL_TAG_SHIFT, UNDEFINED = (ValueTag::UNDEFINED as u64) << JSVAL_TAG_SHIFT, + NULL = (ValueTag::NULL as u64) << JSVAL_TAG_SHIFT, + BOOLEAN = (ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT, + MAGIC = (ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT, STRING = (ValueTag::STRING as u64) << JSVAL_TAG_SHIFT, SYMBOL = (ValueTag::SYMBOL as u64) << JSVAL_TAG_SHIFT, + PRIVATE_GCTHING = (ValueTag::PRIVATE_GCTHING as u64) << JSVAL_TAG_SHIFT, BIGINT = (ValueTag::BIGINT as u64) << JSVAL_TAG_SHIFT, - BOOLEAN = (ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT, - MAGIC = (ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT, - NULL = (ValueTag::NULL as u64) << JSVAL_TAG_SHIFT, OBJECT = (ValueTag::OBJECT as u64) << JSVAL_TAG_SHIFT, } const JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF; #[inline(always)] -fn AsJSVal(val: u64) -> JSVal { - JSVal { asBits_: val } +fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal { + JSVal { + asBits_: ((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload, + } } #[cfg(target_pointer_width = "64")] #[inline(always)] -fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal { - AsJSVal(((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload) +fn AssertGCPointerValid(bits: u64) { + assert_eq!(bits >> JSVAL_TAG_SHIFT, 0) } #[cfg(target_pointer_width = "32")] #[inline(always)] -fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal { - AsJSVal(((tag as u32 as u64) << 32) | payload) +fn AssertGCPointerValid(bits: u64) {} + +#[cfg(target_pointer_width = "64")] +#[inline(always)] +fn AssertGCPointerAlignment(bits: u64) { + assert_eq!(bits & CELL_ALIGN_MASK, 0); } +#[cfg(target_pointer_width = "32")] #[inline(always)] -pub fn NullValue() -> JSVal { - BuildJSVal(ValueTag::NULL, 0) +fn AssertGCPointerAlignment(bits: u64) {} + +#[cfg(target_pointer_width = "64")] +#[inline(always)] +fn IsValidUserModePointer(bits: u64) -> bool { + bits & 0xFFFF_0000_0000_0000 == 0 } +#[cfg(target_pointer_width = "32")] #[inline(always)] -pub fn UndefinedValue() -> JSVal { - BuildJSVal(ValueTag::UNDEFINED, 0) +fn IsValidUserModePointer(_: u64) -> bool { + true } #[inline(always)] @@ -110,19 +115,21 @@ pub fn Int32Value(i: i32) -> JSVal { BuildJSVal(ValueTag::INT32, i as u32 as u64) } -#[cfg(target_pointer_width = "64")] #[inline(always)] -pub fn DoubleValue(f: f64) -> JSVal { - let bits: u64 = unsafe { mem::transmute(f) }; - assert!(bits <= ValueShiftedTag::MAX_DOUBLE as u64); - AsJSVal(bits) +pub fn UndefinedValue() -> JSVal { + BuildJSVal(ValueTag::UNDEFINED, 0) +} + +#[inline(always)] +pub fn NullValue() -> JSVal { + BuildJSVal(ValueTag::NULL, 0) } -#[cfg(target_pointer_width = "32")] #[inline(always)] pub fn DoubleValue(f: f64) -> JSVal { - let bits: u64 = unsafe { mem::transmute(f) }; - let val = AsJSVal(bits); + let val = JSVal { + asBits_: f.to_bits(), + }; assert!(val.is_double()); val } @@ -136,38 +143,36 @@ pub fn UInt32Value(ui: u32) -> JSVal { } } -#[cfg(target_pointer_width = "64")] #[inline(always)] pub fn StringValue(s: &JSString) -> JSVal { let bits = s as *const JSString as usize as u64; - assert!((bits >> JSVAL_TAG_SHIFT) == 0); + AssertGCPointerValid(bits); BuildJSVal(ValueTag::STRING, bits) } -#[cfg(target_pointer_width = "32")] #[inline(always)] -pub fn StringValue(s: &JSString) -> JSVal { - let bits = s as *const JSString as usize as u64; - BuildJSVal(ValueTag::STRING, bits) +pub fn SymbolValue(s: &Symbol) -> JSVal { + let bits = s as *const Symbol as usize as u64; + AssertGCPointerValid(bits); + BuildJSVal(ValueTag::SYMBOL, bits) } #[inline(always)] -pub fn BooleanValue(b: bool) -> JSVal { - BuildJSVal(ValueTag::BOOLEAN, b as u64) +pub fn BigIntValue(s: &BigInt) -> JSVal { + let bits = s as *const BigInt as usize as u64; + AssertGCPointerValid(bits); + BuildJSVal(ValueTag::BIGINT, bits) } -#[cfg(target_pointer_width = "64")] #[inline(always)] -pub fn ObjectValue(o: *mut JSObject) -> JSVal { - let bits = o as usize as u64; - assert!((bits >> JSVAL_TAG_SHIFT) == 0); - BuildJSVal(ValueTag::OBJECT, bits) +pub fn BooleanValue(b: bool) -> JSVal { + BuildJSVal(ValueTag::BOOLEAN, b as u64) } -#[cfg(target_pointer_width = "32")] #[inline(always)] pub fn ObjectValue(o: *mut JSObject) -> JSVal { let bits = o as usize as u64; + AssertGCPointerValid(bits); BuildJSVal(ValueTag::OBJECT, bits) } @@ -180,42 +185,11 @@ pub fn ObjectOrNullValue(o: *mut JSObject) -> JSVal { } } -#[cfg(target_pointer_width = "64")] -#[inline(always)] -pub fn SymbolValue(s: &Symbol) -> JSVal { - let bits = s as *const Symbol as usize as u64; - assert!((bits >> JSVAL_TAG_SHIFT) == 0); - BuildJSVal(ValueTag::SYMBOL, bits) -} - -#[cfg(target_pointer_width = "32")] -#[inline(always)] -pub fn SymbolValue(s: &Symbol) -> JSVal { - let bits = s as *const Symbol as usize as u64; - BuildJSVal(ValueTag::SYMBOL, bits) -} - -#[cfg(target_pointer_width = "64")] -#[inline(always)] -pub fn BigIntValue(s: &BigInt) -> JSVal { - let bits = s as *const BigInt as usize as u64; - assert!((bits >> JSVAL_TAG_SHIFT) == 0); - BuildJSVal(ValueTag::BIGINT, bits) -} - -#[cfg(target_pointer_width = "32")] -#[inline(always)] -pub fn BigIntValue(s: &BigInt) -> JSVal { - let bits = s as *const BigInt as usize as u64; - BuildJSVal(ValueTag::BIGINT, bits) -} - #[inline(always)] pub fn PrivateValue(o: *const c_void) -> JSVal { let ptrBits = o as usize as u64; - #[cfg(target_pointer_width = "64")] - assert_eq!(ptrBits & 0xFFFF000000000000, 0); - AsJSVal(ptrBits) + assert!(IsValidUserModePointer(ptrBits)); + JSVal { asBits_: ptrBits } } impl JSVal { @@ -224,213 +198,156 @@ impl JSVal { self.asBits_ } - #[inline(always)] #[cfg(target_pointer_width = "64")] - pub fn is_undefined(&self) -> bool { - self.asBits() == ValueShiftedTag::UNDEFINED as u64 - } - #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_undefined(&self) -> bool { - (self.asBits() >> 32) == ValueTag::UNDEFINED as u64 + fn payload(&self) -> u64 { + self.asBits_ & JSVAL_PAYLOAD_MASK } - #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_null(&self) -> bool { - self.asBits() == ValueShiftedTag::NULL as u64 - } - - #[inline(always)] #[cfg(target_pointer_width = "32")] - pub fn is_null(&self) -> bool { - (self.asBits() >> 32) == ValueTag::NULL as u64 + #[inline(always)] + fn payload(&self) -> u32 { + (self.asBits_ & 0xFFFFFFFF) as u32 } #[inline(always)] - pub fn is_null_or_undefined(&self) -> bool { - self.is_null() || self.is_undefined() + fn toTag(&self) -> u64 { + self.asBits_ >> JSVAL_TAG_SHIFT } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_boolean(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64 + pub fn is_undefined(&self) -> bool { + self.asBits() == ValueShiftedTag::UNDEFINED as u64 } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_boolean(&self) -> bool { - (self.asBits() >> 32) == ValueTag::BOOLEAN as u64 + pub fn is_null(&self) -> bool { + self.asBits() == ValueShiftedTag::NULL as u64 } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_int32(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::INT32 as u64 + pub fn is_null_or_undefined(&self) -> bool { + self.is_null() || self.is_undefined() } #[inline(always)] - #[cfg(target_pointer_width = "32")] pub fn is_int32(&self) -> bool { - (self.asBits() >> 32) == ValueTag::INT32 as u64 + self.toTag() == ValueTag::INT32 as u64 } - #[inline(always)] #[cfg(target_pointer_width = "64")] + #[inline(always)] pub fn is_double(&self) -> bool { self.asBits() <= ValueShiftedTag::MAX_DOUBLE as u64 } - #[inline(always)] #[cfg(target_pointer_width = "32")] + #[inline(always)] pub fn is_double(&self) -> bool { - (self.asBits() >> 32) <= JSVAL_TAG_CLEAR as u64 + (self.asBits() >> JSVAL_TAG_SHIFT) as u32 <= JSVAL_TAG_CLEAR } - #[inline(always)] #[cfg(target_pointer_width = "64")] + #[inline(always)] pub fn is_number(&self) -> bool { const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET: u64 = ValueShiftedTag::BOOLEAN as u64; self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET } - #[inline(always)] #[cfg(target_pointer_width = "32")] + #[inline(always)] pub fn is_number(&self) -> bool { + assert_ne!(self.toTag(), JSVAL_TAG_CLEAR as u64); const JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET: u64 = ValueTag::INT32 as u64; - (self.asBits() >> 32) <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET - } - - #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_primitive(&self) -> bool { - const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = ValueShiftedTag::OBJECT as u64; - self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET + self.toTag() <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_primitive(&self) -> bool { - const JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET: u64 = ValueTag::OBJECT as u64; - (self.asBits() >> 32) < JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET + pub fn is_string(&self) -> bool { + self.toTag() == ValueTag::STRING as u64 } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_string(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::STRING as u64 + pub fn is_symbol(&self) -> bool { + self.toTag() == ValueTag::SYMBOL as u64 } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_string(&self) -> bool { - (self.asBits() >> 32) == ValueTag::STRING as u64 + pub fn is_bigint(&self) -> bool { + self.toTag() == ValueTag::BIGINT as u64 } - #[inline(always)] #[cfg(target_pointer_width = "64")] + #[inline(always)] pub fn is_object(&self) -> bool { - assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64); + assert!(self.toTag() <= ValueTag::OBJECT as u64); self.asBits() >= ValueShiftedTag::OBJECT as u64 } - #[inline(always)] #[cfg(target_pointer_width = "32")] + #[inline(always)] pub fn is_object(&self) -> bool { - (self.asBits() >> 32) == ValueTag::OBJECT as u64 + self.toTag() == ValueTag::OBJECT as u64 } - #[inline(always)] #[cfg(target_pointer_width = "64")] - pub fn is_object_or_null(&self) -> bool { - const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueShiftedTag::NULL as u64; - assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64); - self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET - } - #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_object_or_null(&self) -> bool { - const JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueTag::NULL as u64; - assert!((self.asBits() >> 32) <= ValueTag::OBJECT as u64); - (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET - } - - #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_magic(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::MAGIC as u64 + pub fn is_primitive(&self) -> bool { + const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = ValueShiftedTag::OBJECT as u64; + self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET } - #[inline(always)] #[cfg(target_pointer_width = "32")] - pub fn is_magic(&self) -> bool { - (self.asBits() >> 32) == ValueTag::MAGIC as u64 - } - #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_symbol(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::SYMBOL as u64 - } - - #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_symbol(&self) -> bool { - (self.asBits() >> 32) == ValueTag::SYMBOL as u64 + pub fn is_primitive(&self) -> bool { + const JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET: u64 = ValueTag::OBJECT as u64; + self.toTag() < JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn is_bigint(&self) -> bool { - (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64 + pub fn is_object_or_null(&self) -> bool { + self.is_object() || self.is_null() } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn is_bigint(&self) -> bool { - (self.asBits() >> 32) == ValueTag::BIGINT as u64 + pub fn is_numeric(&self) -> bool { + self.is_number() || self.is_bigint() } - #[inline(always)] #[cfg(target_pointer_width = "64")] + #[inline(always)] pub fn is_gcthing(&self) -> bool { const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = ValueShiftedTag::STRING as u64; self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET } - #[inline(always)] #[cfg(target_pointer_width = "32")] + #[inline(always)] pub fn is_gcthing(&self) -> bool { const JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET: u64 = ValueTag::STRING as u64; - (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET + self.toTag() >= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn to_boolean(&self) -> bool { - assert!(self.is_boolean()); - (self.asBits() & JSVAL_PAYLOAD_MASK) != 0 + pub fn is_boolean(&self) -> bool { + (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64 } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn to_boolean(&self) -> bool { - (self.asBits() & 0x00000000FFFFFFFF) != 0 + pub fn is_magic(&self) -> bool { + self.toTag() == ValueTag::MAGIC as u64 } #[inline(always)] pub fn to_int32(&self) -> i32 { assert!(self.is_int32()); - (self.asBits() & 0x00000000FFFFFFFF) as i32 + (self.asBits() & 0xFFFFFFFF) as i32 } #[inline(always)] pub fn to_double(&self) -> f64 { assert!(self.is_double()); - unsafe { mem::transmute(self.asBits()) } + f64::from_bits(self.asBits()) } #[inline(always)] @@ -444,19 +361,27 @@ impl JSVal { } #[inline(always)] - #[cfg(target_pointer_width = "64")] pub fn to_string(&self) -> *mut JSString { assert!(self.is_string()); - let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; + let ptrBits = self.payload(); + AssertGCPointerAlignment(ptrBits as u64); ptrBits as usize as *mut JSString } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn to_string(&self) -> *mut JSString { - assert!(self.is_string()); - let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; - ptrBits as *mut JSString + pub fn to_symbol(&self) -> *mut Symbol { + assert!(self.is_symbol()); + let ptrBits = self.payload(); + AssertGCPointerAlignment(ptrBits as u64); + ptrBits as usize as *mut Symbol + } + + #[inline(always)] + pub fn to_bigint(&self) -> *mut BigInt { + assert!(self.is_bigint()); + let ptrBits = self.payload(); + AssertGCPointerAlignment(ptrBits as u64); + ptrBits as usize as *mut BigInt } #[inline(always)] @@ -469,8 +394,8 @@ impl JSVal { #[cfg(target_pointer_width = "64")] pub fn to_object_or_null(&self) -> *mut JSObject { assert!(self.is_object_or_null()); - let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; - assert!((ptrBits & 0x7) == 0); + let ptrBits = self.payload(); + AssertGCPointerAlignment(ptrBits); ptrBits as usize as *mut JSObject } @@ -483,44 +408,28 @@ impl JSVal { } #[inline(always)] - pub fn to_symbol(&self) -> *mut Symbol { - assert!(self.is_symbol()); - let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; - assert!((ptrBits & 0x7) == 0); - ptrBits as usize as *mut Symbol - } - - #[inline(always)] - pub fn to_bigint(&self) -> *mut BigInt { - assert!(self.is_bigint()); - let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; - assert!((ptrBits & 0x7) == 0); - ptrBits as usize as *mut BigInt + pub fn to_gcthing(&self) -> *mut c_void { + assert!(self.is_gcthing()); + let ptrBits = self.payload(); + AssertGCPointerAlignment(ptrBits as u64); + ptrBits as *mut c_void } #[inline(always)] - pub fn to_private(&self) -> *const c_void { - assert!(self.is_double()); - #[cfg(target_pointer_width = "64")] - assert_eq!(self.asBits() & 0xFFFF000000000000, 0); - self.asBits() as usize as *const c_void + pub fn to_boolean(&self) -> bool { + assert!(self.is_boolean()); + self.payload() != 0 } #[inline(always)] - #[cfg(target_pointer_width = "64")] - pub fn to_gcthing(&self) -> *mut c_void { - assert!(self.is_gcthing()); - let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK; - assert!((ptrBits & 0x7) == 0); - ptrBits as *mut c_void + pub fn is_private(&self) -> bool { + self.is_double() && IsValidUserModePointer(self.asBits()) } #[inline(always)] - #[cfg(target_pointer_width = "32")] - pub fn to_gcthing(&self) -> *mut c_void { - assert!(self.is_gcthing()); - let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32; - ptrBits as *mut c_void + pub fn to_private(&self) -> *const c_void { + assert!(self.is_private()); + self.asBits() as usize as *const c_void } #[inline(always)] @@ -544,6 +453,7 @@ impl JSVal { } impl Default for JSVal { + #[inline(always)] fn default() -> JSVal { UndefinedValue() }