| Index: runtime/vm/jit_optimizer.cc
|
| diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
|
| index 41c3341e42295e174595e6835f5b78c7806d3a01..61df7ea64f5b381830aa9db3264411e16b8632b0 100644
|
| --- a/runtime/vm/jit_optimizer.cc
|
| +++ b/runtime/vm/jit_optimizer.cc
|
| @@ -36,23 +36,19 @@ static bool ShouldInlineSimd() {
|
| return FlowGraphCompiler::SupportsUnboxedSimd128();
|
| }
|
|
|
| -
|
| static bool CanUnboxDouble() {
|
| return FlowGraphCompiler::SupportsUnboxedDoubles();
|
| }
|
|
|
| -
|
| static bool CanConvertUnboxedMintToDouble() {
|
| return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
|
| }
|
|
|
| -
|
| // Optimize instance calls using ICData.
|
| void JitOptimizer::ApplyICData() {
|
| VisitBlocks();
|
| }
|
|
|
| -
|
| // 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
|
| @@ -83,13 +79,11 @@ void JitOptimizer::ApplyClassIds() {
|
| }
|
| }
|
|
|
| -
|
| // TODO(srdjan): Test/support other number types as well.
|
| static bool IsNumberCid(intptr_t cid) {
|
| return (cid == kSmiCid) || (cid == kDoubleCid);
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| if (call->ic_data()->NumberOfUsedChecks() > 0) {
|
| @@ -196,7 +190,6 @@ bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) {
|
| return false;
|
| }
|
|
|
| -
|
| void JitOptimizer::SpecializePolymorphicInstanceCall(
|
| PolymorphicInstanceCallInstr* call) {
|
| if (!FLAG_polymorphic_with_deopt) {
|
| @@ -227,7 +220,6 @@ void JitOptimizer::SpecializePolymorphicInstanceCall(
|
| call->ReplaceWith(specialized, current_iterator());
|
| }
|
|
|
| -
|
| static bool ClassIdIsOneOf(intptr_t class_id,
|
| const GrowableArray<intptr_t>& class_ids) {
|
| for (intptr_t i = 0; i < class_ids.length(); i++) {
|
| @@ -239,7 +231,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(
|
| @@ -264,7 +255,6 @@ static bool ICDataHasOnlyReceiverArgumentClassIds(
|
| return true;
|
| }
|
|
|
| -
|
| static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
|
| intptr_t receiver_class_id,
|
| intptr_t argument_class_id) {
|
| @@ -286,13 +276,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) ||
|
| @@ -303,7 +291,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;
|
| @@ -331,7 +318,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) {
|
| @@ -341,13 +327,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()) {
|
| @@ -363,7 +347,6 @@ static bool ShouldSpecializeForDouble(const ICData& ic_data) {
|
| return HasTwoDoubleOrSmi(ic_data);
|
| }
|
|
|
| -
|
| void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
|
| // Remove the original push arguments.
|
| for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
|
| @@ -374,7 +357,6 @@ void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
|
| call->ReplaceWith(replacement, current_iterator());
|
| }
|
|
|
| -
|
| void JitOptimizer::AddCheckSmi(Definition* to_check,
|
| intptr_t deopt_id,
|
| Environment* deopt_environment,
|
| @@ -387,7 +369,6 @@ void JitOptimizer::AddCheckSmi(Definition* to_check,
|
| }
|
| }
|
|
|
| -
|
| void JitOptimizer::AddCheckClass(Definition* to_check,
|
| const Cids& cids,
|
| intptr_t deopt_id,
|
| @@ -399,7 +380,6 @@ void JitOptimizer::AddCheckClass(Definition* to_check,
|
| InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
|
| }
|
|
|
| -
|
| void JitOptimizer::AddChecksForArgNr(InstanceCallInstr* call,
|
| Definition* instr,
|
| int argument_number) {
|
| @@ -407,7 +387,6 @@ void JitOptimizer::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) {
|
| @@ -424,7 +403,6 @@ static bool ArgIsAlways(intptr_t cid,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
|
| // Check for monomorphic IC data.
|
| if (!call->HasICData()) return false;
|
| @@ -437,7 +415,6 @@ bool JitOptimizer::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) {
|
| @@ -453,7 +430,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.
|
| @@ -534,7 +510,6 @@ bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
|
| return false;
|
| }
|
|
|
| -
|
| static bool SmiFitsInDouble() {
|
| return kSmiBits < 53;
|
| }
|
| @@ -578,10 +553,11 @@ bool JitOptimizer::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;
|
| }
|
| }
|
| @@ -621,7 +597,6 @@ bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -655,10 +630,11 @@ bool JitOptimizer::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;
|
| }
|
| }
|
| @@ -673,7 +649,6 @@ bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| intptr_t operands_type = kIllegalCid;
|
| @@ -787,10 +762,11 @@ bool JitOptimizer::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)
|
| @@ -861,7 +837,6 @@ bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| ASSERT(call->ArgumentCount() == 1);
|
| @@ -892,7 +867,6 @@ bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| // Using field class.
|
| RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) {
|
| Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
|
| @@ -912,7 +886,6 @@ RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) {
|
| return Field::null();
|
| }
|
|
|
| -
|
| bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| const ICData& ic_data = *call->ic_data();
|
| @@ -950,7 +923,6 @@ bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -970,7 +942,6 @@ bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -989,7 +960,6 @@ bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| Token::Kind op_kind) {
|
| if (!ShouldInlineSimd()) {
|
| @@ -1008,7 +978,6 @@ bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
|
| return true;
|
| }
|
|
|
| -
|
| // Only unique implicit instance getters can be currently handled.
|
| bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| @@ -1033,7 +1002,6 @@ bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
|
| return InlineImplicitInstanceGetter(call);
|
| }
|
|
|
| -
|
| void JitOptimizer::ReplaceWithMathCFunction(
|
| InstanceCallInstr* call,
|
| MethodRecognizer::Kind recognized_kind) {
|
| @@ -1048,7 +1016,6 @@ void JitOptimizer::ReplaceWithMathCFunction(
|
| ReplaceCall(call, invoke);
|
| }
|
|
|
| -
|
| // Inline only simple, frequently called core library methods.
|
| bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
| ASSERT(call->HasICData());
|
| @@ -1129,7 +1096,6 @@ bool JitOptimizer::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.
|
| @@ -1197,7 +1163,6 @@ RawBool* JitOptimizer::InstanceOfAsBool(
|
| return results_differ ? Bool::null() : prev.raw();
|
| }
|
|
|
| -
|
| // Returns true if checking against this type is a direct class id comparison.
|
| bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
|
| @@ -1244,7 +1209,6 @@ bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
|
| return true;
|
| }
|
|
|
| -
|
| // TODO(srdjan): Use ICData to check if always true or false.
|
| void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeTestOperator(call->token_kind()));
|
| @@ -1321,7 +1285,6 @@ void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
| ReplaceCall(call, instance_of);
|
| }
|
|
|
| -
|
| // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
|
| void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| ASSERT(Token::IsTypeCastOperator(call->token_kind()));
|
| @@ -1362,7 +1325,6 @@ void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
| ReplaceCall(call, assert_as);
|
| }
|
|
|
| -
|
| // Tries to optimize instance call by replacing it with a faster instruction
|
| // (e.g, binary op, field load, ..).
|
| void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| @@ -1479,7 +1441,6 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| }
|
| }
|
|
|
| -
|
| void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| MethodRecognizer::Kind recognized_kind =
|
| MethodRecognizer::RecognizeKind(call->function());
|
| @@ -1562,7 +1523,6 @@ void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
|
| }
|
| }
|
|
|
| -
|
| void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) {
|
| if (instr->IsUnboxedStore()) {
|
| // Determine if this field should be unboxed based on the usage of getter
|
| @@ -1616,7 +1576,6 @@ void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) {
|
| }
|
| }
|
|
|
| -
|
| void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
|
| // Replace generic allocation with a sequence of inlined allocation and
|
| // explicit initializing stores.
|
| @@ -1647,7 +1606,6 @@ void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
|
| }
|
| }
|
|
|
| -
|
| void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
|
| #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
|
| @@ -1655,7 +1613,6 @@ void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
|
| #endif
|
| }
|
|
|
| -
|
| bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| const ICData& unary_ic_data) {
|
| ASSERT(!unary_ic_data.NumberOfChecksIs(0) &&
|
| @@ -1695,17 +1652,19 @@ bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| }
|
| if (field.guarded_cid() != kDynamicCid) {
|
| ASSERT(I->use_field_guards());
|
| - InsertBefore(
|
| - instr, new (Z) GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)),
|
| - field, instr->deopt_id()),
|
| - instr->env(), FlowGraph::kEffect);
|
| + InsertBefore(instr,
|
| + new (Z)
|
| + GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)),
|
| + field, instr->deopt_id()),
|
| + instr->env(), FlowGraph::kEffect);
|
| }
|
|
|
| if (field.needs_length_check()) {
|
| ASSERT(I->use_field_guards());
|
| - InsertBefore(instr, new (Z) GuardFieldLengthInstr(
|
| - new (Z) Value(instr->ArgumentAt(1)), field,
|
| - instr->deopt_id()),
|
| + InsertBefore(instr,
|
| + new (Z)
|
| + GuardFieldLengthInstr(new (Z) Value(instr->ArgumentAt(1)),
|
| + field, instr->deopt_id()),
|
| instr->env(), FlowGraph::kEffect);
|
| }
|
|
|
| @@ -1726,6 +1685,5 @@ bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
|
| return true;
|
| }
|
|
|
| -
|
| } // namespace dart
|
| #endif // DART_PRECOMPILED_RUNTIME
|
|
|