# HG changeset patch # User Lukas Stadler # Date 1336558296 -7200 # Node ID c7f92c6246ba0d4d00b8076f6e1d7bc276c10f76 # Parent 1436de7b7caba63e86c853bac41429c75821f018# Parent 67e63e8dcbd23c539ee341d58a682ab829552a18 Merge diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Wed May 09 12:11:36 2012 +0200 @@ -29,7 +29,7 @@ public class InsertStateAfterPlaceholderPhase extends Phase { - private static class PlaceholderNode extends AbstractStateSplit implements Node.IterableNodeType, LIRLowerable { + private static class PlaceholderNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, LIRLowerable { public PlaceholderNode() { super(StampFactory.illegal()); } @@ -38,6 +38,11 @@ public void generate(LIRGeneratorTool gen) { // nothing to do } + + @Override + public boolean hasSideEffect() { + return false; + } } @Override diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Wed May 09 12:11:36 2012 +0200 @@ -23,7 +23,13 @@ package com.oracle.graal.compiler.target; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.spi.*; +/** + * An alternative to {@link LIRLowerable} for lowering that is tightly coupled + * to {@link LIRGenerator} and {@link LIRInstruction}. + */ public interface LIRGenLowerable { void generate(LIRGenerator generator); diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Wed May 09 12:11:36 2012 +0200 @@ -27,10 +27,13 @@ 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.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -766,10 +769,10 @@ /** * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. + * * @param invoke the invoke that will be replaced * @param inlineGraph the graph that the invoke will be replaced with * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required - * @return The node that represents the return value, or null for void methods and methods that have no non-exceptional exit. */ public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { NodeInputList parameters = invoke.callTarget().arguments(); @@ -903,6 +906,150 @@ } } + /** + * 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) { + // 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, false, 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); + while (!loopBegin.isDeleted()) { + snippetCopy.mark(); + LoopTransformUtil.peel(loop, wholeLoop); + new CanonicalizerPhase(null, runtime, null, true, immutabilityPredicate).apply(snippetCopy); + } + Debug.dump(snippetCopy, "After exploding loop %s", loopBegin); + } + } + + // Gather the nodes in the snippets that are to be inlined + ArrayList nodes = new ArrayList<>(); + ReturnNode returnNode = null; + BeginNode 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(); + Map duplicates = graph.addDuplicates(nodes, replacements); + + // 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 : duplicates.values()) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node; + if (frameState != null) { + stateSplit.setStateAfter(null); + } + } + } + + // 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 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Wed May 09 12:11:36 2012 +0200 @@ -34,7 +34,7 @@ */ public class Graph { - protected final String name; + public final String name; private static final boolean TIME_TRAVEL = false; @@ -220,6 +220,9 @@ return true; } + /** + * @see #getNewNodes() + */ public void mark() { this.mark = nodeIdCount(); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed May 09 12:11:36 2012 +0200 @@ -555,6 +555,8 @@ if (type.isPrimitive()) { if (type == Integer.TYPE) { value = unsafe.getInt(node, dataOffsets[i]); + } else if (type == Long.TYPE) { + value = unsafe.getLong(node, dataOffsets[i]); } else if (type == Boolean.TYPE) { value = unsafe.getBoolean(node, dataOffsets[i]); } else if (type == Long.TYPE) { diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed May 09 12:11:36 2012 +0200 @@ -153,10 +153,10 @@ Debug.scope("CodeInstall", new Object[] {compiler.getCompiler(), method}, new Runnable() { @Override public void run() { - final HotSpotCodeInfo info = Debug.isDumpEnabled() ? new HotSpotCodeInfo(compiler, tm, method) : null; + final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null; compiler.getRuntime().installMethod(method, tm, info); if (info != null) { - Debug.dump(info, "After code installation"); + Debug.dump(info[0], "After code installation"); } } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java Wed May 09 12:11:36 2012 +0200 @@ -157,12 +157,19 @@ } /** - * Factory method for getting a Graal compiler instance. This method is called via reflection. + * Factory method for getting a {@link GraalRuntime} instance. This method is called via reflection. */ public static GraalRuntime getGraalRuntime() { return getInstance().getRuntime(); } + /** + * Factory method for getting a {@link GraalCompiler} instance. This method is called via reflection. + */ + public static GraalCompiler getGraalCompiler() { + return getInstance().getCompiler(); + } + @Override public GraalCompiler getCompiler() { if (compiler == null) { @@ -238,19 +245,6 @@ @Override public HotSpotRuntime getRuntime() { if (runtime == null) { - if (GraalOptions.PrintCFGToFile) { -// context.addCompilationObserver(new CFGPrinterObserver()); - } - // if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) { - // CompilationObserver observer; - // if (GraalOptions.PrintIdealGraphFile) { - // observer = new IdealGraphPrinterObserver(); - // } else { - // observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort); - // } -// context.addCompilationObserver(observer); - // TODO (thomaswue): Install observer. - // } runtime = new HotSpotRuntime(config, this); } return runtime; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java Wed May 09 12:11:36 2012 +0200 @@ -24,11 +24,13 @@ import java.io.*; +import com.oracle.max.cri.ci.CiKind.FormatWithToString; + /** * Parent class for all HotSpot Ri... types. */ -public abstract class CompilerObject implements Serializable { +public abstract class CompilerObject implements Serializable, FormatWithToString { private static final long serialVersionUID = -4551670987101214877L; protected final Compiler compiler; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java Wed May 09 12:11:36 2012 +0200 @@ -60,7 +60,7 @@ // Report the filters that have been configured so the user can verify it's what they expect if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) { - TTY.println(this.toString()); + TTY.println(Thread.currentThread().getName() + ": " + toString()); } if (GraalOptions.PrintIdealGraphFile) { diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed May 09 12:11:36 2012 +0200 @@ -63,7 +63,7 @@ void RiConstantPool_loadReferencedType(HotSpotTypeResolved pool, int cpi, byte byteCode); - HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean installCode, HotSpotCodeInfo info); + HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean makeDefault, HotSpotCodeInfo info); long installStub(HotSpotTargetMethod targetMethod, HotSpotCodeInfo info); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed May 09 12:11:36 2012 +0200 @@ -78,7 +78,7 @@ public native RiField RiConstantPool_lookupField(HotSpotTypeResolved pool, int cpi, byte byteCode); @Override - public native HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean installCode, HotSpotCodeInfo info); + public native HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean makeDefault, HotSpotCodeInfo info); @Override public native long installStub(HotSpotTargetMethod targetMethod, HotSpotCodeInfo info); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed May 09 12:11:36 2012 +0200 @@ -53,6 +53,7 @@ private final Compiler compiler; private IntrinsifyArrayCopyPhase intrinsifyArrayCopy; + private LowerCheckCastPhase lowerCheckCastPhase; public final HotSpotTypePrimitive typeBoolean; public final HotSpotTypePrimitive typeChar; @@ -115,10 +116,12 @@ @Override public void run() { VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime); + VMToCompilerImpl.this.lowerCheckCastPhase = new LowerCheckCastPhase(runtime); GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget()); Snippets.install(runtime, runtime.getCompiler().getTarget(), new SystemSnippets()); Snippets.install(runtime, runtime.getCompiler().getTarget(), new UnsafeSnippets()); Snippets.install(runtime, runtime.getCompiler().getTarget(), new ArrayCopySnippets()); + Snippets.install(runtime, runtime.getCompiler().getTarget(), new CheckCastSnippets()); } }); @@ -157,6 +160,8 @@ } } + + /** * This method is the first method compiled during bootstrapping. Put any code in there that warms up compiler paths * that are otherwise not exercised during bootstrapping and lead to later deoptimization when application code is @@ -483,6 +488,7 @@ if (GraalOptions.Intrinsify) { phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy); } + phasePlan.addPhase(PhasePosition.HIGH_LEVEL, lowerCheckCastPhase); return phasePlan; } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,71 @@ +/* + * 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.hotspot.nodes; + +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.target.amd64.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; + +/** + * A node for calling the HotSpot stub implementing the slow path of a type check. + * This stub does not use any registers. + */ +public final class TypeCheckSlowPath extends FloatingNode implements LIRGenLowerable { + + @Input private ValueNode objectHub; + @Input private ValueNode hub; + + public ValueNode objectHub() { + return objectHub; + } + + public ValueNode hub() { + return hub; + } + + public TypeCheckSlowPath(ValueNode objectHub, ValueNode hub) { + super(StampFactory.forKind(CiKind.Object)); + this.objectHub = objectHub; + this.hub = hub; + } + + @Override + public void generate(LIRGenerator gen) { + CiValue objectHubOpr = gen.operand(objectHub); + AMD64TypeCheckSlowPathOp op = new AMD64TypeCheckSlowPathOp(objectHubOpr, gen.operand(hub)); + gen.append(op); + gen.setResult(this, objectHubOpr); + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static Object check(Object objectHub, Object hub) { + throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler"); + } + + +} diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java Wed May 09 12:11:36 2012 +0200 @@ -44,4 +44,9 @@ super(compiler); this.javaMirror = javaMirror; } + + @Override + public String toString() { + return "HotSpotKlassOop<" + javaMirror.getName() + ">"; + } } diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Wed May 09 12:11:36 2012 +0200 @@ -475,14 +475,25 @@ return (RiResolvedMethod) compiler.getCompilerToVM().getRiMethod(reflectionMethod); } - @Override - public void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo info) { - compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), true, (HotSpotCodeInfo) info); + private HotSpotCodeInfo makeInfo(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) { + HotSpotCodeInfo hsInfo = null; + if (info != null && info.length > 0) { + hsInfo = new HotSpotCodeInfo(compiler, code, (HotSpotMethodResolved) method); + info[0] = hsInfo; + } + return hsInfo; } @Override - public RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code) { - return compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), false, null); + public void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) { + HotSpotCodeInfo hsInfo = makeInfo(method, code, info); + compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), true, hsInfo); + } + + @Override + public RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) { + HotSpotCodeInfo hsInfo = makeInfo(method, code, info); + return compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), false, hsInfo); } @Override diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,59 @@ +/* + * 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.hotspot.snippets; +import com.oracle.graal.graph.Node.Fold; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.snippets.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; + + +public class CheckCastSnippets implements SnippetsInterface { + + @Snippet + public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) { + if (object == null) { + return object; + } + Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object); + // if we get an exact match: succeed immediately + for (int i = 0; i < hintHubs.length; i++) { + Object hintHub = hintHubs[i]; + if (hintHub == objectHub) { + return object; + } + } + if (hintsAreExact || TypeCheckSlowPath.check(objectHub, hub) == null) { + DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException); + } + return object; + } + + @Fold + private static int hubOffset() { + return CompilerImpl.getInstance().getConfig().hubOffset; + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,86 @@ +/* + * 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.hotspot.snippets; + +import java.util.*; + +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate; +import com.oracle.graal.compiler.util.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.ri.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; + +/** + * Lowers a {@link CheckCastNode} by replacing it with the graph of a {@linkplain CheckCastSnippets checkcast snippet}. + */ +public class LowerCheckCastPhase extends Phase { + private final GraalRuntime runtime; + private final RiResolvedMethod checkcast; + + public LowerCheckCastPhase(GraalRuntime runtime) { + this.runtime = runtime; + try { + checkcast = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class)); + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + @Override + protected void run(StructuredGraph graph) { + final Map hintHubsSet = new IdentityHashMap<>(); + IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() { + public boolean apply(CiConstant constant) { + return hintHubsSet.containsKey(constant); + } + }; + for (CheckCastNode node : graph.getNodes(CheckCastNode.class)) { + ValueNode hub = node.targetClassInstruction(); + ValueNode object = node.object(); + RiResolvedType[] hints = node.hints(); + StructuredGraph snippetGraph = (StructuredGraph) checkcast.compilerStorage().get(Graph.class); + assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed"; + HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.length]; + for (int i = 0; i < hintHubs.length; i++) { + hintHubs[i] = ((HotSpotType) hints[i]).klassOop(); + } + assert !node.hintsExact() || hints.length > 0 : "cannot have 0 exact hints!"; + final CiConstant hintHubsConst = CiConstant.forObject(hintHubs); + hintHubsSet.put(hintHubsConst, hintHubsConst); + Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, node, Arrays.toString(hints), node.hintsExact()); + + InliningUtil.inlineSnippet(runtime, node, (FixedWithNextNode) node.anchor(), snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(node.hintsExact())); + } + if (!hintHubsSet.isEmpty()) { + Debug.log("Lowered %d checkcasts in %s ", hintHubsSet.size(), graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase(null, runtime, null, false, immutabilityPredicate).apply(graph); + } + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,69 @@ +/* + * 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 + * 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.hotspot.target.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; + +/** + * Performs a call to the {@code slow_subtype_check_id} stub. + */ +public class AMD64TypeCheckSlowPathOp extends AMD64LIRInstruction { + + public AMD64TypeCheckSlowPathOp(CiValue objectHub, CiValue hub) { + super("TYPECHECK_SLOW", new CiValue[] {objectHub}, null, new CiValue[] {objectHub, hub}, NO_OPERANDS, NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue objectHub = input(0); + CiValue hub = input(1); + + masm.push(asRegister(objectHub)); + masm.push(asRegister(hub)); + AMD64Call.directCall(tasm, masm, CompilerImpl.getInstance().getConfig().instanceofStub, null); + + // Two pops to balance the two pushes above - the value first popped is discarded + masm.pop(asRegister(result)); + masm.pop(asRegister(result)); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed May 09 12:11:36 2012 +0200 @@ -165,7 +165,7 @@ frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn); // finish the start block - ((AbstractStateSplit) lastInstr).setStateAfter(frameState.create(0)); + lastInstr.setStateAfter(frameState.create(0)); if (blockMap.startBlock.isLoopHeader) { appendGoto(createTarget(blockMap.startBlock, frameState)); } else { @@ -255,7 +255,7 @@ FrameStateBuilder dispatchState = frameState.copy(); dispatchState.clearStack(); - BeginNode dispatchBegin = currentGraph.add(new BeginNode()); + BeginNode dispatchBegin = currentGraph.add(new BeginStateSplitNode()); dispatchBegin.setStateAfter(dispatchState.create(bci)); if (exceptionObject == null) { @@ -639,7 +639,8 @@ append(anchor); CheckCastNode checkCast; RiResolvedType[] hints = getTypeCheckHints((RiResolvedType) type, GraalOptions.CheckcastMaxHints); - checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, Util.isFinalClass((RiResolvedType) type))); + boolean hintsExact = Util.isFinalClass((RiResolvedType) type); + checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, hintsExact)); append(currentGraph.add(new ValueAnchorNode(checkCast))); frameState.apush(checkCast); } else { @@ -1501,7 +1502,7 @@ } if (lastInstr instanceof StateSplit) { StateSplit stateSplit = (StateSplit) lastInstr; - if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { + if (stateSplit.stateAfter() == null) { stateSplit.setStateAfter(frameState.create(bci)); } } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java Wed May 09 12:10:35 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2009, 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.nodes; - -import java.util.*; - -import com.oracle.graal.nodes.type.*; - -/** - * The {@code AbstractStateSplit} class is the abstract base class of all instructions - * that store an immutable copy of the frame state. - */ -public abstract class AbstractStateSplit extends FixedWithNextNode implements StateSplit { - - @Input(notDataflow = true) private FrameState stateAfter; - - @Override - public FrameState stateAfter() { - return stateAfter; - } - - @Override - public void setStateAfter(FrameState x) { - assert x == null || x.isAlive() : "frame state must be in a graph"; - updateUsages(stateAfter, x); - stateAfter = x; - } - - /** - * Creates a new state split with the specified value type. - * @param kind the type of the value that this instruction produces - */ - public AbstractStateSplit(Stamp stamp) { - super(stamp); - } - - @Override - public boolean needsStateAfter() { - return true; - } - - @Override - public Map getDebugProperties() { - Map debugProperties = super.getDebugProperties(); - if (stateAfter() != null) { - debugProperties.put("stateAfter", stateAfter().toString(Verbosity.Debugger)); - } - return debugProperties; - } -} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public class BeginNode extends AbstractStateSplit implements LIRLowerable, Simplifiable, Node.IterableNodeType { +public class BeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Node.IterableNodeType { public BeginNode() { super(StampFactory.illegal()); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,37 @@ +/* + * 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.nodes; + +/** + * Base class for {@link BeginNode}s that are associated with a frame state. + */ +public class BeginStateSplitNode extends BeginNode implements StateSplit { + + /** + * A begin node has no side effect. + */ + @Override + public boolean hasSideEffect() { + return false; + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Wed May 09 12:11:36 2012 +0200 @@ -22,13 +22,43 @@ */ package com.oracle.graal.nodes; +import java.util.*; + import com.oracle.graal.nodes.type.*; /** * Base class of all nodes that are fixed within the control flow graph and have an immediate successor. + * This class also provides an implementation of {@link StateSplit} without being a {@link StateSplit} itself. */ public abstract class FixedWithNextNode extends FixedNode { + @Input(notDataflow = true) private FrameState stateAfter; + + public FrameState stateAfter() { + return stateAfter; + } + + public void setStateAfter(FrameState x) { + assert x == null || x.isAlive() : "frame state must be in a graph"; + assert this instanceof StateSplit : getClass() + " does not implement " + StateSplit.class; + updateUsages(stateAfter, x); + stateAfter = x; + } + + // Subclasses that implement StateSplit but do not represent side-effecting instructions must override this. + public boolean hasSideEffect() { + return true; + } + + @Override + public Map getDebugProperties() { + Map debugProperties = super.getDebugProperties(); + if (stateAfter() != null) { + debugProperties.put("stateAfter", stateAfter().toString(Verbosity.Debugger)); + } + return debugProperties; + } + public FixedNode next() { assert scheduledNext() == null || scheduledNext() instanceof FixedNode : "next() cannot be used while the graph is scheduled"; return (FixedNode) scheduledNext(); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed May 09 12:11:36 2012 +0200 @@ -282,7 +282,7 @@ @Override public void generate(LIRGeneratorTool gen) { - // Nothing to do, frame states are processed as part of the handling of AbstractStateSplit nodes. + // Nothing to do, frame states are processed as part of the handling of StateSplit nodes. } private static String toString(FrameState frameState) { diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Wed May 09 12:11:36 2012 +0200 @@ -34,7 +34,7 @@ /** * The {@code InvokeNode} represents all kinds of method calls. */ -public final class InvokeNode extends AbstractStateSplit implements Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint { +public final class InvokeNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint { @Input private final MethodCallTargetNode callTarget; private final int bci; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed May 09 12:11:36 2012 +0200 @@ -145,6 +145,10 @@ this.stateAfter = stateAfter; } + public boolean hasSideEffect() { + return true; + } + public FrameState stateDuring() { FrameState tempStateAfter = stateAfter(); FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), this.callTarget.targetMethod().signature().returnKind(false)); @@ -169,11 +173,6 @@ } @Override - public boolean needsStateAfter() { - return true; - } - - @Override public void intrinsify(Node node) { MethodCallTargetNode call = callTarget; FrameState state = stateAfter(); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java Wed May 09 12:11:36 2012 +0200 @@ -24,7 +24,7 @@ import com.oracle.graal.nodes.spi.*; -public class LoopExitNode extends BeginNode { +public class LoopExitNode extends BeginStateSplitNode { @Input(notDataflow = true) private LoopBeginNode loopBegin; public LoopExitNode(LoopBeginNode loop) { assert loop != null; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Wed May 09 12:11:36 2012 +0200 @@ -32,16 +32,11 @@ /** * Denotes the merging of multiple control-flow paths. */ -public class MergeNode extends BeginNode implements Node.IterableNodeType, LIRLowerable { +public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable { @Input(notDataflow = true) private final NodeInputList ends = new NodeInputList<>(this); @Override - public boolean needsStateAfter() { - return false; - } - - @Override public void generate(LIRGeneratorTool gen) { gen.visitMerge(this); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java Wed May 09 12:11:36 2012 +0200 @@ -22,6 +22,9 @@ */ package com.oracle.graal.nodes; +/** + * A state split is a node that may have a frame state associated with it. + */ public interface StateSplit { /** @@ -35,9 +38,9 @@ void setStateAfter(FrameState x); /** - * Determines if the caller should create an {@link #stateAfter() after} - * frame state for this node if it doesn't already have one. + * Determines if this node has a side-effect. Execution of such a node changes + * state visible to other threads. These nodes denote boundaries across which deoptimization + * points cannot be moved. */ - boolean needsStateAfter(); - + boolean hasSideEffect(); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed May 09 12:11:36 2012 +0200 @@ -64,7 +64,7 @@ private StructuredGraph(String name, RiResolvedMethod method, long graphId) { super(name); - this.start = add(new BeginNode()); + this.start = add(new BeginStateSplitNode()); this.method = method; this.graphId = graphId; } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java Wed May 09 12:11:36 2012 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -public abstract class AbstractCallNode extends AbstractStateSplit implements MemoryCheckpoint { +public abstract class AbstractCallNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint { @Input protected final NodeInputList arguments; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Wed May 09 12:11:36 2012 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -public abstract class AccessNode extends AbstractStateSplit implements Access { +public abstract class AccessNode extends FixedWithNextNode implements Access { @Input private ValueNode object; @Input private GuardNode guard; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ import com.oracle.graal.nodes.type.*; -public final class BoxNode extends AbstractStateSplit implements Node.IterableNodeType { +public final class BoxNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType { @Input private ValueNode source; private int bci; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Wed May 09 12:11:36 2012 +0200 @@ -30,7 +30,7 @@ /** * Creates a memory barrier. */ -public class MembarNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint { +public class MembarNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint { private final int barriers; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java Wed May 09 12:11:36 2012 +0200 @@ -25,8 +25,11 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; - -public abstract class SafeAccessNode extends AbstractStateSplit { +/** + * An analog to {@link AccessNode} with the additional semantics of null-checking + * the receiver object before the access. + */ +public abstract class SafeAccessNode extends FixedWithNextNode { @Input private ValueNode object; @Input private LocationNode location; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ import com.oracle.max.cri.ri.*; -public class SafeWriteNode extends SafeAccessNode implements Lowerable{ +public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable{ @Input private ValueNode value; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ /** * Load of a value from a location specified as an offset relative to an object. */ -public class UnsafeLoadNode extends AbstractStateSplit implements Lowerable { +public class UnsafeLoadNode extends FixedWithNextNode implements Lowerable { @Input private ValueNode object; @Input private ValueNode offset; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ /** * Store of a value at a location specified as an offset relative to an object. */ -public class UnsafeStoreNode extends AbstractStateSplit implements Lowerable { +public class UnsafeStoreNode extends FixedWithNextNode implements StateSplit, Lowerable { @Input private ValueNode object; @Input private ValueNode offset; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Wed May 09 12:11:36 2012 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.nodes.type.*; -public final class WriteMemoryCheckpointNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint { +public final class WriteMemoryCheckpointNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint { public WriteMemoryCheckpointNode() { this(StampFactory.illegal()); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Wed May 09 12:11:36 2012 +0200 @@ -28,7 +28,7 @@ import com.oracle.graal.nodes.type.*; -public final class WriteNode extends AccessNode implements LIRLowerable { +public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable { @Input private ValueNode value; public ValueNode value() { diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java Wed May 09 12:11:36 2012 +0200 @@ -28,7 +28,7 @@ /** * This the base class of all array operations. */ -public abstract class AccessArrayNode extends AbstractStateSplit { +public abstract class AccessArrayNode extends FixedWithNextNode { @Input private ValueNode array; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java Wed May 09 12:11:36 2012 +0200 @@ -35,7 +35,7 @@ /** * The base class of all instructions that access fields. */ -public abstract class AccessFieldNode extends AbstractStateSplit implements Lowerable { +public abstract class AccessFieldNode extends FixedWithNextNode implements Lowerable { @Input private ValueNode object; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed May 09 12:11:36 2012 +0200 @@ -43,7 +43,7 @@ * {@link MonitorEnterNode}. Optimization phases are free to throw {@link CiBailout} if they detect such cases. * Otherwise, they are detected during LIR construction. */ -public abstract class AccessMonitorNode extends AbstractStateSplit implements MemoryCheckpoint { +public abstract class AccessMonitorNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint { @Input private ValueNode object; private boolean eliminated; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Wed May 09 12:11:36 2012 +0200 @@ -33,7 +33,7 @@ * Represents an atomic compare-and-swap operation * The result is a boolean that contains whether the value matched the expected value. */ -public class CompareAndSwapNode extends AbstractStateSplit implements LIRLowerable, Lowerable, MemoryCheckpoint { +public class CompareAndSwapNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint { @Input private ValueNode object; @Input private ValueNode offset; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ /** * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler. */ -public class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint { +public class ExceptionObjectNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint { /** * Constructs a new ExceptionObject instruction. diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed May 09 12:11:36 2012 +0200 @@ -55,11 +55,6 @@ } @Override - public boolean needsStateAfter() { - return false; - } - - @Override public ValueNode canonical(CanonicalizerTool tool) { CiConstant constant = null; if (isStatic()) { diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Wed May 09 12:11:36 2012 +0200 @@ -58,11 +58,6 @@ } @Override - public boolean needsStateAfter() { - return false; - } - - @Override public void lower(CiLoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ /** * This node is used to perform the finalizer registration at the end of the java.lang.Object constructor. */ -public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable, LIRLowerable { +public final class RegisterFinalizerNode extends FixedWithNextNode implements StateSplit, Canonicalizable, LIRLowerable { @Input private ValueNode object; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Wed May 09 12:11:36 2012 +0200 @@ -29,7 +29,7 @@ /** * The {@code StoreFieldNode} represents a write to a static or instance field. */ -public final class StoreFieldNode extends AccessFieldNode { +public final class StoreFieldNode extends AccessFieldNode implements StateSplit { @Input private ValueNode value; diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Wed May 09 12:11:36 2012 +0200 @@ -31,7 +31,7 @@ /** * The {@code StoreIndexedNode} represents a write to an array element. */ -public final class StoreIndexedNode extends AccessIndexedNode implements Lowerable { +public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable { @Input private ValueNode value; diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java Wed May 09 12:11:36 2012 +0200 @@ -160,7 +160,7 @@ } private void openScope(String name) { - printer.beginGroup(name, name, Debug.contextLookup(RiResolvedMethod.class), -1); + printer.beginGroup(Thread.currentThread().getName() + ":" + name, name, Debug.contextLookup(RiResolvedMethod.class), -1); } private void closeScope() { diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Wed May 09 12:11:36 2012 +0200 @@ -24,8 +24,17 @@ import java.lang.annotation.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; + +/** + * A snippet is a Graal graph expressed as a Java source method. Graal snippets can be used for: + *
    + *
  • intrinsifying native JDK methods (see {@link ClassSubstitution})
  • + *
  • lowering operations that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode)
  • + *
  • replacing a method call with a single graph node (see {@link NodeIntrinsic})
  • + *
+ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Snippet { - } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Wed May 09 12:11:36 2012 +0200 @@ -53,16 +53,18 @@ } } - private static void installSnippets(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz, - BoxingMethodPool pool) { - for (Method snippet : clazz.getDeclaredMethods()) { - int modifiers = snippet.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet); - if (snippetRiMethod.compilerStorage().get(Graph.class) == null) { - buildSnippetGraph(snippetRiMethod, runtime, target, pool); + private static void installSnippets(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) { + for (Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + Method snippet = method; + int modifiers = snippet.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet); + if (snippetRiMethod.compilerStorage().get(Graph.class) == null) { + buildSnippetGraph(snippetRiMethod, runtime, target, pool); + } } } } diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Wed May 09 12:11:36 2012 +0200 @@ -69,7 +69,7 @@ final RiResolvedMethod riMethod = runtime.getRiMethod(method); CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); try { Object result = compiledMethod.execute("1", "2", "3"); Assert.assertEquals("1-2-3", result); @@ -84,7 +84,7 @@ final StructuredGraph graph = parse(method); final RiResolvedMethod riMethod = runtime.getRiMethod(method); CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); try { Object result = compiledMethod.executeVarargs("1", "2", "3"); Assert.assertEquals("1 2 3", result); @@ -99,7 +99,7 @@ final StructuredGraph graph = parse(method); final RiResolvedMethod riMethod = runtime.getRiMethod(method); CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); try { f1 = "0"; Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); @@ -128,7 +128,7 @@ } CiTargetMethod targetMethod = runtime.compile(riMethod, graph); - final RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod); + final RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod); final CompilableObject compilableObject = new CompilableObjectImpl(0); diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalAccess.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,86 @@ +/* + * 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 java.util.*; + +import com.oracle.graal.compiler.*; + +/** + * Utility for getting a Graal objects from the current execution environment. + */ +class GraalAccess { + + /** + * The known classes declaring a {@code getGraalCompiler()} method. These class names + * have aliases that can be used with the {@code "graal.access"} system property to + * specify the VM environment to try first when getting a Graal compiler instance. + */ + private static Map graalAccessClasses = new LinkedHashMap<>(); + static { + graalAccessClasses.put("HotSpot", "com.oracle.graal.hotspot.CompilerImpl"); + graalAccessClasses.put("Maxine", "com.oracle.max.vm.ext.maxri.MaxRuntime"); + } + + /** + * Gets a {@link GraalCompiler} instance from the current execution environment. + */ + static GraalCompiler getGraalCompiler() { + String vm = System.getProperty("graal.access"); + if (vm != null) { + String cn = graalAccessClasses.get(vm); + if (cn != null) { + GraalCompiler graalCompiler = getGraalCompiler(cn); + if (graalCompiler != null) { + return graalCompiler; + } + } + } + + for (String className : graalAccessClasses.values()) { + GraalCompiler graalCompiler = getGraalCompiler(className); + if (graalCompiler != null) { + return graalCompiler; + } + } + throw new InternalError("Could not create a GraalRuntime instance"); + } + + /** + * Calls {@code getGraalCompiler()} via reflection on a given class. + * + * @return {@code null} if there was an error invoking the method or if the method returns {@code null} itself + */ + private static GraalCompiler getGraalCompiler(String className) { + try { + Class c = Class.forName(className); + Method m = c.getDeclaredMethod("getGraalCompiler"); + return (GraalCompiler) m.invoke(null); + } catch (Exception e) { + //e.printStackTrace(); + System.err.println(e); + return null; + } + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalRuntimeAccess.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalRuntimeAccess.java Wed May 09 12:10:35 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +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 java.util.*; - -import com.oracle.graal.cri.*; - -/** - * Utility for getting a {@link GraalRuntime} instance from the current execution environment. - */ -class GraalRuntimeAccess { - - /** - * The known classes declaring a {@code getGraalRuntime()} method. These class names - * have aliases that can be used with the {@code "graal.runtime"} system property to - * specify the VM environment to try first when getting a Graal runtime instance. - */ - private static Map graalRuntimeFactoryClasses = new LinkedHashMap<>(); - static { - graalRuntimeFactoryClasses.put("HotSpot", "com.oracle.graal.hotspot.CompilerImpl"); - graalRuntimeFactoryClasses.put("Maxine", "com.oracle.max.vm.ext.maxri.MaxRuntime"); - } - - /** - * Gets a Graal runtime instance from the current execution environment. - */ - static GraalRuntime getGraalRuntime() { - String vm = System.getProperty("graal.runtime"); - if (vm != null) { - String cn = graalRuntimeFactoryClasses.get(vm); - if (cn != null) { - GraalRuntime graal = getGraalRuntime(cn); - if (graal != null) { - return graal; - } - } - } - - for (String className : graalRuntimeFactoryClasses.values()) { - GraalRuntime graal = getGraalRuntime(className); - if (graal != null) { - return graal; - } - } - throw new InternalError("Could not create a GraalRuntime instance"); - } - - /** - * Calls {@code getGraalRuntime()} via reflection on a given class. - * - * @return {@code null} if there was an error invoking the methodor if the method return {@code null} itself - */ - private static GraalRuntime getGraalRuntime(String className) { - try { - Class c = Class.forName(className); - Method m = c.getDeclaredMethod("getGraalRuntime"); - return (GraalRuntime) m.invoke(null); - } catch (Exception e) { - //e.printStackTrace(); - System.err.println(e); - return null; - } - } -} diff -r 1436de7b7cab -r c7f92c6246ba 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 Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed May 09 12:11:36 2012 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.tests; import java.lang.reflect.*; +import java.util.concurrent.*; import junit.framework.*; @@ -33,6 +34,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; /** @@ -40,7 +42,7 @@ * for Graal compiler transformations. The general pattern for a test is: *
    *
  1. Create a graph by {@linkplain #parse(String) parsing} a method.
  2. - *
  3. Manually modify the graph (e.g. replace a paramter node with a constant).
  4. + *
  5. Manually modify the graph (e.g. replace a parameter node with a constant).
  6. *
  7. Apply a transformation to the graph.
  8. *
  9. Assert that the transformed graph is equal to an expected graph.
  10. *
@@ -53,11 +55,13 @@ */ public abstract class GraphTest { + protected final GraalCompiler graalCompiler; protected final GraalRuntime runtime; public GraphTest() { Debug.enable(); - this.runtime = GraalRuntimeAccess.getGraalRuntime(); + this.graalCompiler = GraalAccess.getGraalCompiler(); + this.runtime = graalCompiler.runtime; } protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { @@ -96,6 +100,21 @@ } } + protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) { + Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { + @Override + public RiCompiledMethod call() throws Exception { + final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null; + RiCompiledMethod installedMethod = runtime.addMethod(method, tm, info); + if (info != null) { + Debug.dump(info[0], "After code installation"); + } + return installedMethod; + } + }); + return runtime.addMethod(method, tm, null); + } + /** * Parses a Java method to produce a graph. * diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java Wed May 09 12:11:36 2012 +0200 @@ -0,0 +1,135 @@ +/* + * 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.*; + +public class LowerCheckCastTest extends GraphTest { + + static { + // Ensure that the methods to be compiled and executed are fully resolved + asNumber(0); + asString("0"); + asNumberExt(0); + asStringExt("0"); + } + + private RiCompiledMethod compile(String name, Class[] hintClasses, boolean exact) { + //System.out.println("compiling: " + name + ", hints=" + Arrays.toString(hintClasses) + ", exact=" + exact); + + Method method = getMethod(name); + final StructuredGraph graph = parse(method); + + RiResolvedType[] hints = new RiResolvedType[hintClasses.length]; + for (int i = 0; i < hintClasses.length; i++) { + hints[i] = runtime.getType(hintClasses[i]); + } + + CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); + assert ccn != null; + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.anchor(), ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), hints, exact)); + graph.replaceFloating(ccn, ccnNew); + + final RiResolvedMethod riMethod = runtime.getRiMethod(method); + CiTargetMethod targetMethod = runtime.compile(riMethod, graph); + return addMethod(riMethod, targetMethod); + } + + private static final boolean EXACT = true; + private static final boolean NOT_EXACT = false; + + private static Class[] hints(Class... classes) { + return classes; + } + + private void test(String name, Class[] hints, boolean exact, Object expected, Object... args) { + RiCompiledMethod compiledMethod = compile(name, hints, exact); + Assert.assertEquals(expected, compiledMethod.executeVarargs(args)); + } + + @Test + public void test1() { + test("asNumber", hints(), NOT_EXACT, 111, 111); + test("asNumber", hints(Integer.class), NOT_EXACT, 111, 111); + test("asNumber", hints(Long.class, Short.class), NOT_EXACT, 111, 111); + test("asNumberExt", hints(), NOT_EXACT, 121, 111); + test("asNumberExt", hints(Integer.class), NOT_EXACT, 121, 111); + test("asNumberExt", hints(Long.class, Short.class), NOT_EXACT, 121, 111); + } + + @Test + public void test2() { + test("asString", hints(), NOT_EXACT, "111", "111"); + test("asString", hints(String.class), EXACT, "111", "111"); + test("asString", hints(String.class), NOT_EXACT, "111", "111"); + + test("asStringExt", hints(), NOT_EXACT, "#111", "111"); + test("asStringExt", hints(String.class), EXACT, "#111", "111"); + test("asStringExt", hints(String.class), NOT_EXACT, "#111", "111"); + } + + @Test(expected = ClassCastException.class) + public void test3() { + test("asNumber", hints(), NOT_EXACT, 111, "111"); + } + + @Test(expected = ClassCastException.class) + public void test4() { + test("asString", hints(String.class), EXACT, "111", 111); + } + + @Test(expected = ClassCastException.class) + public void test5() { + test("asNumberExt", hints(), NOT_EXACT, 111, "111"); + } + + @Test(expected = ClassCastException.class) + public void test6() { + test("asStringExt", hints(String.class), EXACT, "111", 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; + } +} diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Wed May 09 12:11:36 2012 +0200 @@ -23,6 +23,9 @@ package com.oracle.max.cri.ci; import static com.oracle.max.cri.ci.CiKind.Flags.*; + +import java.lang.reflect.*; + import sun.misc.*; import com.oracle.max.cri.ri.*; @@ -297,6 +300,8 @@ return String.valueOf(value); } else if (value instanceof Class< ? >) { return ((Class< ? >) value).getName() + ".class"; + } else if (value.getClass().isArray()) { + return formatArray(value); } else { return CiUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); } @@ -306,6 +311,35 @@ } } + private static final int MAX_FORMAT_ARRAY_LENGTH = Integer.getInteger("maxFormatArrayLength", 5); + + private static String formatArray(Object array) { + Class< ? > componentType = array.getClass().getComponentType(); + assert componentType != null; + int arrayLength = Array.getLength(array); + StringBuilder buf = new StringBuilder(CiUtil.getSimpleName(componentType, true)). + append('['). + append(arrayLength). + append("]{"); + int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); + boolean primitive = componentType.isPrimitive(); + for (int i = 0; i < length; i++) { + if (primitive) { + buf.append(Array.get(array, i)); + } else { + Object o = ((Object[]) array)[i]; + buf.append(CiKind.Object.format(o)); + } + if (i != length - 1) { + buf.append(", "); + } + } + if (arrayLength != length) { + buf.append(", ..."); + } + return buf.append('}').toString(); + } + public final char signatureChar() { return Character.toUpperCase(typeChar); } diff -r 1436de7b7cab -r c7f92c6246ba graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java Wed May 09 12:10:35 2012 +0200 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java Wed May 09 12:11:36 2012 +0200 @@ -176,17 +176,20 @@ * * @param method a method whose executable code is being modified * @param code the code to be executed when {@code method} is called - * @param info the object into which details of the installed code will be written (ignored if null) + * @param info the object into which details of the installed code will be written. + * Ignored if null, otherwise the info is written to index 0 of this array. */ - void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo info); + void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info); /** * Adds the given machine code as an implementation of the given method without making it the default implementation. * @param method a method to which the executable code is begin added * @param code the code to be added + * @param info the object into which details of the installed code will be written. + * Ignored if null, otherwise the info is written to index 0 of this array. * @return a reference to the compiled and ready-to-run code */ - RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code); + RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info); /** * Encodes a deoptimization action and a deoptimization reason in an integer value. diff -r 1436de7b7cab -r c7f92c6246ba mx/commands.py --- a/mx/commands.py Wed May 09 12:10:35 2012 +0200 +++ b/mx/commands.py Wed May 09 12:11:36 2012 +0200 @@ -51,15 +51,6 @@ _make_eclipse_launch = False -_jacocoExcludes = ['com.oracle.graal.hotspot.snippets.ArrayCopySnippets', - 'com.oracle.graal.snippets.DoubleSnippets', - 'com.oracle.graal.snippets.FloatSnippets', - 'com.oracle.graal.snippets.MathSnippetsX86', - 'com.oracle.graal.snippets.NodeClassSnippets', - 'com.oracle.graal.hotspot.snippets.SystemSnippets', - 'com.oracle.graal.hotspot.snippets.UnsafeSnippets', - 'com.oracle.graal.compiler.tests.*'] - _copyrightTemplate = """/* * Copyright (c) {0}, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -571,16 +562,49 @@ args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args if _jacoco == 'on' or _jacoco == 'append': jacocoagent = mx.library("JACOCOAGENT", True) + # Exclude all compiler tests and snippets + excludes = ['com.oracle.graal.compiler.tests.*'] + for p in mx.projects(): + for s in p.source_dirs(): + _add_classes_with_annotation(excludes, s, None, '@Snippet') + _add_classes_with_annotation(excludes, s, None, '@ClassSubstitution') agentOptions = { 'append' : 'true' if _jacoco == 'append' else 'false', 'bootclasspath' : 'true', 'includes' : 'com.oracle.*', - 'excludes' : ':'.join(_jacocoExcludes) + 'excludes' : ':'.join(excludes) } args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args exe = join(_jdk(build), 'bin', mx.exe_suffix('java')) return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) +def _add_classes_with_annotation(classes, srcDir, pkgRoot, annotation): + """ + Scan 'srcDir' for Java source files containing a line starting with 'annotation' + (ignoring preceding whitespace) and add the fully qualified class name + to 'classes' for each Java source file matched. + """ + pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$") + for root, _, files in os.walk(srcDir): + for name in files: + if name.endswith('.java') and name != 'package-info.java': + hasTest = False + with open(join(root, name)) as f: + pkg = None + for line in f: + if line.startswith("package "): + match = pkgDecl.match(line) + if match: + pkg = match.group(1) + else: + if line.strip().startswith(annotation): + hasTest = True + break + if hasTest: + assert pkg is not None + if pkgRoot is None or pkg.startswith(pkgRoot): + classes.append(pkg + '.' + name[:-len('.java')]) + # Table of unit tests. # Keys are project names, values are package name lists. @@ -594,28 +618,6 @@ 'com.oracle.graal.jtt': ['com.oracle.graal.jtt'], } -def _add_test_classes(testClassList, searchDir, pkgRoot): - pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$") - for root, _, files in os.walk(searchDir): - for name in files: - if name.endswith('.java') and name != 'package-info.java': - hasTest = False - with open(join(root, name)) as f: - pkg = None - for line in f: - if line.startswith("package "): - match = pkgDecl.match(line) - if match: - pkg = match.group(1) - else: - if line.strip().startswith('@Test'): - hasTest = True - break - if hasTest: - assert pkg is not None - if pkg.startswith(pkgRoot): - testClassList.append(pkg + '.' + name[:-len('.java')]) - def unittest(args): """run the Graal Compiler Unit Tests in the GraalVM @@ -637,13 +639,13 @@ p = mx.project(proj) classes = [] for pkg in _unittests[proj]: - _add_test_classes(classes, join(p.dir, 'src'), pkg) + _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test') if len(pos) != 0: classes = [c for c in classes if containsAny(c, pos)] if len(neg) != 0: classes = [c for c in classes if not containsAny(c, neg)] - + vm(['-XX:-BootstrapGraal', '-esa'] + vmArgs + ['-cp', mx.classpath(proj), 'org.junit.runner.JUnitCore'] + classes) def jtt(args): @@ -667,7 +669,7 @@ p = mx.project(proj) classes = [] for pkg in _jtttests[proj]: - _add_test_classes(classes, join(p.dir, 'src'), pkg) + _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test') if len(pos) != 0: classes = [c for c in classes if containsAny(c, pos)]