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 |