[runtime] Unify and fix the strict equality comparison.
authorbmeurer <bmeurer@chromium.org>
Mon, 17 Aug 2015 08:01:55 +0000 (01:01 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 17 Aug 2015 08:02:08 +0000 (08:02 +0000)
Add Object::StrictEquals to unify the implementation of strict equality
comparison in the runtime and the api (the api was already missing a
case for SIMD).  Now we (almost) have a single bottleneck for strict
equality, we just need to reduce the amount of unnecessary complexity
for the code stub.

R=yangguo@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30186}

17 files changed:
src/api.cc
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/builtins.h
src/ia32/code-stubs-ia32.cc
src/mips/code-stubs-mips.cc
src/mips64/code-stubs-mips64.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/ppc/code-stubs-ppc.cc
src/runtime.js
src/runtime/runtime-object.cc
src/runtime/runtime-simd.cc
src/runtime/runtime.h
src/x64/code-stubs-x64.cc
src/x87/code-stubs-x87.cc

index 8fa2e2c..46cac75 100644 (file)
@@ -3405,33 +3405,9 @@ bool Value::Equals(Local<Value> that) const {
 
 
 bool Value::StrictEquals(Local<Value> that) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> other = Utils::OpenHandle(*that);
-  if (obj->IsSmi()) {
-    return other->IsNumber() && obj->Number() == other->Number();
-  }
-  i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate();
-  LOG_API(isolate, "StrictEquals");
-  // Must check HeapNumber first, since NaN !== NaN.
-  if (obj->IsHeapNumber()) {
-    if (!other->IsNumber()) return false;
-    double x = obj->Number();
-    double y = other->Number();
-    // Must check explicitly for NaN:s on Windows, but -0 works fine.
-    return x == y && !std::isnan(x) && !std::isnan(y);
-  } else if (*obj == *other) {  // Also covers Booleans.
-    return true;
-  } else if (obj->IsSmi()) {
-    return other->IsNumber() && obj->Number() == other->Number();
-  } else if (obj->IsString()) {
-    return other->IsString() &&
-        i::String::Equals(i::Handle<i::String>::cast(obj),
-                          i::Handle<i::String>::cast(other));
-  } else if (obj->IsUndefined() || obj->IsUndetectableObject()) {
-    return other->IsUndefined() || other->IsUndetectableObject();
-  } else {
-    return false;
-  }
+  auto self = Utils::OpenHandle(this);
+  auto other = Utils::OpenHandle(*that);
+  return self->StrictEquals(*other);
 }
 
 
index 5bd6c08..ffc821b 100644 (file)
@@ -681,26 +681,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
 
   __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript native;
