Chromium Code Reviews| 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 |