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/bytecode-array-builder.h" | 5 #include "src/interpreter/bytecode-array-builder.h" |
6 | 6 |
7 namespace v8 { | 7 namespace v8 { |
8 namespace internal { | 8 namespace internal { |
9 namespace interpreter { | 9 namespace interpreter { |
10 | 10 |
11 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) | 11 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) |
12 : isolate_(isolate), | 12 : isolate_(isolate), |
13 zone_(zone), | 13 zone_(zone), |
14 bytecodes_(zone), | 14 bytecodes_(zone), |
15 bytecode_generated_(false), | 15 bytecode_generated_(false), |
16 last_block_end_(0), | 16 last_block_end_(0), |
17 last_bytecode_start_(~0), | 17 last_bytecode_start_(~0), |
18 return_seen_in_block_(false), | 18 return_seen_in_block_(false), |
19 constants_map_(isolate->heap(), zone), | 19 constants_map_(isolate->heap(), zone), |
20 constants_(zone), | 20 constants_(zone), |
21 parameter_count_(-1), | 21 parameter_count_(-1), |
22 local_register_count_(-1), | 22 local_register_count_(-1), |
23 context_register_count_(-1), | 23 context_register_count_(-1), |
24 temporary_register_count_(0), | 24 free_temporaries_(zone), |
25 temporary_register_next_(0) {} | 25 temporary_register_count_(0) {} |
26 | 26 |
27 | 27 |
28 void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { | 28 void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { |
29 local_register_count_ = number_of_locals; | 29 local_register_count_ = number_of_locals; |
30 DCHECK_LE(context_register_count_, 0); | 30 DCHECK_LE(context_register_count_, 0); |
31 temporary_register_next_ = local_register_count_; | |
32 } | 31 } |
33 | 32 |
34 | 33 |
35 void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { | 34 void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { |
36 parameter_count_ = number_of_parameters; | 35 parameter_count_ = number_of_parameters; |
37 } | 36 } |
38 | 37 |
39 | 38 |
40 void BytecodeArrayBuilder::set_context_count(int number_of_contexts) { | 39 void BytecodeArrayBuilder::set_context_count(int number_of_contexts) { |
41 context_register_count_ = number_of_contexts; | 40 context_register_count_ = number_of_contexts; |
42 DCHECK_GE(local_register_count_, 0); | 41 DCHECK_GE(local_register_count_, 0); |
43 temporary_register_next_ = local_register_count_ + context_register_count_; | |
44 } | 42 } |
45 | 43 |
46 | 44 |
47 Register BytecodeArrayBuilder::first_context_register() const { | 45 Register BytecodeArrayBuilder::first_context_register() const { |
48 DCHECK_GT(context_register_count_, 0); | 46 DCHECK_GT(context_register_count_, 0); |
49 return Register(local_register_count_); | 47 return Register(local_register_count_); |
50 } | 48 } |
51 | 49 |
52 | 50 |
53 Register BytecodeArrayBuilder::last_context_register() const { | 51 Register BytecodeArrayBuilder::last_context_register() const { |
54 DCHECK_GT(context_register_count_, 0); | 52 DCHECK_GT(context_register_count_, 0); |
55 return Register(local_register_count_ + context_register_count_ - 1); | 53 return Register(local_register_count_ + context_register_count_ - 1); |
56 } | 54 } |
57 | 55 |
58 | 56 |
57 Register BytecodeArrayBuilder::first_temporary_register() const { | |
58 DCHECK_GT(temporary_register_count_, 0); | |
59 return Register(fixed_register_count()); | |
60 } | |
61 | |
62 | |
63 Register BytecodeArrayBuilder::last_temporary_register() const { | |
64 DCHECK_GT(temporary_register_count_, 0); | |
65 return Register(fixed_register_count() + temporary_register_count_ - 1); | |
66 } | |
67 | |
68 | |
59 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { | 69 Register BytecodeArrayBuilder::Parameter(int parameter_index) const { |
60 DCHECK_GE(parameter_index, 0); | 70 DCHECK_GE(parameter_index, 0); |
61 return Register::FromParameterIndex(parameter_index, parameter_count()); | 71 return Register::FromParameterIndex(parameter_index, parameter_count()); |
62 } | 72 } |
63 | 73 |
64 | 74 |
75 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { | |
76 // OTH: TODO review or context? | |
rmcilroy
2015/10/19 12:56:21
I don't think we need to worry about contexts sinc
oth
2015/10/20 15:28:51
Agree. Now have a RegisterIsTemporary() as an addi
| |
77 return reg.is_parameter() || reg.index() < local_register_count_; | |
rmcilroy
2015/10/19 12:56:21
use local_register_count() instead.
oth
2015/10/20 15:28:51
Done.
| |
78 } | |
79 | |
80 | |
65 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { | 81 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
66 DCHECK_EQ(bytecode_generated_, false); | 82 DCHECK_EQ(bytecode_generated_, false); |
67 | 83 |
68 EnsureReturn(); | 84 EnsureReturn(); |
69 | 85 |
70 int bytecode_size = static_cast<int>(bytecodes_.size()); | 86 int bytecode_size = static_cast<int>(bytecodes_.size()); |
71 int register_count = fixed_register_count() + temporary_register_count_; | 87 int register_count = fixed_register_count() + temporary_register_count_; |
72 int frame_size = register_count * kPointerSize; | 88 int frame_size = register_count * kPointerSize; |
73 | 89 |
74 Factory* factory = isolate_->factory(); | 90 Factory* factory = isolate_->factory(); |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 } | 609 } |
594 | 610 |
595 | 611 |
596 void BytecodeArrayBuilder::EnsureReturn() { | 612 void BytecodeArrayBuilder::EnsureReturn() { |
597 if (!return_seen_in_block_) { | 613 if (!return_seen_in_block_) { |
598 LoadUndefined(); | 614 LoadUndefined(); |
599 Return(); | 615 Return(); |
600 } | 616 } |
601 } | 617 } |
602 | 618 |
619 | |
603 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, | 620 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, |
604 Register receiver, | 621 Register receiver, |
605 size_t arg_count) { | 622 size_t arg_count) { |
606 if (FitsInIdx8Operand(arg_count)) { | 623 if (FitsInIdx8Operand(arg_count)) { |
607 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), | 624 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), |
608 static_cast<uint8_t>(arg_count)); | 625 static_cast<uint8_t>(arg_count)); |
609 } else { | 626 } else { |
610 UNIMPLEMENTED(); | 627 UNIMPLEMENTED(); |
611 } | 628 } |
612 return *this; | 629 return *this; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 entry = constants_map_.Get(object); | 664 entry = constants_map_.Get(object); |
648 *entry = constants_.size(); | 665 *entry = constants_.size(); |
649 constants_.push_back(object); | 666 constants_.push_back(object); |
650 } | 667 } |
651 DCHECK(constants_[*entry].is_identical_to(object)); | 668 DCHECK(constants_[*entry].is_identical_to(object)); |
652 return *entry; | 669 return *entry; |
653 } | 670 } |
654 | 671 |
655 | 672 |
656 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | 673 int BytecodeArrayBuilder::BorrowTemporaryRegister() { |
657 int temporary_reg_index = temporary_register_next_++; | 674 int retval; |
658 int count = temporary_register_next_ - fixed_register_count(); | 675 if (free_temporaries_.empty()) { |
659 if (count > temporary_register_count_) { | 676 temporary_register_count_ += 1; |
660 temporary_register_count_ = count; | 677 retval = last_temporary_register().index(); |
678 } else { | |
679 retval = free_temporaries_.back(); | |
680 free_temporaries_.pop_back(); | |
681 for (size_t i = 0; i < free_temporaries_.size(); i++) { | |
rmcilroy
2015/10/19 12:56:21
Only do this loop if #DEBUG.
oth
2015/10/20 15:28:52
Re-implemented with ZoneSet.
| |
682 DCHECK(free_temporaries_[i] != retval); | |
683 } | |
661 } | 684 } |
662 return temporary_reg_index; | 685 return retval; |
663 } | 686 } |
664 | 687 |
665 | 688 |
666 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { | 689 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { |
667 DCHECK_EQ(reg_index, temporary_register_next_ - 1); | 690 for (size_t i = 0; i < free_temporaries_.size(); i++) { |
rmcilroy
2015/10/19 12:56:22
ditto
oth
2015/10/20 15:28:52
Re-implemented with ZoneSet.
| |
668 temporary_register_next_ = reg_index; | 691 DCHECK(free_temporaries_[i] != reg_index); |
692 } | |
693 free_temporaries_.push_back(reg_index); | |
669 } | 694 } |
670 | 695 |
671 | 696 |
697 static void CheckConsecutiveRun(ZoneVector<int>* v, size_t count) { | |
rmcilroy
2015/10/19 12:56:21
This code should only be run if #DEBUG - just make
oth
2015/10/20 15:28:52
Method removed.
| |
698 DCHECK_GE(v->size(), count); | |
699 auto current = v->rbegin(); | |
700 while (count-- > 1) { | |
rmcilroy
2015/10/19 12:56:21
for loop instead?
oth
2015/10/20 15:28:52
Ack.
| |
701 auto successor = current + 1; | |
702 DCHECK_EQ(*successor, *current + 1); | |
703 current = successor; | |
704 } | |
705 } | |
706 | |
707 | |
708 void BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters( | |
709 size_t count) { | |
710 // TODO(oth): this is a placeholder. There should have a better | |
711 // allocator that avoids sorting, e.g. bitmap allocator with hint to | |
712 // next cell in a consecutive sequence, or something similar. | |
713 | |
714 if (count == 0) { | |
715 return; | |
716 } | |
717 | |
718 size_t run = 0; | |
719 std::sort(free_temporaries_.begin(), free_temporaries_.end()); | |
rmcilroy
2015/10/19 12:56:21
How about we just keep free_temporaries sorted rat
oth
2015/10/20 15:28:52
Yes, it's become a bit overwhelming in it's curren
| |
720 | |
721 // First check for a run in the existing elements | |
rmcilroy
2015/10/19 12:56:22
How often do we end up (in the current test code)
oth
2015/10/20 15:28:52
IIRC it only occurs in VisitObjectLiterals which i
| |
722 if (free_temporaries_.size() >= count) { | |
723 size_t run_start = 0; | |
724 int last_temporary = free_temporaries_[0] - 1; | |
725 for (size_t i = 0; i < free_temporaries_.size(); i++) { | |
726 if (free_temporaries_[i] == last_temporary + 1) { | |
727 if (i - run_start + 1 == count) { | |
728 std::rotate(free_temporaries_.begin(), | |
729 free_temporaries_.begin() + i + 1, | |
730 free_temporaries_.end()); | |
731 std::reverse(free_temporaries_.rbegin(), | |
732 free_temporaries_.rbegin() + count); | |
733 CheckConsecutiveRun(&free_temporaries_, count); | |
734 return; | |
735 } | |
736 } else { | |
737 run_start = i; | |
738 } | |
739 last_temporary = free_temporaries_[i]; | |
740 } | |
741 } | |
742 | |
743 // Next check if a run can be formed abutting the end of the | |
744 // free list. | |
745 if (!free_temporaries_.empty()) { | |
746 auto start = free_temporaries_.rbegin(); | |
747 int last_index = last_temporary_register().index() + 1; | |
748 while (run < count && start != free_temporaries_.rend() && | |
749 *start == last_index - 1) { | |
750 last_index = *start; | |
751 start++; | |
752 run++; | |
753 } | |
754 } | |
755 | |
756 // Complete run with new temporaries as necessary. | |
757 while (run < count) { | |
758 // Push back enough temporaries to ensure consecutive allocations. | |
759 temporary_register_count_ += 1; | |
760 int index = last_temporary_register().index(); | |
761 free_temporaries_.push_back(index); | |
762 run++; | |
763 } | |
764 | |
765 // Finally, reverse end of free list to give consecutive order as | |
766 // registers are popped off. | |
767 auto lhs = free_temporaries_.rbegin(); | |
768 auto rhs = lhs + count; | |
769 std::reverse(lhs, rhs); | |
770 CheckConsecutiveRun(&free_temporaries_, count); | |
771 } | |
772 | |
773 | |
774 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { | |
775 if (temporary_register_count_ > 0) { | |
776 for (size_t i = 0; i < free_temporaries_.size(); i++) { | |
777 if (free_temporaries_[i] == reg.index()) { | |
778 return false; | |
779 } | |
780 } | |
781 return reg <= last_temporary_register(); | |
782 } else { | |
783 return false; | |
784 } | |
785 } | |
786 | |
787 | |
672 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, | 788 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, |
673 uint32_t operand_value) const { | 789 uint32_t operand_value) const { |
674 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); | 790 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); |
675 switch (operand_type) { | 791 switch (operand_type) { |
676 case OperandType::kNone: | 792 case OperandType::kNone: |
677 return false; | 793 return false; |
678 case OperandType::kIdx16: | 794 case OperandType::kIdx16: |
679 return static_cast<uint16_t>(operand_value) == operand_value; | 795 return static_cast<uint16_t>(operand_value) == operand_value; |
680 case OperandType::kCount8: | 796 case OperandType::kCount8: |
681 case OperandType::kImm8: | 797 case OperandType::kImm8: |
682 case OperandType::kIdx8: | 798 case OperandType::kIdx8: |
683 return static_cast<uint8_t>(operand_value) == operand_value; | 799 return static_cast<uint8_t>(operand_value) == operand_value; |
684 case OperandType::kReg8: { | 800 case OperandType::kReg8: { |
685 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); | 801 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); |
686 if (reg.is_function_context() || reg.is_function_closure()) { | 802 if (reg.is_function_context() || reg.is_function_closure()) { |
687 return true; | 803 return true; |
688 } else if (reg.is_parameter()) { | 804 } else if (reg.is_parameter()) { |
689 int parameter_index = reg.ToParameterIndex(parameter_count()); | 805 int parameter_index = reg.ToParameterIndex(parameter_count_); |
690 return parameter_index >= 0 && parameter_index < parameter_count(); | 806 return parameter_index >= 0 && parameter_index < parameter_count_; |
807 } else if (reg.index() < local_register_count_) { | |
rmcilroy
2015/10/19 12:56:21
I don't think this check is necessary given the ch
oth
2015/10/20 15:28:52
Yes, agree. Removed.
| |
808 return true; | |
809 } else if (reg.index() < | |
810 local_register_count_ + context_register_count_) { | |
rmcilroy
2015/10/19 12:56:22
reg.index() < fixed_register_count()
oth
2015/10/20 15:28:52
Done.
| |
811 // context_register_count_ may be -1 if not initialized. | |
rmcilroy
2015/10/19 12:56:21
This comment should no longer be true - if you spo
oth
2015/10/20 15:28:52
Acknowledged. Removed comment.
| |
812 return true; | |
691 } else { | 813 } else { |
692 return (reg.index() >= 0 && reg.index() < temporary_register_next_); | 814 return TemporaryRegisterIsLive(reg); |
693 } | 815 } |
694 } | 816 } |
695 } | 817 } |
696 UNREACHABLE(); | 818 UNREACHABLE(); |
697 return false; | 819 return false; |
698 } | 820 } |
699 | 821 |
700 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { | 822 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { |
701 return last_bytecode_start_ < bytecodes()->size() && | 823 return last_bytecode_start_ < bytecodes()->size() && |
702 last_bytecode_start_ >= last_block_end_; | 824 last_bytecode_start_ >= last_block_end_; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
866 } | 988 } |
867 | 989 |
868 | 990 |
869 // static | 991 // static |
870 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { | 992 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { |
871 return kMinUInt16 <= value && value <= kMaxUInt16; | 993 return kMinUInt16 <= value && value <= kMaxUInt16; |
872 } | 994 } |
873 | 995 |
874 | 996 |
875 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) | 997 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) |
876 : builder_(builder), count_(0), last_register_index_(-1) {} | 998 : builder_(builder), allocated_(builder->zone()) {} |
877 | 999 |
878 | 1000 |
879 TemporaryRegisterScope::~TemporaryRegisterScope() { | 1001 TemporaryRegisterScope::~TemporaryRegisterScope() { |
880 while (count_-- != 0) { | 1002 for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) { |
881 builder_->ReturnTemporaryRegister(last_register_index_--); | 1003 builder_->ReturnTemporaryRegister(*i); |
882 } | 1004 } |
1005 allocated_.clear(); | |
883 } | 1006 } |
884 | 1007 |
885 | 1008 |
886 Register TemporaryRegisterScope::NewRegister() { | 1009 Register TemporaryRegisterScope::NewRegister() { |
887 count_++; | 1010 int allocated = builder_->BorrowTemporaryRegister(); |
888 last_register_index_ = builder_->BorrowTemporaryRegister(); | 1011 allocated_.push_back(allocated); |
889 return Register(last_register_index_); | 1012 return Register(allocated); |
1013 } | |
1014 | |
1015 | |
1016 void TemporaryRegisterScope::PrepareForConsecutiveAllocations(size_t count) { | |
rmcilroy
2015/10/19 12:56:21
As discussed offline - we should be moving towards
oth
2015/10/20 15:28:51
Added a TODO in the constructor for TemporaryRegis
| |
1017 builder_->PrepareForConsecutiveTemporaryRegisters(count); | |
890 } | 1018 } |
891 | 1019 |
892 } // namespace interpreter | 1020 } // namespace interpreter |
893 } // namespace internal | 1021 } // namespace internal |
894 } // namespace v8 | 1022 } // namespace v8 |
OLD | NEW |