| Index: runtime/vm/flow_graph_optimizer.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_optimizer.cc (revision 39414)
|
| +++ runtime/vm/flow_graph_optimizer.cc (working copy)
|
| @@ -112,7 +112,7 @@
|
| // Attempt to build ICData for call using propagated class-ids.
|
| bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| - if (call->ic_data()->NumberOfChecks() > 0) {
|
| + if (call->ic_data()->NumberOfUsedChecks() > 0) {
|
| // This occurs when an instance call has too many checks, will be converted
|
| // to megamorphic call.
|
| return false;
|
| @@ -195,8 +195,7 @@
|
| intptr_t cid) {
|
| ASSERT(ic_data.NumArgsTested() == 1);
|
|
|
| - if ((ic_data.NumberOfChecks() == 1) &&
|
| - (ic_data.GetReceiverClassIdAt(0) == cid)) {
|
| + if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
|
| return ic_data; // Nothing to do
|
| }
|
|
|
| @@ -853,17 +852,21 @@
|
| intptr_t argument_class_id) {
|
| ASSERT(receiver_class_id != kIllegalCid);
|
| ASSERT(argument_class_id != kIllegalCid);
|
| - if (ic_data.NumArgsTested() != 2) return false;
|
| + if (ic_data.NumArgsTested() != 2) {
|
| + return false;
|
| + }
|
|
|
| Function& target = Function::Handle();
|
| const intptr_t len = ic_data.NumberOfChecks();
|
| for (intptr_t i = 0; i < len; i++) {
|
| GrowableArray<intptr_t> class_ids;
|
| - ic_data.GetCheckAt(i, &class_ids, &target);
|
| - ASSERT(class_ids.length() == 2);
|
| - if ((class_ids[0] == receiver_class_id) &&
|
| - (class_ids[1] == argument_class_id)) {
|
| - return true;
|
| + if (ic_data.IsUsedAt(i)) {
|
| + ic_data.GetCheckAt(i, &class_ids, &target);
|
| + ASSERT(class_ids.length() == 2);
|
| + if ((class_ids[0] == receiver_class_id) &&
|
| + (class_ids[1] == argument_class_id)) {
|
| + return true;
|
| + }
|
| }
|
| }
|
| return false;
|
| @@ -887,16 +890,20 @@
|
| const ICData& ic_data,
|
| const GrowableArray<intptr_t>& receiver_class_ids,
|
| const GrowableArray<intptr_t>& argument_class_ids) {
|
| - if (ic_data.NumArgsTested() != 2) return false;
|
| + if (ic_data.NumArgsTested() != 2) {
|
| + return false;
|
| + }
|
| Function& target = Function::Handle();
|
| const intptr_t len = ic_data.NumberOfChecks();
|
| for (intptr_t i = 0; i < len; i++) {
|
| - GrowableArray<intptr_t> class_ids;
|
| - ic_data.GetCheckAt(i, &class_ids, &target);
|
| - ASSERT(class_ids.length() == 2);
|
| - if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
|
| - !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
|
| - return false;
|
| + if (ic_data.IsUsedAt(i)) {
|
| + GrowableArray<intptr_t> class_ids;
|
| + ic_data.GetCheckAt(i, &class_ids, &target);
|
| + ASSERT(class_ids.length() == 2);
|
| + if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
|
| + !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
|
| + return false;
|
| + }
|
| }
|
| }
|
| return true;
|
| @@ -904,34 +911,47 @@
|
|
|
|
|
| static bool HasOnlyOneSmi(const ICData& ic_data) {
|
| - return (ic_data.NumberOfChecks() == 1)
|
| + return (ic_data.NumberOfUsedChecks() == 1)
|
| && ic_data.HasReceiverClassId(kSmiCid);
|
| }
|
|
|
|
|
| static bool HasOnlySmiOrMint(const ICData& ic_data) {
|
| - if (ic_data.NumberOfChecks() == 1) {
|
| + if (ic_data.NumberOfUsedChecks() == 1) {
|
| return ic_data.HasReceiverClassId(kSmiCid)
|
| || ic_data.HasReceiverClassId(kMintCid);
|
| }
|
| - return (ic_data.NumberOfChecks() == 2)
|
| + return (ic_data.NumberOfUsedChecks() == 2)
|
| && ic_data.HasReceiverClassId(kSmiCid)
|
| && ic_data.HasReceiverClassId(kMintCid);
|
| }
|
|
|
|
|
| static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
|
| - return (ic_data.NumberOfChecks() == 1) &&
|
| - ICDataHasReceiverArgumentClassIds(ic_data, cid, cid);
|
| + if (ic_data.NumberOfUsedChecks() != 1) {
|
| + return false;
|
| + }
|
| + GrowableArray<intptr_t> first;
|
| + GrowableArray<intptr_t> second;
|
| + ic_data.GetUsedCidsForTwoArgs(&first, &second);
|
| + return (first[0] == cid) && (second[0] == cid);
|
| }
|
|
|
| // Returns false if the ICData contains anything other than the 4 combinations
|
| // of Mint and Smi for the receiver and argument classes.
|
| static bool HasTwoMintOrSmi(const ICData& ic_data) {
|
| - GrowableArray<intptr_t> class_ids(2);
|
| - class_ids.Add(kSmiCid);
|
| - class_ids.Add(kMintCid);
|
| - return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
|
| + GrowableArray<intptr_t> first;
|
| + GrowableArray<intptr_t> second;
|
| + ic_data.GetUsedCidsForTwoArgs(&first, &second);
|
| + for (intptr_t i = 0; i < first.length(); i++) {
|
| + if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
|
| + return false;
|
| + }
|
| + if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| }
|
|
|
|
|
| @@ -946,7 +966,7 @@
|
|
|
|
|
| static bool HasOnlyOneDouble(const ICData& ic_data) {
|
| - return (ic_data.NumberOfChecks() == 1)
|
| + return (ic_data.NumberOfUsedChecks() == 1)
|
| && ic_data.HasReceiverClassId(kDoubleCid);
|
| }
|
|
|
| @@ -1001,8 +1021,8 @@
|
| const ICData& unary_checks,
|
| intptr_t deopt_id,
|
| intptr_t token_pos) {
|
| - if ((unary_checks.NumberOfChecks() == 1) &&
|
| - (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
|
| + if ((unary_checks.NumberOfUsedChecks() == 1) &&
|
| + unary_checks.HasReceiverClassId(kSmiCid)) {
|
| return new(I) CheckSmiInstr(new(I) Value(to_check),
|
| deopt_id,
|
| token_pos);
|
| @@ -1037,10 +1057,14 @@
|
| const ICData& ic_data,
|
| intptr_t arg_number) {
|
| ASSERT(ic_data.NumArgsTested() > arg_number);
|
| + if (ic_data.NumberOfUsedChecks() == 0) {
|
| + return false;
|
| + }
|
| const intptr_t num_checks = ic_data.NumberOfChecks();
|
| - if (num_checks == 0) return false;
|
| for (intptr_t i = 0; i < num_checks; i++) {
|
| - if (ic_data.GetClassIdAt(i, arg_number) != cid) return false;
|
| + if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
|
| + return false;
|
| + }
|
| }
|
| return true;
|
| }
|
| @@ -1134,7 +1158,10 @@
|
| if (!call->HasICData()) return false;
|
| const ICData& ic_data =
|
| ICData::Handle(I, call->ic_data()->AsUnaryClassChecks());
|
| - if (ic_data.NumberOfChecks() != 1) return false;
|
| + if (ic_data.NumberOfChecks() != 1) {
|
| + return false;
|
| + }
|
| + ASSERT(ic_data.NumberOfUsedChecks() == 1);
|
| ASSERT(ic_data.HasOneTarget());
|
|
|
| const Function& target = Function::Handle(I, ic_data.GetTargetAt(0));
|
| @@ -1693,7 +1720,10 @@
|
| if (!call->HasICData()) return false;
|
| const ICData& ic_data =
|
| ICData::Handle(I, call->ic_data()->AsUnaryClassChecks());
|
| - if (ic_data.NumberOfChecks() != 1) return false;
|
| + if (ic_data.NumberOfChecks() != 1) {
|
| + return false;
|
| + }
|
| + ASSERT(ic_data.NumberOfUsedChecks() == 1);
|
| ASSERT(ic_data.HasOneTarget());
|
|
|
| const Function& target = Function::Handle(I, ic_data.GetTargetAt(0));
|
| @@ -2628,7 +2658,7 @@
|
| bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| - if (ic_data.NumberOfChecks() == 0) {
|
| + if (ic_data.NumberOfUsedChecks() == 0) {
|
| // No type feedback collected.
|
| return false;
|
| }
|
| @@ -2834,7 +2864,7 @@
|
| bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| - if ((ic_data.NumberOfChecks() == 0) || !ic_data.HasOneTarget()) {
|
| + if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
|
| // No type feedback collected or multiple targets found.
|
| return false;
|
| }
|
| @@ -4129,7 +4159,7 @@
|
| // Tries to optimize instance call by replacing it with a faster instruction
|
| // (e.g, binary op, field load, ..).
|
| void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| - if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) {
|
| + if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
|
| return;
|
| }
|
|
|
| @@ -4148,7 +4178,7 @@
|
| const ICData& unary_checks =
|
| ICData::ZoneHandle(I, instr->ic_data()->AsUnaryClassChecks());
|
|
|
| - intptr_t max_checks = (op_kind == Token::kEQ)
|
| + const intptr_t max_checks = (op_kind == Token::kEQ)
|
| ? FLAG_max_equality_polymorphic_checks
|
| : FLAG_max_polymorphic_checks;
|
| if ((unary_checks.NumberOfChecks() > max_checks) &&
|
|
|