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 */
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 }
|
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 */
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 }
|