diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 10340b0db0..0c4675eb46 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -5961,6 +5961,44 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { } +void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { + ASSERT(state_ == CompareIC::SYMBOLS); + Label miss; + + // Registers containing left and right operands respectively. + Register left = r1; + Register right = r0; + Register tmp1 = r2; + Register tmp2 = r3; + + // Check that both operands are heap objects. + __ JumpIfEitherSmi(left, right, &miss); + + // Check that both operands are symbols. + __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); + __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); + __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); + __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); + STATIC_ASSERT(kSymbolTag != 0); + __ and_(tmp1, tmp1, Operand(tmp2)); + __ tst(tmp1, Operand(kIsSymbolMask)); + __ b(eq, &miss); + + // Symbols are compared by identity. + __ cmp(left, right); + // Make sure r0 is non-zero. At this point input operands are + // guaranteed to be non-zero. + ASSERT(right.is(r0)); + STATIC_ASSERT(EQUAL == 0); + STATIC_ASSERT(kSmiTag == 0); + __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); + __ Ret(); + + __ bind(&miss); + GenerateMiss(masm); +} + + void ICCompareStub::GenerateStrings(MacroAssembler* masm) { ASSERT(state_ == CompareIC::STRINGS); Label miss; diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 954180c97f..7f08d22dc9 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -200,6 +200,9 @@ void ICCompareStub::Generate(MacroAssembler* masm) { case CompareIC::STRINGS: GenerateStrings(masm); break; + case CompareIC::SYMBOLS: + GenerateSymbols(masm); + break; case CompareIC::OBJECTS: GenerateObjects(masm); break; diff --git a/src/code-stubs.h b/src/code-stubs.h index 4c5b2ff090..05750f535f 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -426,6 +426,7 @@ class ICCompareStub: public CodeStub { void GenerateSmis(MacroAssembler* masm); void GenerateHeapNumbers(MacroAssembler* masm); + void GenerateSymbols(MacroAssembler* masm); void GenerateStrings(MacroAssembler* masm); void GenerateObjects(MacroAssembler* masm); void GenerateMiss(MacroAssembler* masm); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 00fab7f551..3c0042da37 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -5854,6 +5854,52 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { } +void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { + ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(GetCondition() == equal); + + // Registers containing left and right operands respectively. + Register left = edx; + Register right = eax; + Register tmp1 = ecx; + Register tmp2 = ebx; + + // Check that both operands are heap objects. + NearLabel miss; + __ mov(tmp1, Operand(left)); + STATIC_ASSERT(kSmiTag == 0); + __ and_(tmp1, Operand(right)); + __ test(tmp1, Immediate(kSmiTagMask)); + __ j(zero, &miss); + + // Check that both operands are symbols. + __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); + __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); + __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); + __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); + STATIC_ASSERT(kSymbolTag != 0); + __ and_(tmp1, Operand(tmp2)); + __ test(tmp1, Immediate(kIsSymbolMask)); + __ j(zero, &miss); + + // Symbols are compared by identity. + NearLabel done; + __ cmp(left, Operand(right)); + // Make sure eax is non-zero. At this point input operands are + // guaranteed to be non-zero. + ASSERT(right.is(eax)); + __ j(not_equal, &done); + STATIC_ASSERT(EQUAL == 0); + STATIC_ASSERT(kSmiTag == 0); + __ Set(eax, Immediate(Smi::FromInt(EQUAL))); + __ bind(&done); + __ ret(0); + + __ bind(&miss); + GenerateMiss(masm); +} + + void ICCompareStub::GenerateStrings(MacroAssembler* masm) { ASSERT(state_ == CompareIC::STRINGS); ASSERT(GetCondition() == equal); diff --git a/src/ic.cc b/src/ic.cc index 980dd0846d..e2089ff155 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -2141,6 +2141,7 @@ const char* CompareIC::GetStateName(State state) { case SMIS: return "SMIS"; case HEAP_NUMBERS: return "HEAP_NUMBERS"; case OBJECTS: return "OBJECTS"; + case SYMBOLS: return "SYMBOLS"; case STRINGS: return "STRINGS"; case GENERIC: return "GENERIC"; default: @@ -2154,12 +2155,16 @@ CompareIC::State CompareIC::TargetState(State state, bool has_inlined_smi_code, Handle x, Handle y) { - if (!has_inlined_smi_code && state != UNINITIALIZED) return GENERIC; + if (!has_inlined_smi_code && state != UNINITIALIZED && state != SYMBOLS) { + return GENERIC; + } if (state == UNINITIALIZED && x->IsSmi() && y->IsSmi()) return SMIS; if ((state == UNINITIALIZED || (state == SMIS && has_inlined_smi_code)) && x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC; if (state == UNINITIALIZED && + x->IsSymbol() && y->IsSymbol()) return SYMBOLS; + if ((state == UNINITIALIZED || state == SYMBOLS) && x->IsString() && y->IsString()) return STRINGS; if (state == UNINITIALIZED && x->IsJSObject() && y->IsJSObject()) return OBJECTS; diff --git a/src/ic.h b/src/ic.h index 807b173a3e..0591674bb2 100644 --- a/src/ic.h +++ b/src/ic.h @@ -592,6 +592,7 @@ class CompareIC: public IC { UNINITIALIZED, SMIS, HEAP_NUMBERS, + SYMBOLS, STRINGS, OBJECTS, GENERIC diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 5f0a84d7d1..27e6576d29 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -4739,6 +4739,49 @@ void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { } +void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { + ASSERT(state_ == CompareIC::SYMBOLS); + ASSERT(GetCondition() == equal); + + // Registers containing left and right operands respectively. + Register left = rdx; + Register right = rax; + Register tmp1 = rcx; + Register tmp2 = rbx; + + // Check that both operands are heap objects. + NearLabel miss; + Condition cond = masm->CheckEitherSmi(left, right, tmp1); + __ j(cond, &miss); + + // Check that both operands are symbols. + __ movq(tmp1, FieldOperand(left, HeapObject::kMapOffset)); + __ movq(tmp2, FieldOperand(right, HeapObject::kMapOffset)); + __ movzxbq(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); + __ movzxbq(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); + STATIC_ASSERT(kSymbolTag != 0); + __ and_(tmp1, tmp2); + __ testb(tmp1, Immediate(kIsSymbolMask)); + __ j(zero, &miss); + + // Symbols are compared by identity. + NearLabel done; + __ cmpq(left, right); + // Make sure rax is non-zero. At this point input operands are + // guaranteed to be non-zero. + ASSERT(right.is(rax)); + __ j(not_equal, &done); + STATIC_ASSERT(EQUAL == 0); + STATIC_ASSERT(kSmiTag == 0); + __ Move(rax, Smi::FromInt(EQUAL)); + __ bind(&done); + __ ret(0); + + __ bind(&miss); + GenerateMiss(masm); +} + + void ICCompareStub::GenerateStrings(MacroAssembler* masm) { ASSERT(state_ == CompareIC::STRINGS); ASSERT(GetCondition() == equal); @@ -4764,7 +4807,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { __ movq(tmp3, tmp1); STATIC_ASSERT(kNotStringTag != 0); __ or_(tmp3, tmp2); - __ testl(tmp3, Immediate(kIsNotStringMask)); + __ testb(tmp3, Immediate(kIsNotStringMask)); __ j(not_zero, &miss); // Fast check for identical strings. @@ -4784,7 +4827,7 @@ void ICCompareStub::GenerateStrings(MacroAssembler* masm) { NearLabel do_compare; STATIC_ASSERT(kSymbolTag != 0); __ and_(tmp1, tmp2); - __ testl(tmp1, Immediate(kIsSymbolMask)); + __ testb(tmp1, Immediate(kIsSymbolMask)); __ j(zero, &do_compare); // Make sure rax is non-zero. At this point input operands are // guaranteed to be non-zero.