// 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() {}
|
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() {}
|
|
// 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_;
|
|
DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator);
|
};
|
|
} // namespace interpreter
|
} // namespace internal
|
} // namespace v8
|
|
|
#endif // V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_
|