Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: src/interpreter/bytecode-array-builder.cc

Issue 1392933002: [Interpreter] Reduce temporary register usage in generated bytecode. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Remove dead code. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698