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