| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ |
| #define V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ |
| |
| #include "src/interpreter/bytecode-register.h" |
| #include "src/interpreter/bytecodes.h" |
| #include "src/zone/zone-containers.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace interpreter { |
| |
| // A class that allows the allocation of contiguous temporary registers. |
| class BytecodeRegisterAllocator final { |
| public: |
| // Enables observation of register allocation and free events. |
| class Observer { |
| public: |
| virtual ~Observer() = default; |
| virtual void RegisterAllocateEvent(Register reg) = 0; |
| virtual void RegisterListAllocateEvent(RegisterList reg_list) = 0; |
| virtual void RegisterListFreeEvent(RegisterList reg_list) = 0; |
| }; |
| |
| explicit BytecodeRegisterAllocator(int start_index) |
| : next_register_index_(start_index), |
| max_register_count_(start_index), |
| observer_(nullptr) {} |
| ~BytecodeRegisterAllocator() = default; |
| BytecodeRegisterAllocator(const BytecodeRegisterAllocator&) = delete; |
| BytecodeRegisterAllocator& operator=(const BytecodeRegisterAllocator&) = |
| delete; |
| |
| // Returns a new register. |
| Register NewRegister() { |
| Register reg(next_register_index_++); |
| max_register_count_ = std::max(next_register_index_, max_register_count_); |
| if (observer_) { |
| observer_->RegisterAllocateEvent(reg); |
| } |
| return reg; |
| } |
| |
| // Returns a consecutive list of |count| new registers. |
| RegisterList NewRegisterList(int count) { |
| RegisterList reg_list(next_register_index_, count); |
| next_register_index_ += count; |
| max_register_count_ = std::max(next_register_index_, max_register_count_); |
| if (observer_) { |
| observer_->RegisterListAllocateEvent(reg_list); |
| } |
| return reg_list; |
| } |
| |
| // Returns a growable register list. |
| RegisterList NewGrowableRegisterList() { |
| RegisterList reg_list(next_register_index_, 0); |
| return reg_list; |
| } |
| |
| // Appends a new register to |reg_list| increasing it's count by one and |
| // returning the register added. |
| // |
| // Note: no other new registers must be currently allocated since the register |
| // list was originally allocated. |
| Register GrowRegisterList(RegisterList* reg_list) { |
| Register reg(NewRegister()); |
| reg_list->IncrementRegisterCount(); |
| // If the following CHECK fails then a register was allocated (and not |
| // freed) between the creation of the RegisterList and this call to add a |
| // Register. |
| CHECK_EQ(reg.index(), reg_list->last_register().index()); |
| return reg; |
| } |
| |
| // Release all registers above |register_index|. |
| void ReleaseRegisters(int register_index) { |
| int count = next_register_index_ - register_index; |
| next_register_index_ = register_index; |
| if (observer_) { |
| observer_->RegisterListFreeEvent(RegisterList(register_index, count)); |
| } |
| } |
| |
| // Returns true if the register |reg| is a live register. |
| bool RegisterIsLive(Register reg) const { |
| return reg.index() < next_register_index_; |
| } |
| |
| // Returns a register list for all currently live registers. |
| RegisterList AllLiveRegisters() const { |
| return RegisterList(0, next_register_index()); |
| } |
| |
| void set_observer(Observer* observer) { observer_ = observer; } |
| |
| int next_register_index() const { return next_register_index_; } |
| int maximum_register_count() const { return max_register_count_; } |
| |
| private: |
| int next_register_index_; |
| int max_register_count_; |
| Observer* observer_; |
| }; |
| |
| } // namespace interpreter |
| } // namespace internal |
| } // namespace v8 |
| |
| |
| #endif // V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ |