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/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
13 #include "vm/exceptions.h" | 13 #include "vm/exceptions.h" |
14 #include "vm/flow_graph_builder.h" | 14 #include "vm/flow_graph_builder.h" |
15 #include "vm/flow_graph_compiler.h" | 15 #include "vm/flow_graph_compiler.h" |
16 #include "vm/flow_graph_inliner.h" | 16 #include "vm/flow_graph_inliner.h" |
17 #include "vm/flow_graph_range_analysis.h" | 17 #include "vm/flow_graph_range_analysis.h" |
18 #include "vm/hash_map.h" | 18 #include "vm/hash_map.h" |
19 #include "vm/il_printer.h" | 19 #include "vm/il_printer.h" |
20 #include "vm/intermediate_language.h" | 20 #include "vm/intermediate_language.h" |
21 #include "vm/object_store.h" | 21 #include "vm/object_store.h" |
22 #include "vm/parser.h" | 22 #include "vm/parser.h" |
23 #include "vm/precompiler.h" | |
24 #include "vm/resolver.h" | 23 #include "vm/resolver.h" |
25 #include "vm/scopes.h" | 24 #include "vm/scopes.h" |
26 #include "vm/stack_frame.h" | 25 #include "vm/stack_frame.h" |
27 #include "vm/symbols.h" | 26 #include "vm/symbols.h" |
28 | 27 |
29 namespace dart { | 28 namespace dart { |
30 | 29 |
31 DEFINE_FLAG(int, getter_setter_ratio, 13, | 30 DEFINE_FLAG(int, getter_setter_ratio, 13, |
32 "Ratio of getter/setter usage used for double field unboxing heuristics"); | 31 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
33 DEFINE_FLAG(bool, guess_icdata_cid, true, | 32 DEFINE_FLAG(bool, guess_icdata_cid, true, |
34 "Artificially create type feedback for arithmetic etc. operations" | 33 "Artificially create type feedback for arithmetic etc. operations" |
35 " by guessing the other unknown argument cid"); | 34 " by guessing the other unknown argument cid"); |
36 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 35 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
37 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 36 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | 37 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
39 "Maximum number of polymorphic checks in equality operator," | 38 "Maximum number of polymorphic checks in equality operator," |
40 " otherwise use megamorphic dispatch."); | 39 " otherwise use megamorphic dispatch."); |
41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); | 40 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); |
42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 41 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
43 DEFINE_FLAG(bool, truncating_left_shift, true, | 42 DEFINE_FLAG(bool, truncating_left_shift, true, |
44 "Optimize left shift to truncate if possible"); | 43 "Optimize left shift to truncate if possible"); |
45 DEFINE_FLAG(bool, use_cha_deopt, true, | 44 DEFINE_FLAG(bool, use_cha_deopt, true, |
46 "Use class hierarchy analysis even if it can cause deoptimization."); | 45 "Use class hierarchy analysis even if it can cause deoptimization."); |
47 | 46 |
48 DECLARE_FLAG(bool, precompilation); | |
49 DECLARE_FLAG(bool, polymorphic_with_deopt); | 47 DECLARE_FLAG(bool, polymorphic_with_deopt); |
50 DECLARE_FLAG(bool, trace_cha); | 48 DECLARE_FLAG(bool, trace_cha); |
51 DECLARE_FLAG(bool, trace_field_guards); | 49 DECLARE_FLAG(bool, trace_field_guards); |
52 | 50 |
53 // Quick access to the current isolate and zone. | 51 // Quick access to the current isolate and zone. |
54 #define I (isolate()) | 52 #define I (isolate()) |
55 #define Z (zone()) | 53 #define Z (zone()) |
56 | 54 |
57 static bool ShouldInlineSimd() { | 55 static bool ShouldInlineSimd() { |
58 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 56 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
59 } | 57 } |
60 | 58 |
61 | 59 |
62 static bool CanUnboxDouble() { | 60 static bool CanUnboxDouble() { |
63 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 61 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
64 } | 62 } |
65 | 63 |
66 | 64 |
67 static bool CanConvertUnboxedMintToDouble() { | 65 static bool CanConvertUnboxedMintToDouble() { |
68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 66 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
69 } | 67 } |
70 | 68 |
71 | 69 |
72 // Optimize instance calls using ICData. | 70 // Optimize instance calls using ICData. |
73 void FlowGraphOptimizer::ApplyICData() { | 71 void FlowGraphOptimizer::ApplyICData() { |
74 VisitBlocks(); | 72 VisitBlocks(); |
75 } | 73 } |
76 | 74 |
77 | 75 |
78 void FlowGraphOptimizer::PopulateWithICData() { | |
79 ASSERT(current_iterator_ == NULL); | |
80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | |
81 !block_it.Done(); | |
82 block_it.Advance()) { | |
83 ForwardInstructionIterator it(block_it.Current()); | |
84 for (; !it.Done(); it.Advance()) { | |
85 Instruction* instr = it.Current(); | |
86 if (instr->IsInstanceCall()) { | |
87 InstanceCallInstr* call = instr->AsInstanceCall(); | |
88 if (!call->HasICData()) { | |
89 const Array& arguments_descriptor = | |
90 Array::Handle(zone(), | |
91 ArgumentsDescriptor::New(call->ArgumentCount(), | |
92 call->argument_names())); | |
93 const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New( | |
94 function(), call->function_name(), | |
95 arguments_descriptor, call->deopt_id(), | |
96 call->checked_argument_count())); | |
97 call->set_ic_data(&ic_data); | |
98 } | |
99 } | |
100 } | |
101 current_iterator_ = NULL; | |
102 } | |
103 } | |
104 | |
105 | |
106 // Optimize instance calls using cid. This is called after optimizer | 76 // Optimize instance calls using cid. This is called after optimizer |
107 // converted instance calls to instructions. Any remaining | 77 // converted instance calls to instructions. Any remaining |
108 // instance calls are either megamorphic calls, cannot be optimized or | 78 // instance calls are either megamorphic calls, cannot be optimized or |
109 // have no runtime type feedback collected. | 79 // have no runtime type feedback collected. |
110 // Attempts to convert an instance call (IC call) using propagated class-ids, | 80 // Attempts to convert an instance call (IC call) using propagated class-ids, |
111 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 81 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
112 void FlowGraphOptimizer::ApplyClassIds() { | 82 void FlowGraphOptimizer::ApplyClassIds() { |
113 ASSERT(current_iterator_ == NULL); | 83 ASSERT(current_iterator_ == NULL); |
114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 84 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
115 !block_it.Done(); | 85 !block_it.Done(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 if (class_ids.length() > 1) { | 180 if (class_ids.length() > 1) { |
211 ic_data.AddCheck(class_ids, function); | 181 ic_data.AddCheck(class_ids, function); |
212 } else { | 182 } else { |
213 ASSERT(class_ids.length() == 1); | 183 ASSERT(class_ids.length() == 1); |
214 ic_data.AddReceiverCheck(class_ids[0], function); | 184 ic_data.AddReceiverCheck(class_ids[0], function); |
215 } | 185 } |
216 call->set_ic_data(&ic_data); | 186 call->set_ic_data(&ic_data); |
217 return true; | 187 return true; |
218 } | 188 } |
219 | 189 |
220 #ifdef DART_PRECOMPILER | |
221 if (FLAG_precompilation && | |
222 (isolate()->object_store()->unique_dynamic_targets() != Array::null())) { | |
223 // Check if the target is unique. | |
224 Function& target_function = Function::Handle(Z); | |
225 Precompiler::GetUniqueDynamicTarget( | |
226 isolate(), call->function_name(), &target_function); | |
227 // Calls with named arguments must be resolved/checked at runtime. | |
228 String& error_message = String::Handle(Z); | |
229 if (!target_function.IsNull() && | |
230 !target_function.HasOptionalNamedParameters() && | |
231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | |
232 &error_message)) { | |
233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | |
234 const ICData& ic_data = ICData::ZoneHandle(Z, | |
235 ICData::NewFrom(*call->ic_data(), 1)); | |
236 ic_data.AddReceiverCheck(cid, target_function); | |
237 call->set_ic_data(&ic_data); | |
238 return true; | |
239 } | |
240 } | |
241 #endif | |
242 | |
243 // Check if getter or setter in function's class and class is currently leaf. | 190 // Check if getter or setter in function's class and class is currently leaf. |
244 if (FLAG_guess_icdata_cid && | 191 if (FLAG_guess_icdata_cid && |
245 ((call->token_kind() == Token::kGET) || | 192 ((call->token_kind() == Token::kGET) || |
246 (call->token_kind() == Token::kSET))) { | 193 (call->token_kind() == Token::kSET))) { |
247 const Class& owner_class = Class::Handle(Z, function().Owner()); | 194 const Class& owner_class = Class::Handle(Z, function().Owner()); |
248 if (!owner_class.is_abstract() && | 195 if (!owner_class.is_abstract() && |
249 !CHA::HasSubclasses(owner_class) && | 196 !CHA::HasSubclasses(owner_class) && |
250 !CHA::IsImplemented(owner_class)) { | 197 !CHA::IsImplemented(owner_class)) { |
251 const Array& args_desc_array = Array::Handle(Z, | 198 const Array& args_desc_array = Array::Handle(Z, |
252 ArgumentsDescriptor::New(call->ArgumentCount(), | 199 ArgumentsDescriptor::New(call->ArgumentCount(), |
(...skipping 1796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2049 return true; | 1996 return true; |
2050 } | 1997 } |
2051 } | 1998 } |
2052 return false; | 1999 return false; |
2053 } | 2000 } |
2054 | 2001 |
2055 | 2002 |
2056 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | 2003 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( |
2057 StaticCallInstr* call, | 2004 StaticCallInstr* call, |
2058 MethodRecognizer::Kind recognized_kind) { | 2005 MethodRecognizer::Kind recognized_kind) { |
2059 if (FLAG_precompilation) { | |
2060 // Cannot handle unboxed instructions. | |
2061 return false; | |
2062 } | |
2063 if (!ShouldInlineSimd()) { | 2006 if (!ShouldInlineSimd()) { |
2064 return false; | 2007 return false; |
2065 } | 2008 } |
2066 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | 2009 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { |
2067 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); | 2010 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); |
2068 ReplaceCall(call, zero); | 2011 ReplaceCall(call, zero); |
2069 return true; | 2012 return true; |
2070 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | 2013 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { |
2071 Float32x4SplatInstr* splat = | 2014 Float32x4SplatInstr* splat = |
2072 new(Z) Float32x4SplatInstr( | 2015 new(Z) Float32x4SplatInstr( |
(...skipping 23 matching lines...) Expand all Loading... |
2096 ReplaceCall(call, cast); | 2039 ReplaceCall(call, cast); |
2097 return true; | 2040 return true; |
2098 } | 2041 } |
2099 return false; | 2042 return false; |
2100 } | 2043 } |
2101 | 2044 |
2102 | 2045 |
2103 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( | 2046 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( |
2104 StaticCallInstr* call, | 2047 StaticCallInstr* call, |
2105 MethodRecognizer::Kind recognized_kind) { | 2048 MethodRecognizer::Kind recognized_kind) { |
2106 if (FLAG_precompilation) { | |
2107 // Cannot handle unboxed instructions. | |
2108 return false; | |
2109 } | |
2110 if (!ShouldInlineSimd()) { | 2049 if (!ShouldInlineSimd()) { |
2111 return false; | 2050 return false; |
2112 } | 2051 } |
2113 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { | 2052 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { |
2114 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); | 2053 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); |
2115 ReplaceCall(call, zero); | 2054 ReplaceCall(call, zero); |
2116 return true; | 2055 return true; |
2117 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { | 2056 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { |
2118 Float64x2SplatInstr* splat = | 2057 Float64x2SplatInstr* splat = |
2119 new(Z) Float64x2SplatInstr( | 2058 new(Z) Float64x2SplatInstr( |
(...skipping 15 matching lines...) Expand all Loading... |
2135 ReplaceCall(call, cast); | 2074 ReplaceCall(call, cast); |
2136 return true; | 2075 return true; |
2137 } | 2076 } |
2138 return false; | 2077 return false; |
2139 } | 2078 } |
2140 | 2079 |
2141 | 2080 |
2142 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( | 2081 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( |
2143 StaticCallInstr* call, | 2082 StaticCallInstr* call, |
2144 MethodRecognizer::Kind recognized_kind) { | 2083 MethodRecognizer::Kind recognized_kind) { |
2145 if (FLAG_precompilation) { | |
2146 // Cannot handle unboxed instructions. | |
2147 return false; | |
2148 } | |
2149 if (!ShouldInlineSimd()) { | 2084 if (!ShouldInlineSimd()) { |
2150 return false; | 2085 return false; |
2151 } | 2086 } |
2152 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { | 2087 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { |
2153 Int32x4BoolConstructorInstr* con = | 2088 Int32x4BoolConstructorInstr* con = |
2154 new(Z) Int32x4BoolConstructorInstr( | 2089 new(Z) Int32x4BoolConstructorInstr( |
2155 new(Z) Value(call->ArgumentAt(1)), | 2090 new(Z) Value(call->ArgumentAt(1)), |
2156 new(Z) Value(call->ArgumentAt(2)), | 2091 new(Z) Value(call->ArgumentAt(2)), |
2157 new(Z) Value(call->ArgumentAt(3)), | 2092 new(Z) Value(call->ArgumentAt(3)), |
2158 new(Z) Value(call->ArgumentAt(4)), | 2093 new(Z) Value(call->ArgumentAt(4)), |
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2929 /* with_checks = */ false); | 2864 /* with_checks = */ false); |
2930 instr->ReplaceWith(call, current_iterator()); | 2865 instr->ReplaceWith(call, current_iterator()); |
2931 return; | 2866 return; |
2932 } | 2867 } |
2933 } | 2868 } |
2934 | 2869 |
2935 | 2870 |
2936 // Tries to optimize instance call by replacing it with a faster instruction | 2871 // Tries to optimize instance call by replacing it with a faster instruction |
2937 // (e.g, binary op, field load, ..). | 2872 // (e.g, binary op, field load, ..). |
2938 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2873 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
2939 if (FLAG_precompilation) { | |
2940 InstanceCallNoopt(instr); | |
2941 return; | |
2942 } | |
2943 | |
2944 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 2874 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
2945 return; | 2875 return; |
2946 } | 2876 } |
2947 const Token::Kind op_kind = instr->token_kind(); | 2877 const Token::Kind op_kind = instr->token_kind(); |
2948 | 2878 |
2949 // Type test is special as it always gets converted into inlined code. | 2879 // Type test is special as it always gets converted into inlined code. |
2950 if (Token::IsTypeTestOperator(op_kind)) { | 2880 if (Token::IsTypeTestOperator(op_kind)) { |
2951 ReplaceWithInstanceOf(instr); | 2881 ReplaceWithInstanceOf(instr); |
2952 return; | 2882 return; |
2953 } | 2883 } |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3061 unary_kind = MathUnaryInstr::kSin; | 2991 unary_kind = MathUnaryInstr::kSin; |
3062 break; | 2992 break; |
3063 case MethodRecognizer::kMathCos: | 2993 case MethodRecognizer::kMathCos: |
3064 unary_kind = MathUnaryInstr::kCos; | 2994 unary_kind = MathUnaryInstr::kCos; |
3065 break; | 2995 break; |
3066 default: | 2996 default: |
3067 unary_kind = MathUnaryInstr::kIllegal; | 2997 unary_kind = MathUnaryInstr::kIllegal; |
3068 break; | 2998 break; |
3069 } | 2999 } |
3070 if (unary_kind != MathUnaryInstr::kIllegal) { | 3000 if (unary_kind != MathUnaryInstr::kIllegal) { |
3071 if (FLAG_precompilation) { | |
3072 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | |
3073 return; | |
3074 } | |
3075 MathUnaryInstr* math_unary = | 3001 MathUnaryInstr* math_unary = |
3076 new(Z) MathUnaryInstr(unary_kind, | 3002 new(Z) MathUnaryInstr(unary_kind, |
3077 new(Z) Value(call->ArgumentAt(0)), | 3003 new(Z) Value(call->ArgumentAt(0)), |
3078 call->deopt_id()); | 3004 call->deopt_id()); |
3079 ReplaceCall(call, math_unary); | 3005 ReplaceCall(call, math_unary); |
3080 return; | 3006 return; |
3081 } | 3007 } |
3082 switch (recognized_kind) { | 3008 switch (recognized_kind) { |
3083 case MethodRecognizer::kFloat32x4Zero: | 3009 case MethodRecognizer::kFloat32x4Zero: |
3084 case MethodRecognizer::kFloat32x4Splat: | 3010 case MethodRecognizer::kFloat32x4Splat: |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3147 } | 3073 } |
3148 } | 3074 } |
3149 break; | 3075 break; |
3150 } | 3076 } |
3151 case MethodRecognizer::kMathDoublePow: | 3077 case MethodRecognizer::kMathDoublePow: |
3152 case MethodRecognizer::kMathTan: | 3078 case MethodRecognizer::kMathTan: |
3153 case MethodRecognizer::kMathAsin: | 3079 case MethodRecognizer::kMathAsin: |
3154 case MethodRecognizer::kMathAcos: | 3080 case MethodRecognizer::kMathAcos: |
3155 case MethodRecognizer::kMathAtan: | 3081 case MethodRecognizer::kMathAtan: |
3156 case MethodRecognizer::kMathAtan2: { | 3082 case MethodRecognizer::kMathAtan2: { |
3157 if (FLAG_precompilation) { | |
3158 // No UnboxDouble instructons allowed. | |
3159 return; | |
3160 } | |
3161 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | 3083 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble |
3162 // instructions contain type checks and conversions to double. | 3084 // instructions contain type checks and conversions to double. |
3163 ZoneGrowableArray<Value*>* args = | 3085 ZoneGrowableArray<Value*>* args = |
3164 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 3086 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
3165 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 3087 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
3166 args->Add(new(Z) Value(call->ArgumentAt(i))); | 3088 args->Add(new(Z) Value(call->ArgumentAt(i))); |
3167 } | 3089 } |
3168 InvokeMathCFunctionInstr* invoke = | 3090 InvokeMathCFunctionInstr* invoke = |
3169 new(Z) InvokeMathCFunctionInstr(args, | 3091 new(Z) InvokeMathCFunctionInstr(args, |
3170 call->deopt_id(), | 3092 call->deopt_id(), |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3406 | 3328 |
3407 // Discard the environment from the original instruction because the store | 3329 // Discard the environment from the original instruction because the store |
3408 // can't deoptimize. | 3330 // can't deoptimize. |
3409 instr->RemoveEnvironment(); | 3331 instr->RemoveEnvironment(); |
3410 ReplaceCall(instr, store); | 3332 ReplaceCall(instr, store); |
3411 return true; | 3333 return true; |
3412 } | 3334 } |
3413 | 3335 |
3414 | 3336 |
3415 } // namespace dart | 3337 } // namespace dart |
OLD | NEW |