comparison graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java @ 2616:3558ca7088c0

FrameState and Graphviz changes: * removed popx, pushx methods from GraphBuilder * FrameState subclass of Value * added String shortName() to Node * added GraphvizPrinter option to use short names * small hack in GraphvizPrinter: omit FrameState->Local connections * added GraalGraphviz to implicit classpatch (read from GRAAL env var)
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 09 May 2011 17:00:25 +0200
parents bd235cb4375a
children dd115f80acf8
comparison
equal deleted inserted replaced
2615:5768534fd4e5 2616:3558ca7088c0
24 24
25 import java.util.*; 25 import java.util.*;
26 26
27 import com.oracle.graal.graph.*; 27 import com.oracle.graal.graph.*;
28 import com.sun.c1x.*; 28 import com.sun.c1x.*;
29 import com.sun.c1x.debug.*;
29 import com.sun.c1x.ir.*; 30 import com.sun.c1x.ir.*;
30 import com.sun.cri.ci.*; 31 import com.sun.cri.ci.*;
31 32
32 import static com.sun.c1x.value.ValueUtil.*; 33 import static com.sun.c1x.value.ValueUtil.*;
33 34
34 /** 35 /**
35 * The {@code FrameState} class encapsulates the frame state (i.e. local variables and 36 * The {@code FrameState} class encapsulates the frame state (i.e. local variables and
36 * operand stack) at a particular point in the abstract interpretation. 37 * operand stack) at a particular point in the abstract interpretation.
37 */ 38 */
38 public class FrameState { 39 public class FrameState extends Value implements FrameStateAccess {
39 40
40 /**
41 * The operand stack and local variables.
42 * The local variables occupy the index range {@code [0 .. maxLocals)}.
43 * The operand stack occupies the index range {@code [maxLocals .. values.length)}.
44 * The top of the operand stack is at index {@code maxLocals + stackIndex}.
45 * This does not include the operand stack or local variables of parent frames.
46 *
47 * {@linkplain CiKind#isDoubleWord() Double-word} local variables and
48 * operand stack values occupy 2 slots in this array with the second slot
49 * being {@code null}.
50 */
51 protected final Value[] values;
52
53 /**
54 * The number of local variables.
55 */
56 protected final int localsSize; 41 protected final int localsSize;
57 42
58 protected final int stackSize; 43 protected final int stackSize;
44
45 protected final int locksSize;
46
47 private static final int SUCCESSOR_COUNT = 0;
48
49 @Override
50 protected int inputCount() {
51 return super.inputCount() + localsSize + stackSize + locksSize;
52 }
53
54 @Override
55 protected int successorCount() {
56 return super.successorCount() + SUCCESSOR_COUNT;
57 }
59 58
60 /** 59 /**
61 * The bytecode index to which this frame state applies. This will be {@code -1} 60 * The bytecode index to which this frame state applies. This will be {@code -1}
62 * iff this state is mutable. 61 * iff this state is mutable.
63 */ 62 */
69 * @param bci the bytecode index of the frame state 68 * @param bci the bytecode index of the frame state
70 * @param localsSize number of locals 69 * @param localsSize number of locals
71 * @param stackSize size of the stack 70 * @param stackSize size of the stack
72 * @param lockSize number of locks 71 * @param lockSize number of locks
73 */ 72 */
74 public FrameState(int bci, int localsSize, int stackSize, int lockSize) { 73 public FrameState(int bci, int localsSize, int stackSize, int locksSize, Graph graph) {
74 super(CiKind.Illegal, localsSize + stackSize + locksSize, SUCCESSOR_COUNT, graph);
75 this.bci = bci; 75 this.bci = bci;
76 this.values = new Value[localsSize + stackSize + lockSize];
77 this.localsSize = localsSize; 76 this.localsSize = localsSize;
78 this.stackSize = stackSize; 77 this.stackSize = stackSize;
78 this.locksSize = locksSize;
79 C1XMetrics.FrameStatesCreated++; 79 C1XMetrics.FrameStatesCreated++;
80 C1XMetrics.FrameStateValuesCreated += this.values.length; 80 C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize;
81 } 81 }
82 82
83 FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks) { 83 FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks, Graph graph) {
84 this(bci, locals.length, stackSize, locks.size()); 84 this(bci, locals.length, stackSize, locks.size(), graph);
85 System.arraycopy(locals, 0, values, 0, locals.length); 85 for (int i = 0; i < locals.length; i++) {
86 System.arraycopy(stack, 0, values, locals.length, stackSize); 86 inputs().set(i, locals[i]);
87 }
88 for (int i = 0; i < stackSize; i++) {
89 inputs().set(i + localsSize, stack[i]);
90 }
87 for (int i = 0; i < locks.size(); i++) { 91 for (int i = 0; i < locks.size(); i++) {
88 values[locals.length + stackSize + i] = locks.get(i); 92 inputs().set(locals.length + stackSize + i, locks.get(i));
89 } 93 }
90 } 94 }
91 95
92 /** 96 /**
93 * Gets a immutable copy ({@link FrameState}) of this frame state. 97 * Gets a copy of this frame state.
94 */ 98 */
95 public FrameState copy() { 99 public FrameState duplicate() {
96 FrameState other = new FrameState(bci, localsSize, stackSize, locksSize()); 100 FrameState other = copy();
97 System.arraycopy(values, 0, other.values, 0, values.length); 101 other.inputs().setAll(inputs());
98 return other; 102 return other;
99 } 103 }
100 104
101 /** 105 /**
102 * Gets an immutable copy of this frame state but without the stack. 106 * Gets a copy of this frame state without the stack.
103 */ 107 */
104 public FrameState copyWithEmptyStack() { 108 public FrameState duplicateWithEmptyStack() {
105 FrameState other = new FrameState(bci, localsSize, 0, locksSize()); 109 FrameState other = new FrameState(bci, localsSize, 0, locksSize(), graph());
106 System.arraycopy(values, 0, other.values, 0, localsSize); 110 for (int i = 0; i < localsSize; i++) {
107 System.arraycopy(values, localsSize + stackSize, other.values, localsSize, locksSize()); 111 other.inputs().set(i, localAt(i));
112 }
113 for (int i = 0; i < locksSize; i++) {
114 other.inputs().set(localsSize + i, lockAt(i));
115 }
108 return other; 116 return other;
109 } 117 }
110 118
111 public boolean isCompatibleWith(FrameState other) { 119 public boolean isCompatibleWith(FrameStateAccess other) {
112 if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) { 120 if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) {
113 return false; 121 return false;
114 } 122 }
115 for (int i = 0; i < stackSize(); i++) { 123 for (int i = 0; i < stackSize(); i++) {
116 Value x = stackAt(i); 124 Value x = stackAt(i);
126 } 134 }
127 return true; 135 return true;
128 } 136 }
129 137
130 /** 138 /**
131 * Returns the size of the local variables. 139 * Gets the size of the local variables.
132 *
133 * @return the size of the local variables
134 */ 140 */
135 public int localsSize() { 141 public int localsSize() {
136 return localsSize; 142 return localsSize;
137 } 143 }
138 144
145 151
146 /** 152 /**
147 * Gets number of locks held by this frame state. 153 * Gets number of locks held by this frame state.
148 */ 154 */
149 public int locksSize() { 155 public int locksSize() {
150 return values.length - localsSize - stackSize; 156 return locksSize;
151 } 157 }
152 158
153 /** 159 /**
154 * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then 160 * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then
155 * invalidates the high word as well. 161 * invalidates the high word as well.
158 */ 164 */
159 public void invalidateLocal(int i) { 165 public void invalidateLocal(int i) {
160 // note that for double word locals, the high slot should already be null 166 // note that for double word locals, the high slot should already be null
161 // unless the local is actually dead and the high slot is being reused; 167 // unless the local is actually dead and the high slot is being reused;
162 // in either case, it is not necessary to null the high slot 168 // in either case, it is not necessary to null the high slot
163 values[i] = null; 169 inputs().set(i, null);
164 } 170 }
165 171
166 /** 172 /**
167 * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, 173 * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word},
168 * then the next local variable index is also overwritten. 174 * then the next local variable index is also overwritten.
171 * @param x the instruction which produces the value for the local 177 * @param x the instruction which produces the value for the local
172 */ 178 */
173 public void storeLocal(int i, Value x) { 179 public void storeLocal(int i, Value x) {
174 assert i < localsSize : "local variable index out of range: " + i; 180 assert i < localsSize : "local variable index out of range: " + i;
175 invalidateLocal(i); 181 invalidateLocal(i);
176 values[i] = x; 182 inputs().set(i, x);
177 if (isDoubleWord(x)) { 183 if (isDoubleWord(x)) {
178 // (tw) if this was a double word then kill i+1 184 // (tw) if this was a double word then kill i+1
179 values[i + 1] = null; 185 inputs().set(i + 1, null);
180 } 186 }
181 if (i > 0) { 187 if (i > 0) {
182 // if there was a double word at i - 1, then kill it 188 // if there was a double word at i - 1, then kill it
183 Value p = values[i - 1]; 189 Value p = localAt(i - 1);
184 if (isDoubleWord(p)) { 190 if (isDoubleWord(p)) {
185 values[i - 1] = null; 191 inputs().set(i - 1, null);
186 } 192 }
187 } 193 }
188 } 194 }
189 195
190 /** 196 /**
193 * @param i the index into the locals 199 * @param i the index into the locals
194 * @return the instruction that produced the value for the specified local 200 * @return the instruction that produced the value for the specified local
195 */ 201 */
196 public final Value localAt(int i) { 202 public final Value localAt(int i) {
197 assert i < localsSize : "local variable index out of range: " + i; 203 assert i < localsSize : "local variable index out of range: " + i;
198 return values[i]; 204 return (Value) inputs().get(i);
199 } 205 }
200 206
201 /** 207 /**
202 * Get the value on the stack at the specified stack index. 208 * Get the value on the stack at the specified stack index.
203 * 209 *
204 * @param i the index into the stack, with {@code 0} being the bottom of the stack 210 * @param i the index into the stack, with {@code 0} being the bottom of the stack
205 * @return the instruction at the specified position in the stack 211 * @return the instruction at the specified position in the stack
206 */ 212 */
207 public final Value stackAt(int i) { 213 public final Value stackAt(int i) {
208 assert i >= 0 && i < (localsSize + stackSize); 214 assert i >= 0 && i < (localsSize + stackSize);
209 return values[localsSize + i]; 215 return (Value) inputs().get(localsSize + i);
210 } 216 }
211 217
212 /** 218 /**
213 * Retrieves the lock at the specified index in the lock stack. 219 * Retrieves the lock at the specified index in the lock stack.
214 * @param i the index into the lock stack 220 * @param i the index into the lock stack
215 * @return the instruction which produced the object at the specified location in the lock stack 221 * @return the instruction which produced the object at the specified location in the lock stack
216 */ 222 */
217 public final Value lockAt(int i) { 223 public final Value lockAt(int i) {
218 assert i >= 0; 224 assert i >= 0;
219 return values[localsSize + stackSize + i]; 225 return (Value) inputs().get(localsSize + stackSize + i);
220 } 226 }
221 227
222 /** 228 /**
223 * Inserts a phi statement into the stack at the specified stack index. 229 * Inserts a phi statement into the stack at the specified stack index.
224 * @param block the block begin for which we are creating the phi 230 * @param block the block begin for which we are creating the phi
225 * @param i the index into the stack for which to create a phi 231 * @param i the index into the stack for which to create a phi
226 * @param graph 232 */
227 */ 233 public void setupPhiForStack(BlockBegin block, int i) {
228 public void setupPhiForStack(BlockBegin block, int i, Graph graph) {
229 Value p = stackAt(i); 234 Value p = stackAt(i);
230 if (p != null) { 235 if (p != null) {
231 if (p instanceof Phi) { 236 if (p instanceof Phi) {
232 Phi phi = (Phi) p; 237 Phi phi = (Phi) p;
233 if (phi.block() == block && phi.isOnStack() && phi.stackIndex() == i) { 238 if (phi.block() == block && phi.isOnStack() && phi.stackIndex() == i) {
234 return; 239 return;
235 } 240 }
236 } 241 }
237 values[localsSize + i] = new Phi(p.kind, block, -i - 1, graph); 242 inputs().set(localsSize + i, new Phi(p.kind, block, -i - 1, graph()));
238 } 243 }
239 } 244 }
240 245
241 /** 246 /**
242 * Inserts a phi statement for the local at the specified index. 247 * Inserts a phi statement for the local at the specified index.
243 * @param block the block begin for which we are creating the phi 248 * @param block the block begin for which we are creating the phi
244 * @param i the index of the local variable for which to create the phi 249 * @param i the index of the local variable for which to create the phi
245 * @param graph 250 */
246 */ 251 public void setupPhiForLocal(BlockBegin block, int i) {
247 public void setupPhiForLocal(BlockBegin block, int i, Graph graph) { 252 Value p = localAt(i);
248 Value p = values[i];
249 if (p instanceof Phi) { 253 if (p instanceof Phi) {
250 Phi phi = (Phi) p; 254 Phi phi = (Phi) p;
251 if (phi.block() == block && phi.isLocal() && phi.localIndex() == i) { 255 if (phi.block() == block && phi.isLocal() && phi.localIndex() == i) {
252 return; 256 return;
253 } 257 }
254 } 258 }
255 storeLocal(i, new Phi(p.kind, block, i, graph)); 259 storeLocal(i, new Phi(p.kind, block, i, graph()));
256 } 260 }
257 261
258 /** 262 /**
259 * Gets the value at a specified index in the set of operand stack and local values represented by this frame. 263 * Gets the value at a specified index in the set of operand stack and local values represented by this frame.
260 * This method should only be used to iterate over all the values in this frame, irrespective of whether 264 * This method should only be used to iterate over all the values in this frame, irrespective of whether
265 * @param i a value in the range {@code [0 .. valuesSize()]} 269 * @param i a value in the range {@code [0 .. valuesSize()]}
266 * @return the value at index {@code i} which may be {@code null} 270 * @return the value at index {@code i} which may be {@code null}
267 */ 271 */
268 public final Value valueAt(int i) { 272 public final Value valueAt(int i) {
269 assert i < (localsSize + stackSize); 273 assert i < (localsSize + stackSize);
270 return values[i]; 274 return (Value) inputs().get(i);
271 } 275 }
272 276
273 /** 277 /**
274 * The number of operand stack slots and local variables in this frame. 278 * The number of operand stack slots and local variables in this frame.
275 * This method should typically only be used in conjunction with {@link #valueAt(int)}. 279 * This method should typically only be used in conjunction with {@link #valueAt(int)}.
282 return localsSize + stackSize; 286 return localsSize + stackSize;
283 } 287 }
284 288
285 public void checkPhis(BlockBegin block, FrameState other) { 289 public void checkPhis(BlockBegin block, FrameState other) {
286 checkSize(other); 290 checkSize(other);
287 final int max = valuesSize(); 291 for (int i = 0; i < valuesSize(); i++) {
288 for (int i = 0; i < max; i++) { 292 Value x = valueAt(i);
289 Value x = values[i]; 293 Value y = other.valueAt(i);
290 Value y = other.values[i];
291 if (x != null && x != y) { 294 if (x != null && x != y) {
292 if (x instanceof Phi) { 295 if (x instanceof Phi) {
293 Phi phi = (Phi) x; 296 Phi phi = (Phi) x;
294 if (phi.block() == block) { 297 if (phi.block() == block) {
295 for (int j = 0; j < phi.phiInputCount(); j++) { 298 for (int j = 0; j < phi.phiInputCount(); j++) {
303 throw new CiBailout("instruction is not a phi or null at " + i); 306 throw new CiBailout("instruction is not a phi or null at " + i);
304 } 307 }
305 } 308 }
306 } 309 }
307 310
308 private void checkSize(FrameState other) { 311 private void checkSize(FrameStateAccess other) {
309 if (other.stackSize() != stackSize()) { 312 if (other.stackSize() != stackSize()) {
310 throw new CiBailout("stack sizes do not match"); 313 throw new CiBailout("stack sizes do not match");
311 } else if (other.localsSize != localsSize) { 314 } else if (other.localsSize() != localsSize) {
312 throw new CiBailout("local sizes do not match"); 315 throw new CiBailout("local sizes do not match");
313 } 316 }
314 } 317 }
315 318
316 public void merge(BlockBegin block, FrameState other, Graph graph) { 319 public void merge(BlockBegin block, FrameStateAccess other) {
317 checkSize(other); 320 checkSize(other);
318 for (int i = 0; i < valuesSize(); i++) { 321 for (int i = 0; i < valuesSize(); i++) {
319 Value x = values[i]; 322 Value x = valueAt(i);
320 if (x != null) { 323 if (x != null) {
321 Value y = other.values[i]; 324 Value y = other.valueAt(i);
322 if (x != y) { 325 if (x != y) {
323 if (typeMismatch(x, y)) { 326 if (typeMismatch(x, y)) {
324 if (x instanceof Phi) { 327 if (x instanceof Phi) {
325 Phi phi = (Phi) x; 328 Phi phi = (Phi) x;
326 if (phi.block() == block) { 329 if (phi.block() == block) {
327 phi.makeDead(); 330 phi.makeDead();
328 } 331 }
329 } 332 }
330 values[i] = null; 333 inputs().set(i, null);
331 continue; 334 continue;
332 } 335 }
333 if (i < localsSize) { 336 if (i < localsSize) {
334 // this a local 337 // this a local
335 setupPhiForLocal(block, i, graph); 338 setupPhiForLocal(block, i);
336 } else { 339 } else {
337 // this is a stack slot 340 // this is a stack slot
338 setupPhiForStack(block, i - localsSize, graph); 341 setupPhiForStack(block, i - localsSize);
339 } 342 }
340 } 343 }
341 } 344 }
342 } 345 }
343 } 346 }
356 * 359 *
357 * @param block only phis {@linkplain Phi#block() associated} with this block are traversed 360 * @param block only phis {@linkplain Phi#block() associated} with this block are traversed
358 * @param proc the call back invoked for each live phi traversed 361 * @param proc the call back invoked for each live phi traversed
359 */ 362 */
360 public final boolean forEachLivePhi(BlockBegin block, PhiProcedure proc) { 363 public final boolean forEachLivePhi(BlockBegin block, PhiProcedure proc) {
361 int max = this.valuesSize(); 364 for (int i = 0; i < valuesSize(); i++) {
362 for (int i = 0; i < max; i++) { 365 Value instr = valueAt(i);
363 Value instr = values[i];
364 if (instr instanceof Phi && !instr.isDeadPhi()) { 366 if (instr instanceof Phi && !instr.isDeadPhi()) {
365 Phi phi = (Phi) instr; 367 Phi phi = (Phi) instr;
366 if (block == null || phi.block() == block) { 368 if (block == null || phi.block() == block) {
367 if (!proc.doPhi(phi)) { 369 if (!proc.doPhi(phi)) {
368 return false; 370 return false;
375 377
376 /** 378 /**
377 * Checks whether this frame state has any {@linkplain Phi phi} statements. 379 * Checks whether this frame state has any {@linkplain Phi phi} statements.
378 */ 380 */
379 public boolean hasPhis() { 381 public boolean hasPhis() {
380 int max = valuesSize(); 382 for (int i = 0; i < valuesSize(); i++) {
381 for (int i = 0; i < max; i++) { 383 Value value = valueAt(i);
382 Value value = values[i];
383 if (value instanceof Phi) { 384 if (value instanceof Phi) {
384 return true; 385 return true;
385 } 386 }
386 } 387 }
387 return false; 388 return false;
388 } 389 }
389 390
390 /** 391 /**
391 * Iterates over all the values in this frame state and its callers, including the stack, locals, and locks.
392 * @param closure the closure to apply to each value
393 */
394 public void valuesDo(ValueClosure closure) {
395 for (int i = 0; i < values.length; i++) {
396 if (values[i] != null) {
397 Value newValue = closure.apply(values[i]);
398 values[i] = newValue;
399 }
400 }
401 }
402
403 /**
404 * The interface implemented by a client of {@link FrameState#forEachLiveStateValue(ValueProcedure)}. 392 * The interface implemented by a client of {@link FrameState#forEachLiveStateValue(ValueProcedure)}.
405 */ 393 */
406 public static interface ValueProcedure { 394 public static interface ValueProcedure {
407 void doValue(Value value); 395 void doValue(Value value);
408 } 396 }
411 * Traverses all {@linkplain Value#isLive() live values} of this frame state. 399 * Traverses all {@linkplain Value#isLive() live values} of this frame state.
412 * 400 *
413 * @param proc the call back called to process each live value traversed 401 * @param proc the call back called to process each live value traversed
414 */ 402 */
415 public final void forEachLiveStateValue(ValueProcedure proc) { 403 public final void forEachLiveStateValue(ValueProcedure proc) {
416 final int max = this.valuesSize(); 404 for (int i = 0; i < valuesSize(); i++) {
417 for (int i = 0; i < max; i++) { 405 Value value = valueAt(i);
418 Value value = this.values[i];
419 if (value != null) { 406 if (value != null) {
420 proc.doValue(value); 407 proc.doValue(value);
421 } 408 }
422 } 409 }
423 } 410 }
439 Value value = lockAt(i); 426 Value value = lockAt(i);
440 sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); 427 sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
441 } 428 }
442 return sb.toString(); 429 return sb.toString();
443 } 430 }
431
432 @Override
433 public BlockBegin block() {
434 return null;
435 }
436
437 @Override
438 public void accept(ValueVisitor v) {
439 v.visitFrameState(this);
440 }
441
442 @Override
443 public void print(LogStream out) {
444 out.print("FrameState");
445 }
446
447 @Override
448 public FrameState copy() {
449 return new FrameState(bci, localsSize, stackSize, locksSize, graph());
450 }
451
452
444 } 453 }