# HG changeset patch # User Doug Simon # Date 1337697870 -7200 # Node ID 6ec0857cdf46205ae9c52795f86a8f079b8f8cb7 # Parent 441cf24df4531e2fd9300b74074c349e3d3d7b92 added support for snippet templates which are snippet graphs specialized by binding a constant to at least one of the snippet's parameters diff -r 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:42:56 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Tue May 22 16:44:30 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.*; -import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -907,160 +903,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 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:42:56 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Tue May 22 16:44:30 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 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:42:56 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Tue May 22 16:44:30 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); } @@ -415,31 +405,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 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:42:56 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Tue May 22 16:44:30 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 od 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 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:44:30 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 441cf24df453 -r 6ec0857cdf46 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 Tue May 22 16:42:56 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java Tue May 22 16:44:30 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: