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

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

Issue 2842753002: Reland "Use off-heap data for type feedback in PolymorphicInstanceCallInstr" (Closed)
Patch Set: Fix AOT case 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 2723 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
2744 // Shared code generation methods (EmitNativeCode and 2842 // Shared code generation methods (EmitNativeCode and
2745 // MakeLocationSummary). Only assembly code that can be shared across all 2843 // MakeLocationSummary). Only assembly code that can be shared across all
2746 // architectures can be used. Machine specific register allocation and code 2844 // architectures can be used. Machine specific register allocation and code
2747 // generation is located in intermediate_language_<arch>.cc 2845 // generation is located in intermediate_language_<arch>.cc
2748 2846
2749 #define __ compiler->assembler()-> 2847 #define __ compiler->assembler()->
2750 2848
2751 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone, 2849 LocationSummary* GraphEntryInstr::MakeLocationSummary(Zone* zone,
2752 bool optimizing) const { 2850 bool optimizing) const {
2753 UNREACHABLE(); 2851 UNREACHABLE();
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
3162 } 3260 }
3163 #endif // !defined(TARGET_ARCH_DBC) 3261 #endif // !defined(TARGET_ARCH_DBC)
3164 } 3262 }
3165 3263
3166 3264
3167 bool InstanceCallInstr::MatchesCoreName(const String& name) { 3265 bool InstanceCallInstr::MatchesCoreName(const String& name) {
3168 return function_name().raw() == Library::PrivateCoreLibName(name).raw(); 3266 return function_name().raw() == Library::PrivateCoreLibName(name).raw();
3169 } 3267 }
3170 3268
3171 3269
3172 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { 3270 bool CallTargets::HasSingleRecognizedTarget() const {
3173 if (FLAG_precompiled_mode && with_checks()) return false; 3271 if (!HasSingleTarget()) return false;
3174 3272 return MethodRecognizer::RecognizeKind(FirstTarget()) !=
3175 return ic_data().HasOneTarget() && 3273 MethodRecognizer::kUnknown;
3176 (MethodRecognizer::RecognizeKind(Function::Handle(
3177 ic_data().GetTargetAt(0))) != MethodRecognizer::kUnknown);
3178 } 3274 }
3179 3275
3180 3276
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
3181 // DBC does not support optimizing compiler and thus doesn't emit 3344 // DBC does not support optimizing compiler and thus doesn't emit
3182 // PolymorphicInstanceCallInstr. 3345 // PolymorphicInstanceCallInstr.
3183 #if !defined(TARGET_ARCH_DBC) 3346 #if !defined(TARGET_ARCH_DBC)
3184 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 3347 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
3185 ASSERT(ic_data().NumArgsTested() == 1);
3186 if (!with_checks()) { 3348 if (!with_checks()) {
3187 ASSERT(ic_data().HasOneTarget()); 3349 ASSERT(targets().HasSingleTarget());
3188 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); 3350 const Function& target = targets().FirstTarget();
3189 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), 3351 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(),
3190 target, instance_call()->ArgumentCount(), 3352 target, instance_call()->ArgumentCount(),
3191 instance_call()->argument_names(), locs(), 3353 instance_call()->argument_names(), locs(),
3192 ICData::Handle()); 3354 ICData::Handle());
3193 return; 3355 return;
3194 } 3356 }
3195 3357
3196 compiler->EmitPolymorphicInstanceCall( 3358 compiler->EmitPolymorphicInstanceCall(
3197 ic_data(), instance_call()->ArgumentCount(), 3359 targets_, *instance_call(), instance_call()->ArgumentCount(),
3198 instance_call()->argument_names(), deopt_id(), 3360 instance_call()->argument_names(), deopt_id(),
3199 instance_call()->token_pos(), locs(), complete(), total_call_count()); 3361 instance_call()->token_pos(), locs(), complete(), total_call_count());
3200 } 3362 }
3201 #endif 3363 #endif
3202 3364
3203 3365
3204 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( 3366 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType(
3205 const ICData& ic_data) { 3367 const CallTargets& targets) {
3206 bool is_string = true; 3368 bool is_string = true;
3207 bool is_integer = true; 3369 bool is_integer = true;
3208 bool is_double = true; 3370 bool is_double = true;
3209 3371
3210 const intptr_t num_checks = ic_data.NumberOfChecks(); 3372 const intptr_t num_checks = targets.length();
3211 for (intptr_t i = 0; i < num_checks; i++) { 3373 for (intptr_t i = 0; i < num_checks; i++) {
3212 const intptr_t cid = ic_data.GetReceiverClassIdAt(i); 3374 ASSERT(targets[i].target->raw() == targets[0].target->raw());
3213 is_string = is_string && RawObject::IsStringClassId(cid); 3375 const intptr_t start = targets[i].cid_start;
3214 is_integer = is_integer && RawObject::IsIntegerClassId(cid); 3376 const intptr_t end = targets[i].cid_end;
3215 is_double = is_double && (cid == kDoubleCid); 3377 for (intptr_t cid = start; cid <= end; cid++) {
3378 is_string = is_string && RawObject::IsStringClassId(cid);
3379 is_integer = is_integer && RawObject::IsIntegerClassId(cid);
3380 is_double = is_double && (cid == kDoubleCid);
3381 }
3216 } 3382 }
3217 3383
3218 if (is_string) { 3384 if (is_string) {
3385 ASSERT(!is_integer);
3386 ASSERT(!is_double);
3219 return Type::StringType(); 3387 return Type::StringType();
3220 } else if (is_integer) { 3388 } else if (is_integer) {
3389 ASSERT(!is_double);
3221 return Type::IntType(); 3390 return Type::IntType();
3222 } else if (is_double) { 3391 } else if (is_double) {
3223 return Type::Double(); 3392 return Type::Double();
3224 } 3393 }
3225 3394
3226 return Type::null(); 3395 return Type::null();
3227 } 3396 }
3228 3397
3229 3398
3230 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { 3399 Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) {
3231 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); 3400 const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid();
3232 3401
3233 if (!HasICData()) return this; 3402 // TODO(erikcorry): Even for cold call sites we could still try to look up
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;
3234 3407
3235 const ICData& new_ic_data = 3408 const CallTargets* new_target =
3236 FlowGraphCompiler::TrySpecializeICDataByReceiverCid(*ic_data(), 3409 FlowGraphCompiler::ResolveCallTargetsForReceiverCid(
3237 receiver_cid); 3410 receiver_cid,
3238 if (new_ic_data.raw() == ic_data()->raw()) { 3411 String::Handle(flow_graph->zone(), ic_data()->target_name()),
3412 Array::Handle(flow_graph->zone(), ic_data()->arguments_descriptor()));
3413 if (new_target == NULL) {
3239 // No specialization. 3414 // No specialization.
3240 return this; 3415 return this;
3241 } 3416 }
3242 3417
3243 const bool with_checks = false; 3418 const bool with_checks = false;
3244 const bool complete = false; 3419 const bool complete = false;
3245 PolymorphicInstanceCallInstr* specialized = new PolymorphicInstanceCallInstr( 3420 PolymorphicInstanceCallInstr* specialized = new PolymorphicInstanceCallInstr(
3246 this, new_ic_data, with_checks, complete); 3421 this, *new_target, with_checks, complete);
3247 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); 3422 flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue);
3248 return specialized; 3423 return specialized;
3249 } 3424 }
3250 3425
3251 3426
3252 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { 3427 Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) {
3253 if (!HasSingleRecognizedTarget() || with_checks()) { 3428 if (!IsSureToCallSingleRecognizedTarget()) {
3254 return this; 3429 return this;
3255 } 3430 }
3256 3431
3257 const Function& target = Function::Handle(ic_data().GetTargetAt(0)); 3432 const Function& target = targets().FirstTarget();
3258 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 3433 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
3259 const AbstractType& type = 3434 const AbstractType& type =
3260 AbstractType::Handle(ComputeRuntimeType(ic_data())); 3435 AbstractType::Handle(ComputeRuntimeType(targets_));
3261 if (!type.IsNull()) { 3436 if (!type.IsNull()) {
3262 return flow_graph->GetConstant(type); 3437 return flow_graph->GetConstant(type);
3263 } 3438 }
3264 } 3439 }
3265 3440
3266 return this; 3441 return this;
3267 } 3442 }
3268 3443
3269 3444
3445 bool PolymorphicInstanceCallInstr::IsSureToCallSingleRecognizedTarget() const {
3446 if (FLAG_precompiled_mode && with_checks()) return false;
3447 return targets_.HasSingleRecognizedTarget();
3448 }
3449
3450
3270 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) { 3451 Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) {
3271 if (!FLAG_precompiled_mode) { 3452 if (!FLAG_precompiled_mode) {
3272 return this; 3453 return this;
3273 } 3454 }
3274 3455
3275 if (function().recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 3456 if (function().recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
3276 if (input_use_list() == NULL) { 3457 if (input_use_list() == NULL) {
3277 // This function has only environment uses. In precompiled mode it is 3458 // This function has only environment uses. In precompiled mode it is
3278 // fine to remove it - because we will never deoptimize. 3459 // fine to remove it - because we will never deoptimize.
3279 return flow_graph->constant_dead(); 3460 return flow_graph->constant_dead();
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after
4002 "native function '%s' (%" Pd " arguments) cannot be found", 4183 "native function '%s' (%" Pd " arguments) cannot be found",
4003 native_name().ToCString(), function().NumParameters()); 4184 native_name().ToCString(), function().NumParameters());
4004 } 4185 }
4005 set_is_auto_scope(auto_setup_scope); 4186 set_is_auto_scope(auto_setup_scope);
4006 set_native_c_function(native_function); 4187 set_native_c_function(native_function);
4007 } 4188 }
4008 4189
4009 #undef __ 4190 #undef __
4010 4191
4011 } // namespace dart 4192 } // 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