# HG changeset patch # User Lukas Stadler # Date 1337939084 -7200 # Node ID 0368c19fc175b9737b354220934f714f96ed6db9 # Parent 141817e206d41a55974aa6fc0914f04ce7e5ab5d# Parent ecba62805b64acc323788b3eb1687fa2e59b2076 Merge diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java Fri May 25 11:44:44 2012 +0200 @@ -157,7 +157,7 @@ if (anchor == null) { anchor = graph.add(new ValueAnchorNode()); } - anchor.addAnchoredValue(guard); + anchor.addAnchoredNode(guard); } if (anchor != null) { graph.addAfterFixed(readNode, anchor); diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Fri May 25 11:44:44 2012 +0200 @@ -29,7 +29,6 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; @@ -111,27 +110,6 @@ } } - protected void run0(final StructuredGraph graph) { - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, true); - - NodeBitMap processed = graph.createNodeBitMap(); - NodeBitMap activeGuards = graph.createNodeBitMap(); - processBlock(cfg.getStartBlock(), activeGuards, processed, null); - - processed.negate(); - final CiLoweringTool loweringTool = new LoweringToolBase(); - for (Node node : processed) { - if (node instanceof CheckCastNode) { - // This is a checkcast that was created while lowering some other node (e.g. StoreIndexed). - // This checkcast must now be LIR lowered. - // TODO (dnsimon) this is temp workaround that will be removed - } else if (node instanceof Lowerable) { - assert !(node instanceof FixedNode) || node.predecessor() == null : node; - ((Lowerable) node).lower(loweringTool); - } - } - } - private void processBlock(Block block, NodeBitMap activeGuards, NodeBitMap processed, FixedNode parentAnchor) { FixedNode anchor = parentAnchor; diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Fri May 25 11:44:44 2012 +0200 @@ -27,14 +27,10 @@ import java.util.concurrent.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Verbosity; -import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -906,160 +902,6 @@ } } - /** - * Performs replacement of a node with a snippet graph. - * @param replacee the node that will be replaced - * @param anchor the control flow replacee - * @param snippetGraph the graph that the replacee will be replaced with - * @param explodeLoops specifies if all the loops in the snippet graph are counted loops that must be completely unrolled - * @param args - */ - public static void inlineSnippet(final RiRuntime runtime, - final Node replacee, - final FixedWithNextNode anchor, - final StructuredGraph snippetGraph, - final boolean explodeLoops, - final IsImmutablePredicate immutabilityPredicate, - final Object... args) { - Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() { - @Override - public void run() { - inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args); - } - }); - } - private static void inlineSnippet0(RiRuntime runtime, - Node replacee, - FixedWithNextNode anchor, - StructuredGraph snippetGraph, - boolean explodeLoops, - IsImmutablePredicate immutabilityPredicate, - Object... args) { - - Debug.dump(replacee.graph(), "Before lowering %s", replacee); - - // Copy snippet graph, replacing parameters with given args in the process - StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); - IdentityHashMap replacements = new IdentityHashMap<>(); - replacements.put(snippetGraph.start(), snippetCopy.start()); - int localCount = 0; - for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) { - int index = local.index(); - if (args[index] instanceof CiConstant) { - CiConstant arg = (CiConstant) args[index]; - assert arg.kind.stackKind() == local.kind() : arg.kind + " != " + local.kind(); - ConstantNode argNode = ConstantNode.forCiConstant(arg, runtime, snippetCopy); - replacements.put(local, argNode); - args[index] = null; - } else { - assert args[index] instanceof ValueNode; - } - localCount++; - } - assert localCount == args.length : "snippet argument count mismatch"; - snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); - if (!replacements.isEmpty()) { - new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy); - } - - // Explode all loops in the snippet if requested - if (explodeLoops && 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++; - } - Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); - } - new DeadCodeEliminationPhase().apply(snippetCopy); - } - - // Gather the nodes in the snippet that are to be inlined - ArrayList nodes = new ArrayList<>(); - ReturnNode returnNode = null; - StartNode entryPointNode = snippetCopy.start(); - FixedNode firstCFGNode = entryPointNode.next(); - replacements.clear(); - for (Node node : snippetCopy.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else if (node instanceof LocalNode) { - LocalNode local = (LocalNode) node; - int index = local.index(); - assert args[index] instanceof ValueNode; - ValueNode arg = (ValueNode) args[index]; - assert arg.kind() == local.kind(); - replacements.put(node, arg); - args[index] = null; - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - returnNode = (ReturnNode) node; - } - } - } - - // Inline the gathered snippet nodes - StructuredGraph graph = (StructuredGraph) replacee.graph(); - int mark = graph.getMark(); - Map duplicates = graph.addDuplicates(nodes, replacements); - Debug.dump(graph, "After inlining snippet %s", snippetCopy.method()); - - // Remove all frame states from the inlined snippet graph. Snippets must be atomic (i.e. free - // of side-effects that prevent deoptimizing to a point before the snippet). - for (Node node : graph.getNewNodes(mark)) { - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n " + frameState.toString(Verbosity.Debugger); - if (frameState != null) { - stateSplit.setStateAfter(null); - } - } - } - - Debug.dump(graph, "After removing frame states"); - - // Rewire the control flow graph around the replacee - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - anchor.replaceAtPredecessors(firstCFGNodeDuplicate); - FixedNode next = anchor.next(); - anchor.setNext(null); - - // Replace all usages of the replacee with the value returned by the snippet - Node returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = replacements.get(returnNode.result()); - } else { - returnValue = duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacee.replaceAtUsages(returnValue); - - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - } - - // Remove the replacee from its graph - replacee.clearInputs(); - replacee.replaceAtUsages(null); - if (replacee instanceof FixedNode) { - GraphUtil.killCFG((FixedNode) replacee); - } else { - replacee.safeDelete(); - } - } - public static void receiverNullCheck(Invoke invoke) { MethodCallTargetNode callTarget = invoke.callTarget(); StructuredGraph graph = (StructuredGraph) invoke.graph(); diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugDumpScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugDumpScope.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugDumpScope.java Fri May 25 11:44:44 2012 +0200 @@ -22,16 +22,24 @@ */ package com.oracle.graal.debug; -public final class DebugDumpScope { +public class DebugDumpScope { + + public final String name; - private final String name; + /** + * Specifies if this scope decorates an inner scope. + * A hierarchical or tree representation of nested scopes may choose to represent + * a decorator scope at the same level as the scope it decorates. + */ + public final boolean decorator; public DebugDumpScope(String name) { - this.name = name; + this(name, false); } - public String getName() { - return name; + public DebugDumpScope(String name, boolean decorator) { + this.name = name; + this.decorator = decorator; } @Override diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Fri May 25 11:44:44 2012 +0200 @@ -509,7 +509,11 @@ * @param replacements the replacement map (can be null if no replacement is to be performed) * @return a map which associates the original nodes from {@code nodes} to their duplicates */ + @SuppressWarnings("all") public Map addDuplicates(Iterable newNodes, Map replacements) { + if (replacements == null) { + replacements = Collections.emptyMap(); + } return NodeClass.addGraphDuplicate(this, newNodes, replacements); } } diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java Fri May 25 11:44:44 2012 +0200 @@ -0,0 +1,59 @@ +/* + * 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.graph.iterators; + +import java.util.*; + +import com.oracle.graal.graph.*; + + +public class DistinctPredicatedProxyNodeIterator extends PredicatedProxyNodeIterator { + private NodeBitMap visited; + + public DistinctPredicatedProxyNodeIterator(NodePredicate until, Iterator iterator, NodePredicate predicate) { + super(until, iterator, predicate); + } + + @Override + protected void forward() { + if (current == null) { + super.forward(); + while (!accept(current)) { + current = null; + super.forward(); + } + } + } + + private boolean accept(T n) { + if (n == null) { + return true; + } + if (visited == null) { + visited = n.graph().createNodeBitMap(true); + } + boolean accept = !visited.isMarked(n); + visited.mark(n); + return accept; + } +} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java Fri May 25 11:44:44 2012 +0200 @@ -30,6 +30,7 @@ private final NodeIterable nodeIterable; private NodePredicate predicate = NodePredicates.alwaysTrue(); private NodePredicate until = NodePredicates.isNull(); + private boolean distinct; public FilteredNodeIterable(NodeIterable nodeIterable) { this.nodeIterable = nodeIterable; } @@ -52,9 +53,23 @@ return this; } @Override + public FilteredNodeIterable nonNull() { + this.predicate = this.predicate.or(NodePredicates.isNotNull()); + return this; + } + @Override + public FilteredNodeIterable distinct() { + distinct = true; + return this; + } + @Override public Iterator iterator() { final Iterator iterator = nodeIterable.iterator(); - return new PredicatedProxyNodeIterator<>(until, iterator, predicate); + if (distinct) { + return new DistinctPredicatedProxyNodeIterator<>(until, iterator, predicate); + } else { + return new PredicatedProxyNodeIterator<>(until, iterator, predicate); + } } @SuppressWarnings("unchecked") diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java Fri May 25 11:44:44 2012 +0200 @@ -46,6 +46,9 @@ public FilteredNodeIterable nonNull() { return new FilteredNodeIterable<>(this).and(NodePredicates.isNotNull()); } + public FilteredNodeIterable distinct() { + return new FilteredNodeIterable<>(this).distinct(); + } public List snapshot() { ArrayList list = new ArrayList<>(); for (T n : this) { diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/PredicatedProxyNodeIterator.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/PredicatedProxyNodeIterator.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/PredicatedProxyNodeIterator.java Fri May 25 11:44:44 2012 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -26,7 +26,7 @@ import com.oracle.graal.graph.*; -public final class PredicatedProxyNodeIterator extends NodeIterator { +public class PredicatedProxyNodeIterator extends NodeIterator { private final Iterator iterator; private final NodePredicate predicate; private final NodePredicate until; diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri May 25 11:44:44 2012 +0200 @@ -111,7 +111,7 @@ CiTargetMethod result = null; TTY.Filter filter = new TTY.Filter(GraalOptions.PrintFilter, method); try { - result = Debug.scope("Compiling", new Callable() { + result = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable() { @Override public CiTargetMethod call() throws Exception { @@ -148,7 +148,7 @@ } private void installMethod(final CiTargetMethod tm) { - Debug.scope("CodeInstall", new Object[] {compiler.getCompiler(), method}, new Runnable() { + Debug.scope("CodeInstall", new Object[] {new DebugDumpScope(String.valueOf(id), true), compiler.getCompiler(), method}, new Runnable() { @Override public void run() { final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null; diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Fri May 25 11:44:44 2012 +0200 @@ -40,7 +40,7 @@ */ public final Class javaMirror; - HotSpotKlassOop(Compiler compiler, Class javaMirror) { + public HotSpotKlassOop(Compiler compiler, Class javaMirror) { super(compiler); this.javaMirror = javaMirror; } diff -r 141817e206d4 -r 0368c19fc175 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 May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Fri May 25 11:44:44 2012 +0200 @@ -28,10 +28,8 @@ import java.util.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.target.*; -import com.oracle.graal.compiler.util.*; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; @@ -65,7 +63,7 @@ final HotSpotRegisterConfig regConfig; private final HotSpotRegisterConfig globalStubRegConfig; private final Compiler compiler; - private RiResolvedMethod checkcastSnippet; + private CheckCastSnippets.Templates checkcasts; public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) { this.config = config; @@ -81,15 +79,7 @@ Snippets.install(this, compiler.getTarget(), new UnsafeSnippets()); Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets()); Snippets.install(this, compiler.getTarget(), new CheckCastSnippets()); - try { - if (GraalOptions.CheckcastCounters) { - checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastWithCounters", Object.class, Object.class, Object[].class, boolean.class, Counter.class)); - } else { - checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class)); - } - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } + checkcasts = new CheckCastSnippets.Templates(this); } @@ -416,31 +406,30 @@ graph.replaceFixed(objectClassNode, memoryRead); } else if (n instanceof CheckCastNode) { if (shouldLowerCheckcast(graph)) { - final Map hintHubsSet = new IdentityHashMap<>(); - IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() { - public boolean apply(CiConstant constant) { - return hintHubsSet.containsKey(constant); - } - }; 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); - StructuredGraph snippetGraph = (StructuredGraph) checkcastSnippet.compilerStorage().get(Graph.class); - assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed"; HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length]; for (int i = 0; i < hintHubs.length; i++) { hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop(); } - final CiConstant hintHubsConst = CiConstant.forObject(hintHubs); - hintHubsSet.put(hintHubsConst, hintHubsConst); 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) { - Counter noHintsCounter = checkcast.targetClass() == null ? Counter.noHints_unknown : checkcast.targetClass().isInterface() ? Counter.noHints_iface : Counter.noHints_class; - InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact), CiConstant.forObject(noHintsCounter)); + if (checkcast.targetClass() == null) { + noHintsCounter = Counter.noHints_unknown; + } else if (checkcast.targetClass().isInterface()) { + noHintsCounter = Counter.noHints_iface; + } else { + noHintsCounter = Counter.noHints_class; + } } else { - InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact)); + 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); } } else { diff -r 141817e206d4 -r 0368c19fc175 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 May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Fri May 25 11:44:44 2012 +0200 @@ -22,9 +22,11 @@ */ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*; +import static com.oracle.graal.snippets.SnippetTemplate.*; import java.io.*; import java.util.*; +import java.util.concurrent.*; import sun.misc.*; @@ -33,6 +35,7 @@ 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.*; @@ -52,11 +55,12 @@ * @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 */ @Snippet - public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) { + public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) { if (object == null) { return object; } @@ -108,7 +112,7 @@ /** * Increments this counter if counters are enabled. The body of this method has been carefully crafted * such that it contains no safepoints and no calls, neither of which are permissible in a snippet. - * Also, increments are not guaranteed to be atomic but that's acceptable for a counter like this. + * Also, increments are not guaranteed to be atomic which is acceptable for a counter. */ void inc() { if (ENABLED) { @@ -120,11 +124,8 @@ static final boolean ENABLED = GraalOptions.CheckcastCounters; } - /** - * @see #checkcast(Object, Object, Object[], boolean) - */ @Snippet - public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, Counter noHintsCounter) { + public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) { if (object == null) { isNull.inc(); return object; @@ -169,11 +170,6 @@ return CompilerImpl.getInstance().getConfig().hubOffset; } - @Fold - private static boolean isInterface(RiResolvedType type) { - return type.isInterface(); - } - public static void printCounter(PrintStream out, Counter c, long total) { double percent = total == 0D ? 0D : ((double) (c.count * 100)) / total; out.println(String.format("%16s: %5.2f%%%10d // %s", c.name(), percent, c.count, c.description)); @@ -208,4 +204,55 @@ printCounter(out, c, total); } } + + /** + * Templates for partially specialized checkcast snippet graphs. + */ + public static class Templates { + + private final ConcurrentHashMap templates; + private final RiResolvedMethod method; + 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)); + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + /** + * Gets a checkcast snippet specialized for a given set of inputs. + */ + public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) { + Integer key = key(nHints, isExact, checkNull); + 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); + templates.put(key, result); + } + return result; + } + + /** + * Creates a canonical key for a combination of specialization parameters. + */ + private static Integer key(int nHints, boolean isExact, boolean checkNull) { + int key = nHints << 2; + if (isExact) { + key |= 2; + } + if (checkNull) { + key |= 1; + } + return key; + } + } } diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Fri May 25 11:44:44 2012 +0200 @@ -44,8 +44,10 @@ // Nothing to emit, since this node is used for structural purposes only. } - public void addAnchoredValue(ValueNode value) { - this.dependencies().add(value); + public void addAnchoredNode(ValueNode value) { + if (!this.dependencies().contains(value)) { + this.dependencies().add(value); + } } @Override @@ -53,8 +55,8 @@ if (this.predecessor() instanceof ValueAnchorNode) { // transfer values and remove ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor(); - for (ValueNode node : dependencies().nonNull()) { - previousAnchor.dependencies().add(node); + for (ValueNode node : dependencies().nonNull().distinct()) { + previousAnchor.addAnchoredNode(node); } return null; } diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Fri May 25 11:44:44 2012 +0200 @@ -47,6 +47,7 @@ private CFGPrinter cfgPrinter; private RiResolvedMethod curMethod; + private List curDecorators = Collections.emptyList(); @Override public void dump(Object object, String message) { @@ -57,14 +58,37 @@ } } - private static RiResolvedMethod lookupMethod() { - RiResolvedMethod method = Debug.contextLookup(RiResolvedMethod.class); - if (method != null) { - return method; + /** + * Looks for the outer most method and its {@link DebugDumpScope#decorator}s + * in the current debug scope and opens a new compilation scope if this pair + * does not match the current method and decorator pair. + */ + private void checkMethodScope() { + RiResolvedMethod method = null; + ArrayList decorators = new ArrayList<>(); + for (Object o : Debug.context()) { + if (o instanceof RiResolvedMethod) { + method = (RiResolvedMethod) o; + decorators.clear(); + } else if (o instanceof StructuredGraph) { + StructuredGraph graph = (StructuredGraph) o; + assert graph != null && graph.method() != null : "cannot find method context for CFG dump"; + method = graph.method(); + decorators.clear(); + } else if (o instanceof DebugDumpScope) { + DebugDumpScope debugDumpScope = (DebugDumpScope) o; + if (debugDumpScope.decorator) { + decorators.add(debugDumpScope.name); + } + } } - StructuredGraph graph = Debug.contextLookup(StructuredGraph.class); - assert graph != null && graph.method() != null : "cannot find method context for CFG dump"; - return graph.method(); + + if (method != curMethod || !curDecorators.equals(decorators)) { + cfgPrinter.printCompilation(method); + TTY.println("CFGPrinter: Dumping method %s", method); + curMethod = method; + curDecorators = decorators; + } } public void dumpSandboxed(Object object, String message) { @@ -84,13 +108,7 @@ TTY.println("CFGPrinter: Output to file %s", file); } - RiResolvedMethod newMethod = lookupMethod(); - - if (newMethod != curMethod) { - cfgPrinter.printCompilation(newMethod); - TTY.println("CFGPrinter: Dumping method %s", newMethod); - curMethod = newMethod; - } + checkMethodScope(); cfgPrinter.target = compiler.target; if (object instanceof LIR) { diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java Fri May 25 11:44:44 2012 +0200 @@ -123,7 +123,7 @@ for (int i = 0; i < inlineContext.size(); ++i) { if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) { for (int j = i; j < inlineContext.size(); ++j) { - openScope(inlineContext.get(j)); + openScope(inlineContext.get(j), j == 0); } break; } @@ -153,14 +153,19 @@ result.add(CiUtil.format("%H::%n(%p)", method)); } else if (o instanceof DebugDumpScope) { DebugDumpScope debugDumpScope = (DebugDumpScope) o; - result.add(debugDumpScope.getName()); + if (debugDumpScope.decorator && !result.isEmpty()) { + result.set(result.size() - 1, debugDumpScope.name + ":" + result.get(result.size() - 1)); + } else { + result.add(debugDumpScope.name); + } } } return result; } - private void openScope(String name) { - printer.beginGroup(Thread.currentThread().getName() + ":" + name, name, Debug.contextLookup(RiResolvedMethod.class), -1); + private void openScope(String name, boolean showThread) { + String prefix = showThread ? Thread.currentThread().getName() + ":" : ""; + printer.beginGroup(prefix + name, name, Debug.contextLookup(RiResolvedMethod.class), -1); } private void closeScope() { diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Fri May 25 11:44:44 2012 +0200 @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2011, 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; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; + +/** + * A snippet template is a graph created by parsing a snippet method and then + * specialized by binding constants to some of the snippet arguments and applying + * transformations such as canonicalization and loop peeling. + */ +public class SnippetTemplate { + + /** + * Special value denoting a non-specialized argument. + */ + public static final Object _ = new Object() { + @Override + public String toString() { + return "_"; + } + }; + + /** + * Creates a snippet template. + * + * @param runtime + * @param method the snippet method to create the initial graph from + * @param args the arguments used to specialize the graph + */ + public static SnippetTemplate create(final RiRuntime runtime, final RiResolvedMethod method, final Object... args) { + return Debug.scope("SnippetSpecialization", method, new Callable() { + @Override + public SnippetTemplate call() throws Exception { + assert Modifier.isStatic(method.accessFlags()) : "snippet method must be static: " + method; + RiSignature signature = method.signature(); + assert signature.argumentCount(false) == args.length : "snippet method expects " + signature.argumentCount(false) + " arguments, " + args.length + " given"; + StructuredGraph snippetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class); + + final Map constantArrays = new IdentityHashMap<>(); + IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() { + public boolean apply(CiConstant constant) { + return constantArrays.containsKey(constant); + } + }; + + // Copy snippet graph, replacing parameters with given args in the process + StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); + IdentityHashMap replacements = new IdentityHashMap<>(); + replacements.put(snippetGraph.start(), snippetCopy.start()); + int localCount = 0; + for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) { + int index = local.index(); + Object arg = args[index]; + if (arg != _) { + CiKind kind = signature.argumentKindAt(index, false); + assert kind.isObject() || (arg != null && kind.toBoxedJavaClass() == arg.getClass()) : + "arg " + index + " for " + method + " has wrong kind: expected " + kind + ", got " + (arg == null ? "null" : arg.getClass().getSimpleName()); + CiConstant specializationArg = CiConstant.forBoxed(kind, arg); + if (kind.isObject()) { + assert arg == null || signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().isInstance(arg) : + String.format("argument %d is of wrong type: expected %s, got %s", index, signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().getName(), arg.getClass().getName()); + if (arg != null) { + if (arg.getClass().isArray()) { + constantArrays.put(specializationArg, specializationArg); + } + } + } + + ConstantNode argNode = ConstantNode.forCiConstant(specializationArg, runtime, snippetCopy); + replacements.put(local, argNode); + } + localCount++; + } + assert localCount == args.length : "snippet argument count mismatch"; + snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); + + Debug.dump(snippetCopy, "Before specialization"); + + if (!replacements.isEmpty()) { + 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++; + } + Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); + } + } + + // 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). + for (Node node : snippetCopy.getNodes()) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n " + frameState.toString(Verbosity.Debugger); + if (frameState != null) { + stateSplit.setStateAfter(null); + } + } + } + + new DeadCodeEliminationPhase().apply(snippetCopy); + return new SnippetTemplate(args, snippetCopy); + } + }); + } + + SnippetTemplate(Object[] args, StructuredGraph graph) { + Object[] flattenedArgs = flatten(args); + this.graph = graph; + this.parameters = new Object[flattenedArgs.length]; + + // Find the constant nodes corresponding to the flattened positional parameters + for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) { + if (node.kind().isObject()) { + CiConstant constant = node.asConstant(); + if (constant.kind.isObject() && !constant.isNull()) { + for (int i = 0; i < flattenedArgs.length; i++) { + if (flattenedArgs[i] == constant.asObject()) { + parameters[i] = node; + } + } + } + } + } + + // Find the local nodes corresponding to the flattened positional parameters + int localIndex = 0; + for (int i = 0; i < flattenedArgs.length; i++) { + if (flattenedArgs[i] == _) { + for (LocalNode local : graph.getNodes(LocalNode.class)) { + if (local.index() == localIndex) { + assert parameters[i] == null; + parameters[i] = local; + } + } + localIndex++; + } else { + Object param = parameters[i]; + if (param == null) { + parameters[i] = flattenedArgs[i]; + } else { + assert param instanceof ConstantNode; + assert ((ConstantNode) param).kind().isObject(); + } + } + } + + nodes = new ArrayList<>(graph.getNodeCount()); + ReturnNode retNode = null; + StartNode entryPointNode = graph.start(); + for (Node node : graph.getNodes()) { + if (node == entryPointNode || node == entryPointNode.stateAfter()) { + // Do nothing. + } else { + nodes.add(node); + if (node instanceof ReturnNode) { + retNode = (ReturnNode) node; + } + } + } + this.returnNode = retNode; + } + + /** + * The graph built from the snippet method. + */ + public final StructuredGraph graph; + + /** + * The flattened positional parameters of this snippet. + * A {@link LocalNode} element is bound to a {@link ValueNode} to be supplied during + * instantiation, a {@link ConstantNode} is replaced by an object constant and any + * other element denotes an input fixed during specialization. + */ + public final Object[] parameters; + + /** + * The return node (if any) of the snippet. + */ + public final ReturnNode returnNode; + + /** + * The nodes to be inlined when this specialization is instantiated. + */ + public final ArrayList nodes; + + private IdentityHashMap replacements(StructuredGraph replaceeGraph, RiRuntime runtime, Object... args) { + Object[] flattenedArgs = flatten(args); + IdentityHashMap replacements = new IdentityHashMap<>(); + assert parameters.length >= flattenedArgs.length; + for (int i = 0; i < flattenedArgs.length; i++) { + Object param = parameters[i]; + Object arg = flattenedArgs[i]; + if (arg == null) { + assert !(param instanceof ValueNode) : param; + } else if (arg instanceof ValueNode) { + assert param instanceof LocalNode; + replacements.put((LocalNode) param, (ValueNode) arg); + } else { + replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph)); + } + } + return replacements; + } + + /** + * Replaces a given node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param anchor the control flow replacee + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(RiRuntime runtime, + Node replacee, + FixedWithNextNode anchor, Object... args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = graph.name == null ? "{copy}" : graph.name + "{copy}"; + StructuredGraph graphCopy = new StructuredGraph(name, graph.method()); + StartNode entryPointNode = graph.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap replacements = replacements(replaceeGraph, runtime, args); + Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", graphCopy.method()); + + // Re-wire the control flow graph around the replacee + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + anchor.replaceAtPredecessors(firstCFGNodeDuplicate); + FixedNode next = anchor.next(); + anchor.setNext(null); + + // Replace all usages of the replacee with the value returned by the snippet + Node returnValue = null; + if (returnNode != null) { + if (returnNode.result() instanceof LocalNode) { + returnValue = replacements.get(returnNode.result()); + } else { + returnValue = duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacee.replaceAtUsages(returnValue); + + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + } + + // Remove the replacee from its graph + replacee.clearInputs(); + replacee.replaceAtUsages(null); + if (replacee instanceof FixedNode) { + GraphUtil.killCFG((FixedNode) replacee); + } else { + replacee.safeDelete(); + } + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + /** + * Flattens a list of objects by replacing any array in {@code args} with its elements. + */ + private static Object[] flatten(Object... args) { + List list = new ArrayList<>(args.length * 2); + for (Object o : args) { + if (o instanceof Object[]) { + list.addAll(Arrays.asList((Object[]) o)); + } else { + list.add(o); + } + } + return list.toArray(new Object[list.size()]); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(graph.toString()).append('('); + for (int i = 0; i < parameters.length; i++) { + Object param = parameters[i]; + if (param instanceof ConstantNode) { + buf.append(((ConstantNode) param).asConstant().asObject()); + } else if (param instanceof LocalNode) { + buf.append('_'); + } else { + buf.append(param); + } + if (i != parameters.length - 1) { + buf.append(", "); + } + } + return buf.append(')').toString(); + } +} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java Fri May 25 11:44:44 2012 +0200 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011, 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; + +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.max.cri.ri.*; + +/** + * Tests the implementation of checkcast, allowing profiling information to + * be manually specified. + */ +public class CheckCastTest extends TypeCheckTest { + + @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)); + graph.replaceFixedWithFixed(ccn, ccnNew); + } + } + + @Test + public void test1() { + test("asNumber", profile(), 111); + test("asNumber", profile(Integer.class), 111); + test("asNumber", profile(Long.class, Short.class), 111); + test("asNumberExt", profile(), 111); + test("asNumberExt", profile(Integer.class), 111); + test("asNumberExt", profile(Long.class, Short.class), 111); + } + + @Test + public void test2() { + test("asString", profile(), "111"); + test("asString", profile(String.class), "111"); + test("asString", profile(String.class), "111"); + + final String nullString = null; + test("asString", profile(), nullString); + test("asString", profile(String.class), nullString); + test("asString", profile(String.class), nullString); + + test("asStringExt", profile(), "111"); + test("asStringExt", profile(String.class), "111"); + test("asStringExt", profile(String.class), "111"); + } + + @Test + public void test3() { + test("asNumber", profile(), "111"); + } + + @Test + public void test4() { + test("asString", profile(String.class), 111); + } + + @Test + public void test5() { + test("asNumberExt", profile(), "111"); + } + + @Test + public void test6() { + test("asStringExt", profile(String.class), 111); + } + + public static Number asNumber(Object o) { + return (Number) o; + } + + public static String asString(Object o) { + return (String) o; + } + + public static Number asNumberExt(Object o) { + Number n = (Number) o; + return n.intValue() + 10; + } + + public static String asStringExt(Object o) { + String s = (String) o; + 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; + } +} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Fri May 25 11:44:44 2012 +0200 @@ -68,8 +68,7 @@ } final RiResolvedMethod riMethod = runtime.getRiMethod(method); - CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = compile(riMethod, graph); try { Object result = compiledMethod.execute("1", "2", "3"); Assert.assertEquals("1-2-3", result); @@ -83,8 +82,7 @@ Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); final RiResolvedMethod riMethod = runtime.getRiMethod(method); - CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = compile(riMethod, graph); try { Object result = compiledMethod.executeVarargs("1", "2", "3"); Assert.assertEquals("1 2 3", result); @@ -98,8 +96,7 @@ Method method = getMethod("testMethodVirtual"); final StructuredGraph graph = parse(method); final RiResolvedMethod riMethod = runtime.getRiMethod(method); - CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = compile(riMethod, graph); try { f1 = "0"; Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); @@ -127,9 +124,7 @@ } } - CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - final RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); - + RiCompiledMethod compiledMethod = compile(riMethod, graph); final CompilableObject compilableObject = new CompilableObjectImpl(0); Object result; diff -r 141817e206d4 -r 0368c19fc175 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 May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Fri May 25 11:44:44 2012 +0200 @@ -146,6 +146,17 @@ } } + private static int compilationId = 0; + + protected RiCompiledMethod compile(final RiResolvedMethod method, final StructuredGraph graph) { + return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable() { + public RiCompiledMethod call() throws Exception { + CiTargetMethod targetMethod = runtime.compile(method, graph); + return addMethod(method, targetMethod); + } + }); + } + protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) { Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { @Override diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfTest.java Fri May 25 11:44:44 2012 +0200 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011, 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; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.max.cri.ri.*; + +/** + * Tests the implementation of instanceof, allowing profiling information to + * be manually specified. + */ +public class InstanceOfTest extends TypeCheckTest { + + @Override + protected void replaceProfile(StructuredGraph graph, RiTypeProfile profile) { + InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); + if (ion != null) { + InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.targetClassInstruction(), ion.targetClass(), ion.object(), profile)); + graph.replaceFloating(ion, ionNew); + } + } + + @Test + public void test1() { + test("isString", profile(), "object"); + test("isString", profile(String.class), "object"); + + test("isString", profile(), Object.class); + test("isString", profile(String.class), Object.class); + } + + @Test + public void test2() { + test("isStringInt", profile(), "object"); + test("isStringInt", profile(String.class), "object"); + + test("isStringInt", profile(), Object.class); + test("isStringInt", profile(String.class), Object.class); + } + + @Test + public void test3() { + Throwable throwable = new Exception(); + test("isThrowable", profile(), throwable); + test("isThrowable", profile(Throwable.class), throwable); + test("isThrowable", profile(Exception.class, Error.class), throwable); + + test("isThrowable", profile(), Object.class); + test("isThrowable", profile(Throwable.class), Object.class); + test("isThrowable", profile(Exception.class, Error.class), Object.class); + } + + @Test + public void test4() { + Throwable throwable = new Exception(); + test("isThrowableInt", profile(), throwable); + test("isThrowableInt", profile(Throwable.class), throwable); + test("isThrowableInt", profile(Exception.class, Error.class), throwable); + + test("isThrowableInt", profile(), Object.class); + test("isThrowableInt", profile(Throwable.class), Object.class); + test("isThrowableInt", profile(Exception.class, Error.class), Object.class); + } + + @Test + public void test5() { + Map map = new HashMap<>(); + test("isMap", profile(), map); + test("isMap", profile(HashMap.class), map); + test("isMap", profile(TreeMap.class, HashMap.class), map); + + test("isMap", profile(), Object.class); + test("isMap", profile(HashMap.class), Object.class); + test("isMap", profile(TreeMap.class, HashMap.class), Object.class); + } + + @Test + public void test6() { + Map map = new HashMap<>(); + test("isMapInt", profile(), map); + test("isMapInt", profile(HashMap.class), map); + test("isMapInt", profile(TreeMap.class, HashMap.class), map); + + test("isMapInt", profile(), Object.class); + test("isMapInt", profile(HashMap.class), Object.class); + test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); + } + + public static boolean isString(Object o) { + return o instanceof String; + } + + public static int isStringInt(Object o) { + if (o instanceof String) { + return 1; + } + return 0; + } + + public static boolean isThrowable(Object o) { + return o instanceof Throwable; + } + + public static int isThrowableInt(Object o) { + if (o instanceof Throwable) { + return 1; + } + return 0; + } + + public static boolean isMap(Object o) { + return o instanceof Map; + } + + public static int isMapInt(Object o) { + if (o instanceof Map) { + return 1; + } + return 0; + } +} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java Fri May 25 11:35:18 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2011, 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; - -import java.lang.reflect.*; - -import org.junit.*; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType; - -public class LowerCheckCastTest extends GraphTest { - - private RiCompiledMethod compile(Method method, RiTypeProfile profile) { - final StructuredGraph graph = parse(method); - - CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); - if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile)); - graph.replaceFixedWithFixed(ccn, ccnNew); - } - - final RiResolvedMethod riMethod = runtime.getRiMethod(method); - CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - return addMethod(riMethod, targetMethod); - } - - private RiTypeProfile profile(Class... types) { - if (types.length == 0) { - return null; - } - ProfiledType[] ptypes = new ProfiledType[types.length]; - for (int i = 0; i < types.length; i++) { - ptypes[i] = new ProfiledType(runtime.getType(types[i]), 1.0D / types.length); - } - return new RiTypeProfile(0.0D, ptypes); - } - - private void test(String name, RiTypeProfile profile, Object... args) { - Method method = getMethod(name); - Object expect = null; - Throwable exception = null; - try { - // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved - expect = method.invoke(null, args); - } catch (InvocationTargetException e) { - exception = e.getTargetException(); - } catch (Exception e) { - throw new RuntimeException(e); - } - RiCompiledMethod compiledMethod = compile(method, profile); - compiledMethod.method(); - - if (exception != null) { - try { - compiledMethod.executeVarargs(args); - Assert.fail("expected " + exception); - } catch (Throwable e) { - Assert.assertEquals(exception.getClass(), e.getClass()); - } - } else { - Object actual = compiledMethod.executeVarargs(args); - Assert.assertEquals(expect, actual); - } - } - - @Test - public void test1() { - test("asNumber", profile(), 111); - test("asNumber", profile(Integer.class), 111); - test("asNumber", profile(Long.class, Short.class), 111); - test("asNumberExt", profile(), 111); - test("asNumberExt", profile(Integer.class), 111); - test("asNumberExt", profile(Long.class, Short.class), 111); - } - - @Test - public void test2() { - test("asString", profile(), "111"); - test("asString", profile(String.class), "111"); - test("asString", profile(String.class), "111"); - - final String nullString = null; - test("asString", profile(), nullString); - test("asString", profile(String.class), nullString); - test("asString", profile(String.class), nullString); - - test("asStringExt", profile(), "111"); - test("asStringExt", profile(String.class), "111"); - test("asStringExt", profile(String.class), "111"); - } - - @Test - public void test3() { - test("asNumber", profile(), "111"); - } - - @Test - public void test4() { - test("asString", profile(String.class), 111); - } - - @Test - public void test5() { - test("asNumberExt", profile(), "111"); - } - - @Test - public void test6() { - test("asStringExt", profile(String.class), 111); - } - - public static Number asNumber(Object o) { - return (Number) o; - } - - public static String asString(Object o) { - return (String) o; - } - - public static Number asNumberExt(Object o) { - Number n = (Number) o; - return n.intValue() + 10; - } - - public static String asStringExt(Object o) { - String s = (String) o; - 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; - } -} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java Fri May 25 11:44:44 2012 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, 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; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType; + +/** + * Base class for checkcast and instanceof test classes. + */ +public abstract class TypeCheckTest extends GraphTest { + + protected abstract void replaceProfile(StructuredGraph graph, RiTypeProfile profile); + + private RiCompiledMethod compile(Method method, RiTypeProfile profile) { + final StructuredGraph graph = parse(method); + replaceProfile(graph, profile); + return compile(runtime.getRiMethod(method), graph); + } + + protected RiTypeProfile profile(Class... types) { + if (types.length == 0) { + return null; + } + ProfiledType[] ptypes = new ProfiledType[types.length]; + for (int i = 0; i < types.length; i++) { + ptypes[i] = new ProfiledType(runtime.getType(types[i]), 1.0D / types.length); + } + return new RiTypeProfile(0.0D, ptypes); + } + + protected void test(String name, RiTypeProfile profile, Object... args) { + Method method = getMethod(name); + Object expect = null; + Throwable exception = null; + try { + // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved + expect = method.invoke(null, args); + } catch (InvocationTargetException e) { + exception = e.getTargetException(); + } catch (Exception e) { + throw new RuntimeException(e); + } + RiCompiledMethod compiledMethod = compile(method, profile); + compiledMethod.method(); + + if (exception != null) { + try { + compiledMethod.executeVarargs(args); + Assert.fail("expected " + exception); + } catch (Throwable e) { + Assert.assertEquals(exception.getClass(), e.getClass()); + } + } else { + Object actual = compiledMethod.executeVarargs(args); + Assert.assertEquals(expect, actual); + } + } +} diff -r 141817e206d4 -r 0368c19fc175 graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java Fri May 25 11:35:18 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java Fri May 25 11:44:44 2012 +0200 @@ -473,6 +473,8 @@ */ public static CiConstant forBoxed(CiKind kind, Object value) { switch (kind) { + case Boolean: + return forBoolean((Boolean) value); case Byte: return forByte((Byte) value); case Char: diff -r 141817e206d4 -r 0368c19fc175 mx/commands.py --- a/mx/commands.py Fri May 25 11:35:18 2012 +0200 +++ b/mx/commands.py Fri May 25 11:44:44 2012 +0200 @@ -736,6 +736,10 @@ args = parser.parse_args(args) + global _vmbuild + global _vm + global _jacoco + tasks = [] total = Task('Gate') try: @@ -752,9 +756,7 @@ t = Task('BuildJava') build(['--no-native']) tasks.append(t.stop()) - global _jacoco for vmbuild in ['fastdebug', 'product']: - global _vmbuild _vmbuild = vmbuild if args.buildNative: @@ -816,6 +818,15 @@ t = Task('BuildHotSpotVarieties') buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product']) tasks.append(t.stop()) + + for vmbuild in ['product', 'fastdebug']: + _vmbuild = vmbuild + for theVm in ['client', 'server']: + _vm = theVm + + t = Task('DaCapo_pmd:' + theVm + ':' + vmbuild) + dacapo(['pmd']) + tasks.append(t.stop()) except KeyboardInterrupt: total.abort(1) diff -r 141817e206d4 -r 0368c19fc175 src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Fri May 25 11:35:18 2012 +0200 +++ b/src/share/vm/runtime/vframeArray.cpp Fri May 25 11:44:44 2012 +0200 @@ -252,7 +252,9 @@ case Deoptimization::Unpack_uncommon_trap: case Deoptimization::Unpack_reexecute: // redo last byte code +#ifdef GRAAL assert(should_reexecute(), ""); +#endif pc = Interpreter::deopt_entry(vtos, 0); use_next_mdp = false; break;