| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 4001)
|
| +++ src/runtime.cc (working copy)
|
| @@ -3676,12 +3676,17 @@
|
| }
|
|
|
|
|
| +static double StringToNumber(String* subject) {
|
| + subject->TryFlatten();
|
| + return StringToDouble(subject, ALLOW_HEX);
|
| +}
|
| +
|
| +
|
| static Object* Runtime_StringToNumber(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 1);
|
| CONVERT_CHECKED(String, subject, args[0]);
|
| - subject->TryFlatten();
|
| - return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
|
| + return Heap::NumberFromDouble(StringToNumber(subject));
|
| }
|
|
|
|
|
| @@ -4498,12 +4503,7 @@
|
| }
|
|
|
|
|
| -static Object* Runtime_NumberEquals(Arguments args) {
|
| - NoHandleAllocation ha;
|
| - ASSERT(args.length() == 2);
|
| -
|
| - CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| - CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| +static Object* NumberEquals(double x, double y) {
|
| if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
|
| if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
|
| if (x == y) return Smi::FromInt(EQUAL);
|
| @@ -4517,13 +4517,17 @@
|
| }
|
|
|
|
|
| -static Object* Runtime_StringEquals(Arguments args) {
|
| +static Object* Runtime_NumberEquals(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 2);
|
|
|
| - CONVERT_CHECKED(String, x, args[0]);
|
| - CONVERT_CHECKED(String, y, args[1]);
|
| + CONVERT_DOUBLE_CHECKED(x, args[0]);
|
| + CONVERT_DOUBLE_CHECKED(y, args[1]);
|
| + return NumberEquals(x, y);
|
| +}
|
|
|
| +
|
| +static Object* StringEquals(String* x, String* y) {
|
| bool not_equal = !x->Equals(y);
|
| // This is slightly convoluted because the value that signifies
|
| // equality is 0 and inequality is 1 so we have to negate the result
|
| @@ -4535,6 +4539,17 @@
|
| }
|
|
|
|
|
| +static Object* Runtime_StringEquals(Arguments args) {
|
| + NoHandleAllocation ha;
|
| + ASSERT(args.length() == 2);
|
| +
|
| + CONVERT_CHECKED(String, x, args[0]);
|
| + CONVERT_CHECKED(String, y, args[1]);
|
| +
|
| + return StringEquals(x, y);
|
| +}
|
| +
|
| +
|
| static Object* Runtime_NumberCompare(Arguments args) {
|
| NoHandleAllocation ha;
|
| ASSERT(args.length() == 3);
|
| @@ -8353,7 +8368,108 @@
|
| return NULL;
|
| }
|
|
|
| +static inline Object* StrictObjectEquals(Object* x, Object* y) {
|
| + return (x == y) ? Smi::FromInt(EQUAL) : Smi::FromInt(NOT_EQUAL);
|
| +}
|
|
|
| +
|
| +// Equivalent of JS 'x == null'.
|
| +static bool EqualsToNull(Object* x) {
|
| + return x->IsNull() || x->IsUndefined() || x->IsUndetectableObject();
|
| +}
|
| +
|
| +
|
| +static double BooleanToNumber(Object* x) {
|
| + return x->IsTrue() ? 1 : 0;
|
| +}
|
| +
|
| +
|
| +static double ObjectToNumber(Object* x, bool* supported) {
|
| + if (x->IsNumber()) {
|
| + return x->Number();
|
| + } else if (x->IsString()) {
|
| + return StringToNumber(String::cast(x));
|
| + } else if (x->IsBoolean()) {
|
| + return BooleanToNumber(x);
|
| + } else if (x->IsUndefined()) {
|
| + return OS::nan_value();
|
| + } else if (EqualsToNull(x)) {
|
| + return 0;
|
| + } else {
|
| + *supported = false;
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +
|
| +static Object* Runtime_FastEquals(Arguments args) {
|
| + // Partial implementation of the compare operations.
|
| + // Returns EQUAL, NOT_EQUAL or a special case code which must be handled
|
| + // in a builting function EQUAL (comparisons implying calling custom JS
|
| + // code difficult to handle in C).
|
| +
|
| + const int EQUALS_FIRST_ARG_TO_PRIMITIVE = 2;
|
| + const int EQUALS_SECOND_ARG_TO_PRIMITIVE = 3;
|
| + const int EQUALS_SECOND_ARG_TO_DEFAULT_VALUE = 4;
|
| +
|
| + NoHandleAllocation ha;
|
| + AssertNoAllocation na();
|
| + Object* x = args[0];
|
| + Object* y = args[1];
|
| +
|
| + if (EqualsToNull(x)) {
|
| + // NOTE: This checks for null, undefined and undetactable.
|
| + // Undetactable check must be before string check.
|
| + return EqualsToNull(y) ? Smi::FromInt(EQUAL) : Smi::FromInt(NOT_EQUAL);
|
| + } else if (x->IsString()) {
|
| + if (y->IsString()) return StringEquals(String::cast(x), String::cast(y));
|
| + if (y->IsNumber()) {
|
| + double dx = StringToNumber(String::cast(x)); // Type checked above.
|
| + return NumberEquals(dx, y->Number());
|
| + }
|
| + if (y->IsBoolean()) {
|
| + double dx = StringToNumber(String::cast(x)); // Type checked above.
|
| + double dy = BooleanToNumber(y);
|
| + return NumberEquals(dx, dy);
|
| + }
|
| + if (EqualsToNull(y)) {
|
| + return Smi::FromInt(NOT_EQUAL);
|
| + }
|
| +
|
| + // Speclal case: y = %ToPrimitive(y, NO_HINT) and repeat.
|
| + return Smi::FromInt(EQUALS_SECOND_ARG_TO_PRIMITIVE);
|
| + } else if (x->IsNumber()) {
|
| + if (EqualsToNull(y)) return Smi::FromInt(NOT_EQUAL);
|
| + bool supported = true;
|
| + double dy = ObjectToNumber(y, &supported); // y is not null.
|
| + if (!supported) return Smi::FromInt(EQUALS_SECOND_ARG_TO_DEFAULT_VALUE);
|
| + return NumberEquals(x->Number(), dy);
|
| + } else if (x->IsBoolean()) {
|
| + if (y->IsBoolean()) {
|
| + return StrictObjectEquals(x, y);
|
| + }
|
| + if (EqualsToNull(y)) return Smi::FromInt(NOT_EQUAL);
|
| + double dx = BooleanToNumber(x); // Type checked above.
|
| + bool supported = true;
|
| + double dy = ObjectToNumber(y, &supported);
|
| + if (!supported) return Smi::FromInt(EQUALS_SECOND_ARG_TO_DEFAULT_VALUE);
|
| + return NumberEquals(dx, dy);
|
| + } else {
|
| + // x is not a number, boolean, null or undefined.
|
| + if (EqualsToNull(y)) return Smi::FromInt(NOT_EQUAL);
|
| + if (y->IsJSObject()) {
|
| + return StrictObjectEquals(x, y);
|
| + }
|
| + if (y->IsJSFunction()) {
|
| + return StrictObjectEquals(x, y);
|
| + }
|
| +
|
| + // Speclal case: x = %ToPrimitive(x, NO_HINT) and repeat.
|
| + return Smi::FromInt(EQUALS_FIRST_ARG_TO_PRIMITIVE);
|
| + }
|
| +}
|
| +
|
| +
|
| // ----------------------------------------------------------------------------
|
| // Implementation of Runtime
|
|
|
|
|