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