OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |