| Index: runtime/vm/aot_optimizer.cc
|
| diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
|
| index 73c94047a723cdbaab571e4c7f13a08bb1be68ee..f12991544d978301deaeaed2ef779e11b34711e5 100644
|
| --- a/runtime/vm/aot_optimizer.cc
|
| +++ b/runtime/vm/aot_optimizer.cc
|
| @@ -47,17 +47,14 @@ static bool ShouldInlineSimd() {
|
| return FlowGraphCompiler::SupportsUnboxedSimd128();
|
| }
|
|
|
| -
|
| static bool CanUnboxDouble() {
|
| return FlowGraphCompiler::SupportsUnboxedDoubles();
|
| }
|
|
|
| -
|
| static bool CanConvertUnboxedMintToDouble() {
|
| return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
|
| }
|
|
|
| -
|
| // Returns named function that is a unique dynamic target, i.e.,
|
| // - the target is identified by its name alone, since it occurs only once.
|
| // - target's class has no subclasses, and neither is subclassed, i.e.,
|
| @@ -75,7 +72,6 @@ static void GetUniqueDynamicTarget(Isolate* isolate,
|
| isolate->object_store()->unique_dynamic_targets());
|
| }
|
|
|
| -
|
| AotOptimizer::AotOptimizer(Precompiler* precompiler,
|
| FlowGraph* flow_graph,
|
| bool use_speculative_inlining,
|
| @@ -95,13 +91,11 @@ AotOptimizer::AotOptimizer(Precompiler* precompiler,
|
| }
|
| }
|
|
|
| -
|
| // Optimize instance calls using ICData.
|
| void AotOptimizer::ApplyICData() {
|
| VisitBlocks();
|
| }
|
|
|
| -
|
| bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
|
| if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) {
|
| return false;
|
| @@ -124,7 +118,6 @@ bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
|
| return true;
|
| }
|
|
|
| -
|
| // Optimize instance calls using cid. This is called after optimizer
|
| // converted instance calls to instructions. Any remaining
|
| // instance calls are either megamorphic calls, cannot be optimized or
|
| @@ -152,13 +145,11 @@ void AotOptimizer::ApplyClassIds() {
|
| }
|
| }
|
|
|
| -
|
| // TODO(srdjan): Test/support other number types as well.
|
| static bool IsNumberCid(intptr_t cid) {
|
| return (cid == kSmiCid) || (cid == kDoubleCid);
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| if (call->ic_data()->NumberOfUsedChecks() > 0) {
|
| @@ -281,7 +272,6 @@ bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| return false;
|
| }
|
|
|
| -
|
| static bool ClassIdIsOneOf(intptr_t class_id,
|
| const GrowableArray<intptr_t>& class_ids) {
|
| for (intptr_t i = 0; i < class_ids.length(); i++) {
|
| @@ -293,7 +283,6 @@ static bool ClassIdIsOneOf(intptr_t class_id,
|
| return false;
|
| }
|
|
|
| -
|
| // Returns true if ICData tests two arguments and all ICData cids are in the
|
| // required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
|
| static bool ICDataHasOnlyReceiverArgumentClassIds(
|
| @@ -318,7 +307,6 @@ static bool ICDataHasOnlyReceiverArgumentClassIds(
|
| return true;
|
| }
|
|
|
| -
|
| static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
|
| intptr_t receiver_class_id,
|
| intptr_t argument_class_id) {
|
| @@ -340,13 +328,11 @@ static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
|
| return false;
|
| }
|
|
|
| -
|
| static bool HasOnlyOneSmi(const ICData& ic_data) {
|
| return (ic_data.NumberOfUsedChecks() == 1) &&
|
| ic_data.HasReceiverClassId(kSmiCid);
|
| }
|
|
|
| -
|
| static bool HasOnlySmiOrMint(const ICData& ic_data) {
|
| if (ic_data.NumberOfUsedChecks() == 1) {
|
| return ic_data.HasReceiverClassId(kSmiCid) ||
|
| @@ -357,7 +343,6 @@ static bool HasOnlySmiOrMint(const ICData& ic_data) {
|
| ic_data.HasReceiverClassId(kMintCid);
|
| }
|
|
|
| -
|
| static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
|
| if (ic_data.NumberOfUsedChecks() != 1) {
|
| return false;
|
| @@ -385,7 +370,6 @@ static bool HasTwoMintOrSmi(const ICData& ic_data) {
|
| return true;
|
| }
|
|
|
| -
|
| // Returns false if the ICData contains anything other than the 4 combinations
|
| // of Double and Smi for the receiver and argument classes.
|
| static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
|
| @@ -395,13 +379,11 @@ static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
|
| return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
|
| }
|
|
|
| -
|
| static bool HasOnlyOneDouble(const ICData& ic_data) {
|
| return (ic_data.NumberOfUsedChecks() == 1) &&
|
| ic_data.HasReceiverClassId(kDoubleCid);
|
| }
|
|
|
| -
|
| static bool ShouldSpecializeForDouble(const ICData& ic_data) {
|
| // Don't specialize for double if we can't unbox them.
|
| if (!CanUnboxDouble()) {
|
| @@ -417,7 +399,6 @@ static bool ShouldSpecializeForDouble(const ICData& ic_data) {
|
| return HasTwoDoubleOrSmi(ic_data);
|
| }
|
|
|
| -
|
| void AotOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
|
| // Remove the original push arguments.
|
| for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| @@ -428,7 +409,6 @@ void AotOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
|
| call->ReplaceWith(replacement, current_iterator());
|
| }
|
|
|
| -
|
| void AotOptimizer::AddCheckSmi(Definition* to_check,
|
| intptr_t deopt_id,
|
| Environment* deopt_environment,
|
| @@ -441,7 +421,6 @@ void AotOptimizer::AddCheckSmi(Definition* to_check,
|
| }
|
| }
|
|
|
| -
|
| void AotOptimizer::AddCheckClass(Definition* to_check,
|
| const Cids& cids,
|
| intptr_t deopt_id,
|
| @@ -453,7 +432,6 @@ void AotOptimizer::AddCheckClass(Definition* to_check,
|
| InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
|
| }
|
|
|
| -
|
| void AotOptimizer::AddChecksForArgNr(InstanceCallInstr* call,
|
| Definition* instr,
|
| int argument_number) {
|
| @@ -461,7 +439,6 @@ void AotOptimizer::AddChecksForArgNr(InstanceCallInstr* call,
|
| AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call);
|
| }
|
|
|
| -
|
| static bool ArgIsAlways(intptr_t cid,
|
| const ICData& ic_data,
|
| intptr_t arg_number) {
|
| @@ -478,7 +455,6 @@ static bool ArgIsAlways(intptr_t cid,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call,
|
| const ICData* unary_checks) {
|
| // Check for monomorphic IC data.
|
| @@ -490,7 +466,6 @@ bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call,
|
| flow_graph_, current_iterator(), call);
|
| }
|
|
|
| -
|
| // Return true if d is a string of length one (a constant or result from
|
| // from string-from-char-code instruction.
|
| static bool IsLengthOneString(Definition* d) {
|
| @@ -506,7 +481,6 @@ static bool IsLengthOneString(Definition* d) {
|
| }
|
| }
|
|
|
| -
|
| // Returns true if the string comparison was converted into char-code
|
| // comparison. Conversion is only possible for strings of length one.
|
| // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
|
| @@ -587,19 +561,16 @@ bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
|
| return false;
|
| }
|
|
|
| -
|
| static bool SmiFitsInDouble() {
|
| return kSmiBits < 53;
|
| }
|
|
|
| -
|
| static bool IsGetRuntimeType(Definition* defn) {
|
| StaticCallInstr* call = defn->AsStaticCall();
|
| return (call != NULL) && (call->function().recognized_kind() ==
|
| MethodRecognizer::kObjectRuntimeType);
|
| }
|
|
|
| -
|
| // Recognize a.runtimeType == b.runtimeType and fold it into
|
| // Object._haveSameRuntimeType(a, b).
|
| // Note: this optimization is not speculative.
|
| @@ -643,7 +614,6 @@ bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) {
|
| return false;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -680,10 +650,11 @@ bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| // call.
|
| return false;
|
| } else {
|
| - InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
|
| - new (Z) Value(right),
|
| - call->deopt_id()),
|
| - call->env(), FlowGraph::kEffect);
|
| + InsertBefore(
|
| + call,
|
| + new (Z) CheckEitherNonSmiInstr(
|
| + new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
|
| + call->env(), FlowGraph::kEffect);
|
| cid = kDoubleCid;
|
| }
|
| }
|
| @@ -726,7 +697,6 @@ bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -761,10 +731,11 @@ bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| // call.
|
| return false;
|
| } else {
|
| - InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
|
| - new (Z) Value(right),
|
| - call->deopt_id()),
|
| - call->env(), FlowGraph::kEffect);
|
| + InsertBefore(
|
| + call,
|
| + new (Z) CheckEitherNonSmiInstr(
|
| + new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
|
| + call->env(), FlowGraph::kEffect);
|
| cid = kDoubleCid;
|
| }
|
| }
|
| @@ -779,7 +750,6 @@ bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| intptr_t operands_type = kIllegalCid;
|
| @@ -894,10 +864,11 @@ bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| // binary operation with two smis is a smi not a double, except '/' which
|
| // returns a double for two smis.
|
| if (op_kind != Token::kDIV) {
|
| - InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
|
| - new (Z) Value(right),
|
| - call->deopt_id()),
|
| - call->env(), FlowGraph::kEffect);
|
| + InsertBefore(
|
| + call,
|
| + new (Z) CheckEitherNonSmiInstr(
|
| + new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
|
| + call->env(), FlowGraph::kEffect);
|
| }
|
|
|
| BinaryDoubleOpInstr* double_bin_op = new (Z)
|
| @@ -968,7 +939,6 @@ bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| ASSERT(call->type_args_len() == 0);
|
| @@ -1000,7 +970,6 @@ bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| // Using field class
|
| RawField* AotOptimizer::GetField(intptr_t class_id, const String& field_name) {
|
| Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
|
| @@ -1015,7 +984,6 @@ RawField* AotOptimizer::GetField(intptr_t class_id, const String& field_name) {
|
| return Field::null();
|
| }
|
|
|
| -
|
| bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -1052,7 +1020,6 @@ bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -1073,7 +1040,6 @@ bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -1093,7 +1059,6 @@ bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -1113,7 +1078,6 @@ bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| // Only unique implicit instance getters can be currently handled.
|
| bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| @@ -1138,7 +1102,6 @@ bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| return InlineImplicitInstanceGetter(call);
|
| }
|
|
|
| -
|
| void AotOptimizer::ReplaceWithMathCFunction(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| @@ -1154,7 +1117,6 @@ void AotOptimizer::ReplaceWithMathCFunction(
|
| ReplaceCall(call, invoke);
|
| }
|
|
|
| -
|
| // Inline only simple, frequently called core library methods.
|
| bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| @@ -1235,7 +1197,6 @@ bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| flow_graph_, current_iterator(), call);
|
| }
|
|
|
| -
|
| // If type tests specified by 'ic_data' do not depend on type arguments,
|
| // return mapping cid->result in 'results' (i : cid; i + 1: result).
|
| // If all tests yield the same result, return it otherwise return Bool::null.
|
| @@ -1303,7 +1264,6 @@ RawBool* AotOptimizer::InstanceOfAsBool(
|
| return results_differ ? Bool::null() : prev.raw();
|
| }
|
|
|
| -
|
| // Returns true if checking against this type is a direct class id comparison.
|
| bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
|
| @@ -1348,7 +1308,6 @@ bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| return true;
|
| }
|
|
|
| -
|
| // TODO(srdjan): Use ICData to check if always true or false.
|
| void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeTestOperator(call->token_kind()));
|
| @@ -1466,7 +1425,6 @@ void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ReplaceCall(call, instance_of);
|
| }
|
|
|
| -
|
| // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
|
| void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeCastOperator(call->token_kind()));
|
| @@ -1629,7 +1587,6 @@ void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| ReplaceCall(call, assert_as);
|
| }
|
|
|
| -
|
| bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) {
|
| if (!use_speculative_inlining_) return false;
|
| for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
|
| @@ -1638,7 +1595,6 @@ bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) {
|
| return true;
|
| }
|
|
|
| -
|
| static bool HasLikelySmiOperand(InstanceCallInstr* instr) {
|
| ASSERT(instr->type_args_len() == 0);
|
| // Phis with at least one known smi are // guessed to be likely smi as well.
|
| @@ -1658,7 +1614,6 @@ static bool HasLikelySmiOperand(InstanceCallInstr* instr) {
|
| return true;
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) {
|
| const Token::Kind op_kind = call->token_kind();
|
| if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
|
| @@ -1675,7 +1630,6 @@ bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) {
|
| return false;
|
| }
|
|
|
| -
|
| // Tries to optimize instance call by replacing it with a faster instruction
|
| // (e.g, binary op, field load, ..).
|
| void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| @@ -1949,7 +1903,6 @@ void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| }
|
| }
|
|
|
| -
|
| void AotOptimizer::VisitPolymorphicInstanceCall(
|
| PolymorphicInstanceCallInstr* call) {
|
| const intptr_t receiver_cid =
|
| @@ -1967,7 +1920,6 @@ void AotOptimizer::VisitPolymorphicInstanceCall(
|
| }
|
| }
|
|
|
| -
|
| void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| if (!IsAllowedForInlining(call->deopt_id())) {
|
| // Inlining disabled after a speculative inlining attempt.
|
| @@ -2053,7 +2005,6 @@ void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| }
|
| }
|
|
|
| -
|
| void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
|
| #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
|
| @@ -2061,7 +2012,6 @@ void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| #endif
|
| }
|
|
|
| -
|
| bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| const ICData& unary_ic_data) {
|
| ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
|
| @@ -2116,7 +2066,6 @@ bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| return true;
|
| }
|
|
|
| -
|
| void AotOptimizer::ReplaceArrayBoundChecks() {
|
| for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
|
| !block_it.Done(); block_it.Advance()) {
|
|
|