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 =
}
+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());
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
V(CmpMapAndBranch) \
+ V(CmpSymbolEq) \
+ V(CmpSymbolEqAndBranch) \
V(CmpT) \
V(CmpTAndBranch) \
V(ConstantD) \
};
+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) {
}
+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());
V(Compare) \
V(CompareJSObjectEq) \
V(CompareMap) \
+ V(CompareSymbolEq) \
V(Constant) \
V(Context) \
V(DeleteProperty) \
};
+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) {
}
+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));
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);
ZoneMapList* types,
Handle<String> name);
+ HCompareSymbolEq* BuildSymbolCompare(HValue* left,
+ HValue* right,
+ Token::Value op);
HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
HValue* index);
HInstruction* BuildBinaryOperation(BinaryOperation* expr,
}
+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());
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());
}
+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());
V(CmpIDAndBranch) \
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
+ V(CmpSymbolEq) \
+ V(CmpSymbolEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
V(CmpTAndBranch) \
};
+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) {
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();
}
+bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) {
+ Handle<Object> object = GetInfo(expr->id());
+ if (!object->IsCode()) return false;
+ Handle<Code> code = Handle<Code>::cast(object);
+ if (!code->is_compare_ic_stub()) return false;
+ CompareIC::State state = static_cast<CompareIC::State>(code->compare_state());
+ return state == CompareIC::SYMBOLS;
+}
+
+
TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) {
Handle<Object> object = GetInfo(expr->id());
TypeInfo unknown = TypeInfo::Unknown();
TypeInfo UnaryType(UnaryOperation* expr);
TypeInfo BinaryType(BinaryOperation* expr);
TypeInfo CompareType(CompareOperation* expr);
+ bool IsSymbolCompare(CompareOperation* expr);
TypeInfo SwitchType(CaseClause* clause);
TypeInfo IncrementType(CountOperation* expr);
}
+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());
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 =
}
+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());
V(CmpJSObjectEq) \
V(CmpJSObjectEqAndBranch) \
V(CmpMapAndBranch) \
+ V(CmpSymbolEq) \
+ V(CmpSymbolEqAndBranch) \
V(CmpT) \
V(CmpTAndBranch) \
V(ConstantD) \
};
+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) {