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

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

Issue 2307903002: [Interpreter] Collect allocation site feedback in call bytecode handler. (Closed)
Patch Set: Fixed a bug in mips implementation. 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
« no previous file with comments | « src/interface-descriptors.h ('k') | src/mips/interface-descriptors-mips.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 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 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not 474 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
475 // computed, meaning that it can't appear to be a pointer. If the low bit is 475 // computed, meaning that it can't appear to be a pointer. If the low bit is
476 // 0, then hash is computed, but the 0 bit prevents the field from appearing 476 // 0, then hash is computed, but the 0 bit prevents the field from appearing
477 // to be a pointer. 477 // to be a pointer.
478 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); 478 STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
479 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == 479 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
480 WeakCell::kValueOffset && 480 WeakCell::kValueOffset &&
481 WeakCell::kValueOffset == Symbol::kHashFieldSlot); 481 WeakCell::kValueOffset == Symbol::kHashFieldSlot);
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 call_function(this);
485 486
486 // Slot id of 0 is used to indicate no typefeedback is available. Call using 487 // Slot id of 0 is used to indicate no typefeedback is available. Call using
487 // call builtin. 488 // call builtin.
488 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); 489 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
489 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); 490 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
490 GotoIf(is_feedback_unavailable, &call); 491 GotoIf(is_feedback_unavailable, &call);
491 492
492 // The checks. First, does function match the recorded monomorphic target? 493 // The checks. First, does function match the recorded monomorphic target?
493 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); 494 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
494 Node* feedback_value = LoadWeakCellValue(feedback_element); 495 Node* feedback_value = LoadWeakCellValue(feedback_element);
(...skipping 21 matching lines...) Expand all
516 isolate(), tail_call_mode, CallableType::kJSFunction); 517 isolate(), tail_call_mode, CallableType::kJSFunction);
517 Node* code_target = HeapConstant(callable.code()); 518 Node* code_target = HeapConstant(callable.code());
518 Node* ret_value = CallStub(callable.descriptor(), code_target, context, 519 Node* ret_value = CallStub(callable.descriptor(), code_target, context,
519 arg_count, first_arg, function); 520 arg_count, first_arg, function);
520 return_value.Bind(ret_value); 521 return_value.Bind(ret_value);
521 Goto(&end); 522 Goto(&end);
522 } 523 }
523 524
524 Bind(&extra_checks); 525 Bind(&extra_checks);
525 { 526 {
526 Label check_initialized(this, Label::kDeferred), mark_megamorphic(this); 527 Label check_initialized(this, Label::kDeferred), mark_megamorphic(this),
528 check_allocation_site(this),
529 create_allocation_site(this, Label::kDeferred);
527 // Check if it is a megamorphic target 530 // Check if it is a megamorphic target
528 Node* is_megamorphic = WordEqual( 531 Node* is_megamorphic = WordEqual(
529 feedback_element, 532 feedback_element,
530 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); 533 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
531 BranchIf(is_megamorphic, &call, &check_initialized); 534 BranchIf(is_megamorphic, &call, &check_allocation_site);
535
536 Bind(&check_allocation_site);
537 {
538 Node* is_allocation_site =
539 WordEqual(LoadMap(feedback_element),
540 LoadRoot(Heap::kAllocationSiteMapRootIndex));
541 GotoUnless(is_allocation_site, &check_initialized);
542
543 // If it is not the Array() function, mark megamorphic.
544 Node* context_slot =
545 LoadFixedArrayElement(LoadNativeContext(context),
546 Int32Constant(Context::ARRAY_FUNCTION_INDEX));
547 Node* is_array_function = WordEqual(context_slot, function);
548 GotoUnless(is_array_function, &mark_megamorphic);
549
550 // It is a monomorphic Array function. Increment the call count.
551 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
552 Node* call_count =
553 LoadFixedArrayElement(type_feedback_vector, call_count_slot);
554 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
555 // Count is Smi, so we don't need a write barrier.
556 StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
557 SKIP_WRITE_BARRIER);
558
559 // Call ArrayConstructorStub.
560 Callable callable_call =
561 CodeFactory::InterpreterPushArgsAndConstructArray(isolate());
562 Node* code_target_call = HeapConstant(callable_call.code());
563 Node* ret_value =
564 CallStub(callable_call.descriptor(), code_target_call, context,
565 arg_count, function, feedback_element, first_arg);
566 return_value.Bind(ret_value);
567 Goto(&end);
568 }
532 569
533 Bind(&check_initialized); 570 Bind(&check_initialized);
534 { 571 {
535 Label possibly_monomorphic(this); 572 Label possibly_monomorphic(this);
536 // Check if it is uninitialized. 573 // Check if it is uninitialized.
537 Node* is_uninitialized = WordEqual( 574 Node* is_uninitialized = WordEqual(
538 feedback_element, 575 feedback_element,
539 HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate()))); 576 HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate())));
540 GotoUnless(is_uninitialized, &mark_megamorphic); 577 GotoUnless(is_uninitialized, &mark_megamorphic);
541 578
542 Node* is_smi = WordIsSmi(function); 579 Node* is_smi = WordIsSmi(function);
543 GotoIf(is_smi, &mark_megamorphic); 580 GotoIf(is_smi, &mark_megamorphic);
544 581
545 // Check if function is an object of JSFunction type 582 // Check if function is an object of JSFunction type
546 Node* instance_type = LoadInstanceType(function); 583 Node* instance_type = LoadInstanceType(function);
547 Node* is_js_function = 584 Node* is_js_function =
548 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); 585 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
549 GotoUnless(is_js_function, &mark_megamorphic); 586 GotoUnless(is_js_function, &mark_megamorphic);
550 587
551 // Check that it is not the Array() function. 588 // Check if it is the Array() function.
552 Node* context_slot = 589 Node* context_slot =
553 LoadFixedArrayElement(LoadNativeContext(context), 590 LoadFixedArrayElement(LoadNativeContext(context),
554 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); 591 Int32Constant(Context::ARRAY_FUNCTION_INDEX));
555 Node* is_array_function = WordEqual(context_slot, function); 592 Node* is_array_function = WordEqual(context_slot, function);
556 GotoIf(is_array_function, &mark_megamorphic); 593 GotoIf(is_array_function, &create_allocation_site);
557 594
558 // Check if the function belongs to the same native context 595 // Check if the function belongs to the same native context
559 Node* native_context = LoadNativeContext( 596 Node* native_context = LoadNativeContext(
560 LoadObjectField(function, JSFunction::kContextOffset)); 597 LoadObjectField(function, JSFunction::kContextOffset));
561 Node* is_same_native_context = 598 Node* is_same_native_context =
562 WordEqual(native_context, LoadNativeContext(context)); 599 WordEqual(native_context, LoadNativeContext(context));
563 GotoUnless(is_same_native_context, &mark_megamorphic); 600 GotoUnless(is_same_native_context, &mark_megamorphic);
564 601
565 // Initialize it to a monomorphic target. 602 // Initialize it to a monomorphic target.
566 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); 603 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
567 // Count is Smi, so we don't need a write barrier. 604 // Count is Smi, so we don't need a write barrier.
568 StoreFixedArrayElement(type_feedback_vector, call_count_slot, 605 StoreFixedArrayElement(type_feedback_vector, call_count_slot,
569 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER); 606 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
570 607
571 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), 608 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
572 function); 609 function);
573 610
574 // Call using call function builtin. 611 // Call using call function builtin.
575 Callable callable = CodeFactory::InterpreterPushArgsAndCall( 612 Goto(&call_function);
576 isolate(), tail_call_mode, CallableType::kJSFunction); 613 }
577 Node* code_target = HeapConstant(callable.code()); 614
578 Node* ret_value = CallStub(callable.descriptor(), code_target, context, 615 Bind(&create_allocation_site);
579 arg_count, first_arg, function); 616 {
580 return_value.Bind(ret_value); 617 // TODO(mythria): Inline the creation of the allocation site.
581 Goto(&end); 618 CreateAllocationSiteStub create_stub(isolate());
619 CallStub(create_stub.GetCallInterfaceDescriptor(),
620 HeapConstant(create_stub.GetCode()), context,
621 type_feedback_vector, SmiTag(slot_id));
622
623 // Initialize the count to 1.
624 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
625 // Count is Smi, so we don't need a write barrier.
626 StoreFixedArrayElement(type_feedback_vector, call_count_slot,
627 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
628
629 // Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state.
630 // They start collecting feedback only when a call is executed the second
631 // time. So, do not pass any feedback here.
632 Goto(&call_function);
582 } 633 }
583 634
584 Bind(&mark_megamorphic); 635 Bind(&mark_megamorphic);
585 { 636 {
586 // Mark it as a megamorphic. 637 // Mark it as a megamorphic.
587 // MegamorphicSentinel is created as a part of Heap::InitialObjects 638 // MegamorphicSentinel is created as a part of Heap::InitialObjects
588 // and will not move during a GC. So it is safe to skip write barrier. 639 // and will not move during a GC. So it is safe to skip write barrier.
589 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); 640 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
590 StoreFixedArrayElement( 641 StoreFixedArrayElement(
591 type_feedback_vector, slot_id, 642 type_feedback_vector, slot_id,
592 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), 643 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
593 SKIP_WRITE_BARRIER); 644 SKIP_WRITE_BARRIER);
594 Goto(&call); 645 Goto(&call);
595 } 646 }
596 } 647 }
597 648
649 Bind(&call_function);
650 {
651 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
652 isolate(), tail_call_mode, CallableType::kJSFunction);
653 Node* code_target_call = HeapConstant(callable_call.code());
654 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
655 context, arg_count, first_arg, function);
656 return_value.Bind(ret_value);
657 Goto(&end);
658 }
659
598 Bind(&call); 660 Bind(&call);
599 { 661 {
600 // Call using call builtin. 662 // Call using call builtin.
601 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( 663 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
602 isolate(), tail_call_mode, CallableType::kAny); 664 isolate(), tail_call_mode, CallableType::kAny);
603 Node* code_target_call = HeapConstant(callable_call.code()); 665 Node* code_target_call = HeapConstant(callable_call.code());
604 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, 666 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
605 context, arg_count, first_arg, function); 667 context, arg_count, first_arg, function);
606 return_value.Bind(ret_value); 668 return_value.Bind(ret_value);
607 Goto(&end); 669 Goto(&end);
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
757 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); 819 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
758 // Count is Smi, so we don't need a write barrier. 820 // Count is Smi, so we don't need a write barrier.
759 StoreFixedArrayElement(type_feedback_vector, call_count_slot, 821 StoreFixedArrayElement(type_feedback_vector, call_count_slot,
760 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER); 822 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
761 Goto(&call_construct_function); 823 Goto(&call_construct_function);
762 } 824 }
763 } 825 }
764 826
765 Bind(&mark_megamorphic); 827 Bind(&mark_megamorphic);
766 { 828 {
767 // MegamorphicSentinel is an immortal immovable object so no 829 // MegamorphicSentinel is an immortal immovable object so
768 // write-barrier 830 // write-barrier is not needed.
769 // is needed.
770 Comment("transition to megamorphic"); 831 Comment("transition to megamorphic");
771 DCHECK( 832 DCHECK(
772 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); 833 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
773 StoreFixedArrayElement( 834 StoreFixedArrayElement(
774 type_feedback_vector, slot_id, 835 type_feedback_vector, slot_id,
775 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), 836 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
776 SKIP_WRITE_BARRIER); 837 SKIP_WRITE_BARRIER);
777 Goto(&call_construct_function); 838 Goto(&call_construct_function);
778 } 839 }
779 } 840 }
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
1263 Goto(&loop); 1324 Goto(&loop);
1264 } 1325 }
1265 Bind(&done_loop); 1326 Bind(&done_loop);
1266 1327
1267 return array; 1328 return array;
1268 } 1329 }
1269 1330
1270 } // namespace interpreter 1331 } // namespace interpreter
1271 } // namespace internal 1332 } // namespace internal
1272 } // namespace v8 1333 } // namespace v8
OLDNEW
« no previous file with comments | « src/interface-descriptors.h ('k') | src/mips/interface-descriptors-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698