-  if (cc == eq) {
-    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == eq && strict()) {
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    native =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    int ncr;  // NaN compare result
-    if (cc == lt || cc == le) {
-      ncr = GREATER;
+    Builtins::JavaScript native;
+    if (cc == eq) {
+      native = Builtins::EQUALS;
     } else {
-      DCHECK(cc == gt || cc == ge);  // remaining cases
-      ncr = LESS;
+      native =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      int ncr;  // NaN compare result
+      if (cc == lt || cc == le) {
+        ncr = GREATER;
+      } else {
+        DCHECK(cc == gt || cc == ge);  // remaining cases
+        ncr = LESS;
+      }
+      __ mov(r0, Operand(Smi::FromInt(ncr)));
+      __ push(r0);
     }
-    __ mov(r0, Operand(Smi::FromInt(ncr)));
-    __ push(r0);
-  }
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(native, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(native, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index 74ed8a2..48a6e5c 100644 (file)
@@ -652,26 +652,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
 
   __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript native;
-  if (cond == eq) {
-    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cond == eq && strict()) {
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    native =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    int ncr;  // NaN compare result
-    if ((cond == lt) || (cond == le)) {
-      ncr = GREATER;
+    Builtins::JavaScript native;
+    if (cond == eq) {
+      native = Builtins::EQUALS;
     } else {
-      DCHECK((cond == gt) || (cond == ge));  // remaining cases
-      ncr = LESS;
+      native =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      int ncr;  // NaN compare result
+      if ((cond == lt) || (cond == le)) {
+        ncr = GREATER;
+      } else {
+        DCHECK((cond == gt) || (cond == ge));  // remaining cases
+        ncr = LESS;
+      }
+      __ Mov(x10, Smi::FromInt(ncr));
+      __ Push(x10);
     }
-    __ Mov(x10, Smi::FromInt(ncr));
-    __ Push(x10);
-  }
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(native, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(native, JUMP_FUNCTION);
+  }
 
   __ Bind(&miss);
   GenerateMiss(masm);
index 6ec618a..cf90aac 100644 (file)
@@ -150,7 +150,6 @@ enum BuiltinExtraArguments {
 // Define list of builtins implemented in JavaScript.
 #define BUILTINS_LIST_JS(V)                \
   V(EQUALS, 1)                             \
-  V(STRICT_EQUALS, 1)                      \
   V(COMPARE, 2)                            \
   V(COMPARE_STRONG, 2)                     \
   V(ADD, 1)                                \
index 6480e74..dc8c517 100644 (file)
@@ -1894,21 +1894,26 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
   __ push(eax);
 
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript builtin;
-  if (cc == equal) {
-    builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == equal && strict()) {
+    __ push(ecx);
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    builtin =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
-  }
+    Builtins::JavaScript builtin;
+    if (cc == equal) {
+      builtin = Builtins::EQUALS;
+    } else {
+      builtin =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
+    }
 
-  // Restore return address on the stack.
-  __ push(ecx);
+    // Restore return address on the stack.
+    __ push(ecx);
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index 069611b..2fa0849 100644 (file)
@@ -728,26 +728,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
   // a1 (rhs) second.
   __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript native;
-  if (cc == eq) {
-    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == eq && strict()) {
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    native =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    int ncr;  // NaN compare result.
-    if (cc == lt || cc == le) {
-      ncr = GREATER;
+    Builtins::JavaScript native;
+    if (cc == eq) {
+      native = Builtins::EQUALS;
     } else {
-      DCHECK(cc == gt || cc == ge);  // Remaining cases.
-      ncr = LESS;
+      native =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      int ncr;  // NaN compare result.
+      if (cc == lt || cc == le) {
+        ncr = GREATER;
+      } else {
+        DCHECK(cc == gt || cc == ge);  // Remaining cases.
+        ncr = LESS;
+      }
+      __ li(a0, Operand(Smi::FromInt(ncr)));
+      __ push(a0);
     }
-    __ li(a0, Operand(Smi::FromInt(ncr)));
-    __ push(a0);
-  }
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(native, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(native, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index f62b354..9a2802e 100644 (file)
@@ -723,26 +723,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
   // a1 (rhs) second.
   __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript native;
-  if (cc == eq) {
-    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == eq && strict()) {
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    native =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    int ncr;  // NaN compare result.
-    if (cc == lt || cc == le) {
-      ncr = GREATER;
+    Builtins::JavaScript native;
+    if (cc == eq) {
+      native = Builtins::EQUALS;
     } else {
-      DCHECK(cc == gt || cc == ge);  // Remaining cases.
-      ncr = LESS;
+      native =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      int ncr;  // NaN compare result.
+      if (cc == lt || cc == le) {
+        ncr = GREATER;
+      } else {
+        DCHECK(cc == gt || cc == ge);  // Remaining cases.
+        ncr = LESS;
+      }
+      __ li(a0, Operand(Smi::FromInt(ncr)));
+      __ push(a0);
     }
-    __ li(a0, Operand(Smi::FromInt(ncr)));
-    __ push(a0);
-  }
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(native, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(native, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index 1cb246b..2afd802 100644 (file)
@@ -1521,6 +1521,29 @@ int HeapNumber::get_sign() {
 }
 
 
+bool Simd128Value::Equals(Simd128Value* that) {
+#define SIMD128_VALUE(TYPE, Type, type, lane_count, lane_type) \
+  if (this->Is##Type()) {                                      \
+    if (!that->Is##Type()) return false;                       \
+    return Type::cast(this)->Equals(Type::cast(that));         \
+  }
+  SIMD128_TYPES(SIMD128_VALUE)
+#undef SIMD128_VALUE
+  return false;
+}
+
+
+#define SIMD128_VALUE_EQUALS(TYPE, Type, type, lane_count, lane_type) \
+  bool Type::Equals(Type* that) {                                     \
+    for (int lane = 0; lane < lane_count; ++lane) {                   \
+      if (this->get_lane(lane) != that->get_lane(lane)) return false; \
+    }                                                                 \
+    return true;                                                      \
+  }
+SIMD128_TYPES(SIMD128_VALUE_EQUALS)
+#undef SIMD128_VALUE_EQUALS
+
+
 float Float32x4::get_lane(int lane) const {
   DCHECK(lane < 4 && lane >= 0);
 #if defined(V8_TARGET_LITTLE_ENDIAN)
index 2cfc82d..1f25a5d 100644 (file)
@@ -102,6 +102,24 @@ bool Object::BooleanValue() {
 }
 
 
+bool Object::StrictEquals(Object* that) {
+  if (this->IsNumber()) {
+    if (!that->IsNumber()) return false;
+    double const x = this->Number();
+    double const y = that->Number();
+    // Must check explicitly for NaN:s on Windows, but -0 works fine.
+    return x == y && !std::isnan(x) && !std::isnan(y);
+  } else if (this->IsString()) {
+    if (!that->IsString()) return false;
+    return String::cast(this)->Equals(String::cast(that));
+  } else if (this->IsSimd128Value()) {
+    if (!that->IsSimd128Value()) return false;
+    return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
+  }
+  return this == that;
+}
+
+
 bool Object::IsCallable() const {
   const Object* fun = this;
   while (fun->IsJSFunctionProxy()) {
index c298cc8..a19ac5d 100644 (file)
@@ -1088,6 +1088,9 @@ class Object {
 
   bool BooleanValue();                                      // ECMA-262 9.2.
 
+  // ES6 section 7.2.13 Strict Equality Comparison
+  bool StrictEquals(Object* that);
+
   // Convert to a JSObject if needed.
   // native_context is used when creating wrapper object.
   static inline MaybeHandle<JSReceiver> ToObject(Isolate* isolate,
@@ -1593,6 +1596,9 @@ class Simd128Value : public HeapObject {
   DECLARE_PRINTER(Simd128Value)
   DECLARE_VERIFIER(Simd128Value)
 
+  // Equality operations.
+  inline bool Equals(Simd128Value* that);
+
   // Checks that another instance is bit-wise equal.
   bool BitwiseEquals(const Simd128Value* other) const;
   // Computes a hash from the 128 bit value, viewed as 4 32-bit integers.
@@ -1629,6 +1635,8 @@ class Simd128Value : public HeapObject {
                                                                      \
     DECLARE_PRINTER(Type)                                            \
                                                                      \
+    inline bool Equals(Type* that);                                  \
+                                                                     \
    private:                                                          \
     DISALLOW_IMPLICIT_CONSTRUCTORS(Type);                            \
   };
index b136b7d..303c857 100644 (file)
@@ -716,26 +716,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
 
   __ Push(lhs, rhs);
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript native;
-  if (cc == eq) {
-    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == eq && strict()) {
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    native =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    int ncr;  // NaN compare result
-    if (cc == lt || cc == le) {
-      ncr = GREATER;
+    Builtins::JavaScript native;
+    if (cc == eq) {
+      native = Builtins::EQUALS;
     } else {
-      DCHECK(cc == gt || cc == ge);  // remaining cases
-      ncr = LESS;
+      native =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      int ncr;  // NaN compare result
+      if (cc == lt || cc == le) {
+        ncr = GREATER;
+      } else {
+        DCHECK(cc == gt || cc == ge);  // remaining cases
+        ncr = LESS;
+      }
+      __ LoadSmiLiteral(r3, Smi::FromInt(ncr));
+      __ push(r3);
     }
-    __ LoadSmiLiteral(r3, Smi::FromInt(ncr));
-    __ push(r3);
-  }
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(native, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(native, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index 5683f84..4de9c29 100644 (file)
@@ -127,6 +127,7 @@ EQUALS = function EQUALS(y) {
     } else if (IS_NULL_OR_UNDEFINED(x)) {
       return IS_NULL_OR_UNDEFINED(y) ? 0 : 1;
     } else if (IS_SIMD_VALUE(x)) {
+      if (!IS_SIMD_VALUE(y)) return 1;  // not equal
        return %SimdEquals(x, y);
     } else {
       // x is an object.
@@ -142,26 +143,6 @@ EQUALS = function EQUALS(y) {
   }
 }
 
-// ECMA-262, section 11.9.4, page 56.
-STRICT_EQUALS = function STRICT_EQUALS(x) {
-  if (IS_STRING(this)) {
-    if (!IS_STRING(x)) return 1;  // not equal
-    return %StringEquals(this, x);
-  }
-
-  if (IS_NUMBER(this)) {
-    if (!IS_NUMBER(x)) return 1;  // not equal
-    return %NumberEquals(this, x);
-  }
-
-  if (IS_SIMD_VALUE(this)) return %SimdEquals(this, x);
-
-  // If anything else gets here, we just do simple identity check.
-  // Objects (including functions), null, undefined and booleans were
-  // checked in the CompareStub, so there should be nothing left.
-  return %_ObjectEquals(this, x) ? 0 : 1;
-}
-
 
 // ECMA-262, section 11.8.5, page 53. The 'ncr' parameter is used as
 // the result when either (or both) the operands are NaN.
index f0c83e0..6247087 100644 (file)
@@ -1461,5 +1461,15 @@ RUNTIME_FUNCTION(Runtime_ToObject) {
       isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
 }
 
+
+RUNTIME_FUNCTION(Runtime_StrictEquals) {
+  SealHandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  CONVERT_ARG_CHECKED(Object, x, 0);
+  CONVERT_ARG_CHECKED(Object, y, 1);
+  // TODO(bmeurer): Change this at some point to return true/false instead.
+  return Smi::FromInt(x->StrictEquals(y) ? EQUAL : NOT_EQUAL);
+}
+
 }  // namespace internal
 }  // namespace v8
index bcf3567..ad337ea 100644 (file)
@@ -48,14 +48,6 @@ int8_t ConvertNumber<int8_t>(double number) {
 }
 
 
-bool Equals(Float32x4* a, Float32x4* b) {
-  for (int i = 0; i < 4; i++) {
-    if (a->get_lane(i) != b->get_lane(i)) return false;
-  }
-  return true;
-}
-
-
 // TODO(bbudge): Make this consistent with SIMD instruction results.
 inline float RecipApprox(float a) { return 1.0f / a; }
 
@@ -148,22 +140,11 @@ RUNTIME_FUNCTION(Runtime_SimdToObject) {
 
 
 RUNTIME_FUNCTION(Runtime_SimdEquals) {
-  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 = Equals(Float32x4::cast(*a), Float32x4::cast(b));
-      } else {
-        result = a->BitwiseEquals(b);
-      }
-    }
-  }
-  return Smi::FromInt(result ? EQUAL : NOT_EQUAL);
+  SealHandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  CONVERT_ARG_CHECKED(Simd128Value, x, 0);
+  CONVERT_ARG_CHECKED(Simd128Value, y, 1);
+  return Smi::FromInt(x->Equals(y) ? EQUAL : NOT_EQUAL);
 }
 
 
index 9ff0ada..e145b2d 100644 (file)
@@ -492,7 +492,8 @@ namespace internal {
   F(ClassOf, 1, 1)                                   \
   F(DefineGetterPropertyUnchecked, 4, 1)             \
   F(DefineSetterPropertyUnchecked, 4, 1)             \
-  F(ToObject, 1, 1)
+  F(ToObject, 1, 1)                                  \
+  F(StrictEquals, 2, 1)
 
 
 #define FOR_EACH_INTRINSIC_OBSERVE(F)            \
index 29de1bd..5d99915 100644 (file)
@@ -1763,20 +1763,25 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
   __ Push(rax);
 
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript builtin;
-  if (cc == equal) {
-    builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == equal && strict()) {
+    __ PushReturnAddressFrom(rcx);
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    builtin =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
-  }
+    Builtins::JavaScript builtin;
+    if (cc == equal) {
+      builtin = Builtins::EQUALS;
+    } else {
+      builtin =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      __ Push(Smi::FromInt(NegativeComparisonResult(cc)));
+    }
 
-  __ PushReturnAddressFrom(rcx);
+    __ PushReturnAddressFrom(rcx);
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);
index c7a6d23..cf2f0b3 100644 (file)
@@ -1605,21 +1605,26 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
   __ push(eax);
 
   // Figure out which native to call and setup the arguments.
-  Builtins::JavaScript builtin;
-  if (cc == equal) {
-    builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  if (cc == equal && strict()) {
+    __ push(ecx);
+    __ TailCallRuntime(Runtime::kStrictEquals, 2, 1);
   } else {
-    builtin =
-        is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
-    __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
-  }
+    Builtins::JavaScript builtin;
+    if (cc == equal) {
+      builtin = Builtins::EQUALS;
+    } else {
+      builtin =
+          is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
+      __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
+    }
 
-  // Restore return address on the stack.
-  __ push(ecx);
+    // Restore return address on the stack.
+    __ push(ecx);
 
-  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
-  // tagged as a small integer.
-  __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+    // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+    // tagged as a small integer.
+    __ InvokeBuiltin(builtin, JUMP_FUNCTION);
+  }
 
   __ bind(&miss);
   GenerateMiss(masm);