Commit 1e79bd5c authored by bmeurer's avatar bmeurer Committed by Commit bot

[builtins] Support SameValue and SameValueZero via runtime functions.

Also move Object.is implementation to C++ builtin, which is faster
than the current implementation.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1695743003

Cr-Commit-Position: refs/heads/master@{#34069}
parent 6de9b9ce
......@@ -1103,6 +1103,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kObjectGetOwnPropertyNames, 1, false);
SimpleInstallFunction(object_function, "getOwnPropertySymbols",
Builtins::kObjectGetOwnPropertySymbols, 1, false);
SimpleInstallFunction(object_function, "is", Builtins::kObjectIs, 2, true);
Handle<JSFunction> object_is_extensible =
SimpleInstallFunction(object_function, "isExtensible",
Builtins::kObjectIsExtensible, 1, false);
......
......@@ -1813,6 +1813,16 @@ BUILTIN(ObjectGetOwnPropertySymbols) {
}
// ES#sec-object.is Object.is ( value1, value2 )
BUILTIN(ObjectIs) {
SealHandleScope shs(isolate);
DCHECK_EQ(3, args.length());
Handle<Object> value1 = args.at<Object>(1);
Handle<Object> value2 = args.at<Object>(2);
return isolate->heap()->ToBoolean(value1->SameValue(*value2));
}
// ES6 section 19.1.2.11 Object.isExtensible ( O )
BUILTIN(ObjectIsExtensible) {
HandleScope scope(isolate);
......
......@@ -119,6 +119,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(ObjectGetOwnPropertyDescriptor, kNone) \
V(ObjectGetOwnPropertyNames, kNone) \
V(ObjectGetOwnPropertySymbols, kNone) \
V(ObjectIs, kNone) \
V(ObjectIsExtensible, kNone) \
V(ObjectIsFrozen, kNone) \
V(ObjectIsSealed, kNone) \
......
......@@ -27,7 +27,6 @@ var ObjectToString = utils.ImportNow("object_to_string");
var ObserveBeginPerformSplice;
var ObserveEndPerformSplice;
var ObserveEnqueueSpliceRecord;
var SameValueZero;
var iteratorSymbol = utils.ImportNow("iterator_symbol");
var unscopablesSymbol = utils.ImportNow("unscopables_symbol");
......@@ -43,7 +42,6 @@ utils.Import(function(from) {
ObserveBeginPerformSplice = from.ObserveBeginPerformSplice;
ObserveEndPerformSplice = from.ObserveEndPerformSplice;
ObserveEnqueueSpliceRecord = from.ObserveEnqueueSpliceRecord;
SameValueZero = from.SameValueZero;
});
utils.ImportFromExperimental(function(from) {
......@@ -1724,7 +1722,7 @@ function InnerArrayIncludes(searchElement, fromIndex, array, length) {
while (k < length) {
var elementK = array[k];
if (SameValueZero(searchElement, elementK)) {
if (%SameValueZero(searchElement, elementK)) {
return true;
}
......
......@@ -187,7 +187,6 @@ function PostNatives(utils) {
"PromiseChain",
"PromiseDeferred",
"PromiseResolved",
"SameValueZero",
"SetIterator",
"SetIteratorNext",
"SetValues",
......
......@@ -36,36 +36,11 @@ utils.ImportFromExperimental(function(from) {
// ----------------------------------------------------------------------------
/* -------------------------------------
- - - C o n v e r s i o n s - - -
-------------------------------------
*/
// ES5, section 9.12
function SameValue(x, y) {
if (typeof x !== typeof y) return false;
if (IS_NUMBER(x)) {
if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
// x is +0 and y is -0 or vice versa.
if (x === 0 && y === 0 && 1/x !== 1/y) {
return false;
}
}
if (IS_SIMD_VALUE(x)) return %SimdSameValue(x, y);
return x === y;
}
// ES6, section 7.2.4
function SameValueZero(x, y) {
if (typeof x !== typeof y) return false;
if (IS_NUMBER(x)) {
if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
}
if (IS_SIMD_VALUE(x)) return %SimdSameValueZero(x, y);
return x === y;
}
/* ---------------------------------
- - - U t i l i t i e s - - -
---------------------------------
*/
function ConcatIterableToArray(target, iterable) {
var index = target.length;
......@@ -76,12 +51,6 @@ function ConcatIterableToArray(target, iterable) {
}
/* ---------------------------------
- - - U t i l i t i e s - - -
---------------------------------
*/
// This function should be called rather than %AddElement in contexts where the
// argument might not be less than 2**32-1. ES2015 ToLength semantics mean that
// this is a concern at basically all callsites.
......@@ -164,8 +133,6 @@ utils.Export(function(to) {
to.AddIndexedProperty = AddIndexedProperty;
to.MaxSimple = MaxSimple;
to.MinSimple = MinSimple;
to.SameValue = SameValue;
to.SameValueZero = SameValueZero;
to.ToPositiveInteger = ToPositiveInteger;
to.SpeciesConstructor = SpeciesConstructor;
});
......
......@@ -23,7 +23,6 @@ var ObjectToString = utils.ImportNow("object_to_string");
var ObserveBeginPerformSplice;
var ObserveEndPerformSplice;
var ObserveEnqueueSpliceRecord;
var SameValue = utils.ImportNow("SameValue");
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
......@@ -544,17 +543,17 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
if ((IsGenericDescriptor(desc) ||
IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
(!desc.hasEnumerable() ||
SameValue(desc.isEnumerable(), current.isEnumerable())) &&
%SameValue(desc.isEnumerable(), current.isEnumerable())) &&
(!desc.hasConfigurable() ||
SameValue(desc.isConfigurable(), current.isConfigurable())) &&
%SameValue(desc.isConfigurable(), current.isConfigurable())) &&
(!desc.hasWritable() ||
SameValue(desc.isWritable(), current.isWritable())) &&
%SameValue(desc.isWritable(), current.isWritable())) &&
(!desc.hasValue() ||
SameValue(desc.getValue(), current.getValue())) &&
%SameValue(desc.getValue(), current.getValue())) &&
(!desc.hasGetter() ||
SameValue(desc.getGet(), current.getGet())) &&
%SameValue(desc.getGet(), current.getGet())) &&
(!desc.hasSetter() ||
SameValue(desc.getSet(), current.getSet()))) {
%SameValue(desc.getSet(), current.getSet()))) {
return true;
}
if (!current.isConfigurable()) {
......@@ -593,7 +592,7 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
}
}
if (!currentIsWritable && desc.hasValue() &&
!SameValue(desc.getValue(), current.getValue())) {
!%SameValue(desc.getValue(), current.getValue())) {
if (should_throw) {
throw MakeTypeError(kRedefineDisallowed, p);
} else {
......@@ -604,14 +603,14 @@ function DefineObjectProperty(obj, p, desc, should_throw) {
// Step 11
if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
if (desc.hasSetter() &&
!SameValue(desc.getSet(), current.getSet())) {
!%SameValue(desc.getSet(), current.getSet())) {
if (should_throw) {
throw MakeTypeError(kRedefineDisallowed, p);
} else {
return false;
}
}
if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
if (desc.hasGetter() && !%SameValue(desc.getGet(),current.getGet())) {
if (should_throw) {
throw MakeTypeError(kRedefineDisallowed, p);
} else {
......@@ -871,7 +870,7 @@ utils.InstallFunctions(GlobalObject, DONT_ENUM, [
"getPrototypeOf", ObjectGetPrototypeOf,
"setPrototypeOf", ObjectSetPrototypeOf,
// getOwnPropertySymbols is added in symbol.js.
"is", SameValue, // ECMA-262, Edition 6, section 19.1.2.10
// is is added in bootstrapper.cc.
// deliverChangeRecords, getNotifier, observe and unobserve are added
// in object-observe.js.
]);
......
......@@ -1491,25 +1491,22 @@ bool Object::SameValue(Object* other) {
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
if (IsSimd128Value() && other->IsSimd128Value()) {
if (IsFloat32x4() && other->IsFloat32x4()) {
Float32x4* a = Float32x4::cast(this);
Float32x4* b = Float32x4::cast(other);
for (int i = 0; i < 4; i++) {
float x = a->get_lane(i);
float y = b->get_lane(i);
// Implements the ES5 SameValue operation for floating point types.
// http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
if (std::signbit(x) != std::signbit(y)) return false;
}
return true;
} else {
Simd128Value* a = Simd128Value::cast(this);
Simd128Value* b = Simd128Value::cast(other);
return a->map()->instance_type() == b->map()->instance_type() &&
a->BitwiseEquals(b);
if (IsFloat32x4() && other->IsFloat32x4()) {
Float32x4* a = Float32x4::cast(this);
Float32x4* b = Float32x4::cast(other);
for (int i = 0; i < 4; i++) {
float x = a->get_lane(i);
float y = b->get_lane(i);
// Implements the ES5 SameValue operation for floating point types.
// http://www.ecma-international.org/ecma-262/6.0/#sec-samevalue
if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
if (std::signbit(x) != std::signbit(y)) return false;
}
return true;
} else if (IsSimd128Value() && other->IsSimd128Value()) {
Simd128Value* a = Simd128Value::cast(this);
Simd128Value* b = Simd128Value::cast(other);
return a->map() == b->map() && a->BitwiseEquals(b);
}
return false;
}
......@@ -1530,25 +1527,22 @@ bool Object::SameValueZero(Object* other) {
if (IsString() && other->IsString()) {
return String::cast(this)->Equals(String::cast(other));
}
if (IsSimd128Value() && other->IsSimd128Value()) {
if (IsFloat32x4() && other->IsFloat32x4()) {
Float32x4* a = Float32x4::cast(this);
Float32x4* b = Float32x4::cast(other);
for (int i = 0; i < 4; i++) {
float x = a->get_lane(i);
float y = b->get_lane(i);
// Implements the ES6 SameValueZero operation for floating point types.
// http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
// SameValueZero doesn't distinguish between 0 and -0.
}
return true;
} else {
Simd128Value* a = Simd128Value::cast(this);
Simd128Value* b = Simd128Value::cast(other);
return a->map()->instance_type() == b->map()->instance_type() &&
a->BitwiseEquals(b);
if (IsFloat32x4() && other->IsFloat32x4()) {
Float32x4* a = Float32x4::cast(this);
Float32x4* b = Float32x4::cast(other);
for (int i = 0; i < 4; i++) {
float x = a->get_lane(i);
float y = b->get_lane(i);
// Implements the ES6 SameValueZero operation for floating point types.
// http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
if (x != y && !(std::isnan(x) && std::isnan(y))) return false;
// SameValueZero doesn't distinguish between 0 and -0.
}
return true;
} else if (IsSimd128Value() && other->IsSimd128Value()) {
Simd128Value* a = Simd128Value::cast(this);
Simd128Value* b = Simd128Value::cast(other);
return a->map() == b->map() && a->BitwiseEquals(b);
}
return false;
}
......
......@@ -1095,6 +1095,24 @@ RUNTIME_FUNCTION(Runtime_StrictEquals) {
}
RUNTIME_FUNCTION(Runtime_SameValue) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
CONVERT_ARG_CHECKED(Object, y, 1);
return isolate->heap()->ToBoolean(x->SameValue(y));
}
RUNTIME_FUNCTION(Runtime_SameValueZero) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
CONVERT_ARG_CHECKED(Object, y, 1);
return isolate->heap()->ToBoolean(x->SameValueZero(y));
}
// TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan,
// GreaterThan, etc. which return true or false.
RUNTIME_FUNCTION(Runtime_Compare) {
......
......@@ -164,46 +164,6 @@ RUNTIME_FUNCTION(Runtime_IsSimdValue) {
}
RUNTIME_FUNCTION(Runtime_SimdSameValue) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0);
bool result = false;
// args[1] is of unknown type.
if (args[1]->IsSimd128Value()) {
Simd128Value* b = Simd128Value::cast(args[1]);
if (a->map() == b->map()) {
if (a->IsFloat32x4()) {
result = Float32x4::cast(*a)->SameValue(Float32x4::cast(b));
} else {
result = a->BitwiseEquals(b);
}
}
}
return isolate->heap()->ToBoolean(result);
}
RUNTIME_FUNCTION(Runtime_SimdSameValueZero) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Simd128Value, a, 0);
bool result = false;
// args[1] is of unknown type.
if (args[1]->IsSimd128Value()) {
Simd128Value* b = Simd128Value::cast(args[1]);
if (a->map() == b->map()) {
if (a->IsFloat32x4()) {
result = Float32x4::cast(*a)->SameValueZero(Float32x4::cast(b));
} else {
result = a->BitwiseEquals(b);
}
}
}
return isolate->heap()->ToBoolean(result);
}
//-------------------------------------------------------------------
// Utility macros.
......
......@@ -465,6 +465,8 @@ namespace internal {
F(ToName, 1, 1) \
F(Equals, 2, 1) \
F(StrictEquals, 2, 1) \
F(SameValue, 2, 1) \
F(SameValueZero, 2, 1) \
F(Compare, 3, 1) \
F(InstanceOf, 2, 1) \
F(HasInPrototypeChain, 2, 1) \
......@@ -548,8 +550,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_SIMD(F) \
F(IsSimdValue, 1, 1) \
F(SimdSameValue, 2, 1) \
F(SimdSameValueZero, 2, 1) \
F(CreateFloat32x4, 4, 1) \
F(CreateInt32x4, 4, 1) \
F(CreateUint32x4, 4, 1) \
......
......@@ -407,7 +407,7 @@ function TestSameValue(type, lanes) {
var simdFn = SIMD[type];
var instance = createInstance(type);
var sameValue = Object.is
var sameValueZero = natives.ImportNow("SameValueZero");
var sameValueZero = function(x, y) { return %SameValueZero(x, y); }
// SIMD values should not be the same as instances of different types.
checkTypeMatrix(type, function(other) {
......
......@@ -26,14 +26,14 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-natives-as natives
// Flags: --expose-natives-as natives --allow-natives-syntax
// Test the SameValue and SameValueZero internal methods.
var obj1 = {x: 10, y: 11, z: "test"};
var obj2 = {x: 10, y: 11, z: "test"};
var sameValue = Object.is;
var sameValueZero = natives.ImportNow("SameValueZero");
var sameValueZero = function(x, y) { return %SameValueZero(x, y); }
// Calls SameValue and SameValueZero and checks that their results match.
function sameValueBoth(a, b) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment