# HG changeset patch # User Thomas Wuerthinger # Date 1338561125 -7200 # Node ID c9b8994b43d85393e25e0db7520cf684c2ea6fd4 # Parent 044502e7b5a444b056037d6c4ecc7d4efa399ceb# Parent 174eb2b7f6bafaf78433dd84bdc3b43826328389 Merge. diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Jun 01 16:32:05 2012 +0200 @@ -352,9 +352,20 @@ for (Block pred : block.getPredecessors()) { if (fs == null) { fs = blockLastState.get(pred); - } else if (fs != blockLastState.get(pred)) { - fs = null; - break; + } else { + if (blockLastState.get(pred) == null) { + // Only a back edge can have a null state for its enclosing block. + assert pred.getEndNode() instanceof LoopEndNode; + + if (block.getBeginNode().stateAfter() == null) { + // We'll assert later that the begin and end of a framestate-less loop + // share the frame state that flowed into the loop + blockLastState.put(pred, fs); + } + } else if (fs != blockLastState.get(pred)) { + fs = null; + break; + } } } if (GraalOptions.TraceLIRGeneratorLevel >= 2) { @@ -433,6 +444,10 @@ TTY.println("END Generating LIR for block B" + block.getId()); } + // Check that the begin and end of a framestate-less loop + // share the frame state that flowed into the loop + assert blockLastState.get(block) == null || blockLastState.get(block) == lastState; + blockLocks.put(currentBlock, curLocks); blockLastState.put(block, lastState); currentBlock = null; @@ -707,16 +722,24 @@ } private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { - emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info); - if (trueSuccessor != null) { - emitJump(trueSuccessor, null); + if (falseSuccessor != null) { + emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info); + if (trueSuccessor != null) { + emitJump(trueSuccessor, null); + } + } else { + emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, info); } } public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) { - emitBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info); - if (trueSuccessorBlock != null) { - emitJump(trueSuccessorBlock, null); + if (falseSuccessorBlock != null) { + emitBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info); + if (trueSuccessorBlock != null) { + emitJump(trueSuccessorBlock, null); + } + } else { + emitBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessorBlock, info); } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java Fri Jun 01 16:32:05 2012 +0200 @@ -35,7 +35,7 @@ } public static void peel(Loop loop, SuperBlock wholeLoop) { - SuperBlock peel = wholeLoop.duplicate(); // duplicates the nodes, merges early exits + SuperBlock peel = wholeLoop.duplicate(true); // duplicates the nodes, merges early exits peel.insertBefore(loop.loopBegin().forwardEnd()); // connects peeled part's CFG @@ -43,7 +43,7 @@ resolver.wholeLoop(wholeLoop).peeled(peel); // block (comming from the loop) was peeled into peel resolver.resolve(); - peel.finish(); + peel.finishDuplication(); } public static SuperBlock wholeLoop(Loop loop) { diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java Fri Jun 01 16:32:05 2012 +0200 @@ -38,7 +38,8 @@ protected List earlyExits; protected Map duplicationMapping; protected SuperBlock original; - protected NodeBitMap loopNodes; + protected NodeBitMap allNodes; + protected NodeBitMap allNodesExcludeLoopPhi; public SuperBlock(BeginNode entry, BeginNode exit, List blocks, List earlyExits) { this.entry = entry; @@ -57,31 +58,45 @@ return entry; } - public NodeBitMap loopNodes() { - if (loopNodes == null) { - loopNodes = computeNodes(); + public NodeBitMap nodes() { + if (allNodes == null) { + allNodes = computeNodes(); } - return loopNodes; + return allNodes; + } + + private NodeBitMap nodesExcludeLoopPhi() { + if (allNodesExcludeLoopPhi == null) { + allNodesExcludeLoopPhi = nodes().copy(); + if (entry instanceof LoopBeginNode) { + for (PhiNode phi : ((LoopBeginNode) entry).phis()) { + allNodesExcludeLoopPhi.clear(phi); + } + } + } + return allNodesExcludeLoopPhi; } public SuperBlock duplicate() { - NodeBitMap nodes = loopNodes(); + return duplicate(false); + } + + public SuperBlock duplicate(boolean excludeLoop) { + NodeBitMap nodes = nodes(); Map replacements = new HashMap<>(); StructuredGraph graph = (StructuredGraph) entry.graph(); - BeginNode newEntry = graph.add(new BeginNode()); - BeginNode newExit = null; + if (excludeLoop || (entry instanceof MergeNode && !(entry instanceof LoopBeginNode))) { + replacements.put(entry, graph.add(new BeginNode())); // no merge/loop begin + } List newEarlyExits = new ArrayList<>(earlyExits.size()); - if (!(exit instanceof MergeNode)) { - newExit = graph.add(new BeginNode()); - replacements.put(exit, newExit); - } - replacements.put(entry, newEntry); // no merge/loop begin for (BeginNode earlyExit : earlyExits) { BeginNode newEarlyExit = graph.add(new BeginNode()); newEarlyExits.add(newEarlyExit); replacements.put(earlyExit, newEarlyExit); } - if (exit instanceof LoopBeginNode) { + if (exit instanceof LoopBeginNode && excludeLoop) { + assert entry == exit; + nodes = nodesExcludeLoopPhi(); for (LoopEndNode end : ((LoopBeginNode) exit).loopEnds()) { if (nodes.isMarked(end)) { replacements.put(end, graph.add(new EndNode())); @@ -89,8 +104,14 @@ } } Map duplicates = graph.addDuplicates(nodes, replacements); - if (exit instanceof MergeNode) { + BeginNode newExit; + if (excludeLoop || (exit instanceof MergeNode && !(exit instanceof LoopBeginNode))) { newExit = mergeExits(replacements, duplicates); + } else if (exit != entry) { + newExit = graph.add(new BeginNode()); + replacements.put(exit, newExit); + } else { + newExit = (BeginNode) duplicates.get(exit); } List newBlocks = new ArrayList<>(blocks.size()); @@ -105,7 +126,7 @@ for (Entry e : replacements.entrySet()) { duplicates.put(e.getKey(), e.getValue()); } - SuperBlock superBlock = new SuperBlock(newEntry, newExit, newBlocks, newEarlyExits); + SuperBlock superBlock = new SuperBlock((BeginNode) duplicates.get(entry), newExit, newBlocks, newEarlyExits); superBlock.duplicationMapping = duplicates; superBlock.original = this; return superBlock; @@ -163,7 +184,7 @@ return newExit; } - public void finish() { + public void finishDuplication() { if (original != null) { mergeEarlyExits((StructuredGraph) entry.graph(), original.earlyExits, duplicationMapping); } @@ -376,12 +397,6 @@ } } - if (entry instanceof LoopBeginNode) { - for (PhiNode phi : ((LoopBeginNode) entry).phis()) { - nodes.clear(phi); - } - } - return nodes; } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java Fri Jun 01 16:32:05 2012 +0200 @@ -120,12 +120,23 @@ if (folding || CiUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { assert argument instanceof ConstantNode : "parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.callTarget().targetMethod() + ": " + argument; ConstantNode constantNode = (ConstantNode) argument; - Object o = constantNode.asConstant().boxedValue(); + CiConstant constant = constantNode.asConstant(); + Object o = constant.boxedValue(); if (o instanceof Class< ? >) { reflectionCallArguments[i] = runtime.getType((Class< ? >) o); parameterTypes[i] = RiResolvedType.class; } else { - reflectionCallArguments[i] = o; + if (parameterTypes[i] == boolean.class) { + reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); + } else if (parameterTypes[i] == byte.class) { + reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); + } else if (parameterTypes[i] == short.class) { + reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); + } else if (parameterTypes[i] == char.class) { + reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); + } else { + reflectionCallArguments[i] = o; + } } } else { reflectionCallArguments[i] = argument; @@ -186,7 +197,6 @@ } private static Node createNodeInstance(Class< ? > nodeClass, Class< ? >[] parameterTypes, Object[] nodeConstructorArguments) { - Constructor< ? > constructor; try { constructor = nodeClass.getDeclaredConstructor(parameterTypes); @@ -197,7 +207,7 @@ try { return (ValueNode) constructor.newInstance(nodeConstructorArguments); } catch (Exception e) { - throw new RuntimeException(e); + throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Fri Jun 01 16:32:05 2012 +0200 @@ -36,9 +36,13 @@ } public NodeBitMap(Graph graph, boolean autoGrow) { + this(graph, autoGrow, new BitMap(graph.nodeIdCount())); + } + + private NodeBitMap(Graph graph, boolean autoGrow, BitMap bits) { this.graph = graph; this.autoGrow = autoGrow; - bitMap = new BitMap(graph.nodeIdCount()); + bitMap = bits; } public Graph graph() { @@ -178,4 +182,8 @@ public int cardinality() { return bitMap.cardinality(); } + + public NodeBitMap copy() { + return new NodeBitMap(graph, autoGrow, bitMap.copy()); + } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri Jun 01 16:32:05 2012 +0200 @@ -47,6 +47,9 @@ public int vmPageSize; public int stackShadowPages; public int hubOffset; + public int superCheckOffsetOffset; + public int secondarySuperCacheOffset; + public int secondarySupersOffset; public int arrayLengthOffset; public int klassStateOffset; public int klassStateFullyInitialized; diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Fri Jun 01 16:32:05 2012 +0200 @@ -28,16 +28,13 @@ import java.util.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.cri.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.Compiler; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.snippets.*; -import com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter; import com.oracle.graal.hotspot.target.amd64.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -342,15 +339,13 @@ } else if (n instanceof UnsafeLoadNode) { UnsafeLoadNode load = (UnsafeLoadNode) n; assert load.kind() != CiKind.Illegal; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph); - location.setIndexScalingEnabled(false); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph, false); ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID)); graph.replaceFixedWithFixed(load, memoryRead); } else if (n instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) n; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph); - location.setIndexScalingEnabled(false); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph, false); WriteNode write = graph.add(new WriteNode(store.object(), store.value(), location)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); @@ -366,31 +361,7 @@ graph.replaceFixed(objectClassNode, memoryRead); } else if (n instanceof CheckCastNode) { if (shouldLowerCheckcast(graph)) { - CheckCastNode checkcast = (CheckCastNode) n; - ValueNode hub = checkcast.targetClassInstruction(); - ValueNode object = checkcast.object(); - TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); - HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; - for (int i = 0; i < hintHubs.length; i++) { - hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop(); - } - Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact); - - final Counter noHintsCounter; - if (GraalOptions.CheckcastCounters) { - if (checkcast.targetClass() == null) { - noHintsCounter = Counter.noHints_unknown; - } else if (checkcast.targetClass().isInterface()) { - noHintsCounter = Counter.noHints_iface; - } else { - noHintsCounter = Counter.noHints_class; - } - } else { - noHintsCounter = null; - } - boolean checkNull = !object.stamp().nonNull(); - checkcasts.get(hintHubs.length, hints.exact, checkNull, noHintsCounter).instantiate(this, checkcast, checkcast, hub, object, hintHubs, noHintsCounter); - new DeadCodeEliminationPhase().apply(graph); + checkcasts.lower((CheckCastNode) n, tool); } } else { assert false : "Node implementing Lowerable not handled: " + n; @@ -410,7 +381,7 @@ } private IndexedLocationNode createArrayLocation(Graph graph, CiKind elementKind, ValueNode index) { - return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph); + return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph, true); } private SafeReadNode safeReadArrayLength(ValueNode array, long leafGraphId) { @@ -445,7 +416,7 @@ StructuredGraph graph = new StructuredGraph(); LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull())); SafeReadNode klassOop = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID); - Stamp resultStamp = StampFactory.declared(getType(Class.class)); + Stamp resultStamp = StampFactory.declaredNonNull(getType(Class.class)); FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.classMirrorOffset, graph), null, resultStamp)); ReturnNode ret = graph.add(new ReturnNode(result)); graph.start().setNext(klassOop); diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotTypeResolvedImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotTypeResolvedImpl.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotTypeResolvedImpl.java Fri Jun 01 16:32:05 2012 +0200 @@ -26,6 +26,7 @@ import java.lang.reflect.*; import java.util.*; +import com.oracle.graal.hotspot.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; @@ -42,6 +43,7 @@ private boolean hasFinalizer; private boolean hasSubclass; private boolean hasFinalizableSubclass; + private int superCheckOffset; private boolean isArrayClass; private boolean isInstanceClass; private boolean isInterface; @@ -264,7 +266,7 @@ return this; } - // (dnsimon) this value may require identity semantics + // this value may require identity semantics so cache it private HotSpotKlassOop klassOopCache; @Override @@ -274,4 +276,14 @@ } return klassOopCache; } + + private static final int SECONDARY_SUPER_CACHE_OFFSET = CompilerImpl.getInstance().getConfig().secondarySuperCacheOffset; + + public boolean isPrimaryType() { + return SECONDARY_SUPER_CACHE_OFFSET != superCheckOffset; + } + + public int superCheckOffset() { + return superCheckOffset; + } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Fri Jun 01 16:32:05 2012 +0200 @@ -221,18 +221,19 @@ if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > src.length || destPos + length > dest.length) { throw new IndexOutOfBoundsException(); } + final int scale = arrayIndexScale(CiKind.Object); if (src == dest && srcPos < destPos) { // bad aliased case - copyObjectsDown(src, srcPos * 8L, dest, destPos * 8L, length); + copyObjectsDown(src, srcPos * scale, dest, destPos * scale, length); } else { - copyObjectsUp(src, srcPos * 8L, dest, destPos * 8L, length); + copyObjectsUp(src, srcPos * scale, dest, destPos * scale, length); } if (length > 0) { - int header = arrayHeaderSizeFor(CiKind.Object); + int header = arrayBaseOffset(CiKind.Object); int cardShift = cardTableShift(); long cardStart = cardTableStart(); long dstAddr = GetObjectAddressNode.get(dest); - long start = (dstAddr + header + destPos * 8L) >>> cardShift; - long end = (dstAddr + header + (destPos + length - 1) * 8L) >>> cardShift; + long start = (dstAddr + header + destPos * scale) >>> cardShift; + long end = (dstAddr + header + (destPos + length - 1) * scale) >>> cardShift; long count = end - start + 1; while (count-- > 0) { DirectStoreNode.store((start + cardStart) + count, false); @@ -242,7 +243,7 @@ @Snippet public static void copyBytesDown(Object src, int srcPos, Object dest, int destPos, int length) { - int header = arrayHeaderSizeFor(CiKind.Byte); + int header = arrayBaseOffset(CiKind.Byte); for (long i = length - 1; i >= 0; i--) { Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte); UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte); @@ -251,7 +252,7 @@ @Snippet public static void copyShortsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Short); + int header = arrayBaseOffset(CiKind.Short); for (long i = (length - 1) * 2; i >= 0; i -= 2) { Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short); UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short); @@ -260,7 +261,7 @@ @Snippet public static void copyIntsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Int); + int header = arrayBaseOffset(CiKind.Int); for (long i = (length - 1) * 4; i >= 0; i -= 4) { Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int); UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int); @@ -269,7 +270,7 @@ @Snippet public static void copyLongsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Long); + int header = arrayBaseOffset(CiKind.Long); for (long i = (length - 1) * 8; i >= 0; i -= 8) { Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long); UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long); @@ -279,8 +280,9 @@ // Does NOT perform store checks @Snippet public static void copyObjectsDown(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Object); - for (long i = (length - 1) * wordSize(); i >= 0; i -= wordSize()) { + int header = arrayBaseOffset(CiKind.Object); + final int scale = arrayIndexScale(CiKind.Object); + for (long i = (length - 1) * scale; i >= 0; i -= scale) { Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object); DirectObjectStoreNode.store(dest, header, i + destOffset, a); } @@ -295,7 +297,7 @@ */ @Snippet public static void copyBytesUp(Object src, int srcPos, Object dest, int destPos, int length) { - int header = arrayHeaderSizeFor(CiKind.Byte); + int header = arrayBaseOffset(CiKind.Byte); for (long i = 0; i < length; i++) { Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte); UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte); @@ -312,7 +314,7 @@ */ @Snippet public static void copyShortsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Short); + int header = arrayBaseOffset(CiKind.Short); for (long i = 0; i < length * 2L; i += 2) { Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short); UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short); @@ -321,7 +323,7 @@ @Snippet public static void copyIntsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Int); + int header = arrayBaseOffset(CiKind.Int); for (long i = 0; i < length * 4L; i += 4) { Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int); UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int); @@ -330,7 +332,7 @@ @Snippet public static void copyLongsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Long); + int header = arrayBaseOffset(CiKind.Long); for (long i = 0; i < length * 8L; i += 8) { Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long); UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long); @@ -340,20 +342,33 @@ // Does NOT perform store checks @Snippet public static void copyObjectsUp(Object src, long srcOffset, Object dest, long destOffset, int length) { - int header = arrayHeaderSizeFor(CiKind.Object); - for (long i = 0; i < length * wordSize(); i += wordSize()) { + int header = arrayBaseOffset(CiKind.Object); + final int scale = arrayIndexScale(CiKind.Object); + for (long i = 0; i < length * scale; i += scale) { Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object); DirectObjectStoreNode.store(dest, header, i + destOffset, a); } } + @Fold - private static int wordSize() { - return CompilerImpl.getInstance().getTarget().wordSize; + static int arrayBaseOffset(CiKind elementKind) { + return elementKind.arrayBaseOffset(); } @Fold - static int arrayHeaderSizeFor(CiKind elementKind) { - return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind); + static int arrayIndexScale(CiKind elementKind) { + return elementKind.arrayIndexScale(); + } + + static { + assert arrayIndexScale(CiKind.Byte) == 1; + assert arrayIndexScale(CiKind.Boolean) == 1; + assert arrayIndexScale(CiKind.Char) == 2; + assert arrayIndexScale(CiKind.Short) == 2; + assert arrayIndexScale(CiKind.Int) == 4; + assert arrayIndexScale(CiKind.Long) == 8; + assert arrayIndexScale(CiKind.Float) == 4; + assert arrayIndexScale(CiKind.Double) == 8; } @Fold diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri Jun 01 16:32:05 2012 +0200 @@ -21,7 +21,9 @@ * questions. */ package com.oracle.graal.hotspot.snippets; +import static com.oracle.graal.hotspot.snippets.ArrayCopySnippets.*; import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*; +import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.TemplateFlag.*; import static com.oracle.graal.snippets.SnippetTemplate.*; import java.io.*; @@ -31,53 +33,173 @@ import sun.misc.*; import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Fold; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.ri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; /** - * Snippets used for lowering {@link CheckCastNode}s. + * Snippets used for implementing the type test of a checkcast instruction. + * + * The test first checks against the profiled types (if any) and then implements the + * checks described in paper + * Fast subtype checking in the HotSpot JVM by Cliff Click and John Rose. */ public class CheckCastSnippets implements SnippetsInterface { /** - * Checks that a given object is null or is a subtype of a given type. - * - * @param hub the hub of the type being checked against - * @param object the object whose type is being checked against {@code hub} - * @param hintHubs the hubs of objects that have been profiled during previous executions - * @param hintsAreExact specifies if {@code hintHubs} contains all subtypes of {@code hub} - * @param checkNull specifies if {@code object} may be null - * @return {@code object} if the type check succeeds - * @throws ClassCastException if the type check fails + * Type test used when the type being tested against is a restricted primary type. */ @Snippet - public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) { - if (object == null) { + public static Object checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset) { + if (checkNull && object == null) { return object; } - Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object); + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hintHubs.length; i++) { + Object hintHub = hintHubs[i]; + if (hintHub == objectHub) { + return object; + } + } + if (hintsAreExact) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } else { + if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } + } + return object; + } + + /** + * Type test used when the type being tested against is a restricted secondary type. + */ + @Snippet + public static Object checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) { + if (checkNull && object == null) { + return object; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); for (int i = 0; i < hintHubs.length; i++) { Object hintHub = hintHubs[i]; if (hintHub == objectHub) { return object; } } - if (hintsAreExact || !TypeCheckSlowPath.check(objectHub, hub)) { + if (hintsAreExact) { DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } else { + if (!checkSecondarySubType(hub, objectHub)) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } + } + return object; + } + + /** + * Type test used when the type being tested against is not known at compile time (e.g. the type test + * in an object array store check). + */ + @Snippet + public static Object checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) { + if (checkNull && object == null) { + return object; + } + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hintHubs.length; i++) { + Object hintHub = hintHubs[i]; + if (hintHub == objectHub) { + return object; + } + } + if (hintsAreExact) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } else { + if (!checkUnknownSubType(hub, objectHub)) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } } return object; } + //This is used instead of a Java array read to avoid the array bounds check. + static Object loadNonNullObjectElement(Object array, int index) { + return UnsafeLoadNode.loadObject(array, arrayBaseOffset(CiKind.Object), index * arrayIndexScale(CiKind.Object), true); + } + + static boolean checkSecondarySubType(Object t, Object s) { + // if (S.cache == T) return true + if (UnsafeLoadNode.loadObject(s, 0, secondarySuperCacheOffset(), true) == t) { + return true; + } + + // if (T == S) return true + if (s == t) { + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class); + + for (int i = 0; i < secondarySupers.length; i++) { + if (t == loadNonNullObjectElement(secondarySupers, i)) { + DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t); + return true; + } + } + + return false; + } + + static boolean checkUnknownSubType(Object t, Object s) { + // int off = T.offset + int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), CiKind.Int); + + // if (T = S[off]) return true + if (UnsafeLoadNode.loadObject(s, 0, superCheckOffset, true) == t) { + return true; + } + + // if (off != &cache) return false + if (superCheckOffset != secondarySuperCacheOffset()) { + return false; + } + + // if (T == S) return true + if (s == t) { + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Object[] secondarySupers = UnsafeCastNode.cast(UnsafeLoadNode.loadObject(s, 0, secondarySupersOffset(), true), Object[].class); + for (int i = 0; i < secondarySupers.length; i++) { + if (t == loadNonNullObjectElement(secondarySupers, i)) { + DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t); + return true; + } + } + + return false; + } + /** * Counters for the various code paths through a type check. */ @@ -85,9 +207,7 @@ hintsHit("hit a hint type"), hintsMissed("missed the hint types"), exact("tested type is (statically) final"), - noHints_class("profile information is not used (test type is a class)"), - noHints_iface("profile information is not used (test type is an interface)"), - noHints_unknown("test type is not a compile-time constant"), + noHints("profile information is not used"), isNull("object tested is null"), exception("type test failed with a ClassCastException"); @@ -124,21 +244,25 @@ static final boolean ENABLED = GraalOptions.CheckcastCounters; } + /** + * Type test used when {@link GraalOptions#CheckcastCounters} is enabled. + */ @Snippet - public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) { + public static Object checkcastCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) { if (object == null) { isNull.inc(); return object; } - Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object); + Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true); if (hintHubs.length == 0) { - noHintsCounter.inc(); - if (!TypeCheckSlowPath.check(objectHub, hub)) { + noHints.inc(); + if (!checkUnknownSubType(hub, objectHub)) { exception.inc(); DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); } } else { // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); for (int i = 0; i < hintHubs.length; i++) { Object hintHub = hintHubs[i]; if (hintHub == objectHub) { @@ -151,7 +275,7 @@ } } if (!hintsAreExact) { - if (!TypeCheckSlowPath.check(objectHub, hub)) { + if (!checkUnknownSubType(hub, objectHub)) { exception.inc(); DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); } else { @@ -166,6 +290,21 @@ } @Fold + private static int superCheckOffsetOffset() { + return CompilerImpl.getInstance().getConfig().superCheckOffsetOffset; + } + + @Fold + private static int secondarySuperCacheOffset() { + return CompilerImpl.getInstance().getConfig().secondarySuperCacheOffset; + } + + @Fold + private static int secondarySupersOffset() { + return CompilerImpl.getInstance().getConfig().secondarySupersOffset; + } + + @Fold private static int hubOffset() { return CompilerImpl.getInstance().getConfig().hubOffset; } @@ -205,54 +344,148 @@ } } + public enum TemplateFlag { + CHECK_NULL, + EXACT_HINTS, + COUNTERS, + PRIMARY_SUPER, + SECONDARY_SUPER, + UNKNOWN_SUPER; + + public int bit(boolean value) { + if (value) { + return bit(); + } + return 0; + } + + public boolean bool(int flags) { + return (flags & bit()) != 0; + } + + static final int FLAGS_BITS = values().length; + static final int FLAGS_MASK = (1 << FLAGS_BITS) - 1; + + static final int NHINTS_SHIFT = FLAGS_BITS; + static final int NHINTS_BITS = 3; + static final int SUPER_CHECK_OFFSET_SHIFT = NHINTS_SHIFT + NHINTS_BITS; + + public int bit() { + return 1 << ordinal(); + } + } + /** * Templates for partially specialized checkcast snippet graphs. */ public static class Templates { private final ConcurrentHashMap templates; - private final RiResolvedMethod method; + private final RiResolvedMethod counters; + private final RiResolvedMethod primary; + private final RiResolvedMethod secondary; + private final RiResolvedMethod unknown; private final RiRuntime runtime; public Templates(RiRuntime runtime) { this.runtime = runtime; this.templates = new ConcurrentHashMap<>(); try { - Class[] parameterTypes = {Object.class, Object.class, Object[].class, boolean.class, boolean.class, Counter.class}; - String name = GraalOptions.CheckcastCounters ? "checkcastWithCounters" : "checkcast"; - method = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod(name, parameterTypes)); + primary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, Object[].class, boolean.class, boolean.class, int.class)); + secondary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class, boolean.class)); + unknown = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class, boolean.class)); + counters = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastCounters", Object.class, Object.class, Object[].class, boolean.class)); } catch (NoSuchMethodException e) { throw new GraalInternalError(e); } } /** - * Gets a checkcast snippet specialized for a given set of inputs. + * Interface for lazily creating a snippet template. */ - public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) { - Integer key = key(nHints, isExact, checkNull); + abstract static class Factory { + abstract SnippetTemplate create(HotSpotKlassOop[] hints, int flags); + } + + /** + * Gets a template from the template cache, creating and installing it first if necessary. + */ + private SnippetTemplate getTemplate(int nHints, int flags, int superCheckOffset, Factory factory) { + assert (flags & ~FLAGS_MASK) == 0; + assert nHints >= 0 && nHints < (1 << NHINTS_BITS) - 1 : "nHints out of range"; + assert superCheckOffset >= 0 && superCheckOffset == ((superCheckOffset << SUPER_CHECK_OFFSET_SHIFT) >>> SUPER_CHECK_OFFSET_SHIFT) : "superCheckOffset out of range"; + Integer key = superCheckOffset << SUPER_CHECK_OFFSET_SHIFT | nHints << NHINTS_SHIFT | flags; SnippetTemplate result = templates.get(key); if (result == null) { HotSpotKlassOop[] hints = new HotSpotKlassOop[nHints]; - Arrays.fill(hints, new HotSpotKlassOop(null, Templates.class)); - result = SnippetTemplate.create(runtime, method, _, _, hints, isExact, checkNull, noHintsCounter); + for (int i = 0; i < hints.length; i++) { + hints[i] = new HotSpotKlassOop(null, Templates.class); + } + result = factory.create(hints, flags); + //System.err.println(result); templates.put(key, result); } return result; } /** - * Creates a canonical key for a combination of specialization parameters. + * Lowers a checkcast node. */ - private static Integer key(int nHints, boolean isExact, boolean checkNull) { - int key = nHints << 2; - if (isExact) { - key |= 2; + public void lower(CheckCastNode checkcast, CiLoweringTool tool) { + StructuredGraph graph = (StructuredGraph) checkcast.graph(); + ValueNode hub = checkcast.targetClassInstruction(); + ValueNode object = checkcast.object(); + TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); + HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; + for (int i = 0; i < hintHubs.length; i++) { + hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop(); } - if (checkNull) { - key |= 1; + Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact); + + final HotSpotTypeResolvedImpl target = (HotSpotTypeResolvedImpl) checkcast.targetClass(); + int flags = EXACT_HINTS.bit(hints.exact) | CHECK_NULL.bit(!object.stamp().nonNull()); + if (GraalOptions.CheckcastCounters) { + SnippetTemplate template = getTemplate(hintHubs.length, flags | COUNTERS.bit(), 0, new Factory() { + @SuppressWarnings("hiding") + @Override + SnippetTemplate create(HotSpotKlassOop[] hints, int flags) { + // checkcastCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) + return SnippetTemplate.create(runtime, counters, _, _, hints, EXACT_HINTS.bool(flags)); + } + }); + template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs, hints.exact); + } else if (target == null) { + SnippetTemplate template = getTemplate(hintHubs.length, flags | UNKNOWN_SUPER.bit(), 0, new Factory() { + @SuppressWarnings("hiding") + @Override + SnippetTemplate create(HotSpotKlassOop[] hints, int flags) { + // checkcastUnknown(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) + return SnippetTemplate.create(runtime, unknown, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags)); + } + }); + template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs); + } else if (target.isPrimaryType()) { + SnippetTemplate template = getTemplate(hintHubs.length, flags | PRIMARY_SUPER.bit(), target.superCheckOffset(), new Factory() { + @SuppressWarnings("hiding") + @Override + SnippetTemplate create(HotSpotKlassOop[] hints, int flags) { + // checkcastPrimary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, int superCheckOffset) + return SnippetTemplate.create(runtime, primary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags), target.superCheckOffset()); + } + }); + template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs); + } else { + SnippetTemplate template = getTemplate(hintHubs.length, flags | SECONDARY_SUPER.bit(), 0, new Factory() { + @SuppressWarnings("hiding") + @Override + SnippetTemplate create(HotSpotKlassOop[] hints, int flags) { + // checkcastSecondary(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull) + return SnippetTemplate.create(runtime, secondary, _, _, hints, EXACT_HINTS.bool(flags), CHECK_NULL.bool(flags)); + } + }); + template.instantiate(runtime, checkcast, checkcast, hub, object, hintHubs); } - return key; + new DeadCodeEliminationPhase().apply(graph); } } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Fri Jun 01 16:32:05 2012 +0200 @@ -68,6 +68,31 @@ return reversePostOrder[0]; } + public Iterable postOrder() { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private int nextIndex = reversePostOrder.length - 1; + @Override + public boolean hasNext() { + return nextIndex >= 0; + } + + @Override + public Block next() { + return reversePostOrder[nextIndex--]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + public NodeMap getNodeToBlock() { return nodeToBlock; } @@ -304,7 +329,7 @@ } private void computePostdominators() { - for (Block block : reversePostOrder) { + for (Block block : postOrder()) { if (block.isLoopEnd()) { // We do not want the loop header registered as the postdominator of the loop end. continue; diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -31,7 +31,10 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; - +/** + * A floating read of a value from memory specified in terms of an object base and an object relative location. + * This node does not null check the object. + */ public final class FloatingReadNode extends FloatingAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable { @Input private Node lastLocationAccess; diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -27,10 +27,20 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +/** + * Extension of a {@linkplain LocationNode location} to include a scaled index or an additional offset. + */ public final class IndexedLocationNode extends LocationNode implements LIRLowerable, Canonicalizable { + + /** + * An offset or index depending on whether {@link #indexScalingEnabled} is true or false respectively. + */ @Input private ValueNode index; - private boolean indexScalingEnabled; + private final boolean indexScalingEnabled; + /** + * Gets the index or offset of this location. + */ public ValueNode index() { return index; } @@ -46,17 +56,6 @@ return indexScalingEnabled; } - /** - * Enables or disables scaling of the index by the value kind's size. Has no effect if the index input is not used. - */ - public void setIndexScalingEnabled(boolean enable) { - this.indexScalingEnabled = enable; - } - - public static IndexedLocationNode create(Object identity, CiKind kind, int displacement, ValueNode index, Graph graph) { - return create(identity, kind, displacement, index, graph, true); - } - public static IndexedLocationNode create(Object identity, CiKind kind, int displacement, ValueNode index, Graph graph, boolean indexScalingEnabled) { return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScalingEnabled)); } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -29,6 +29,10 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +/** + * A location for a memory access in terms of the kind of value accessed and the displacement + * (in bytes) from a base object or address. + */ public class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable { private int displacement; diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -22,11 +22,11 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.max.cri.ci.*; import com.oracle.graal.cri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; /** * Load of a value from a location specified as an offset relative to an object. @@ -50,6 +50,14 @@ return offset; } + public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, boolean nonNull) { + super(nonNull ? StampFactory.objectNonNull() : StampFactory.object()); + this.object = object; + this.displacement = displacement; + this.offset = offset; + this.loadKind = CiKind.Object; + } + public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, CiKind kind) { super(StampFactory.forKind(kind.stackKind())); this.object = object; @@ -72,4 +80,10 @@ public static T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter CiKind kind) { throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static Object loadObject(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter boolean nonNull) { + throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); + } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -24,8 +24,6 @@ import java.lang.reflect.*; -import sun.misc.*; - import com.oracle.graal.cri.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -71,7 +69,7 @@ int length = Array.getLength(array); if (index >= 0 && index < length) { return ConstantNode.forCiConstant(elementKind().readUnsafeConstant(array, - Unsafe.ARRAY_OBJECT_BASE_OFFSET + index * Unsafe.ARRAY_OBJECT_INDEX_SCALE), tool.runtime(), graph()); + elementKind().arrayBaseOffset() + index * elementKind().arrayIndexScale()), tool.runtime(), graph()); } } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Fri Jun 01 16:32:05 2012 +0200 @@ -35,6 +35,7 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.snippets.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; @@ -115,24 +116,41 @@ new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy); } - // Explode all loops in the snippet - if (snippetCopy.hasLoops()) { - ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false); - for (Loop loop : cfg.getLoops()) { - LoopBeginNode loopBegin = loop.loopBegin(); - SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop); - Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin); - int peel = 0; - while (!loopBegin.isDeleted()) { - int mark = snippetCopy.getMark(); - LoopTransformUtil.peel(loop, wholeLoop); - Debug.dump(snippetCopy, "After peel %d", peel); - new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy); - peel++; + boolean exploded = false; + do { + exploded = false; + for (Node node : snippetCopy.getNodes()) { + if (node instanceof ExplodeLoopNode) { + final ExplodeLoopNode explodeLoop = (ExplodeLoopNode) node; + LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); + ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false); + for (Loop loop : cfg.getLoops()) { + if (loop.loopBegin() == loopBegin) { + SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop); + Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin); + int peel = 0; + while (!loopBegin.isDeleted()) { + int mark = snippetCopy.getMark(); + LoopTransformUtil.peel(loop, wholeLoop); + Debug.dump(snippetCopy, "After peel %d", peel); + new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy); + peel++; + } + Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); + exploded = true; + break; + } + } + + FixedNode explodeLoopNext = explodeLoop.next(); + explodeLoop.clearSuccessors(); + explodeLoop.replaceAtPredecessors(explodeLoopNext); + explodeLoop.replaceAtUsages(null); + GraphUtil.killCFG(explodeLoop); + break; } - Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); } - } + } while (exploded); // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free // of side-effects that prevent deoptimizing to a point before the snippet). @@ -245,8 +263,10 @@ } else if (arg instanceof ValueNode) { assert param instanceof LocalNode; replacements.put((LocalNode) param, (ValueNode) arg); + } else if (param instanceof ConstantNode) { + replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph)); } else { - replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph)); + assert param.equals(arg) : param + " != " + arg; } } return replacements; diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java Fri Jun 01 16:32:05 2012 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.snippets.nodes; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Placeholder node to denote to snippet preparation that the following loop + * must be completely unrolled. + */ +public final class ExplodeLoopNode extends FixedWithNextNode { + + public ExplodeLoopNode() { + super(StampFactory.forVoid()); + } + + public LoopBeginNode findLoopBegin() { + Node next = next(); + while (!(next instanceof LoopBeginNode)) { + assert next != null : "cannot find loop after " + this; + Iterator< ? extends Node> successors = next.cfgSuccessors().iterator(); + assert successors.hasNext() : "cannot find loop after " + this; + next = successors.next(); + assert !successors.hasNext() : "should only be straight line code after " + this; + } + return (LoopBeginNode) next; + } + + /** + * A call to this method must be placed immediately prior to the loop that is to be exploded. + */ + @NodeIntrinsic + public static void explodeLoop() { + throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); + } +} diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java Fri Jun 01 16:32:05 2012 +0200 @@ -34,13 +34,27 @@ */ public class CheckCastTest extends TypeCheckTest { + /** + * Enables making the target type "unknown" at compile time. + */ + boolean unknown; + @Override protected void replaceProfile(StructuredGraph graph, RiTypeProfile profile) { CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile)); + RiResolvedType targetClass = unknown ? null : ccn.targetClass(); + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), targetClass, ccn.object(), profile)); graph.replaceFixedWithFixed(ccn, ccnNew); } + unknown = false; + } + + @Override + protected void test(String name, RiTypeProfile profile, Object... args) { + super.test(name, profile, args); + unknown = true; + super.test(name, profile, args); } @Test @@ -89,6 +103,19 @@ test("asStringExt", profile(String.class), 111); } + @Test + public void test7() { + Throwable throwable = new Exception(); + test("asThrowable", profile(), throwable); + test("asThrowable", profile(Throwable.class), throwable); + test("asThrowable", profile(Exception.class, Error.class), throwable); + } + + @Test + public void test8() { + test("arrayFill", profile(), new Object[100], "111"); + } + public static Number asNumber(Object o) { return (Number) o; } @@ -97,6 +124,14 @@ return (String) o; } + public static Throwable asThrowable(Object o) { + return (Throwable) o; + } + + public static ValueNode asValueNode(Object o) { + return (ValueNode) o; + } + public static Number asNumberExt(Object o) { Number n = (Number) o; return n.intValue() + 10; @@ -107,15 +142,48 @@ return "#" + s; } - @Test - public void test7() { - test("arrayFill", profile(), new Object[100], "111"); - } - public static Object[] arrayFill(Object[] arr, Object value) { for (int i = 0; i < arr.length; i++) { arr[i] = value; } return arr; } + + static class Depth1 implements Cloneable {} + static class Depth2 extends Depth1 {} + static class Depth3 extends Depth2 {} + static class Depth4 extends Depth3 {} + static class Depth5 extends Depth4 {} + static class Depth6 extends Depth5 {} + static class Depth7 extends Depth6 {} + static class Depth8 extends Depth7 {} + static class Depth9 extends Depth8 {} + static class Depth10 extends Depth9 {} + static class Depth11 extends Depth10 {} + static class Depth12 extends Depth11 {} + static class Depth13 extends Depth12 {} + + public static Depth12 asDepth12(Object o) { + return (Depth12) o; + } + + public static Depth12[][] asDepth12Arr(Object o) { + return (Depth12[][]) o; + } + + public static Cloneable asCloneable(Object o) { + return (Cloneable) o; + } + + @Test + public void test9() { + Object o = new Depth13(); + test("asDepth12", profile(), o); + } + + @Test + public void test10() { + Object o = new Depth13[3][]; + test("asDepth12Arr", profile(), o); + } } diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Fri Jun 01 16:32:05 2012 +0200 @@ -158,7 +158,7 @@ } protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) { - Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { + return Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { @Override public RiCompiledMethod call() throws Exception { final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null; @@ -169,7 +169,6 @@ return installedMethod; } }); - return runtime.addMethod(method, tm, null); } /** diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/cfg/SimpleCFGTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/cfg/SimpleCFGTest.java Fri Jun 01 16:32:05 2012 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.tests.cfg; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +public class SimpleCFGTest { + + @Test + public void testImplies() { + StructuredGraph graph = new StructuredGraph(); + + EndNode trueEnd = graph.add(new EndNode()); + EndNode falseEnd = graph.add(new EndNode()); + + BeginNode trueBegin = graph.add(new BeginNode()); + trueBegin.setNext(trueEnd); + BeginNode falseBegin = graph.add(new BeginNode()); + falseBegin.setNext(falseEnd); + + IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5)); + graph.start().setNext(ifNode); + + MergeNode merge = graph.add(new MergeNode()); + merge.addForwardEnd(trueEnd); + merge.addForwardEnd(falseEnd); + ReturnNode returnNode = graph.add(new ReturnNode(null)); + merge.setNext(returnNode); + + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + + Block[] blocks = cfg.getBlocks(); + // check number of blocks + assertEquals(4, blocks.length); + + // check block - node assignment + assertEquals(blocks[0], cfg.blockFor(graph.start())); + assertEquals(blocks[0], cfg.blockFor(ifNode)); + assertEquals(blocks[1], cfg.blockFor(trueBegin)); + assertEquals(blocks[1], cfg.blockFor(trueEnd)); + assertEquals(blocks[2], cfg.blockFor(falseBegin)); + assertEquals(blocks[2], cfg.blockFor(falseEnd)); + assertEquals(blocks[3], cfg.blockFor(merge)); + assertEquals(blocks[3], cfg.blockFor(returnNode)); + + // check dominators + assertDominator(blocks[0], null); + assertDominator(blocks[1], blocks[0]); + assertDominator(blocks[2], blocks[0]); + assertDominator(blocks[3], blocks[0]); + + // check dominated + assertDominatedSize(blocks[0], 3); + assertDominatedSize(blocks[1], 0); + assertDominatedSize(blocks[2], 0); + assertDominatedSize(blocks[3], 0); + + // check postdominators + assertPostdominator(blocks[0], blocks[3]); + assertPostdominator(blocks[1], blocks[3]); + assertPostdominator(blocks[2], blocks[3]); + assertPostdominator(blocks[3], null); + } + + public static void assertDominator(Block block, Block expectedDominator) { + assertEquals("dominator of " + block, expectedDominator, block.getDominator()); + } + + public static void assertDominatedSize(Block block, int size) { + assertEquals("number of dominated blocks of " + block, size, block.getDominated().size()); + } + + public static void assertPostdominator(Block block, Block expectedPostdominator) { + assertEquals("postdominator of " + block, expectedPostdominator, block.getPostdominator()); + } + +} diff -r 044502e7b5a4 -r c9b8994b43d8 graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Fri Jun 01 16:31:49 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Fri Jun 01 16:32:05 2012 +0200 @@ -344,6 +344,58 @@ return Character.toUpperCase(typeChar); } + public final int arrayBaseOffset() { + switch(this) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + case Byte: + return Unsafe.ARRAY_BYTE_BASE_OFFSET; + case Char: + return Unsafe.ARRAY_CHAR_BASE_OFFSET; + case Short: + return Unsafe.ARRAY_SHORT_BASE_OFFSET; + case Int: + return Unsafe.ARRAY_INT_BASE_OFFSET; + case Long: + return Unsafe.ARRAY_LONG_BASE_OFFSET; + case Float: + return Unsafe.ARRAY_FLOAT_BASE_OFFSET; + case Double: + return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + case Object: + return Unsafe.ARRAY_OBJECT_BASE_OFFSET; + default: + assert false : "unexpected kind: " + this; + return -1; + } + } + + public final int arrayIndexScale() { + switch(this) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + case Byte: + return Unsafe.ARRAY_BYTE_INDEX_SCALE; + case Char: + return Unsafe.ARRAY_CHAR_INDEX_SCALE; + case Short: + return Unsafe.ARRAY_SHORT_INDEX_SCALE; + case Int: + return Unsafe.ARRAY_INT_INDEX_SCALE; + case Long: + return Unsafe.ARRAY_LONG_INDEX_SCALE; + case Float: + return Unsafe.ARRAY_FLOAT_INDEX_SCALE; + case Double: + return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + case Object: + return Unsafe.ARRAY_OBJECT_INDEX_SCALE; + default: + assert false : "unexpected kind: " + this; + return -1; + } + } + public CiConstant readUnsafeConstant(Object value, long displacement) { assert value != null; Unsafe u = Unsafe.getUnsafe(); diff -r 044502e7b5a4 -r c9b8994b43d8 hotspot/.cproject --- a/hotspot/.cproject Fri Jun 01 16:31:49 2012 +0200 +++ b/hotspot/.cproject Fri Jun 01 16:32:05 2012 +0200 @@ -20,7 +20,7 @@ - + @@ -80,14 +80,15 @@ - - - + + + + @@ -111,4 +112,5 @@ + diff -r 044502e7b5a4 -r c9b8994b43d8 mxtool/mx.py --- a/mxtool/mx.py Fri Jun 01 16:31:49 2012 +0200 +++ b/mxtool/mx.py Fri Jun 01 16:32:05 2012 +0200 @@ -124,7 +124,7 @@ Property values can use environment variables with Bash syntax (e.g. ${HOME}). """ -import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils +import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile import shutil, fnmatch, re, xml.dom.minidom from collections import Callable from threading import Thread @@ -404,11 +404,11 @@ class XMLElement(xml.dom.minidom.Element): def writexml(self, writer, indent="", addindent="", newl=""): writer.write(indent+"<" + self.tagName) - + attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() - + for a_name in a_names: writer.write(" %s=\"" % a_name) xml.dom.minidom._write_data(writer, attrs[a_name].value) @@ -416,7 +416,7 @@ if self.childNodes: if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text): # if the only child of an Element node is a Text node, then the - # text is printed without any indentation or new line padding + # text is printed without any indentation or new line padding writer.write(">") self.childNodes[0].writexml(writer) writer.write("%s" % (self.tagName,newl)) @@ -440,7 +440,7 @@ e = XMLElement(tagName) e.ownerDocument = self return e - + def open(self, tag, attributes={}, data=None): element = self.createElement(tag) for key, value in attributes.items(): @@ -453,13 +453,13 @@ def close(self, tag): assert self.current != self - assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName + assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName self.current = self.current.parentNode return self - + def element(self, tag, attributes={}, data=None): return self.open(tag, attributes, data).close(tag) - + def xml(self, indent='', newl='', escape=False): assert self.current == self result = self.toprettyxml(indent, newl, encoding="UTF-8") @@ -534,20 +534,49 @@ cp += [_opts.cp_suffix] return os.pathsep.join(cp) -def classpath(names=None, resolve=True, includeSelf=True): +def classpath(names=None, resolve=True, includeSelf=True, includeBootClasspath=False): """ Get the class path for a list of given projects, resolving each entry in the path (e.g. downloading a missing library) if 'resolve' is true. """ if names is None: - return _as_classpath(sorted_deps(includeLibs=True), resolve) - deps = [] - if isinstance(names, types.StringTypes): - project(names).all_deps(deps, True, includeSelf) + result = _as_classpath(sorted_deps(includeLibs=True), resolve) else: - for n in names: - project(n).all_deps(deps, True, includeSelf) - return _as_classpath(deps, resolve) + deps = [] + if isinstance(names, types.StringTypes): + project(names).all_deps(deps, True, includeSelf) + else: + for n in names: + project(n).all_deps(deps, True, includeSelf) + result = _as_classpath(deps, resolve) + if includeBootClasspath: + result = os.pathsep.join([java().bootclasspath(), result]) + return result + +def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False): + """ + Walks the resources available in a given classpath, yielding a tuple for each resource + where the first member of the tuple is a directory path or ZipFile object for a + classpath entry and the second member is the qualified path of the resource relative + to the classpath entry. + """ + cp = classpath(names, resolve, includeSelf, includeBootClasspath) + for entry in cp.split(os.pathsep): + if not exists(entry): + continue + if isdir(entry): + for root, dirs, files in os.walk(entry): + for d in dirs: + entryPath = join(root[len(entry) + 1:], d) + yield entry, entryPath + for f in files: + entryPath = join(root[len(entry) + 1:], f) + yield entry, entryPath + elif entry.endswith('.jar') or entry.endswith('.zip'): + with zipfile.ZipFile(entry, 'r') as zf: + for zi in zf.infolist(): + entryPath = zi.filename + yield zf, entryPath def sorted_deps(projectNames=None, includeLibs=False): """ @@ -830,6 +859,7 @@ self.javac = exe_suffix(join(self.jdk, 'bin', 'javac')) self.javap = exe_suffix(join(self.jdk, 'bin', 'javap')) self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc')) + self._bootclasspath = None if not exists(self.java): abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java) @@ -863,6 +893,27 @@ def format_cmd(self, args): return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args + def bootclasspath(self): + if self._bootclasspath is None: + tmpDir = tempfile.mkdtemp() + try: + src = join(tmpDir, 'bootclasspath.java') + with open(src, 'w') as fp: + print >> fp, """ +public class bootclasspath { + public static void main(String[] args) { + String s = System.getProperty("sun.boot.class.path"); + if (s != null) { + System.out.println(s); + } + } +}""" + subprocess.check_call([self.javac, '-d', tmpDir, src]) + self._bootclasspath = subprocess.check_output([self.java, '-cp', tmpDir, 'bootclasspath']) + finally: + shutil.rmtree(tmpDir) + return self._bootclasspath + def check_get_env(key): """ Gets an environment variable, aborting with a useful message if it is not set. @@ -1039,7 +1090,7 @@ javaCompliance = java().javaCompliance defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar') - + parser = parser if parser is not None else ArgumentParser(prog='mx build') parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)') parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') @@ -1440,8 +1491,8 @@ for dep in p.canonical_deps(): print '"' + p.name + '"->"' + dep + '"' print '}' - - + + def _source_locator_memento(deps): slm = XMLDoc() slm.open('sourceLookupDirector') @@ -1450,7 +1501,7 @@ # Every Java program depends on the JRE memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml() slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) - + for dep in deps: if dep.isLibrary(): if hasattr(dep, 'eclipse.container'): @@ -1482,7 +1533,7 @@ launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'}) launch.close('launchConfiguration') launch = launch.xml(newl='\n') % slm.xml(escape=True) - + if name is None: name = 'attach-' + hostname + '-' + port eclipseLaunches = join('mx', 'eclipse-launches') @@ -1516,11 +1567,11 @@ mainClass = a appArgs = list(reversed(argsCopy)) break - + if mainClass is None: log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs)) return False - + if name is None: if mainClass == '-jar': name = basename(appArgs[0]) @@ -1535,9 +1586,9 @@ for s in suites(): deps += [p for p in s.projects if e == p.output_dir()] deps += [l for l in s.libs if e == l.get_path(False)] - + slm = _source_locator_memento(deps) - + launch = XMLDoc() launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'}) launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'}) @@ -1564,13 +1615,13 @@ for p in projects(): if p.native: continue - + if not exists(p.dir): os.makedirs(p.dir) out = XMLDoc() out.open('classpath') - + for src in p.srcDirs: srcDir = join(p.dir, src) if not exists(srcDir): @@ -1677,7 +1728,7 @@ content = content.replace('${javaCompliance}', str(p.javaCompliance)) update_file(join(settingsDir, name), content) - make_eclipse_attach('localhost', '8000', deps=projects()) + make_eclipse_attach('localhost', '8000', deps=projects()) def netbeansinit(args, suite=None): """(re)generate NetBeans project configurations""" @@ -1717,7 +1768,7 @@ out.element('root', {'id' : 'test.src.dir'}) out.close('test-roots') out.close('data') - + firstDep = True for dep in p.all_deps([], True): if dep == p: @@ -1894,7 +1945,7 @@ def javadoc(args): """generate javadoc for some/all Java projects""" - + parser = ArgumentParser(prog='mx javadoc') parser.add_argument('--unified', action='store_true', help='put javadoc in a single directory instead of one per project') parser.add_argument('--force', action='store_true', help='(re)generate javadoc even if package-list file exists') @@ -2006,6 +2057,20 @@ run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs)) log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir)) +def findclass(args): + """find all classes matching a given substring""" + + for entry, filename in classpath_walk(includeBootClasspath=True): + if filename.endswith('.class'): + if isinstance(entry, zipfile.ZipFile): + classname = filename.replace('/', '.') + else: + classname = filename.replace(os.sep, '.') + classname = classname[:-len('.class')] + for a in args: + if a in classname: + log(classname) + def javap(args): """launch javap with a -classpath option denoting all available classes @@ -2047,6 +2112,7 @@ 'canonicalizeprojects': [canonicalizeprojects, ''], 'clean': [clean, ''], 'eclipseinit': [eclipseinit, ''], + 'findclass': [findclass, ''], 'help': [help_, '[command]'], 'ideclean': [ideclean, ''], 'ideinit': [ideinit, ''], diff -r 044502e7b5a4 -r c9b8994b43d8 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Fri Jun 01 16:31:49 2012 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Fri Jun 01 16:32:05 2012 +0200 @@ -275,6 +275,7 @@ HotSpotTypeResolved::set_simpleName(obj, name()); HotSpotTypeResolved::set_accessFlags(obj, klass->access_flags().as_int()); HotSpotTypeResolved::set_isInterface(obj, klass->is_interface()); + HotSpotTypeResolved::set_superCheckOffset(obj, klass->super_check_offset()); HotSpotTypeResolved::set_isInstanceClass(obj, klass->oop_is_instance()); if (klass->oop_is_javaArray()) { diff -r 044502e7b5a4 -r c9b8994b43d8 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 01 16:31:49 2012 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 01 16:32:05 2012 +0200 @@ -789,6 +789,9 @@ set_int(env, config, "vmPageSize", os::vm_page_size()); set_int(env, config, "stackShadowPages", StackShadowPages); set_int(env, config, "hubOffset", oopDesc::klass_offset_in_bytes()); + set_int(env, config, "superCheckOffsetOffset", in_bytes(Klass::super_check_offset_offset())); + set_int(env, config, "secondarySuperCacheOffset", in_bytes(Klass::secondary_super_cache_offset())); + set_int(env, config, "secondarySupersOffset", in_bytes(Klass::secondary_supers_offset())); set_int(env, config, "arrayLengthOffset", arrayOopDesc::length_offset_in_bytes()); set_int(env, config, "klassStateOffset", in_bytes(instanceKlass::init_state_offset())); set_int(env, config, "klassStateFullyInitialized", (int)instanceKlass::fully_initialized); @@ -1021,6 +1024,7 @@ if (nm == NULL || !nm->is_alive()) { THROW_0(vmSymbols::MethodInvalidatedException()); } + JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL); if (jap.get_ret_type() == T_VOID) { diff -r 044502e7b5a4 -r c9b8994b43d8 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Fri Jun 01 16:31:49 2012 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Fri Jun 01 16:32:05 2012 +0200 @@ -53,6 +53,7 @@ boolean_field(HotSpotTypeResolved, hasFinalizer) \ boolean_field(HotSpotTypeResolved, hasSubclass) \ boolean_field(HotSpotTypeResolved, hasFinalizableSubclass) \ + int_field(HotSpotTypeResolved, superCheckOffset) \ boolean_field(HotSpotTypeResolved, isArrayClass) \ boolean_field(HotSpotTypeResolved, isInstanceClass) \ boolean_field(HotSpotTypeResolved, isInterface) \