Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: runtime/vm/intermediate_language.cc

Issue 2809583002: Use off-heap data for type feedback in PolymorphicInstanceCallInstr (Closed)
Patch Set: More feedback from Slava Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698