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()) { |