1 | // Copyright 2017 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_LABEL_H_ |
6 | #define V8_LABEL_H_ |
7 | |
8 | #include "src/base/macros.h" |
9 | |
10 | namespace v8 { |
11 | namespace internal { |
12 | |
13 | // ----------------------------------------------------------------------------- |
14 | // Labels represent pc locations; they are typically jump or call targets. |
15 | // After declaration, a label can be freely used to denote known or (yet) |
16 | // unknown pc location. Assembler::bind() is used to bind a label to the |
17 | // current pc. A label can be bound only once. |
18 | |
19 | class Label { |
20 | public: |
21 | enum Distance { |
22 | kNear, // near jump: 8 bit displacement (signed) |
23 | kFar // far jump: 32 bit displacement (signed) |
24 | }; |
25 | |
26 | Label() = default; |
27 | |
28 | // On ARM64, the Assembler keeps track of pointers to Labels to resolve |
29 | // branches to distant targets. Copying labels would confuse the Assembler. |
30 | // On other platforms, allow move construction. |
31 | #if !V8_TARGET_ARCH_ARM64 |
32 | // In debug builds, the old Label has to be cleared in order to avoid a DCHECK |
33 | // failure in it's destructor. |
34 | #ifdef DEBUG |
35 | Label(Label&& other) V8_NOEXCEPT { *this = std::move(other); } |
36 | Label& operator=(Label&& other) V8_NOEXCEPT { |
37 | pos_ = other.pos_; |
38 | near_link_pos_ = other.near_link_pos_; |
39 | other.Unuse(); |
40 | other.UnuseNear(); |
41 | return *this; |
42 | } |
43 | #else |
44 | Label(Label&&) V8_NOEXCEPT = default; |
45 | Label& operator=(Label&&) V8_NOEXCEPT = default; |
46 | #endif |
47 | #endif |
48 | |
49 | #ifdef DEBUG |
50 | V8_INLINE ~Label() { |
51 | DCHECK(!is_linked()); |
52 | DCHECK(!is_near_linked()); |
53 | } |
54 | #endif |
55 | |
56 | V8_INLINE void Unuse() { pos_ = 0; } |
57 | V8_INLINE void UnuseNear() { near_link_pos_ = 0; } |
58 | |
59 | V8_INLINE bool is_bound() const { return pos_ < 0; } |
60 | V8_INLINE bool is_unused() const { return pos_ == 0 && near_link_pos_ == 0; } |
61 | V8_INLINE bool is_linked() const { return pos_ > 0; } |
62 | V8_INLINE bool is_near_linked() const { return near_link_pos_ > 0; } |
63 | |
64 | // Returns the position of bound or linked labels. Cannot be used |
65 | // for unused labels. |
66 | int pos() const { |
67 | if (pos_ < 0) return -pos_ - 1; |
68 | if (pos_ > 0) return pos_ - 1; |
69 | UNREACHABLE(); |
70 | } |
71 | |
72 | int near_link_pos() const { return near_link_pos_ - 1; } |
73 | |
74 | private: |
75 | // pos_ encodes both the binding state (via its sign) |
76 | // and the binding position (via its value) of a label. |
77 | // |
78 | // pos_ < 0 bound label, pos() returns the jump target position |
79 | // pos_ == 0 unused label |
80 | // pos_ > 0 linked label, pos() returns the last reference position |
81 | int pos_ = 0; |
82 | |
83 | // Behaves like |pos_| in the "> 0" case, but for near jumps to this label. |
84 | int near_link_pos_ = 0; |
85 | |
86 | void bind_to(int pos) { |
87 | pos_ = -pos - 1; |
88 | DCHECK(is_bound()); |
89 | } |
90 | void link_to(int pos, Distance distance = kFar) { |
91 | if (distance == kNear) { |
92 | near_link_pos_ = pos + 1; |
93 | DCHECK(is_near_linked()); |
94 | } else { |
95 | pos_ = pos + 1; |
96 | DCHECK(is_linked()); |
97 | } |
98 | } |
99 | |
100 | friend class Assembler; |
101 | friend class Displacement; |
102 | friend class RegExpMacroAssemblerIrregexp; |
103 | |
104 | // Disallow copy construction and assignment, but allow move construction and |
105 | // move assignment on selected platforms (see above). |
106 | DISALLOW_COPY_AND_ASSIGN(Label); |
107 | }; |
108 | |
109 | } // namespace internal |
110 | } // namespace v8 |
111 | |
112 | #endif // V8_LABEL_H_ |
113 | |