[ic] Introduce BOOLEAN state for CompareIC.
authorbmeurer <bmeurer@chromium.org>
Tue, 22 Sep 2015 08:01:26 +0000 (01:01 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 22 Sep 2015 08:01:36 +0000 (08:01 +0000)
Slow path for relational comparison of boolean primitive values
now goes through the runtime, which made the slow path even
slower than it already was. So in order to repair the regression,
we just track boolean feedback for comparisons and use that
to generate decent code in Crankshaft (not the best possible
code, but good enough for Crankshaft; TurboFan will be able
to do better on that).

R=jarin@chromium.org
BUG=chromium:534200
LOG=n

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

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

12 files changed:
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/code-stubs.cc
src/code-stubs.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/code-stubs-ia32.cc
src/ic/ic-state.cc
src/ic/ic-state.h
src/mips/code-stubs-mips.cc
src/mips64/code-stubs-mips64.cc
src/x64/code-stubs-x64.cc

index ab5a89f..95548cf 100644 (file)
@@ -3360,6 +3360,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  Label miss;
+
+  __ CheckMap(r1, r2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  __ CheckMap(r0, r3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ ldr(r1, FieldMemOperand(r1, Oddball::kToNumberOffset));
+      __ AssertSmi(r1);
+      __ ldr(r0, FieldMemOperand(r0, Oddball::kToNumberOffset));
+      __ AssertSmi(r0);
+    }
+    __ sub(r0, r1, r0);
+    __ Ret();
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::SMI);
   Label miss;
index 5ba08f7..aaedcef 100644 (file)
@@ -3246,6 +3246,32 @@ void StringCharFromCodeGenerator::GenerateSlow(
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  // Inputs are in x0 (lhs) and x1 (rhs).
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  ASM_LOCATION("CompareICStub[Booleans]");
+  Label miss;
+
+  __ CheckMap(x1, x2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  __ CheckMap(x0, x3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ Ldr(x1, FieldMemOperand(x1, Oddball::kToNumberOffset));
+      __ AssertSmi(x1);
+      __ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset));
+      __ AssertSmi(x0);
+    }
+    __ Sub(x0, x1, x0);
+    __ Ret();
+  }
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   // Inputs are in x0 (lhs) and x1 (rhs).
   DCHECK(state() == CompareICState::SMI);
