OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/code-stubs.h" | 6 #include "src/code-stubs.h" |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/js-generic-lowering.h" | 8 #include "src/compiler/js-generic-lowering.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/machine-operator.h" | 10 #include "src/compiler/machine-operator.h" |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 node->set_op(common()->Call(desc)); | 551 node->set_op(common()->Call(desc)); |
552 } | 552 } |
553 | 553 |
554 | 554 |
555 void JSGenericLowering::LowerJSCallRuntime(Node* node) { | 555 void JSGenericLowering::LowerJSCallRuntime(Node* node) { |
556 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); | 556 const CallRuntimeParameters& p = CallRuntimeParametersOf(node->op()); |
557 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity())); | 557 ReplaceWithRuntimeCall(node, p.id(), static_cast<int>(p.arity())); |
558 } | 558 } |
559 | 559 |
560 | 560 |
| 561 void JSGenericLowering::LowerJSForInDone(Node* node) { |
| 562 ReplaceWithRuntimeCall(node, Runtime::kForInDone); |
| 563 } |
| 564 |
| 565 |
| 566 void JSGenericLowering::LowerJSForInNext(Node* node) { |
| 567 ReplaceWithRuntimeCall(node, Runtime::kForInNext); |
| 568 } |
| 569 |
| 570 |
| 571 void JSGenericLowering::LowerJSForInPrepare(Node* node) { |
| 572 Node* object = NodeProperties::GetValueInput(node, 0); |
| 573 Node* context = NodeProperties::GetContextInput(node); |
| 574 Node* effect = NodeProperties::GetEffectInput(node); |
| 575 Node* control = NodeProperties::GetControlInput(node); |
| 576 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 577 |
| 578 // Get the set of properties to enumerate. |
| 579 Runtime::Function const* function = |
| 580 Runtime::FunctionForId(Runtime::kGetPropertyNamesFast); |
| 581 CallDescriptor const* descriptor = Linkage::GetRuntimeCallDescriptor( |
| 582 zone(), function->function_id, 1, Operator::kNoProperties); |
| 583 Node* cache_type = effect = graph()->NewNode( |
| 584 common()->Call(descriptor), |
| 585 jsgraph()->CEntryStubConstant(function->result_size), object, |
| 586 jsgraph()->ExternalConstant( |
| 587 ExternalReference(function->function_id, isolate())), |
| 588 jsgraph()->Int32Constant(1), context, frame_state, effect, control); |
| 589 control = graph()->NewNode(common()->IfSuccess(), cache_type); |
| 590 |
| 591 Node* object_map = effect = graph()->NewNode( |
| 592 machine()->Load(kMachAnyTagged), object, |
| 593 jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), |
| 594 effect, control); |
| 595 Node* cache_type_map = effect = graph()->NewNode( |
| 596 machine()->Load(kMachAnyTagged), cache_type, |
| 597 jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), |
| 598 effect, control); |
| 599 Node* meta_map = jsgraph()->HeapConstant(isolate()->factory()->meta_map()); |
| 600 |
| 601 // If we got a map from the GetPropertyNamesFast runtime call, we can do a |
| 602 // fast modification check. Otherwise, we got a fixed array, and we have to |
| 603 // perform a slow check on every iteration. |
| 604 Node* check0 = |
| 605 graph()->NewNode(machine()->WordEqual(), cache_type_map, meta_map); |
| 606 Node* branch0 = |
| 607 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
| 608 |
| 609 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
| 610 Node* cache_array_true0; |
| 611 Node* cache_length_true0; |
| 612 Node* cache_type_true0; |
| 613 Node* etrue0; |
| 614 { |
| 615 // Enum cache case. |
| 616 Node* cache_type_enum_length = etrue0 = graph()->NewNode( |
| 617 machine()->Load(kMachUint32), cache_type, |
| 618 jsgraph()->IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag), |
| 619 effect, if_true0); |
| 620 cache_type_enum_length = |
| 621 graph()->NewNode(machine()->Word32And(), cache_type_enum_length, |
| 622 jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask)); |
| 623 |
| 624 Node* check1 = |
| 625 graph()->NewNode(machine()->Word32Equal(), cache_type_enum_length, |
| 626 jsgraph()->Int32Constant(0)); |
| 627 Node* branch1 = |
| 628 graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
| 629 |
| 630 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 631 Node* cache_array_true1; |
| 632 Node* etrue1; |
| 633 { |
| 634 // No properties to enumerate. |
| 635 cache_array_true1 = |
| 636 jsgraph()->HeapConstant(isolate()->factory()->empty_fixed_array()); |
| 637 etrue1 = etrue0; |
| 638 } |
| 639 |
| 640 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 641 Node* cache_array_false1; |
| 642 Node* efalse1; |
| 643 { |
| 644 // Load the enumeration cache from the instance descriptors of {object}. |
| 645 Node* object_map_descriptors = efalse1 = graph()->NewNode( |
| 646 machine()->Load(kMachAnyTagged), object_map, |
| 647 jsgraph()->IntPtrConstant(Map::kDescriptorsOffset - kHeapObjectTag), |
| 648 etrue0, if_false1); |
| 649 Node* object_map_enum_cache = efalse1 = graph()->NewNode( |
| 650 machine()->Load(kMachAnyTagged), object_map_descriptors, |
| 651 jsgraph()->IntPtrConstant(DescriptorArray::kEnumCacheOffset - |
| 652 kHeapObjectTag), |
| 653 efalse1, if_false1); |
| 654 cache_array_false1 = efalse1 = graph()->NewNode( |
| 655 machine()->Load(kMachAnyTagged), object_map_enum_cache, |
| 656 jsgraph()->IntPtrConstant( |
| 657 DescriptorArray::kEnumCacheBridgeCacheOffset - kHeapObjectTag), |
| 658 efalse1, if_false1); |
| 659 } |
| 660 |
| 661 if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 662 etrue0 = |
| 663 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
| 664 cache_array_true0 = |
| 665 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true1, |
| 666 cache_array_false1, if_true0); |
| 667 |
| 668 cache_length_true0 = graph()->NewNode( |
| 669 machine()->WordShl(), |
| 670 machine()->Is64() |
| 671 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), |
| 672 cache_type_enum_length) |
| 673 : cache_type_enum_length, |
| 674 jsgraph()->Int32Constant(kSmiShiftSize + kSmiTagSize)); |
| 675 cache_type_true0 = cache_type; |
| 676 } |
| 677 |
| 678 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
| 679 Node* cache_array_false0; |
| 680 Node* cache_length_false0; |
| 681 Node* cache_type_false0; |
| 682 Node* efalse0; |
| 683 { |
| 684 // FixedArray case. |
| 685 Node* object_instance_type = efalse0 = graph()->NewNode( |
| 686 machine()->Load(kMachUint8), object_map, |
| 687 jsgraph()->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag), |
| 688 effect, if_false0); |
| 689 |
| 690 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 691 Node* check1 = graph()->NewNode( |
| 692 machine()->Uint32LessThanOrEqual(), object_instance_type, |
| 693 jsgraph()->Uint32Constant(LAST_JS_PROXY_TYPE)); |
| 694 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
| 695 check1, if_false0); |
| 696 |
| 697 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 698 Node* cache_type_true1 = jsgraph()->ZeroConstant(); // Zero indicates proxy |
| 699 |
| 700 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 701 Node* cache_type_false1 = jsgraph()->OneConstant(); // One means slow check |
| 702 |
| 703 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
| 704 cache_type_false0 = |
| 705 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_type_true1, |
| 706 cache_type_false1, if_false0); |
| 707 |
| 708 cache_array_false0 = cache_type; |
| 709 cache_length_false0 = efalse0 = graph()->NewNode( |
| 710 machine()->Load(kMachAnyTagged), cache_array_false0, |
| 711 jsgraph()->IntPtrConstant(FixedArray::kLengthOffset - kHeapObjectTag), |
| 712 efalse0, if_false0); |
| 713 } |
| 714 |
| 715 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
| 716 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
| 717 Node* cache_array = |
| 718 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true0, |
| 719 cache_array_false0, control); |
| 720 Node* cache_length = |
| 721 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_length_true0, |
| 722 cache_length_false0, control); |
| 723 cache_type = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), |
| 724 cache_type_true0, cache_type_false0, control); |
| 725 |
| 726 for (auto edge : node->use_edges()) { |
| 727 if (NodeProperties::IsEffectEdge(edge)) { |
| 728 edge.UpdateTo(effect); |
| 729 } else if (NodeProperties::IsControlEdge(edge)) { |
| 730 Node* const use = edge.from(); |
| 731 DCHECK_EQ(IrOpcode::kIfSuccess, use->opcode()); |
| 732 use->ReplaceUses(control); |
| 733 use->Kill(); |
| 734 } else { |
| 735 Node* const use = edge.from(); |
| 736 DCHECK(NodeProperties::IsValueEdge(edge)); |
| 737 DCHECK_EQ(IrOpcode::kProjection, use->opcode()); |
| 738 switch (ProjectionIndexOf(use->op())) { |
| 739 case 0: |
| 740 use->ReplaceUses(cache_type); |
| 741 break; |
| 742 case 1: |
| 743 use->ReplaceUses(cache_array); |
| 744 break; |
| 745 case 2: |
| 746 use->ReplaceUses(cache_length); |
| 747 break; |
| 748 default: |
| 749 UNREACHABLE(); |
| 750 break; |
| 751 } |
| 752 use->Kill(); |
| 753 } |
| 754 } |
| 755 } |
| 756 |
| 757 |
| 758 void JSGenericLowering::LowerJSForInStep(Node* node) { |
| 759 ReplaceWithRuntimeCall(node, Runtime::kForInStep); |
| 760 } |
| 761 |
| 762 |
561 void JSGenericLowering::LowerJSStackCheck(Node* node) { | 763 void JSGenericLowering::LowerJSStackCheck(Node* node) { |
562 Node* effect = NodeProperties::GetEffectInput(node); | 764 Node* effect = NodeProperties::GetEffectInput(node); |
563 Node* control = NodeProperties::GetControlInput(node); | 765 Node* control = NodeProperties::GetControlInput(node); |
564 | 766 |
565 Node* limit = graph()->NewNode( | 767 Node* limit = graph()->NewNode( |
566 machine()->Load(kMachPtr), | 768 machine()->Load(kMachPtr), |
567 jsgraph()->ExternalConstant( | 769 jsgraph()->ExternalConstant( |
568 ExternalReference::address_of_stack_limit(isolate())), | 770 ExternalReference::address_of_stack_limit(isolate())), |
569 jsgraph()->IntPtrConstant(0), effect, control); | 771 jsgraph()->IntPtrConstant(0), effect, control); |
570 Node* pointer = graph()->NewNode(machine()->LoadStackPointer()); | 772 Node* pointer = graph()->NewNode(machine()->LoadStackPointer()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 } | 808 } |
607 | 809 |
608 | 810 |
609 MachineOperatorBuilder* JSGenericLowering::machine() const { | 811 MachineOperatorBuilder* JSGenericLowering::machine() const { |
610 return jsgraph()->machine(); | 812 return jsgraph()->machine(); |
611 } | 813 } |
612 | 814 |
613 } // namespace compiler | 815 } // namespace compiler |
614 } // namespace internal | 816 } // namespace internal |
615 } // namespace v8 | 817 } // namespace v8 |
OLD | NEW |