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

Side by Side Diff: vm/code_generator.cc

Issue 8379013: Implement new inline cache. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 9 years, 1 month 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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/code_generator.h" 5 #include "vm/code_generator.h"
6 6
7 #include "vm/code_index_table.h" 7 #include "vm/code_index_table.h"
8 #include "vm/code_patcher.h" 8 #include "vm/code_patcher.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/dart_api_impl.h"
10 #include "vm/dart_entry.h" 11 #include "vm/dart_entry.h"
11 #include "vm/exceptions.h" 12 #include "vm/exceptions.h"
12 #include "vm/ic_data.h" 13 #include "vm/ic_data.h"
13 #include "vm/ic_stubs.h"
14 #include "vm/object_store.h" 14 #include "vm/object_store.h"
15 #include "vm/resolver.h" 15 #include "vm/resolver.h"
16 #include "vm/runtime_entry.h" 16 #include "vm/runtime_entry.h"
17 #include "vm/stack_frame.h" 17 #include "vm/stack_frame.h"
18 #include "vm/verifier.h" 18 #include "vm/verifier.h"
19 19
20 namespace dart { 20 namespace dart {
21 21
22 DEFINE_FLAG(bool, inline_cache, true, "enable inline caches"); 22 DEFINE_FLAG(bool, inline_cache, true, "enable inline caches");
23 DEFINE_FLAG(bool, trace_deopt, false, "Trace deoptimization"); 23 DEFINE_FLAG(bool, trace_deopt, false, "Trace deoptimization");
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 Exceptions::ReThrow(excp, stack); 414 Exceptions::ReThrow(excp, stack);
415 } 415 }
416 } 416 }
417 417
418 418
419 // Resolves an instance function and compiles it if necessary. 419 // Resolves an instance function and compiles it if necessary.
420 // Arg0: receiver object. 420 // Arg0: receiver object.
421 // Returns: RawCode object or NULL (method not found or not compileable). 421 // Returns: RawCode object or NULL (method not found or not compileable).
422 // This is called by the megamorphic stub when instance call does not need to be 422 // This is called by the megamorphic stub when instance call does not need to be
423 // patched. 423 // patched.
424 // Used by megamorphic lookup/no-such-method-handling.
424 DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) { 425 DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) {
425 ASSERT(arguments.Count() == 426 ASSERT(arguments.Count() ==
426 kResolveCompileInstanceFunctionRuntimeEntry.argument_count()); 427 kResolveCompileInstanceFunctionRuntimeEntry.argument_count());
427 const Instance& receiver = Instance::CheckedHandle(arguments.At(0)); 428 const Instance& receiver = Instance::CheckedHandle(arguments.At(0));
428 const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver)); 429 const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver));
429 arguments.SetReturn(Code::Handle(code.raw())); 430 arguments.SetReturn(Code::Handle(code.raw()));
430 } 431 }
431 432
432 433
433 // Resolve instance call and patch it to jump to IC stub or megamorphic stub. 434 // Handles inline cache misses bu updating the IC data array of the call
regis 2011/10/25 18:06:27 bu -> by
srdjan 2011/10/25 18:28:50 Done.
434 // After patching the caller's instance call instruction, that call will 435 // site.
435 // be reexecuted and ran through the created IC stub. The null receivers 436 // Arg0: Receiver object.
436 // have special handling, i.e., they lead to megamorphic lookup that implements 437 // Returns: target function with compiled code or 0.
437 // the appropriate null behavior. 438 // Modifies the instance call to hold the updated IC data array.
438 // Arg0: receiver object. 439 DEFINE_RUNTIME_ENTRY(InlineCacheMissHandler, 1) {
439 DEFINE_RUNTIME_ENTRY(ResolvePatchInstanceCall, 1) {
440 ASSERT(arguments.Count() == 440 ASSERT(arguments.Count() ==
441 kResolvePatchInstanceCallRuntimeEntry.argument_count()); 441 kInlineCacheMissHandlerRuntimeEntry.argument_count());
442 const Instance& receiver = Instance::CheckedHandle(arguments.At(0)); 442 const Instance& receiver = Instance::CheckedHandle(arguments.At(0));
443 const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver)); 443 const Code& target_code =
444 Code::Handle(ResolveCompileInstanceCallTarget(receiver));
445 if (target_code.IsNull()) {
446 // Let the megamorphic stub handle special cases: NoSuchMethod,
447 // closure calls.
448 arguments.SetReturn(target_code);
449 return;
450 }
451 const Function& target_function =
452 Function::Handle(target_code.function());
453 ASSERT(!target_function.IsNull());
454 if (receiver.IsNull()) {
455 // Null dispatch is slow (e.g., (null).toCString()). The only
456 // fast execution with null receiver is the "==" operator.
457 // Special handling so that we do not pollute the inline cache with null
458 // classes.
459 arguments.SetReturn(target_function);
460 return;
461 }
444 DartFrameIterator iterator; 462 DartFrameIterator iterator;
445 DartFrame* caller_frame = iterator.NextFrame(); 463 DartFrame* caller_frame = iterator.NextFrame();
446 String& function_name = String::Handle(); 464 ICData ic_data(Array::Handle(
447 if ((!receiver.IsNull() && code.IsNull()) || !FLAG_inline_cache) { 465 CodePatcher::GetInstanceCallIcDataAt(caller_frame->pc())));
448 // We did not find a method; it means either that we need to invoke 466 GrowableArray<const Class*> classes;
449 // noSuchMethod or that we have encountered a situation with implicit 467 classes.Add(&Class::ZoneHandle(receiver.clazz()));
450 // closures. All these cases are handled by the megamorphic lookup stub. 468 ic_data.AddCheck(classes, target_function);
451 CodePatcher::PatchInstanceCallAt( 469 CodePatcher::SetInstanceCallIcDataAt(caller_frame->pc(),
452 caller_frame->pc(), StubCode::MegamorphicLookupEntryPoint()); 470 Array::ZoneHandle(ic_data.data()));
453 if (FLAG_trace_ic) { 471 arguments.SetReturn(target_function);
454 OS::Print("IC: cannot find function at 0x%x -> megamorphic lookup.\n",
455 caller_frame->pc());
456 }
457 if (FLAG_trace_patching) {
458 OS::Print("ResolvePatchInstanceCall: patching 0x%x to megamorphic\n",
459 caller_frame->pc());
460 }
461 } else {
462 int num_arguments = -1;
463 int num_named_arguments = -1;
464 uword caller_target = 0;
465 CodePatcher::GetInstanceCallAt(caller_frame->pc(),
466 &function_name,
467 &num_arguments,
468 &num_named_arguments,
469 &caller_target);
470 // If caller_target is not in CallInstanceFunction stub (resolve call)
471 // then it must be pointing to an IC stub.
472 const Class& receiver_class = Class::ZoneHandle(receiver.clazz());
473 const bool ic_miss =
474 !StubCode::InCallInstanceFunctionStubCode(caller_target);
475 GrowableArray<const Class*> classes;
476 GrowableArray<const Function*> targets;
477 if (ic_miss) {
478 bool is_ic =
479 ICStubs::RecognizeICStub(caller_target, &classes, &targets);
480 ASSERT(is_ic);
481 ASSERT(classes.length() == targets.length());
482 // The returned classes array can be empty if the first patch occured
483 // with a null class. 'receiver_class' should not exists.
484 ASSERT(ICStubs::IndexOfClass(classes, receiver_class) < 0);
485 ASSERT(!code.IsNull());
486 ASSERT(!receiver_class.IsNullClass());
487 const Function& function = Function::ZoneHandle(code.function());
488 targets.Add(&function);
489 classes.Add(&receiver_class);
490 } else {
491 // First patch of instance call.
492 // Do not add classes for null receiver. For first IC patch it means that
493 // the IC will always miss and jump to megamorphic lookup (null handling).
494 if (!receiver_class.IsNullClass()) {
495 ASSERT(!code.IsNull());
496 const Function& function = Function::ZoneHandle(code.function());
497 targets.Add(&function);
498 classes.Add(&receiver_class);
499 }
500 }
501 const Code& ic_code = Code::Handle(ICStubs::GetICStub(classes, targets));
502 if (FLAG_trace_ic) {
503 CodeIndexTable* ci_table = Isolate::Current()->code_index_table();
504 ASSERT(ci_table != NULL);
505 const Function& caller =
506 Function::Handle(ci_table->LookupFunction(caller_frame->pc()));
507 const char* patch_kind = ic_miss ? "miss" : "patch";
508 OS::Print("IC %s at 0x%x '%s' (receiver:'%s' function:'%s')",
509 patch_kind,
510 caller_frame->pc(),
511 String::Handle(caller.name()).ToCString(),
512 receiver.ToCString(),
513 function_name.ToCString());
514 OS::Print(" patched to 0x%x\n", ic_code.EntryPoint());
515 if (ic_miss) {
516 for (int i = 0; i < classes.length(); i++) {
517 OS::Print(" IC Miss on %s\n", classes[i]->ToCString());
518 }
519 }
520 }
521 CodePatcher::PatchInstanceCallAt(caller_frame->pc(), ic_code.EntryPoint());
522 if (FLAG_trace_patching) {
523 OS::Print("ResolvePatchInstanceCall: patching 0x%x to ic 0x%x\n",
524 caller_frame->pc(), ic_code.EntryPoint());
525 }
526 }
527 } 472 }
528 473
529 474
530 static RawFunction* LookupDynamicFunction(const Class& in_cls, 475 static RawFunction* LookupDynamicFunction(const Class& in_cls,
531 const String& name) { 476 const String& name) {
532 Class& cls = Class::Handle(); 477 Class& cls = Class::Handle();
533 // For lookups treat null as an instance of class Object. 478 // For lookups treat null as an instance of class Object.
534 if (in_cls.IsNullClass()) { 479 if (in_cls.IsNullClass()) {
535 cls = Isolate::Current()->object_store()->object_class(); 480 cls = Isolate::Current()->object_store()->object_class();
536 } else { 481 } else {
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 uword old_stack_limit = Isolate::Current()->stack_limit(); 735 uword old_stack_limit = Isolate::Current()->stack_limit();
791 Isolate::Current()->AdjustStackLimitForException(); 736 Isolate::Current()->AdjustStackLimitForException();
792 // Recursive stack overflow check. 737 // Recursive stack overflow check.
793 ASSERT(old_stack_limit != Isolate::Current()->stack_limit()); 738 ASSERT(old_stack_limit != Isolate::Current()->stack_limit());
794 GrowableArray<const Object*> args; 739 GrowableArray<const Object*> args;
795 Exceptions::ThrowByType(Exceptions::kStackOverflow, args); 740 Exceptions::ThrowByType(Exceptions::kStackOverflow, args);
796 Isolate::Current()->ResetStackLimitAfterException(); 741 Isolate::Current()->ResetStackLimitAfterException();
797 } 742 }
798 743
799 744
800 static void DisableOldCode(const Function& function,
801 const Code& old_code,
802 const Code& new_code) {
803 const Array& class_ic_stubs = Array::Handle(old_code.class_ic_stubs());
804 if (function.IsClosureFunction()) {
805 // Nothing to do, code may not have inline caches.
806 ASSERT(class_ic_stubs.Length() == 0);
807 return;
808 }
809 if (function.is_static() || function.IsConstructor()) {
810 ASSERT(class_ic_stubs.Length() == 0);
811 return;
812 }
813 Code& ic_stub = Code::Handle();
814 for (int i = 0; i < class_ic_stubs.Length(); i += 2) {
815 // i: array of classes, i + 1: ic stub code.
816 ic_stub ^= class_ic_stubs.At(i + 1);
817 ICStubs::PatchTargets(ic_stub.EntryPoint(),
818 old_code.EntryPoint(),
819 new_code.EntryPoint());
820 }
821 new_code.set_class_ic_stubs(class_ic_stubs);
822 old_code.set_class_ic_stubs(Array::Handle(Array::Empty()));
823 }
824
825
826 // Only unoptimized code has invocation counter threshold checking. 745 // Only unoptimized code has invocation counter threshold checking.
827 // Once the invocation counter threshold is reached any entry into the 746 // Once the invocation counter threshold is reached any entry into the
828 // unoptimized code is redirected to this function. 747 // unoptimized code is redirected to this function.
829 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) { 748 DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) {
830 ASSERT(arguments.Count() == 749 ASSERT(arguments.Count() ==
831 kOptimizeInvokedFunctionRuntimeEntry.argument_count()); 750 kOptimizeInvokedFunctionRuntimeEntry.argument_count());
832 const Function& function = Function::CheckedHandle(arguments.At(0)); 751 const Function& function = Function::CheckedHandle(arguments.At(0));
833 if (function.is_optimizable()) { 752 if (function.is_optimizable()) {
834 ASSERT(!Code::Handle(function.code()).is_optimized()); 753 ASSERT(!Code::Handle(function.code()).is_optimized());
835 const Code& unoptimized_code = Code::Handle(function.code()); 754 const Code& unoptimized_code = Code::Handle(function.code());
836 // Compilation patches the entry of unoptimized code. 755 // Compilation patches the entry of unoptimized code.
837 Compiler::CompileOptimizedFunction(function); 756 Compiler::CompileOptimizedFunction(function);
838 const Code& optimized_code = Code::Handle(function.code()); 757 const Code& optimized_code = Code::Handle(function.code());
839 ASSERT(!optimized_code.IsNull()); 758 ASSERT(!optimized_code.IsNull());
840 ASSERT(!unoptimized_code.IsNull()); 759 ASSERT(!unoptimized_code.IsNull());
841 DisableOldCode(function, unoptimized_code, optimized_code);
842 } else { 760 } else {
843 // TODO(5442338): Abort as this should not happen. 761 // TODO(5442338): Abort as this should not happen.
844 function.set_invocation_counter(0); 762 function.set_invocation_counter(0);
845 } 763 }
846 } 764 }
847 765
848 766
849 // The caller must be a static call in a Dart frame, or an entry frame. 767 // The caller must be a static call in a Dart frame, or an entry frame.
850 // Patch static call to point to 'new_entry_point'. 768 // Patch static call to point to 'new_entry_point'.
851 DEFINE_RUNTIME_ENTRY(FixCallersTarget, 1) { 769 DEFINE_RUNTIME_ENTRY(FixCallersTarget, 1) {
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 function.set_invocation_counter(0); 841 function.set_invocation_counter(0);
924 function.set_deoptimization_counter(function.deoptimization_counter() + 1); 842 function.set_deoptimization_counter(function.deoptimization_counter() + 1);
925 843
926 // We have to skip the following otherwise the compiler will complain 844 // We have to skip the following otherwise the compiler will complain
927 // when it attempts to install unoptimized code into a function that 845 // when it attempts to install unoptimized code into a function that
928 // was already deoptimized. 846 // was already deoptimized.
929 if (Code::Handle(function.code()).is_optimized()) { 847 if (Code::Handle(function.code()).is_optimized()) {
930 // Get unoptimized code. Compilation restores (reenables) the entry of 848 // Get unoptimized code. Compilation restores (reenables) the entry of
931 // unoptimized code. 849 // unoptimized code.
932 Compiler::CompileFunction(function); 850 Compiler::CompileFunction(function);
933
934 DisableOldCode(function, optimized_code, unoptimized_code);
935 } 851 }
936 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized 852 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized
937 // code is alive on frame and gets deoptimized after the function was 853 // code is alive on frame and gets deoptimized after the function was
938 // optimized a second time. 854 // optimized a second time.
939 if (FLAG_trace_deopt) { 855 if (FLAG_trace_deopt) {
940 OS::Print("After patching ->0x%x:\n", continue_at_pc); 856 OS::Print("After patching ->0x%x:\n", continue_at_pc);
941 } 857 }
942 } 858 }
943 859
944 860
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1015 } 931 }
1016 } 932 }
1017 } 933 }
1018 // The cache is null terminated, therefore the loop above should never 934 // The cache is null terminated, therefore the loop above should never
1019 // terminate by itself. 935 // terminate by itself.
1020 UNREACHABLE(); 936 UNREACHABLE();
1021 return Code::null(); 937 return Code::null();
1022 } 938 }
1023 939
1024 } // namespace dart 940 } // namespace dart
OLDNEW
« no previous file with comments | « vm/code_generator.h ('k') | vm/code_generator_ia32.cc » ('j') | vm/stub_code.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698