• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_CODEGEN_LABEL_H_
6 #define V8_CODEGEN_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   // Disallow copy construction and assignment, but allow move construction and
29   // move assignment on selected platforms (see below).
30   Label(const Label&) = delete;
31   Label& operator=(const Label&) = delete;
32 
33 // On ARM64, the Assembler keeps track of pointers to Labels to resolve
34 // branches to distant targets. Copying labels would confuse the Assembler.
35 // On other platforms, allow move construction.
36 #if !V8_TARGET_ARCH_ARM64
37 // In debug builds, the old Label has to be cleared in order to avoid a DCHECK
38 // failure in it's destructor.
39 #ifdef DEBUG
Label(Label && other)40   Label(Label&& other) V8_NOEXCEPT { *this = std::move(other); }
41   Label& operator=(Label&& other) V8_NOEXCEPT {
42     pos_ = other.pos_;
43     near_link_pos_ = other.near_link_pos_;
44     other.Unuse();
45     other.UnuseNear();
46     return *this;
47   }
48 #else
49   Label(Label&&) V8_NOEXCEPT = default;
50   Label& operator=(Label&&) V8_NOEXCEPT = default;
51 #endif
52 #endif
53 
54 #ifdef DEBUG
~Label()55   V8_INLINE ~Label() {
56     DCHECK(!is_linked());
57     DCHECK(!is_near_linked());
58   }
59 #endif
60 
Unuse()61   V8_INLINE void Unuse() { pos_ = 0; }
UnuseNear()62   V8_INLINE void UnuseNear() { near_link_pos_ = 0; }
63 
is_bound()64   V8_INLINE bool is_bound() const { return pos_ < 0; }
is_unused()65   V8_INLINE bool is_unused() const { return pos_ == 0 && near_link_pos_ == 0; }
is_linked()66   V8_INLINE bool is_linked() const { return pos_ > 0; }
is_near_linked()67   V8_INLINE bool is_near_linked() const { return near_link_pos_ > 0; }
68 
69   // Returns the position of bound or linked labels. Cannot be used
70   // for unused labels.
pos()71   int pos() const {
72     if (pos_ < 0) return -pos_ - 1;
73     if (pos_ > 0) return pos_ - 1;
74     UNREACHABLE();
75   }
76 
near_link_pos()77   int near_link_pos() const { return near_link_pos_ - 1; }
78 
79  private:
80   // pos_ encodes both the binding state (via its sign)
81   // and the binding position (via its value) of a label.
82   //
83   // pos_ <  0  bound label, pos() returns the jump target position
84   // pos_ == 0  unused label
85   // pos_ >  0  linked label, pos() returns the last reference position
86   int pos_ = 0;
87 
88   // Behaves like |pos_| in the "> 0" case, but for near jumps to this label.
89   int near_link_pos_ = 0;
90 
bind_to(int pos)91   void bind_to(int pos) {
92     pos_ = -pos - 1;
93     DCHECK(is_bound());
94   }
95   void link_to(int pos, Distance distance = kFar) {
96     if (distance == kNear) {
97       near_link_pos_ = pos + 1;
98       DCHECK(is_near_linked());
99     } else {
100       pos_ = pos + 1;
101       DCHECK(is_linked());
102     }
103   }
104 
105   friend class Assembler;
106   friend class Displacement;
107   friend class RegExpBytecodeGenerator;
108 };
109 
110 }  // namespace internal
111 }  // namespace v8
112 
113 #endif  // V8_CODEGEN_LABEL_H_
114