text: // Copyright 2017 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_CODEGEN_LABEL_H_
  #define V8_CODEGEN_LABEL_H_
  
  #include "src/base/macros.h"
  
  namespace v8 {
  namespace internal {
  
  // -----------------------------------------------------------------------------
  // Labels represent pc locations; they are typically jump or call targets.
  // After declaration, a label can be freely used to denote known or (yet)
  // unknown pc location. Assembler::bind() is used to bind a label to the
  // current pc. A label can be bound only once.
  
  class Label {
   public:
    enum Distance {
      kNear,  // near jump: 8 bit displacement (signed)
      kFar    // far jump: 32 bit displacement (signed)
    };
  
    Label() = default;
  
    // Disallow copy construction and assignment, but allow move construction and
    // move assignment on selected platforms (see below).
    Label(const Label&) = delete;
    Label& operator=(const Label&) = delete;
  
  // On ARM64, the Assembler keeps track of pointers to Labels to resolve
  // branches to distant targets. Copying labels would confuse the Assembler.
  // On other platforms, allow move construction.
  #if !V8_TARGET_ARCH_ARM64
  // In debug builds, the old Label has to be cleared in order to avoid a DCHECK
  // failure in it's destructor.
  #ifdef DEBUG
    Label(Label&& other) V8_NOEXCEPT { *this = std::move(other); }
    Label& operator=(Label&& other) V8_NOEXCEPT {
      pos_ = other.pos_;
      near_link_pos_ = other.near_link_pos_;
      other.Unuse();
      other.UnuseNear();
      return *this;
    }
  #else
    Label(Label&&) V8_NOEXCEPT = default;
    Label& operator=(Label&&) V8_NOEXCEPT = default;
  #endif
  #endif
  
  #ifdef DEBUG
    V8_INLINE ~Label() {
      DCHECK(!is_linked());
      DCHECK(!is_near_linked());
    }
  #endif
  
    V8_INLINE void Unuse() { pos_ = 0; }
    V8_INLINE void UnuseNear() { near_link_pos_ = 0; }
  
    V8_INLINE bool is_bound() const { return pos_ < 0; }
    V8_INLINE bool is_unused() const { return pos_ == 0 && near_link_pos_ == 0; }
    V8_INLINE bool is_linked() const { return pos_ > 0; }
    V8_INLINE bool is_near_linked() const { return near_link_pos_ > 0; }
  
    // Returns the position of bound or linked labels. Cannot be used
    // for unused labels.
    int pos() const {
      if (pos_ < 0) return -pos_ - 1;
      if (pos_ > 0) return pos_ - 1;
      UNREACHABLE();
    }
  
    int near_link_pos() const { return near_link_pos_ - 1; }
  
   private:
    // pos_ encodes both the binding state (via its sign)
    // and the binding position (via its value) of a label.
    //
    // pos_ <  0  bound label, pos() returns the jump target position
    // pos_ == 0  unused label
    // pos_ >  0  linked label, pos() returns the last reference position
    int pos_ = 0;
  
    // Behaves like |pos_| in the "> 0" case, but for near jumps to this label.
    int near_link_pos_ = 0;
  
    void bind_to(int pos) {
      pos_ = -pos - 1;
      DCHECK(is_bound());
    }
    void link_to(int pos, Distance distance = kFar) {
      if (distance == kNear) {
        near_link_pos_ = pos + 1;
        DCHECK(is_near_linked());
      } else {
        pos_ = pos + 1;
        DCHECK(is_linked());
      }
    }
  
    friend class Assembler;
    friend class Displacement;
    friend class RegExpBytecodeGenerator;
  };
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_CODEGEN_LABEL_H_
  