| 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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/bootstrap.h" | 8 #include "vm/bootstrap.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/constant_propagator.h" | 10 #include "vm/constant_propagator.h" |
| (...skipping 2723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2734 case kUnboxedInt32x4: | 2734 case kUnboxedInt32x4: |
| 2735 return false; | 2735 return false; |
| 2736 | 2736 |
| 2737 default: | 2737 default: |
| 2738 UNREACHABLE(); | 2738 UNREACHABLE(); |
| 2739 return false; | 2739 return false; |
| 2740 } | 2740 } |
| 2741 } | 2741 } |
| 2742 | 2742 |
| 2743 | 2743 |
| 2744 static int OrderById(const CidRangeTarget* a, const CidRangeTarget* b) { | |
| 2745 // Negative if 'a' should sort before 'b'. | |
| 2746 ASSERT(a->cid_start == a->cid_end); | |
| 2747 ASSERT(b->cid_start == b->cid_end); | |
| 2748 return a->cid_start - b->cid_start; | |
| 2749 } | |
| 2750 | |
| 2751 | |
| 2752 static int OrderByFrequency(const CidRangeTarget* a, const CidRangeTarget* b) { | |
| 2753 // Negative if 'a' should sort before 'b'. | |
| 2754 return b->count - a->count; | |
| 2755 } | |
| 2756 | |
| 2757 | |
| 2758 CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) { | |
| 2759 CallTargets* targets = new (zone) CallTargets(); | |
| 2760 if (ic_data.NumberOfChecks() == 0) return targets; | |
| 2761 | |
| 2762 Function& dummy = Function::Handle(zone); | |
| 2763 | |
| 2764 bool check_one_arg = ic_data.NumArgsTested() == 1; | |
| 2765 | |
| 2766 int checks = ic_data.NumberOfChecks(); | |
| 2767 for (int i = 0; i < checks; i++) { | |
| 2768 intptr_t id = 0; | |
| 2769 if (check_one_arg) { | |
| 2770 ic_data.GetOneClassCheckAt(i, &id, &dummy); | |
| 2771 } else { | |
| 2772 // The API works for multi dispatch ICs that check more than one | |
| 2773 // argument, but we know we will only check one arg here, so only the 0th | |
| 2774 // element of id will be used. | |
| 2775 GrowableArray<intptr_t> arg_ids; | |
| 2776 ic_data.GetCheckAt(i, &arg_ids, &dummy); | |
| 2777 id = arg_ids[0]; | |
| 2778 } | |
| 2779 Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i)); | |
| 2780 targets->Add(CidRangeTarget(id, id, &function, ic_data.GetCountAt(i))); | |
| 2781 } | |
| 2782 | |
| 2783 targets->Sort(OrderById); | |
| 2784 | |
| 2785 Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor()); | |
| 2786 ArgumentsDescriptor args_desc(args_desc_array); | |
| 2787 String& name = String::Handle(zone, ic_data.target_name()); | |
| 2788 | |
| 2789 Function& fn = Function::Handle(zone); | |
| 2790 | |
| 2791 intptr_t length = targets->length(); | |
| 2792 | |
| 2793 // Spread class-ids to preceding classes where a lookup yields the same | |
| 2794 // method. | |
| 2795 for (int idx = 0; idx < length; idx++) { | |
| 2796 int lower_limit_cid = (idx == 0) ? -1 : targets->At(idx - 1).cid_end; | |
| 2797 const Function& target = *targets->At(idx).target; | |
| 2798 for (int i = targets->At(idx).cid_start - 1; i > lower_limit_cid; i--) { | |
| 2799 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && | |
| 2800 fn.raw() == target.raw()) { | |
| 2801 CidRangeTarget t = targets->At(idx); | |
| 2802 t.cid_start = i; | |
| 2803 (*targets)[idx] = t; | |
| 2804 } else { | |
| 2805 break; | |
| 2806 } | |
| 2807 } | |
| 2808 } | |
| 2809 // Spread class-ids to following classes where a lookup yields the same | |
| 2810 // method. | |
| 2811 for (int idx = 0; idx < length; idx++) { | |
| 2812 int upper_limit_cid = | |
| 2813 (idx == length - 1) ? 1000000000 : targets->At(idx + 1).cid_start; | |
| 2814 const Function& target = *targets->At(idx).target; | |
| 2815 for (int i = targets->At(idx).cid_end + 1; i < upper_limit_cid; i++) { | |
| 2816 if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn) && | |
| 2817 fn.raw() == target.raw()) { | |
| 2818 (*targets)[idx].cid_end = i; | |
| 2819 } else { | |
| 2820 break; | |
| 2821 } | |
| 2822 } | |
| 2823 } | |
| 2824 // Merge adjacent class id ranges. | |
| 2825 int dest = 0; | |
| 2826 for (int src = 1; src < length; src++) { | |
| 2827 if (targets->At(dest).cid_end + 1 == targets->At(src).cid_start && | |
| 2828 targets->At(dest).target->raw() == targets->At(src).target->raw()) { | |
| 2829 (*targets)[dest].cid_end = targets->At(src).cid_end; | |
| 2830 (*targets)[dest].count += targets->At(src).count; | |
| 2831 } else { | |
| 2832 dest++; | |
| 2833 if (src != dest) (*targets)[dest] = targets->At(src); | |
| 2834 } | |
| 2835 } | |
| 2836 targets->SetLength(dest + 1); | |
| 2837 targets->Sort(OrderByFrequency); | |
| 2838 return targets; | |
| 2839 } | |
| 2840 | |
| 2841 | |
| 2842 // Shared code generation methods (EmitNativeCode and | 2744 // Shared code generation methods (EmitNativeCode and |
| 2843 // MakeLocationSummary). Only assembly code that can be shared across all | 2745 // MakeLocationSummary). Only assembly code that can be shared across all |
| 2844 // architectures can be used. Machine specific register allocation and code | 2746 // architectures can be used. Machine specific register allocation and code |
| 2845 // generation is located in intermediate_language_<arch>.cc | 2747 // generation is located in intermediate_language_<arch>.cc |
| 2846 | 2748 |
| 2847 #define __ compiler->assembler()-> | 2749 #define __ compiler->assembler()-> |
| 2848 | 2750 |
| 2849 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, | 2751 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, |
| 2850 bool optimizing) const { | 2752 bool optimizing) const { |
| 2851 UNREACHABLE(); | 2753 UNREACHABLE(); |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3260 } | 3162 } |
| 3261 #endif // !defined(TARGET_ARCH_DBC) | 3163 #endif // !defined(TARGET_ARCH_DBC) |
| 3262 } | 3164 } |
| 3263 | 3165 |
| 3264 | 3166 |
| 3265 bool InstanceCallInstr::MatchesCoreName(const String& name) { | 3167 bool InstanceCallInstr::MatchesCoreName(const String& name) { |
| 3266 return function_name().raw() == Library::PrivateCoreLibName(name).raw(); | 3168 return function_name().raw() == Library::PrivateCoreLibName(name).raw(); |
| 3267 } | 3169 } |
| 3268 | 3170 |
| 3269 | 3171 |
| 3270 bool CallTargets::HasSingleRecognizedTarget() const { | 3172 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { |
| 3271 if (!HasSingleTarget()) return false; | 3173 if (FLAG_precompiled_mode && with_checks()) return false; |
| 3272 return MethodRecognizer::RecognizeKind(FirstTarget()) != | 3174 |
| 3273 MethodRecognizer::kUnknown; | 3175 return ic_data().HasOneTarget() && |
| 3176 (MethodRecognizer::RecognizeKind(Function::Handle( |
| 3177 ic_data().GetTargetAt(0))) != MethodRecognizer::kUnknown); |
| 3274 } | 3178 } |
| 3275 | 3179 |
| 3276 | 3180 |
| 3277 bool CallTargets::HasSingleTarget() const { | |
| 3278 ASSERT(length() != 0); | |
| 3279 for (int i = 0; i < length(); i++) { | |
| 3280 if (cid_ranges_[i].target->raw() != cid_ranges_[0].target->raw()) | |
| 3281 return false; | |
| 3282 } | |
| 3283 return true; | |
| 3284 } | |
| 3285 | |
| 3286 | |
| 3287 bool CallTargets::IsMonomorphic() const { | |
| 3288 if (length() != 1) return false; | |
| 3289 return cid_ranges_[0].cid_start == cid_ranges_[0].cid_end; | |
| 3290 } | |
| 3291 | |
| 3292 | |
| 3293 intptr_t CallTargets::MonomorphicReceiverCid() const { | |
| 3294 ASSERT(IsMonomorphic()); | |
| 3295 return cid_ranges_[0].cid_start; | |
| 3296 } | |
| 3297 | |
| 3298 | |
| 3299 Function& CallTargets::FirstTarget() const { | |
| 3300 ASSERT(length() != 0); | |
| 3301 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | |
| 3302 return *cid_ranges_[0].target; | |
| 3303 } | |
| 3304 | |
| 3305 | |
| 3306 Function& CallTargets::MostPopularTarget() const { | |
| 3307 ASSERT(length() != 0); | |
| 3308 ASSERT(cid_ranges_[0].target->IsZoneHandle()); | |
| 3309 for (int i = 1; i < length(); i++) { | |
| 3310 ASSERT(cid_ranges_[i].count <= cid_ranges_[0].count); | |
| 3311 } | |
| 3312 return *cid_ranges_[0].target; | |
| 3313 } | |
| 3314 | |
| 3315 | |
| 3316 intptr_t CallTargets::AggregateCallCount() const { | |
| 3317 intptr_t sum = 0; | |
| 3318 for (int i = 0; i < length(); i++) { | |
| 3319 sum += cid_ranges_[i].count; | |
| 3320 } | |
| 3321 return sum; | |
| 3322 } | |
| 3323 | |
| 3324 | |
| 3325 bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() | |
| 3326 const { | |
| 3327 const intptr_t len = targets_.length(); | |
| 3328 Function& target = Function::Handle(); | |
| 3329 for (intptr_t i = 0; i < len; i++) { | |
| 3330 target ^= targets_[i].target->raw(); | |
| 3331 if (!target.IsDispatcherOrImplicitAccessor()) { | |
| 3332 return false; | |
| 3333 } | |
| 3334 } | |
| 3335 return true; | |
| 3336 } | |
| 3337 | |
| 3338 | |
| 3339 intptr_t PolymorphicInstanceCallInstr::CallCount() const { | |
| 3340 return targets().AggregateCallCount(); | |
| 3341 } | |
| 3342 | |
| 3343 | |
| 3344 // DBC does not support optimizing compiler and thus doesn't emit | 3181 // DBC does not support optimizing compiler and thus doesn't emit |
| 3345 // PolymorphicInstanceCallInstr. | 3182 // PolymorphicInstanceCallInstr. |
| 3346 #if !defined(TARGET_ARCH_DBC) | 3183 #if !defined(TARGET_ARCH_DBC) |
| 3347 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3184 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3185 ASSERT(ic_data().NumArgsTested() == 1); |
| 3348 if (!with_checks()) { | 3186 if (!with_checks()) { |
| 3349 ASSERT(targets().HasSingleTarget()); | 3187 ASSERT(ic_data().HasOneTarget()); |
| 3350 const Function& target = targets().FirstTarget(); | 3188 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| 3351 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), | 3189 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), |
| 3352 target, instance_call()->ArgumentCount(), | 3190 target, instance_call()->ArgumentCount(), |
| 3353 instance_call()->argument_names(), locs(), | 3191 instance_call()->argument_names(), locs(), |
| 3354 ICData::Handle()); | 3192 ICData::Handle()); |
| 3355 return; | 3193 return; |
| 3356 } | 3194 } |
| 3357 | 3195 |
| 3358 compiler->EmitPolymorphicInstanceCall( | 3196 compiler->EmitPolymorphicInstanceCall( |
| 3359 targets_, *instance_call(), instance_call()->ArgumentCount(), | 3197 ic_data(), instance_call()->ArgumentCount(), |
| 3360 instance_call()->argument_names(), deopt_id(), | 3198 instance_call()->argument_names(), deopt_id(), |
| 3361 instance_call()->token_pos(), locs(), complete(), total_call_count()); | 3199 instance_call()->token_pos(), locs(), complete(), total_call_count()); |
| 3362 } | 3200 } |
| 3363 #endif | 3201 #endif |
| 3364 | 3202 |
| 3365 | 3203 |
| 3366 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( | 3204 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
| 3367 const CallTargets& targets) { | 3205 const ICData& ic_data) { |
| 3368 bool is_string = true; | 3206 bool is_string = true; |
| 3369 bool is_integer = true; | 3207 bool is_integer = true; |
| 3370 bool is_double = true; | 3208 bool is_double = true; |
| 3371 | 3209 |
| 3372 const intptr_t num_checks = targets.length(); | 3210 const intptr_t num_checks = ic_data.NumberOfChecks(); |
| 3373 for (intptr_t i = 0; i < num_checks; i++) { | 3211 for (intptr_t i = 0; i < num_checks; i++) { |
| 3374 ASSERT(targets[i].target->raw() == targets[0].target->raw()); | 3212 const intptr_t cid = ic_data.GetReceiverClassIdAt(i); |
| 3375 const intptr_t start = targets[i].cid_start; | 3213 is_string = is_string && RawObject::IsStringClassId(cid); |
| 3376 const intptr_t end = targets[i].cid_end; | 3214 is_integer = is_integer && RawObject::IsIntegerClassId(cid); |
| 3377 for (intptr_t cid = start; cid <= end; cid++) { | 3215 is_double = is_double && (cid == kDoubleCid); |
| 3378 is_string = is_string && RawObject::IsStringClassId(cid); | |
| 3379 is_integer = is_integer && RawObject::IsIntegerClassId(cid); | |
| 3380 is_double = is_double && (cid == kDoubleCid); | |
| 3381 } | |
| 3382 } | 3216 } |
| 3383 | 3217 |
| 3384 if (is_string) { | 3218 if (is_string) { |
| 3385 ASSERT(!is_integer); | |
| 3386 ASSERT(!is_double); | |
| 3387 return Type::StringType(); | 3219 return Type::StringType(); |
| 3388 } else if (is_integer) { | 3220 } else if (is_integer) { |
| 3389 ASSERT(!is_double); | |
| 3390 return Type::IntType(); | 3221 return Type::IntType(); |
| 3391 } else if (is_double) { | 3222 } else if (is_double) { |
| 3392 return Type::Double(); | 3223 return Type::Double(); |
| 3393 } | 3224 } |
| 3394 | 3225 |
| 3395 return Type::null(); | 3226 return Type::null(); |
| 3396 } | 3227 } |
| 3397 | 3228 |
| 3398 | 3229 |
| 3399 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3230 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| 3400 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); | 3231 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); |
| 3401 | 3232 |
| 3402 // TODO(erikcorry): Even for cold call sites we could still try to look up | 3233 if (!HasICData()) return this; |
| 3403 // methods when we know the receiver cid. We don't currently do this because | |
| 3404 // it turns the InstanceCall into a PolymorphicInstanceCall which doesn't get | |
| 3405 // recognized or inlined when it is cold. | |
| 3406 if (ic_data()->NumberOfUsedChecks() == 0) return this; | |
| 3407 | 3234 |
| 3408 const CallTargets* new_target = | 3235 const ICData& new_ic_data = |
| 3409 FlowGraphCompiler::ResolveCallTargetsForReceiverCid( | 3236 FlowGraphCompiler::TrySpecializeICDataByReceiverCid(*ic_data(), |
| 3410 receiver_cid, | 3237 receiver_cid); |
| 3411 String::Handle(flow_graph->zone(), ic_data()->target_name()), | 3238 if (new_ic_data.raw() == ic_data()->raw()) { |
| 3412 Array::Handle(flow_graph->zone(), ic_data()->arguments_descriptor())); | |
| 3413 if (new_target == NULL) { | |
| 3414 // No specialization. | 3239 // No specialization. |
| 3415 return this; | 3240 return this; |
| 3416 } | 3241 } |
| 3417 | 3242 |
| 3418 const bool with_checks = false; | 3243 const bool with_checks = false; |
| 3419 const bool complete = false; | 3244 const bool complete = false; |
| 3420 PolymorphicInstanceCallInstr* specialized = new PolymorphicInstanceCallInstr( | 3245 PolymorphicInstanceCallInstr* specialized = new PolymorphicInstanceCallInstr( |
| 3421 this, *new_target, with_checks, complete); | 3246 this, new_ic_data, with_checks, complete); |
| 3422 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); | 3247 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); |
| 3423 return specialized; | 3248 return specialized; |
| 3424 } | 3249 } |
| 3425 | 3250 |
| 3426 | 3251 |
| 3427 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3252 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| 3428 if (!targets().HasSingleRecognizedTarget()) { | 3253 if (!HasSingleRecognizedTarget() || with_checks()) { |
| 3429 return this; | 3254 return this; |
| 3430 } | 3255 } |
| 3431 | 3256 |
| 3432 const Function& target = targets().FirstTarget(); | 3257 const Function& target = Function::Handle(ic_data().GetTargetAt(0)); |
| 3433 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { | 3258 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
| 3434 const AbstractType& type = | 3259 const AbstractType& type = |
| 3435 AbstractType::Handle(ComputeRuntimeType(targets_)); | 3260 AbstractType::Handle(ComputeRuntimeType(ic_data())); |
| 3436 if (!type.IsNull()) { | 3261 if (!type.IsNull()) { |
| 3437 return flow_graph->GetConstant(type); | 3262 return flow_graph->GetConstant(type); |
| 3438 } | 3263 } |
| 3439 } | 3264 } |
| 3440 | 3265 |
| 3441 return this; | 3266 return this; |
| 3442 } | 3267 } |
| 3443 | 3268 |
| 3444 | 3269 |
| 3445 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) { | 3270 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| (...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4177 "native function '%s' (%" Pd " arguments) cannot be found", | 4002 "native function '%s' (%" Pd " arguments) cannot be found", |
| 4178 native_name().ToCString(), function().NumParameters()); | 4003 native_name().ToCString(), function().NumParameters()); |
| 4179 } | 4004 } |
| 4180 set_is_auto_scope(auto_setup_scope); | 4005 set_is_auto_scope(auto_setup_scope); |
| 4181 set_native_c_function(native_function); | 4006 set_native_c_function(native_function); |
| 4182 } | 4007 } |
| 4183 | 4008 |
| 4184 #undef __ | 4009 #undef __ |
| 4185 | 4010 |
| 4186 } // namespace dart | 4011 } // namespace dart |
| OLD | NEW |