Mercurial > hg > graal-compiler
comparison graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java @ 2563:491896f81cae
Removing inlining support (1st part)
author | Gilles Duboscq <gilles.duboscq@oracle.com> |
---|---|
date | Fri, 29 Apr 2011 11:50:28 +0200 |
parents | c58a301eb2d7 |
children | 274360f98f97 |
comparison
equal
deleted
inserted
replaced
2559:46eab5817cc2 | 2563:491896f81cae |
---|---|
28 import java.lang.reflect.*; | 28 import java.lang.reflect.*; |
29 import java.util.*; | 29 import java.util.*; |
30 | 30 |
31 import com.sun.c1x.*; | 31 import com.sun.c1x.*; |
32 import com.sun.c1x.debug.*; | 32 import com.sun.c1x.debug.*; |
33 import com.sun.c1x.graph.ScopeData.ReturnBlock; | |
34 import com.sun.c1x.ir.*; | 33 import com.sun.c1x.ir.*; |
35 import com.sun.c1x.opt.*; | 34 import com.sun.c1x.opt.*; |
36 import com.sun.c1x.util.*; | 35 import com.sun.c1x.util.*; |
37 import com.sun.c1x.value.*; | 36 import com.sun.c1x.value.*; |
38 import com.sun.cri.bytecode.*; | 37 import com.sun.cri.bytecode.*; |
815 // of initialization is required), it can be commoned with static field accesses. | 814 // of initialization is required), it can be commoned with static field accesses. |
816 genResolveClass(RiType.Representation.StaticFields, holder, isInitialized, cpi); | 815 genResolveClass(RiType.Representation.StaticFields, holder, isInitialized, cpi); |
817 } | 816 } |
818 | 817 |
819 Value[] args = curState.popArguments(target.signature().argumentSlots(false)); | 818 Value[] args = curState.popArguments(target.signature().argumentSlots(false)); |
820 if (!tryInline(target, args)) { | 819 appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); |
821 appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); | |
822 } | |
823 } | 820 } |
824 | 821 |
825 void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { | 822 void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { |
826 Value[] args = curState.popArguments(target.signature().argumentSlots(true)); | 823 Value[] args = curState.popArguments(target.signature().argumentSlots(true)); |
827 | 824 |
924 private CiKind returnKind(RiMethod target) { | 921 private CiKind returnKind(RiMethod target) { |
925 return target.signature().returnKind(); | 922 return target.signature().returnKind(); |
926 } | 923 } |
927 | 924 |
928 private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { | 925 private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { |
929 if (!tryInline(target, args)) { | 926 appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); |
930 // could not optimize or inline the method call | |
931 appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); | |
932 } | |
933 } | 927 } |
934 | 928 |
935 private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { | 929 private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { |
936 CiKind resultType = returnKind(target); | 930 CiKind resultType = returnKind(target); |
937 Value result = append(new Invoke(opcode, resultType.stackKind(), args, target, target.signature().returnType(compilation.method.holder()), null)); | 931 Value result = append(new Invoke(opcode, resultType.stackKind(), args, target, target.signature().returnType(compilation.method.holder()), null)); |
1350 } | 1344 } |
1351 data.setJsrContinuation(jsrCont); | 1345 data.setJsrContinuation(jsrCont); |
1352 scopeData = data; | 1346 scopeData = data; |
1353 } | 1347 } |
1354 | 1348 |
1355 void pushScope(RiMethod target, BlockBegin continuation) { | |
1356 // prepare callee scope | |
1357 IRScope calleeScope = new IRScope(scope(), curState.immutableCopy(bci()), target, -1); | |
1358 BlockMap blockMap = compilation.getBlockMap(calleeScope.method); | |
1359 calleeScope.setStoresInLoops(blockMap.getStoresInLoops()); | |
1360 // prepare callee state | |
1361 curState = curState.pushScope(calleeScope); | |
1362 BytecodeStream stream = new BytecodeStream(target.code()); | |
1363 RiConstantPool constantPool = compilation.runtime.getConstantPool(target); | |
1364 ScopeData data = new ScopeData(scopeData, calleeScope, blockMap, stream, constantPool); | |
1365 data.setContinuation(continuation); | |
1366 scopeData = data; | |
1367 } | |
1368 | |
1369 MutableFrameState stateAtEntry(RiMethod method) { | 1349 MutableFrameState stateAtEntry(RiMethod method) { |
1370 MutableFrameState state = new MutableFrameState(scope(), -1, method.maxLocals(), method.maxStackSize()); | 1350 MutableFrameState state = new MutableFrameState(scope(), -1, method.maxLocals(), method.maxStackSize()); |
1371 int index = 0; | 1351 int index = 0; |
1372 if (!isStatic(method.accessFlags())) { | 1352 if (!isStatic(method.accessFlags())) { |
1373 // add the receiver and assume it is non null | 1353 // add the receiver and assume it is non null |
1391 index += kind.sizeInSlots(); | 1371 index += kind.sizeInSlots(); |
1392 } | 1372 } |
1393 return state; | 1373 return state; |
1394 } | 1374 } |
1395 | 1375 |
1396 private boolean tryInline(RiMethod target, Value[] args) { | |
1397 boolean forcedInline = compilation.runtime.mustInline(target); | |
1398 if (forcedInline) { | |
1399 for (IRScope scope = scope().caller; scope != null; scope = scope.caller) { | |
1400 if (scope.method.equals(target)) { | |
1401 throw new CiBailout("Cannot recursively inline method that is force-inlined: " + target); | |
1402 } | |
1403 } | |
1404 C1XMetrics.InlineForcedMethods++; | |
1405 } | |
1406 if (forcedInline || checkInliningConditions(target)) { | |
1407 if (C1XOptions.TraceBytecodeParserLevel > 0) { | |
1408 log.adjustIndentation(1); | |
1409 log.println("\\"); | |
1410 log.adjustIndentation(1); | |
1411 if (C1XOptions.TraceBytecodeParserLevel < TRACELEVEL_STATE) { | |
1412 log.println("| [inlining " + target + "]"); | |
1413 log.println("|"); | |
1414 } | |
1415 } | |
1416 | |
1417 inline(target, args, forcedInline); | |
1418 | |
1419 if (C1XOptions.TraceBytecodeParserLevel > 0) { | |
1420 if (C1XOptions.TraceBytecodeParserLevel < TRACELEVEL_STATE) { | |
1421 log.println("|"); | |
1422 log.println("| [return to " + curState.scope().method + "]"); | |
1423 } | |
1424 log.adjustIndentation(-1); | |
1425 log.println("/"); | |
1426 log.adjustIndentation(-1); | |
1427 } | |
1428 return true; | |
1429 } | |
1430 return false; | |
1431 } | |
1432 | |
1433 private boolean checkInliningConditions(RiMethod target) { | |
1434 if (!C1XOptions.OptInline) { | |
1435 return false; // all inlining is turned off | |
1436 } | |
1437 if (!target.isResolved()) { | |
1438 return cannotInline(target, "unresolved method"); | |
1439 } | |
1440 if (target.code() == null) { | |
1441 return cannotInline(target, "method has no code"); | |
1442 } | |
1443 if (!target.holder().isInitialized()) { | |
1444 return cannotInline(target, "holder is not initialized"); | |
1445 } | |
1446 if (recursiveInlineLevel(target) > C1XOptions.MaximumRecursiveInlineLevel) { | |
1447 return cannotInline(target, "recursive inlining too deep"); | |
1448 } | |
1449 if (target.code().length > scopeData.maxInlineSize()) { | |
1450 return cannotInline(target, "inlinee too large for this level"); | |
1451 } | |
1452 if (scopeData.scope.level + 1 > C1XOptions.MaximumInlineLevel) { | |
1453 return cannotInline(target, "inlining too deep"); | |
1454 } | |
1455 if (stats.nodeCount > C1XOptions.MaximumDesiredSize) { | |
1456 return cannotInline(target, "compilation already too big " + "(" + compilation.stats.nodeCount + " nodes)"); | |
1457 } | |
1458 if (compilation.runtime.mustNotInline(target)) { | |
1459 C1XMetrics.InlineForbiddenMethods++; | |
1460 return cannotInline(target, "inlining excluded by runtime"); | |
1461 } | |
1462 if (compilation.runtime.mustNotCompile(target)) { | |
1463 return cannotInline(target, "compile excluded by runtime"); | |
1464 } | |
1465 if (isSynchronized(target.accessFlags())) { | |
1466 return cannotInline(target, "is synchronized"); | |
1467 } | |
1468 if (target.exceptionHandlers().length != 0) { | |
1469 return cannotInline(target, "has exception handlers"); | |
1470 } | |
1471 if (!target.hasBalancedMonitors()) { | |
1472 return cannotInline(target, "has unbalanced monitors"); | |
1473 } | |
1474 if (target.isConstructor()) { | |
1475 if (compilation.runtime.isExceptionType(target.holder())) { | |
1476 // don't inline constructors of throwable classes unless the inlining tree is | |
1477 // rooted in a throwable class | |
1478 if (!compilation.runtime.isExceptionType(rootScope().method.holder())) { | |
1479 return cannotInline(target, "don't inline Throwable constructors"); | |
1480 } | |
1481 } | |
1482 } | |
1483 return true; | |
1484 } | |
1485 | |
1486 private boolean cannotInline(RiMethod target, String reason) { | |
1487 if (C1XOptions.PrintInliningFailures) { | |
1488 TTY.println("Cannot inline " + target.toString() + " into " + compilation.method.toString() + " because of " + reason); | |
1489 } | |
1490 return false; | |
1491 } | |
1492 | |
1493 private void inline(RiMethod target, Value[] args, boolean forcedInline) { | |
1494 BlockBegin orig = curBlock; | |
1495 if (!forcedInline && !isStatic(target.accessFlags())) { | |
1496 // the receiver object must be null-checked for instance methods | |
1497 Value receiver = args[0]; | |
1498 if (!receiver.isNonNull() && !receiver.kind.isWord()) { | |
1499 NullCheck check = new NullCheck(receiver, null); | |
1500 args[0] = append(check); | |
1501 } | |
1502 } | |
1503 | |
1504 // Introduce a new callee continuation point. All return instructions | |
1505 // in the callee will be transformed to Goto's to the continuation | |
1506 BlockBegin continuationBlock = blockAtOrNull(nextBCI()); | |
1507 boolean continuationExisted = true; | |
1508 if (continuationBlock == null) { | |
1509 // there was not already a block starting at the next BCI | |
1510 continuationBlock = new BlockBegin(nextBCI(), ir.nextBlockNumber()); | |
1511 continuationBlock.setDepthFirstNumber(0); | |
1512 continuationExisted = false; | |
1513 } | |
1514 // record the number of predecessors before inlining, to determine | |
1515 // whether the inlined method has added edges to the continuation | |
1516 int continuationPredecessors = continuationBlock.predecessors().size(); | |
1517 | |
1518 // push the target scope | |
1519 pushScope(target, continuationBlock); | |
1520 | |
1521 // pass parameters into the callee state | |
1522 FrameState calleeState = curState; | |
1523 for (int i = 0; i < args.length; i++) { | |
1524 Value arg = args[i]; | |
1525 if (arg != null) { | |
1526 calleeState.storeLocal(i, arg); | |
1527 } | |
1528 } | |
1529 | |
1530 // setup state that is used at returns from the inlined method. | |
1531 // this is essentially the state of the continuation block, | |
1532 // but without the return value on the stack. | |
1533 scopeData.setContinuationState(scope().callerState); | |
1534 | |
1535 Value lock = null; | |
1536 BlockBegin syncHandler = null; | |
1537 // inline the locking code if the target method is synchronized | |
1538 if (Modifier.isSynchronized(target.accessFlags())) { | |
1539 // lock the receiver object if it is an instance method, the class object otherwise | |
1540 lock = synchronizedObject(curState, target); | |
1541 syncHandler = new BlockBegin(Instruction.SYNCHRONIZATION_ENTRY_BCI, ir.nextBlockNumber()); | |
1542 syncHandler.setNext(null, -1); | |
1543 inlineSyncEntry(lock, syncHandler); | |
1544 } | |
1545 | |
1546 BlockBegin calleeStartBlock = blockAt(0); | |
1547 if (calleeStartBlock.isParserLoopHeader()) { | |
1548 // the block is a loop header, so we have to insert a goto | |
1549 Goto gotoCallee = new Goto(calleeStartBlock, null, false); | |
1550 gotoCallee.setStateAfter(curState.immutableCopy(bci())); | |
1551 appendWithoutOptimization(gotoCallee, 0); | |
1552 curBlock.setEnd(gotoCallee); | |
1553 calleeStartBlock.mergeOrClone(calleeState); | |
1554 lastInstr = curBlock = calleeStartBlock; | |
1555 scopeData.addToWorkList(calleeStartBlock); | |
1556 // now iterate over all the blocks | |
1557 iterateAllBlocks(); | |
1558 } else { | |
1559 // ready to resume parsing inlined method into this block | |
1560 iterateBytecodesForBlock(0, true); | |
1561 // now iterate over the rest of the blocks | |
1562 iterateAllBlocks(); | |
1563 } | |
1564 | |
1565 assert continuationExisted || !continuationBlock.wasVisited() : "continuation should not have been parsed if we created it"; | |
1566 | |
1567 ReturnBlock simpleInlineInfo = scopeData.simpleInlineInfo(); | |
1568 if (simpleInlineInfo != null && curBlock == orig) { | |
1569 // Optimization: during parsing of the callee we | |
1570 // generated at least one Goto to the continuation block. If we | |
1571 // generated exactly one, and if the inlined method spanned exactly | |
1572 // one block (and we didn't have to Goto its entry), then we snip | |
1573 // off the Goto to the continuation, allowing control to fall | |
1574 // through back into the caller block and effectively performing | |
1575 // block merging. This allows local load elimination and local value numbering | |
1576 // to take place across multiple callee scopes if they are relatively simple, and | |
1577 // is currently essential to making inlining profitable. It also reduces the | |
1578 // number of blocks in the CFG | |
1579 lastInstr = simpleInlineInfo.returnPredecessor; | |
1580 curState = simpleInlineInfo.returnState.popScope(); | |
1581 lastInstr.setNext(null, -1); | |
1582 } else if (continuationPredecessors == continuationBlock.predecessors().size()) { | |
1583 // Inlining caused the instructions after the invoke in the | |
1584 // caller to not reachable any more (i.e. no control flow path | |
1585 // in the callee was terminated by a return instruction). | |
1586 // So skip filling this block with instructions! | |
1587 assert continuationBlock == scopeData.continuation(); | |
1588 assert lastInstr instanceof BlockEnd; | |
1589 skipBlock = true; | |
1590 } else { | |
1591 // Resume parsing in continuation block unless it was already parsed. | |
1592 // Note that if we don't change lastInstr here, iteration in | |
1593 // iterateBytecodesForBlock will stop when we return. | |
1594 if (!scopeData.continuation().wasVisited()) { | |
1595 // add continuation to work list instead of parsing it immediately | |
1596 assert lastInstr instanceof BlockEnd; | |
1597 scopeData.parent.addToWorkList(scopeData.continuation()); | |
1598 skipBlock = true; | |
1599 } | |
1600 } | |
1601 | |
1602 // fill the exception handler for synchronized methods with instructions | |
1603 if (syncHandler != null && syncHandler.stateBefore() != null) { | |
1604 // generate unlocking code if the exception handler is reachable | |
1605 fillSyncHandler(lock, syncHandler, true); | |
1606 } else { | |
1607 popScope(); | |
1608 } | |
1609 | |
1610 stats.inlineCount++; | |
1611 } | |
1612 | |
1613 private Value synchronizedObject(FrameState curState2, RiMethod target) { | 1376 private Value synchronizedObject(FrameState curState2, RiMethod target) { |
1614 if (isStatic(target.accessFlags())) { | 1377 if (isStatic(target.accessFlags())) { |
1615 Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass)); | 1378 Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass)); |
1616 return appendWithoutOptimization(classConstant, Instruction.SYNCHRONIZATION_ENTRY_BCI); | 1379 return appendWithoutOptimization(classConstant, Instruction.SYNCHRONIZATION_ENTRY_BCI); |
1617 } else { | 1380 } else { |
1618 return curState2.localAt(0); | 1381 return curState2.localAt(0); |
1619 } | 1382 } |
1620 } | 1383 } |
1621 | 1384 |
1622 private void inlineSyncEntry(Value lock, BlockBegin syncHandler) { | |
1623 genMonitorEnter(lock, Instruction.SYNCHRONIZATION_ENTRY_BCI); | |
1624 syncHandler.setExceptionEntry(); | |
1625 syncHandler.setBlockFlag(BlockBegin.BlockFlag.IsOnWorkList); | |
1626 ExceptionHandler handler = new ExceptionHandler(new CiExceptionHandler(0, method().code().length, -1, 0, null)); | |
1627 handler.setEntryBlock(syncHandler); | |
1628 scopeData.addExceptionHandler(handler); | |
1629 } | |
1630 | |
1631 private void fillSyncHandler(Value lock, BlockBegin syncHandler, boolean inlinedMethod) { | 1385 private void fillSyncHandler(Value lock, BlockBegin syncHandler, boolean inlinedMethod) { |
1632 BlockBegin origBlock = curBlock; | 1386 BlockBegin origBlock = curBlock; |
1633 MutableFrameState origState = curState; | 1387 MutableFrameState origState = curState; |
1634 Instruction origLast = lastInstr; | 1388 Instruction origLast = lastInstr; |
1635 | 1389 |
1651 lock = appendWithoutOptimization(l, Instruction.SYNCHRONIZATION_ENTRY_BCI); | 1405 lock = appendWithoutOptimization(l, Instruction.SYNCHRONIZATION_ENTRY_BCI); |
1652 } | 1406 } |
1653 } | 1407 } |
1654 // exit the monitor | 1408 // exit the monitor |
1655 genMonitorExit(lock, Instruction.SYNCHRONIZATION_ENTRY_BCI); | 1409 genMonitorExit(lock, Instruction.SYNCHRONIZATION_ENTRY_BCI); |
1656 | |
1657 // exit the context of the synchronized method | |
1658 if (inlinedMethod) { | |
1659 popScope(); | |
1660 bci = curState.scope().callerBCI(); | |
1661 curState = curState.popScope(); | |
1662 } | |
1663 | 1410 |
1664 apush(exception); | 1411 apush(exception); |
1665 genThrow(bci); | 1412 genThrow(bci); |
1666 BlockEnd end = (BlockEnd) lastInstr; | 1413 BlockEnd end = (BlockEnd) lastInstr; |
1667 curBlock.setEnd(end); | 1414 curBlock.setEnd(end); |
1685 b.setNext(null, -1); | 1432 b.setNext(null, -1); |
1686 | 1433 |
1687 iterateBytecodesForBlock(b.bci(), false); | 1434 iterateBytecodesForBlock(b.bci(), false); |
1688 } | 1435 } |
1689 } | 1436 } |
1690 } | |
1691 | |
1692 private void popScope() { | |
1693 int maxLocks = scope().maxLocks(); | |
1694 scopeData = scopeData.parent; | |
1695 scope().updateMaxLocks(maxLocks); | |
1696 } | 1437 } |
1697 | 1438 |
1698 private void popScopeForJsr() { | 1439 private void popScopeForJsr() { |
1699 scopeData = scopeData.parent; | 1440 scopeData = scopeData.parent; |
1700 } | 1441 } |
2082 } | 1823 } |
2083 } | 1824 } |
2084 return null; | 1825 return null; |
2085 } | 1826 } |
2086 | 1827 |
2087 private int recursiveInlineLevel(RiMethod target) { | |
2088 int rec = 0; | |
2089 IRScope scope = scope(); | |
2090 while (scope != null) { | |
2091 if (scope.method != target) { | |
2092 break; | |
2093 } | |
2094 scope = scope.caller; | |
2095 rec++; | |
2096 } | |
2097 return rec; | |
2098 } | |
2099 | |
2100 private RiConstantPool constantPool() { | 1828 private RiConstantPool constantPool() { |
2101 return scopeData.constantPool; | 1829 return scopeData.constantPool; |
2102 } | 1830 } |
2103 } | 1831 } |