# HG changeset patch # User Christian Haeubl # Date 1373270280 -7200 # Node ID 3c2a77f01e8932ba590d5ba277e3209e5ed925b5 # Parent 703d00fe27038dbd07bddc04d0d01b35f4ac75bf# Parent cb2d97f002d443a75d28829b1ed76e0a24d5eaa2 Merge. diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Mon Jul 08 09:58:00 2013 +0200 @@ -372,4 +372,21 @@ record(assumptions.list[i]); } } + + public void print(PrintStream out) { + List nonNullList = new ArrayList<>(); + if (list != null) { + for (int i = 0; i < list.length; ++i) { + Assumption a = list[i]; + if (a != null) { + nonNullList.add(a); + } + } + } + + out.printf("%d assumptions:\n", nonNullList.size()); + for (Assumption a : nonNullList) { + out.println(a.toString()); + } + } } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Mon Jul 08 09:58:00 2013 +0200 @@ -101,6 +101,23 @@ } } + /** + * Creates a new debug scope that is unrelated to the current scope and runs a given task in the + * new scope. + * + * @param name new scope name + * @param context the context objects of the new scope + * @param config the debug configuration to use for the new scope + * @param callable the task to run in the new scope + */ + public static T sandbox(String name, Object[] context, DebugConfig config, Callable callable) { + if (ENABLED) { + return DebugScope.getInstance().scope(name, null, callable, true, config, context); + } else { + return DebugScope.call(callable); + } + } + public static void scope(String name, Runnable runnable) { scope(name, new Object[0], runnable); } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Jul 08 09:58:00 2013 +0200 @@ -432,8 +432,12 @@ } Variable input = load(inputVal); if (runtime().config.useCompressedOops && isCompressCandidate(access)) { - Variable scratch = newVariable(Kind.Long); - append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + if (input.getKind() == Kind.Object) { + Variable scratch = newVariable(Kind.Long); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + append(new StoreOp(input.getKind(), storeAddress, input, state)); + } } else { append(new StoreOp(kind, storeAddress, input, state)); } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Mon Jul 08 09:58:00 2013 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.compiler.test.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -630,10 +631,15 @@ new SafepointInsertionPhase().apply(graph); new WriteBarrierAdditionPhase().apply(graph); + int barriers = 0; // First, the total number of expected barriers is checked. - final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); - Assert.assertTrue(expectedBarriers == barriers); - + if (((HotSpotRuntime) runtime()).config.useG1GC) { + barriers = graph.getNodes(G1PreWriteBarrier.class).count() + graph.getNodes(G1PostWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers * 2 == barriers); + } else { + barriers = graph.getNodes(SerialWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers == barriers); + } // Iterate over all write nodes and remove barriers according to input indices. NodeIteratorClosure closure = new NodeIteratorClosure() { @@ -653,10 +659,10 @@ } } } - } else if (node instanceof SerialWriteBarrier) { + } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) { // Remove flagged write barriers. if (currentState) { - graph.removeFixed(((SerialWriteBarrier) node)); + graph.removeFixed(((FixedWithNextNode) node)); return false; } } @@ -692,7 +698,7 @@ try { ReentrantNodeIterator.apply(closure, graph.start(), false, null); Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.output())); - new WriteBarrierVerificationPhase().apply(graph); + new WriteBarrierVerificationPhase(((HotSpotRuntime) runtime()).config.useG1GC).apply(graph); } catch (AssertionError error) { /* * Catch assertion, test for expected one and re-throw in order to validate unit diff -r 703d00fe2703 -r 3c2a77f01e89 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 Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Jul 08 09:58:00 2013 +0200 @@ -50,6 +50,7 @@ public boolean usePopCountInstruction; public boolean useAESIntrinsics; public boolean useG1GC; + public long gcTotalCollectionsAddress; // Compressed Oops related values. public boolean useCompressedOops; diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Jul 08 09:58:00 2013 +0200 @@ -1214,7 +1214,7 @@ ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase()); if (VerifyPhases.getValue()) { - ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase()); + ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config.useG1GC)); } return ret; diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Mon Jul 08 09:58:00 2013 +0200 @@ -41,12 +41,18 @@ */ public class WriteBarrierVerificationPhase extends Phase { + private final boolean useG1GC; + + public WriteBarrierVerificationPhase(boolean useG1GC) { + this.useG1GC = useG1GC; + } + @Override protected void run(StructuredGraph graph) { processWrites(graph); } - private static void processWrites(StructuredGraph graph) { + private void processWrites(StructuredGraph graph) { for (Node node : graph.getNodes()) { if (isObjectWrite(node)) { validateWrite(node); @@ -54,7 +60,7 @@ } } - private static void validateWrite(Node write) { + private void validateWrite(Node write) { /* * The currently validated write is checked in order to discover if it has an appropriate * attached write barrier. @@ -68,14 +74,25 @@ while (iterator.hasNext()) { Node currentNode = iterator.next(); assert !isSafepoint(currentNode) : "Write barrier must be present"; - if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (SerialWriteBarrier) currentNode))) { - expandFrontier(frontier, currentNode); + if (useG1GC) { + if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier(write, (WriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); + } + } else { + if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (WriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); + } } } } - private static boolean hasAttachedBarrier(Node node) { - return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next()); + private boolean hasAttachedBarrier(Node node) { + if (useG1GC) { + return ((FixedWithNextNode) node).next() instanceof G1PostWriteBarrier && ((FixedWithNextNode) node).predecessor() instanceof G1PreWriteBarrier && + validateBarrier(node, (G1PostWriteBarrier) ((FixedWithNextNode) node).next()) && validateBarrier(node, (G1PreWriteBarrier) ((FixedWithNextNode) node).predecessor()); + } else { + return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next()); + } } private static boolean isObjectWrite(Node node) { @@ -103,7 +120,7 @@ return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode); } - private static boolean validateBarrier(Node write, SerialWriteBarrier barrier) { + private static boolean validateBarrier(Node write, WriteBarrier barrier) { ValueNode writtenObject = null; LocationNode writtenLocation = null; if (write instanceof WriteNode) { diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon Jul 08 09:58:00 2013 +0200 @@ -692,4 +692,9 @@ public static int verifiedEntryPointOffset() { return config().nmethodEntryOffset; } + + @Fold + public static long gcTotalCollectionsAddress() { + return config().gcTotalCollectionsAddress; + } } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 08 09:58:00 2013 +0200 @@ -259,7 +259,7 @@ args.addConst("size", size); args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); - args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("fillContents", useG1GC() ? true : newInstanceNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); @@ -284,7 +284,7 @@ args.add("prototypeMarkWord", arrayType.prototypeMarkWord()); args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("fillContents", useG1GC() ? true : newArrayNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); @@ -295,7 +295,7 @@ Arguments args = new Arguments(allocateArrayDynamic); args.add("elementType", newArrayNode.getElementType()); args.add("length", newArrayNode.length()); - args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("fillContents", useG1GC() ? true : newArrayNode.fillContents()); SnippetTemplate template = template(args); template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args); diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 08 09:58:00 2013 +0200 @@ -54,7 +54,7 @@ private static Object instanceClone(Object src, Word hub, int layoutHelper) { int instanceSize = layoutHelper; Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false); + Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, useG1GC() ? true : false); Pointer memory = Word.fromObject(result); for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { @@ -71,7 +71,7 @@ int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false); + Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, useG1GC() ? true : false); Pointer memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Mon Jul 08 09:58:00 2013 +0200 @@ -28,11 +28,13 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; @@ -40,12 +42,14 @@ import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; public class WriteBarrierSnippets implements Snippets { private static final SnippetCounter.Group countersWriteBarriers = SnippetCounters.getValue() ? new SnippetCounter.Group("WriteBarriers") : null; private static final SnippetCounter serialFieldWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialFieldWriteBarrier", "Number of Serial Field Write Barriers"); private static final SnippetCounter serialArrayWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialArrayWriteBarrier", "Number of Serial Array Write Barriers"); + private static final int gcStartCycles = GraalOptions.GCDebugStartCycle.getValue(); @Snippet public static void serialArrayWriteBarrier(Object obj, Object location, @ConstantParameter boolean usePrecise) { @@ -85,19 +89,15 @@ } } - /** - * Log method of debugging purposes. - */ - static void log(boolean enabled, String format, WordBase value) { - if (enabled) { - Log.printf(format, value.rawValue()); + @Snippet + public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck, + @ConstantParameter boolean trace) { + if (nullCheck && object == null) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } - } - - @Snippet - public static void g1PreWriteBarrier(Object object, Object expectedObject, Object location, @ConstantParameter boolean doLoad) { Word thread = thread(); Object fixedObject = FixedValueAnchorNode.getObject(object); + verifyOop(fixedObject); Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject); Word field = (Word) Word.fromArray(fixedObject, location); Word previousOop = (Word) Word.fromObject(fixedExpectedObject); @@ -105,19 +105,33 @@ Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset()); Word indexAddress = thread.add(g1SATBQueueIndexOffset()); Word indexValue = indexAddress.readWord(0); - + int gcCycle = 0; + if (trace) { + gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0); + log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedObject).rawValue()); + log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedExpectedObject).rawValue()); + log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue()); + log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue); + log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L); + } // If the concurrent marker is enabled, the barrier is issued. - if (markingValue != (byte) 0) { + if (probability(NOT_LIKELY_PROBABILITY, markingValue != (byte) 0)) { // If the previous value has to be loaded (before the write), the load is issued. // The load is always issued except the cases of CAS and referent field. - if (doLoad) { + if (probability(LIKELY_PROBABILITY, doLoad)) { previousOop = (Word) Word.fromObject(field.readObjectCompressed(0)); + if (trace) { + if (previousOop.notEqual(Word.zero())) { + verifyOop(previousOop.toObject()); + } + log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue()); + } } // If the previous value is null the barrier should not be issued. - if (previousOop.notEqual(0)) { + if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) { // If the thread-local SATB buffer is full issue a native call which will // initialize a new one and add the entry. - if (indexValue.notEqual(0)) { + if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) { Word nextIndex = indexValue.subtract(wordSize()); Word logAddress = bufferAddress.add(nextIndex); // Log the object to be marked as well as update the SATB's buffer next index. @@ -131,10 +145,12 @@ } @Snippet - public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise) { + public static void g1PostWriteBarrier(Object object, Object value, Object location, @ConstantParameter boolean usePrecise, @ConstantParameter boolean trace) { Word thread = thread(); Object fixedObject = FixedValueAnchorNode.getObject(object); Object fixedValue = FixedValueAnchorNode.getObject(value); + verifyOop(fixedObject); + verifyOop(fixedValue); Word oop = (Word) Word.fromObject(fixedObject); Word field; if (usePrecise) { @@ -142,7 +158,12 @@ } else { field = oop; } - + int gcCycle = 0; + if (trace) { + gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0); + log(trace, "[%d] G1-Post Thread: %p Object: %p Field: %p\n", gcCycle, thread.rawValue(), Word.fromObject(fixedObject).rawValue()); + log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), field.rawValue()); + } Word writtenValue = (Word) Word.fromObject(fixedValue); Word bufferAddress = thread.readWord(g1CardQueueBufferOffset()); Word indexAddress = thread.add(g1CardQueueIndexOffset()); @@ -163,16 +184,17 @@ } Word cardAddress = cardBase.add(displacement); - if (xorResult.notEqual(0)) { + if (probability(LIKELY_PROBABILITY, xorResult.notEqual(0))) { // If the written value is not null continue with the barrier addition. - if (writtenValue.notEqual(0)) { + if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) { byte cardByte = cardAddress.readByte(0); // If the card is already dirty, (hence already enqueued) skip the insertion. - if (cardByte != (byte) 0) { + if (probability(LIKELY_PROBABILITY, cardByte != (byte) 0)) { + log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue()); cardAddress.writeByte(0, (byte) 0); // If the thread local card queue is full, issue a native call which will // initialize a new one and add the card entry. - if (indexValue.notEqual(0)) { + if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) { Word nextIndex = indexValue.subtract(wordSize()); Word logAddress = bufferAddress.add(nextIndex); // Log the object to be scanned as well as update @@ -305,6 +327,8 @@ args.add("expectedObject", writeBarrierPre.getExpectedObject()); args.add("location", writeBarrierPre.getLocation()); args.addConst("doLoad", writeBarrierPre.doLoad()); + args.addConst("nullCheck", !writeBarrierPre.getObject().stamp().nonNull()); + args.addConst("trace", traceBarrier()); template(args).instantiate(runtime, writeBarrierPre, DEFAULT_REPLACER, args); } @@ -314,6 +338,7 @@ args.add("value", writeBarrierPost.getValue()); args.add("location", writeBarrierPost.getLocation()); args.addConst("usePrecise", writeBarrierPost.usePrecise()); + args.addConst("trace", traceBarrier()); template(args).instantiate(runtime, writeBarrierPost, DEFAULT_REPLACER, args); } @@ -333,4 +358,29 @@ template(args).instantiate(runtime, arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } } + + /** + * Log method of debugging purposes. + */ + private static void log(boolean enabled, String format, long value) { + if (enabled) { + Log.printf(format, value); + } + } + + private static void log(boolean enabled, String format, long value1, long value2) { + if (enabled) { + Log.printf(format, value1, value2); + } + } + + private static void log(boolean enabled, String format, long value1, long value2, long value3) { + if (enabled) { + Log.printf(format, value1, value2, value3); + } + } + + private static boolean traceBarrier() { + return gcStartCycles > 0 && ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress()).readLong(0) > gcStartCycles); + } } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Jul 08 09:58:00 2013 +0200 @@ -33,6 +33,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -123,10 +124,10 @@ @Override protected void run(final StructuredGraph graph) { - InliningData data = new InliningData(graph, compilationAssumptions); + final InliningData data = new InliningData(graph, compilationAssumptions); while (data.hasUnprocessedGraphs()) { - MethodInvocation currentInvocation = data.currentInvocation(); + final MethodInvocation currentInvocation = data.currentInvocation(); GraphInfo graphInfo = data.currentGraph(); if (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(), currentInvocation.relevance(), false)) { int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs(); @@ -142,8 +143,15 @@ currentInvocation.incrementProcessedGraphs(); if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) { data.popInvocation(); - MethodInvocation parentInvoke = data.currentInvocation(); - tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1); + final MethodInvocation parentInvoke = data.currentInvocation(); + Debug.scope("Inlining", data.inliningContext(), new Runnable() { + + @Override + public void run() { + tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1); + } + }); + } } } @@ -595,6 +603,9 @@ private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new LinkedList(), 1.0, 1.0); + /** + * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee. + */ private final ArrayDeque graphQueue; private final ArrayDeque invocationQueue; @@ -646,6 +657,18 @@ } } + /** + * Gets the call hierarchy of this inling from outer most call to inner most callee. + */ + public Object[] inliningContext() { + Object[] result = new Object[graphQueue.size()]; + int i = 0; + for (GraphInfo g : graphQueue) { + result[i++] = g.graph.method(); + } + return result; + } + public MethodInvocation currentInvocation() { return invocationQueue.peek(); } @@ -684,10 +707,12 @@ StringBuilder result = new StringBuilder("Invocations: "); for (MethodInvocation invocation : invocationQueue) { - result.append(invocation.callee().numberOfMethods()); - result.append("x "); - result.append(invocation.callee().invoke()); - result.append("; "); + if (invocation.callee() != null) { + result.append(invocation.callee().numberOfMethods()); + result.append("x "); + result.append(invocation.callee().invoke()); + result.append("; "); + } } result.append("\nGraphs: "); @@ -768,8 +793,26 @@ public boolean isRoot() { return callee == null; } + + @Override + public String toString() { + if (isRoot()) { + return ""; + } + CallTargetNode callTarget = callee.invoke().callTarget(); + if (callTarget instanceof MethodCallTargetNode) { + ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod(); + return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod); + } else { + return "Invoke#" + callTarget.targetName(); + } + } } + /** + * Information about a graph that will potentially be inlined. This includes tracking the + * invocations in graph that will subject to inlining themselves. + */ private static class GraphInfo { private final StructuredGraph graph; @@ -791,6 +834,10 @@ } } + /** + * Gets the method associated with the {@linkplain #graph() graph} represented by this + * object. + */ public ResolvedJavaMethod method() { return graph.method(); } @@ -799,6 +846,9 @@ return !remainingInvokes.isEmpty(); } + /** + * The graph about which this object contains inlining information. + */ public StructuredGraph graph() { return graph; } @@ -823,6 +873,11 @@ public double invokeRelevance(Invoke invoke) { return Math.min(CapInheritedRelevance.getValue(), relevance) * nodeRelevance.get(invoke.asNode()); } + + @Override + public String toString() { + return MetaUtil.format("%H.%n(%p)", method()) + remainingInvokes; + } } private static class CompiledMethodInfo { diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Jul 08 09:58:00 2013 +0200 @@ -143,7 +143,8 @@ // Debug settings: @Option(help = "") public static final OptionValue BootstrapReplacements = new OptionValue<>(false); - + @Option(help = "") + public static final OptionValue GCDebugStartCycle = new OptionValue<>(-1); // Ideal graph visualizer output settings @Option(help = "") public static final OptionValue PrintBinaryGraphs = new OptionValue<>(true); diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon Jul 08 09:58:00 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.phases.schedule; import static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.nodes.cfg.ControlFlowGraph.*; import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; @@ -335,7 +336,7 @@ @Override public void apply(Block newBlock) { - this.block = getCommonDominator(this.block, newBlock); + this.block = commonDominator(this.block, newBlock); } } @@ -487,16 +488,6 @@ // now true usages are ready } - private static Block getCommonDominator(Block a, Block b) { - if (a == null) { - return b; - } - if (b == null) { - return a; - } - return ControlFlowGraph.commonDominator(a, b); - } - private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) { NodeBitMap visited = graph.createNodeBitMap(); for (Block b : cfg.getBlocks()) { diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Mon Jul 08 09:58:00 2013 +0200 @@ -57,7 +57,8 @@ public PartialEvaluationTest() { // Make sure Truffle runtime is initialized. Assert.assertTrue(Truffle.getRuntime() instanceof GraalTruffleRuntime); - this.partialEvaluator = new PartialEvaluator(runtime, ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements()); + this.partialEvaluator = new PartialEvaluator(runtime, ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(), new TruffleCache(runtime, GraphBuilderConfiguration.getDefault(), + TruffleCompilerImpl.Optimizations, ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements())); DebugEnvironment.initialize(System.out); } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java Mon Jul 08 09:58:00 2013 +0200 @@ -220,6 +220,7 @@ } int slotIndex = slot.getIndex(); if (slotIndex >= tags.length) { + CompilerDirectives.transferToInterpreter(); resize(); } tags[slotIndex] = (byte) accessKind.ordinal(); @@ -237,9 +238,11 @@ } int slotIndex = slot.getIndex(); if (slotIndex >= tags.length) { + CompilerDirectives.transferToInterpreter(); resize(); } if (tags[slotIndex] != accessKind.ordinal()) { + CompilerDirectives.transferToInterpreter(); descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot)); if (tags[slotIndex] != accessKind.ordinal()) { throw new FrameSlotTypeException(); diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Jul 08 09:58:00 2013 +0200 @@ -70,14 +70,16 @@ private final Replacements replacements; private Set constantReceivers; private final HotSpotGraphCache cache; + private final TruffleCache truffleCache; - public PartialEvaluator(MetaAccessProvider metaAccessProvider, Replacements replacements) { + public PartialEvaluator(MetaAccessProvider metaAccessProvider, Replacements replacements, TruffleCache truffleCache) { this.metaAccessProvider = metaAccessProvider; this.nodeClass = metaAccessProvider.lookupJavaType(com.oracle.truffle.api.nodes.Node.class); this.customCanonicalizer = new PartialEvaluatorCanonicalizer(metaAccessProvider, nodeClass); this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(metaAccessProvider); this.replacements = replacements; this.cache = HotSpotGraalRuntime.graalRuntime().getCache(); + this.truffleCache = truffleCache; try { executeHelperMethod = metaAccessProvider.lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class)); @@ -215,7 +217,7 @@ StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); NewFrameNode otherNewFrame = null; if (inlineGraph == null) { - inlineGraph = parseGraph(config, methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, !AOTCompilation.getValue()); + inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, !AOTCompilation.getValue()); otherNewFrame = inlineGraph.getNodes(NewFrameNode.class).first(); } @@ -225,7 +227,6 @@ int nodeCountAfter = graph.getNodeCount(); Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); } - changed = true; if (otherNewFrame != null) { @@ -240,23 +241,21 @@ } while (changed && newFrameNode.isAlive() && newFrameNode.usages().isNotEmpty()); } - private StructuredGraph parseGraph(final GraphBuilderConfiguration config, final ResolvedJavaMethod targetMethod, final NodeInputList arguments, final Assumptions assumptions, - final boolean canonicalizeReads) { + private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList arguments, final Assumptions assumptions, final boolean canonicalizeReads) { - final StructuredGraph graph = new StructuredGraph(targetMethod); + final StructuredGraph graph = truffleCache.lookup(targetMethod, arguments).copy(); Debug.scope("parseGraph", targetMethod, new Runnable() { @Override public void run() { - new GraphBuilderPhase(metaAccessProvider, config, TruffleCompilerImpl.Optimizations).apply(graph); // Pass on constant arguments. for (LocalNode local : graph.getNodes(LocalNode.class)) { ValueNode arg = arguments.get(local.index()); - if (arg instanceof NewFrameNode) { - local.setStamp(arg.stamp()); - } else if (arg.isConstant()) { + if (arg.isConstant()) { Constant constant = arg.asConstant(); local.replaceAndDelete(ConstantNode.forConstant(constant, metaAccessProvider, graph)); + } else { + local.setStamp(arg.stamp()); } } diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Mon Jul 08 09:58:00 2013 +0200 @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2013, 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.truffle; + +import static com.oracle.graal.phases.GraalOptions.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.truffle.phases.*; +import com.oracle.graal.virtual.phases.ea.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Implementation of a cache for Truffle graphs for improving partial evaluation time. + */ +public final class TruffleCache { + + private final MetaAccessProvider metaAccessProvider; + private final GraphBuilderConfiguration config; + private final OptimisticOptimizations optimisticOptimizations; + private final Replacements replacements; + + private final HashMap cache = new HashMap<>(); + + public TruffleCache(MetaAccessProvider metaAccessProvider, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations, Replacements replacements) { + this.metaAccessProvider = metaAccessProvider; + this.config = config; + this.optimisticOptimizations = optimisticOptimizations; + this.replacements = replacements; + } + + public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments) { + + if (cache.containsKey(method)) { + StructuredGraph graph = cache.get(method); + if (checkArgumentStamps(graph, arguments)) { + return graph; + } + } + + StructuredGraph resultGraph = Debug.sandbox("TruffleCache", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Callable() { + + public StructuredGraph call() { + StructuredGraph newGraph = parseGraph(method); + + // Get stamps from actual arguments. + List stamps = new ArrayList<>(); + for (ValueNode arg : arguments) { + stamps.add(arg.stamp()); + } + + if (cache.containsKey(method)) { + // Make sure stamps are generalized based on previous stamps. + StructuredGraph graph = cache.get(method); + for (LocalNode localNode : graph.getNodes(LocalNode.class)) { + int index = localNode.index(); + Stamp stamp = stamps.get(index); + stamps.set(index, stamp.meet(localNode.stamp())); + } + } + + // Set stamps into graph before optimizing. + for (LocalNode localNode : newGraph.getNodes(LocalNode.class)) { + int index = localNode.index(); + Stamp stamp = stamps.get(index); + localNode.setStamp(stamp); + } + + optimizeGraph(newGraph); + cache.put(method, newGraph); + if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { + TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, newGraph.getNodeCount())); + } + return newGraph; + } + }); + return resultGraph; + } + + private void optimizeGraph(StructuredGraph newGraph) { + + ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(metaAccessProvider); + ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase = new ConvertDeoptimizeToGuardPhase(); + + Assumptions assumptions = new Assumptions(false); + CanonicalizerPhase.Instance canonicalizerPhase = new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, !AOTCompilation.getValue(), null, null); + + Integer maxNodes = TruffleCompilerOptions.TruffleOperationCacheMaxNodes.getValue(); + + contractGraph(newGraph, eliminate, convertDeoptimizeToGuardPhase, canonicalizerPhase); + + while (newGraph.getNodeCount() <= maxNodes) { + + int mark = newGraph.getMark(); + + expandGraph(newGraph, maxNodes); + + if (newGraph.getNewNodes(mark).count() == 0) { + // No progress => exit iterative optimization. + break; + } + + contractGraph(newGraph, eliminate, convertDeoptimizeToGuardPhase, canonicalizerPhase); + } + + HighTierContext context = new HighTierContext(metaAccessProvider, assumptions, replacements); + PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, new CanonicalizerPhase(true)); + partialEscapePhase.apply(newGraph, context); + + if (newGraph.getNodeCount() > maxNodes && (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue() || TruffleCompilerOptions.TraceTrufflePerformanceWarnings.getValue())) { + TTY.println(String.format("[truffle] PERFORMANCE WARNING: method %s got too large with %d nodes.", newGraph.method(), newGraph.getNodeCount())); + } + } + + private static void contractGraph(StructuredGraph newGraph, ConditionalEliminationPhase eliminate, ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase, + CanonicalizerPhase.Instance canonicalizerPhase) { + // Canonicalize / constant propagate. + canonicalizerPhase.apply(newGraph); + + // Convert deopt to guards. + convertDeoptimizeToGuardPhase.apply(newGraph); + + // Conditional elimination. + eliminate.apply(newGraph); + } + + private void expandGraph(StructuredGraph newGraph, int maxNodes) { + NodeBitMap visitedNodes = newGraph.createNodeBitMap(true); + Queue workQueue = new LinkedList<>(); + workQueue.add(newGraph.start()); + + while (!workQueue.isEmpty() && newGraph.getNodeCount() <= maxNodes) { + AbstractBeginNode start = workQueue.poll(); + expandPath(newGraph, maxNodes, visitedNodes, start, workQueue); + } + } + + private void expandPath(StructuredGraph newGraph, int maxNodes, NodeBitMap visitedNodes, AbstractBeginNode start, Queue workQueue) { + FixedNode next = start; + while (!visitedNodes.isMarked(next)) { + visitedNodes.mark(next); + if (next instanceof Invoke) { + Invoke invoke = (Invoke) next; + next = expandInvoke(invoke); + if (newGraph.getNodeCount() > maxNodes) { + return; + } + } + + if (next instanceof ControlSplitNode) { + ControlSplitNode controlSplitNode = (ControlSplitNode) next; + AbstractBeginNode maxProbNode = null; + for (Node succ : controlSplitNode.cfgSuccessors()) { + AbstractBeginNode successor = (AbstractBeginNode) succ; + if (maxProbNode == null || controlSplitNode.probability(successor) > controlSplitNode.probability(maxProbNode)) { + maxProbNode = successor; + } + } + for (Node succ : controlSplitNode.cfgSuccessors()) { + AbstractBeginNode successor = (AbstractBeginNode) succ; + if (successor != maxProbNode) { + workQueue.add(successor); + } + } + next = maxProbNode; + } else if (next instanceof EndNode) { + EndNode endNode = (EndNode) next; + next = endNode.merge(); + } else if (next instanceof ControlSinkNode) { + return; + } else if (next instanceof FixedWithNextNode) { + FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) next; + next = fixedWithNextNode.next(); + } + } + } + + private FixedNode expandInvoke(Invoke invoke) { + if (invoke.callTarget() instanceof MethodCallTargetNode) { + final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget(); + if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && + !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) { + if (methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) != null) { + // Do not inline explode loop methods, they need canonicalization and forced + // unrolling. + return invoke.asNode(); + } + StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable() { + + public StructuredGraph call() { + StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null) { + inlineGraph = parseGraph(methodCallTargetNode.targetMethod()); + } + return inlineGraph; + } + }); + FixedNode fixedNode = (FixedNode) invoke.predecessor(); + InliningUtil.inline(invoke, inlinedGraph, true); + return fixedNode; + } + } + return invoke.asNode(); + } + + private StructuredGraph parseGraph(ResolvedJavaMethod method) { + StructuredGraph graph = new StructuredGraph(method); + new GraphBuilderPhase(metaAccessProvider, config, optimisticOptimizations).apply(graph); + // Intrinsify methods. + new ReplaceIntrinsicsPhase(replacements).apply(graph); + return graph; + } + + private static boolean checkArgumentStamps(StructuredGraph graph, NodeInputList arguments) { + assert graph.getNodes(LocalNode.class).count() == arguments.count(); + for (LocalNode localNode : graph.getNodes(LocalNode.class)) { + Stamp newStamp = localNode.stamp().meet(arguments.get(localNode.index()).stamp()); + if (!newStamp.equals(localNode.stamp())) { + if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { + TTY.println(String.format("[truffle] graph cache entry too specific for method %s argument %s previous stamp %s new stamp %s.", graph.method(), localNode, localNode.stamp(), + newStamp)); + } + return false; + } + } + + return true; + } +} diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 08 09:58:00 2013 +0200 @@ -62,6 +62,7 @@ private final Backend backend; private final ResolvedJavaType[] skippedExceptionTypes; private final HotSpotGraalRuntime graalRuntime; + private final TruffleCache truffleCache; private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; @@ -75,9 +76,13 @@ this.backend = Graal.getRequiredCapability(Backend.class); this.replacements = ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(); this.graalRuntime = HotSpotGraalRuntime.graalRuntime(); + this.skippedExceptionTypes = getSkippedExceptionTypes(metaAccessProvider); - this.partialEvaluator = new PartialEvaluator(metaAccessProvider, replacements); - this.skippedExceptionTypes = getSkippedExceptionTypes(metaAccessProvider); + final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); + config.setSkippedExceptionTypes(skippedExceptionTypes); + this.truffleCache = new TruffleCache(this.runtime, config, TruffleCompilerImpl.Optimizations, this.replacements); + + this.partialEvaluator = new PartialEvaluator(metaAccessProvider, replacements, truffleCache); if (DebugEnabled.getValue()) { DebugEnvironment.initialize(System.out); @@ -142,7 +147,8 @@ @Override public CompilationResult call() { CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false); - return GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, plan, OptimisticOptimizations.ALL, new SpeculationLog(), suites, new CompilationResult()); + return GraalCompiler.compileGraph(graph, cc, graph.method(), runtime, replacements, backend, runtime.getTarget(), null, plan, OptimisticOptimizations.ALL, new SpeculationLog(), + suites, new CompilationResult()); } }); diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 08 09:58:00 2013 +0200 @@ -53,6 +53,8 @@ public static final OptionValue TruffleFunctionInlining = new OptionValue<>(true); @Option(help = "") public static final OptionValue TruffleConstantUnrollLimit = new OptionValue<>(32); + @Option(help = "") + public static final OptionValue TruffleOperationCacheMaxNodes = new OptionValue<>(200); // tracing @Option(help = "") @@ -60,6 +62,10 @@ @Option(help = "") public static final OptionValue TraceTruffleCompilationDetails = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TraceTruffleCacheDetails = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue TraceTrufflePerformanceWarnings = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TruffleInlinePrinter = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleCompilationExceptions = new OptionValue<>(true); diff -r 703d00fe2703 -r 3c2a77f01e89 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java Mon Jul 08 09:57:14 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java Mon Jul 08 09:58:00 2013 +0200 @@ -41,7 +41,9 @@ if (frame != null) { for (MethodCallTargetNode callTarget : frame.usages().filter(MethodCallTargetNode.class)) { if (callTarget.invoke() != null) { - Throwable exception = new VerificationError("Frame escapes at: %s#%s", callTarget, callTarget.targetMethod()); + String properties = callTarget.getDebugProperties().toString(); + String arguments = callTarget.arguments().toString(); + Throwable exception = new VerificationError("Frame escapes at: %s#%s\nproperties:%s\narguments: %s", callTarget, callTarget.targetMethod(), properties, arguments); throw GraphUtil.approxSourceException(callTarget, exception); } } diff -r 703d00fe2703 -r 3c2a77f01e89 mx/commands.py --- a/mx/commands.py Mon Jul 08 09:57:14 2013 +0200 +++ b/mx/commands.py Mon Jul 08 09:58:00 2013 +0200 @@ -706,8 +706,7 @@ return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses) def _run_tests(args, harness, annotations, testfile): - pos = [a for a in args if a[0] != '-' and a[0] != '@' ] - neg = [a[1:] for a in args if a[0] == '-'] + tests = [a for a in args if a[0] != '@' ] vmArgs = [a[1:] for a in args if a[0] == '@'] def containsAny(c, substrings): @@ -715,17 +714,28 @@ if s in c: return True return False - - classes = [] + + candidates = [] for p in mx.projects(): if mx.java().javaCompliance < p.javaCompliance: continue - classes += _find_classes_with_annotations(p, None, annotations).keys() + candidates += _find_classes_with_annotations(p, None, annotations).keys() - if len(pos) != 0: - classes = [c for c in classes if containsAny(c, pos)] - if len(neg) != 0: - classes = [c for c in classes if not containsAny(c, neg)] + classes = [] + if len(tests) == 0: + classes = candidates + else: + for t in tests: + if t.startswith('-'): + mx.abort('VM option needs @ prefix (i.e., @' + t + ')') + + found = False + for c in candidates: + if t in c: + found = True + classes.append(c) + if not found: + mx.log('warning: no tests matched by substring "' + t) projectscp = mx.classpath([pcp.name for pcp in mx.projects() if pcp.javaCompliance <= mx.java().javaCompliance]) @@ -764,8 +774,7 @@ _unittestHelpSuffix = """ If filters are supplied, only tests whose fully qualified name - includes a filter as a substring are run. Negative filters are - those with a '-' prefix. + includes a filter as a substring are run. Options with a '@' prefix are passed to the VM. diff -r 703d00fe2703 -r 3c2a77f01e89 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Mon Jul 08 09:57:14 2013 +0200 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Mon Jul 08 09:58:00 2013 +0200 @@ -490,7 +490,9 @@ // Total number of GC collections (started) unsigned int total_collections() const { return _total_collections; } unsigned int total_full_collections() const { return _total_full_collections;} - +#ifdef GRAAL + void* total_collections_address() { return &_total_collections;} +#endif // Increment total number of GC collections (started) // Should be protected but used by PSMarkSweep - cleanup for 1.4.2 void increment_total_collections(bool full = false) { diff -r 703d00fe2703 -r 3c2a77f01e89 src/share/vm/graal/graalCompilerToGPU.cpp --- a/src/share/vm/graal/graalCompilerToGPU.cpp Mon Jul 08 09:57:14 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToGPU.cpp Mon Jul 08 09:58:00 2013 +0200 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "graal/graalCompiler.hpp" +#include "runtime/javaCalls.hpp" #include "graal/graalCompilerToVM.hpp" #include "graal/graalEnv.hpp" #include "graal/graalJavaAccess.hpp" diff -r 703d00fe2703 -r 3c2a77f01e89 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Mon Jul 08 09:57:14 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Jul 08 09:58:00 2013 +0200 @@ -907,6 +907,7 @@ set_int("g1SATBQueueBufferOffset", in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf())); set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre); set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post); + set_address("gcTotalCollectionsAddress", (jlong)(address)(Universe::heap()->total_collections_address())); BarrierSet* bs = Universe::heap()->barrier_set(); switch (bs->kind()) {