content: // ASM: a very small and fast Java bytecode manipulation framework
  // Copyright (c) 2000-2011 INRIA, France Telecom
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions
  // are met:
  // 1. Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  // 2. Redistributions in binary form must reproduce the above copyright
  //    notice, this list of conditions and the following disclaimer in the
  //    documentation and/or other materials provided with the distribution.
  // 3. Neither the name of the copyright holders nor the names of its
  //    contributors may be used to endorse or promote products derived from
  //    this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  // THE POSSIBILITY OF SUCH DAMAGE.
  package com.alibaba.fastjson2.internal.asm;
  
  /**
   * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
   * and for try catch blocks. A label designates the <i>instruction</i> that is just after. Note
   * however that there can be other elements between a label and the instruction it designates (such
   * as other labels, stack map frames, line numbers, etc.).
   *
   * @author Eric Bruneton
   */
  public class Label {
      /**
       * A flag indicating that a label is only used for debug attributes. Such a label is not the start
       * of a basic block, the target of a jump instruction, or an exception handler. It can be safely
       * ignored in control flow graph analysis algorithms (for optimization purposes).
       */
      static final int FLAG_DEBUG_ONLY = 1;
  
      /**
       * A flag indicating that a label is the target of a jump instruction, or the start of an
       * exception handler.
       */
      static final int FLAG_JUMP_TARGET = 2;
  
      /**
       * A flag indicating that the bytecode offset of a label is known.
       */
      static final int FLAG_RESOLVED = 4;
  
      /**
       * A flag indicating that a label corresponds to a reachable basic block.
       */
      static final int FLAG_REACHABLE = 8;
  
      /**
       * The number of elements to add to the {@link #forwardReferences} array when it needs to be
       * resized to store a new forward reference.
       */
      static final int FORWARD_REFERENCES_CAPACITY_INCREMENT = 6;
  
      /**
       * The bit mask to extract the type of a forward reference to this label. The extracted type is
       * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}.
       *
       * @see #forwardReferences
       */
      static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000;
  
      /**
       * The type of forward references stored with two bytes in the bytecode. This is the case, for
       * instance, of a forward reference from an ifnull instruction.
       */
      static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000;
  
      /**
       * The type of forward references stored in four bytes in the bytecode. This is the case, for
       * instance, of a forward reference from a lookupswitch instruction.
       */
      static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000;
  
      /**
       * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle
       * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes,
       * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}).
       *
       * @see #forwardReferences
       */
      static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF;
  
      /**
       * A sentinel element used to indicate the end of a list of labels.
       *
       * @see #nextListElement
       */
      static final Label EMPTY_LIST = new Label();
  
      /**
       * A user managed state associated with this label. Warning: this field is used by the ASM tree
       * package. In order to use it with the ASM tree package you must override the getLabelNode method
       * in MethodNode.
       */
      public Object info;
  
      short flags;
  
      /**
       * The offset of this label in the bytecode of its method, in bytes. This value is set if and only
       * if the {@link #FLAG_RESOLVED} flag is set.
       */
      int bytecodeOffset;
  
      /**
       * The forward references to this label. The first element is the number of forward references,
       * times 2 (this corresponds to the index of the last element actually used in this array). Then,
       * each forward reference is described with two consecutive integers noted
       * 'sourceInsnBytecodeOffset' and 'reference':
       *
       * <ul>
       *   <li>'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the
       *       forward reference,
       *   <li>'reference' contains the type and the offset in the bytecode where the forward reference
       *       value must be stored, which can be extracted with {@link #FORWARD_REFERENCE_TYPE_MASK}
       *       and {@link #FORWARD_REFERENCE_HANDLE_MASK}.
       * </ul>
       *
       * <p>For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is
       * equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1
       * (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after
       * the start of the instruction itself). For the default case of a lookupswitch instruction at
       * bytecode offset x, 'sourceInsnBytecodeOffset' is equal to x, and 'reference' is of type {@link
       * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the lookupswitch
       * instruction uses a 4 bytes bytecode offset operand stored one to four bytes after the start of
       * the instruction itself).
       */
      private int[] forwardReferences;
  
      /**
       * The maximum height reached by the output stack, relatively to the top of the input stack, in
       * the basic block corresponding to this label. This maximum is always positive or {@literal
       * null}.
       */
      short outputStackMax;
  
      Frame frame;
  
      Label nextBasicBlock;
  
      Edge outgoingEdges;
  
      Label nextListElement;
  
      // -----------------------------------------------------------------------------------------------
      // Constructor and accessors
      // -----------------------------------------------------------------------------------------------
  
      /**
       * Constructs a new label.
       */
      public Label() {
          // Nothing to do.
      }
  
      final Label getCanonicalInstance() {
          return frame == null ? this : frame.owner;
      }
  
      // -----------------------------------------------------------------------------------------------
      // Methods to compute offsets and to manage forward references
      // -----------------------------------------------------------------------------------------------
  
      /**
       * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label
       * is known, the relative bytecode offset between the label and the instruction referencing it is
       * computed and written directly. Otherwise, a null relative offset is written and a new forward
       * reference is declared for this label.
       *
       * @param code                     the bytecode of the method. This is where the reference is appended.
       * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
       *                                 reference to be appended.
       * @param wideReference            whether the reference must be stored in 4 bytes (instead of 2 bytes).
       */
      final void put(
              final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) {
          if ((flags & FLAG_RESOLVED) == 0) {
              if (wideReference) {
                  addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length);
                  code.putInt(-1);
              } else {
                  addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length);
                  code.putShort(-1);
              }
          } else {
              if (wideReference) {
                  code.putInt(bytecodeOffset - sourceInsnBytecodeOffset);
              } else {
                  code.putShort(bytecodeOffset - sourceInsnBytecodeOffset);
              }
          }
      }
  
      /**
       * Adds a forward reference to this label. This method must be called only for a true forward
       * reference, i.e. only if this label is not resolved yet. For backward references, the relative
       * bytecode offset of the reference can be, and must be, computed and stored directly.
       *
       * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
       *                                 reference stored at referenceHandle.
       * @param referenceType            either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link
       *                                 #FORWARD_REFERENCE_TYPE_WIDE}.
       * @param referenceHandle          the offset in the bytecode where the forward reference value must be
       *                                 stored.
       */
      private void addForwardReference(
              final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) {
          if (forwardReferences == null) {
              forwardReferences = new int[FORWARD_REFERENCES_CAPACITY_INCREMENT];
          }
          int lastElementIndex = forwardReferences[0];
          if (lastElementIndex + 2 >= forwardReferences.length) {
              int[] newValues = new int[forwardReferences.length + FORWARD_REFERENCES_CAPACITY_INCREMENT];
              System.arraycopy(forwardReferences, 0, newValues, 0, forwardReferences.length);
              forwardReferences = newValues;
          }
          forwardReferences[lastElementIndex + 1] = sourceInsnBytecodeOffset;
          forwardReferences[lastElementIndex + 2] = referenceType | referenceHandle;
          forwardReferences[0] = lastElementIndex + 2;
      }
  
      /**
       * Sets the bytecode offset of this label to the given value and resolves the forward references
       * to this label, if any. This method must be called when this label is added to the bytecode of
       * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that
       * where left in the bytecode by each forward reference previously added to this label.
       *
       * @param code           the bytecode of the method.
       * @param bytecodeOffset the bytecode offset of this label.
       * @return {@literal true} if a blank that was left for this label was too small to store the
       * offset. In such a case the corresponding jump instruction is replaced with an equivalent
       * ASM specific instruction using an unsigned two bytes offset. These ASM specific
       * instructions are later replaced with standard bytecode instructions with wider offsets (4
       * bytes instead of 2), in ClassReader.
       */
      final boolean resolve(final byte[] code, final int bytecodeOffset) {
          this.flags |= FLAG_RESOLVED;
          this.bytecodeOffset = bytecodeOffset;
          if (forwardReferences == null) {
              return false;
          }
          boolean hasAsmInstructions = false;
          for (int i = forwardReferences[0]; i > 0; i -= 2) {
              final int sourceInsnBytecodeOffset = forwardReferences[i - 1];
              final int reference = forwardReferences[i];
              final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset;
              int handle = reference & FORWARD_REFERENCE_HANDLE_MASK;
              if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) {
                  if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) {
                      // Change the opcode of the jump instruction, in order to be able to find it later in
                      // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except
                      // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to
                      // 65535, which is sufficient since the size of a method is limited to 65535 bytes).
                      int opcode = code[sourceInsnBytecodeOffset] & 0xFF;
                      if (opcode < Opcodes.IFNULL) {
                          // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR.
                          code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA);
                      } else {
                          // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL.
                          code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA);
                      }
                      hasAsmInstructions = true;
                  }
              } else {
                  code[handle++] = (byte) (relativeOffset >>> 24);
                  code[handle++] = (byte) (relativeOffset >>> 16);
              }
              code[handle++] = (byte) (relativeOffset >>> 8);
              code[handle] = (byte) relativeOffset;
          }
          return hasAsmInstructions;
      }
  }
  