# HG changeset patch # User Doug Simon # Date 1336383644 -7200 # Node ID dec5a35ddbe2825c4d24a16cd63592da0893e590 # Parent 6cc970203f30f6d77e92fe4407edbebb7a028765 lowering checkcasts with Java snippets (incomplete) diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Mon May 07 11:40:44 2012 +0200 @@ -27,10 +27,12 @@ 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.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 +768,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 +905,108 @@ } } + /** + * Performs replacement of a node with a snippet graph. + * + * @param replacee the node that will be replaced + * @param anchor if non-null, then this fixed node is control flow replacee. This is required iff replacee is not a fixed node. + * @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 snippetInline(RiRuntime runtime, Node replacee, FixedNode anchor, StructuredGraph snippetGraph, boolean explodeLoops, 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); + + // 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); + while (!loopBegin.isDeleted()) { + snippetCopy.mark(); + LoopTransformUtil.peel(loop, wholeLoop); + new CanonicalizerPhase(null, runtime, null, true, null).apply(snippetCopy); + } + } + } + + // Inline snippet + 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; + } + } + } + + StructuredGraph graph = (StructuredGraph) replacee.graph(); + Map duplicates = graph.addDuplicates(nodes, replacements); + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + if (anchor != null) { + assert !(replacee instanceof FixedNode) : "anchor not required when replacing fixed node " + replacee; + anchor.replaceAtPredecessors(firstCFGNodeDuplicate); + } else { + assert replacee.successors().first() != null; + assert replacee.predecessor() != null; + replacee.replaceAtPredecessors(firstCFGNodeDuplicate); + } + + 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); + } + + 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:40:44 2012 +0200 @@ -0,0 +1,64 @@ +/* + * 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; + } + + @Fold + private static int klassOopOffset() { + return CompilerImpl.getInstance().getConfig().klassOopOffset; + } +} diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:40:44 2012 +0200 @@ -0,0 +1,91 @@ +/* + * 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.*; + +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); + } + } + + private static HotSpotKlassOop klassOop(RiResolvedType resolvedType) { + return ((HotSpotType) resolvedType).klassOop(); + } + + @Override + protected void run(StructuredGraph graph) { + // TODO (dnsimon) remove this once lowering works in general + if (graph.method() == null || !graph.method().holder().name().contains("LowerCheckCastTest")) { + return; + } + + int hits = 0; + graph.mark(); + IsImmutablePredicate immutabilityPredicate = null; + for (CheckCastNode ccn : graph.getNodes(CheckCastNode.class)) { + ValueNode hub = ccn.targetClassInstruction(); + ValueNode object = ccn.object(); + RiResolvedType[] hints = ccn.hints(); + StructuredGraph snippetGraph = (StructuredGraph) checkcast.compilerStorage().get(Graph.class); + hits++; + HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.length]; + for (int i = 0; i < hintHubs.length; i++) { + hintHubs[i] = klassOop(hints[i]); + } + final CiConstant hintHubsConst = CiConstant.forObject(hintHubs); + immutabilityPredicate = new IsImmutablePredicate() { + public boolean apply(CiConstant constant) { + return constant == hintHubsConst; + } + }; + Debug.log("Lowering checkcast in %s: ccn=%s, hintsHubs=%s, exact=%b", graph, ccn, Arrays.toString(hints), ccn.hintsExact()); + InliningUtil.snippetInline(runtime, ccn, ccn.anchor(), snippetGraph, true, hub, object, hintHubsConst, CiConstant.forBoolean(ccn.hintsExact())); + } + if (hits != 0) { + Debug.log("Lowered %d checkcasts in %s ", hits, graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase(null, runtime, null, false, immutabilityPredicate).apply(graph); + } + } +} diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon May 07 11:40:44 2012 +0200 @@ -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 { diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java Mon May 07 11:40:44 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 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Mon May 07 11:40:44 2012 +0200 @@ -27,5 +27,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Snippet { - + boolean atomic() default false; } diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:34:16 2012 +0200 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Mon May 07 11:40:44 2012 +0200 @@ -37,6 +37,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; /** * Utilities for snippet installation and management. @@ -53,16 +54,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, method.getAnnotation(Snippet.class).atomic(), pool); + } } } } @@ -80,7 +83,7 @@ throw new RuntimeException("Snippet must not be abstract or native"); } RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet); - StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool); + StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, false, pool); runtime.getRiMethod(method).compilerStorage().put(Graph.class, graph); } catch (NoSuchMethodException e) { throw new RuntimeException("Could not resolve method to substitute with: " + snippet.getName(), e); @@ -88,7 +91,7 @@ } } - private static StructuredGraph buildSnippetGraph(final RiResolvedMethod snippetRiMethod, final GraalRuntime runtime, final CiTarget target, final BoxingMethodPool pool) { + private static StructuredGraph buildSnippetGraph(final RiResolvedMethod snippetRiMethod, final GraalRuntime runtime, final CiTarget target, final boolean atomic, final BoxingMethodPool pool) { return Debug.scope("BuildSnippetGraph", snippetRiMethod, new Callable() { @Override @@ -109,7 +112,7 @@ if (holder.isSubtypeOf(runtime.getType(SnippetsInterface.class))) { StructuredGraph targetGraph = (StructuredGraph) targetMethod.compilerStorage().get(Graph.class); if (targetGraph == null) { - targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool); + targetGraph = buildSnippetGraph(targetMethod, runtime, target, atomic, pool); } InliningUtil.inline(invoke, targetGraph, true); if (GraalOptions.OptCanonicalizer) { @@ -126,6 +129,18 @@ new CanonicalizerPhase(target, runtime, null).apply(graph); } + if (atomic) { + for (Node n : graph.getNodes()) { + if (n instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) n; + if (stateSplit.stateAfter() != null) { + TTY.println(graph + ": " + stateSplit); + stateSplit.setStateAfter(null); + } + } + } + } + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { end.disableSafepoint(); } diff -r 6cc970203f30 -r dec5a35ddbe2 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 Mon May 07 11:40:44 2012 +0200 @@ -0,0 +1,124 @@ +/* + * 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 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.*; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. + * Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class LowerCheckCastTest extends GraphTest { + + static int warmup() { + Object[] numbers = {76L, (short) 34}; + int result = 0; + for (int i = 0; i < 20; i++) { + Object num = numbers[i % numbers.length]; + result += result + asNumber(num).intValue(); + } + return result; + } + + private RiCompiledMethod compile(String name, Class[] hintClasses, boolean exact) { + System.out.println("compiling: " + name + ", hints=" + Arrays.toString(hintClasses) + ", exact=" + exact); + // Ensure that the method is fully resolved + asNumber(0); + + 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); + } + + //@Test + public void test1() { + Class[] hints = {}; + RiCompiledMethod compiledMethod = compile("asNumber", hints, false); + Assert.assertEquals(Integer.valueOf(111), compiledMethod.executeVarargs(111)); + } + + //@Test + public void test2() { + Class[] hints = {Integer.class}; + RiCompiledMethod compiledMethod = compile("asNumber", hints, false); + Assert.assertEquals(Integer.valueOf(111), compiledMethod.executeVarargs(111)); + } + + @Test + public void test3() { + Class[] hints = {Long.class, Short.class}; + RiCompiledMethod compiledMethod = compile("asNumber", hints, false); + Assert.assertEquals(Integer.valueOf(111), compiledMethod.executeVarargs(111)); + } + + //@Test + public void test4() { + Class[] hints = {}; + RiCompiledMethod compiledMethod = compile("asString", hints, true); + Assert.assertEquals("111", compiledMethod.executeVarargs("111")); + } + + @Test + public void test5() { + Class[] hints = {String.class}; + RiCompiledMethod compiledMethod = compile("asString", hints, true); + Assert.assertEquals("111", compiledMethod.executeVarargs("111")); + } + + //@Test(expected = ClassCastException.class) + public void test100() { + Class[] hints = {}; + RiCompiledMethod compiledMethod = compile("asNumber", hints, false); + compiledMethod.executeVarargs("number"); + } + + public static Number asNumber(Object o) { + return (Number) o; + } + + public static String asString(Object o) { + return (String) o; + } +}