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