325N/A/*
325N/A * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/A/*
325N/A * This file is available under and governed by the GNU General Public
325N/A * License version 2 only, as published by the Free Software Foundation.
325N/A * However, the following notice accompanied the original version of this
325N/A * file:
325N/A *
325N/A * ASM: a very small and fast Java bytecode manipulation framework
325N/A * Copyright (c) 2000-2007 INRIA, France Telecom
325N/A * All rights reserved.
325N/A *
325N/A * Redistribution and use in source and binary forms, with or without
325N/A * modification, are permitted provided that the following conditions
325N/A * are met:
325N/A * 1. Redistributions of source code must retain the above copyright
325N/A * notice, this list of conditions and the following disclaimer.
325N/A * 2. Redistributions in binary form must reproduce the above copyright
325N/A * notice, this list of conditions and the following disclaimer in the
325N/A * documentation and/or other materials provided with the distribution.
325N/A * 3. Neither the name of the copyright holders nor the names of its
325N/A * contributors may be used to endorse or promote products derived from
325N/A * this software without specific prior written permission.
325N/A *
325N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
325N/A * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
325N/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
325N/A * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
325N/A * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
325N/A * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
325N/A * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
325N/A * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
325N/A * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
325N/A * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
325N/A * THE POSSIBILITY OF SUCH DAMAGE.
325N/A */
325N/Apackage com.sun.xml.internal.ws.org.objectweb.asm;
325N/A
325N/A/**
325N/A * A label represents a position in the bytecode of a method. Labels are used
325N/A * for jump, goto, and switch instructions, and for try catch blocks.
325N/A *
325N/A * @author Eric Bruneton
325N/A */
325N/Apublic class Label {
325N/A
325N/A /**
325N/A * Indicates if this label is only used for debug attributes. Such a label
325N/A * is not the start of a basic block, the target of a jump instruction, or
325N/A * an exception handler. It can be safely ignored in control flow graph
325N/A * analysis algorithms (for optimization purposes).
325N/A */
325N/A static final int DEBUG = 1;
325N/A
325N/A /**
325N/A * Indicates if the position of this label is known.
325N/A */
325N/A static final int RESOLVED = 2;
325N/A
325N/A /**
325N/A * Indicates if this label has been updated, after instruction resizing.
325N/A */
325N/A static final int RESIZED = 4;
325N/A
325N/A /**
325N/A * Indicates if this basic block has been pushed in the basic block stack.
325N/A * See {@link MethodWriter#visitMaxs visitMaxs}.
325N/A */
325N/A static final int PUSHED = 8;
325N/A
325N/A /**
325N/A * Indicates if this label is the target of a jump instruction, or the start
325N/A * of an exception handler.
325N/A */
325N/A static final int TARGET = 16;
325N/A
325N/A /**
325N/A * Indicates if a stack map frame must be stored for this label.
325N/A */
325N/A static final int STORE = 32;
325N/A
325N/A /**
325N/A * Indicates if this label corresponds to a reachable basic block.
325N/A */
325N/A static final int REACHABLE = 64;
325N/A
325N/A /**
325N/A * Indicates if this basic block ends with a JSR instruction.
325N/A */
325N/A static final int JSR = 128;
325N/A
325N/A /**
325N/A * Indicates if this basic block ends with a RET instruction.
325N/A */
325N/A static final int RET = 256;
325N/A
325N/A /**
325N/A * Indicates if this basic block is the start of a subroutine.
325N/A */
325N/A static final int SUBROUTINE = 512;
325N/A
325N/A /**
325N/A * Indicates if this subroutine basic block has been visited.
325N/A */
325N/A static final int VISITED = 1024;
325N/A
325N/A /**
325N/A * Field used to associate user information to a label. Warning: this field
325N/A * is used by the ASM tree package. In order to use it with the ASM tree
325N/A * package you must override the {@link
325N/A * com.sun.xml.internal.ws.org.objectweb.asm.tree.MethodNode#getLabelNode} method.
325N/A */
325N/A public Object info;
325N/A
325N/A /**
325N/A * Flags that indicate the status of this label.
325N/A *
325N/A * @see #DEBUG
325N/A * @see #RESOLVED
325N/A * @see #RESIZED
325N/A * @see #PUSHED
325N/A * @see #TARGET
325N/A * @see #STORE
325N/A * @see #REACHABLE
325N/A * @see #JSR
325N/A * @see #RET
325N/A */
325N/A int status;
325N/A
325N/A /**
325N/A * The line number corresponding to this label, if known.
325N/A */
325N/A int line;
325N/A
325N/A /**
325N/A * The position of this label in the code, if known.
325N/A */
325N/A int position;
325N/A
325N/A /**
325N/A * Number of forward references to this label, times two.
325N/A */
325N/A private int referenceCount;
325N/A
325N/A /**
325N/A * Informations about forward references. Each forward reference is
325N/A * described by two consecutive integers in this array: the first one is the
325N/A * position of the first byte of the bytecode instruction that contains the
325N/A * forward reference, while the second is the position of the first byte of
325N/A * the forward reference itself. In fact the sign of the first integer
325N/A * indicates if this reference uses 2 or 4 bytes, and its absolute value
325N/A * gives the position of the bytecode instruction. This array is also used
325N/A * as a bitset to store the subroutines to which a basic block belongs. This
325N/A * information is needed in {@linked MethodWriter#visitMaxs}, after all
325N/A * forward references have been resolved. Hence the same array can be used
325N/A * for both purposes without problems.
325N/A */
325N/A private int[] srcAndRefPositions;
325N/A
325N/A // ------------------------------------------------------------------------
325N/A
325N/A /*
325N/A * Fields for the control flow and data flow graph analysis algorithms (used
325N/A * to compute the maximum stack size or the stack map frames). A control
325N/A * flow graph contains one node per "basic block", and one edge per "jump"
325N/A * from one basic block to another. Each node (i.e., each basic block) is
325N/A * represented by the Label object that corresponds to the first instruction
325N/A * of this basic block. Each node also stores the list of its successors in
325N/A * the graph, as a linked list of Edge objects.
325N/A *
325N/A * The control flow analysis algorithms used to compute the maximum stack
325N/A * size or the stack map frames are similar and use two steps. The first
325N/A * step, during the visit of each instruction, builds information about the
325N/A * state of the local variables and the operand stack at the end of each
325N/A * basic block, called the "output frame", <i>relatively</i> to the frame
325N/A * state at the beginning of the basic block, which is called the "input
325N/A * frame", and which is <i>unknown</i> during this step. The second step,
325N/A * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that
325N/A * computes information about the input frame of each basic block, from the
325N/A * input state of the first basic block (known from the method signature),
325N/A * and by the using the previously computed relative output frames.
325N/A *
325N/A * The algorithm used to compute the maximum stack size only computes the
325N/A * relative output and absolute input stack heights, while the algorithm
325N/A * used to compute stack map frames computes relative output frames and
325N/A * absolute input frames.
325N/A */
325N/A
325N/A /**
325N/A * Start of the output stack relatively to the input stack. The exact
325N/A * semantics of this field depends on the algorithm that is used.
325N/A *
325N/A * When only the maximum stack size is computed, this field is the number of
325N/A * elements in the input stack.
325N/A *
325N/A * When the stack map frames are completely computed, this field is the
325N/A * offset of the first output stack element relatively to the top of the
325N/A * input stack. This offset is always negative or null. A null offset means
325N/A * that the output stack must be appended to the input stack. A -n offset
325N/A * means that the first n output stack elements must replace the top n input
325N/A * stack elements, and that the other elements must be appended to the input
325N/A * stack.
325N/A */
325N/A int inputStackTop;
325N/A
325N/A /**
325N/A * Maximum height reached by the output stack, relatively to the top of the
325N/A * input stack. This maximum is always positive or null.
325N/A */
325N/A int outputStackMax;
325N/A
325N/A /**
325N/A * Information about the input and output stack map frames of this basic
325N/A * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
325N/A * option is used.
325N/A */
325N/A Frame frame;
325N/A
325N/A /**
325N/A * The successor of this label, in the order they are visited. This linked
325N/A * list does not include labels used for debug info only. If
325N/A * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
325N/A * does not contain successive labels that denote the same bytecode position
325N/A * (in this case only the first label appears in this list).
325N/A */
325N/A Label successor;
325N/A
325N/A /**
325N/A * The successors of this node in the control flow graph. These successors
325N/A * are stored in a linked list of {@link Edge Edge} objects, linked to each
325N/A * other by their {@link Edge#next} field.
325N/A */
325N/A Edge successors;
325N/A
325N/A /**
325N/A * The next basic block in the basic block stack. This stack is used in the
325N/A * main loop of the fix point algorithm used in the second step of the
325N/A * control flow analysis algorithms.
325N/A *
325N/A * @see MethodWriter#visitMaxs
325N/A */
325N/A Label next;
325N/A
325N/A // ------------------------------------------------------------------------
325N/A // Constructor
325N/A // ------------------------------------------------------------------------
325N/A
325N/A /**
325N/A * Constructs a new label.
325N/A */
325N/A public Label() {
325N/A }
325N/A
325N/A // ------------------------------------------------------------------------
325N/A // Methods to compute offsets and to manage forward references
325N/A // ------------------------------------------------------------------------
325N/A
325N/A /**
325N/A * Returns the offset corresponding to this label. This offset is computed
325N/A * from the start of the method's bytecode. <i>This method is intended for
325N/A * {@link Attribute} sub classes, and is normally not needed by class
325N/A * generators or adapters.</i>
325N/A *
325N/A * @return the offset corresponding to this label.
325N/A * @throws IllegalStateException if this label is not resolved yet.
325N/A */
325N/A public int getOffset() {
325N/A if ((status & RESOLVED) == 0) {
325N/A throw new IllegalStateException("Label offset position has not been resolved yet");
325N/A }
325N/A return position;
325N/A }
325N/A
325N/A /**
325N/A * Puts a reference to this label in the bytecode of a method. If the
325N/A * position of the label is known, the offset is computed and written
325N/A * directly. Otherwise, a null offset is written and a new forward reference
325N/A * is declared for this label.
325N/A *
325N/A * @param owner the code writer that calls this method.
325N/A * @param out the bytecode of the method.
325N/A * @param source the position of first byte of the bytecode instruction that
325N/A * contains this label.
325N/A * @param wideOffset <tt>true</tt> if the reference must be stored in 4
325N/A * bytes, or <tt>false</tt> if it must be stored with 2 bytes.
325N/A * @throws IllegalArgumentException if this label has not been created by
325N/A * the given code writer.
325N/A */
325N/A void put(
325N/A final MethodWriter owner,
325N/A final ByteVector out,
325N/A final int source,
325N/A final boolean wideOffset)
325N/A {
325N/A if ((status & RESOLVED) == 0) {
325N/A if (wideOffset) {
325N/A addReference(-1 - source, out.length);
325N/A out.putInt(-1);
325N/A } else {
325N/A addReference(source, out.length);
325N/A out.putShort(-1);
325N/A }
325N/A } else {
325N/A if (wideOffset) {
325N/A out.putInt(position - source);
325N/A } else {
325N/A out.putShort(position - source);
325N/A }
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Adds a forward reference to this label. This method must be called only
325N/A * for a true forward reference, i.e. only if this label is not resolved
325N/A * yet. For backward references, the offset of the reference can be, and
325N/A * must be, computed and stored directly.
325N/A *
325N/A * @param sourcePosition the position of the referencing instruction. This
325N/A * position will be used to compute the offset of this forward
325N/A * reference.
325N/A * @param referencePosition the position where the offset for this forward
325N/A * reference must be stored.
325N/A */
325N/A private void addReference(
325N/A final int sourcePosition,
325N/A final int referencePosition)
325N/A {
325N/A if (srcAndRefPositions == null) {
325N/A srcAndRefPositions = new int[6];
325N/A }
325N/A if (referenceCount >= srcAndRefPositions.length) {
325N/A int[] a = new int[srcAndRefPositions.length + 6];
325N/A System.arraycopy(srcAndRefPositions,
325N/A 0,
325N/A a,
325N/A 0,
325N/A srcAndRefPositions.length);
325N/A srcAndRefPositions = a;
325N/A }
325N/A srcAndRefPositions[referenceCount++] = sourcePosition;
325N/A srcAndRefPositions[referenceCount++] = referencePosition;
325N/A }
325N/A
325N/A /**
325N/A * Resolves all forward references to this label. This method must be called
325N/A * when this label is added to the bytecode of the method, i.e. when its
325N/A * position becomes known. This method fills in the blanks that where left
325N/A * in the bytecode by each forward reference previously added to this label.
325N/A *
325N/A * @param owner the code writer that calls this method.
325N/A * @param position the position of this label in the bytecode.
325N/A * @param data the bytecode of the method.
325N/A * @return <tt>true</tt> if a blank that was left for this label was to
325N/A * small to store the offset. In such a case the corresponding jump
325N/A * instruction is replaced with a pseudo instruction (using unused
325N/A * opcodes) using an unsigned two bytes offset. These pseudo
325N/A * instructions will need to be replaced with true instructions with
325N/A * wider offsets (4 bytes instead of 2). This is done in
325N/A * {@link MethodWriter#resizeInstructions}.
325N/A * @throws IllegalArgumentException if this label has already been resolved,
325N/A * or if it has not been created by the given code writer.
325N/A */
325N/A boolean resolve(
325N/A final MethodWriter owner,
325N/A final int position,
325N/A final byte[] data)
325N/A {
325N/A boolean needUpdate = false;
325N/A this.status |= RESOLVED;
325N/A this.position = position;
325N/A int i = 0;
325N/A while (i < referenceCount) {
325N/A int source = srcAndRefPositions[i++];
325N/A int reference = srcAndRefPositions[i++];
325N/A int offset;
325N/A if (source >= 0) {
325N/A offset = position - source;
325N/A if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
325N/A /*
325N/A * changes the opcode of the jump instruction, in order to
325N/A * be able to find it later (see resizeInstructions in
325N/A * MethodWriter). These temporary opcodes are similar to
325N/A * jump instruction opcodes, except that the 2 bytes offset
325N/A * is unsigned (and can therefore represent values from 0 to
325N/A * 65535, which is sufficient since the size of a method is
325N/A * limited to 65535 bytes).
325N/A */
325N/A int opcode = data[reference - 1] & 0xFF;
325N/A if (opcode <= Opcodes.JSR) {
325N/A // changes IFEQ ... JSR to opcodes 202 to 217
325N/A data[reference - 1] = (byte) (opcode + 49);
325N/A } else {
325N/A // changes IFNULL and IFNONNULL to opcodes 218 and 219
325N/A data[reference - 1] = (byte) (opcode + 20);
325N/A }
325N/A needUpdate = true;
325N/A }
325N/A data[reference++] = (byte) (offset >>> 8);
325N/A data[reference] = (byte) offset;
325N/A } else {
325N/A offset = position + source + 1;
325N/A data[reference++] = (byte) (offset >>> 24);
325N/A data[reference++] = (byte) (offset >>> 16);
325N/A data[reference++] = (byte) (offset >>> 8);
325N/A data[reference] = (byte) offset;
325N/A }
325N/A }
325N/A return needUpdate;
325N/A }
325N/A
325N/A /**
325N/A * Returns the first label of the series to which this label belongs. For an
325N/A * isolated label or for the first label in a series of successive labels,
325N/A * this method returns the label itself. For other labels it returns the
325N/A * first label of the series.
325N/A *
325N/A * @return the first label of the series to which this label belongs.
325N/A */
325N/A Label getFirst() {
325N/A return !ClassReader.FRAMES || frame == null ? this : frame.owner;
325N/A }
325N/A
325N/A // ------------------------------------------------------------------------
325N/A // Methods related to subroutines
325N/A // ------------------------------------------------------------------------
325N/A
325N/A /**
325N/A * Returns true is this basic block belongs to the given subroutine.
325N/A *
325N/A * @param id a subroutine id.
325N/A * @return true is this basic block belongs to the given subroutine.
325N/A */
325N/A boolean inSubroutine(final long id) {
325N/A if ((status & Label.VISITED) != 0) {
325N/A return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
325N/A }
325N/A return false;
325N/A }
325N/A
325N/A /**
325N/A * Returns true if this basic block and the given one belong to a common
325N/A * subroutine.
325N/A *
325N/A * @param block another basic block.
325N/A * @return true if this basic block and the given one belong to a common
325N/A * subroutine.
325N/A */
325N/A boolean inSameSubroutine(final Label block) {
325N/A for (int i = 0; i < srcAndRefPositions.length; ++i) {
325N/A if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
325N/A return true;
325N/A }
325N/A }
325N/A return false;
325N/A }
325N/A
325N/A /**
325N/A * Marks this basic block as belonging to the given subroutine.
325N/A *
325N/A * @param id a subroutine id.
325N/A * @param nbSubroutines the total number of subroutines in the method.
325N/A */
325N/A void addToSubroutine(final long id, final int nbSubroutines) {
325N/A if ((status & VISITED) == 0) {
325N/A status |= VISITED;
325N/A srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1];
325N/A }
325N/A srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
325N/A }
325N/A
325N/A /**
325N/A * Finds the basic blocks that belong to a given subroutine, and marks these
325N/A * blocks as belonging to this subroutine. This recursive method follows the
325N/A * control flow graph to find all the blocks that are reachable from the
325N/A * current block WITHOUT following any JSR target.
325N/A *
325N/A * @param JSR a JSR block that jumps to this subroutine. If this JSR is not
325N/A * null it is added to the successor of the RET blocks found in the
325N/A * subroutine.
325N/A * @param id the id of this subroutine.
325N/A * @param nbSubroutines the total number of subroutines in the method.
325N/A */
325N/A void visitSubroutine(final Label JSR, final long id, final int nbSubroutines)
325N/A {
325N/A if (JSR != null) {
325N/A if ((status & VISITED) != 0) {
325N/A return;
325N/A }
325N/A status |= VISITED;
325N/A // adds JSR to the successors of this block, if it is a RET block
325N/A if ((status & RET) != 0) {
325N/A if (!inSameSubroutine(JSR)) {
325N/A Edge e = new Edge();
325N/A e.info = inputStackTop;
325N/A e.successor = JSR.successors.successor;
325N/A e.next = successors;
325N/A successors = e;
325N/A }
325N/A }
325N/A } else {
325N/A // if this block already belongs to subroutine 'id', returns
325N/A if (inSubroutine(id)) {
325N/A return;
325N/A }
325N/A // marks this block as belonging to subroutine 'id'
325N/A addToSubroutine(id, nbSubroutines);
325N/A }
325N/A // calls this method recursively on each successor, except JSR targets
325N/A Edge e = successors;
325N/A while (e != null) {
325N/A // if this block is a JSR block, then 'successors.next' leads
325N/A // to the JSR target (see {@link #visitJumpInsn}) and must therefore
325N/A // not be followed
325N/A if ((status & Label.JSR) == 0 || e != successors.next) {
325N/A e.successor.visitSubroutine(JSR, id, nbSubroutines);
325N/A }
325N/A e = e.next;
325N/A }
325N/A }
325N/A
325N/A // ------------------------------------------------------------------------
325N/A // Overriden Object methods
325N/A // ------------------------------------------------------------------------
325N/A
325N/A /**
325N/A * Returns a string representation of this label.
325N/A *
325N/A * @return a string representation of this label.
325N/A */
325N/A public String toString() {
325N/A return "L" + System.identityHashCode(this);
325N/A }
325N/A}