| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/exceptions.h" |
| 11 #include "vm/flow_graph_builder.h" | 12 #include "vm/flow_graph_builder.h" |
| 12 #include "vm/flow_graph_compiler.h" | 13 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/hash_map.h" | 14 #include "vm/hash_map.h" |
| 14 #include "vm/il_printer.h" | 15 #include "vm/il_printer.h" |
| 15 #include "vm/intermediate_language.h" | 16 #include "vm/intermediate_language.h" |
| 16 #include "vm/object_store.h" | 17 #include "vm/object_store.h" |
| 17 #include "vm/parser.h" | 18 #include "vm/parser.h" |
| 18 #include "vm/resolver.h" | 19 #include "vm/resolver.h" |
| 19 #include "vm/scopes.h" | 20 #include "vm/scopes.h" |
| 20 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 40 "Print live sets for load optimization pass."); | 41 "Print live sets for load optimization pass."); |
| 41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 42 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 43 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 43 DEFINE_FLAG(bool, truncating_left_shift, true, | 44 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 44 "Optimize left shift to truncate if possible"); | 45 "Optimize left shift to truncate if possible"); |
| 45 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 46 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 46 DECLARE_FLAG(bool, eliminate_type_checks); | 47 DECLARE_FLAG(bool, eliminate_type_checks); |
| 47 DECLARE_FLAG(bool, enable_type_checks); | 48 DECLARE_FLAG(bool, enable_type_checks); |
| 48 DECLARE_FLAG(bool, source_lines); | 49 DECLARE_FLAG(bool, source_lines); |
| 49 DECLARE_FLAG(bool, trace_type_check_elimination); | 50 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 51 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
| 50 | 52 |
| 51 static bool ShouldInlineSimd() { | 53 static bool ShouldInlineSimd() { |
| 52 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 54 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 53 } | 55 } |
| 54 | 56 |
| 55 | 57 |
| 56 // Optimize instance calls using ICData. | 58 // Optimize instance calls using ICData. |
| 57 void FlowGraphOptimizer::ApplyICData() { | 59 void FlowGraphOptimizer::ApplyICData() { |
| 58 VisitBlocks(); | 60 VisitBlocks(); |
| 59 } | 61 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 | 105 |
| 104 | 106 |
| 105 // Attempt to build ICData for call using propagated class-ids. | 107 // Attempt to build ICData for call using propagated class-ids. |
| 106 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 108 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 107 ASSERT(call->HasICData()); | 109 ASSERT(call->HasICData()); |
| 108 if (call->ic_data()->NumberOfChecks() > 0) { | 110 if (call->ic_data()->NumberOfChecks() > 0) { |
| 109 // This occurs when an instance call has too many checks, will be converted | 111 // This occurs when an instance call has too many checks, will be converted |
| 110 // to megamorphic call. | 112 // to megamorphic call. |
| 111 return false; | 113 return false; |
| 112 } | 114 } |
| 115 if (FLAG_warn_on_javascript_compatibility) { |
| 116 // Do not make the instance call megamorphic if the callee needs to decode |
| 117 // the calling code sequence to lookup the ic data and verify if a warning |
| 118 // has already been issued or not. |
| 119 // TryCreateICData is only invoked if the ic_data target has not been called |
| 120 // yet, so no warning can possibly have been issued. |
| 121 ASSERT(!call->ic_data()->IssuedJSWarning()); |
| 122 if (call->ic_data()->MayCheckForJSWarning()) { |
| 123 return false; |
| 124 } |
| 125 } |
| 113 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 126 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| 114 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 127 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
| 115 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 128 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
| 116 const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); | 129 const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); |
| 117 class_ids.Add(cid); | 130 class_ids.Add(cid); |
| 118 } | 131 } |
| 119 | 132 |
| 120 const Token::Kind op_kind = call->token_kind(); | 133 const Token::Kind op_kind = call->token_kind(); |
| 121 if (Token::IsRelationalOperator(op_kind) || | 134 if (Token::IsRelationalOperator(op_kind) || |
| 122 Token::IsEqualityOperator(op_kind) || | 135 Token::IsEqualityOperator(op_kind) || |
| (...skipping 3742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3865 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 3878 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 3866 Definition* left = call->ArgumentAt(0); | 3879 Definition* left = call->ArgumentAt(0); |
| 3867 Definition* instantiator = call->ArgumentAt(1); | 3880 Definition* instantiator = call->ArgumentAt(1); |
| 3868 Definition* type_args = call->ArgumentAt(2); | 3881 Definition* type_args = call->ArgumentAt(2); |
| 3869 const AbstractType& type = | 3882 const AbstractType& type = |
| 3870 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 3883 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 3871 const bool negate = Bool::Cast( | 3884 const bool negate = Bool::Cast( |
| 3872 call->ArgumentAt(4)->OriginalDefinition()->AsConstant()->value()).value(); | 3885 call->ArgumentAt(4)->OriginalDefinition()->AsConstant()->value()).value(); |
| 3873 const ICData& unary_checks = | 3886 const ICData& unary_checks = |
| 3874 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 3887 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 3888 if (FLAG_warn_on_javascript_compatibility && |
| 3889 !unary_checks.IssuedJSWarning() && |
| 3890 (type.IsIntType() || type.IsDoubleType() || !type.IsInstantiated())) { |
| 3891 // No warning was reported yet for this type check, either because it has |
| 3892 // not been executed yet, or because no problematic combinations of instance |
| 3893 // type and test type have been encountered so far. A warning may still be |
| 3894 // reported, so do not replace the instance call. |
| 3895 return; |
| 3896 } |
| 3875 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 3897 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 3876 ZoneGrowableArray<intptr_t>* results = | 3898 ZoneGrowableArray<intptr_t>* results = |
| 3877 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); | 3899 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); |
| 3878 Bool& as_bool = | 3900 Bool& as_bool = |
| 3879 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); | 3901 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); |
| 3880 if (as_bool.IsNull()) { | 3902 if (as_bool.IsNull()) { |
| 3881 if (results->length() == unary_checks.NumberOfChecks() * 2) { | 3903 if (results->length() == unary_checks.NumberOfChecks() * 2) { |
| 3882 const bool can_deopt = TryExpandTestCidsResult(results, type); | 3904 const bool can_deopt = TryExpandTestCidsResult(results, type); |
| 3883 TestCidsInstr* test_cids = new TestCidsInstr( | 3905 TestCidsInstr* test_cids = new TestCidsInstr( |
| 3884 call->token_pos(), | 3906 call->token_pos(), |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3946 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 3968 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 3947 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 3969 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 3948 Definition* left = call->ArgumentAt(0); | 3970 Definition* left = call->ArgumentAt(0); |
| 3949 Definition* instantiator = call->ArgumentAt(1); | 3971 Definition* instantiator = call->ArgumentAt(1); |
| 3950 Definition* type_args = call->ArgumentAt(2); | 3972 Definition* type_args = call->ArgumentAt(2); |
| 3951 const AbstractType& type = | 3973 const AbstractType& type = |
| 3952 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 3974 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 3953 ASSERT(!type.IsMalformedOrMalbounded()); | 3975 ASSERT(!type.IsMalformedOrMalbounded()); |
| 3954 const ICData& unary_checks = | 3976 const ICData& unary_checks = |
| 3955 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 3977 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 3978 if (FLAG_warn_on_javascript_compatibility && |
| 3979 !unary_checks.IssuedJSWarning() && |
| 3980 (type.IsIntType() || type.IsDoubleType() || !type.IsInstantiated())) { |
| 3981 // No warning was reported yet for this type check, either because it has |
| 3982 // not been executed yet, or because no problematic combinations of instance |
| 3983 // type and test type have been encountered so far. A warning may still be |
| 3984 // reported, so do not replace the instance call. |
| 3985 return; |
| 3986 } |
| 3956 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 3987 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 3957 ZoneGrowableArray<intptr_t>* results = | 3988 ZoneGrowableArray<intptr_t>* results = |
| 3958 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); | 3989 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); |
| 3959 const Bool& as_bool = | 3990 const Bool& as_bool = |
| 3960 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); | 3991 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); |
| 3961 if (as_bool.raw() == Bool::True().raw()) { | 3992 if (as_bool.raw() == Bool::True().raw()) { |
| 3962 AddReceiverCheck(call); | 3993 AddReceiverCheck(call); |
| 3963 // Remove the original push arguments. | 3994 // Remove the original push arguments. |
| 3964 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 3995 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 3965 PushArgumentInstr* push = call->PushArgumentAt(i); | 3996 PushArgumentInstr* push = call->PushArgumentAt(i); |
| (...skipping 5552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9518 } | 9549 } |
| 9519 | 9550 |
| 9520 // Insert materializations at environment uses. | 9551 // Insert materializations at environment uses. |
| 9521 for (intptr_t i = 0; i < exits.length(); i++) { | 9552 for (intptr_t i = 0; i < exits.length(); i++) { |
| 9522 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); | 9553 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); |
| 9523 } | 9554 } |
| 9524 } | 9555 } |
| 9525 | 9556 |
| 9526 | 9557 |
| 9527 } // namespace dart | 9558 } // namespace dart |
| OLD | NEW |