| 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/aot_optimizer.h" | 5 #include "vm/aot_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" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 static bool CanUnboxDouble() { | 47 static bool CanUnboxDouble() { |
| 48 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 48 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 49 } | 49 } |
| 50 | 50 |
| 51 | 51 |
| 52 static bool CanConvertUnboxedMintToDouble() { | 52 static bool CanConvertUnboxedMintToDouble() { |
| 53 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 53 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 | 56 |
| 57 // Returns named function that is a unique dynamic target, i.e., |
| 58 // - the target is identified by its name alone, since it occurs only once. |
| 59 // - target's class has no subclasses, and neither is subclassed, i.e., |
| 60 // the receiver type can be only the function's class. |
| 61 // Returns Function::null() if there is no unique dynamic target for |
| 62 // given 'fname'. 'fname' must be a symbol. |
| 63 static void GetUniqueDynamicTarget(Isolate* isolate, |
| 64 const String& fname, |
| 65 Object* function) { |
| 66 UniqueFunctionsSet functions_set( |
| 67 isolate->object_store()->unique_dynamic_targets()); |
| 68 ASSERT(fname.IsSymbol()); |
| 69 *function = functions_set.GetOrNull(fname); |
| 70 ASSERT(functions_set.Release().raw() == |
| 71 isolate->object_store()->unique_dynamic_targets()); |
| 72 } |
| 73 |
| 74 |
| 75 AotOptimizer::AotOptimizer(FlowGraph* flow_graph, |
| 76 bool use_speculative_inlining, |
| 77 GrowableArray<intptr_t>* inlining_black_list) |
| 78 : FlowGraphVisitor(flow_graph->reverse_postorder()), |
| 79 flow_graph_(flow_graph), |
| 80 use_speculative_inlining_(use_speculative_inlining), |
| 81 inlining_black_list_(inlining_black_list), |
| 82 has_unique_no_such_method_(false) { |
| 83 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
| 84 Function& target_function = Function::Handle(); |
| 85 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
| 86 GetUniqueDynamicTarget( |
| 87 isolate(), Symbols::NoSuchMethod(), &target_function); |
| 88 has_unique_no_such_method_ = !target_function.IsNull(); |
| 89 } |
| 90 } |
| 91 |
| 92 |
| 57 // Optimize instance calls using ICData. | 93 // Optimize instance calls using ICData. |
| 58 void AotOptimizer::ApplyICData() { | 94 void AotOptimizer::ApplyICData() { |
| 59 VisitBlocks(); | 95 VisitBlocks(); |
| 60 } | 96 } |
| 61 | 97 |
| 62 | 98 |
| 63 void AotOptimizer::PopulateWithICData() { | 99 void AotOptimizer::PopulateWithICData() { |
| 64 ASSERT(current_iterator_ == NULL); | 100 ASSERT(current_iterator_ == NULL); |
| 65 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 101 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 66 !block_it.Done(); | 102 !block_it.Done(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 } | 152 } |
| 117 } | 153 } |
| 118 | 154 |
| 119 | 155 |
| 120 // TODO(srdjan): Test/support other number types as well. | 156 // TODO(srdjan): Test/support other number types as well. |
| 121 static bool IsNumberCid(intptr_t cid) { | 157 static bool IsNumberCid(intptr_t cid) { |
| 122 return (cid == kSmiCid) || (cid == kDoubleCid); | 158 return (cid == kSmiCid) || (cid == kDoubleCid); |
| 123 } | 159 } |
| 124 | 160 |
| 125 | 161 |
| 126 // Returns named function that is a unique dynamic target, i.e., | |
| 127 // - the target is identified by its name alone, since it occurs only once. | |
| 128 // - target's class has no subclasses, and neither is subclassed, i.e., | |
| 129 // the receiver type can be only the function's class. | |
| 130 // Returns Function::null() if there is no unique dynamic target for | |
| 131 // given 'fname'. 'fname' must be a symbol. | |
| 132 static void GetUniqueDynamicTarget(Isolate* isolate, | |
| 133 const String& fname, | |
| 134 Object* function) { | |
| 135 UniqueFunctionsSet functions_set( | |
| 136 isolate->object_store()->unique_dynamic_targets()); | |
| 137 ASSERT(fname.IsSymbol()); | |
| 138 *function = functions_set.GetOrNull(fname); | |
| 139 ASSERT(functions_set.Release().raw() == | |
| 140 isolate->object_store()->unique_dynamic_targets()); | |
| 141 } | |
| 142 | |
| 143 | |
| 144 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { | 162 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 145 ASSERT(call->HasICData()); | 163 ASSERT(call->HasICData()); |
| 146 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 164 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
| 147 // This occurs when an instance call has too many checks, will be converted | 165 // This occurs when an instance call has too many checks, will be converted |
| 148 // to megamorphic call. | 166 // to megamorphic call. |
| 149 return false; | 167 return false; |
| 150 } | 168 } |
| 151 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 169 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| 152 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 170 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
| 153 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 171 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 | 238 |
| 221 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { | 239 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
| 222 // Check if the target is unique. | 240 // Check if the target is unique. |
| 223 Function& target_function = Function::Handle(Z); | 241 Function& target_function = Function::Handle(Z); |
| 224 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); | 242 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); |
| 225 // Calls with named arguments must be resolved/checked at runtime. | 243 // Calls with named arguments must be resolved/checked at runtime. |
| 226 if (!target_function.IsNull() && | 244 if (!target_function.IsNull() && |
| 227 !target_function.HasOptionalNamedParameters() && | 245 !target_function.HasOptionalNamedParameters() && |
| 228 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | 246 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, |
| 229 /* error_message = */ NULL)) { | 247 /* error_message = */ NULL)) { |
| 230 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | 248 const Class& cls = Class::Handle(Z, target_function.Owner()); |
| 231 const ICData& ic_data = ICData::ZoneHandle(Z, | 249 if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { |
| 232 ICData::NewFrom(*call->ic_data(), 1)); | 250 const ICData& ic_data = ICData::ZoneHandle(Z, |
| 233 ic_data.AddReceiverCheck(cid, target_function); | 251 ICData::NewFrom(*call->ic_data(), 1)); |
| 234 call->set_ic_data(&ic_data); | 252 ic_data.AddReceiverCheck(cls.id(), target_function); |
| 235 return true; | 253 call->set_ic_data(&ic_data); |
| 254 if (has_unique_no_such_method_) { |
| 255 call->set_has_unique_selector(true); |
| 256 } |
| 257 return true; |
| 258 } |
| 236 } | 259 } |
| 237 } | 260 } |
| 238 | 261 |
| 239 return false; | 262 return false; |
| 240 } | 263 } |
| 241 | 264 |
| 242 | 265 |
| 243 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, | 266 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 244 intptr_t cid) { | 267 intptr_t cid) { |
| 245 ASSERT(ic_data.NumArgsTested() == 1); | 268 ASSERT(ic_data.NumArgsTested() == 1); |
| (...skipping 1742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1988 PolymorphicInstanceCallInstr* call = | 2011 PolymorphicInstanceCallInstr* call = |
| 1989 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2012 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1990 /* with_checks = */ true, | 2013 /* with_checks = */ true, |
| 1991 /* complete = */ false); | 2014 /* complete = */ false); |
| 1992 instr->ReplaceWith(call, current_iterator()); | 2015 instr->ReplaceWith(call, current_iterator()); |
| 1993 return; | 2016 return; |
| 1994 } | 2017 } |
| 1995 } | 2018 } |
| 1996 | 2019 |
| 1997 | 2020 |
| 2021 void AotOptimizer::VisitPolymorphicInstanceCall( |
| 2022 PolymorphicInstanceCallInstr* call) { |
| 2023 if (call->with_checks()) { |
| 2024 const intptr_t receiver_cid = |
| 2025 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 2026 if (receiver_cid != kDynamicCid) { |
| 2027 const Class& receiver_class = Class::Handle(Z, |
| 2028 isolate()->class_table()->At(receiver_cid)); |
| 2029 |
| 2030 const Array& args_desc_array = Array::Handle(Z, |
| 2031 ArgumentsDescriptor::New(call->ArgumentCount(), |
| 2032 call->instance_call()->argument_names())); |
| 2033 ArgumentsDescriptor args_desc(args_desc_array); |
| 2034 const Function& function = Function::Handle(Z, |
| 2035 Resolver::ResolveDynamicForReceiverClass( |
| 2036 receiver_class, |
| 2037 call->instance_call()->function_name(), |
| 2038 args_desc)); |
| 2039 if (!function.IsNull()) { |
| 2040 call->set_with_checks(false); |
| 2041 } |
| 2042 } |
| 2043 } |
| 2044 } |
| 2045 |
| 2046 |
| 1998 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2047 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1999 if (!IsAllowedForInlining(call->deopt_id())) { | 2048 if (!IsAllowedForInlining(call->deopt_id())) { |
| 2000 // Inlining disabled after a speculative inlining attempt. | 2049 // Inlining disabled after a speculative inlining attempt. |
| 2001 return; | 2050 return; |
| 2002 } | 2051 } |
| 2003 MethodRecognizer::Kind recognized_kind = | 2052 MethodRecognizer::Kind recognized_kind = |
| 2004 MethodRecognizer::RecognizeKind(call->function()); | 2053 MethodRecognizer::RecognizeKind(call->function()); |
| 2005 switch (recognized_kind) { | 2054 switch (recognized_kind) { |
| 2006 case MethodRecognizer::kObjectConstructor: | 2055 case MethodRecognizer::kObjectConstructor: |
| 2007 case MethodRecognizer::kObjectArrayAllocate: | 2056 case MethodRecognizer::kObjectArrayAllocate: |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2178 check->env(), FlowGraph::kEffect); | 2227 check->env(), FlowGraph::kEffect); |
| 2179 current_iterator()->RemoveCurrentFromGraph(); | 2228 current_iterator()->RemoveCurrentFromGraph(); |
| 2180 } | 2229 } |
| 2181 } | 2230 } |
| 2182 } | 2231 } |
| 2183 } | 2232 } |
| 2184 | 2233 |
| 2185 #endif // DART_PRECOMPILER | 2234 #endif // DART_PRECOMPILER |
| 2186 | 2235 |
| 2187 } // namespace dart | 2236 } // namespace dart |
| OLD | NEW |