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