0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-01-22 06:09:47 -05:00

Add 'Value::same_value_zero()' (#414)

This commit is contained in:
Bert Belder 2020-07-04 06:00:58 +02:00
parent 1b84bc74f6
commit d3f6e4d36c
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
3 changed files with 94 additions and 3 deletions

View file

@ -1,6 +1,9 @@
use crate::isolate::Isolate;
use std::alloc::Layout;
use std::ptr::NonNull;
use crate::HandleScope;
use crate::Integer;
use crate::Isolate;
use crate::Local;
use crate::Number;
@ -57,4 +60,21 @@ impl Integer {
pub fn value(&self) -> i64 {
unsafe { v8__Integer__Value(self) }
}
/// Internal helper function to produce a handle containing a SMI zero value,
/// without the need for the caller to provide (or have entered) a
/// `HandleScope`.
pub(crate) fn zero<'s>() -> Local<'s, Integer> {
// The SMI representation of zero is also zero. In debug builds, double
// check this, so in the unlikely event that V8 changes its internal
// representation of SMIs such that this invariant no longer holds, we'd
// catch it.
static ZERO_SMI: usize = 0;
let zero_raw = &ZERO_SMI as *const _ as *mut Self;
let zero_nn = unsafe { NonNull::new_unchecked(zero_raw) };
let zero_local = unsafe { Local::from_non_null(zero_nn) };
debug_assert_eq!(Layout::new::<usize>(), Layout::new::<Local<Self>>());
debug_assert_eq!(zero_local.value(), 0);
zero_local
}
}

View file

@ -419,14 +419,35 @@ impl Value {
unsafe { v8__Value__IsModuleNamespaceObject(self) }
}
pub fn strict_equals<'s>(&self, that: Local<'s, Value>) -> bool {
pub fn strict_equals(&self, that: Local<Value>) -> bool {
unsafe { v8__Value__StrictEquals(self, &*that) }
}
pub fn same_value<'s>(&self, that: Local<'s, Value>) -> bool {
pub fn same_value(&self, that: Local<Value>) -> bool {
unsafe { v8__Value__SameValue(self, &*that) }
}
/// Implements the the abstract operation `SameValueZero`, which is defined in
/// ECMA-262 6th edition § 7.2.10
/// (http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero).
///
/// This operation is used to compare values for the purpose of insertion into
/// a `Set`, or determining whether `Map` keys are equivalent. Its semantics
/// are almost the same as `strict_equals()` and `same_value()`, with the
/// following important distinctions:
/// - It considers `NaN` equal to `NaN` (unlike `strict_equals()`).
/// - It considers `-0` equal to `0` (unlike `same_value()`).
pub fn same_value_zero(&self, that: Local<Value>) -> bool {
// The SMI representation of zero is also zero. In debug builds, double
// check this, so in the unlikely event that V8 changes its internal
// representation of SMIs such that this invariant no longer holds, we'd
// catch it.
self.same_value(that) || {
let zero = Integer::zero().into();
self.strict_equals(zero) && that.strict_equals(zero)
}
}
pub fn to_big_int<'s>(
&self,
scope: &mut HandleScope<'s>,

View file

@ -1763,6 +1763,56 @@ fn equality() {
}
}
#[test]
#[allow(clippy::eq_op)]
fn equality_edge_cases() {
let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
let pos_zero = eval(scope, "0").unwrap();
let neg_zero = eval(scope, "-0").unwrap();
let nan = eval(scope, "NaN").unwrap();
assert!(pos_zero == pos_zero);
assert!(pos_zero.same_value(pos_zero));
assert!(pos_zero.same_value_zero(pos_zero));
assert!(pos_zero.strict_equals(pos_zero));
assert!(neg_zero == neg_zero);
assert!(neg_zero.same_value(neg_zero));
assert!(neg_zero.same_value_zero(neg_zero));
assert!(neg_zero.strict_equals(neg_zero));
assert!(pos_zero == neg_zero);
assert!(!pos_zero.same_value(neg_zero));
assert!(pos_zero.same_value_zero(neg_zero));
assert!(pos_zero.strict_equals(neg_zero));
assert!(neg_zero == pos_zero);
assert!(!neg_zero.same_value(pos_zero));
assert!(neg_zero.same_value_zero(pos_zero));
assert!(pos_zero.strict_equals(pos_zero));
assert!(nan != nan);
assert!(nan.same_value(nan));
assert!(nan.same_value_zero(nan));
assert!(!nan.strict_equals(nan));
assert!(nan != pos_zero);
assert!(!nan.same_value(pos_zero));
assert!(!nan.same_value_zero(pos_zero));
assert!(!nan.strict_equals(pos_zero));
assert!(neg_zero != nan);
assert!(!neg_zero.same_value(nan));
assert!(!neg_zero.same_value_zero(nan));
assert!(!neg_zero.strict_equals(nan));
}
#[test]
fn array_buffer_view() {
let _setup_guard = setup();