| 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 exit_seen_in_block_(false), | 18 exit_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 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 } | 621 } |
| 601 | 622 |
| 602 | 623 |
| 603 void BytecodeArrayBuilder::EnsureReturn() { | 624 void BytecodeArrayBuilder::EnsureReturn() { |
| 604 if (!exit_seen_in_block_) { | 625 if (!exit_seen_in_block_) { |
| 605 LoadUndefined(); | 626 LoadUndefined(); |
| 606 Return(); | 627 Return(); |
| 607 } | 628 } |
| 608 } | 629 } |
| 609 | 630 |
| 631 |
| 610 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, | 632 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, |
| 611 Register receiver, | 633 Register receiver, |
| 612 size_t arg_count) { | 634 size_t arg_count) { |
| 613 if (FitsInIdx8Operand(arg_count)) { | 635 if (FitsInIdx8Operand(arg_count)) { |
| 614 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), | 636 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(), |
| 615 static_cast<uint8_t>(arg_count)); | 637 static_cast<uint8_t>(arg_count)); |
| 616 } else { | 638 } else { |
| 617 UNIMPLEMENTED(); | 639 UNIMPLEMENTED(); |
| 618 } | 640 } |
| 619 return *this; | 641 return *this; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 entry = constants_map_.Get(object); | 676 entry = constants_map_.Get(object); |
| 655 *entry = constants_.size(); | 677 *entry = constants_.size(); |
| 656 constants_.push_back(object); | 678 constants_.push_back(object); |
| 657 } | 679 } |
| 658 DCHECK(constants_[*entry].is_identical_to(object)); | 680 DCHECK(constants_[*entry].is_identical_to(object)); |
| 659 return *entry; | 681 return *entry; |
| 660 } | 682 } |
| 661 | 683 |
| 662 | 684 |
| 663 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | 685 int BytecodeArrayBuilder::BorrowTemporaryRegister() { |
| 664 int temporary_reg_index = temporary_register_next_++; | 686 if (free_temporaries_.empty()) { |
| 665 int count = temporary_register_next_ - fixed_register_count(); | 687 temporary_register_count_ += 1; |
| 666 if (count > temporary_register_count_) { | 688 return last_temporary_register().index(); |
| 667 temporary_register_count_ = count; | 689 } else { |
| 690 auto pos = free_temporaries_.begin(); |
| 691 int retval = *pos; |
| 692 free_temporaries_.erase(pos); |
| 693 return retval; |
| 668 } | 694 } |
| 669 return temporary_reg_index; | 695 } |
| 696 |
| 697 |
| 698 void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) { |
| 699 DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end()); |
| 700 free_temporaries_.erase(reg_index); |
| 670 } | 701 } |
| 671 | 702 |
| 672 | 703 |
| 673 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { | 704 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { |
| 674 DCHECK_EQ(reg_index, temporary_register_next_ - 1); | 705 DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end()); |
| 675 temporary_register_next_ = reg_index; | 706 free_temporaries_.insert(reg_index); |
| 676 } | 707 } |
| 677 | 708 |
| 678 | 709 |
| 710 int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters( |
| 711 size_t count) { |
| 712 if (count == 0) { |
| 713 return -1; |
| 714 } |
| 715 |
| 716 // Search within existing temporaries for a run. |
| 717 auto start = free_temporaries_.begin(); |
| 718 size_t run_length = 0; |
| 719 for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) { |
| 720 if (*run_end != *start + static_cast<int>(run_length)) { |
| 721 start = run_end; |
| 722 run_length = 0; |
| 723 } |
| 724 if (++run_length == count) { |
| 725 return *start; |
| 726 } |
| 727 } |
| 728 |
| 729 // Continue run if possible across existing last temporary. |
| 730 if (temporary_register_count_ > 0 && |
| 731 (start == free_temporaries_.end() || |
| 732 *start + static_cast<int>(run_length) != |
| 733 last_temporary_register().index() + 1)) { |
| 734 run_length = 0; |
| 735 } |
| 736 |
| 737 // Ensure enough registers for run. |
| 738 while (run_length++ < count) { |
| 739 temporary_register_count_++; |
| 740 free_temporaries_.insert(last_temporary_register().index()); |
| 741 } |
| 742 return last_temporary_register().index() - static_cast<int>(count) + 1; |
| 743 } |
| 744 |
| 745 |
| 746 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { |
| 747 if (temporary_register_count_ > 0) { |
| 748 DCHECK(reg.index() >= first_temporary_register().index() && |
| 749 reg.index() <= last_temporary_register().index()); |
| 750 return free_temporaries_.find(reg.index()) == free_temporaries_.end(); |
| 751 } else { |
| 752 return false; |
| 753 } |
| 754 } |
| 755 |
| 756 |
| 679 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, | 757 bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, |
| 680 uint32_t operand_value) const { | 758 uint32_t operand_value) const { |
| 681 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); | 759 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); |
| 682 switch (operand_type) { | 760 switch (operand_type) { |
| 683 case OperandType::kNone: | 761 case OperandType::kNone: |
| 684 return false; | 762 return false; |
| 685 case OperandType::kIdx16: | 763 case OperandType::kIdx16: |
| 686 return static_cast<uint16_t>(operand_value) == operand_value; | 764 return static_cast<uint16_t>(operand_value) == operand_value; |
| 687 case OperandType::kCount8: | 765 case OperandType::kCount8: |
| 688 case OperandType::kImm8: | 766 case OperandType::kImm8: |
| 689 case OperandType::kIdx8: | 767 case OperandType::kIdx8: |
| 690 return static_cast<uint8_t>(operand_value) == operand_value; | 768 return static_cast<uint8_t>(operand_value) == operand_value; |
| 691 case OperandType::kReg8: { | 769 case OperandType::kReg8: { |
| 692 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); | 770 Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value)); |
| 693 if (reg.is_function_context() || reg.is_function_closure()) { | 771 if (reg.is_function_context() || reg.is_function_closure()) { |
| 694 return true; | 772 return true; |
| 695 } else if (reg.is_parameter()) { | 773 } else if (reg.is_parameter()) { |
| 696 int parameter_index = reg.ToParameterIndex(parameter_count()); | 774 int parameter_index = reg.ToParameterIndex(parameter_count_); |
| 697 return parameter_index >= 0 && parameter_index < parameter_count(); | 775 return parameter_index >= 0 && parameter_index < parameter_count_; |
| 776 } else if (reg.index() < fixed_register_count()) { |
| 777 return true; |
| 698 } else { | 778 } else { |
| 699 return (reg.index() >= 0 && reg.index() < temporary_register_next_); | 779 return TemporaryRegisterIsLive(reg); |
| 700 } | 780 } |
| 701 } | 781 } |
| 702 } | 782 } |
| 703 UNREACHABLE(); | 783 UNREACHABLE(); |
| 704 return false; | 784 return false; |
| 705 } | 785 } |
| 706 | 786 |
| 707 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { | 787 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { |
| 708 return last_bytecode_start_ < bytecodes()->size() && | 788 return last_bytecode_start_ < bytecodes()->size() && |
| 709 last_bytecode_start_ >= last_block_end_; | 789 last_bytecode_start_ >= last_block_end_; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 } | 953 } |
| 874 | 954 |
| 875 | 955 |
| 876 // static | 956 // static |
| 877 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { | 957 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { |
| 878 return kMinUInt16 <= value && value <= kMaxUInt16; | 958 return kMinUInt16 <= value && value <= kMaxUInt16; |
| 879 } | 959 } |
| 880 | 960 |
| 881 | 961 |
| 882 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) | 962 TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) |
| 883 : builder_(builder), count_(0), last_register_index_(-1) {} | 963 : builder_(builder), |
| 964 allocated_(builder->zone()), |
| 965 next_consecutive_register_(-1), |
| 966 next_consecutive_count_(-1) {} |
| 884 | 967 |
| 885 | 968 |
| 886 TemporaryRegisterScope::~TemporaryRegisterScope() { | 969 TemporaryRegisterScope::~TemporaryRegisterScope() { |
| 887 while (count_-- != 0) { | 970 for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) { |
| 888 builder_->ReturnTemporaryRegister(last_register_index_--); | 971 builder_->ReturnTemporaryRegister(*i); |
| 972 } |
| 973 allocated_.clear(); |
| 974 } |
| 975 |
| 976 |
| 977 Register TemporaryRegisterScope::NewRegister() { |
| 978 int allocated = builder_->BorrowTemporaryRegister(); |
| 979 allocated_.push_back(allocated); |
| 980 return Register(allocated); |
| 981 } |
| 982 |
| 983 |
| 984 void TemporaryRegisterScope::PrepareForConsecutiveAllocations(size_t count) { |
| 985 if (static_cast<int>(count) > next_consecutive_count_) { |
| 986 next_consecutive_register_ = |
| 987 builder_->PrepareForConsecutiveTemporaryRegisters(count); |
| 988 next_consecutive_count_ = static_cast<int>(count); |
| 889 } | 989 } |
| 890 } | 990 } |
| 891 | 991 |
| 892 | 992 |
| 893 Register TemporaryRegisterScope::NewRegister() { | 993 Register TemporaryRegisterScope::NextConsecutiveRegister() { |
| 894 count_++; | 994 DCHECK_GE(next_consecutive_register_, 0); |
| 895 last_register_index_ = builder_->BorrowTemporaryRegister(); | 995 DCHECK_GT(next_consecutive_count_, 0); |
| 896 return Register(last_register_index_); | 996 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
| 997 allocated_.push_back(next_consecutive_register_); |
| 998 next_consecutive_count_--; |
| 999 return Register(next_consecutive_register_++); |
| 897 } | 1000 } |
| 898 | 1001 |
| 899 } // namespace interpreter | 1002 } // namespace interpreter |
| 900 } // namespace internal | 1003 } // namespace internal |
| 901 } // namespace v8 | 1004 } // namespace v8 |
| OLD | NEW |