All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shade.com.alibaba.fastjson2.internal.asm.Label Maven / Gradle / Ivy

There is a newer version: 1.3.7
Show newest version
// 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 instruction 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':
     *
     * 
    *
  • 'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the * forward reference, *
  • '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}. *
* *

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; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy