1 /*
   2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.vm.ci.code;
  24 
  25 import java.util.*;
  26 
  27 import jdk.vm.ci.meta.*;
  28 
  29 /**
  30  * Represents the Java bytecode frame state(s) at a given position including {@link Value locations}
  31  * where to find the local variables, operand stack values and locked objects of the bytecode
  32  * frame(s).
  33  */
  34 public class BytecodeFrame extends BytecodePosition {
  35 
  36     /**
  37      * An array of values representing how to reconstruct the state of the Java frame. This is array
  38      * is partitioned as follows:
  39      * <p>
  40      * <table summary="" border="1" cellpadding="5" frame="void" rules="all">
  41      * <tr>
  42      * <th>Start index (inclusive)</th>
  43      * <th>End index (exclusive)</th>
  44      * <th>Description</th>
  45      * </tr>
  46      * <tr>
  47      * <td>0</td>
  48      * <td>numLocals</td>
  49      * <td>Local variables</td>
  50      * </tr>
  51      * <tr>
  52      * <td>numLocals</td>
  53      * <td>numLocals + numStack</td>
  54      * <td>Operand stack</td>
  55      * </tr>
  56      * <tr>
  57      * <td>numLocals + numStack</td>
  58      * <td>values.length</td>
  59      * <td>Locked objects</td>
  60      * </tr>
  61      * </table>
  62      * <p>
  63      * Note that the number of locals and the number of stack slots may be smaller than the maximum
  64      * number of locals and stack slots as specified in the compiled method.
  65      */
  66     public final JavaValue[] values;
  67 
  68     /**
  69      * An array describing the Java kind of the {@link #values}. It records a kind for the locals
  70      * and the operand stack.
  71      */
  72     public final JavaKind[] slotKinds;
  73 
  74     /**
  75      * The number of locals in the values array.
  76      */
  77     public final int numLocals;
  78 
  79     /**
  80      * The number of stack slots in the values array.
  81      */
  82     public final int numStack;
  83 
  84     /**
  85      * The number of locks in the values array.
  86      */
  87     public final int numLocks;
  88 
  89     /**
  90      * True if this is a position inside an exception handler before the exception object has been
  91      * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int)
  92      * getStackValue(0)} is the location of the exception object. If deoptimization happens at this
  93      * position, the interpreter will rethrow the exception instead of executing the bytecode
  94      * instruction at this position.
  95      */
  96     public final boolean rethrowException;
  97 
  98     public final boolean duringCall;
  99 
 100     /**
 101      * This BCI should be used for frame states that are built for code with no meaningful BCI.
 102      */
 103     public static final int UNKNOWN_BCI = -5;
 104 
 105     /**
 106      * The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
 107      * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized,
 108      * the monitor is still held.
 109      */
 110     public static final int UNWIND_BCI = -1;
 111 
 112     /**
 113      * The BCI for the state before starting to execute a method. Note that if the method is
 114      * synchronized, the monitor is not yet held.
 115      */
 116     public static final int BEFORE_BCI = -2;
 117 
 118     /**
 119      * The BCI for the state after finishing the execution of a method and returning normally. Note
 120      * that if the method was synchronized the monitor is already released.
 121      */
 122     public static final int AFTER_BCI = -3;
 123 
 124     /**
 125      * The BCI for exception unwind. This is synthetic code and has no representation in bytecode.
 126      * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the
 127      * monitor is already released.
 128      */
 129     public static final int AFTER_EXCEPTION_BCI = -4;
 130 
 131     /**
 132      * This BCI should be used for states that cannot be the target of a deoptimization, like
 133      * snippet frame states.
 134      */
 135     public static final int INVALID_FRAMESTATE_BCI = -6;
 136 
 137     /**
 138      * Determines if a given BCI matches one of the placeholder BCI constants defined in this class.
 139      */
 140     public static boolean isPlaceholderBci(int bci) {
 141         return bci < 0;
 142     }
 143 
 144     /**
 145      * Gets the name of a given placeholder BCI.
 146      */
 147     public static String getPlaceholderBciName(int bci) {
 148         assert isPlaceholderBci(bci);
 149         if (bci == BytecodeFrame.AFTER_BCI) {
 150             return "AFTER_BCI";
 151         } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
 152             return "AFTER_EXCEPTION_BCI";
 153         } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
 154             return "INVALID_FRAMESTATE_BCI";
 155         } else if (bci == BytecodeFrame.BEFORE_BCI) {
 156             return "BEFORE_BCI";
 157         } else if (bci == BytecodeFrame.UNKNOWN_BCI) {
 158             return "UNKNOWN_BCI";
 159         } else {
 160             assert bci == BytecodeFrame.UNWIND_BCI;
 161             return "UNWIND_BCI";
 162         }
 163     }
 164 
 165     /**
 166      * Creates a new frame object.
 167      *
 168      * @param caller the caller frame (which may be {@code null})
 169      * @param method the method
 170      * @param bci a BCI within the method
 171      * @param rethrowException specifies if the VM should re-throw the pending exception when
 172      *            deopt'ing using this frame
 173      * @param values the frame state {@link #values}
 174      * @param numLocals the number of local variables
 175      * @param numStack the depth of the stack
 176      * @param numLocks the number of locked objects
 177      */
 178     public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack,
 179                     int numLocks) {
 180         super(caller, method, bci);
 181         assert values != null;
 182         this.rethrowException = rethrowException;
 183         this.duringCall = duringCall;
 184         this.values = values;
 185         this.slotKinds = slotKinds;
 186         this.numLocals = numLocals;
 187         this.numStack = numStack;
 188         this.numLocks = numLocks;
 189         assert !rethrowException || numStack == 1 : "must have exception on top of the stack";
 190     }
 191 
 192     /**
 193      * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the
 194      * slot following a double word item. This should really be checked in FrameState itself but
 195      * because of Word type rewriting and alternative backends that can't be done.
 196      */
 197     public boolean validateFormat() {
 198         if (caller() != null) {
 199             caller().validateFormat();
 200         }
 201         for (int i = 0; i < numLocals + numStack; i++) {
 202             if (values[i] != null) {
 203                 JavaKind kind = slotKinds[i];
 204                 if (kind.needsTwoSlots()) {
 205                     assert slotKinds.length > i + 1 : String.format("missing second word %s", this);
 206                     assert slotKinds[i + 1] == JavaKind.Illegal : this;
 207                 }
 208             }
 209         }
 210         return true;
 211     }
 212 
 213     /**
 214      * Gets the value representing the specified local variable.
 215      *
 216      * @param i the local variable index
 217      * @return the value that can be used to reconstruct the local's current value
 218      */
 219     public JavaValue getLocalValue(int i) {
 220         return values[i];
 221     }
 222 
 223     /**
 224      * Gets the value representing the specified stack slot.
 225      *
 226      * @param i the stack index
 227      * @return the value that can be used to reconstruct the stack slot's current value
 228      */
 229     public JavaValue getStackValue(int i) {
 230         return values[i + numLocals];
 231     }
 232 
 233     /**
 234      * Gets the value representing the specified lock.
 235      *
 236      * @param i the lock index
 237      * @return the value that can be used to reconstruct the lock's current value
 238      */
 239     public JavaValue getLockValue(int i) {
 240         return values[i + numLocals + numStack];
 241     }
 242 
 243     /**
 244      * Gets the caller of this frame.
 245      *
 246      * @return {@code null} if this frame has no caller
 247      */
 248     public BytecodeFrame caller() {
 249         return (BytecodeFrame) getCaller();
 250     }
 251 
 252     @Override
 253     public boolean equals(Object obj) {
 254         if (this == obj) {
 255             return true;
 256         }
 257         if (obj instanceof BytecodeFrame && super.equals(obj)) {
 258             BytecodeFrame that = (BytecodeFrame) obj;
 259             // @formatter:off
 260             if (this.duringCall == that.duringCall &&
 261                 this.rethrowException == that.rethrowException &&
 262                 this.numLocals == that.numLocals &&
 263                 this.numLocks == that.numLocks &&
 264                 this.numStack == that.numStack &&
 265                 Arrays.equals(this.values, that.values)) {
 266                 return true;
 267             }
 268             // @formatter:off
 269             return true;
 270         }
 271         return false;
 272     }
 273 
 274     @Override
 275     public String toString() {
 276         return CodeUtil.append(new StringBuilder(100), this).toString();
 277     }
 278 }