Index: runtime/vm/flow_graph_builder.cc |
=================================================================== |
--- runtime/vm/flow_graph_builder.cc (revision 29797) |
+++ runtime/vm/flow_graph_builder.cc (working copy) |
@@ -671,6 +671,7 @@ |
Token::kEQ_STRICT, |
value, |
constant_true); |
+ comp->set_needs_number_check(false); |
BranchInstr* branch = new BranchInstr(comp); |
AddInstruction(branch); |
CloseFragment(); |
@@ -683,10 +684,8 @@ |
void TestGraphVisitor::MergeBranchWithComparison(ComparisonInstr* comp) { |
BranchInstr* branch; |
if (Token::IsStrictEqualityOperator(comp->kind())) { |
- branch = new BranchInstr(new StrictCompareInstr(comp->token_pos(), |
- comp->kind(), |
- comp->left(), |
- comp->right())); |
+ ASSERT(comp->IsStrictCompare()); |
+ branch = new BranchInstr(comp); |
} else if (Token::IsEqualityOperator(comp->kind()) && |
(comp->left()->BindsToConstantNull() || |
comp->right()->BindsToConstantNull())) { |
@@ -708,11 +707,13 @@ |
void TestGraphVisitor::MergeBranchWithNegate(BooleanNegateInstr* neg) { |
ASSERT(!FLAG_enable_type_checks); |
Value* constant_true = Bind(new ConstantInstr(Bool::True())); |
- BranchInstr* branch = new BranchInstr( |
+ StrictCompareInstr* comp = |
new StrictCompareInstr(condition_token_pos(), |
Token::kNE_STRICT, |
neg->value(), |
- constant_true)); |
+ constant_true); |
+ comp->set_needs_number_check(false); |
+ BranchInstr* branch = new BranchInstr(comp); |
AddInstruction(branch); |
CloseFragment(); |
true_successor_addresses_.Add(branch->true_successor_address()); |
@@ -1366,6 +1367,24 @@ |
} |
+StrictCompareInstr* EffectGraphVisitor::BuildStrictCompare(AstNode* left, |
+ AstNode* right, |
+ Token::Kind kind, |
+ intptr_t token_pos) { |
+ ValueGraphVisitor for_left_value(owner(), temp_index()); |
+ left->Visit(&for_left_value); |
+ Append(for_left_value); |
+ ValueGraphVisitor for_right_value(owner(), temp_index()); |
+ right->Visit(&for_right_value); |
+ Append(for_right_value); |
+ StrictCompareInstr* comp = new StrictCompareInstr(token_pos, |
+ kind, |
+ for_left_value.value(), |
+ for_right_value.value()); |
+ return comp; |
+} |
+ |
+ |
// <Expression> :: Comparison { kind: Token::Kind |
// left: <Expression> |
// right: <Expression> } |
@@ -1379,52 +1398,62 @@ |
BuildTypeCast(node); |
return; |
} |
+ |
if ((node->kind() == Token::kEQ_STRICT) || |
(node->kind() == Token::kNE_STRICT)) { |
- ValueGraphVisitor for_left_value(owner(), temp_index()); |
- node->left()->Visit(&for_left_value); |
- Append(for_left_value); |
- ValueGraphVisitor for_right_value(owner(), temp_index()); |
- node->right()->Visit(&for_right_value); |
- Append(for_right_value); |
- StrictCompareInstr* comp = new StrictCompareInstr(node->token_pos(), |
- node->kind(), |
- for_left_value.value(), |
- for_right_value.value()); |
- ReturnDefinition(comp); |
+ ReturnDefinition(BuildStrictCompare(node->left(), node->right(), |
+ node->kind(), node->token_pos())); |
return; |
} |
if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
+ // Eagerly fold null-comparisons. |
+ LiteralNode* left_lit = node->left()->AsLiteralNode(); |
+ LiteralNode* right_lit = node->right()->AsLiteralNode(); |
+ if (((left_lit != NULL) && left_lit->literal().IsNull()) || |
+ ((right_lit != NULL) && right_lit->literal().IsNull())) { |
+ Token::Kind kind = |
+ (node->kind() == Token::kEQ) ? Token::kEQ_STRICT : Token::kNE_STRICT; |
+ StrictCompareInstr* compare = |
+ BuildStrictCompare(node->left(), node->right(), |
+ kind, node->token_pos()); |
+ ReturnDefinition(compare); |
+ return; |
+ } |
+ |
+ ZoneGrowableArray<PushArgumentInstr*>* arguments = |
+ new ZoneGrowableArray<PushArgumentInstr*>(2); |
+ |
ValueGraphVisitor for_left_value(owner(), temp_index()); |
node->left()->Visit(&for_left_value); |
Append(for_left_value); |
+ PushArgumentInstr* push_left = PushArgument(for_left_value.value()); |
+ arguments->Add(push_left); |
+ |
ValueGraphVisitor for_right_value(owner(), temp_index()); |
node->right()->Visit(&for_right_value); |
Append(for_right_value); |
+ PushArgumentInstr* push_right = PushArgument(for_right_value.value()); |
+ arguments->Add(push_right); |
+ |
+ Definition* result = |
+ new InstanceCallInstr(node->token_pos(), |
+ Symbols::EqualOperator(), |
+ Token::kEQ, // Result is negated later for kNE. |
+ arguments, |
+ Object::null_array(), |
+ 2, |
+ owner()->ic_data_array()); |
if (FLAG_enable_type_checks) { |
- EqualityCompareInstr* comp = new EqualityCompareInstr( |
- node->token_pos(), |
- Token::kEQ, |
- for_left_value.value(), |
- for_right_value.value(), |
- owner()->ic_data_array()); |
- if (node->kind() == Token::kEQ) { |
- ReturnDefinition(comp); |
- } else { |
- Value* eq_result = Bind(comp); |
- eq_result = Bind(new AssertBooleanInstr(node->token_pos(), eq_result)); |
- ReturnDefinition(new BooleanNegateInstr(eq_result)); |
- } |
- } else { |
- EqualityCompareInstr* comp = new EqualityCompareInstr( |
- node->token_pos(), |
- node->kind(), |
- for_left_value.value(), |
- for_right_value.value(), |
- owner()->ic_data_array()); |
- ReturnDefinition(comp); |
+ Value* value = Bind(result); |
+ result = new AssertBooleanInstr(node->token_pos(), value); |
} |
+ |
+ if (node->kind() == Token::kNE) { |
+ Value* value = Bind(result); |
+ result = new BooleanNegateInstr(value); |
+ } |
+ ReturnDefinition(result); |
return; |
} |
@@ -2925,6 +2954,21 @@ |
if (!function.IsClosureFunction()) { |
MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function); |
switch (kind) { |
+ case MethodRecognizer::kObjectEquals: { |
+ Value* receiver = Bind(BuildLoadThisVar(node->scope())); |
+ LocalVariable* other_var = |
+ node->scope()->LookupVariable(Symbols::Other(), |
+ true); // Test only. |
+ Value* other = Bind(new LoadLocalInstr(*other_var)); |
+ StrictCompareInstr* compare = |
+ new StrictCompareInstr(node->token_pos(), |
+ Token::kEQ_STRICT, |
+ receiver, |
+ other); |
+ // Receiver is not a number because numbers override equality. |
+ compare->set_needs_number_check(false); |
+ return ReturnDefinition(compare); |
+ } |
case MethodRecognizer::kStringBaseLength: |
case MethodRecognizer::kStringBaseIsEmpty: { |
Value* receiver = Bind(BuildLoadThisVar(node->scope())); |