Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(427)

Unified Diff: runtime/vm/flow_graph_optimizer.cc

Issue 27307005: Change == into an instance call to allow polymorphic inlining of ==. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased, addressed comments Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_optimizer.cc
===================================================================
--- runtime/vm/flow_graph_optimizer.cc (revision 29797)
+++ runtime/vm/flow_graph_optimizer.cc (working copy)
@@ -26,6 +26,9 @@
DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination.");
DEFINE_FLAG(int, max_polymorphic_checks, 4,
"Maximum number of polymorphic check, otherwise it is megamorphic.");
+DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
+ "Maximum number of polymorphic checks in equality operator,"
+ " otherwise use megamorphic dispatch.");
DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis.");
DEFINE_FLAG(bool, trace_constant_propagation, false,
"Print constant propagation and useless code elimination.");
@@ -85,9 +88,6 @@
ComparisonInstr* compare = instr->AsBranch()->comparison();
if (compare->IsStrictCompare()) {
VisitStrictCompare(compare->AsStrictCompare());
- } else if (compare->IsEqualityCompare()) {
- StrictifyEqualityCompare(compare->AsEqualityCompare(),
- instr->AsBranch());
}
}
}
@@ -1288,7 +1288,102 @@
static bool SmiFitsInDouble() { return kSmiBits < 53; }
+bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
+ const ICData& ic_data = *call->ic_data();
+ ASSERT(ic_data.num_args_tested() == 2);
+ ASSERT(call->ArgumentCount() == 2);
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+
+ intptr_t cid = kIllegalCid;
+ if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ InsertBefore(call,
+ new CheckSmiInstr(new Value(left), call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
+ InsertBefore(call,
+ new CheckSmiInstr(new Value(right), call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
+ cid = kSmiCid;
+ } else if (HasTwoMintOrSmi(ic_data) &&
+ FlowGraphCompiler::SupportsUnboxedMints()) {
+ cid = kMintCid;
+ } else if (HasTwoDoubleOrSmi(ic_data)) {
+ // Use double comparison.
+ if (SmiFitsInDouble()) {
+ cid = kDoubleCid;
+ } else {
+ if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+ // We cannot use double comparison on two smis. Need polymorphic
+ // call.
+ return false;
+ } else {
+ InsertBefore(call,
+ new CheckEitherNonSmiInstr(new Value(left),
+ new Value(right),
+ call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
+ cid = kDoubleCid;
+ }
+ }
+ } else {
+ // Check if ICDData contains checks with Smi/Null combinations. In that case
+ // we can still emit the optimized Smi equality operation but need to add
+ // checks for null or Smi.
+ GrowableArray<intptr_t> smi_or_null(2);
+ smi_or_null.Add(kSmiCid);
+ smi_or_null.Add(kNullCid);
+ if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
+ smi_or_null,
+ smi_or_null)) {
+ const ICData& unary_checks_0 =
+ ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
+ AddCheckClass(left,
+ unary_checks_0,
+ call->deopt_id(),
+ call->env(),
+ call);
+
+ const ICData& unary_checks_1 =
+ ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1));
+ AddCheckClass(right,
+ unary_checks_1,
+ call->deopt_id(),
+ call->env(),
+ call);
+ cid = kSmiCid;
+ } else {
+ // Shortcut for equality with null.
+ ConstantInstr* right_const = right->AsConstant();
+ ConstantInstr* left_const = left->AsConstant();
+ if ((right_const != NULL && right_const->value().IsNull()) ||
+ (left_const != NULL && left_const->value().IsNull())) {
+ StrictCompareInstr* comp = new StrictCompareInstr(call->token_pos(),
+ Token::kEQ_STRICT,
+ new Value(left),
+ new Value(right));
+ ReplaceCall(call, comp);
+ return true;
+ }
+ return false;
+ }
+ }
+ ASSERT(cid != kIllegalCid);
+ EqualityCompareInstr* comp = new EqualityCompareInstr(call->token_pos(),
+ op_kind,
+ new Value(left),
+ new Value(right),
+ cid,
+ call->deopt_id());
+ ReplaceCall(call, comp);
+ return true;
+}
+
+
bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
Token::Kind op_kind) {
const ICData& ic_data = *call->ic_data();
@@ -2933,6 +3028,18 @@
}
+static Definition* OriginalDefinition(Definition* defn) {
+ while (defn->IsRedefinition() || defn->IsAssertAssignable()) {
+ if (defn->IsRedefinition()) {
+ defn = defn->AsRedefinition()->value()->definition();
+ } else {
+ defn = defn->AsAssertAssignable()->value()->definition();
+ }
+ }
+ return defn;
+}
+
+
// TODO(srdjan): Use ICData to check if always true or false.
void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
@@ -2941,8 +3048,8 @@
Definition* type_args = call->ArgumentAt(2);
const AbstractType& type =
AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
- const bool negate =
- Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value();
+ const bool negate = Bool::Cast(
+ OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value();
const ICData& unary_checks =
ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
@@ -3041,7 +3148,10 @@
const ICData& unary_checks =
ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks());
- if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) &&
+ intptr_t max_checks = (op_kind == Token::kEQ)
+ ? FLAG_max_equality_polymorphic_checks
+ : FLAG_max_polymorphic_checks;
+ if ((unary_checks.NumberOfChecks() > max_checks) &&
InstanceCallNeedsClassCheck(instr)) {
// Too many checks, it will be megamorphic which needs unary checks.
instr->set_ic_data(&unary_checks);
@@ -3055,6 +3165,10 @@
return;
}
+ if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) {
+ return;
+ }
+
if (Token::IsRelationalOperator(op_kind) &&
TryReplaceWithRelationalOp(instr, op_kind)) {
return;
@@ -3280,222 +3394,6 @@
}
-bool FlowGraphOptimizer::CanStrictifyEqualityCompare(
- EqualityCompareInstr* compare) {
- // If one of the inputs is null this is a strict comparison.
- if (compare->left()->BindsToConstantNull() ||
- compare->right()->BindsToConstantNull()) {
- return true;
- }
-
- if (compare->left()->Type()->IsNone()) {
- return false; // We might be running prior to any type propagation passes.
- }
-
- // Try resolving target function using propagated cid for the receiver.
- // If receiver is either null or has default equality operator then
- // we can convert such comparison to a strict one.
- const intptr_t receiver_cid =
- compare->left()->Type()->ToNullableCid();
-
- if (receiver_cid == kDynamicCid) {
- return false;
- }
-
- const Class& receiver_class = Class::Handle(
- Isolate::Current()->class_table()->At(receiver_cid));
-
- // Resolve equality operator.
- const intptr_t kNumArgs = 2;
- ArgumentsDescriptor args_desc(
- Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
- const Function& function = Function::Handle(
- Resolver::ResolveDynamicForReceiverClass(
- receiver_class,
- Symbols::EqualOperator(),
- args_desc));
-
- if (function.IsNull()) {
- return false;
- }
-
- // Default equality operator declared on the Object class just calls
- // identical.
- return (Class::Handle(function.Owner()).id() == kInstanceCid);
-}
-
-
-template <typename T>
-bool FlowGraphOptimizer::StrictifyEqualityCompare(
- EqualityCompareInstr* compare,
- T current_instruction) const {
- if (CanStrictifyEqualityCompare(compare)) {
- Token::Kind strict_kind = (compare->kind() == Token::kEQ) ?
- Token::kEQ_STRICT : Token::kNE_STRICT;
- StrictCompareInstr* strict_comp =
- new StrictCompareInstr(compare->token_pos(),
- strict_kind,
- compare->left()->CopyWithType(),
- compare->right()->CopyWithType());
- // Numbers override equality and are therefore not part of this conversion.
- strict_comp->set_needs_number_check(false);
- current_instruction->ReplaceWith(strict_comp, current_iterator());
- return true;
- }
- return false;
-}
-
-
-// Returns true if we converted EqualityCompare to StrictCompare.
-template <typename T>
-bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData(
- EqualityCompareInstr* compare,
- const ICData& unary_ic_data,
- T current_instruction) {
- ASSERT(unary_ic_data.num_args_tested() == 1);
- if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
- // If possible classes do not override Object's equality then replace
- // with strict equality.
- Function& target = Function::Handle();
- Class& targets_class = Class::Handle();
- for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) {
- intptr_t cid = kIllegalCid;
- unary_ic_data.GetOneClassCheckAt(i, &cid, &target);
- targets_class = target.Owner();
- if (targets_class.id() != kInstanceCid) {
- // Overriden equality operator.
- return false;
- }
- }
- AddCheckClass(compare->left()->definition(),
- unary_ic_data,
- compare->deopt_id(),
- current_instruction->env(),
- current_instruction);
- ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE));
- Token::Kind strict_kind = (compare->kind() == Token::kEQ) ?
- Token::kEQ_STRICT : Token::kNE_STRICT;
- StrictCompareInstr* strict_comp =
- new StrictCompareInstr(compare->token_pos(),
- strict_kind,
- compare->left()->Copy(),
- compare->right()->Copy());
- // Numbers override equality and are therefore not part of this conversion.
- strict_comp->set_needs_number_check(false);
- current_instruction->ReplaceWith(strict_comp, current_iterator());
- return true;
- }
- return false;
-}
-
-
-template <typename T>
-void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
- T current_instruction) {
- if (StrictifyEqualityCompare(comp, current_instruction)) {
- // Based on input types, equality converted to strict-equality.
- return;
- }
-
- if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
- return;
- }
-
- const ICData& ic_data = *comp->ic_data();
- ASSERT(ic_data.num_args_tested() == 2);
- ASSERT(comp->operation_cid() == kIllegalCid);
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
- InsertBefore(current_instruction,
- new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
- current_instruction->env(),
- Definition::kEffect);
- InsertBefore(current_instruction,
- new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
- current_instruction->env(),
- Definition::kEffect);
- comp->set_operation_cid(kSmiCid);
- } else if (HasTwoMintOrSmi(ic_data) &&
- FlowGraphCompiler::SupportsUnboxedMints()) {
- comp->set_operation_cid(kMintCid);
- } else if (HasTwoDoubleOrSmi(ic_data)) {
- // Use double comparison.
- if (SmiFitsInDouble()) {
- comp->set_operation_cid(kDoubleCid);
- } else {
- if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
- // We cannot use double comparison on two smis.
- ASSERT(comp->operation_cid() == kIllegalCid);
- } else {
- InsertBefore(current_instruction,
- new CheckEitherNonSmiInstr(comp->left()->Copy(),
- comp->right()->Copy(),
- comp->deopt_id()),
- current_instruction->env(),
- Definition::kEffect);
- comp->set_operation_cid(kDoubleCid);
- }
- }
- }
-
- if (comp->operation_cid() != kIllegalCid) {
- // Done.
- return;
- }
-
- const ICData& unary_checks_0 =
- ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
- if (StrictifyEqualityCompareWithICData(
- comp, unary_checks_0, current_instruction)) {
- // Based on ICData, equality converted to strict-equality.
- return;
- }
-
- // Check if ICDData contains checks with Smi/Null combinations. In that case
- // we can still emit the optimized Smi equality operation but need to add
- // checks for null or Smi.
- // TODO(srdjan): Add it for Double and Mint.
- GrowableArray<intptr_t> smi_or_null(2);
- smi_or_null.Add(kSmiCid);
- smi_or_null.Add(kNullCid);
- if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
- smi_or_null,
- smi_or_null)) {
- AddCheckClass(comp->left()->definition(),
- unary_checks_0,
- comp->deopt_id(),
- current_instruction->env(),
- current_instruction);
-
- const ICData& unary_checks_1 =
- ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1));
- AddCheckClass(comp->right()->definition(),
- unary_checks_1,
- comp->deopt_id(),
- current_instruction->env(),
- current_instruction);
- comp->set_operation_cid(kSmiCid);
- }
-}
-
-
-
-
-void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
- HandleEqualityCompare(instr, instr);
-}
-
-
-void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) {
- ComparisonInstr* comparison = instr->comparison();
- if (comparison->IsEqualityCompare()) {
- HandleEqualityCompare(comparison->AsEqualityCompare(), instr);
- } else {
- ASSERT(comparison->IsStrictCompare());
- // Nothing to do.
- }
-}
-
-
// Range analysis for smi values.
class RangeAnalysis : public ValueObject {
public:
@@ -4601,17 +4499,6 @@
static Place* Wrap(const Place& place);
private:
- static Definition* OriginalDefinition(Definition* defn) {
- while (defn->IsRedefinition() || defn->IsAssertAssignable()) {
- if (defn->IsRedefinition()) {
- defn = defn->AsRedefinition()->value()->definition();
- } else {
- defn = defn->AsAssertAssignable()->value()->definition();
- }
- }
- return defn;
- }
-
bool SameField(Place* other) const {
return (kind_ == kField) ? (field().raw() == other->field().raw())
: (offset_in_bytes_ == other->offset_in_bytes_);
@@ -6454,10 +6341,8 @@
const Object& right = instr->right()->definition()->constant_value();
if (instr->left()->definition() == instr->right()->definition()) {
- // Fold x == x, and x != x to true/false for numbers and checked strict
- // comparisons.
- if (instr->IsCheckedStrictEqual() ||
- RawObject::IsIntegerClassId(instr->operation_cid())) {
+ // Fold x == x, and x != x to true/false for numbers comparisons.
+ if (RawObject::IsIntegerClassId(instr->operation_cid())) {
return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ));
}
}
@@ -7428,9 +7313,8 @@
comparison->kind(),
left,
right,
- Object::null_array());
- new_equality_compare->set_ic_data(equality_compare->ic_data());
- new_equality_compare->set_operation_cid(equality_compare->operation_cid());
+ equality_compare->operation_cid(),
+ equality_compare->deopt_id());
new_comparison = new_equality_compare;
} else {
ASSERT(comparison->IsRelationalOp());
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698