| Index: runtime/vm/aot_optimizer.cc
|
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/aot_optimizer.cc
|
| similarity index 78%
|
| copy from runtime/vm/flow_graph_optimizer.cc
|
| copy to runtime/vm/aot_optimizer.cc
|
| index 1ad25c8fdb3cb9a10db529c8bb9fdc8d1ff87633..371b98fee7bd127f6c010bf888b08a3aaaeb5be9 100644
|
| --- a/runtime/vm/flow_graph_optimizer.cc
|
| +++ b/runtime/vm/aot_optimizer.cc
|
| @@ -2,7 +2,7 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -#include "vm/flow_graph_optimizer.h"
|
| +#include "vm/aot_optimizer.h"
|
|
|
| #include "vm/bit_vector.h"
|
| #include "vm/branch_optimizer.h"
|
| @@ -18,6 +18,7 @@
|
| #include "vm/hash_map.h"
|
| #include "vm/il_printer.h"
|
| #include "vm/intermediate_language.h"
|
| +#include "vm/object.h"
|
| #include "vm/object_store.h"
|
| #include "vm/parser.h"
|
| #include "vm/precompiler.h"
|
| @@ -28,27 +29,7 @@
|
|
|
| namespace dart {
|
|
|
| -DEFINE_FLAG(int, getter_setter_ratio, 13,
|
| - "Ratio of getter/setter usage used for double field unboxing heuristics");
|
| -DEFINE_FLAG(bool, guess_icdata_cid, true,
|
| - "Artificially create type feedback for arithmetic etc. operations"
|
| - " by guessing the other unknown argument cid");
|
| -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, merge_sin_cos, false, "Merge sin/cos into sincos");
|
| -DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
|
| -DEFINE_FLAG(bool, truncating_left_shift, true,
|
| - "Optimize left shift to truncate if possible");
|
| -DEFINE_FLAG(bool, use_cha_deopt, true,
|
| - "Use class hierarchy analysis even if it can cause deoptimization.");
|
| -
|
| DECLARE_FLAG(bool, precompilation);
|
| -DECLARE_FLAG(bool, polymorphic_with_deopt);
|
| -DECLARE_FLAG(bool, trace_cha);
|
| -DECLARE_FLAG(bool, trace_field_guards);
|
|
|
| // Quick access to the current isolate and zone.
|
| #define I (isolate())
|
| @@ -70,12 +51,12 @@ static bool CanConvertUnboxedMintToDouble() {
|
|
|
|
|
| // Optimize instance calls using ICData.
|
| -void FlowGraphOptimizer::ApplyICData() {
|
| +void AotOptimizer::ApplyICData() {
|
| VisitBlocks();
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::PopulateWithICData() {
|
| +void AotOptimizer::PopulateWithICData() {
|
| ASSERT(current_iterator_ == NULL);
|
| for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
|
| !block_it.Done();
|
| @@ -109,7 +90,7 @@ void FlowGraphOptimizer::PopulateWithICData() {
|
| // have no runtime type feedback collected.
|
| // Attempts to convert an instance call (IC call) using propagated class-ids,
|
| // e.g., receiver class id, guarded-cid, or by guessing cid-s.
|
| -void FlowGraphOptimizer::ApplyClassIds() {
|
| +void AotOptimizer::ApplyClassIds() {
|
| ASSERT(current_iterator_ == NULL);
|
| for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
|
| !block_it.Done();
|
| @@ -140,7 +121,19 @@ static bool IsNumberCid(intptr_t cid) {
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| +static void GetUniqueDynamicTarget(Isolate* isolate,
|
| + const String& fname,
|
| + Object* function) {
|
| + UniqueFunctionsSet functions_set(
|
| + isolate->object_store()->unique_dynamic_targets());
|
| + ASSERT(fname.IsSymbol());
|
| + *function = functions_set.GetOrNull(fname);
|
| + ASSERT(functions_set.Release().raw() ==
|
| + isolate->object_store()->unique_dynamic_targets());
|
| +}
|
| +
|
| +
|
| +bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| if (call->ic_data()->NumberOfUsedChecks() > 0) {
|
| // This occurs when an instance call has too many checks, will be converted
|
| @@ -196,8 +189,7 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| Resolver::ResolveDynamicForReceiverClass(
|
| receiver_class,
|
| call->function_name(),
|
| - args_desc,
|
| - false /* allow add */));
|
| + args_desc));
|
| if (function.IsNull()) {
|
| return false;
|
| }
|
| @@ -218,13 +210,10 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| return true;
|
| }
|
|
|
| -#ifdef DART_PRECOMPILER
|
| - if (FLAG_precompilation &&
|
| - (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
|
| + if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
|
| // Check if the target is unique.
|
| Function& target_function = Function::Handle(Z);
|
| - Precompiler::GetUniqueDynamicTarget(
|
| - isolate(), call->function_name(), &target_function);
|
| + GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
|
| // Calls with named arguments must be resolved/checked at runtime.
|
| String& error_message = String::Handle(Z);
|
| if (!target_function.IsNull() &&
|
| @@ -239,7 +228,6 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| return true;
|
| }
|
| }
|
| -#endif
|
|
|
| // Check if getter or setter in function's class and class is currently leaf.
|
| if (FLAG_guess_icdata_cid &&
|
| @@ -256,8 +244,7 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| const Function& function = Function::Handle(Z,
|
| Resolver::ResolveDynamicForReceiverClass(owner_class,
|
| call->function_name(),
|
| - args_desc,
|
| - false /* allow_add */));
|
| + args_desc));
|
| if (!function.IsNull()) {
|
| const ICData& ic_data = ICData::ZoneHandle(Z,
|
| ICData::NewFrom(*call->ic_data(), class_ids.length()));
|
| @@ -272,7 +259,7 @@ bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| }
|
|
|
|
|
| -const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data,
|
| +const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
|
| intptr_t cid) {
|
| ASSERT(ic_data.NumArgsTested() == 1);
|
|
|
| @@ -300,7 +287,7 @@ const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data,
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::SpecializePolymorphicInstanceCall(
|
| +void AotOptimizer::SpecializePolymorphicInstanceCall(
|
| PolymorphicInstanceCallInstr* call) {
|
| if (!FLAG_polymorphic_with_deopt) {
|
| // Specialization adds receiver checks which can lead to deoptimization.
|
| @@ -349,7 +336,7 @@ static bool IsPositiveOrZeroSmiConst(Definition* d) {
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
|
| +void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
|
| Definition* bit_and_instr,
|
| Definition* left_instr,
|
| Definition* right_instr) {
|
| @@ -387,7 +374,7 @@ void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
|
| +void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
|
| intptr_t index,
|
| Representation rep,
|
| intptr_t cid) {
|
| @@ -415,7 +402,7 @@ void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
|
| // v7 <- +(v5, v6)
|
| // Because of the environment it is important that merged instruction replaces
|
| // first original instruction encountered.
|
| -void FlowGraphOptimizer::TryMergeTruncDivMod(
|
| +void AotOptimizer::TryMergeTruncDivMod(
|
| GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
|
| if (merge_candidates->length() < 2) {
|
| // Need at least a TRUNCDIV and a MOD.
|
| @@ -476,7 +463,7 @@ void FlowGraphOptimizer::TryMergeTruncDivMod(
|
|
|
|
|
| // Tries to merge MathUnary operations, in this case sinus and cosinus.
|
| -void FlowGraphOptimizer::TryMergeMathUnary(
|
| +void AotOptimizer::TryMergeMathUnary(
|
| GrowableArray<MathUnaryInstr*>* merge_candidates) {
|
| if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
|
| !FLAG_merge_sin_cos) {
|
| @@ -537,7 +524,7 @@ void FlowGraphOptimizer::TryMergeMathUnary(
|
| // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
|
| // shift can be a truncating Smi shift-left and result is always Smi.
|
| // Merging occurs only per basic-block.
|
| -void FlowGraphOptimizer::TryOptimizePatterns() {
|
| +void AotOptimizer::TryOptimizePatterns() {
|
| if (!FLAG_truncating_left_shift) return;
|
| ASSERT(current_iterator_ == NULL);
|
| GrowableArray<BinarySmiOpInstr*> div_mod_merge;
|
| @@ -723,7 +710,7 @@ static bool ShouldSpecializeForDouble(const ICData& ic_data) {
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::ReplaceCall(Definition* call,
|
| +void AotOptimizer::ReplaceCall(Definition* call,
|
| Definition* replacement) {
|
| // Remove the original push arguments.
|
| for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| @@ -735,7 +722,7 @@ void FlowGraphOptimizer::ReplaceCall(Definition* call,
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
|
| +void AotOptimizer::AddCheckSmi(Definition* to_check,
|
| intptr_t deopt_id,
|
| Environment* deopt_environment,
|
| Instruction* insert_before) {
|
| @@ -750,7 +737,7 @@ void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
|
| }
|
|
|
|
|
| -Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
|
| +Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
|
| const ICData& unary_checks,
|
| intptr_t deopt_id,
|
| TokenPosition token_pos) {
|
| @@ -765,7 +752,7 @@ Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
|
| +void AotOptimizer::AddCheckClass(Definition* to_check,
|
| const ICData& unary_checks,
|
| intptr_t deopt_id,
|
| Environment* deopt_environment,
|
| @@ -777,7 +764,7 @@ void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
|
| +void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
|
| AddCheckClass(call->ArgumentAt(0),
|
| ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
|
| call->deopt_id(),
|
| @@ -803,7 +790,7 @@ static bool ArgIsAlways(intptr_t cid,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
|
| +bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
|
| // Check for monomorphic IC data.
|
| if (!call->HasICData()) return false;
|
| const ICData& ic_data =
|
| @@ -835,7 +822,7 @@ static bool IsLengthOneString(Definition* d) {
|
| // comparison. Conversion is only possible for strings of length one.
|
| // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
|
| // TODO(srdjan): Expand for two-byte and external strings.
|
| -bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
|
| // Check that left and right are length one strings (either string constants
|
| @@ -922,7 +909,7 @@ bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
|
|
|
| static bool SmiFitsInDouble() { return kSmiBits < 53; }
|
|
|
| -bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| const ICData& ic_data = *call->ic_data();
|
| ASSERT(ic_data.NumArgsTested() == 2);
|
| @@ -1031,7 +1018,7 @@ bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| const ICData& ic_data = *call->ic_data();
|
| ASSERT(ic_data.NumArgsTested() == 2);
|
| @@ -1093,7 +1080,7 @@ bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| intptr_t operands_type = kIllegalCid;
|
| ASSERT(call->HasICData());
|
| @@ -1302,7 +1289,7 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| ASSERT(call->ArgumentCount() == 1);
|
| Definition* input = call->ArgumentAt(0);
|
| @@ -1337,7 +1324,7 @@ bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
|
|
|
|
| // Using field class
|
| -RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
|
| +RawField* AotOptimizer::GetField(intptr_t class_id,
|
| const String& field_name) {
|
| Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
|
| Field& field = Field::Handle(Z);
|
| @@ -1355,7 +1342,7 @@ RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
|
| // Use CHA to determine if the call needs a class check: if the callee's
|
| // receiver is the same as the caller's receiver and there are no overriden
|
| // callee functions, then no class check is needed.
|
| -bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
|
| +bool AotOptimizer::InstanceCallNeedsClassCheck(
|
| InstanceCallInstr* call, RawFunction::Kind kind) const {
|
| if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
|
| // Even if class or function are private, lazy class finalization
|
| @@ -1386,7 +1373,7 @@ bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
|
| bool allow_check) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -1413,12 +1400,9 @@ bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
|
| AbstractType::ZoneHandle(Z, field.type()),
|
| call->token_pos());
|
| load->set_is_immutable(field.is_final());
|
| - if (field.guarded_cid() != kIllegalCid) {
|
| - if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
|
| - load->set_result_cid(field.guarded_cid());
|
| - }
|
| - flow_graph()->parsed_function().AddToGuardedFields(&field);
|
| - }
|
| +
|
| + // No guarded cid in precompiled mode.
|
| + ASSERT(field.guarded_cid() == kDynamicCid);
|
|
|
| // Discard the environment from the original instruction because the load
|
| // can't deoptimize.
|
| @@ -1437,7 +1421,7 @@ bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
|
| MethodRecognizer::Kind getter) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1512,7 +1496,7 @@ bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
|
| MethodRecognizer::Kind getter) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1538,7 +1522,7 @@ bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
|
| MethodRecognizer::Kind getter) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1613,7 +1597,7 @@ bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1646,7 +1630,7 @@ bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1678,7 +1662,7 @@ bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| +bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| return false;
|
| @@ -1712,7 +1696,7 @@ bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
|
|
| // Only unique implicit instance getters can be currently handled.
|
| // Returns false if 'allow_check' is false and a check is needed.
|
| -bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
|
| +bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
|
| bool allow_check) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -1737,7 +1721,7 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline(
|
| +bool AotOptimizer::TryReplaceInstanceCallWithInline(
|
| InstanceCallInstr* call) {
|
| Function& target = Function::Handle(Z);
|
| GrowableArray<intptr_t> class_ids;
|
| @@ -1781,7 +1765,7 @@ bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline(
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::ReplaceWithMathCFunction(
|
| +void AotOptimizer::ReplaceWithMathCFunction(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| AddReceiverCheck(call);
|
| @@ -1822,7 +1806,7 @@ static bool IsSupportedByteArrayViewCid(intptr_t cid) {
|
|
|
|
|
| // Inline only simple, frequently called core library methods.
|
| -bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| +bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
|
| @@ -2055,418 +2039,54 @@ bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineFloat32x4Constructor(
|
| +bool AotOptimizer::TryInlineFloat32x4Constructor(
|
| StaticCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (FLAG_precompilation) {
|
| - // Cannot handle unboxed instructions.
|
| - return false;
|
| - }
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
|
| - Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr();
|
| - ReplaceCall(call, zero);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
|
| - Float32x4SplatInstr* splat =
|
| - new(Z) Float32x4SplatInstr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, splat);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
|
| - Float32x4ConstructorInstr* con =
|
| - new(Z) Float32x4ConstructorInstr(
|
| - new(Z) Value(call->ArgumentAt(1)),
|
| - new(Z) Value(call->ArgumentAt(2)),
|
| - new(Z) Value(call->ArgumentAt(3)),
|
| - new(Z) Value(call->ArgumentAt(4)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, con);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) {
|
| - Int32x4ToFloat32x4Instr* cast =
|
| - new(Z) Int32x4ToFloat32x4Instr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, cast);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) {
|
| - Float64x2ToFloat32x4Instr* cast =
|
| - new(Z) Float64x2ToFloat32x4Instr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, cast);
|
| - return true;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + ASSERT(FLAG_precompilation);
|
| return false;
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineFloat64x2Constructor(
|
| +bool AotOptimizer::TryInlineFloat64x2Constructor(
|
| StaticCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (FLAG_precompilation) {
|
| - // Cannot handle unboxed instructions.
|
| - return false;
|
| - }
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - if (recognized_kind == MethodRecognizer::kFloat64x2Zero) {
|
| - Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr();
|
| - ReplaceCall(call, zero);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) {
|
| - Float64x2SplatInstr* splat =
|
| - new(Z) Float64x2SplatInstr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, splat);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) {
|
| - Float64x2ConstructorInstr* con =
|
| - new(Z) Float64x2ConstructorInstr(
|
| - new(Z) Value(call->ArgumentAt(1)),
|
| - new(Z) Value(call->ArgumentAt(2)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, con);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) {
|
| - Float32x4ToFloat64x2Instr* cast =
|
| - new(Z) Float32x4ToFloat64x2Instr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, cast);
|
| - return true;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + ASSERT(FLAG_precompilation);
|
| return false;
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineInt32x4Constructor(
|
| +bool AotOptimizer::TryInlineInt32x4Constructor(
|
| StaticCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (FLAG_precompilation) {
|
| - // Cannot handle unboxed instructions.
|
| - return false;
|
| - }
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) {
|
| - Int32x4BoolConstructorInstr* con =
|
| - new(Z) Int32x4BoolConstructorInstr(
|
| - new(Z) Value(call->ArgumentAt(1)),
|
| - new(Z) Value(call->ArgumentAt(2)),
|
| - new(Z) Value(call->ArgumentAt(3)),
|
| - new(Z) Value(call->ArgumentAt(4)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, con);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) {
|
| - Float32x4ToInt32x4Instr* cast =
|
| - new(Z) Float32x4ToInt32x4Instr(
|
| - new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
|
| - ReplaceCall(call, cast);
|
| - return true;
|
| - } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) {
|
| - Int32x4ConstructorInstr* con =
|
| - new(Z) Int32x4ConstructorInstr(
|
| - new(Z) Value(call->ArgumentAt(1)),
|
| - new(Z) Value(call->ArgumentAt(2)),
|
| - new(Z) Value(call->ArgumentAt(3)),
|
| - new(Z) Value(call->ArgumentAt(4)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, con);
|
| - return true;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + ASSERT(FLAG_precompilation);
|
| return false;
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineFloat32x4Method(
|
| +bool AotOptimizer::TryInlineFloat32x4Method(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - ASSERT(call->HasICData());
|
| - switch (recognized_kind) {
|
| - case MethodRecognizer::kFloat32x4ShuffleX:
|
| - case MethodRecognizer::kFloat32x4ShuffleY:
|
| - case MethodRecognizer::kFloat32x4ShuffleZ:
|
| - case MethodRecognizer::kFloat32x4ShuffleW:
|
| - case MethodRecognizer::kFloat32x4GetSignMask:
|
| - ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid));
|
| - ASSERT(call->ic_data()->HasOneTarget());
|
| - return InlineFloat32x4Getter(call, recognized_kind);
|
| -
|
| - case MethodRecognizer::kFloat32x4Equal:
|
| - case MethodRecognizer::kFloat32x4GreaterThan:
|
| - case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
|
| - case MethodRecognizer::kFloat32x4LessThan:
|
| - case MethodRecognizer::kFloat32x4LessThanOrEqual:
|
| - case MethodRecognizer::kFloat32x4NotEqual: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* right = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - // Replace call.
|
| - Float32x4ComparisonInstr* cmp =
|
| - new(Z) Float32x4ComparisonInstr(recognized_kind,
|
| - new(Z) Value(left),
|
| - new(Z) Value(right),
|
| - call->deopt_id());
|
| - ReplaceCall(call, cmp);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4Min:
|
| - case MethodRecognizer::kFloat32x4Max: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* right = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float32x4MinMaxInstr* minmax =
|
| - new(Z) Float32x4MinMaxInstr(
|
| - recognized_kind,
|
| - new(Z) Value(left),
|
| - new(Z) Value(right),
|
| - call->deopt_id());
|
| - ReplaceCall(call, minmax);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4Scale: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* right = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - // Left and right values are swapped when handed to the instruction,
|
| - // this is done so that the double value is loaded into the output
|
| - // register and can be destroyed.
|
| - Float32x4ScaleInstr* scale =
|
| - new(Z) Float32x4ScaleInstr(recognized_kind,
|
| - new(Z) Value(right),
|
| - new(Z) Value(left),
|
| - call->deopt_id());
|
| - ReplaceCall(call, scale);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4Sqrt:
|
| - case MethodRecognizer::kFloat32x4ReciprocalSqrt:
|
| - case MethodRecognizer::kFloat32x4Reciprocal: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float32x4SqrtInstr* sqrt =
|
| - new(Z) Float32x4SqrtInstr(recognized_kind,
|
| - new(Z) Value(left),
|
| - call->deopt_id());
|
| - ReplaceCall(call, sqrt);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4WithX:
|
| - case MethodRecognizer::kFloat32x4WithY:
|
| - case MethodRecognizer::kFloat32x4WithZ:
|
| - case MethodRecognizer::kFloat32x4WithW: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* right = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind,
|
| - new(Z) Value(left),
|
| - new(Z) Value(right),
|
| - call->deopt_id());
|
| - ReplaceCall(call, with);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4Absolute:
|
| - case MethodRecognizer::kFloat32x4Negate: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float32x4ZeroArgInstr* zeroArg =
|
| - new(Z) Float32x4ZeroArgInstr(
|
| - recognized_kind, new(Z) Value(left), call->deopt_id());
|
| - ReplaceCall(call, zeroArg);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4Clamp: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* lower = call->ArgumentAt(1);
|
| - Definition* upper = call->ArgumentAt(2);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr(
|
| - new(Z) Value(left),
|
| - new(Z) Value(lower),
|
| - new(Z) Value(upper),
|
| - call->deopt_id());
|
| - ReplaceCall(call, clamp);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat32x4ShuffleMix:
|
| - case MethodRecognizer::kFloat32x4Shuffle: {
|
| - return InlineFloat32x4Getter(call, recognized_kind);
|
| - }
|
| - default:
|
| - return false;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + return false;
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineFloat64x2Method(
|
| +bool AotOptimizer::TryInlineFloat64x2Method(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - ASSERT(call->HasICData());
|
| - switch (recognized_kind) {
|
| - case MethodRecognizer::kFloat64x2GetX:
|
| - case MethodRecognizer::kFloat64x2GetY:
|
| - ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid));
|
| - ASSERT(call->ic_data()->HasOneTarget());
|
| - return InlineFloat64x2Getter(call, recognized_kind);
|
| - case MethodRecognizer::kFloat64x2Negate:
|
| - case MethodRecognizer::kFloat64x2Abs:
|
| - case MethodRecognizer::kFloat64x2Sqrt:
|
| - case MethodRecognizer::kFloat64x2GetSignMask: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float64x2ZeroArgInstr* zeroArg =
|
| - new(Z) Float64x2ZeroArgInstr(
|
| - recognized_kind, new(Z) Value(left), call->deopt_id());
|
| - ReplaceCall(call, zeroArg);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kFloat64x2Scale:
|
| - case MethodRecognizer::kFloat64x2WithX:
|
| - case MethodRecognizer::kFloat64x2WithY:
|
| - case MethodRecognizer::kFloat64x2Min:
|
| - case MethodRecognizer::kFloat64x2Max: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* right = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Float64x2OneArgInstr* zeroArg =
|
| - new(Z) Float64x2OneArgInstr(recognized_kind,
|
| - new(Z) Value(left),
|
| - new(Z) Value(right),
|
| - call->deopt_id());
|
| - ReplaceCall(call, zeroArg);
|
| - return true;
|
| - }
|
| - default:
|
| - return false;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + return false;
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineInt32x4Method(
|
| +bool AotOptimizer::TryInlineInt32x4Method(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| - if (!ShouldInlineSimd()) {
|
| - return false;
|
| - }
|
| - ASSERT(call->HasICData());
|
| - switch (recognized_kind) {
|
| - case MethodRecognizer::kInt32x4ShuffleMix:
|
| - case MethodRecognizer::kInt32x4Shuffle:
|
| - case MethodRecognizer::kInt32x4GetFlagX:
|
| - case MethodRecognizer::kInt32x4GetFlagY:
|
| - case MethodRecognizer::kInt32x4GetFlagZ:
|
| - case MethodRecognizer::kInt32x4GetFlagW:
|
| - case MethodRecognizer::kInt32x4GetSignMask:
|
| - ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid));
|
| - ASSERT(call->ic_data()->HasOneTarget());
|
| - return InlineInt32x4Getter(call, recognized_kind);
|
| -
|
| - case MethodRecognizer::kInt32x4Select: {
|
| - Definition* mask = call->ArgumentAt(0);
|
| - Definition* trueValue = call->ArgumentAt(1);
|
| - Definition* falseValue = call->ArgumentAt(2);
|
| - // Type check left.
|
| - AddCheckClass(mask,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr(
|
| - new(Z) Value(mask),
|
| - new(Z) Value(trueValue),
|
| - new(Z) Value(falseValue),
|
| - call->deopt_id());
|
| - ReplaceCall(call, select);
|
| - return true;
|
| - }
|
| - case MethodRecognizer::kInt32x4WithFlagX:
|
| - case MethodRecognizer::kInt32x4WithFlagY:
|
| - case MethodRecognizer::kInt32x4WithFlagZ:
|
| - case MethodRecognizer::kInt32x4WithFlagW: {
|
| - Definition* left = call->ArgumentAt(0);
|
| - Definition* flag = call->ArgumentAt(1);
|
| - // Type check left.
|
| - AddCheckClass(left,
|
| - ICData::ZoneHandle(
|
| - Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
|
| - call->deopt_id(),
|
| - call->env(),
|
| - call);
|
| - Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr(
|
| - recognized_kind,
|
| - new(Z) Value(left),
|
| - new(Z) Value(flag),
|
| - call->deopt_id());
|
| - ReplaceCall(call, setFlag);
|
| - return true;
|
| - }
|
| - default:
|
| - return false;
|
| - }
|
| + // Cannot handle unboxed instructions.
|
| + return false;
|
| }
|
|
|
|
|
| @@ -2476,7 +2096,7 @@ bool FlowGraphOptimizer::TryInlineInt32x4Method(
|
| // If no mapping is possible, 'results' is empty.
|
| // An instance-of test returning all same results can be converted to a class
|
| // check.
|
| -RawBool* FlowGraphOptimizer::InstanceOfAsBool(
|
| +RawBool* AotOptimizer::InstanceOfAsBool(
|
| const ICData& ic_data,
|
| const AbstractType& type,
|
| ZoneGrowableArray<intptr_t>* results) const {
|
| @@ -2535,7 +2155,7 @@ RawBool* FlowGraphOptimizer::InstanceOfAsBool(
|
|
|
|
|
| // Returns true if checking against this type is a direct class id comparison.
|
| -bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| +bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
|
| // Requires CHA.
|
| if (!type.IsInstantiated()) return false;
|
| @@ -2639,7 +2259,7 @@ static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
|
|
|
|
|
| // TODO(srdjan): Use ICData to check if always true or false.
|
| -void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| +void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeTestOperator(call->token_kind()));
|
| Definition* left = call->ArgumentAt(0);
|
| Definition* type_args = NULL;
|
| @@ -2747,7 +2367,7 @@ void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
|
|
|
|
| // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
|
| -void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| +void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeCastOperator(call->token_kind()));
|
| Definition* left = call->ArgumentAt(0);
|
| Definition* type_args = call->ArgumentAt(1);
|
| @@ -2790,7 +2410,7 @@ void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
|
| +bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
|
| for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
|
| if ((*inlining_black_list_)[i] == call_deopt_id) return true;
|
| }
|
| @@ -2798,7 +2418,7 @@ bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
|
| }
|
|
|
| // Special optimizations when running in --noopt mode.
|
| -void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
|
| +void AotOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
|
| // TODO(srdjan): Investigate other attempts, as they are not allowed to
|
| // deoptimize.
|
|
|
| @@ -2937,118 +2557,13 @@ void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
|
|
|
| // Tries to optimize instance call by replacing it with a faster instruction
|
| // (e.g, binary op, field load, ..).
|
| -void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| - if (FLAG_precompilation) {
|
| - InstanceCallNoopt(instr);
|
| - return;
|
| - }
|
| -
|
| - if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
|
| - return;
|
| - }
|
| - const Token::Kind op_kind = instr->token_kind();
|
| -
|
| - // Type test is special as it always gets converted into inlined code.
|
| - if (Token::IsTypeTestOperator(op_kind)) {
|
| - ReplaceWithInstanceOf(instr);
|
| - return;
|
| - }
|
| -
|
| - if (Token::IsTypeCastOperator(op_kind)) {
|
| - ReplaceWithTypeCast(instr);
|
| - return;
|
| - }
|
| -
|
| - const ICData& unary_checks =
|
| - ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
|
| -
|
| - const 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, RawFunction::kRegularFunction)) {
|
| - // Too many checks, it will be megamorphic which needs unary checks.
|
| - instr->set_ic_data(&unary_checks);
|
| - return;
|
| - }
|
| -
|
| - if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
|
| - return;
|
| - }
|
| - if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
|
| - return;
|
| - }
|
| -
|
| - if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) {
|
| - return;
|
| - }
|
| -
|
| - if (Token::IsRelationalOperator(op_kind) &&
|
| - TryReplaceWithRelationalOp(instr, op_kind)) {
|
| - return;
|
| - }
|
| -
|
| - if (Token::IsBinaryOperator(op_kind) &&
|
| - TryReplaceWithBinaryOp(instr, op_kind)) {
|
| - return;
|
| - }
|
| - if (Token::IsUnaryOperator(op_kind) &&
|
| - TryReplaceWithUnaryOp(instr, op_kind)) {
|
| - return;
|
| - }
|
| - if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
|
| - return;
|
| - }
|
| - if ((op_kind == Token::kSET) &&
|
| - TryInlineInstanceSetter(instr, unary_checks)) {
|
| - return;
|
| - }
|
| - if (TryInlineInstanceMethod(instr)) {
|
| - return;
|
| - }
|
| -
|
| - bool has_one_target = unary_checks.HasOneTarget();
|
| -
|
| - if (has_one_target) {
|
| - // Check if the single target is a polymorphic target, if it is,
|
| - // we don't have one target.
|
| - const Function& target =
|
| - Function::Handle(Z, unary_checks.GetTargetAt(0));
|
| - const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
|
| - has_one_target = !polymorphic_target;
|
| - }
|
| -
|
| - if (has_one_target) {
|
| - RawFunction::Kind function_kind =
|
| - Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
|
| - if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
|
| - PolymorphicInstanceCallInstr* call =
|
| - new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
|
| - /* call_with_checks = */ false);
|
| - instr->ReplaceWith(call, current_iterator());
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
|
| - bool call_with_checks;
|
| - if (has_one_target && FLAG_polymorphic_with_deopt) {
|
| - // Type propagation has not run yet, we cannot eliminate the check.
|
| - AddReceiverCheck(instr);
|
| - // Call can still deoptimize, do not detach environment from instr.
|
| - call_with_checks = false;
|
| - } else {
|
| - call_with_checks = true;
|
| - }
|
| - PolymorphicInstanceCallInstr* call =
|
| - new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
|
| - call_with_checks);
|
| - instr->ReplaceWith(call, current_iterator());
|
| - }
|
| +void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| + ASSERT(FLAG_precompilation);
|
| + InstanceCallNoopt(instr);
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| +void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| if (!CanUnboxDouble()) {
|
| return;
|
| }
|
| @@ -3070,17 +2585,11 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| break;
|
| }
|
| if (unary_kind != MathUnaryInstr::kIllegal) {
|
| - if (FLAG_precompilation) {
|
| - // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
|
| - return;
|
| - }
|
| - MathUnaryInstr* math_unary =
|
| - new(Z) MathUnaryInstr(unary_kind,
|
| - new(Z) Value(call->ArgumentAt(0)),
|
| - call->deopt_id());
|
| - ReplaceCall(call, math_unary);
|
| + ASSERT(FLAG_precompilation);
|
| + // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
|
| return;
|
| }
|
| +
|
| switch (recognized_kind) {
|
| case MethodRecognizer::kFloat32x4Zero:
|
| case MethodRecognizer::kFloat32x4Splat:
|
| @@ -3156,24 +2665,9 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| case MethodRecognizer::kMathAcos:
|
| case MethodRecognizer::kMathAtan:
|
| case MethodRecognizer::kMathAtan2: {
|
| - if (FLAG_precompilation) {
|
| - // No UnboxDouble instructons allowed.
|
| - return;
|
| - }
|
| - // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
|
| - // instructions contain type checks and conversions to double.
|
| - ZoneGrowableArray<Value*>* args =
|
| - new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
|
| - for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
| - args->Add(new(Z) Value(call->ArgumentAt(i)));
|
| - }
|
| - InvokeMathCFunctionInstr* invoke =
|
| - new(Z) InvokeMathCFunctionInstr(args,
|
| - call->deopt_id(),
|
| - recognized_kind,
|
| - call->token_pos());
|
| - ReplaceCall(call, invoke);
|
| - break;
|
| + ASSERT(FLAG_precompilation);
|
| + // No UnboxDouble instructions allowed.
|
| + return;
|
| }
|
| case MethodRecognizer::kDoubleFromInteger: {
|
| if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
|
| @@ -3229,61 +2723,7 @@ void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::VisitStoreInstanceField(
|
| - StoreInstanceFieldInstr* instr) {
|
| - if (instr->IsUnboxedStore()) {
|
| - ASSERT(instr->is_potential_unboxed_initialization_);
|
| - // Determine if this field should be unboxed based on the usage of getter
|
| - // and setter functions: The heuristic requires that the setter has a
|
| - // usage count of at least 1/kGetterSetterRatio of the getter usage count.
|
| - // This is to avoid unboxing fields where the setter is never or rarely
|
| - // executed.
|
| - const Field& field = Field::ZoneHandle(Z, instr->field().raw());
|
| - const String& field_name = String::Handle(Z, field.name());
|
| - const Class& owner = Class::Handle(Z, field.owner());
|
| - const Function& getter =
|
| - Function::Handle(Z, owner.LookupGetterFunction(field_name));
|
| - const Function& setter =
|
| - Function::Handle(Z, owner.LookupSetterFunction(field_name));
|
| - bool unboxed_field = false;
|
| - if (!getter.IsNull() && !setter.IsNull()) {
|
| - if (field.is_double_initialized()) {
|
| - unboxed_field = true;
|
| - } else if ((setter.usage_counter() > 0) &&
|
| - ((FLAG_getter_setter_ratio * setter.usage_counter()) >=
|
| - getter.usage_counter())) {
|
| - unboxed_field = true;
|
| - }
|
| - }
|
| - if (!unboxed_field) {
|
| - // TODO(srdjan): Instead of aborting pass this field to the mutator thread
|
| - // so that it can:
|
| - // - set it to unboxed
|
| - // - deoptimize dependent code.
|
| - if (Compiler::IsBackgroundCompilation()) {
|
| - isolate()->AddDeoptimizingBoxedField(field);
|
| - Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
|
| - UNREACHABLE();
|
| - }
|
| - if (FLAG_trace_optimization || FLAG_trace_field_guards) {
|
| - THR_Print("Disabling unboxing of %s\n", field.ToCString());
|
| - if (!setter.IsNull()) {
|
| - OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter());
|
| - }
|
| - if (!getter.IsNull()) {
|
| - OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter());
|
| - }
|
| - }
|
| - field.set_is_unboxing_candidate(false);
|
| - field.DeoptimizeDependentCode();
|
| - } else {
|
| - flow_graph()->parsed_function().AddToGuardedFields(&field);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
|
| +void AotOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
|
| // Replace generic allocation with a sequence of inlined allocation and
|
| // explicit initalizing stores.
|
| AllocateUninitializedContextInstr* replacement =
|
| @@ -3318,7 +2758,7 @@ void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
|
| }
|
|
|
|
|
| -void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| +void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
|
| #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
|
| if (!instr->can_pack_into_smi())
|
| @@ -3327,7 +2767,7 @@ void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| }
|
|
|
|
|
| -bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| +bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| const ICData& unary_ic_data,
|
| bool allow_checks) {
|
| ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
|
| @@ -3402,9 +2842,8 @@ bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| kEmitStoreBarrier,
|
| instr->token_pos());
|
|
|
| - if (store->IsUnboxedStore()) {
|
| - flow_graph()->parsed_function().AddToGuardedFields(&field);
|
| - }
|
| + // No unboxed stores in precompiled code.
|
| + ASSERT(!store->IsUnboxedStore());
|
|
|
| // Discard the environment from the original instruction because the store
|
| // can't deoptimize.
|
|
|