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 temporary_register_count_(0), |
25 temporary_register_next_(0) {} | 25 free_temporaries_(zone) {} |
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 return reg.is_parameter() || reg.index() < locals_count(); | |
77 } | |
78 | |
79 | |
80 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { | |
81 return temporary_register_count_ > 0 && first_temporary_register() <= reg && | |
82 reg <= last_temporary_register(); | |
83 } | |
84 | |
85 | |
65 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { | 86 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
66 DCHECK_EQ(bytecode_generated_, false); | 87 DCHECK_EQ(bytecode_generated_, false); |
67 | 88 |
68 EnsureReturn(); | 89 EnsureReturn(); |
69 | 90 |
70 int bytecode_size = static_cast<int>(bytecodes_.size()); | 91 int bytecode_size = static_cast<int>(bytecodes_.size()); |
71 int register_count = fixed_register_count() + temporary_register_count_; | 92 int register_count = fixed_register_count() + temporary_register_count_; |
72 int frame_size = register_count * kPointerSize; | 93 int frame_size = register_count * kPointerSize; |
73 | 94 |
74 Factory* factory = isolate_->factory(); | 95 Factory* factory = isolate_->factory(); |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 } | 614 } |
594 | 615 |
595 | 616 |
596 void BytecodeArrayBuilder::EnsureReturn() { | 617 void BytecodeArrayBuilder::EnsureReturn() { |
597 if (!return_seen_in_block_) { | 618 if (!return_seen_in_block_) { |
598 LoadUndefined(); | 619 LoadUndefined(); |
599 Return(); | 620 Return(); |
600 } | 621 } |
601 } | 622 } |
602 | 623 |
624 | |
603 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, | 625 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, |
604 Register receiver, | 626 Register receiver, |
605 size_t arg_count) { | 627 size_t arg_count) { |
606 if (FitsInIdx8Operand(arg_count)) { | 628 if (FitsInIdx8Operand(arg_count)) { |
607 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), | 629 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), |
608 static_cast<uint8_t>(arg_count)); | 630 static_cast<uint8_t>(arg_count)); |
609 } else { | 631 } else { |
610 UNIMPLEMENTED(); | 632 UNIMPLEMENTED(); |
611 } | 633 } |
612 return *this; | 634 return *this; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 entry = constants_map_.Get(object); | 669 entry = constants_map_.Get(object); |
648 *entry = constants_.size(); | 670 *entry = constants_.size(); |
649 constants_.push_back(object); | 671 constants_.push_back(object); |
650 } | 672 } |
651 DCHECK(constants_[*entry].is_identical_to(object)); | 673 DCHECK(constants_[*entry].is_identical_to(object)); |
652 return *entry; | 674 return *entry; |
653 } | 675 } |
654 | 676 |
655 | 677 |
656 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | 678 int BytecodeArrayBuilder::BorrowTemporaryRegister() { |
657 int temporary_reg_index = temporary_register_next_++; | 679 if (free_temporaries_.empty()) { |
658 int count = temporary_register_next_ - fixed_register_count(); | 680 temporary_register_count_ += 1; |
659 if (count > temporary_register_count_) { | 681 return last_temporary_register().index(); |
660 temporary_register_count_ = count; | 682 } else { |
683 auto pos = free_temporaries_.begin(); | |
684 int retval = *pos; | |
685 free_temporaries_.erase(pos); | |
686 return retval; | |
661 } | 687 } |
662 return temporary_reg_index; | 688 } |
689 | |
690 | |
691 void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) { | |
692 free_temporaries_.erase(reg_index); | |
rmcilroy
2015/10/20 16:39:20
Could you DCHECK that the value is in free_tempora
oth
2015/10/20 20:58:42
Done.
| |
663 } | 693 } |
664 | 694 |
665 | 695 |
666 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { | 696 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { |
667 DCHECK_EQ(reg_index, temporary_register_next_ - 1); | 697 DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end()); |
668 temporary_register_next_ = reg_index; | 698 free_temporaries_.insert(reg_index); |
669 } | 699 } |
670 | 700 |
671 | 701 |
702 int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters( | |
703 size_t count) { | |
704 if (count == 0) { | |
705 return -1; | |
706 } | |
707 | |
708 // Search within existing temporaries for a run. | |
709 auto start = free_temporaries_.begin(); | |
710 int run_length = 0; | |
711 for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) { | |
712 if (*run_end != *start + run_length) { | |
713 start = run_end; | |
714 run_length = 0; | |
715 } | |
716 if (++run_length == count) { | |
717 return *start; | |
718 } | |
719 } | |
720 | |
721 // Continue run if possible across existing last temporary. | |
722 if (temporary_register_count_ > 0 && | |
723 (start == free_temporaries_.end() || | |
724 *start + run_length != last_temporary_register().index() + 1)) { | |
725 run_length = 0; | |
726 } | |
727 | |
728 // Ensure enough registers for run. | |
729 while (run_length++ < count) { | |
730 temporary_register_count_++; | |
731 free_temporaries_.insert(last_temporary_register().index()); | |
732 } | |
733 return last_temporary_register().index() - static_cast<int>(count) + 1; | |
734 } | |
735 | |
736 | |
737 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { | |
738 if (temporary_register_count_ > 0) { | |
739 DCHECK(reg.index() >= first_temporary_register().index() && | |
740 reg.index() <= last_temporary_register().index()); | |
741 return free_temporaries_.find(reg.index()) == free_temporaries_.end(); | |
742 } else { | |
743 return false; | |
744 } | |
745 } | |
746 | |
747 | |
672 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, | 748 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, |
673 uint32_t operand_value) const { | 749 uint32_t operand_value) const { |
674 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); | 750 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); |
675 switch (operand_type) { | 751 switch (operand_type) { |
676 case OperandType::kNone: | 752 case OperandType::kNone: |
677 return false; | 753 return false; |
678 case OperandType::kIdx16: | 754 case OperandType::kIdx16: |
679 return static_cast<uint16_t>(operand_value) == operand_value; | 755 return static_cast<uint16_t>(operand_value) == operand_value; |
680 case OperandType::kCount8: | 756 case OperandType::kCount8: |
681 case OperandType::kImm8: | 757 case OperandType::kImm8: |
682 case OperandType::kIdx8: | 758 case OperandType::kIdx8: |
683 return static_cast<uint8_t>(operand_value) == operand_value; | 759 return static_cast<uint8_t>(operand_value) == operand_value; |
684 case OperandType::kReg8: { | 760 case OperandType::kReg8: { |
685 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); | 761 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); |
686 if (reg.is_function_context() || reg.is_function_closure()) { | 762 if (reg.is_function_context() || reg.is_function_closure()) { |
687 return true; | 763 return true; |
688 } else if (reg.is_parameter()) { | 764 } else if (reg.is_parameter()) { |
689 int parameter_index = reg.ToParameterIndex(parameter_count()); | 765 int parameter_index = reg.ToParameterIndex(parameter_count_); |
690 return parameter_index >= 0 && parameter_index < parameter_count(); | 766 return parameter_index >= 0 && parameter_index < parameter_count_; |
767 } else if (reg.index() < fixed_register_count()) { | |
768 return true; | |
691 } else { | 769 } else { |
692 return (reg.index() >= 0 && reg.index() < temporary_register_next_); | 770 return TemporaryRegisterIsLive(reg); |
693 } | 771 } |
694 } | 772 } |
695 } | 773 } |
696 UNREACHABLE(); | 774 UNREACHABLE(); |
697 return false; | 775 return false; |
698 } | 776 } |
699 | 777 |
700 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { | 778 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { |
701 return last_bytecode_start_ < bytecodes()->size() && | 779 return last_bytecode_start_ < bytecodes()->size() && |
702 last_bytecode_start_ >= last_block_end_; | 780 last_bytecode_start_ >= last_block_end_; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
866 } | 944 } |
867 | 945 |
868 | 946 |
869 // static | 947 // static |
870 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { | 948 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { |
871 return kMinUInt16 <= value && value <= kMaxUInt16; | 949 return kMinUInt16 <= value && value <= kMaxUInt16; |
872 } | 950 } |
873 | 951 |
874 | 952 |
875 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) | 953 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) |
876 : builder_(builder), count_(0), last_register_index_(-1) {} | 954 : builder_(builder), |
955 allocated_(builder->zone()), | |
956 next_consecutive_register_(-1), | |
957 next_consecutive_count_(-1) { | |
958 // TODO(oth): Deprecate TemporaryRegisterScope use. Should be using | |
959 // result scopes as far as possible. | |
rmcilroy
2015/10/20 16:39:20
nit - move TODO to TemporaryRegisterScope declarat
oth
2015/10/20 20:58:42
Done.
| |
960 } | |
877 | 961 |
878 | 962 |
879 TemporaryRegisterScope::~TemporaryRegisterScope() { | 963 TemporaryRegisterScope::~TemporaryRegisterScope() { |
880 while (count_-- != 0) { | 964 for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) { |
881 builder_->ReturnTemporaryRegister(last_register_index_--); | 965 builder_->ReturnTemporaryRegister(*i); |
966 } | |
967 allocated_.clear(); | |
968 } | |
969 | |
970 | |
971 Register TemporaryRegisterScope::NewRegister() { | |
972 int allocated = builder_->BorrowTemporaryRegister(); | |
973 allocated_.push_back(allocated); | |
974 return Register(allocated); | |
975 } | |
976 | |
977 | |
978 void TemporaryRegisterScope::PrepareForConsecutiveAllocations(size_t count) { | |
979 if (static_cast<int>(count) > next_consecutive_count_) { | |
980 next_consecutive_register_ = | |
981 builder_->PrepareForConsecutiveTemporaryRegisters(count); | |
982 next_consecutive_count_ = static_cast<int>(count); | |
882 } | 983 } |
883 } | 984 } |
884 | 985 |
885 | 986 |
886 Register TemporaryRegisterScope::NewRegister() { | 987 Register TemporaryRegisterScope::NextConsecutiveRegister() { |
887 count_++; | 988 DCHECK_GE(next_consecutive_register_, 0); |
888 last_register_index_ = builder_->BorrowTemporaryRegister(); | 989 DCHECK_GT(next_consecutive_count_, 0); |
889 return Register(last_register_index_); | 990 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
991 allocated_.push_back(next_consecutive_register_); | |
992 next_consecutive_count_--; | |
993 return Register(next_consecutive_register_++); | |
890 } | 994 } |
891 | 995 |
892 } // namespace interpreter | 996 } // namespace interpreter |
893 } // namespace internal | 997 } // namespace internal |
894 } // namespace v8 | 998 } // namespace v8 |
OLD | NEW |