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 final 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 * This field is intentionally exposed as a mutable array that a compiler may modify (e.g. 70 * during register allocation). 71 */ 72 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "field is intentionally mutable")// 73 public final JavaValue[] values; 74 75 /** 76 * An array describing the Java kinds in {@link #values}. It records a kind for the locals and 77 * the operand stack. 78 */ 79 private final JavaKind[] slotKinds; 80 81 /** 82 * The number of locals in the values array. 83 */ 84 public final int numLocals; 85 86 /** 87 * The number of stack slots in the values array. 88 */ 89 public final int numStack; 90 91 /** 92 * The number of locks in the values array. 93 */ 94 public final int numLocks; 95 96 /** 97 * True if this is a position inside an exception handler before the exception object has been 98 * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int) 99 * getStackValue(0)} is the location of the exception object. If deoptimization happens at this 100 * position, the interpreter will rethrow the exception instead of executing the bytecode 101 * instruction at this position. 102 */ 103 public final boolean rethrowException; 104 105 /** 106 * Specifies if this object represents a frame state in the middle of executing a call. If true, 107 * the arguments to the call have been popped from the stack and the return value (for a 108 * non-void call) has not yet been pushed. 109 */ 110 public final boolean duringCall; 111 112 /** 113 * This BCI should be used for frame states that are built for code with no meaningful BCI. 114 */ 115 public static final int UNKNOWN_BCI = -5; 116 117 /** 118 * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. 119 * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized, 120 * the monitor is still held. 121 */ 122 public static final int UNWIND_BCI = -1; 123 124 /** 125 * The BCI for the state before starting to execute a method. Note that if the method is 126 * synchronized, the monitor is not yet held. 127 */ 128 public static final int BEFORE_BCI = -2; 129 130 /** 131 * The BCI for the state after finishing the execution of a method and returning normally. Note 132 * that if the method was synchronized the monitor is already released. 133 */ 134 public static final int AFTER_BCI = -3; 135 136 /** 137 * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. 138 * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the 139 * monitor is already released. 140 */ 141 public static final int AFTER_EXCEPTION_BCI = -4; 142 143 /** 144 * This BCI should be used for states that cannot be the target of a deoptimization, like 145 * snippet frame states. 146 */ 147 public static final int INVALID_FRAMESTATE_BCI = -6; 148 149 /** 150 * Determines if a given BCI matches one of the placeholder BCI constants defined in this class. 151 */ 152 public static boolean isPlaceholderBci(int bci) { 153 return bci < 0; 154 } 155 156 /** 157 * Gets the name of a given placeholder BCI. 158 */ 159 public static String getPlaceholderBciName(int bci) { 160 assert isPlaceholderBci(bci); 161 if (bci == BytecodeFrame.AFTER_BCI) { 162 return "AFTER_BCI"; 163 } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { 164 return "AFTER_EXCEPTION_BCI"; 165 } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { 166 return "INVALID_FRAMESTATE_BCI"; 167 } else if (bci == BytecodeFrame.BEFORE_BCI) { 168 return "BEFORE_BCI"; 169 } else if (bci == BytecodeFrame.UNKNOWN_BCI) { 170 return "UNKNOWN_BCI"; 171 } else { 172 assert bci == BytecodeFrame.UNWIND_BCI; 173 return "UNWIND_BCI"; 174 } 175 } 176 177 /** 178 * Creates a new frame object. 179 * 180 * @param caller the caller frame (which may be {@code null}) 181 * @param method the method 182 * @param bci a BCI within the method 183 * @param rethrowException specifies if the VM should re-throw the pending exception when 184 * deopt'ing using this frame 185 * @param values the frame state {@link #values}. 186 * @param slotKinds the kinds in {@code values}. This array is now owned by this object and must 187 * not be mutated by the caller. 188 * @param numLocals the number of local variables 189 * @param numStack the depth of the stack 190 * @param numLocks the number of locked objects 191 */ 192 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "caller transfers ownership of `slotKinds`") 193 public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack, 194 int numLocks) { 195 super(caller, method, bci); 196 assert values != null; 197 this.rethrowException = rethrowException; 198 this.duringCall = duringCall; 199 this.values = values; 200 this.slotKinds = slotKinds; 201 this.numLocals = numLocals; 202 this.numStack = numStack; 203 this.numLocks = numLocks; 204 assert !rethrowException || numStack == 1 : "must have exception on top of the stack"; 205 } 206 207 /** 208 * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the 209 * slot following a double word item. This should really be checked in FrameState itself but 210 * because of Word type rewriting and alternative backends that can't be done. 211 */ 212 public boolean validateFormat() { 213 if (caller() != null) { 214 caller().validateFormat(); 215 } 216 for (int i = 0; i < numLocals + numStack; i++) { 217 if (values[i] != null) { 218 JavaKind kind = slotKinds[i]; 219 if (kind.needsTwoSlots()) { 220 assert slotKinds.length > i + 1 : String.format("missing second word %s", this); 221 assert slotKinds[i + 1] == JavaKind.Illegal : this; 222 } 223 } 224 } 225 return true; 226 } 227 228 /** 229 * Gets the kind of a local variable. 230 * 231 * @param i the local variable to query 232 * @return the kind of local variable {@code i} 233 * @throw {@link IndexOutOfBoundsException} if {@code i < 0 || i >= this.numLocals} 234 */ 235 public JavaKind getLocalValueKind(int i) { 236 if (i < 0 || i >= numLocals) { 237 throw new IndexOutOfBoundsException(); 238 } 239 return slotKinds[i]; 240 } 241 242 /** 243 * Gets the kind of a stack slot. 244 * 245 * @param i the local variable to query 246 * @return the kind of stack slot {@code i} 247 * @throw {@link IndexOutOfBoundsException} if {@code i < 0 || i >= this.numStack} 248 */ 249 public JavaKind getStackValueKind(int i) { 250 if (i < 0 || i >= numStack) { 251 throw new IndexOutOfBoundsException(); 252 } 253 return slotKinds[i + numLocals]; 254 } 255 256 /** 257 * Gets the value representing the specified local variable. 258 * 259 * @param i the local variable index 260 * @return the value that can be used to reconstruct the local's current value 261 * @throw {@link IndexOutOfBoundsException} if {@code i < 0 || i >= this.numLocals} 262 */ 263 public JavaValue getLocalValue(int i) { 264 if (i < 0 || i >= numLocals) { 265 throw new IndexOutOfBoundsException(); 266 } 267 return values[i]; 268 } 269 270 /** 271 * Gets the value representing the specified stack slot. 272 * 273 * @param i the stack index 274 * @return the value that can be used to reconstruct the stack slot's current value 275 * @throw {@link IndexOutOfBoundsException} if {@code i < 0 || i >= this.numStack} 276 */ 277 public JavaValue getStackValue(int i) { 278 if (i < 0 || i >= numStack) { 279 throw new IndexOutOfBoundsException(); 280 } 281 return values[i + numLocals]; 282 } 283 284 /** 285 * Gets the value representing the specified lock. 286 * 287 * @param i the lock index 288 * @return the value that can be used to reconstruct the lock's current value 289 * @throw {@link IndexOutOfBoundsException} if {@code i < 0 || i >= this.numLocks} 290 */ 291 public JavaValue getLockValue(int i) { 292 if (i < 0 || i >= numLocks) { 293 throw new IndexOutOfBoundsException(); 294 } 295 return values[i + numLocals + numStack]; 296 } 297 298 /** 299 * Gets the caller of this frame. 300 * 301 * @return {@code null} if this frame has no caller 302 */ 303 public BytecodeFrame caller() { 304 return (BytecodeFrame) getCaller(); 305 } 306 307 @Override 308 public int hashCode() { 309 return (numLocals + 1) ^ (numStack + 11) ^ (numLocks + 7); 310 } 311 312 @Override 313 public boolean equals(Object obj) { 314 if (this == obj) { 315 return true; 316 } 317 if (obj instanceof BytecodeFrame && super.equals(obj)) { 318 BytecodeFrame that = (BytecodeFrame) obj; 319 // @formatter:off 320 if (this.duringCall == that.duringCall && 321 this.rethrowException == that.rethrowException && 322 this.numLocals == that.numLocals && 323 this.numLocks == that.numLocks && 324 this.numStack == that.numStack && 325 Arrays.equals(this.values, that.values)) { 326 return true; 327 } 328 // @formatter:off 329 return true; 330 } 331 return false; 332 } 333 334 @Override 335 public String toString() { 336 return CodeUtil.append(new StringBuilder(100), this).toString(); 337 } 338 }