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 3 // found in the LICENSE file. 4 5 #ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ 6 #define V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ 7 8 #include "src/interpreter/bytecode-register.h" 9 #include "src/interpreter/bytecodes.h" 10 #include "src/zone/zone-containers.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace interpreter { 15 16 // A class that allows the allocation of contiguous temporary registers. 17 class BytecodeRegisterAllocator final { 18 public: 19 // Enables observation of register allocation and free events. 20 class Observer { 21 public: ~Observer()22 virtual ~Observer() {} 23 virtual void RegisterAllocateEvent(Register reg) = 0; 24 virtual void RegisterListAllocateEvent(RegisterList reg_list) = 0; 25 virtual void RegisterListFreeEvent(RegisterList reg_list) = 0; 26 }; 27 BytecodeRegisterAllocator(int start_index)28 explicit BytecodeRegisterAllocator(int start_index) 29 : next_register_index_(start_index), 30 max_register_count_(start_index), 31 observer_(nullptr) {} ~BytecodeRegisterAllocator()32 ~BytecodeRegisterAllocator() {} 33 34 // Returns a new register. NewRegister()35 Register NewRegister() { 36 Register reg(next_register_index_++); 37 max_register_count_ = std::max(next_register_index_, max_register_count_); 38 if (observer_) { 39 observer_->RegisterAllocateEvent(reg); 40 } 41 return reg; 42 } 43 44 // Returns a consecutive list of |count| new registers. NewRegisterList(int count)45 RegisterList NewRegisterList(int count) { 46 RegisterList reg_list(next_register_index_, count); 47 next_register_index_ += count; 48 max_register_count_ = std::max(next_register_index_, max_register_count_); 49 if (observer_) { 50 observer_->RegisterListAllocateEvent(reg_list); 51 } 52 return reg_list; 53 } 54 55 // Returns a growable register list. NewGrowableRegisterList()56 RegisterList NewGrowableRegisterList() { 57 RegisterList reg_list(next_register_index_, 0); 58 return reg_list; 59 } 60 61 // Appends a new register to |reg_list| increasing it's count by one and 62 // returning the register added. 63 // 64 // Note: no other new registers must be currently allocated since the register 65 // list was originally allocated. GrowRegisterList(RegisterList * reg_list)66 Register GrowRegisterList(RegisterList* reg_list) { 67 Register reg(NewRegister()); 68 reg_list->IncrementRegisterCount(); 69 // If the following CHECK fails then a register was allocated (and not 70 // freed) between the creation of the RegisterList and this call to add a 71 // Register. 72 CHECK_EQ(reg.index(), reg_list->last_register().index()); 73 return reg; 74 } 75 76 // Release all registers above |register_index|. ReleaseRegisters(int register_index)77 void ReleaseRegisters(int register_index) { 78 if (observer_) { 79 observer_->RegisterListFreeEvent( 80 RegisterList(register_index, next_register_index_ - register_index)); 81 } 82 next_register_index_ = register_index; 83 } 84 85 // Returns true if the register |reg| is a live register. RegisterIsLive(Register reg)86 bool RegisterIsLive(Register reg) const { 87 return reg.index() < next_register_index_; 88 } 89 set_observer(Observer * observer)90 void set_observer(Observer* observer) { observer_ = observer; } 91 next_register_index()92 int next_register_index() const { return next_register_index_; } maximum_register_count()93 int maximum_register_count() const { return max_register_count_; } 94 95 private: 96 int next_register_index_; 97 int max_register_count_; 98 Observer* observer_; 99 100 DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator); 101 }; 102 103 } // namespace interpreter 104 } // namespace internal 105 } // namespace v8 106 107 108 #endif // V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ 109