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_LABEL_H_
6#define V8_INTERPRETER_BYTECODE_LABEL_H_
7
8#include <algorithm>
9
10#include "src/zone/zone-containers.h"
11
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
16class BytecodeArrayBuilder;
17
18// A label representing a loop header in a bytecode array. It is bound before
19// the jump is seen, so its position is always known by the time the jump is
20// reached.
21class V8_EXPORT_PRIVATE BytecodeLoopHeader final {
22 public:
23  BytecodeLoopHeader() : offset_(kInvalidOffset) {}
24
25  size_t offset() const {
26    DCHECK_NE(offset_, kInvalidOffset);
27    return offset_;
28  }
29
30 private:
31  static const size_t kInvalidOffset = static_cast<size_t>(-1);
32
33  void bind_to(size_t offset) {
34    DCHECK_NE(offset, kInvalidOffset);
35    DCHECK_EQ(offset_, kInvalidOffset);
36    offset_ = offset;
37  }
38
39  // The bytecode offset of the loop header.
40  size_t offset_;
41
42  friend class BytecodeArrayWriter;
43};
44
45// A label representing a forward branch target in a bytecode array. When a
46// label is bound, it represents a known position in the bytecode array. A label
47// can only have at most one referrer jump.
48class V8_EXPORT_PRIVATE BytecodeLabel final {
49 public:
50  BytecodeLabel() : bound_(false), jump_offset_(kInvalidOffset) {}
51
52  bool is_bound() const { return bound_; }
53  size_t jump_offset() const {
54    DCHECK_NE(jump_offset_, kInvalidOffset);
55    return jump_offset_;
56  }
57
58  bool has_referrer_jump() const { return jump_offset_ != kInvalidOffset; }
59
60 private:
61  static const size_t kInvalidOffset = static_cast<size_t>(-1);
62
63  void bind() {
64    DCHECK(!bound_);
65    bound_ = true;
66  }
67
68  void set_referrer(size_t offset) {
69    DCHECK(!bound_);
70    DCHECK_NE(offset, kInvalidOffset);
71    DCHECK_EQ(jump_offset_, kInvalidOffset);
72    jump_offset_ = offset;
73  }
74
75  // Set when the label is bound (i.e. the start of the target basic block).
76  bool bound_;
77  // Set when the jump referrer is set (i.e. the location of the jump).
78  size_t jump_offset_;
79
80  friend class BytecodeArrayWriter;
81};
82
83// Class representing a branch target of multiple jumps.
84class V8_EXPORT_PRIVATE BytecodeLabels {
85 public:
86  explicit BytecodeLabels(Zone* zone) : labels_(zone), is_bound_(false) {}
87  BytecodeLabels(const BytecodeLabels&) = delete;
88  BytecodeLabels& operator=(const BytecodeLabels&) = delete;
89
90  BytecodeLabel* New();
91
92  void Bind(BytecodeArrayBuilder* builder);
93
94  bool is_bound() const {
95    DCHECK_IMPLIES(
96        is_bound_,
97        std::all_of(labels_.begin(), labels_.end(), [](const BytecodeLabel& l) {
98          return !l.has_referrer_jump() || l.is_bound();
99        }));
100    return is_bound_;
101  }
102
103  bool empty() const { return labels_.empty(); }
104
105 private:
106  ZoneLinkedList<BytecodeLabel> labels_;
107  bool is_bound_;
108};
109
110}  // namespace interpreter
111}  // namespace internal
112}  // namespace v8
113
114#endif  // V8_INTERPRETER_BYTECODE_LABEL_H_
115