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 }