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

Side by Side Diff: src/interpreter/interpreter-assembler.cc

Issue 2225923003: [Interpreter] Collect type feedback for 'new' in the bytecode handler (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: updated mjsunit.status Created 4 years, 3 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
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/interpreter/interpreter-assembler.h" 5 #include "src/interpreter/interpreter-assembler.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <ostream> 8 #include <ostream>
9 9
10 #include "src/code-factory.h" 10 #include "src/code-factory.h"
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 482
483 Variable return_value(this, MachineRepresentation::kTagged); 483 Variable return_value(this, MachineRepresentation::kTagged);
484 Label handle_monomorphic(this), extra_checks(this), end(this), call(this); 484 Label handle_monomorphic(this), extra_checks(this), end(this), call(this);
485 485
486 // Slot id of 0 is used to indicate no typefeedback is available. Call using 486 // Slot id of 0 is used to indicate no typefeedback is available. Call using
487 // call builtin. 487 // call builtin.
488 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); 488 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
489 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); 489 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
490 GotoIf(is_feedback_unavailable, &call); 490 GotoIf(is_feedback_unavailable, &call);
491 491
492 // The checks. First, does rdi match the recorded monomorphic target? 492 // The checks. First, does function match the recorded monomorphic target?
493 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); 493 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
494 Node* feedback_value = LoadWeakCellValue(feedback_element); 494 Node* feedback_value = LoadWeakCellValue(feedback_element);
495 Node* is_monomorphic = WordEqual(function, feedback_value); 495 Node* is_monomorphic = WordEqual(function, feedback_value);
496 BranchIf(is_monomorphic, &handle_monomorphic, &extra_checks); 496 BranchIf(is_monomorphic, &handle_monomorphic, &extra_checks);
497 497
498 Bind(&handle_monomorphic); 498 Bind(&handle_monomorphic);
499 { 499 {
500 // The compare above could have been a SMI/SMI comparison. Guard against 500 // The compare above could have been a SMI/SMI comparison. Guard against
501 // this convincing us that we have a monomorphic JSFunction. 501 // this convincing us that we have a monomorphic JSFunction.
502 Node* is_smi = WordIsSmi(function); 502 Node* is_smi = WordIsSmi(function);
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 TailCallMode tail_call_mode) { 616 TailCallMode tail_call_mode) {
617 Callable callable = CodeFactory::InterpreterPushArgsAndCall( 617 Callable callable = CodeFactory::InterpreterPushArgsAndCall(
618 isolate(), tail_call_mode, CallableType::kAny); 618 isolate(), tail_call_mode, CallableType::kAny);
619 Node* code_target = HeapConstant(callable.code()); 619 Node* code_target = HeapConstant(callable.code());
620 return CallStub(callable.descriptor(), code_target, context, arg_count, 620 return CallStub(callable.descriptor(), code_target, context, arg_count,
621 first_arg, function); 621 first_arg, function);
622 } 622 }
623 623
624 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, 624 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
625 Node* new_target, Node* first_arg, 625 Node* new_target, Node* first_arg,
626 Node* arg_count) { 626 Node* arg_count, Node* slot_id,
627 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate()); 627 Node* type_feedback_vector) {
628 Node* code_target = HeapConstant(callable.code()); 628 Label call_construct(this), js_function(this), end(this);
629 return CallStub(callable.descriptor(), code_target, context, arg_count, 629 Variable return_value(this, MachineRepresentation::kTagged);
630 new_target, constructor, first_arg); 630 Variable allocation_feedback(this, MachineRepresentation::kTagged);
631 allocation_feedback.Bind(UndefinedConstant());
632
633 // Slot id of 0 is used to indicate no type feedback is available.
634 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
635 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
636 GotoIf(is_feedback_unavailable, &call_construct);
637
638 // Check that the constructor is not a smi.
639 Node* is_smi = WordIsSmi(constructor);
640 GotoIf(is_smi, &call_construct);
641
642 // Check that constructor is a JSFunction.
643 Node* instance_type = LoadInstanceType(constructor);
644 Node* is_js_function =
645 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
646 BranchIf(is_js_function, &js_function, &call_construct);
647
648 Bind(&js_function);
649 {
650 // Cache the called function in a feedback vector slot. Cache states
651 // are uninitialized, monomorphic (indicated by a JSFunction), and
652 // megamorphic.
653 // TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a
654 // deferred block so that call_construct_function will be scheduled just
655 // after increment_count and in the fast path we can reduce one branch in
656 // the
657 // fast path.
658 Label increment_count(this), extra_checks(this),
659 call_construct_function(this);
660
661 Node* feedback_element =
662 LoadFixedArrayElement(type_feedback_vector, slot_id);
663 Node* feedback_value = LoadWeakCellValue(feedback_element);
664 Node* is_monomorphic = WordEqual(constructor, feedback_value);
665 BranchIf(is_monomorphic, &increment_count, &extra_checks);
666
667 Bind(&extra_checks);
668 {
669 Label mark_megamorphic(this), initialize(this),
670 check_allocation_site(this), check_initialized(this),
671 set_alloc_feedback_and_inc_count(this);
672 {
673 // Check if it is a megamorphic target
674 Comment("check if megamorphic");
675 Node* is_megamorphic = WordEqual(
676 feedback_element,
677 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
678 GotoIf(is_megamorphic, &call_construct_function);
679
680 Comment("check if weak cell");
681 Node* is_weak_cell = WordEqual(LoadMap(feedback_element),
682 LoadRoot(Heap::kWeakCellMapRootIndex));
683 GotoUnless(is_weak_cell, &check_allocation_site);
684 // If the weak cell is cleared, we have a new chance to become
685 // monomorphic.
686 Comment("check if weak cell is cleared");
687 Node* is_smi = WordIsSmi(feedback_value);
688 BranchIf(is_smi, &initialize, &mark_megamorphic);
689 }
690
691 Bind(&check_allocation_site);
692 {
693 Comment("check if it is an allocation site");
694 Node* is_allocation_site =
695 WordEqual(LoadObjectField(feedback_element, 0),
696 LoadRoot(Heap::kAllocationSiteMapRootIndex));
697 GotoUnless(is_allocation_site, &check_initialized);
698
699 // Make sure the function is the Array() function
700 Node* context_slot =
701 LoadFixedArrayElement(LoadNativeContext(context),
702 Int32Constant(Context::ARRAY_FUNCTION_INDEX));
703 Node* is_array_function = WordEqual(context_slot, constructor);
704 BranchIf(is_array_function, &set_alloc_feedback_and_inc_count,
705 &mark_megamorphic);
706 }
707
708 Bind(&set_alloc_feedback_and_inc_count);
709 {
710 allocation_feedback.Bind(feedback_element);
711 Goto(&increment_count);
712 }
713
714 Bind(&check_initialized);
715 {
716 // Check if it is uninitialized.
717 Comment("check if uninitialized");
718 Node* is_uninitialized = WordEqual(
719 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex));
720 BranchIf(is_uninitialized, &initialize, &mark_megamorphic);
721 }
722
723 Bind(&initialize);
724 {
725 Label initialize_count(this), create_weak_cell(this),
726 create_allocation_site(this);
727 Comment("initialize the feedback element");
728 // Check that it is the Array() function.
729 Node* context_slot =
730 LoadFixedArrayElement(LoadNativeContext(context),
731 Int32Constant(Context::ARRAY_FUNCTION_INDEX));
732 Node* is_array_function = WordEqual(context_slot, constructor);
733 BranchIf(is_array_function, &create_allocation_site, &create_weak_cell);
734
735 Bind(&create_allocation_site);
736 {
737 // TODO(mythria): Inline the creation of allocation site.
738 CreateAllocationSiteStub create_stub(isolate());
739 CallStub(create_stub.GetCallInterfaceDescriptor(),
740 HeapConstant(create_stub.GetCode()), context,
741 type_feedback_vector, SmiTag(slot_id));
742 Node* feedback_element =
743 LoadFixedArrayElement(type_feedback_vector, slot_id);
744 allocation_feedback.Bind(feedback_element);
745 Goto(&initialize_count);
746 }
747
748 Bind(&create_weak_cell);
749 {
750 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
751 constructor);
752 Goto(&initialize_count);
753 }
754
755 Bind(&initialize_count);
756 {
757 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
758 // Count is Smi, so we don't need a write barrier.
759 StoreFixedArrayElement(type_feedback_vector, call_count_slot,
760 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
761 Goto(&call_construct_function);
762 }
763 }
764
765 Bind(&mark_megamorphic);
766 {
767 // MegamorphicSentinel is an immortal immovable object so no
768 // write-barrier
769 // is needed.
770 Comment("transition to megamorphic");
771 DCHECK(
772 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
773 StoreFixedArrayElement(
774 type_feedback_vector, slot_id,
775 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
776 SKIP_WRITE_BARRIER);
777 Goto(&call_construct_function);
778 }
779 }
780
781 Bind(&increment_count);
782 {
783 // Increment the call count.
784 Comment("increment call count");
785 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
786 Node* call_count =
787 LoadFixedArrayElement(type_feedback_vector, call_count_slot);
788 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
789 // Count is Smi, so we don't need a write barrier.
790 StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
791 SKIP_WRITE_BARRIER);
792 Goto(&call_construct_function);
793 }
794
795 Bind(&call_construct_function);
796 {
797 Comment("call using callConstructFunction");
798 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
799 isolate(), CallableType::kJSFunction);
800 return_value.Bind(CallStub(callable_function.descriptor(),
801 HeapConstant(callable_function.code()),
802 context, arg_count, new_target, constructor,
803 allocation_feedback.value(), first_arg));
804 Goto(&end);
805 }
806 }
807
808 Bind(&call_construct);
809 {
810 Comment("call using callConstruct builtin");
811 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
812 isolate(), CallableType::kAny);
813 Node* code_target = HeapConstant(callable.code());
814 return_value.Bind(CallStub(callable.descriptor(), code_target, context,
815 arg_count, new_target, constructor,
816 UndefinedConstant(), first_arg));
817 Goto(&end);
818 }
819
820 Bind(&end);
821 return return_value.value();
631 } 822 }
632 823
633 Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, 824 Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context,
634 Node* first_arg, Node* arg_count, 825 Node* first_arg, Node* arg_count,
635 int result_size) { 826 int result_size) {
636 Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size); 827 Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size);
637 Node* code_target = HeapConstant(callable.code()); 828 Node* code_target = HeapConstant(callable.code());
638 829
639 // Get the function entry from the function id. 830 // Get the function entry from the function id.
640 Node* function_table = ExternalConstant( 831 Node* function_table = ExternalConstant(
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 Goto(&loop); 1263 Goto(&loop);
1073 } 1264 }
1074 Bind(&done_loop); 1265 Bind(&done_loop);
1075 1266
1076 return array; 1267 return array;
1077 } 1268 }
1078 1269
1079 } // namespace interpreter 1270 } // namespace interpreter
1080 } // namespace internal 1271 } // namespace internal
1081 } // namespace v8 1272 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698