Mercurial > hg > graal-compiler
comparison graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/GraphBuilder.java @ 2872:0341b6424579
Project renaming.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 08 Jun 2011 08:42:25 +0200 |
parents | graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java@fc75fd3fa5e4 |
children |
comparison
equal
deleted
inserted
replaced
2871:d704eb526603 | 2872:0341b6424579 |
---|---|
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.graph; | |
24 | |
25 import static com.sun.cri.bytecode.Bytecodes.*; | |
26 import static java.lang.reflect.Modifier.*; | |
27 | |
28 import java.lang.reflect.*; | |
29 import java.util.*; | |
30 | |
31 import com.oracle.graal.graph.*; | |
32 import com.oracle.max.graal.schedule.*; | |
33 import com.sun.c1x.*; | |
34 import com.sun.c1x.debug.*; | |
35 import com.sun.c1x.graph.BlockMap.*; | |
36 import com.sun.c1x.graph.BlockMap.Block; | |
37 import com.sun.c1x.ir.*; | |
38 import com.sun.c1x.util.*; | |
39 import com.sun.c1x.value.*; | |
40 import com.sun.cri.bytecode.*; | |
41 import com.sun.cri.ci.*; | |
42 import com.sun.cri.ri.*; | |
43 import com.sun.cri.ri.RiType.*; | |
44 | |
45 /** | |
46 * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. | |
47 * A number of optimizations may be performed during parsing of the bytecode, including value | |
48 * numbering, inlining, constant folding, strength reduction, etc. | |
49 */ | |
50 public final class GraphBuilder { | |
51 | |
52 /** | |
53 * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace | |
54 * the bytecode instructions as they are parsed. | |
55 */ | |
56 public static final int TRACELEVEL_INSTRUCTIONS = 1; | |
57 | |
58 /** | |
59 * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace | |
60 * the frame state before each bytecode instruction as it is parsed. | |
61 */ | |
62 public static final int TRACELEVEL_STATE = 2; | |
63 | |
64 private final C1XCompilation compilation; | |
65 private final CompilerGraph graph; | |
66 | |
67 private final CiStatistics stats; | |
68 private final RiRuntime runtime; | |
69 private final RiMethod method; | |
70 private final RiConstantPool constantPool; | |
71 | |
72 private final BytecodeStream stream; // the bytecode stream | |
73 private final LogStream log; | |
74 private final FrameStateBuilder frameState; // the current execution state | |
75 | |
76 // bci-to-block mapping | |
77 private Block[] blockFromBci; | |
78 private ArrayList<Block> blockList; | |
79 | |
80 private int nextBlockNumber; | |
81 | |
82 private Value methodSynchronizedObject; | |
83 private CiExceptionHandler syncHandler; | |
84 | |
85 private Block unwindBlock; | |
86 private Block returnBlock; | |
87 | |
88 // the worklist of blocks, sorted by depth first number | |
89 private final PriorityQueue<Block> workList = new PriorityQueue<Block>(10, new Comparator<Block>() { | |
90 public int compare(Block o1, Block o2) { | |
91 return o1.blockID - o2.blockID; | |
92 } | |
93 }); | |
94 | |
95 private Instruction lastInstr; // the last instruction added | |
96 | |
97 private final Set<Block> blocksOnWorklist = new HashSet<Block>(); | |
98 private final Set<Block> blocksVisited = new HashSet<Block>(); | |
99 | |
100 | |
101 /** | |
102 * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. | |
103 * | |
104 * @param compilation the compilation | |
105 * @param ir the IR to build the graph into | |
106 * @param graph | |
107 */ | |
108 public GraphBuilder(C1XCompilation compilation, RiMethod method, CompilerGraph graph) { | |
109 this.compilation = compilation; | |
110 this.graph = graph; | |
111 | |
112 this.runtime = compilation.runtime; | |
113 this.method = method; | |
114 this.stats = compilation.stats; | |
115 this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; | |
116 this.stream = new BytecodeStream(method.code()); | |
117 | |
118 this.constantPool = runtime.getConstantPool(method); | |
119 this.frameState = new FrameStateBuilder(method, graph); | |
120 } | |
121 | |
122 /** | |
123 * Builds the graph for a the specified {@code IRScope}. | |
124 * | |
125 * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception | |
126 * handler and the method is not synchronized | |
127 */ | |
128 public void build(boolean createUnwind) { | |
129 if (log != null) { | |
130 log.println(); | |
131 log.println("Compiling " + method); | |
132 } | |
133 | |
134 // 2. compute the block map, setup exception handlers and get the entrypoint(s) | |
135 BlockMap blockMap = compilation.getBlockMap(method); | |
136 | |
137 blockList = new ArrayList<Block>(blockMap.blocks); | |
138 blockFromBci = new Block[method.code().length]; | |
139 for (int i = 0; i < blockList.size(); i++) { | |
140 int blockID = nextBlockNumber(); | |
141 assert blockID == i; | |
142 Block block = blockList.get(i); | |
143 if (block.startBci >= 0) { | |
144 blockFromBci[block.startBci] = block; | |
145 } | |
146 } | |
147 | |
148 // 1. create the start block | |
149 Block startBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI); | |
150 markOnWorkList(startBlock); | |
151 lastInstr = createTarget(startBlock, frameState); | |
152 graph.start().setStart(lastInstr); | |
153 | |
154 if (isSynchronized(method.accessFlags())) { | |
155 // 4A.1 add a monitor enter to the start block | |
156 methodSynchronizedObject = synchronizedObject(frameState, method); | |
157 genMonitorEnter(methodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI); | |
158 // 4A.2 finish the start block | |
159 finishStartBlock(startBlock); | |
160 | |
161 // 4A.3 setup an exception handler to unlock the root method synchronized object | |
162 syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); | |
163 } else { | |
164 // 4B.1 simply finish the start block | |
165 finishStartBlock(startBlock); | |
166 | |
167 if (createUnwind) { | |
168 syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); | |
169 } | |
170 } | |
171 | |
172 // 5. SKIPPED: look for intrinsics | |
173 | |
174 // 6B.1 do the normal parsing | |
175 addToWorkList(blockFromBci[0]); | |
176 iterateAllBlocks(); | |
177 | |
178 // remove Placeholders | |
179 for (Node n : graph.getNodes()) { | |
180 if (n instanceof Placeholder) { | |
181 Placeholder p = (Placeholder) n; | |
182 assert p.blockPredecessors().size() == 1; | |
183 Node pred = p.blockPredecessors().get(0); | |
184 int predIndex = p.predecessorsIndex().get(0); | |
185 pred.successors().setAndClear(predIndex, p, 0); | |
186 p.delete(); | |
187 } | |
188 } | |
189 | |
190 // remove FrameStates | |
191 for (Node n : graph.getNodes()) { | |
192 if (n instanceof FrameState) { | |
193 boolean delete = false; | |
194 if (n.usages().size() == 0 && n.predecessors().size() == 0) { | |
195 delete = true; | |
196 } | |
197 if (delete) { | |
198 n.delete(); | |
199 } | |
200 } | |
201 } | |
202 } | |
203 | |
204 private int nextBlockNumber() { | |
205 stats.blockCount++; | |
206 return nextBlockNumber++; | |
207 } | |
208 | |
209 private Block nextBlock(int bci) { | |
210 Block block = new Block(); | |
211 block.startBci = bci; | |
212 block.endBci = bci; | |
213 block.blockID = nextBlockNumber(); | |
214 return block; | |
215 } | |
216 | |
217 private Block unwindBlock() { | |
218 if (unwindBlock == null) { | |
219 unwindBlock = new Block(); | |
220 unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; | |
221 unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; | |
222 unwindBlock.blockID = nextBlockNumber(); | |
223 addToWorkList(unwindBlock); | |
224 } | |
225 return unwindBlock; | |
226 } | |
227 | |
228 private Block returnBlock() { | |
229 if (returnBlock == null) { | |
230 returnBlock = new Block(); | |
231 returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; | |
232 returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; | |
233 returnBlock.blockID = nextBlockNumber(); | |
234 addToWorkList(returnBlock); | |
235 } | |
236 return returnBlock; | |
237 } | |
238 | |
239 private void markOnWorkList(Block block) { | |
240 blocksOnWorklist.add(block); | |
241 } | |
242 | |
243 private boolean isOnWorkList(Block block) { | |
244 return blocksOnWorklist.contains(block); | |
245 } | |
246 | |
247 private void markVisited(Block block) { | |
248 blocksVisited.add(block); | |
249 } | |
250 | |
251 private boolean isVisited(Block block) { | |
252 return blocksVisited.contains(block); | |
253 } | |
254 | |
255 private void finishStartBlock(Block startBlock) { | |
256 assert bci() == 0; | |
257 Instruction target = createTargetAt(0, frameState); | |
258 appendGoto(target); | |
259 } | |
260 | |
261 public void mergeOrClone(Block target, FrameStateAccess newState) { | |
262 Instruction first = target.firstInstruction; | |
263 if (target.isLoopHeader && isVisited(target)) { | |
264 first = ((LoopBegin) first).loopEnd(); | |
265 } | |
266 assert first instanceof StateSplit; | |
267 | |
268 int bci = target.startBci; | |
269 | |
270 FrameState existingState = ((StateSplit) first).stateBefore(); | |
271 | |
272 if (existingState == null) { | |
273 // copy state because it is modified | |
274 FrameState duplicate = newState.duplicate(bci); | |
275 | |
276 // if the block is a loop header, insert all necessary phis | |
277 if (first instanceof LoopBegin && target.isLoopHeader) { | |
278 assert first instanceof Merge; | |
279 insertLoopPhis((Merge) first, duplicate); | |
280 ((Merge) first).setStateBefore(duplicate); | |
281 } else { | |
282 ((StateSplit) first).setStateBefore(duplicate); | |
283 } | |
284 } else { | |
285 if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { | |
286 // stacks or locks do not match--bytecodes would not verify | |
287 TTY.println(existingState.toString()); | |
288 TTY.println(newState.duplicate(0).toString()); | |
289 throw new CiBailout("stack or locks do not match"); | |
290 } | |
291 assert existingState.localsSize() == newState.localsSize(); | |
292 assert existingState.stackSize() == newState.stackSize(); | |
293 | |
294 if (first instanceof Placeholder) { | |
295 assert !target.isLoopHeader; | |
296 Merge merge = new Merge(graph); | |
297 | |
298 Placeholder p = (Placeholder) first; | |
299 assert p.next() == null; | |
300 p.replace(merge); | |
301 target.firstInstruction = merge; | |
302 merge.setStateBefore(existingState); | |
303 first = merge; | |
304 } | |
305 | |
306 existingState.merge((Merge) first, newState); | |
307 } | |
308 | |
309 for (int j = 0; j < frameState.localsSize() + frameState.stackSize(); ++j) { | |
310 if (frameState.valueAt(j) != null) { | |
311 assert !frameState.valueAt(j).isDeleted(); | |
312 } | |
313 } | |
314 } | |
315 | |
316 private void insertLoopPhis(Merge merge, FrameState newState) { | |
317 int stackSize = newState.stackSize(); | |
318 for (int i = 0; i < stackSize; i++) { | |
319 // always insert phis for the stack | |
320 Value x = newState.stackAt(i); | |
321 if (x != null) { | |
322 newState.setupPhiForStack(merge, i).addInput(x); | |
323 } | |
324 } | |
325 int localsSize = newState.localsSize(); | |
326 for (int i = 0; i < localsSize; i++) { | |
327 Value x = newState.localAt(i); | |
328 if (x != null) { | |
329 newState.setupPhiForLocal(merge, i).addInput(x); | |
330 } | |
331 } | |
332 } | |
333 | |
334 public BytecodeStream stream() { | |
335 return stream; | |
336 } | |
337 | |
338 public int bci() { | |
339 return stream.currentBCI(); | |
340 } | |
341 | |
342 private void loadLocal(int index, CiKind kind) { | |
343 frameState.push(kind, frameState.loadLocal(index)); | |
344 } | |
345 | |
346 private void storeLocal(CiKind kind, int index) { | |
347 frameState.storeLocal(index, frameState.pop(kind)); | |
348 } | |
349 | |
350 public boolean covers(RiExceptionHandler handler, int bci) { | |
351 return handler.startBCI() <= bci && bci < handler.endBCI(); | |
352 } | |
353 | |
354 public boolean isCatchAll(RiExceptionHandler handler) { | |
355 return handler.catchTypeCPI() == 0; | |
356 } | |
357 | |
358 private Instruction handleException(Value exceptionObject, int bci) { | |
359 assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; | |
360 | |
361 RiExceptionHandler firstHandler = null; | |
362 RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); | |
363 // join with all potential exception handlers | |
364 if (exceptionHandlers != null) { | |
365 for (RiExceptionHandler handler : exceptionHandlers) { | |
366 // if the handler covers this bytecode index, add it to the list | |
367 if (covers(handler, bci)) { | |
368 firstHandler = handler; | |
369 break; | |
370 } | |
371 } | |
372 } | |
373 | |
374 if (firstHandler == null) { | |
375 firstHandler = syncHandler; | |
376 } | |
377 | |
378 if (firstHandler != null) { | |
379 compilation.setHasExceptionHandlers(); | |
380 | |
381 Block dispatchBlock = null; | |
382 for (Block block : blockList) { | |
383 if (block instanceof ExceptionBlock) { | |
384 ExceptionBlock excBlock = (ExceptionBlock) block; | |
385 if (excBlock.handler == firstHandler) { | |
386 dispatchBlock = block; | |
387 break; | |
388 } | |
389 } | |
390 } | |
391 // if there's no dispatch block then the catch block needs to be a catch all | |
392 if (dispatchBlock == null) { | |
393 assert isCatchAll(firstHandler); | |
394 int handlerBCI = firstHandler.handlerBCI(); | |
395 if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) { | |
396 dispatchBlock = unwindBlock(); | |
397 } else { | |
398 dispatchBlock = blockFromBci[handlerBCI]; | |
399 } | |
400 } | |
401 FrameState entryState = frameState.duplicateWithEmptyStack(bci); | |
402 | |
403 StateSplit entry = new Placeholder(graph); | |
404 entry.setStateBefore(entryState); | |
405 | |
406 Instruction currentNext = entry; | |
407 Value currentExceptionObject = exceptionObject; | |
408 if (currentExceptionObject == null) { | |
409 ExceptionObject exception = new ExceptionObject(graph); | |
410 entry.setNext(exception); | |
411 currentNext = exception; | |
412 currentExceptionObject = exception; | |
413 } | |
414 FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, currentExceptionObject); | |
415 | |
416 Instruction successor = createTarget(dispatchBlock, stateWithException); | |
417 currentNext.setNext(successor); | |
418 return entry; | |
419 } | |
420 return null; | |
421 } | |
422 | |
423 private void genLoadConstant(int cpi) { | |
424 Object con = constantPool.lookupConstant(cpi); | |
425 | |
426 if (con instanceof RiType) { | |
427 // this is a load of class constant which might be unresolved | |
428 RiType riType = (RiType) con; | |
429 if (!riType.isResolved()) { | |
430 append(new Deoptimize(graph)); | |
431 frameState.push(CiKind.Object, append(Constant.forObject(null, graph))); | |
432 } else { | |
433 frameState.push(CiKind.Object, append(new Constant(riType.getEncoding(Representation.JavaClass), graph))); | |
434 } | |
435 } else if (con instanceof CiConstant) { | |
436 CiConstant constant = (CiConstant) con; | |
437 frameState.push(constant.kind.stackKind(), appendConstant(constant)); | |
438 } else { | |
439 throw new Error("lookupConstant returned an object of incorrect type"); | |
440 } | |
441 } | |
442 | |
443 private void genLoadIndexed(CiKind kind) { | |
444 Value index = frameState.ipop(); | |
445 Value array = frameState.apop(); | |
446 Value length = append(new ArrayLength(array, graph)); | |
447 Value v = append(new LoadIndexed(array, index, length, kind, graph)); | |
448 frameState.push(kind.stackKind(), v); | |
449 } | |
450 | |
451 private void genStoreIndexed(CiKind kind) { | |
452 Value value = frameState.pop(kind.stackKind()); | |
453 Value index = frameState.ipop(); | |
454 Value array = frameState.apop(); | |
455 Value length = append(new ArrayLength(array, graph)); | |
456 StoreIndexed result = new StoreIndexed(array, index, length, kind, value, graph); | |
457 append(result); | |
458 } | |
459 | |
460 private void stackOp(int opcode) { | |
461 switch (opcode) { | |
462 case POP: { | |
463 frameState.xpop(); | |
464 break; | |
465 } | |
466 case POP2: { | |
467 frameState.xpop(); | |
468 frameState.xpop(); | |
469 break; | |
470 } | |
471 case DUP: { | |
472 Value w = frameState.xpop(); | |
473 frameState.xpush(w); | |
474 frameState.xpush(w); | |
475 break; | |
476 } | |
477 case DUP_X1: { | |
478 Value w1 = frameState.xpop(); | |
479 Value w2 = frameState.xpop(); | |
480 frameState.xpush(w1); | |
481 frameState.xpush(w2); | |
482 frameState.xpush(w1); | |
483 break; | |
484 } | |
485 case DUP_X2: { | |
486 Value w1 = frameState.xpop(); | |
487 Value w2 = frameState.xpop(); | |
488 Value w3 = frameState.xpop(); | |
489 frameState.xpush(w1); | |
490 frameState.xpush(w3); | |
491 frameState.xpush(w2); | |
492 frameState.xpush(w1); | |
493 break; | |
494 } | |
495 case DUP2: { | |
496 Value w1 = frameState.xpop(); | |
497 Value w2 = frameState.xpop(); | |
498 frameState.xpush(w2); | |
499 frameState.xpush(w1); | |
500 frameState.xpush(w2); | |
501 frameState.xpush(w1); | |
502 break; | |
503 } | |
504 case DUP2_X1: { | |
505 Value w1 = frameState.xpop(); | |
506 Value w2 = frameState.xpop(); | |
507 Value w3 = frameState.xpop(); | |
508 frameState.xpush(w2); | |
509 frameState.xpush(w1); | |
510 frameState.xpush(w3); | |
511 frameState.xpush(w2); | |
512 frameState.xpush(w1); | |
513 break; | |
514 } | |
515 case DUP2_X2: { | |
516 Value w1 = frameState.xpop(); | |
517 Value w2 = frameState.xpop(); | |
518 Value w3 = frameState.xpop(); | |
519 Value w4 = frameState.xpop(); | |
520 frameState.xpush(w2); | |
521 frameState.xpush(w1); | |
522 frameState.xpush(w4); | |
523 frameState.xpush(w3); | |
524 frameState.xpush(w2); | |
525 frameState.xpush(w1); | |
526 break; | |
527 } | |
528 case SWAP: { | |
529 Value w1 = frameState.xpop(); | |
530 Value w2 = frameState.xpop(); | |
531 frameState.xpush(w1); | |
532 frameState.xpush(w2); | |
533 break; | |
534 } | |
535 default: | |
536 throw Util.shouldNotReachHere(); | |
537 } | |
538 | |
539 } | |
540 | |
541 private void genArithmeticOp(CiKind kind, int opcode) { | |
542 genArithmeticOp(kind, opcode, false); | |
543 } | |
544 | |
545 private void genArithmeticOp(CiKind kind, int opcode, boolean canTrap) { | |
546 genArithmeticOp(kind, opcode, kind, kind, canTrap); | |
547 } | |
548 | |
549 private void genArithmeticOp(CiKind result, int opcode, CiKind x, CiKind y, boolean canTrap) { | |
550 Value yValue = frameState.pop(y); | |
551 Value xValue = frameState.pop(x); | |
552 Value result1 = append(new Arithmetic(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph)); | |
553 if (canTrap) { | |
554 append(new ValueAnchor(result1, graph)); | |
555 } | |
556 frameState.push(result, result1); | |
557 } | |
558 | |
559 private void genNegateOp(CiKind kind) { | |
560 frameState.push(kind, append(new Negate(frameState.pop(kind), graph))); | |
561 } | |
562 | |
563 private void genShiftOp(CiKind kind, int opcode) { | |
564 Value s = frameState.ipop(); | |
565 Value x = frameState.pop(kind); | |
566 Shift v; | |
567 switch(opcode){ | |
568 case ISHL: | |
569 case LSHL: v = new LeftShift(kind, x, s, graph); break; | |
570 case ISHR: | |
571 case LSHR: v = new RightShift(kind, x, s, graph); break; | |
572 case IUSHR: | |
573 case LUSHR: v = new UnsignedRightShift(kind, x, s, graph); break; | |
574 default: | |
575 throw new CiBailout("should not reach"); | |
576 } | |
577 frameState.push(kind, append(v)); | |
578 } | |
579 | |
580 private void genLogicOp(CiKind kind, int opcode) { | |
581 Value y = frameState.pop(kind); | |
582 Value x = frameState.pop(kind); | |
583 Logic v; | |
584 switch(opcode){ | |
585 case IAND: | |
586 case LAND: v = new And(kind, x, y, graph); break; | |
587 case IOR: | |
588 case LOR: v = new Or(kind, x, y, graph); break; | |
589 case IXOR: | |
590 case LXOR: v = new Xor(kind, x, y, graph); break; | |
591 default: | |
592 throw new CiBailout("should not reach"); | |
593 } | |
594 frameState.push(kind, append(v)); | |
595 } | |
596 | |
597 private void genCompareOp(CiKind kind, int opcode, CiKind resultKind) { | |
598 Value y = frameState.pop(kind); | |
599 Value x = frameState.pop(kind); | |
600 Value value = append(new NormalizeCompare(opcode, resultKind, x, y, graph)); | |
601 if (!resultKind.isVoid()) { | |
602 frameState.ipush(value); | |
603 } | |
604 } | |
605 | |
606 private void genConvert(int opcode, CiKind from, CiKind to) { | |
607 CiKind tt = to.stackKind(); | |
608 frameState.push(tt, append(new Convert(opcode, frameState.pop(from.stackKind()), tt, graph))); | |
609 } | |
610 | |
611 private void genIncrement() { | |
612 int index = stream().readLocalIndex(); | |
613 int delta = stream().readIncrement(); | |
614 Value x = frameState.localAt(index); | |
615 Value y = append(Constant.forInt(delta, graph)); | |
616 frameState.storeLocal(index, append(new Arithmetic(IADD, CiKind.Int, x, y, isStrict(method.accessFlags()), false, graph))); | |
617 } | |
618 | |
619 private void genGoto(int fromBCI, int toBCI) { | |
620 appendGoto(createTargetAt(toBCI, frameState)); | |
621 } | |
622 | |
623 private void ifNode(Value x, Condition cond, Value y) { | |
624 assert !x.isDeleted() && !y.isDeleted(); | |
625 If ifNode = new If(new Compare(x, cond, y, graph), graph); | |
626 append(ifNode); | |
627 Instruction tsucc = createTargetAt(stream().readBranchDest(), frameState); | |
628 ifNode.setBlockSuccessor(0, tsucc); | |
629 Instruction fsucc = createTargetAt(stream().nextBCI(), frameState); | |
630 ifNode.setBlockSuccessor(1, fsucc); | |
631 } | |
632 | |
633 private void genIfZero(Condition cond) { | |
634 Value y = appendConstant(CiConstant.INT_0); | |
635 Value x = frameState.ipop(); | |
636 ifNode(x, cond, y); | |
637 } | |
638 | |
639 private void genIfNull(Condition cond) { | |
640 Value y = appendConstant(CiConstant.NULL_OBJECT); | |
641 Value x = frameState.apop(); | |
642 ifNode(x, cond, y); | |
643 } | |
644 | |
645 private void genIfSame(CiKind kind, Condition cond) { | |
646 Value y = frameState.pop(kind); | |
647 Value x = frameState.pop(kind); | |
648 assert !x.isDeleted() && !y.isDeleted(); | |
649 ifNode(x, cond, y); | |
650 } | |
651 | |
652 private void genThrow(int bci) { | |
653 Value exception = frameState.apop(); | |
654 append(new NullCheck(exception, graph)); | |
655 | |
656 Instruction entry = handleException(exception, bci); | |
657 if (entry != null) { | |
658 append(entry); | |
659 } else { | |
660 frameState.clearStack(); | |
661 frameState.apush(exception); | |
662 appendGoto(createTarget(unwindBlock(), frameState)); | |
663 } | |
664 } | |
665 | |
666 private void genCheckCast() { | |
667 int cpi = stream().readCPI(); | |
668 RiType type = constantPool.lookupType(cpi, CHECKCAST); | |
669 boolean isInitialized = type.isResolved(); | |
670 Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); | |
671 Value object = frameState.apop(); | |
672 if (typeInstruction != null) { | |
673 frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); | |
674 } else { | |
675 frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); | |
676 } | |
677 } | |
678 | |
679 private void genInstanceOf() { | |
680 int cpi = stream().readCPI(); | |
681 RiType type = constantPool.lookupType(cpi, INSTANCEOF); | |
682 boolean isInitialized = type.isResolved(); | |
683 Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); | |
684 Value object = frameState.apop(); | |
685 if (typeInstruction != null) { | |
686 frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); | |
687 } else { | |
688 frameState.ipush(appendConstant(CiConstant.INT_0)); | |
689 } | |
690 } | |
691 | |
692 void genNewInstance(int cpi) { | |
693 RiType type = constantPool.lookupType(cpi, NEW); | |
694 if (type.isResolved()) { | |
695 NewInstance n = new NewInstance(type, cpi, constantPool, graph); | |
696 frameState.apush(append(n)); | |
697 } else { | |
698 append(new Deoptimize(graph)); | |
699 frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); | |
700 } | |
701 } | |
702 | |
703 private void genNewTypeArray(int typeCode) { | |
704 CiKind kind = CiKind.fromArrayTypeCode(typeCode); | |
705 RiType elementType = runtime.asRiType(kind); | |
706 NewTypeArray nta = new NewTypeArray(frameState.ipop(), elementType, graph); | |
707 frameState.apush(append(nta)); | |
708 } | |
709 | |
710 private void genNewObjectArray(int cpi) { | |
711 RiType type = constantPool.lookupType(cpi, ANEWARRAY); | |
712 Value length = frameState.ipop(); | |
713 if (type.isResolved()) { | |
714 NewArray n = new NewObjectArray(type, length, graph); | |
715 frameState.apush(append(n)); | |
716 } else { | |
717 append(new Deoptimize(graph)); | |
718 frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); | |
719 } | |
720 | |
721 } | |
722 | |
723 private void genNewMultiArray(int cpi) { | |
724 RiType type = constantPool.lookupType(cpi, MULTIANEWARRAY); | |
725 int rank = stream().readUByte(bci() + 3); | |
726 Value[] dims = new Value[rank]; | |
727 for (int i = rank - 1; i >= 0; i--) { | |
728 dims[i] = frameState.ipop(); | |
729 } | |
730 if (type.isResolved()) { | |
731 NewArray n = new NewMultiArray(type, dims, cpi, constantPool, graph); | |
732 frameState.apush(append(n)); | |
733 } else { | |
734 append(new Deoptimize(graph)); | |
735 frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); | |
736 } | |
737 } | |
738 | |
739 private void genGetField(int cpi, RiField field) { | |
740 CiKind kind = field.kind(); | |
741 Value receiver = frameState.apop(); | |
742 if (field.isResolved()) { | |
743 LoadField load = new LoadField(receiver, field, graph); | |
744 appendOptimizedLoadField(kind, load); | |
745 } else { | |
746 append(new Deoptimize(graph)); | |
747 frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); | |
748 } | |
749 } | |
750 | |
751 private void genPutField(int cpi, RiField field) { | |
752 Value value = frameState.pop(field.kind().stackKind()); | |
753 Value receiver = frameState.apop(); | |
754 if (field.isResolved()) { | |
755 StoreField store = new StoreField(receiver, field, value, graph); | |
756 appendOptimizedStoreField(store); | |
757 } else { | |
758 append(new Deoptimize(graph)); | |
759 } | |
760 } | |
761 | |
762 private void genGetStatic(int cpi, RiField field) { | |
763 RiType holder = field.holder(); | |
764 boolean isInitialized = field.isResolved(); | |
765 CiConstant constantValue = null; | |
766 if (isInitialized) { | |
767 constantValue = field.constantValue(null); | |
768 } | |
769 if (constantValue != null) { | |
770 frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue)); | |
771 } else { | |
772 Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); | |
773 CiKind kind = field.kind(); | |
774 if (container != null) { | |
775 LoadField load = new LoadField(container, field, graph); | |
776 appendOptimizedLoadField(kind, load); | |
777 } else { | |
778 append(new Deoptimize(graph)); | |
779 frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); | |
780 } | |
781 } | |
782 } | |
783 | |
784 private void genPutStatic(int cpi, RiField field) { | |
785 RiType holder = field.holder(); | |
786 Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi); | |
787 Value value = frameState.pop(field.kind().stackKind()); | |
788 if (container != null) { | |
789 StoreField store = new StoreField(container, field, value, graph); | |
790 appendOptimizedStoreField(store); | |
791 } else { | |
792 append(new Deoptimize(graph)); | |
793 } | |
794 } | |
795 | |
796 private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { | |
797 if (initialized) { | |
798 return appendConstant(holder.getEncoding(representation)); | |
799 } else { | |
800 append(new Deoptimize(graph)); | |
801 return null; | |
802 } | |
803 } | |
804 | |
805 private void appendOptimizedStoreField(StoreField store) { | |
806 append(store); | |
807 } | |
808 | |
809 private void appendOptimizedLoadField(CiKind kind, LoadField load) { | |
810 // append the load to the instruction | |
811 Value optimized = append(load); | |
812 frameState.push(kind.stackKind(), optimized); | |
813 } | |
814 | |
815 private void genInvokeStatic(RiMethod target, int cpi, RiConstantPool constantPool) { | |
816 RiType holder = target.holder(); | |
817 boolean isInitialized = target.isResolved() && holder.isInitialized(); | |
818 if (!isInitialized && C1XOptions.ResolveClassBeforeStaticInvoke) { | |
819 // Re-use the same resolution code as for accessing a static field. Even though | |
820 // the result of resolution is not used by the invocation (only the side effect | |
821 // of initialization is required), it can be commoned with static field accesses. | |
822 genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); | |
823 } | |
824 Value[] args = frameState.popArguments(target.signature().argumentSlots(false)); | |
825 appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); | |
826 } | |
827 | |
828 private void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { | |
829 Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); | |
830 genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool); | |
831 | |
832 } | |
833 | |
834 private void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) { | |
835 Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); | |
836 genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool); | |
837 | |
838 } | |
839 | |
840 private void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) { | |
841 Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); | |
842 invokeDirect(target, args, knownHolder, cpi, constantPool); | |
843 | |
844 } | |
845 | |
846 private void genInvokeIndirect(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { | |
847 Value receiver = args[0]; | |
848 // attempt to devirtualize the call | |
849 if (target.isResolved()) { | |
850 RiType klass = target.holder(); | |
851 | |
852 // 0. check for trivial cases | |
853 if (target.canBeStaticallyBound() && !isAbstract(target.accessFlags())) { | |
854 // check for trivial cases (e.g. final methods, nonvirtual methods) | |
855 invokeDirect(target, args, target.holder(), cpi, constantPool); | |
856 return; | |
857 } | |
858 // 1. check if the exact type of the receiver can be determined | |
859 RiType exact = getExactType(klass, receiver); | |
860 if (exact != null && exact.isResolved()) { | |
861 // either the holder class is exact, or the receiver object has an exact type | |
862 invokeDirect(exact.resolveMethodImpl(target), args, exact, cpi, constantPool); | |
863 return; | |
864 } | |
865 } | |
866 // devirtualization failed, produce an actual invokevirtual | |
867 appendInvoke(opcode, target, args, cpi, constantPool); | |
868 } | |
869 | |
870 private CiKind returnKind(RiMethod target) { | |
871 return target.signature().returnKind(); | |
872 } | |
873 | |
874 private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { | |
875 appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); | |
876 } | |
877 | |
878 private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { | |
879 CiKind resultType = returnKind(target); | |
880 Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph); | |
881 Value result = appendWithBCI(invoke); | |
882 invoke.setExceptionEdge(handleException(null, bci())); | |
883 frameState.pushReturn(resultType, result); | |
884 } | |
885 | |
886 private RiType getExactType(RiType staticType, Value receiver) { | |
887 RiType exact = staticType.exactType(); | |
888 if (exact == null) { | |
889 exact = receiver.exactType(); | |
890 if (exact == null) { | |
891 if (receiver.isConstant()) { | |
892 exact = runtime.getTypeOf(receiver.asConstant()); | |
893 } | |
894 if (exact == null) { | |
895 RiType declared = receiver.declaredType(); | |
896 exact = declared == null || !declared.isResolved() ? null : declared.exactType(); | |
897 } | |
898 } | |
899 } | |
900 return exact; | |
901 } | |
902 | |
903 private void callRegisterFinalizer() { | |
904 Value receiver = frameState.loadLocal(0); | |
905 RiType declaredType = receiver.declaredType(); | |
906 RiType receiverType = declaredType; | |
907 RiType exactType = receiver.exactType(); | |
908 if (exactType == null && declaredType != null) { | |
909 exactType = declaredType.exactType(); | |
910 } | |
911 if (exactType == null && receiver instanceof Local && ((Local) receiver).index() == 0) { | |
912 // the exact type isn't known, but the receiver is parameter 0 => use holder | |
913 receiverType = method.holder(); | |
914 exactType = receiverType.exactType(); | |
915 } | |
916 boolean needsCheck = true; | |
917 if (exactType != null) { | |
918 // we have an exact type | |
919 needsCheck = exactType.hasFinalizer(); | |
920 } else { | |
921 // if either the declared type of receiver or the holder can be assumed to have no finalizers | |
922 if (declaredType != null && !declaredType.hasFinalizableSubclass()) { | |
923 if (compilation.recordNoFinalizableSubclassAssumption(declaredType)) { | |
924 needsCheck = false; | |
925 } | |
926 } | |
927 | |
928 if (receiverType != null && !receiverType.hasFinalizableSubclass()) { | |
929 if (compilation.recordNoFinalizableSubclassAssumption(receiverType)) { | |
930 needsCheck = false; | |
931 } | |
932 } | |
933 } | |
934 | |
935 if (needsCheck) { | |
936 // append a call to the finalizer registration | |
937 append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph)); | |
938 C1XMetrics.InlinedFinalizerChecks++; | |
939 } | |
940 } | |
941 | |
942 private void genReturn(Value x) { | |
943 frameState.clearStack(); | |
944 if (x != null) { | |
945 frameState.push(x.kind, x); | |
946 } | |
947 appendGoto(createTarget(returnBlock(), frameState)); | |
948 } | |
949 | |
950 private void genMonitorEnter(Value x, int bci) { | |
951 int lockNumber = frameState.locksSize(); | |
952 MonitorAddress lockAddress = null; | |
953 if (runtime.sizeOfBasicObjectLock() != 0) { | |
954 lockAddress = new MonitorAddress(lockNumber, graph); | |
955 append(lockAddress); | |
956 } | |
957 MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); | |
958 appendWithBCI(monitorEnter); | |
959 frameState.lock(x); | |
960 if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { | |
961 monitorEnter.setStateAfter(frameState.create(0)); | |
962 } | |
963 } | |
964 | |
965 private void genMonitorExit(Value x) { | |
966 int lockNumber = frameState.locksSize() - 1; | |
967 if (lockNumber < 0) { | |
968 throw new CiBailout("monitor stack underflow"); | |
969 } | |
970 MonitorAddress lockAddress = null; | |
971 if (runtime.sizeOfBasicObjectLock() != 0) { | |
972 lockAddress = new MonitorAddress(lockNumber, graph); | |
973 append(lockAddress); | |
974 } | |
975 appendWithBCI(new MonitorExit(x, lockAddress, lockNumber, graph)); | |
976 frameState.unlock(); | |
977 } | |
978 | |
979 private void genJsr(int dest) { | |
980 throw new CiBailout("jsr/ret not supported"); | |
981 } | |
982 | |
983 private void genRet(int localIndex) { | |
984 throw new CiBailout("jsr/ret not supported"); | |
985 } | |
986 | |
987 private void genTableswitch() { | |
988 int bci = bci(); | |
989 Value value = frameState.ipop(); | |
990 BytecodeTableSwitch ts = new BytecodeTableSwitch(stream(), bci); | |
991 int max = ts.numberOfCases(); | |
992 List<Instruction> list = new ArrayList<Instruction>(max + 1); | |
993 List<Integer> offsetList = new ArrayList<Integer>(max + 1); | |
994 for (int i = 0; i < max; i++) { | |
995 // add all successors to the successor list | |
996 int offset = ts.offsetAt(i); | |
997 list.add(null); | |
998 offsetList.add(offset); | |
999 } | |
1000 int offset = ts.defaultOffset(); | |
1001 list.add(null); | |
1002 offsetList.add(offset); | |
1003 TableSwitch tableSwitch = new TableSwitch(value, list, ts.lowKey(), graph); | |
1004 for (int i = 0; i < offsetList.size(); ++i) { | |
1005 tableSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); | |
1006 } | |
1007 append(tableSwitch); | |
1008 } | |
1009 | |
1010 private void genLookupswitch() { | |
1011 int bci = bci(); | |
1012 Value value = frameState.ipop(); | |
1013 BytecodeLookupSwitch ls = new BytecodeLookupSwitch(stream(), bci); | |
1014 int max = ls.numberOfCases(); | |
1015 List<Instruction> list = new ArrayList<Instruction>(max + 1); | |
1016 List<Integer> offsetList = new ArrayList<Integer>(max + 1); | |
1017 int[] keys = new int[max]; | |
1018 for (int i = 0; i < max; i++) { | |
1019 // add all successors to the successor list | |
1020 int offset = ls.offsetAt(i); | |
1021 list.add(null); | |
1022 offsetList.add(offset); | |
1023 keys[i] = ls.keyAt(i); | |
1024 } | |
1025 int offset = ls.defaultOffset(); | |
1026 list.add(null); | |
1027 offsetList.add(offset); | |
1028 LookupSwitch lookupSwitch = new LookupSwitch(value, list, keys, graph); | |
1029 for (int i = 0; i < offsetList.size(); ++i) { | |
1030 lookupSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); | |
1031 } | |
1032 append(lookupSwitch); | |
1033 } | |
1034 | |
1035 private Value appendConstant(CiConstant constant) { | |
1036 return append(new Constant(constant, graph)); | |
1037 } | |
1038 | |
1039 private Value append(Instruction x) { | |
1040 return appendWithBCI(x); | |
1041 } | |
1042 | |
1043 private Value append(Value v) { | |
1044 return v; | |
1045 } | |
1046 | |
1047 private Value appendWithBCI(Instruction x) { | |
1048 assert x.predecessors().size() == 0 : "instruction should not have been appended yet"; | |
1049 assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; | |
1050 lastInstr.setNext(x); | |
1051 | |
1052 lastInstr = x; | |
1053 if (++stats.nodeCount >= C1XOptions.MaximumInstructionCount) { | |
1054 // bailout if we've exceeded the maximum inlining size | |
1055 throw new CiBailout("Method and/or inlining is too large"); | |
1056 } | |
1057 | |
1058 return x; | |
1059 } | |
1060 | |
1061 private Instruction createTargetAt(int bci, FrameStateAccess stateAfter) { | |
1062 return createTarget(blockFromBci[bci], stateAfter); | |
1063 } | |
1064 | |
1065 private Instruction createTarget(Block block, FrameStateAccess stateAfter) { | |
1066 assert block != null && stateAfter != null; | |
1067 assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : "non-loop block must be iterated after all its predecessors"; | |
1068 | |
1069 if (block.isExceptionEntry) { | |
1070 assert stateAfter.stackSize() == 1; | |
1071 } | |
1072 | |
1073 if (block.firstInstruction == null) { | |
1074 if (block.isLoopHeader) { | |
1075 // block.firstInstruction = new Merge(block.startBci, graph); | |
1076 | |
1077 LoopBegin loopBegin = new LoopBegin(graph); | |
1078 LoopEnd loopEnd = new LoopEnd(graph); | |
1079 loopEnd.setLoopBegin(loopBegin); | |
1080 block.firstInstruction = loopBegin; | |
1081 } else { | |
1082 block.firstInstruction = new Placeholder(graph); | |
1083 } | |
1084 } | |
1085 mergeOrClone(block, stateAfter); | |
1086 addToWorkList(block); | |
1087 | |
1088 if (block.firstInstruction instanceof LoopBegin && isVisited(block)) { | |
1089 return ((LoopBegin) block.firstInstruction).loopEnd(); | |
1090 } else { | |
1091 return block.firstInstruction; | |
1092 } | |
1093 } | |
1094 | |
1095 private Value synchronizedObject(FrameStateAccess state, RiMethod target) { | |
1096 if (isStatic(target.accessFlags())) { | |
1097 Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph); | |
1098 return append(classConstant); | |
1099 } else { | |
1100 return state.localAt(0); | |
1101 } | |
1102 } | |
1103 | |
1104 private void iterateAllBlocks() { | |
1105 Block block; | |
1106 while ((block = removeFromWorkList()) != null) { | |
1107 | |
1108 // remove blocks that have no predecessors by the time it their bytecodes are parsed | |
1109 if (block.firstInstruction == null) { | |
1110 markVisited(block); | |
1111 continue; | |
1112 } | |
1113 | |
1114 if (!isVisited(block)) { | |
1115 markVisited(block); | |
1116 // now parse the block | |
1117 frameState.initializeFrom(((StateSplit) block.firstInstruction).stateBefore()); | |
1118 lastInstr = block.firstInstruction; | |
1119 assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID; | |
1120 | |
1121 if (block == returnBlock) { | |
1122 createReturnBlock(block); | |
1123 } else if (block == unwindBlock) { | |
1124 createUnwindBlock(block); | |
1125 } else if (block instanceof ExceptionBlock) { | |
1126 createExceptionDispatch((ExceptionBlock) block); | |
1127 } else { | |
1128 iterateBytecodesForBlock(block); | |
1129 } | |
1130 } | |
1131 } | |
1132 for (Block b : blocksVisited) { | |
1133 if (b.isLoopHeader) { | |
1134 LoopBegin begin = (LoopBegin) b.firstInstruction; | |
1135 LoopEnd end = begin.loopEnd(); | |
1136 | |
1137 // This can happen with degenerated loops like this one: | |
1138 // for (;;) { | |
1139 // try { | |
1140 // break; | |
1141 // } catch (UnresolvedException iioe) { | |
1142 // } | |
1143 // } | |
1144 if (end.stateBefore() != null) { | |
1145 begin.stateBefore().merge(begin, end.stateBefore()); | |
1146 } else { | |
1147 end.delete(); | |
1148 Merge merge = new Merge(graph); | |
1149 merge.successors().setAndClear(merge.nextIndex(), begin, begin.nextIndex()); | |
1150 begin.replace(merge); | |
1151 } | |
1152 } | |
1153 } | |
1154 } | |
1155 | |
1156 private void createUnwindBlock(Block block) { | |
1157 if (Modifier.isSynchronized(method.accessFlags())) { | |
1158 genMonitorExit(methodSynchronizedObject); | |
1159 } | |
1160 append(graph.createUnwind(frameState.apop())); | |
1161 } | |
1162 | |
1163 private void createReturnBlock(Block block) { | |
1164 if (method.isConstructor() && method.holder().superType() == null) { | |
1165 callRegisterFinalizer(); | |
1166 } | |
1167 CiKind returnKind = method.signature().returnKind().stackKind(); | |
1168 Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind); | |
1169 assert frameState.stackSize() == 0; | |
1170 | |
1171 if (Modifier.isSynchronized(method.accessFlags())) { | |
1172 genMonitorExit(methodSynchronizedObject); | |
1173 } | |
1174 append(graph.createReturn(x)); | |
1175 } | |
1176 | |
1177 private void createExceptionDispatch(ExceptionBlock block) { | |
1178 if (block.handler == null) { | |
1179 assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize(); | |
1180 createUnwindBlock(block); | |
1181 } else { | |
1182 assert frameState.stackSize() == 1; | |
1183 | |
1184 Block nextBlock = block.next == null ? unwindBlock() : block.next; | |
1185 if (block.handler.catchType().isResolved()) { | |
1186 Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState); | |
1187 Instruction nextDispatch = createTarget(nextBlock, frameState); | |
1188 append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph)); | |
1189 } else { | |
1190 Deoptimize deopt = new Deoptimize(graph); | |
1191 deopt.setMessage("unresolved " + block.handler.catchType().name()); | |
1192 append(deopt); | |
1193 Instruction nextDispatch = createTarget(nextBlock, frameState); | |
1194 appendGoto(nextDispatch); | |
1195 } | |
1196 } | |
1197 } | |
1198 | |
1199 private void appendGoto(Instruction target) { | |
1200 lastInstr.setNext(target); | |
1201 } | |
1202 | |
1203 private void iterateBytecodesForBlock(Block block) { | |
1204 assert frameState != null; | |
1205 | |
1206 stream.setBCI(block.startBci); | |
1207 | |
1208 int endBCI = stream.endBCI(); | |
1209 boolean blockStart = true; | |
1210 | |
1211 int bci = block.startBci; | |
1212 while (bci < endBCI) { | |
1213 Block nextBlock = blockFromBci[bci]; | |
1214 if (nextBlock != null && nextBlock != block) { | |
1215 assert !nextBlock.isExceptionEntry; | |
1216 // we fell through to the next block, add a goto and break | |
1217 appendGoto(createTarget(nextBlock, frameState)); | |
1218 break; | |
1219 } | |
1220 // read the opcode | |
1221 int opcode = stream.currentBC(); | |
1222 | |
1223 traceState(); | |
1224 traceInstruction(bci, opcode, blockStart); | |
1225 processBytecode(bci, opcode); | |
1226 | |
1227 if (Schedule.isBlockEnd(lastInstr) || lastInstr.next() != null) { | |
1228 break; | |
1229 } | |
1230 | |
1231 stream.next(); | |
1232 bci = stream.currentBCI(); | |
1233 if (lastInstr instanceof StateSplit) { | |
1234 StateSplit stateSplit = (StateSplit) lastInstr; | |
1235 if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { | |
1236 stateSplit.setStateAfter(frameState.create(bci)); | |
1237 } | |
1238 } | |
1239 blockStart = false; | |
1240 } | |
1241 } | |
1242 | |
1243 private void traceState() { | |
1244 if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) { | |
1245 log.println(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); | |
1246 for (int i = 0; i < frameState.localsSize(); ++i) { | |
1247 Value value = frameState.localAt(i); | |
1248 log.println(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); | |
1249 } | |
1250 for (int i = 0; i < frameState.stackSize(); ++i) { | |
1251 Value value = frameState.stackAt(i); | |
1252 log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); | |
1253 } | |
1254 for (int i = 0; i < frameState.locksSize(); ++i) { | |
1255 Value value = frameState.lockAt(i); | |
1256 log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); | |
1257 } | |
1258 } | |
1259 } | |
1260 | |
1261 private void processBytecode(int bci, int opcode) { | |
1262 int cpi; | |
1263 | |
1264 // Checkstyle: stop | |
1265 switch (opcode) { | |
1266 case NOP : /* nothing to do */ break; | |
1267 case ACONST_NULL : frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); break; | |
1268 case ICONST_M1 : frameState.ipush(appendConstant(CiConstant.INT_MINUS_1)); break; | |
1269 case ICONST_0 : frameState.ipush(appendConstant(CiConstant.INT_0)); break; | |
1270 case ICONST_1 : frameState.ipush(appendConstant(CiConstant.INT_1)); break; | |
1271 case ICONST_2 : frameState.ipush(appendConstant(CiConstant.INT_2)); break; | |
1272 case ICONST_3 : frameState.ipush(appendConstant(CiConstant.INT_3)); break; | |
1273 case ICONST_4 : frameState.ipush(appendConstant(CiConstant.INT_4)); break; | |
1274 case ICONST_5 : frameState.ipush(appendConstant(CiConstant.INT_5)); break; | |
1275 case LCONST_0 : frameState.lpush(appendConstant(CiConstant.LONG_0)); break; | |
1276 case LCONST_1 : frameState.lpush(appendConstant(CiConstant.LONG_1)); break; | |
1277 case FCONST_0 : frameState.fpush(appendConstant(CiConstant.FLOAT_0)); break; | |
1278 case FCONST_1 : frameState.fpush(appendConstant(CiConstant.FLOAT_1)); break; | |
1279 case FCONST_2 : frameState.fpush(appendConstant(CiConstant.FLOAT_2)); break; | |
1280 case DCONST_0 : frameState.dpush(appendConstant(CiConstant.DOUBLE_0)); break; | |
1281 case DCONST_1 : frameState.dpush(appendConstant(CiConstant.DOUBLE_1)); break; | |
1282 case BIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readByte()))); break; | |
1283 case SIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readShort()))); break; | |
1284 case LDC : // fall through | |
1285 case LDC_W : // fall through | |
1286 case LDC2_W : genLoadConstant(stream.readCPI()); break; | |
1287 case ILOAD : loadLocal(stream.readLocalIndex(), CiKind.Int); break; | |
1288 case LLOAD : loadLocal(stream.readLocalIndex(), CiKind.Long); break; | |
1289 case FLOAD : loadLocal(stream.readLocalIndex(), CiKind.Float); break; | |
1290 case DLOAD : loadLocal(stream.readLocalIndex(), CiKind.Double); break; | |
1291 case ALOAD : loadLocal(stream.readLocalIndex(), CiKind.Object); break; | |
1292 case ILOAD_0 : // fall through | |
1293 case ILOAD_1 : // fall through | |
1294 case ILOAD_2 : // fall through | |
1295 case ILOAD_3 : loadLocal(opcode - ILOAD_0, CiKind.Int); break; | |
1296 case LLOAD_0 : // fall through | |
1297 case LLOAD_1 : // fall through | |
1298 case LLOAD_2 : // fall through | |
1299 case LLOAD_3 : loadLocal(opcode - LLOAD_0, CiKind.Long); break; | |
1300 case FLOAD_0 : // fall through | |
1301 case FLOAD_1 : // fall through | |
1302 case FLOAD_2 : // fall through | |
1303 case FLOAD_3 : loadLocal(opcode - FLOAD_0, CiKind.Float); break; | |
1304 case DLOAD_0 : // fall through | |
1305 case DLOAD_1 : // fall through | |
1306 case DLOAD_2 : // fall through | |
1307 case DLOAD_3 : loadLocal(opcode - DLOAD_0, CiKind.Double); break; | |
1308 case ALOAD_0 : // fall through | |
1309 case ALOAD_1 : // fall through | |
1310 case ALOAD_2 : // fall through | |
1311 case ALOAD_3 : loadLocal(opcode - ALOAD_0, CiKind.Object); break; | |
1312 case IALOAD : genLoadIndexed(CiKind.Int ); break; | |
1313 case LALOAD : genLoadIndexed(CiKind.Long ); break; | |
1314 case FALOAD : genLoadIndexed(CiKind.Float ); break; | |
1315 case DALOAD : genLoadIndexed(CiKind.Double); break; | |
1316 case AALOAD : genLoadIndexed(CiKind.Object); break; | |
1317 case BALOAD : genLoadIndexed(CiKind.Byte ); break; | |
1318 case CALOAD : genLoadIndexed(CiKind.Char ); break; | |
1319 case SALOAD : genLoadIndexed(CiKind.Short ); break; | |
1320 case ISTORE : storeLocal(CiKind.Int, stream.readLocalIndex()); break; | |
1321 case LSTORE : storeLocal(CiKind.Long, stream.readLocalIndex()); break; | |
1322 case FSTORE : storeLocal(CiKind.Float, stream.readLocalIndex()); break; | |
1323 case DSTORE : storeLocal(CiKind.Double, stream.readLocalIndex()); break; | |
1324 case ASTORE : storeLocal(CiKind.Object, stream.readLocalIndex()); break; | |
1325 case ISTORE_0 : // fall through | |
1326 case ISTORE_1 : // fall through | |
1327 case ISTORE_2 : // fall through | |
1328 case ISTORE_3 : storeLocal(CiKind.Int, opcode - ISTORE_0); break; | |
1329 case LSTORE_0 : // fall through | |
1330 case LSTORE_1 : // fall through | |
1331 case LSTORE_2 : // fall through | |
1332 case LSTORE_3 : storeLocal(CiKind.Long, opcode - LSTORE_0); break; | |
1333 case FSTORE_0 : // fall through | |
1334 case FSTORE_1 : // fall through | |
1335 case FSTORE_2 : // fall through | |
1336 case FSTORE_3 : storeLocal(CiKind.Float, opcode - FSTORE_0); break; | |
1337 case DSTORE_0 : // fall through | |
1338 case DSTORE_1 : // fall through | |
1339 case DSTORE_2 : // fall through | |
1340 case DSTORE_3 : storeLocal(CiKind.Double, opcode - DSTORE_0); break; | |
1341 case ASTORE_0 : // fall through | |
1342 case ASTORE_1 : // fall through | |
1343 case ASTORE_2 : // fall through | |
1344 case ASTORE_3 : storeLocal(CiKind.Object, opcode - ASTORE_0); break; | |
1345 case IASTORE : genStoreIndexed(CiKind.Int ); break; | |
1346 case LASTORE : genStoreIndexed(CiKind.Long ); break; | |
1347 case FASTORE : genStoreIndexed(CiKind.Float ); break; | |
1348 case DASTORE : genStoreIndexed(CiKind.Double); break; | |
1349 case AASTORE : genStoreIndexed(CiKind.Object); break; | |
1350 case BASTORE : genStoreIndexed(CiKind.Byte ); break; | |
1351 case CASTORE : genStoreIndexed(CiKind.Char ); break; | |
1352 case SASTORE : genStoreIndexed(CiKind.Short ); break; | |
1353 case POP : // fall through | |
1354 case POP2 : // fall through | |
1355 case DUP : // fall through | |
1356 case DUP_X1 : // fall through | |
1357 case DUP_X2 : // fall through | |
1358 case DUP2 : // fall through | |
1359 case DUP2_X1 : // fall through | |
1360 case DUP2_X2 : // fall through | |
1361 case SWAP : stackOp(opcode); break; | |
1362 case IADD : // fall through | |
1363 case ISUB : // fall through | |
1364 case IMUL : genArithmeticOp(CiKind.Int, opcode); break; | |
1365 case IDIV : // fall through | |
1366 case IREM : genArithmeticOp(CiKind.Int, opcode, true); break; | |
1367 case LADD : // fall through | |
1368 case LSUB : // fall through | |
1369 case LMUL : genArithmeticOp(CiKind.Long, opcode); break; | |
1370 case LDIV : // fall through | |
1371 case LREM : genArithmeticOp(CiKind.Long, opcode, true); break; | |
1372 case FADD : // fall through | |
1373 case FSUB : // fall through | |
1374 case FMUL : // fall through | |
1375 case FDIV : // fall through | |
1376 case FREM : genArithmeticOp(CiKind.Float, opcode); break; | |
1377 case DADD : // fall through | |
1378 case DSUB : // fall through | |
1379 case DMUL : // fall through | |
1380 case DDIV : // fall through | |
1381 case DREM : genArithmeticOp(CiKind.Double, opcode); break; | |
1382 case INEG : genNegateOp(CiKind.Int); break; | |
1383 case LNEG : genNegateOp(CiKind.Long); break; | |
1384 case FNEG : genNegateOp(CiKind.Float); break; | |
1385 case DNEG : genNegateOp(CiKind.Double); break; | |
1386 case ISHL : // fall through | |
1387 case ISHR : // fall through | |
1388 case IUSHR : genShiftOp(CiKind.Int, opcode); break; | |
1389 case IAND : // fall through | |
1390 case IOR : // fall through | |
1391 case IXOR : genLogicOp(CiKind.Int, opcode); break; | |
1392 case LSHL : // fall through | |
1393 case LSHR : // fall through | |
1394 case LUSHR : genShiftOp(CiKind.Long, opcode); break; | |
1395 case LAND : // fall through | |
1396 case LOR : // fall through | |
1397 case LXOR : genLogicOp(CiKind.Long, opcode); break; | |
1398 case IINC : genIncrement(); break; | |
1399 case I2L : genConvert(opcode, CiKind.Int , CiKind.Long ); break; | |
1400 case I2F : genConvert(opcode, CiKind.Int , CiKind.Float ); break; | |
1401 case I2D : genConvert(opcode, CiKind.Int , CiKind.Double); break; | |
1402 case L2I : genConvert(opcode, CiKind.Long , CiKind.Int ); break; | |
1403 case L2F : genConvert(opcode, CiKind.Long , CiKind.Float ); break; | |
1404 case L2D : genConvert(opcode, CiKind.Long , CiKind.Double); break; | |
1405 case F2I : genConvert(opcode, CiKind.Float , CiKind.Int ); break; | |
1406 case F2L : genConvert(opcode, CiKind.Float , CiKind.Long ); break; | |
1407 case F2D : genConvert(opcode, CiKind.Float , CiKind.Double); break; | |
1408 case D2I : genConvert(opcode, CiKind.Double, CiKind.Int ); break; | |
1409 case D2L : genConvert(opcode, CiKind.Double, CiKind.Long ); break; | |
1410 case D2F : genConvert(opcode, CiKind.Double, CiKind.Float ); break; | |
1411 case I2B : genConvert(opcode, CiKind.Int , CiKind.Byte ); break; | |
1412 case I2C : genConvert(opcode, CiKind.Int , CiKind.Char ); break; | |
1413 case I2S : genConvert(opcode, CiKind.Int , CiKind.Short ); break; | |
1414 case LCMP : genCompareOp(CiKind.Long, opcode, CiKind.Int); break; | |
1415 case FCMPL : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; | |
1416 case FCMPG : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; | |
1417 case DCMPL : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; | |
1418 case DCMPG : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; | |
1419 case IFEQ : genIfZero(Condition.EQ); break; | |
1420 case IFNE : genIfZero(Condition.NE); break; | |
1421 case IFLT : genIfZero(Condition.LT); break; | |
1422 case IFGE : genIfZero(Condition.GE); break; | |
1423 case IFGT : genIfZero(Condition.GT); break; | |
1424 case IFLE : genIfZero(Condition.LE); break; | |
1425 case IF_ICMPEQ : genIfSame(CiKind.Int, Condition.EQ); break; | |
1426 case IF_ICMPNE : genIfSame(CiKind.Int, Condition.NE); break; | |
1427 case IF_ICMPLT : genIfSame(CiKind.Int, Condition.LT); break; | |
1428 case IF_ICMPGE : genIfSame(CiKind.Int, Condition.GE); break; | |
1429 case IF_ICMPGT : genIfSame(CiKind.Int, Condition.GT); break; | |
1430 case IF_ICMPLE : genIfSame(CiKind.Int, Condition.LE); break; | |
1431 case IF_ACMPEQ : genIfSame(frameState.peekKind(), Condition.EQ); break; | |
1432 case IF_ACMPNE : genIfSame(frameState.peekKind(), Condition.NE); break; | |
1433 case GOTO : genGoto(stream.currentBCI(), stream.readBranchDest()); break; | |
1434 case JSR : genJsr(stream.readBranchDest()); break; | |
1435 case RET : genRet(stream.readLocalIndex()); break; | |
1436 case TABLESWITCH : genTableswitch(); break; | |
1437 case LOOKUPSWITCH : genLookupswitch(); break; | |
1438 case IRETURN : genReturn(frameState.ipop()); break; | |
1439 case LRETURN : genReturn(frameState.lpop()); break; | |
1440 case FRETURN : genReturn(frameState.fpop()); break; | |
1441 case DRETURN : genReturn(frameState.dpop()); break; | |
1442 case ARETURN : genReturn(frameState.apop()); break; | |
1443 case RETURN : genReturn(null ); break; | |
1444 case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, constantPool.lookupField(cpi, opcode)); break; | |
1445 case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, constantPool.lookupField(cpi, opcode)); break; | |
1446 case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, constantPool.lookupField(cpi, opcode)); break; | |
1447 case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, constantPool.lookupField(cpi, opcode)); break; | |
1448 case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; | |
1449 case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(constantPool.lookupMethod(cpi, opcode), null, cpi, constantPool); break; | |
1450 case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; | |
1451 case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; | |
1452 case NEW : genNewInstance(stream.readCPI()); break; | |
1453 case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; | |
1454 case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; | |
1455 case ARRAYLENGTH : genArrayLength(); break; | |
1456 case ATHROW : genThrow(stream.currentBCI()); break; | |
1457 case CHECKCAST : genCheckCast(); break; | |
1458 case INSTANCEOF : genInstanceOf(); break; | |
1459 case MONITORENTER : genMonitorEnter(frameState.apop(), stream.currentBCI()); break; | |
1460 case MONITOREXIT : genMonitorExit(frameState.apop()); break; | |
1461 case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; | |
1462 case IFNULL : genIfNull(Condition.EQ); break; | |
1463 case IFNONNULL : genIfNull(Condition.NE); break; | |
1464 case GOTO_W : genGoto(stream.currentBCI(), stream.readFarBranchDest()); break; | |
1465 case JSR_W : genJsr(stream.readFarBranchDest()); break; | |
1466 case BREAKPOINT: | |
1467 throw new CiBailout("concurrent setting of breakpoint"); | |
1468 default: | |
1469 throw new CiBailout("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); | |
1470 } | |
1471 // Checkstyle: resume | |
1472 } | |
1473 | |
1474 private void traceInstruction(int bci, int opcode, boolean blockStart) { | |
1475 if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_INSTRUCTIONS && !TTY.isSuppressed()) { | |
1476 StringBuilder sb = new StringBuilder(40); | |
1477 sb.append(blockStart ? '+' : '|'); | |
1478 if (bci < 10) { | |
1479 sb.append(" "); | |
1480 } else if (bci < 100) { | |
1481 sb.append(' '); | |
1482 } | |
1483 sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); | |
1484 for (int i = bci + 1; i < stream.nextBCI(); ++i) { | |
1485 sb.append(' ').append(stream.readUByte(i)); | |
1486 } | |
1487 log.println(sb.toString()); | |
1488 } | |
1489 } | |
1490 | |
1491 private void genArrayLength() { | |
1492 frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); | |
1493 } | |
1494 | |
1495 /** | |
1496 * Adds a block to the worklist, if it is not already in the worklist. | |
1497 * This method will keep the worklist topologically stored (i.e. the lower | |
1498 * DFNs are earlier in the list). | |
1499 * @param block the block to add to the work list | |
1500 */ | |
1501 private void addToWorkList(Block block) { | |
1502 if (!isOnWorkList(block)) { | |
1503 markOnWorkList(block); | |
1504 sortIntoWorkList(block); | |
1505 } | |
1506 } | |
1507 | |
1508 private void sortIntoWorkList(Block top) { | |
1509 workList.offer(top); | |
1510 } | |
1511 | |
1512 /** | |
1513 * Removes the next block from the worklist. The list is sorted topologically, so the | |
1514 * block with the lowest depth first number in the list will be removed and returned. | |
1515 * @return the next block from the worklist; {@code null} if there are no blocks | |
1516 * in the worklist | |
1517 */ | |
1518 private Block removeFromWorkList() { | |
1519 return workList.poll(); | |
1520 } | |
1521 } |