index 06e7a65..d9df19e 100644 (file)
@@ -351,6 +351,7 @@ InlineCacheState CompareICStub::GetICState() const {
   switch (state) {
     case CompareICState::UNINITIALIZED:
       return ::v8::internal::UNINITIALIZED;
+    case CompareICState::BOOLEAN:
     case CompareICState::SMI:
     case CompareICState::NUMBER:
     case CompareICState::INTERNALIZED_STRING:
@@ -416,6 +417,9 @@ void CompareICStub::Generate(MacroAssembler* masm) {
     case CompareICState::UNINITIALIZED:
       GenerateMiss(masm);
       break;
+    case CompareICState::BOOLEAN:
+      GenerateBooleans(masm);
+      break;
     case CompareICState::SMI:
       GenerateSmis(masm);
       break;
index 4b259b6..32423c2 100644 (file)
@@ -1697,6 +1697,7 @@ class CompareICStub : public PlatformCodeStub {
  private:
   Code::Kind GetCodeKind() const override { return Code::COMPARE_IC; }
 
+  void GenerateBooleans(MacroAssembler* masm);
   void GenerateSmis(MacroAssembler* masm);
   void GenerateNumbers(MacroAssembler* masm);
   void GenerateInternalizedStrings(MacroAssembler* masm);
index be03186..9f5bc20 100644 (file)
@@ -5946,6 +5946,11 @@ class HObjectAccess final {
                          Representation::Integer32());
   }
 
+  static HObjectAccess ForOddballToNumber(
+      Representation representation = Representation::Tagged()) {
+    return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation);
+  }
+
   static HObjectAccess ForOddballTypeOf() {
     return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
                          Representation::HeapObject());
index b24890a..eef51e5 100644 (file)
@@ -11650,6 +11650,23 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
     HStringCompareAndBranch* result =
         New<HStringCompareAndBranch>(left, right, op);
     return result;
+  } else if (combined_type->Is(Type::Boolean())) {
+    AddCheckMap(left, isolate()->factory()->boolean_map());
+    AddCheckMap(right, isolate()->factory()->boolean_map());
+    if (Token::IsEqualityOp(op)) {
+      HCompareObjectEqAndBranch* result =
+          New<HCompareObjectEqAndBranch>(left, right);
+      return result;
+    }
+    left = Add<HLoadNamedField>(
+        left, nullptr,
+        HObjectAccess::ForOddballToNumber(Representation::Smi()));
+    right = Add<HLoadNamedField>(
+        right, nullptr,
+        HObjectAccess::ForOddballToNumber(Representation::Smi()));
+    HCompareNumericAndBranch* result =
+        New<HCompareNumericAndBranch>(left, right, op);
+    return result;
   } else {
     if (combined_rep.IsTagged() || combined_rep.IsNone()) {
       HCompareGeneric* result = Add<HCompareGeneric>(
index d1efe50..71fcc8d 100644 (file)
@@ -3400,6 +3400,37 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  Label miss;
+  Label::Distance const miss_distance =
+      masm->emit_debug_code() ? Label::kFar : Label::kNear;
+
+  __ JumpIfSmi(edx, &miss, miss_distance);
+  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ JumpIfSmi(eax, &miss, miss_distance);
+  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(ecx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
+  __ JumpIfNotRoot(ebx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset));
+      __ AssertSmi(eax);
+      __ mov(edx, FieldOperand(edx, Oddball::kToNumberOffset));
+      __ AssertSmi(edx);
+      __ xchg(eax, edx);
+    }
+    __ sub(eax, edx);
+    __ Ret();
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::SMI);
   Label miss;
index 79e2f14..bc03d7d 100644 (file)
@@ -358,6 +358,8 @@ const char* CompareICState::GetStateName(State state) {
   switch (state) {
     case UNINITIALIZED:
       return "UNINITIALIZED";
+    case BOOLEAN:
+      return "BOOLEAN";
     case SMI:
       return "SMI";
     case NUMBER:
@@ -384,6 +386,8 @@ Type* CompareICState::StateToType(Zone* zone, State state, Handle<Map> map) {
   switch (state) {
     case UNINITIALIZED:
       return Type::None(zone);
+    case BOOLEAN:
+      return Type::Boolean(zone);
     case SMI:
       return Type::SignedSmall(zone);
     case NUMBER:
@@ -410,6 +414,7 @@ CompareICState::State CompareICState::NewInputState(State old_state,
                                                     Handle<Object> value) {
   switch (old_state) {
     case UNINITIALIZED:
+      if (value->IsBoolean()) return BOOLEAN;
       if (value->IsSmi()) return SMI;
       if (value->IsHeapNumber()) return NUMBER;
       if (value->IsInternalizedString()) return INTERNALIZED_STRING;
@@ -417,6 +422,9 @@ CompareICState::State CompareICState::NewInputState(State old_state,
       if (value->IsSymbol()) return UNIQUE_NAME;
       if (value->IsJSObject()) return OBJECT;
       break;
+    case BOOLEAN:
+      if (value->IsBoolean()) return BOOLEAN;
+      break;
     case SMI:
       if (value->IsSmi()) return SMI;
       if (value->IsHeapNumber()) return NUMBER;
@@ -454,6 +462,7 @@ CompareICState::State CompareICState::TargetState(
     bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) {
   switch (old_state) {
     case UNINITIALIZED:
+      if (x->IsBoolean() && y->IsBoolean()) return BOOLEAN;
       if (x->IsSmi() && y->IsSmi()) return SMI;
       if (x->IsNumber() && y->IsNumber()) return NUMBER;
       if (Token::IsOrderedRelationalCompareOp(op)) {
@@ -500,6 +509,7 @@ CompareICState::State CompareICState::TargetState(
         return Token::IsEqualityOp(op) ? OBJECT : GENERIC;
       }
       return GENERIC;
+    case BOOLEAN:
     case STRING:
     case UNIQUE_NAME:
     case OBJECT:
@@ -509,5 +519,6 @@ CompareICState::State CompareICState::TargetState(
   UNREACHABLE();
   return GENERIC;  // Make the compiler happy.
 }
+
 }  // namespace internal
 }  // namespace v8
index 0b4b9cd..b529b8c 100644 (file)
@@ -174,9 +174,11 @@ class CompareICState {
   //   ... < GENERIC
   //   SMI < NUMBER
   //   INTERNALIZED_STRING < STRING
+  //   INTERNALIZED_STRING < UNIQUE_NAME
   //   KNOWN_OBJECT < OBJECT
   enum State {
     UNINITIALIZED,
+    BOOLEAN,
     SMI,
     NUMBER,
     STRING,
index 40d77dc..b4a9d3b 100644 (file)
@@ -3518,6 +3518,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  Label miss;
+
+  __ CheckMap(a1, a2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  __ CheckMap(a0, a3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ lw(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
+      __ AssertSmi(a1);
+      __ lw(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+      __ AssertSmi(a0);
+    }
+    __ Ret(USE_DELAY_SLOT);
+    __ Subu(v0, a1, a0);
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::SMI);
   Label miss;
index 87a077f..d840665 100644 (file)
@@ -3551,6 +3551,30 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  Label miss;
+
+  __ CheckMap(a1, a2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  __ CheckMap(a0, a3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ ld(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
+      __ AssertSmi(a1);
+      __ ld(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+      __ AssertSmi(a0);
+    }
+    __ Ret(USE_DELAY_SLOT);
+    __ Dsubu(v0, a1, a0);
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::SMI);
   Label miss;
index 3383458..c24a6a0 100644 (file)
@@ -3356,6 +3356,37 @@ void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
 }
 
 
+void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
+  DCHECK_EQ(CompareICState::BOOLEAN, state());
+  Label miss;
+  Label::Distance const miss_distance =
+      masm->emit_debug_code() ? Label::kFar : Label::kNear;
+
+  __ JumpIfSmi(rdx, &miss, miss_distance);
+  __ movp(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
+  __ JumpIfSmi(rax, &miss, miss_distance);
+  __ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(rcx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
+  __ JumpIfNotRoot(rbx, Heap::kBooleanMapRootIndex, &miss, miss_distance);
+  if (op() != Token::EQ_STRICT && is_strong(strength())) {
+    __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion, 0, 1);
+  } else {
+    if (!Token::IsEqualityOp(op())) {
+      __ movp(rax, FieldOperand(rax, Oddball::kToNumberOffset));
+      __ AssertSmi(rax);
+      __ movp(rdx, FieldOperand(rdx, Oddball::kToNumberOffset));
+      __ AssertSmi(rdx);
+      __ xchgp(rax, rdx);
+    }
+    __ subp(rax, rdx);
+    __ Ret();
+  }
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+}
+
+
 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
   DCHECK(state() == CompareICState::SMI);
   Label miss;