diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 2f730386d4..af01c296b1 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1120,6 +1120,10 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), UseRegisterAtStart(compare->right())); + } else if (v->IsCompareSymbolEq()) { + HCompareSymbolEq* compare = HCompareSymbolEq::cast(v); + return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()), + UseRegisterAtStart(compare->right())); } else if (v->IsInstanceOf()) { HInstanceOf* instance_of = HInstanceOf::cast(v); LInstruction* result = @@ -1520,6 +1524,15 @@ LInstruction* LChunkBuilder::DoCompareJSObjectEq( } +LInstruction* LChunkBuilder::DoCompareSymbolEq( + HCompareSymbolEq* instr) { + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseRegisterAtStart(instr->right()); + LCmpSymbolEq* result = new LCmpSymbolEq(left, right); + return DefineAsRegister(result); +} + + LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 6d19c6d151..f98c68f219 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -80,6 +80,8 @@ class LCodeGen; V(CmpJSObjectEq) \ V(CmpJSObjectEqAndBranch) \ V(CmpMapAndBranch) \ + V(CmpSymbolEq) \ + V(CmpSymbolEqAndBranch) \ V(CmpT) \ V(CmpTAndBranch) \ V(ConstantD) \ @@ -683,6 +685,28 @@ class LCmpJSObjectEqAndBranch: public LControlInstruction<2, 0> { }; +class LCmpSymbolEq: public LTemplateInstruction<1, 2, 0> { + public: + LCmpSymbolEq(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEq, "cmp-symbol-eq") +}; + + +class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> { + public: + LCmpSymbolEqAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEqAndBranch, "cmp-symbol-eq-and-branch") +}; + + class LIsNull: public LTemplateInstruction<1, 1, 0> { public: explicit LIsNull(LOperand* value) { diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 5830fa6f55..33733fb463 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1620,6 +1620,28 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { } +void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + Register result = ToRegister(instr->result()); + + __ cmp(left, Operand(right)); + __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); + __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); +} + + +void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + int true_block = chunk_->LookupDestination(instr->true_block_id()); + + __ cmp(left, Operand(right)); + EmitBranch(true_block, false_block, eq); +} + + void LCodeGen::DoIsNull(LIsNull* instr) { Register reg = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 02830f07ff..cca4150e10 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -91,6 +91,7 @@ class LChunkBuilder; V(Compare) \ V(CompareJSObjectEq) \ V(CompareMap) \ + V(CompareSymbolEq) \ V(Constant) \ V(Context) \ V(DeleteProperty) \ @@ -2410,6 +2411,40 @@ class HCompareJSObjectEq: public HBinaryOperation { }; +class HCompareSymbolEq: public HBinaryOperation { + public: + HCompareSymbolEq(HValue* left, HValue* right, Token::Value op) + : HBinaryOperation(left, right), op_(op) { + ASSERT(op == Token::EQ || op == Token::EQ_STRICT); + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetFlag(kDependsOnMaps); + } + + Token::Value op() const { return op_; } + + virtual bool EmitAtUses() { + return !HasSideEffects() && !HasMultipleUses(); + } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + virtual HType CalculateInferredType() { return HType::Boolean(); } + + DECLARE_CONCRETE_INSTRUCTION(CompareSymbolEq); + + protected: + virtual bool DataEquals(HValue* other) { + return op_ == HCompareSymbolEq::cast(other)->op_; + } + + private: + const Token::Value op_; +}; + + class HUnaryPredicate: public HUnaryOperation { public: explicit HUnaryPredicate(HValue* value) : HUnaryOperation(value) { diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 12629ae6fe..ddba47f9a5 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4834,6 +4834,18 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { } +HCompareSymbolEq* HGraphBuilder::BuildSymbolCompare(HValue* left, + HValue* right, + Token::Value op) { + ASSERT(op == Token::EQ || op == Token::EQ_STRICT); + AddInstruction(new(zone()) HCheckNonSmi(left)); + AddInstruction(HCheckInstanceType::NewIsSymbol(left)); + AddInstruction(new(zone()) HCheckNonSmi(right)); + AddInstruction(HCheckInstanceType::NewIsSymbol(right)); + return new(zone()) HCompareSymbolEq(left, right, op); +} + + HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, HValue* index) { AddInstruction(new(zone()) HCheckNonSmi(string)); @@ -5153,6 +5165,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { return Bailout("Unsupported non-primitive compare"); break; } + } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) && + (op == Token::EQ || op == Token::EQ_STRICT)) { + instr = BuildSymbolCompare(left, right, op); } else { HCompare* compare = new(zone()) HCompare(left, right, op); Representation r = ToRepresentation(type_info); diff --git a/src/hydrogen.h b/src/hydrogen.h index e3ab2eb2d0..62752e5a42 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -871,6 +871,9 @@ class HGraphBuilder: public AstVisitor { ZoneMapList* types, Handle name); + HCompareSymbolEq* BuildSymbolCompare(HValue* left, + HValue* right, + Token::Value op); HStringCharCodeAt* BuildStringCharCodeAt(HValue* string, HValue* index); HInstruction* BuildBinaryOperation(BinaryOperation* expr, diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 1c802b404d..21c1f8b15a 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1543,6 +1543,31 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { } +void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + Register result = ToRegister(instr->result()); + + Label done; + __ cmp(left, Operand(right)); + __ mov(result, factory()->false_value()); + __ j(not_equal, &done, Label::kNear); + __ mov(result, factory()->true_value()); + __ bind(&done); +} + + +void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + int true_block = chunk_->LookupDestination(instr->true_block_id()); + + __ cmp(left, Operand(right)); + EmitBranch(true_block, false_block, equal); +} + + void LCodeGen::DoIsNull(LIsNull* instr) { Register reg = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index ac0d8d840a..4acbf72017 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1126,6 +1126,10 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), UseRegisterAtStart(compare->right())); + } else if (v->IsCompareSymbolEq()) { + HCompareSymbolEq* compare = HCompareSymbolEq::cast(v); + return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()), + UseRegisterAtStart(compare->right())); } else if (v->IsInstanceOf()) { HInstanceOf* instance_of = HInstanceOf::cast(v); LOperand* left = UseFixed(instance_of->left(), InstanceofStub::left()); @@ -1553,6 +1557,15 @@ LInstruction* LChunkBuilder::DoCompareJSObjectEq( } +LInstruction* LChunkBuilder::DoCompareSymbolEq( + HCompareSymbolEq* instr) { + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseRegisterAtStart(instr->right()); + LCmpSymbolEq* result = new LCmpSymbolEq(left, right); + return DefineAsRegister(result); +} + + LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 4ee91434c7..1ed3eaabd7 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -73,6 +73,8 @@ class LCodeGen; V(CmpIDAndBranch) \ V(CmpJSObjectEq) \ V(CmpJSObjectEqAndBranch) \ + V(CmpSymbolEq) \ + V(CmpSymbolEqAndBranch) \ V(CmpMapAndBranch) \ V(CmpT) \ V(CmpTAndBranch) \ @@ -668,6 +670,28 @@ class LCmpJSObjectEqAndBranch: public LControlInstruction<2, 0> { }; +class LCmpSymbolEq: public LTemplateInstruction<1, 2, 0> { + public: + LCmpSymbolEq(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEq, "cmp-symbol-eq") +}; + + +class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> { + public: + LCmpSymbolEqAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEqAndBranch, "cmp-symbol-eq-and-branch") +}; + + class LIsNull: public LTemplateInstruction<1, 1, 0> { public: explicit LIsNull(LOperand* value) { diff --git a/src/type-info.cc b/src/type-info.cc index 29e3fbd796..975a36c7b4 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -229,6 +229,9 @@ TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) { return TypeInfo::Smi(); case CompareIC::HEAP_NUMBERS: return TypeInfo::Number(); + case CompareIC::SYMBOLS: + case CompareIC::STRINGS: + return TypeInfo::String(); case CompareIC::OBJECTS: // TODO(kasperl): We really need a type for JS objects here. return TypeInfo::NonPrimitive(); @@ -239,6 +242,16 @@ TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) { } +bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) { + Handle object = GetInfo(expr->id()); + if (!object->IsCode()) return false; + Handle code = Handle::cast(object); + if (!code->is_compare_ic_stub()) return false; + CompareIC::State state = static_cast(code->compare_state()); + return state == CompareIC::SYMBOLS; +} + + TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) { Handle object = GetInfo(expr->id()); TypeInfo unknown = TypeInfo::Unknown(); diff --git a/src/type-info.h b/src/type-info.h index 5bfd4cd09e..53d30703d6 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -264,6 +264,7 @@ class TypeFeedbackOracle BASE_EMBEDDED { TypeInfo UnaryType(UnaryOperation* expr); TypeInfo BinaryType(BinaryOperation* expr); TypeInfo CompareType(CompareOperation* expr); + bool IsSymbolCompare(CompareOperation* expr); TypeInfo SwitchType(CaseClause* clause); TypeInfo IncrementType(CountOperation* expr); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index aaece75bfe..64a6a1d3a0 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -1552,6 +1552,31 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { } +void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + Register result = ToRegister(instr->result()); + + Label done; + __ cmpq(left, right); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ j(not_equal, &done, Label::kNear); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ bind(&done); +} + + +void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) { + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + int true_block = chunk_->LookupDestination(instr->true_block_id()); + + __ cmpq(left, right); + EmitBranch(true_block, false_block, equal); +} + + void LCodeGen::DoIsNull(LIsNull* instr) { Register reg = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 3f4291fd17..f5f2879afd 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1120,6 +1120,10 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), UseRegisterAtStart(compare->right())); + } else if (v->IsCompareSymbolEq()) { + HCompareSymbolEq* compare = HCompareSymbolEq::cast(v); + return new LCmpSymbolEqAndBranch(UseRegisterAtStart(compare->left()), + UseRegisterAtStart(compare->right())); } else if (v->IsInstanceOf()) { HInstanceOf* instance_of = HInstanceOf::cast(v); LInstanceOfAndBranch* result = @@ -1527,6 +1531,15 @@ LInstruction* LChunkBuilder::DoCompareJSObjectEq( } +LInstruction* LChunkBuilder::DoCompareSymbolEq( + HCompareSymbolEq* instr) { + LOperand* left = UseRegisterAtStart(instr->left()); + LOperand* right = UseRegisterAtStart(instr->right()); + LCmpSymbolEq* result = new LCmpSymbolEq(left, right); + return DefineAsRegister(result); +} + + LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 7ca7d6f859..4aa235f137 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -80,6 +80,8 @@ class LCodeGen; V(CmpJSObjectEq) \ V(CmpJSObjectEqAndBranch) \ V(CmpMapAndBranch) \ + V(CmpSymbolEq) \ + V(CmpSymbolEqAndBranch) \ V(CmpT) \ V(CmpTAndBranch) \ V(ConstantD) \ @@ -666,6 +668,28 @@ class LCmpJSObjectEqAndBranch: public LControlInstruction<2, 0> { }; +class LCmpSymbolEq: public LTemplateInstruction<1, 2, 0> { + public: + LCmpSymbolEq(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEq, "cmp-symbol-eq") +}; + + +class LCmpSymbolEqAndBranch: public LControlInstruction<2, 0> { + public: + LCmpSymbolEqAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpSymbolEqAndBranch, "cmp-symbol-eq-and-branch") +}; + + class LIsNull: public LTemplateInstruction<1, 1, 0> { public: explicit LIsNull(LOperand* value) {