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