comparison graal/Compiler/src/com/sun/c1x/value/FrameState.java @ 2507:9ec15d6914ca

Pull over of compiler from maxine repository.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:43:22 +0200
parents
children
comparison
equal deleted inserted replaced
2506:4a3bf8a5bf41 2507:9ec15d6914ca
1 /*
2 * Copyright (c) 2009, 2011, 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 com.sun.c1x.value;
24
25 import java.util.*;
26
27 import com.sun.c1x.*;
28 import com.sun.c1x.graph.*;
29 import com.sun.c1x.ir.*;
30 import com.sun.cri.ci.*;
31 import com.sun.cri.ri.*;
32
33 /**
34 * The {@code FrameState} class encapsulates the frame state (i.e. local variables and
35 * operand stack) at a particular point in the abstract interpretation.
36 *
37 * @author Ben L. Titzer
38 */
39 public abstract class FrameState {
40
41 /**
42 * The operand stack and local variables.
43 * The local variables occupy the index range {@code [0 .. maxLocals)}.
44 * The operand stack occupies the index range {@code [maxLocals .. values.length)}.
45 * The top of the operand stack is at index {@code maxLocals + stackIndex}.
46 * This does not include the operand stack or local variables of parent frames.
47 *
48 * {@linkplain CiKind#isDoubleWord() Double-word} local variables and
49 * operand stack values occupy 2 slots in this array with the second slot
50 * being {@code null}.
51 */
52 protected final Value[] values;
53
54 /**
55 * The depth of the operand stack.
56 * The top of stack value is in {@code values[maxLocals + stackIndex]}.
57 */
58 protected int stackIndex;
59
60 /**
61 * The number of local variables.
62 */
63 protected final int maxLocals;
64
65 protected final IRScope scope;
66
67 /**
68 * The bytecode index to which this frame state applies. This will be {@code -1}
69 * iff this state is mutable.
70 */
71 public final int bci;
72
73 /**
74 * The list of locks held by this frame state.
75 * This does not include locks held by parent frames.
76 */
77 protected ArrayList<Value> locks;
78
79 /**
80 * The number of minimum stack slots required for doing IR wrangling during
81 * {@linkplain GraphBuilder bytecode parsing}. While this may hide stack
82 * overflow issues in the original bytecode, the assumption is that such
83 * issues must be caught by the verifier.
84 */
85 private static final int MINIMUM_STACK_SLOTS = 1;
86
87 /**
88 * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables.
89 *
90 * @param irScope the inlining context of the method
91 * @param bci the bytecode index of the frame state
92 * @param maxLocals maximum number of locals
93 * @param maxStack maximum size of the stack
94 */
95 public FrameState(IRScope irScope, int bci, int maxLocals, int maxStack) {
96 this.scope = irScope;
97 this.bci = bci;
98 this.values = new Value[maxLocals + Math.max(maxStack, MINIMUM_STACK_SLOTS)];
99 this.maxLocals = maxLocals;
100 C1XMetrics.FrameStatesCreated++;
101 C1XMetrics.FrameStateValuesCreated += this.values.length;
102 }
103
104 /**
105 * Copies the contents of this frame state so that further updates to either stack aren't reflected in the other.
106 * @param bci the bytecode index of the copy
107 * @param withLocals indicates whether to copy the local state
108 * @param withStack indicates whether to copy the stack state
109 * @param withLocks indicates whether to copy the lock state
110 *
111 * @return a new frame state with the specified components
112 */
113 public MutableFrameState copy(int bci, boolean withLocals, boolean withStack, boolean withLocks) {
114 final MutableFrameState other = new MutableFrameState(scope, bci, localsSize(), maxStackSize());
115 if (withLocals && withStack) {
116 // fast path: use array copy
117 int valuesSize = valuesSize();
118 assert other.values.length >= valuesSize : "array size: " + other.values.length + ", valuesSize: " + valuesSize + ", maxStackSize: " + maxStackSize() + ", localsSize: " + localsSize();
119 assert values.length >= valuesSize : "array size: " + values.length + ", valuesSize: " + valuesSize + ", maxStackSize: " + maxStackSize() + ", localsSize: " + localsSize();
120 System.arraycopy(values, 0, other.values, 0, valuesSize);
121 other.stackIndex = stackIndex;
122 } else {
123 if (withLocals) {
124 other.replaceLocals(this);
125 }
126 if (withStack) {
127 other.replaceStack(this);
128 }
129 }
130 if (withLocks) {
131 other.replaceLocks(this);
132 }
133 return other;
134 }
135
136 /**
137 * Gets a mutable copy ({@link MutableFrameState}) of this frame state.
138 */
139 public MutableFrameState copy() {
140 return copy(bci, true, true, true);
141 }
142
143 /**
144 * Gets an immutable copy of this frame state but without the stack.
145 */
146 public FrameState immutableCopyWithEmptyStack() {
147 return copy(bci, true, false, true);
148 }
149
150 /**
151 * Gets an immutable copy of this frame state but without the frame info.
152 */
153 public FrameState immutableCopyCodePosOnly() {
154 return copy(bci, false, false, false);
155 }
156
157 public boolean isSameAcrossScopes(FrameState other) {
158 assert stackSize() == other.stackSize();
159 assert localsSize() == other.localsSize();
160 assert locksSize() == other.locksSize();
161 for (int i = 0; i < stackIndex; i++) {
162 Value x = stackAt(i);
163 Value y = other.stackAt(i);
164 if (x != y && typeMismatch(x, y)) {
165 return false;
166 }
167 }
168 if (locks != null) {
169 for (int i = 0; i < locks.size(); i++) {
170 if (lockAt(i) != other.lockAt(i)) {
171 return false;
172 }
173 }
174 }
175 return true;
176 }
177
178 /**
179 * Returns the inlining context associated with this frame state.
180 *
181 * @return the inlining context
182 */
183 public IRScope scope() {
184 return scope;
185 }
186
187 /**
188 * Returns the size of the local variables.
189 *
190 * @return the size of the local variables
191 */
192 public int localsSize() {
193 return maxLocals;
194 }
195
196 /**
197 * Gets number of locks held by this frame state.
198 */
199 public int locksSize() {
200 return locks == null ? 0 : locks.size();
201 }
202
203 public int totalLocksSize() {
204 return locksSize() + ((callerState() == null) ? 0 : callerState().totalLocksSize());
205 }
206
207 /**
208 * Gets the current size (height) of the stack.
209 */
210 public int stackSize() {
211 return stackIndex;
212 }
213
214 /**
215 * Gets the maximum size (height) of the stack.
216 ] */
217 public int maxStackSize() {
218 return values.length - maxLocals;
219 }
220
221 /**
222 * Checks whether the stack is empty.
223 *
224 * @return {@code true} the stack is currently empty
225 */
226 public boolean stackEmpty() {
227 return stackIndex == 0;
228 }
229
230 /**
231 * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then
232 * invalidates the high word as well.
233 *
234 * @param i the index of the local to invalidate
235 */
236 public void invalidateLocal(int i) {
237 // note that for double word locals, the high slot should already be null
238 // unless the local is actually dead and the high slot is being reused;
239 // in either case, it is not necessary to null the high slot
240 values[i] = null;
241 }
242
243 /**
244 * Loads the local variable at the specified index.
245 *
246 * @param i the index of the local variable to load
247 * @return the instruction that produced the specified local
248 */
249 public Value loadLocal(int i) {
250 assert i < maxLocals : "local variable index out of range: " + i;
251 Value x = values[i];
252 if (x != null) {
253 if (x.isIllegal()) {
254 return null;
255 }
256 assert x.kind.isSingleWord() || values[i + 1] == null || values[i + 1] instanceof Phi;
257 }
258 return x;
259 }
260
261 /**
262 * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word},
263 * then the next local variable index is also overwritten.
264 *
265 * @param i the index at which to store
266 * @param x the instruction which produces the value for the local
267 */
268 public void storeLocal(int i, Value x) {
269 assert i < maxLocals : "local variable index out of range: " + i;
270 invalidateLocal(i);
271 values[i] = x;
272 if (isDoubleWord(x)) {
273 // (tw) if this was a double word then kill i+1
274 values[i + 1] = null;
275 }
276 if (i > 0) {
277 // if there was a double word at i - 1, then kill it
278 Value p = values[i - 1];
279 if (isDoubleWord(p)) {
280 values[i - 1] = null;
281 }
282 }
283 }
284
285 /**
286 * Get the value on the stack at the specified stack index.
287 *
288 * @param i the index into the stack, with {@code 0} being the bottom of the stack
289 * @return the instruction at the specified position in the stack
290 */
291 public final Value stackAt(int i) {
292 assert i < stackIndex;
293 return values[i + maxLocals];
294 }
295
296 /**
297 * Gets the value in the local variables at the specified index.
298 *
299 * @param i the index into the locals
300 * @return the instruction that produced the value for the specified local
301 */
302 public final Value localAt(int i) {
303 assert i < maxLocals : "local variable index out of range: " + i;
304 return values[i];
305 }
306
307 /**
308 * Retrieves the lock at the specified index in the lock stack.
309 * @param i the index into the lock stack
310 * @return the instruction which produced the object at the specified location in the lock stack
311 */
312 public final Value lockAt(int i) {
313 return locks.get(i);
314 }
315
316 /**
317 * Inserts a phi statement into the stack at the specified stack index.
318 * @param block the block begin for which we are creating the phi
319 * @param i the index into the stack for which to create a phi
320 */
321 public void setupPhiForStack(BlockBegin block, int i) {
322 Value p = stackAt(i);
323 if (p != null) {
324 if (p instanceof Phi) {
325 Phi phi = (Phi) p;
326 if (phi.block() == block && phi.isOnStack() && phi.stackIndex() == i) {
327 return;
328 }
329 }
330 values[maxLocals + i] = new Phi(p.kind, block, -i - 1);
331 }
332 }
333
334 /**
335 * Inserts a phi statement for the local at the specified index.
336 * @param block the block begin for which we are creating the phi
337 * @param i the index of the local variable for which to create the phi
338 */
339 public void setupPhiForLocal(BlockBegin block, int i) {
340 Value p = values[i];
341 if (p instanceof Phi) {
342 Phi phi = (Phi) p;
343 if (phi.block() == block && phi.isLocal() && phi.localIndex() == i) {
344 return;
345 }
346 }
347 storeLocal(i, new Phi(p.kind, block, i));
348 }
349
350 /**
351 * Gets the value at a specified index in the set of operand stack and local values represented by this frame.
352 * This method should only be used to iterate over all the values in this frame, irrespective of whether
353 * they are on the stack or in local variables.
354 * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used.
355 * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used.
356 *
357 * @param i a value in the range {@code [0 .. valuesSize()]}
358 * @return the value at index {@code i} which may be {@code null}
359 */
360 public final Value valueAt(int i) {
361 return values[i];
362 }
363
364 /**
365 * The number of operand stack slots and local variables in this frame.
366 * This method should typically only be used in conjunction with {@link #valueAt(int)}.
367 * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used.
368 * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used.
369 *
370 * @return the number of local variables in this frame
371 */
372 public final int valuesSize() {
373 return maxLocals + stackIndex;
374 }
375
376 public final int callerStackSize() {
377 FrameState callerState = scope().callerState;
378 return callerState == null ? 0 : callerState.stackSize();
379 }
380
381 public void checkPhis(BlockBegin block, FrameState other) {
382 checkSize(other);
383 final int max = valuesSize();
384 for (int i = 0; i < max; i++) {
385 Value x = values[i];
386 Value y = other.values[i];
387 if (x != null && x != y) {
388 if (x instanceof Phi) {
389 Phi phi = (Phi) x;
390 if (phi.block() == block) {
391 for (int j = 0; j < phi.inputCount(); j++) {
392 if (phi.inputIn(other) == null) {
393 throw new CiBailout("phi " + phi + " has null operand at new predecessor");
394 }
395 }
396 continue;
397 }
398 }
399 throw new CiBailout("instruction is not a phi or null at " + i);
400 }
401 }
402 }
403
404 private void checkSize(FrameState other) {
405 if (other.stackIndex != stackIndex) {
406 throw new CiBailout("stack sizes do not match");
407 } else if (other.maxLocals != maxLocals) {
408 throw new CiBailout("local sizes do not match");
409 }
410 }
411
412 public void merge(BlockBegin block, FrameState other) {
413 checkSize(other);
414 for (int i = 0; i < valuesSize(); i++) {
415 Value x = values[i];
416 if (x != null) {
417 Value y = other.values[i];
418 if (x != y) {
419 if (typeMismatch(x, y)) {
420 if (x instanceof Phi) {
421 Phi phi = (Phi) x;
422 if (phi.block() == block) {
423 phi.makeDead();
424 }
425 }
426 values[i] = null;
427 continue;
428 }
429 if (i < maxLocals) {
430 // this a local
431 setupPhiForLocal(block, i);
432 } else {
433 // this is a stack slot
434 setupPhiForStack(block, i - maxLocals);
435 }
436 }
437 }
438 }
439 }
440
441 private static boolean typeMismatch(Value x, Value y) {
442 return y == null || x.kind != y.kind;
443 }
444
445 private static boolean isDoubleWord(Value x) {
446 return x != null && x.kind.isDoubleWord();
447 }
448
449 /**
450 * The interface implemented by a client of {@link FrameState#forEachPhi(BlockBegin, PhiProcedure)} and
451 * {@link FrameState#forEachLivePhi(BlockBegin, PhiProcedure)}.
452 */
453 public static interface PhiProcedure {
454 boolean doPhi(Phi phi);
455 }
456
457 /**
458 * Traverses all {@linkplain Phi phis} of a given block in this frame state.
459 *
460 * @param block only phis {@linkplain Phi#block() associated} with this block are traversed
461 * @param proc the call back invoked for each live phi traversed
462 */
463 public boolean forEachPhi(BlockBegin block, PhiProcedure proc) {
464 int max = this.valuesSize();
465 for (int i = 0; i < max; i++) {
466 Value instr = values[i];
467 if (instr instanceof Phi && !instr.isDeadPhi()) {
468 Phi phi = (Phi) instr;
469 if (block == null || phi.block() == block) {
470 if (!proc.doPhi(phi)) {
471 return false;
472 }
473 }
474 }
475 }
476 return true;
477 }
478
479 /**
480 * Traverses all live {@linkplain Phi phis} of a given block in this frame state.
481 *
482 * @param block only phis {@linkplain Phi#block() associated} with this block are traversed
483 * @param proc the call back invoked for each live phi traversed
484 */
485 public final boolean forEachLivePhi(BlockBegin block, PhiProcedure proc) {
486 int max = this.valuesSize();
487 for (int i = 0; i < max; i++) {
488 Value instr = values[i];
489 if (instr instanceof Phi && instr.isLive() && !instr.isDeadPhi()) {
490 Phi phi = (Phi) instr;
491 if (block == null || phi.block() == block) {
492 if (!proc.doPhi(phi)) {
493 return false;
494 }
495 }
496 }
497 }
498 return true;
499 }
500
501 /**
502 * Checks whether this frame state has any {@linkplain Phi phi} statements.
503 */
504 public boolean hasPhis() {
505 int max = valuesSize();
506 for (int i = 0; i < max; i++) {
507 Value value = values[i];
508 if (value instanceof Phi) {
509 return true;
510 }
511 }
512 return false;
513 }
514
515 /**
516 * Iterates over all the values in this frame state and its callers, including the stack, locals, and locks.
517 * @param closure the closure to apply to each value
518 */
519 public void valuesDo(ValueClosure closure) {
520 valuesDo(this, closure);
521 }
522
523 /**
524 * Iterates over all the values of a given frame state and its callers, including the stack, locals, and locks.
525 * @param closure the closure to apply to each value
526 */
527 public static void valuesDo(FrameState state, ValueClosure closure) {
528 do {
529 final int max = state.valuesSize();
530 for (int i = 0; i < max; i++) {
531 if (state.values[i] != null) {
532 Value newValue = closure.apply(state.values[i]);
533 state.values[i] = newValue;
534 }
535 }
536 if (state.locks != null) {
537 for (int i = 0; i < state.locks.size(); i++) {
538 Value instr = state.locks.get(i);
539 if (instr != null) {
540 state.locks.set(i, closure.apply(instr));
541 }
542 }
543 }
544 state = state.callerState();
545 } while (state != null);
546 }
547
548 /**
549 * The interface implemented by a client of {@link FrameState#forEachLiveStateValue(ValueProcedure)}.
550 */
551 public static interface ValueProcedure {
552 void doValue(Value value);
553 }
554
555 /**
556 * Traverses all {@linkplain Value#isLive() live values} of this frame state and it's callers.
557 *
558 * @param proc the call back called to process each live value traversed
559 */
560 public final void forEachLiveStateValue(ValueProcedure proc) {
561 FrameState state = this;
562 while (state != null) {
563 final int max = state.valuesSize();
564 for (int i = 0; i < max; i++) {
565 Value value = state.values[i];
566 if (value != null && value.isLive()) {
567 proc.doValue(value);
568 }
569 }
570 state = state.callerState();
571 }
572 }
573
574 public static String toString(FrameState fs) {
575 StringBuilder sb = new StringBuilder();
576 String nl = String.format("%n");
577 while (fs != null) {
578 if (fs.scope == null) {
579 sb.append("<no method>").append(" [bci: ").append(fs.bci).append(']');
580 break;
581 } else {
582 CiUtil.appendLocation(sb, fs.scope.method, fs.bci).append(nl);
583 for (int i = 0; i < fs.localsSize(); ++i) {
584 Value value = fs.localAt(i);
585 sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
586 }
587 for (int i = 0; i < fs.stackSize(); ++i) {
588 Value value = fs.stackAt(i);
589 sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
590 }
591 for (int i = 0; i < fs.locksSize(); ++i) {
592 Value value = fs.lockAt(i);
593 sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
594 }
595 fs = fs.callerState();
596 }
597 }
598 return sb.toString();
599 }
600
601 @Override
602 public String toString() {
603 return toString(this);
604 }
605
606 public CiCodePos toCodePos() {
607 FrameState caller = callerState();
608 CiCodePos callerCodePos = null;
609 if (caller != null) {
610 callerCodePos = caller.toCodePos();
611 }
612 return new CiCodePos(callerCodePos, scope.method, bci);
613 }
614
615 /**
616 * Creates a new {@code MutableFrameState} corresponding to inlining the specified method into this point in this frame state.
617 * @param scope the IRScope representing the inlined method
618 * @return a new frame state representing the state at the beginning of inlining the specified method into this one
619 */
620 public MutableFrameState pushScope(IRScope scope) {
621 assert scope.caller == this.scope;
622 RiMethod method = scope.method;
623 return new MutableFrameState(scope, -1, method.maxLocals(), method.maxStackSize());
624 }
625
626 /**
627 * Creates a new {@code MutableFrameState} corresponding to the state upon returning from this inlined method into the outer
628 * IRScope.
629 * @return a new frame state representing the state at exit from this frame state
630 */
631 public MutableFrameState popScope() {
632 IRScope callingScope = scope.caller;
633 assert callingScope != null;
634 FrameState callerState = scope.callerState;
635 MutableFrameState res = new MutableFrameState(callingScope, bci, callerState.maxLocals, callerState.maxStackSize() + stackIndex);
636 System.arraycopy(callerState.values, 0, res.values, 0, callerState.values.length);
637 System.arraycopy(values, maxLocals, res.values, res.maxLocals + callerState.stackIndex, stackIndex);
638 res.stackIndex = callerState.stackIndex + stackIndex;
639 assert res.stackIndex >= 0;
640 res.replaceLocks(callerState);
641 return res;
642 }
643
644 /**
645 * Gets the caller frame state.
646 *
647 * @return the caller frame state or {@code null} if this is a top-level state
648 */
649 public FrameState callerState() {
650 return scope.callerState;
651 }
652 }