# HG changeset patch # User Stefan Anzinger # Date 1422979399 -3600 # Node ID 212299803bf6143372e9d922f175fa5d0dc90ea3 # Parent d2ec5e56ed312451c16218fb84c891cf79807965# Parent 9865883b51148aca910183a093a4bf6d63b1ba41 Merge diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2015, 2015, 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.api.directives.test; + +import java.lang.annotation.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; + +public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @Repeatable(AnchorSnippet.class) + private @interface NodeCount { + + Class nodeClass(); + + int expectedCount(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + private @interface AnchorSnippet { + NodeCount[] value(); + } + + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) + public static int verifyMergeSnippet(int arg) { + if (arg > 5) { + return 1; + } else { + return 2; + } + } + + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2) + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) + public static int preventMergeSnippet(int arg) { + if (arg > 5) { + GraalDirectives.controlFlowAnchor(); + return 1; + } else { + GraalDirectives.controlFlowAnchor(); + return 2; + } + } + + @Test + public void testMerge() { + test("verifyMergeSnippet", 42); + test("preventMergeSnippet", 42); + } + + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) + public static int verifyDuplicateSnippet(int arg) { + int ret; + if (arg > 5) { + ret = 17; + } else { + ret = arg; + } + return 42 / ret; + } + + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) + public static int preventDuplicateSnippet(int arg) { + int ret; + if (arg > 5) { + ret = 17; + } else { + ret = arg; + } + GraalDirectives.controlFlowAnchor(); + return 42 / ret; + } + + @Test + public void testDuplicate() { + test("verifyDuplicateSnippet", 42); + test("preventDuplicateSnippet", 42); + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0) + public static int verifyFullUnrollSnippet(int arg) { + int ret = arg; + for (int i = 0; i < 5; i++) { + ret = ret * 3 + 1; + } + return ret; + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) + public static int preventFullUnrollSnippet(int arg) { + int ret = arg; + for (int i = 0; i < 5; i++) { + GraalDirectives.controlFlowAnchor(); + ret = ret * 3 + 1; + } + return ret; + } + + @Test + public void testFullUnroll() { + test("verifyFullUnrollSnippet", 42); + test("preventFullUnrollSnippet", 42); + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = IfNode.class, expectedCount = 4) + public static void verifyPeelSnippet(int arg) { + int ret = arg; + while (ret > 1) { + if (ret % 2 == 0) { + ret /= 2; + } else { + ret = 3 * ret + 1; + } + } + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = IfNode.class, expectedCount = 2) + public static void preventPeelSnippet(int arg) { + int ret = arg; + while (ret > 1) { + GraalDirectives.controlFlowAnchor(); + if (ret % 2 == 0) { + ret /= 2; + } else { + ret = 3 * ret + 1; + } + } + } + + @Test + public void testPeel() { + test("verifyPeelSnippet", 42); + test("preventPeelSnippet", 42); + } + + private static List getNodeCountAnnotations(StructuredGraph graph) { + ResolvedJavaMethod method = graph.method(); + AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class); + if (snippet != null) { + return Arrays.asList(snippet.value()); + } + + NodeCount single = method.getAnnotation(NodeCount.class); + if (single != null) { + return Collections.singletonList(single); + } + + return Collections.emptyList(); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + List anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot(); + for (int i = 0; i < anchors.size(); i++) { + ControlFlowAnchorNode a = anchors.get(i); + for (int j = i + 1; j < anchors.size(); j++) { + ControlFlowAnchorNode b = anchors.get(j); + if (a.valueEquals(b)) { + Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")"); + } + } + } + + for (NodeCount nodeCount : getNodeCountAnnotations(graph)) { + NodeIterable nodes = graph.getNodes().filter(nodeCount.nodeClass()); + Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count()); + } + return true; + } +} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java Tue Feb 03 17:03:19 2015 +0100 @@ -317,6 +317,49 @@ return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(",")); } + private boolean opsEquals(ArithmeticOpTable that) { + // @formatter:off + return Objects.equals(neg, that.neg) && + Objects.equals(add, that.add) && + Objects.equals(sub, that.sub) && + Objects.equals(mul, that.mul) && + Objects.equals(div, that.div) && + Objects.equals(rem, that.rem) && + Objects.equals(not, that.not) && + Objects.equals(and, that.and) && + Objects.equals(or, that.or) && + Objects.equals(xor, that.xor) && + Objects.equals(shl, that.shl) && + Objects.equals(shr, that.shr) && + Objects.equals(ushr, that.ushr) && + Objects.equals(abs, that.abs) && + Objects.equals(sqrt, that.sqrt) && + Objects.equals(zeroExtend, that.zeroExtend) && + Objects.equals(signExtend, that.signExtend) && + Objects.equals(narrow, that.narrow); + // @formatter:on + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ArithmeticOpTable that = (ArithmeticOpTable) obj; + if (opsEquals(that)) { + if (Arrays.equals(this.floatConvert, that.floatConvert)) { + return true; + } + } + return false; + } + @Override public String toString() { return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" + @@ -337,19 +380,26 @@ } @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj != null && getClass() == obj.getClass()) { - return obj.toString().equals(toString()); - } - return false; + public int hashCode() { + return operator.hashCode(); } @Override - public int hashCode() { - return toString().hashCode(); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Op that = (Op) obj; + if (operator.equals(that.operator)) { + return true; + } + return true; } } @@ -533,6 +583,36 @@ } @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (associative ? 1231 : 1237); + result = prime * result + (commutative ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + BinaryOp that = (BinaryOp) obj; + if (associative != that.associative) { + return false; + } + if (commutative != that.commutative) { + return false; + } + return true; + } + + @Override public String toString() { if (associative) { if (commutative) { @@ -611,6 +691,30 @@ public FloatConvertOp unwrap() { return this; } + + @Override + public int hashCode() { + final int prime = 31; + return prime * super.hashCode() + op.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + FloatConvertOp that = (FloatConvertOp) obj; + if (op != that.op) { + return false; + } + return true; + } } public abstract static class IntegerConvertOp extends Op { diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Tue Feb 03 17:03:19 2015 +0100 @@ -325,7 +325,7 @@ canonicalizer.apply(graph, context); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); if (loopPeeling) { - new LoopTransformHighPhase().apply(graph); + new LoopPeelingPhase().apply(graph); } new DeadCodeEliminationPhase().apply(graph); canonicalizer.apply(graph, context); diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Tue Feb 03 17:03:19 2015 +0100 @@ -124,7 +124,7 @@ final StructuredGraph graph = parseEager(snippet); final StructuredGraph referenceGraph = parseEager(referenceSnippet); - new LoopTransformLowPhase().apply(graph); + new LoopUnswitchingPhase().apply(graph); // Framestates create comparison problems for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) { diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Tue Feb 03 17:03:19 2015 +0100 @@ -339,8 +339,7 @@ @Test public void testPeeledLoop() { prepareGraph("testPeeledLoopSnippet", false); - new LoopTransformHighPhase().apply(graph); - new LoopTransformLowPhase().apply(graph); + new LoopPeelingPhase().apply(graph); new SchedulePhase().apply(graph); } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/GraalTutorial.java Tue Feb 03 17:03:19 2015 +0100 @@ -25,6 +25,8 @@ import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.java.*; /** * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at @@ -38,15 +40,31 @@ public class GraalTutorial extends InvokeGraal { /* + * Example for the Graal API: access the Graal API metadata object for a method. + */ + + @Test + public void testPrintBytecodes() { + ResolvedJavaMethod method = findMethod(String.class, "hashCode"); + + byte[] bytecodes = method.getCode(); + Assert.assertNotNull(bytecodes); + + System.out.println(new BytecodeDisassembler().disassemble(method)); + } + + /* * A simple Graal compilation example: Compile the method String.hashCode() */ @Test public void testStringHashCode() throws InvalidInstalledCodeException { + int expectedResult = "Hello World".hashCode(); + InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode")); int result = (int) installedCode.executeVarargs("Hello World"); - Assert.assertEquals(-862545276, result); + Assert.assertEquals(expectedResult, result); } /* @@ -70,7 +88,9 @@ /* * Collect profiling information by running the method in the interpreter. */ + for (int i = 0; i < 10000; i++) { + /* Execute several times so that enough profiling information gets collected. */ speculativeOptimization(false); } @@ -121,13 +141,17 @@ @Test public void testInstanceOfUsage() throws InvalidInstalledCodeException { - A a = new A(); + /* + * Collect profiling information by running the method in the interpreter. + */ - /* Allocate an (unsued) instance of B so that the class B gets loaded. */ + A a = new A(); + /* Allocate an (unused) instance of B so that the class B gets loaded. */ @SuppressWarnings("unused") B b = new B(); - + int expectedResult = instanceOfUsage(a); for (int i = 0; i < 10000; i++) { + /* Execute several times so that enough profiling information gets collected. */ instanceOfUsage(a); } @@ -136,7 +160,7 @@ InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage")); int result = (int) compiledMethod.executeVarargs(a); - Assert.assertEquals(42, result); + Assert.assertEquals(expectedResult, result); } /* @@ -149,9 +173,11 @@ @Test public void testIntrinsicUsage() throws InvalidInstalledCodeException { + double expectedResult = intrinsicUsage(42d); + InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage")); double result = (double) compiledMethod.executeVarargs(42d); - Assert.assertEquals(Math.sin(42), result, 0); + Assert.assertEquals(expectedResult, result, 0); } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java Tue Feb 03 17:03:19 2015 +0100 @@ -75,7 +75,7 @@ /** * Adds a root method to the static analysis. The method must be static and must not have any - * parameters, because the possible types of the parametes would not be known. + * parameters, because the possible types of the parameters would not be known. */ public void addMethod(ResolvedJavaMethod method) { if (!method.isStatic() || method.getSignature().getParameterCount(false) > 0) { @@ -222,7 +222,7 @@ * the code before static analysis, the classes would otherwise be not loaded * yet and the bytecode parser would only create a graph. */ - GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault().withOmitAllExceptionEdges(true); + GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault(); /* * For simplicity, we ignore all exception handling during the static analysis. * This is a constraint of this example code, a real static analysis needs to @@ -311,7 +311,7 @@ * The active element for method invocations. For {@link InvokeKind#Virtual virtual} and * {@link InvokeKind#Interface interface} calls, the {@link TypeFlow#getTypes() types} of this * node are the receiver types. When a new receiver type is added, a new callee might be added. - * Adding a new callee means liking the type flow of the actual parameters with the formal + * Adding a new callee means linking the type flow of the actual parameters with the formal * parameters of the callee, and linking the return value of the callee with the return value * state of the invocation. * @@ -319,7 +319,6 @@ * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for * simplicity. */ - class InvokeTypeFlow extends TypeFlow { private final MethodCallTargetNode callTarget; private final TypeFlow[] actualParameters; diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Feb 03 17:03:19 2015 +0100 @@ -356,7 +356,7 @@ try (Scope s1 = Debug.scope("BuildFrameMap")) { // build frame map final StackSlotAllocator allocator; - if (LSStackSlotAllocator.Options.EnableLSStackSlotAllocation.getValue()) { + if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) { allocator = new LSStackSlotAllocator(); } else { allocator = new SimpleStackSlotAllocator(); diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Feb 03 17:03:19 2015 +0100 @@ -85,8 +85,12 @@ } if (OptLoopTransform.getValue()) { - appendPhase(new LoopTransformHighPhase()); - appendPhase(new LoopTransformLowPhase()); + if (LoopPeeling.getValue()) { + appendPhase(new LoopPeelingPhase()); + } + if (LoopUnswitch.getValue()) { + appendPhase(new LoopUnswitchingPhase()); + } } appendPhase(new RemoveValueProxyPhase()); diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Tue Feb 03 17:03:19 2015 +0100 @@ -89,6 +89,10 @@ appendPhase(new FrameStateAssignmentPhase()); + if (ReassociateInvariants.getValue()) { + appendPhase(new ReassociateInvariantPhase()); + } + if (OptDeoptimizationGrouping.getValue()) { appendPhase(new DeoptimizationGroupingPhase()); } diff -r d2ec5e56ed31 -r 212299803bf6 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 Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Feb 03 17:03:19 2015 +0100 @@ -166,7 +166,7 @@ isLeafNode = inputs.getCount() + successors.getCount() == 0; canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz); - startGVNNumber = clazz.getName().hashCode(); + startGVNNumber = clazz.hashCode(); NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class); assert info != null : "Missing NodeInfo annotation on " + clazz; diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Tue Feb 03 17:03:19 2015 +0100 @@ -29,12 +29,18 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +/** + * Provider of HotSpot specific {@link GraphBuilderPlugin}s. + */ @ServiceProvider(GraphBuilderPluginsProvider.class) public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { plugins.register(metaAccess, ObjectPlugin.class); } + /** + * HotSpot specific plugins for {@link Object}. + */ enum ObjectPlugin implements GraphBuilderPlugin { getClass() { public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { @@ -52,10 +58,5 @@ public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name()); } - - @Override - public String toString() { - return Object.class.getName() + "." + name() + "()"; - } } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPluginsProvider.java Tue Feb 03 17:03:19 2015 +0100 @@ -22,41 +22,31 @@ */ package com.oracle.graal.java; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +/** + * Provider of non-runtime specific {@link GraphBuilderPlugin}s. + */ @ServiceProvider(GraphBuilderPluginsProvider.class) public class DefaultGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { plugins.register(metaAccess, ObjectPlugin.class); + plugins.register(metaAccess, BoxingPlugin.class); } + /** + * Plugins for {@link Object}. + */ enum ObjectPlugin implements GraphBuilderPlugin { init() { public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { - assert args.length == 1; - ValueNode rcvr = args[0]; - ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp(); - - boolean needsCheck = true; - if (objectStamp.isExactType()) { - needsCheck = objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { - // if either the declared type of receiver or the holder - // can be assumed to have no finalizers - Assumptions assumptions = builder.getAssumptions(); - if (assumptions.useOptimisticAssumptions()) { - assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type()); - needsCheck = false; - } - } - - if (needsCheck) { - builder.append(new RegisterFinalizerNode(rcvr)); + ValueNode object = args[0]; + if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) { + builder.append(new RegisterFinalizerNode(object)); } return true; } @@ -71,4 +61,50 @@ return Object.class.getName() + "." + name() + "()"; } } + + /** + * Plugins for the standard primitive box classes (e.g., {@link Integer} and friends). + */ + enum BoxingPlugin implements GraphBuilderPlugin { + valueOf$Boolean(Kind.Boolean), + booleanValue$Boolean(Kind.Boolean), + valueOf$Byte(Kind.Byte), + byteValue$Byte(Kind.Byte), + valueOf$Short(Kind.Short), + shortValue$Short(Kind.Short), + valueOf$Char(Kind.Char), + charValue$Char(Kind.Char), + valueOf$Int(Kind.Int), + intValue$Int(Kind.Int), + valueOf$Long(Kind.Long), + longValue$Long(Kind.Long), + valueOf$Float(Kind.Float), + floatValue$Float(Kind.Float), + valueOf$Double(Kind.Double), + doubleValue$Double(Kind.Double); + + BoxingPlugin(Kind kind) { + assert name().startsWith("valueOf$") || name().startsWith(kind.getJavaName() + "Value$"); + this.kind = kind; + this.box = name().charAt(0) == 'v'; + } + + private final Kind kind; + private final boolean box; + + public final boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + if (box) { + ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); + builder.push(Kind.Object, builder.append(new BoxNode(args[0], resultType, kind))); + } else { + builder.push(kind, builder.append(new UnboxNode(args[0], kind))); + } + return true; + } + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + Class[] parameterTypes = box ? new Class[]{kind.toJavaClass()} : new Class[0]; + return GraphBuilderPlugin.resolveTarget(metaAccess, kind.toBoxedJavaClass(), name(), parameterTypes); + } + } } diff -r d2ec5e56ed31 -r 212299803bf6 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 Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Feb 03 17:03:19 2015 +0100 @@ -775,9 +775,13 @@ if (graphBuilderPlugins != null) { GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod); if (plugin != null) { + int beforeStackSize = frameState.stackSize; if (plugin.handleInvocation(this, args)) { + // System.out.println("used plugin: " + plugin); + assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize; return; } + assert beforeStackSize == frameState.stackSize; } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Tue Feb 03 17:03:19 2015 +0100 @@ -42,14 +42,21 @@ boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args); /** - * Gets the target method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} - * . + * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} . */ ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess); - static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class clazz, String methodName, Class... parameterTypes) { + /** + * Looks up a {@link ResolvedJavaMethod}. + * + * @param methodNameBase the name of the method is the prefix of this value up to the first '$' + * character + */ + static ResolvedJavaMethod resolveTarget(MetaAccessProvider metaAccess, Class declaringClass, String methodNameBase, Class... parameterTypes) { + int index = methodNameBase.indexOf('$'); + String methodName = index == -1 ? methodNameBase : methodNameBase.substring(0, index); try { - return metaAccess.lookupJavaMethod(methodName.equals("") ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getDeclaredMethod(methodName, parameterTypes)); + return metaAccess.lookupJavaMethod(methodName.equals("") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes)); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Tue Feb 03 17:03:19 2015 +0100 @@ -44,6 +44,7 @@ GraphBuilderPlugin gbp = (GraphBuilderPlugin) o; ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess); GraphBuilderPlugin oldValue = map.put(target, gbp); + // System.out.println("registered: " + gbp); assert oldValue == null; } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.stackslotalloc; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; + +/** + * Calculates the stack intervals using a worklist-based backwards data-flow analysis. + */ +final class FixPointIntervalBuilder { + private final BlockMap liveInMap; + private final BlockMap liveOutMap; + private final LIR lir; + private final int maxOpId; + private final StackInterval[] stackSlotMap; + + /** + * The number of allocated stack slots. + */ + private static final DebugMetric uninitializedSlots = Debug.metric("StackSlotAllocator[uninitializedSlots]"); + + FixPointIntervalBuilder(LIR lir, StackInterval[] stackSlotMap, int maxOpId) { + this.lir = lir; + this.stackSlotMap = stackSlotMap; + this.maxOpId = maxOpId; + liveInMap = new BlockMap<>(lir.getControlFlowGraph()); + liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); + } + + void build() { + Deque> worklist = new ArrayDeque<>(); + for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) { + worklist.add(lir.getControlFlowGraph().getBlocks().get(i)); + } + for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { + liveInMap.put(block, new BitSet(stackSlotMap.length)); + } + while (!worklist.isEmpty()) { + AbstractBlock block = worklist.poll(); + processBlock(block, worklist); + } + } + + /** + * Merge outSet with in-set of successors. + */ + private boolean updateOutBlock(AbstractBlock block) { + BitSet union = new BitSet(stackSlotMap.length); + block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ))); + BitSet outSet = liveOutMap.get(block); + // check if changed + if (outSet == null || !union.equals(outSet)) { + liveOutMap.put(block, union); + return true; + } + return false; + } + + private void processBlock(AbstractBlock block, Deque> worklist) { + if (updateOutBlock(block)) { + try (Indent indent = Debug.logAndIndent("handle block %s", block)) { + List instructions = lir.getLIRforBlock(block); + // get out set and mark intervals + BitSet outSet = liveOutMap.get(block); + markOutInterval(outSet, getBlockEnd(instructions)); + printLiveSet("liveOut", outSet); + + // process instructions + BlockClosure closure = new BlockClosure((BitSet) outSet.clone()); + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + closure.processInstructionBottomUp(inst); + } + + // add predecessors to work list + worklist.addAll(block.getPredecessors()); + // set in set and mark intervals + BitSet inSet = closure.getCurrentSet(); + liveInMap.put(block, inSet); + markInInterval(inSet, getBlockBegin(instructions)); + printLiveSet("liveIn", inSet); + } + } + } + + private void printLiveSet(String label, BitSet liveSet) { + if (Debug.isLogEnabled()) { + try (Indent indent = Debug.logAndIndent(label)) { + Debug.log("%s", liveSetToString(liveSet)); + } + } + } + + private String liveSetToString(BitSet liveSet) { + StringBuilder sb = new StringBuilder(); + for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + sb.append(interval.getOperand()).append(" "); + } + return sb.toString(); + } + + private void markOutInterval(BitSet outSet, int blockEndOpId) { + for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + Debug.log("mark live operand: %s", interval.getOperand()); + interval.addTo(blockEndOpId); + } + } + + private void markInInterval(BitSet inSet, int blockFirstOpId) { + for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) { + StackInterval interval = getIntervalFromStackId(i); + Debug.log("mark live operand: %s", interval.getOperand()); + interval.addFrom(blockFirstOpId); + } + } + + private final class BlockClosure { + private final BitSet currentSet; + + private BlockClosure(BitSet set) { + currentSet = set; + } + + private BitSet getCurrentSet() { + return currentSet; + } + + /** + * Process all values of an instruction bottom-up, i.e. definitions before usages. Values + * that start or end at the current operation are not included. + */ + private void processInstructionBottomUp(LIRInstruction op) { + try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { + // kills + op.visitEachTemp(this::defConsumer); + op.visitEachOutput(this::defConsumer); + + // gen - values that are considered alive for this state + op.visitEachAlive(this::useConsumer); + op.visitEachState(this::useConsumer); + // mark locations + // gen + op.visitEachInput(this::useConsumer); + } + } + + /** + * @see InstructionValueConsumer + * + * @param inst + * @param operand + * @param mode + * @param flags + */ + private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + VirtualStackSlot vslot = asVirtualStackSlot(operand); + addUse(vslot, inst, flags); + Debug.log("set operand: %s", operand); + currentSet.set(vslot.getId()); + } + } + + /** + * + * @see InstructionValueConsumer + * + * @param inst + * @param operand + * @param mode + * @param flags + */ + private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + VirtualStackSlot vslot = asVirtualStackSlot(operand); + addDef(vslot, inst); + Debug.log("clear operand: %s", operand); + currentSet.clear(vslot.getId()); + } + + } + + private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet flags) { + StackInterval interval = getOrCreateInterval(stackSlot); + if (flags.contains(OperandFlag.UNINITIALIZED)) { + // Stack slot is marked uninitialized so we have to assume it is live all + // the time. + if (Debug.isMeterEnabled() && !(interval.from() == 0 && interval.to() == maxOpId)) { + uninitializedSlots.increment(); + } + interval.addFrom(0); + interval.addTo(maxOpId); + } else { + interval.addTo(inst.id()); + } + } + + private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) { + StackInterval interval = getOrCreateInterval(stackSlot); + interval.addFrom(inst.id()); + } + + } + + private StackInterval get(VirtualStackSlot stackSlot) { + return stackSlotMap[stackSlot.getId()]; + } + + private void put(VirtualStackSlot stackSlot, StackInterval interval) { + stackSlotMap[stackSlot.getId()] = interval; + } + + private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) { + StackInterval interval = get(stackSlot); + if (interval == null) { + interval = new StackInterval(stackSlot, stackSlot.getLIRKind()); + put(stackSlot, interval); + } + return interval; + } + + private StackInterval getIntervalFromStackId(int id) { + return stackSlotMap[id]; + } + + private static int getBlockBegin(List instructions) { + return instructions.get(0).id(); + } + + private static int getBlockEnd(List instructions) { + return instructions.get(instructions.size() - 1).id() + 1; + } + +} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/InstructionNumberer.java Tue Feb 03 17:02:15 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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.lir.stackslotalloc; - -import static com.oracle.graal.api.code.CodeUtil.*; - -import java.util.*; - -import com.oracle.graal.compiler.common.cfg.*; -import com.oracle.graal.lir.*; - -public class InstructionNumberer { - - private LIRInstruction[] opIdToInstructionMap; - private AbstractBlock[] opIdToBlockMap; - - /** - * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. All LIR - * instructions in a method have an index one greater than their linear-scan order predecesor - * with the first instruction having an index of 0. - */ - private static int opIdToIndex(int opId) { - return opId >> 1; - } - - /** - * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. - * - * @param opId an instruction {@linkplain LIRInstruction#id id} - * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} - */ - protected LIRInstruction instructionForId(int opId) { - assert isEven(opId) : "opId not even"; - LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; - assert instr.id() == opId; - return instr; - } - - /** - * Numbers all instructions in all blocks. - */ - protected void numberInstructions(LIR lir, List> sortedBlocks) { - - // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. - int numInstructions = 0; - for (AbstractBlock block : sortedBlocks) { - numInstructions += lir.getLIRforBlock(block).size(); - } - - // initialize with correct length - opIdToInstructionMap = new LIRInstruction[numInstructions]; - opIdToBlockMap = new AbstractBlock[numInstructions]; - - int opId = 0; - int index = 0; - for (AbstractBlock block : sortedBlocks) { - - List instructions = lir.getLIRforBlock(block); - - int numInst = instructions.size(); - for (int j = 0; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - op.setId(opId); - - opIdToInstructionMap[index] = op; - opIdToBlockMap[index] = block; - assert instructionForId(opId) == op : "must match"; - - index++; - opId += 2; // numbering of lirOps by two - } - } - assert index == numInstructions : "must match"; - assert (index << 1) == opId : "must match: " + (index << 1); - } - - /** - * Gets the highest instruction id allocated by this object. - */ - public int maxOpId() { - assert opIdToInstructionMap.length > 0 : "no operations"; - return (opIdToInstructionMap.length - 1) << 1; - } -} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java Tue Feb 03 17:03:19 2015 +0100 @@ -53,329 +53,122 @@ public static class Options { // @formatter:off - @Option(help = "Enable linear scan stack slot allocation.", type = OptionType.Debug) - public static final OptionValue EnableLSStackSlotAllocation = new OptionValue<>(true); + @Option(help = "Use linear scan stack slot allocation.", type = OptionType.Debug) + public static final OptionValue LSStackSlotAllocation = new OptionValue<>(true); // @formatter:on } - /** - * The number of allocated stack slots. - */ - static final DebugMetric uninitializedSlots = Debug.metric("StackSlotAllocator[uninitializedSlots]"); - public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) { new Allocator(res.getLIR(), builder).allocate(); } - static final class Allocator extends InstructionNumberer { + private static final class Allocator { private final LIR lir; private final FrameMapBuilderTool frameMapBuilder; private final StackInterval[] stackSlotMap; - private LinkedList unhandled; - private LinkedList active; - - private List> sortedBlocks; + private final PriorityQueue unhandled; + private final PriorityQueue active; + private final List> sortedBlocks; + private final int maxOpId; private Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) { this.lir = lir; this.frameMapBuilder = frameMapBuilder; this.stackSlotMap = new StackInterval[frameMapBuilder.getNumberOfStackSlots()]; + this.sortedBlocks = lir.getControlFlowGraph().getBlocks(); + + // insert by from + this.unhandled = new PriorityQueue<>((a, b) -> a.from() - b.from()); + // insert by to + this.active = new PriorityQueue<>((a, b) -> a.to() - b.to()); + + // step 1: number instructions + this.maxOpId = numberInstructions(lir, sortedBlocks); } private void allocate() { - // create block ordering - List> blocks = lir.getControlFlowGraph().getBlocks(); - assert blocks.size() > 0; - - sortedBlocks = lir.getControlFlowGraph().getBlocks(); - numberInstructions(lir, sortedBlocks); Debug.dump(lir, "After StackSlot numbering"); long currentFrameSize = Debug.isMeterEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0; - // build intervals - // buildIntervals(); + // step 2: build intervals try (Scope s = Debug.scope("StackSlotAllocationBuildIntervals"); Indent indent = Debug.logAndIndent("BuildIntervals")) { - buildIntervalsSlow(); + buildIntervals(); } + // step 3: verify intervals if (Debug.isEnabled()) { verifyIntervals(); } if (Debug.isDumpEnabled()) { dumpIntervals("Before stack slot allocation"); } - // allocate stack slots + // step 4: allocate stack slots allocateStackSlots(); if (Debug.isDumpEnabled()) { dumpIntervals("After stack slot allocation"); } - // assign stack slots + // step 5: assign stack slots assignStackSlots(); Debug.dump(lir, "After StackSlot assignment"); - StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize); - } - - private void buildIntervalsSlow() { - new SlowIntervalBuilder().build(); - } - - /** - * Calculates the stack intervals using a worklist-based backwards data-flow analysis. - */ - private final class SlowIntervalBuilder { - final BlockMap liveInMap; - final BlockMap liveOutMap; - - private SlowIntervalBuilder() { - liveInMap = new BlockMap<>(lir.getControlFlowGraph()); - liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); - } - - private void build() { - Deque> worklist = new ArrayDeque<>(); - for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) { - worklist.add(lir.getControlFlowGraph().getBlocks().get(i)); - } - for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { - liveInMap.put(block, new BitSet(frameMapBuilder.getNumberOfStackSlots())); - } - while (!worklist.isEmpty()) { - AbstractBlock block = worklist.poll(); - processBlock(block, worklist); - } - } - - /** - * Merge outSet with in-set of successors. - */ - private boolean updateOutBlock(AbstractBlock block) { - BitSet union = new BitSet(frameMapBuilder.getNumberOfStackSlots()); - block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ))); - BitSet outSet = liveOutMap.get(block); - // check if changed - if (outSet == null || !union.equals(outSet)) { - liveOutMap.put(block, union); - return true; - } - return false; - } - - private void processBlock(AbstractBlock block, Deque> worklist) { - if (updateOutBlock(block)) { - try (Indent indent = Debug.logAndIndent("handle block %s", block)) { - List instructions = lir.getLIRforBlock(block); - // get out set and mark intervals - BitSet outSet = liveOutMap.get(block); - markOutInterval(outSet, getBlockEnd(instructions)); - printLiveSet("liveOut", outSet); - - // process instructions - BlockClosure closure = new BlockClosure((BitSet) outSet.clone()); - for (int i = instructions.size() - 1; i >= 0; i--) { - LIRInstruction inst = instructions.get(i); - closure.processInstructionBottomUp(inst); - } - - // add predecessors to work list - worklist.addAll(block.getPredecessors()); - // set in set and mark intervals - BitSet inSet = closure.getCurrentSet(); - liveInMap.put(block, inSet); - markInInterval(inSet, getBlockBegin(instructions)); - printLiveSet("liveIn", inSet); - } - } - } - - private void printLiveSet(String label, BitSet liveSet) { - if (Debug.isLogEnabled()) { - try (Indent indent = Debug.logAndIndent(label)) { - Debug.log("%s", liveSetToString(liveSet)); - } - } - } - - private String liveSetToString(BitSet liveSet) { - StringBuilder sb = new StringBuilder(); - for (int i = liveSet.nextSetBit(0); i >= 0; i = liveSet.nextSetBit(i + 1)) { - StackInterval interval = getIntervalFromStackId(i); - sb.append(interval.getOperand()).append(" "); - } - return sb.toString(); - } - - protected void markOutInterval(BitSet outSet, int blockEndOpId) { - for (int i = outSet.nextSetBit(0); i >= 0; i = outSet.nextSetBit(i + 1)) { - StackInterval interval = getIntervalFromStackId(i); - Debug.log("mark live operand: %s", interval.getOperand()); - interval.addTo(blockEndOpId); - } - } - - protected void markInInterval(BitSet inSet, int blockFirstOpId) { - for (int i = inSet.nextSetBit(0); i >= 0; i = inSet.nextSetBit(i + 1)) { - StackInterval interval = getIntervalFromStackId(i); - Debug.log("mark live operand: %s", interval.getOperand()); - interval.addFrom(blockFirstOpId); - } - } - - private final class BlockClosure { - private final BitSet currentSet; - - private BlockClosure(BitSet set) { - currentSet = set; - } - - private BitSet getCurrentSet() { - return currentSet; - } - - /** - * Process all values of an instruction bottom-up, i.e. definitions before usages. - * Values that start or end at the current operation are not included. - */ - private void processInstructionBottomUp(LIRInstruction op) { - try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { - // kills - op.visitEachTemp(this::defConsumer); - op.visitEachOutput(this::defConsumer); - // forEachDestroyedCallerSavedRegister(op, this::defConsumer); - - // gen - values that are considered alive for this state - op.visitEachAlive(this::useConsumer); - op.visitEachState(this::useConsumer); - // mark locations - // gen - op.visitEachInput(this::useConsumer); - } - } - - /** - * @see InstructionValueConsumer - * - * @param inst - * @param operand - * @param mode - * @param flags - */ - private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { - if (isVirtualStackSlot(operand)) { - VirtualStackSlot vslot = asVirtualStackSlot(operand); - addUse(vslot, inst, flags); - Debug.log("set operand: %s", operand); - currentSet.set(vslot.getId()); - } - } - - /** - * - * @see InstructionValueConsumer - * - * @param inst - * @param operand - * @param mode - * @param flags - */ - private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet flags) { - if (isVirtualStackSlot(operand)) { - VirtualStackSlot vslot = asVirtualStackSlot(operand); - addDef(vslot, inst); - Debug.log("clear operand: %s", operand); - currentSet.clear(vslot.getId()); - } - - } - - private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet flags) { - StackInterval interval = getOrCreateInterval(stackSlot); - if (flags.contains(OperandFlag.UNINITIALIZED)) { - // Stack slot is marked uninitialized so we have to assume it is live all - // the time. - if (Debug.isMeterEnabled() && !(interval.from() == 0 && interval.to() == maxOpId())) { - uninitializedSlots.increment(); - } - interval.addDef(0); - interval.addUse(maxOpId()); - } else { - interval.addUse(inst.id()); - } - } - - private void addDef(VirtualStackSlot stackSlot, LIRInstruction inst) { - StackInterval interval = getOrCreateInterval(stackSlot); - interval.addDef(inst.id()); - } - + if (Debug.isMeterEnabled()) { + StackSlotAllocator.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize); } } - private static int getBlockBegin(List instructions) { - return instructions.get(0).id(); - } + // ==================== + // step 1: number instructions + // ==================== + + /** + * Numbers all instructions in all blocks. + * + * @return The id of the last operation. + */ + private static int numberInstructions(LIR lir, List> sortedBlocks) { + int opId = 0; + int index = 0; + for (AbstractBlock block : sortedBlocks) { - private static int getBlockEnd(List instructions) { - return instructions.get(instructions.size() - 1).id() + 1; + List instructions = lir.getLIRforBlock(block); + + int numInst = instructions.size(); + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + op.setId(opId); + + index++; + opId += 2; // numbering of lirOps by two + } + } + assert (index << 1) == opId : "must match: " + (index << 1); + return opId - 2; } - private StackInterval getOrCreateInterval(VirtualStackSlot stackSlot) { - StackInterval interval = get(stackSlot); - if (interval == null) { - interval = new StackInterval(stackSlot, stackSlot.getLIRKind()); - put(stackSlot, interval); - } - return interval; + // ==================== + // step 2: build intervals + // ==================== + + private void buildIntervals() { + new FixPointIntervalBuilder(lir, stackSlotMap, maxOpId()).build(); } - private StackInterval get(VirtualStackSlot stackSlot) { - return stackSlotMap[stackSlot.getId()]; - } - - private StackInterval getIntervalFromStackId(int id) { - return stackSlotMap[id]; - } - - private void put(VirtualStackSlot stackSlot, StackInterval interval) { - stackSlotMap[stackSlot.getId()] = interval; - } + // ==================== + // step 3: verify intervals + // ==================== private void verifyIntervals() { forEachInterval(interval -> { - assert interval.verify(this); + assert interval.verify(maxOpId()); }); } - private void forEachInterval(Consumer proc) { - for (StackInterval interval : stackSlotMap) { - if (interval != null) { - proc.accept(interval); - } - } - } - - public void dumpIntervals(String label) { - Debug.dump(stackSlotMap, label); - } - - private void createUnhandled() { - unhandled = new LinkedList<>(); - active = new LinkedList<>(); - forEachInterval(this::insertSortedByFrom); - } - - private void insertSortedByFrom(StackInterval interval) { - unhandled.add(interval); - unhandled.sort((a, b) -> a.from() - b.from()); - } - - private void insertSortedByTo(StackInterval interval) { - active.add(interval); - active.sort((a, b) -> a.to() - b.to()); - } + // ==================== + // step 4: allocate stack slots + // ==================== private void allocateStackSlots() { - // create interval lists - createUnhandled(); + // create unhandled lists + forEachInterval(unhandled::add); for (StackInterval current = activateNext(); current != null; current = activateNext()) { try (Indent indent = Debug.logAndIndent("allocate %s", current)) { @@ -395,7 +188,7 @@ StackSlotAllocator.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotRangeSize(slotRange.getSlots())); StackSlotAllocator.allocatedSlots.increment(); } else { - assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpexted VirtualStackSlot type: " + virtualSlot; + assert virtualSlot instanceof SimpleVirtualStackSlot : "Unexpected VirtualStackSlot type: " + virtualSlot; StackSlot slot = findFreeSlot((SimpleVirtualStackSlot) virtualSlot); if (slot != null) { /* @@ -440,58 +233,108 @@ } } - private EnumMap> freeSlots = new EnumMap<>(SlotSize.class); + private EnumMap> freeSlots; + + /** + * @return The list of free stack slots for {@code size} or {@code null} if there is none. + */ + private Deque getOrNullFreeSlots(SlotSize size) { + if (freeSlots == null) { + return null; + } + return freeSlots.get(size); + } + /** + * @return the list of free stack slots for {@code size}. If there is none a list is + * created. + */ + private Deque getOrInitFreeSlots(SlotSize size) { + assert size != SlotSize.Illegal; + Deque freeList; + if (freeSlots != null) { + freeList = freeSlots.get(size); + } else { + freeSlots = new EnumMap<>(SlotSize.class); + freeList = null; + } + if (freeList == null) { + freeList = new ArrayDeque<>(); + freeSlots.put(size, freeList); + } + assert freeList != null; + return freeList; + } + + /** + * Gets a free stack slot for {@code slot} or {@code null} if there is none. + */ private StackSlot findFreeSlot(SimpleVirtualStackSlot slot) { assert slot != null; SlotSize size = forKind(slot.getLIRKind()); - LinkedList freeList = size == SlotSize.Illegal ? null : freeSlots.get(size); + if (size == SlotSize.Illegal) { + return null; + } + Deque freeList = getOrNullFreeSlots(size); if (freeList == null) { return null; } - return freeList.pollFirst(); + return freeList.pollLast(); } + /** + * Adds a stack slot to the list of free slots. + */ private void freeSlot(StackSlot slot) { SlotSize size = forKind(slot.getLIRKind()); if (size == SlotSize.Illegal) { return; } - LinkedList freeList = freeSlots.get(size); - if (freeList == null) { - freeList = new LinkedList<>(); - freeSlots.put(size, freeList); - } - freeList.add(slot); + getOrInitFreeSlots(size).addLast(slot); } + /** + * Gets the next unhandled interval and finishes handled intervals. + */ private StackInterval activateNext() { if (unhandled.isEmpty()) { return null; } - StackInterval next = unhandled.pollFirst(); + StackInterval next = unhandled.poll(); + // finish handled intervals for (int id = next.from(); activePeekId() < id;) { - finished(active.pollFirst()); + finished(active.poll()); } - Debug.log("activte %s", next); - insertSortedByTo(next); + Debug.log("active %s", next); + active.add(next); return next; } + /** + * Gets the lowest {@link StackInterval#to() end position} of all active intervals. If there + * is none {@link Integer#MAX_VALUE} is returned. + */ private int activePeekId() { - StackInterval first = active.peekFirst(); + StackInterval first = active.peek(); if (first == null) { return Integer.MAX_VALUE; } return first.to(); } + /** + * Finishes {@code interval} by adding its location to the list of free stack slots. + */ private void finished(StackInterval interval) { StackSlot location = interval.location(); Debug.log("finished %s (freeing %s)", interval, location); freeSlot(location); } + // ==================== + // step 5: assign stack slots + // ==================== + private void assignStackSlots() { for (AbstractBlock block : sortedBlocks) { lir.getLIRforBlock(block).forEach(op -> { @@ -520,5 +363,33 @@ } return value; } + + // ==================== + // + // ==================== + + /** + * Gets the highest instruction id. + */ + private int maxOpId() { + return maxOpId; + } + + private StackInterval get(VirtualStackSlot stackSlot) { + return stackSlotMap[stackSlot.getId()]; + } + + private void forEachInterval(Consumer proc) { + for (StackInterval interval : stackSlotMap) { + if (interval != null) { + proc.accept(interval); + } + } + } + + private void dumpIntervals(String label) { + Debug.dump(stackSlotMap, label); + } + } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackInterval.java Tue Feb 03 17:03:19 2015 +0100 @@ -24,9 +24,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -public class StackInterval { +public final class StackInterval { private static final int INVALID_START = Integer.MAX_VALUE; private static final int INVALID_END = Integer.MIN_VALUE; @@ -34,25 +33,16 @@ private final LIRKind kind; private int from = INVALID_START; private int to = INVALID_END; - private final StackUsePosList usePos; private StackSlot location; - public enum UseType { - // Prefixes for c1viz - M_USE, - S_DEF - } - public StackInterval(VirtualStackSlot operand, LIRKind kind) { this.operand = operand; this.kind = kind; - this.usePos = new StackUsePosList(); } - public boolean verify(LSStackSlotAllocator.Allocator allocator) { - assert usePosList().verify(); - // maxOpId + 1 it the last position in the last block (i.e. the "write position") - assert from >= 0 && to <= allocator.maxOpId() + 1 : String.format("from %d, to %d, maxOpId %d", from, to, allocator.maxOpId()); + public boolean verify(int maxOpId) { + // maxOpId + 1 is the last position in the last block (i.e. the "write position") + assert 0 <= from && from <= to && to <= maxOpId + 1 : String.format("from %d, to %d, maxOpId %d", from, to, maxOpId); return true; } @@ -60,18 +50,6 @@ return operand; } - public void addUse(int opId) { - addTo(opId); - Debug.log("Adding use pos: %d", opId); - usePos.add(opId, UseType.M_USE); - } - - public void addDef(int opId) { - addFrom(opId); - Debug.log("Adding def pos: %d", opId); - usePos.add(opId, UseType.S_DEF); - } - public void addTo(int opId) { if (opId >= to) { to = opId; @@ -100,10 +78,6 @@ this.location = location; } - public StackInterval locationHint() { - return null; - } - public int from() { return from; } @@ -112,10 +86,6 @@ return to; } - public StackUsePosList usePosList() { - return usePos; - } - public void fixFrom() { if (from == INVALID_START) { from = 0; diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/StackUsePosList.java Tue Feb 03 17:02:15 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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.lir.stackslotalloc; - -import java.util.*; - -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.lir.stackslotalloc.StackInterval.*; - -public class StackUsePosList { - - LinkedList usePosList; - LinkedList typeList; - - StackUsePosList() { - this.usePosList = new LinkedList<>(); - this.typeList = new LinkedList<>(); - } - - public int size() { - return usePosList.size(); - } - - public int usePos(int i) { - return usePosList.get(i); - } - - public void add(int opId, UseType type) { - if (usePosList.isEmpty() || opId <= usePosList.getLast()) { - usePosList.add(opId); - typeList.add(type); - } else if (opId >= usePosList.getFirst()) { - usePosList.addFirst(opId); - typeList.addFirst(type); - } else { - int size = usePosList.size(); - - assert size >= 2 : "Should be handled by the cases above"; - assert size == typeList.size() : "types and use pos out of sync"; - - ListIterator posIt = usePosList.listIterator(size - 1); - ListIterator typeIt = typeList.listIterator(size - 1); - - // we start with size-2 because we know it will not inserted at the end - while (posIt.hasPrevious()) { - assert posIt.nextIndex() == typeIt.nextIndex(); - int current = posIt.previous(); - - if (current >= opId) { - posIt.next(); - posIt.add(opId); - typeIt.add(type); - assert verify(); - return; - } - typeIt.previous(); - } - GraalInternalError.shouldNotReachHere(String.format("Unable to insert %d into %s", opId, usePosList)); - } - } - - public UseType getType(int i) { - return typeList.get(i); - } - - @Override - public String toString() { - return usePosList.toString() + System.lineSeparator() + typeList.toString(); - } - - public boolean verify() { - int prev = -1; - for (int i = usePosList.size() - 1; i >= 0; --i) { - int current = usePosList.get(i); - assert prev <= current : String.format("use positions not sorted: %d after %d", current, prev); - prev = current; - } - return true; - } - -} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Tue Feb 03 17:03:19 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -31,6 +31,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.debug.*; public abstract class LoopPolicies { @@ -45,7 +46,17 @@ } LoopBeginNode loopBegin = loop.loopBegin(); double entryProbability = probabilities.applyAsDouble(loopBegin.forwardEnd()); - return entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue(); + if (entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue()) { + // check whether we're allowed to peel this loop + for (Node node : loop.inside().nodes()) { + if (node instanceof ControlFlowAnchorNode) { + return false; + } + } + return true; + } else { + return false; + } } public static boolean shouldFullUnroll(LoopEx loop) { @@ -57,7 +68,17 @@ int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue(); maxNodes = Math.min(maxNodes, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount()); int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); - return size * maxTrips <= maxNodes; + if (size * maxTrips <= maxNodes) { + // check whether we're allowed to unroll this loop + for (Node node : loop.inside().nodes()) { + if (node instanceof ControlFlowAnchorNode) { + return false; + } + } + return true; + } else { + return false; + } } public static boolean shouldTryUnswitch(LoopEx loop) { diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.loop.phases; + +import java.util.function.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; + +public class LoopPeelingPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + ToDoubleFunction probabilities = new FixedNodeProbabilityCache(); + LoopsData data = new LoopsData(graph); + for (LoopEx loop : data.outerFirst()) { + if (LoopPolicies.shouldPeel(loop, probabilities)) { + Debug.log("Peeling %s", loop); + LoopTransformations.peel(loop); + Debug.dump(graph, "After peeling %s", loop); + } + } + data.deleteUnusedNodes(); + } + } +} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java Tue Feb 03 17:02:15 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012, 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.loop.phases; - -import static com.oracle.graal.compiler.common.GraalOptions.*; - -import java.util.function.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.loop.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; - -public class LoopTransformHighPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (LoopPeeling.getValue()) { - ToDoubleFunction probabilities = new FixedNodeProbabilityCache(); - LoopsData data = new LoopsData(graph); - for (LoopEx loop : data.outerFirst()) { - if (LoopPolicies.shouldPeel(loop, probabilities)) { - Debug.log("Peeling %s", loop); - LoopTransformations.peel(loop); - Debug.dump(graph, "After peeling %s", loop); - } - } - data.deleteUnusedNodes(); - } - } - } -} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Tue Feb 03 17:02:15 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2012, 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.loop.phases; - -import static com.oracle.graal.compiler.common.GraalOptions.*; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.*; -import com.oracle.graal.loop.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; - -public class LoopTransformLowPhase extends Phase { - - private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); - private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates"); - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (ReassociateInvariants.getValue()) { - final LoopsData dataReassociate = new LoopsData(graph); - try (Scope s = Debug.scope("ReassociateInvariants")) { - for (LoopEx loop : dataReassociate.loops()) { - loop.reassociateInvariants(); - } - } catch (Throwable e) { - throw Debug.handle(e); - } - dataReassociate.deleteUnusedNodes(); - } - if (LoopUnswitch.getValue()) { - boolean unswitched; - do { - unswitched = false; - final LoopsData dataUnswitch = new LoopsData(graph); - for (LoopEx loop : dataUnswitch.loops()) { - if (LoopPolicies.shouldTryUnswitch(loop)) { - List controlSplits = LoopTransformations.findUnswitchable(loop); - if (controlSplits != null) { - UNSWITCH_CANDIDATES.increment(); - if (LoopPolicies.shouldUnswitch(loop, controlSplits)) { - if (Debug.isLogEnabled()) { - logUnswitch(loop, controlSplits); - } - LoopTransformations.unswitch(loop, controlSplits); - UNSWITCHED.increment(); - unswitched = true; - break; - } - } - } - } - } while (unswitched); - } - } - } - - private static void logUnswitch(LoopEx loop, List controlSplits) { - StringBuilder sb = new StringBuilder("Unswitching "); - sb.append(loop).append(" at "); - for (ControlSplitNode controlSplit : controlSplits) { - sb.append(controlSplit).append(" ["); - NodePosIterator it = controlSplit.successors().iterator(); - while (it.hasNext()) { - sb.append(controlSplit.probability((AbstractBeginNode) it.next())); - if (it.hasNext()) { - sb.append(", "); - } - } - sb.append("]"); - } - Debug.log("%s", sb); - } -} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, 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.loop.phases; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; + +public class LoopUnswitchingPhase extends Phase { + + private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); + private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates"); + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + boolean unswitched; + do { + unswitched = false; + final LoopsData dataUnswitch = new LoopsData(graph); + for (LoopEx loop : dataUnswitch.loops()) { + if (LoopPolicies.shouldTryUnswitch(loop)) { + List controlSplits = LoopTransformations.findUnswitchable(loop); + if (controlSplits != null) { + UNSWITCH_CANDIDATES.increment(); + if (LoopPolicies.shouldUnswitch(loop, controlSplits)) { + if (Debug.isLogEnabled()) { + logUnswitch(loop, controlSplits); + } + LoopTransformations.unswitch(loop, controlSplits); + UNSWITCHED.increment(); + unswitched = true; + break; + } + } + } + } + } while (unswitched); + } + } + + private static void logUnswitch(LoopEx loop, List controlSplits) { + StringBuilder sb = new StringBuilder("Unswitching "); + sb.append(loop).append(" at "); + for (ControlSplitNode controlSplit : controlSplits) { + sb.append(controlSplit).append(" ["); + NodePosIterator it = controlSplit.successors().iterator(); + while (it.hasNext()) { + sb.append(controlSplit.probability((AbstractBeginNode) it.next())); + if (it.hasNext()) { + sb.append(", "); + } + } + sb.append("]"); + } + Debug.log("%s", sb); + } +} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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.loop.phases; + +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; + +public class ReassociateInvariantPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + final LoopsData dataReassociate = new LoopsData(graph); + try (Scope s = Debug.scope("ReassociateInvariants")) { + for (LoopEx loop : dataReassociate.loops()) { + loop.reassociateInvariants(); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + dataReassociate.deleteUnusedNodes(); + } + } +} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Tue Feb 03 17:03:19 2015 +0100 @@ -78,9 +78,19 @@ } /** - * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, ordered - * in increasing {@link #phiPredecessorIndex}. This method is suited to create new loop - * {@link PhiNode}. + * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, in + * increasing {@link #phiPredecessorIndex} order. This method is suited to create new loop + * {@link PhiNode}.
+ * + * For example a new PhiNode may be added as follow: + * + *
+     * PhiNode phi = new ValuePhiNode(stamp, loop);
+     * phi.addInput(forwardEdgeValue);
+     * for (LoopEndNode loopEnd : loop.orderedLoopEnds()) {
+     *     phi.addInput(backEdgeValue(loopEnd));
+     * }
+     * 
* * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop */ @@ -165,7 +175,7 @@ return super.verify(); } - public int nextEndIndex() { + int nextEndIndex() { return nextEndIndex++; } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Tue Feb 03 17:03:19 2015 +0100 @@ -28,6 +28,10 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.spi.*; +/** + * LoopEnd nodes represent a loop back-edge. When a LoopEnd is reached, execution continues at the + * {@linkplain #loopBegin() loop header}. + */ @NodeInfo public class LoopEndNode extends AbstractEndNode { @@ -79,17 +83,18 @@ } /** - * Returns the 0-based index of this loop end. This is not the index into {@link PhiNode} - * values at the loop begin. Use {@link AbstractMergeNode#phiPredecessorIndex(AbstractEndNode)} - * for this purpose. + * Returns the index of this loop end amongst its {@link LoopBeginNode}'s loop ends.
* - * @return The 0-based index of this loop end. + * Since a LoopBeginNode also has {@linkplain LoopBeginNode#forwardEnds() forward ends}, this is + * not the index into {@link PhiNode} values at the loop begin. Use + * {@link LoopBeginNode#phiPredecessorIndex(AbstractEndNode)} for this purpose. + * */ - public int endIndex() { + int endIndex() { return endIndex; } - public void setEndIndex(int idx) { + void setEndIndex(int idx) { this.endIndex = idx; } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Tue Feb 03 17:03:19 2015 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.debug; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -47,4 +48,9 @@ public void generate(NodeLIRBuilderTool generator) { // do nothing } + + @Override + protected void afterClone(Node other) { + assert false : this + " should never be cloned"; + } } diff -r d2ec5e56ed31 -r 212299803bf6 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 Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Tue Feb 03 17:03:19 2015 +0100 @@ -56,27 +56,31 @@ gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), gen.operand(getValue())); } + /** + * Determines if the compiler should emit code to test whether a given object has a finalizer + * that must be registered with the runtime upon object initialization. + */ + public static boolean mayHaveFinalizer(ValueNode object, Assumptions assumptions) { + ObjectStamp objectStamp = (ObjectStamp) object.stamp(); + if (objectStamp.isExactType()) { + return objectStamp.type().hasFinalizer(); + } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { + // if either the declared type of receiver or the holder + // can be assumed to have no finalizers + if (assumptions.useOptimisticAssumptions()) { + assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type()); + return false; + } + } + return true; + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (!(forValue.stamp() instanceof ObjectStamp)) { return this; } - - ObjectStamp objectStamp = (ObjectStamp) forValue.stamp(); - - boolean needsCheck = true; - if (objectStamp.isExactType()) { - needsCheck = objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) { - // if either the declared type of receiver or the holder - // can be assumed to have no finalizers - if (tool.assumptions().useOptimisticAssumptions()) { - tool.assumptions().recordNoFinalizableSubclassAssumption(objectStamp.type()); - needsCheck = false; - } - } - - if (!needsCheck) { + if (!mayHaveFinalizer(forValue, tool.assumptions())) { return null; } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Tue Feb 03 17:03:19 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -36,6 +36,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @@ -192,7 +193,7 @@ int fixedCount = 0; while (fixed instanceof FixedWithNextNode) { fixed = ((FixedWithNextNode) fixed).next(); - if (fixed instanceof CommitAllocationNode) { + if (fixed instanceof CommitAllocationNode || fixed instanceof ControlFlowAnchorNode) { return false; } fixedCount++; diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Feb 03 17:03:19 2015 +0100 @@ -582,22 +582,12 @@ out.printf("\"[%s|%c]\"", interval.getOperand(), interval.getOperand().getKind().getTypeChar()); } - StackInterval hint = interval.locationHint(); - out.printf("%s %s ", interval.getOperand(), hint != null ? hint.getOperand() : -1); + out.printf("%s -1 ", interval.getOperand()); out.printf("[%d, %d[", interval.from(), interval.to()); - // print use positions - int prev = -1; - StackUsePosList usePosList = interval.usePosList(); - for (int i = usePosList.size() - 1; i >= 0; --i) { - assert prev <= usePosList.usePos(i) : "use positions not sorted"; - out.printf("%d %s ", usePosList.usePos(i), usePosList.getType(i)); - prev = usePosList.usePos(i); - } - // print spill state - out.printf(" \"%s\"", "NOT_SUPPORTED"); + out.printf(" \"NOT_SUPPORTED\""); out.println(); } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Feb 03 17:03:19 2015 +0100 @@ -137,49 +137,20 @@ HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite(), OptimisticOptimizations.NONE); // EA frame and clean up. - try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) { - new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext); - new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext); - } catch (Throwable t) { - Debug.handle(t); - } - - // to make frame propagations visible retry expandTree - while (expandTree(graph, assumptions, expansionLogger)) { + do { try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) { new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext); new IncrementalCanonicalizerPhase<>(canonicalizer, new ConditionalEliminationPhase()).apply(graph, tierContext); } catch (Throwable t) { Debug.handle(t); } - } + } while (expandTree(graph, assumptions, expansionLogger)); if (expansionLogger != null) { expansionLogger.print(callTarget); } - for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) { - Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage()); - throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception); - } - - new VerifyNoIntrinsicsLeftPhase().apply(graph, false); - for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) { - materializeNode.replaceAtUsages(materializeNode.getFrame()); - graph.removeFixed(materializeNode); - } - for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) { - if (virtualObjectNode instanceof VirtualOnlyInstanceNode) { - VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode; - virtualOnlyInstanceNode.setAllowMaterialization(true); - } else if (virtualObjectNode instanceof VirtualInstanceNode) { - VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode; - ResolvedJavaType type = virtualInstanceNode.type(); - if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) { - virtualInstanceNode.setIdentity(false); - } - } - } + postPartialEvaluation(graph); } catch (Throwable e) { throw Debug.handle(e); @@ -188,6 +159,26 @@ return graph; } + private static void postPartialEvaluation(final StructuredGraph graph) { + NeverPartOfCompilationNode.verifyNotFoundIn(graph); + for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) { + materializeNode.replaceAtUsages(materializeNode.getFrame()); + graph.removeFixed(materializeNode); + } + for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) { + if (virtualObjectNode instanceof VirtualOnlyInstanceNode) { + VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode; + virtualOnlyInstanceNode.setAllowMaterialization(true); + } else if (virtualObjectNode instanceof VirtualInstanceNode) { + VirtualInstanceNode virtualInstanceNode = (VirtualInstanceNode) virtualObjectNode; + ResolvedJavaType type = virtualInstanceNode.type(); + if (type.getAnnotation(CompilerDirectives.ValueType.class) != null) { + virtualInstanceNode.setIdentity(false); + } + } + } + } + private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) { ParameterNode thisNode = graph.getParameter(0); diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Feb 03 17:03:19 2015 +0100 @@ -176,5 +176,8 @@ @Option(help = "Print additional more verbose Truffle compilation statistics at the end of a run.", type = OptionType.Debug) public static final OptionValue TruffleCompilationStatisticDetails = new OptionValue<>(false); + + @Option(help = "Experimental new version of the partial evaluator.", type = OptionType.Debug) + public static final OptionValue FastPE = new OptionValue<>(false); // @formatter:on } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Tue Feb 03 17:03:19 2015 +0100 @@ -144,7 +144,12 @@ } public TruffleInliningDecision findByCall(OptimizedDirectCallNode callNode) { - return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null); + for (TruffleInliningDecision d : getCallSites()) { + if (d.getProfile().getCallNode() == callNode) { + return d; + } + } + return null; } /** diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Tue Feb 03 17:02:15 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java Tue Feb 03 17:03:19 2015 +0100 @@ -25,6 +25,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.replacements.nodes.*; @NodeInfo @@ -44,4 +45,11 @@ public final String getMessage() { return message + " " + arguments.toString(); } + + public static void verifyNotFoundIn(final StructuredGraph graph) { + for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) { + Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage()); + throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception); + } + } } diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyNoIntrinsicsLeftPhase.java Tue Feb 03 17:02:15 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle.phases; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.truffle.*; -import com.oracle.graal.truffle.nodes.frame.*; - -/** - * Verification phase for checking that no frame intrinsic nodes introduced by the - * {@link PartialEvaluator} are still in the graph. - */ -public class VerifyNoIntrinsicsLeftPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - verifyNoInstanceLeft(graph, NewFrameNode.class); - } - - public static void verifyNoInstanceLeft(StructuredGraph graph, Class clazz) { - if (graph.getNodes(clazz).count() != 0) { - throw new VerificationError("Found unexpected node(s): %s", graph.getNodes(clazz)); - } - } -} diff -r d2ec5e56ed31 -r 212299803bf6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Tue Feb 03 17:03:19 2015 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.substitutions; + +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.truffle.nodes.frame.*; +import com.oracle.truffle.api.*; + +/** + * Provider of {@link GraphBuilderPlugin}s for Truffle classes. + */ +@ServiceProvider(GraphBuilderPluginsProvider.class) +public class TruffleGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { + public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + plugins.register(metaAccess, CompilerDirectivesPlugin.class); + } + + /** + * Plugins for {@link CompilerDirectives}. + */ + enum CompilerDirectivesPlugin implements GraphBuilderPlugin { + inInterpreter() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(ConstantNode.forBoolean(false)); + return true; + } + }, + inCompiledCode() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(ConstantNode.forBoolean(true)); + return true; + } + }, + transferToInterpreter() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); + return true; + } + }, + transferToInterpreterAndInvalidate() { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); + return true; + } + }, + interpreterOnly(Runnable.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + return true; + } + }, + interpreterOnly$(Callable.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + return true; + } + }, + injectBranchProbability(double.class, boolean.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + ValueNode probability = args[0]; + ValueNode condition = args[1]; + builder.append(new BranchProbabilityNode(probability, condition)); + return true; + } + }, + bailout(String.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + // TODO: is this too eager? Should a BailoutNode be created instead? + ValueNode message = args[0]; + if (message.isConstant()) { + throw new BailoutException(message.asConstant().toValueString()); + } + throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)"); + } + }, + + isCompilationConstant(Object.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + ValueNode arg0 = args[0]; + if (arg0 instanceof BoxNode) { + arg0 = ((BoxNode) arg0).getValue(); + } + if (arg0.isConstant()) { + builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true))); + return true; + } + + // Cannot create MacroNodes in a plugin (yet) + return false; + } + }, + materialize(Object.class) { + public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + builder.append(new ForceMaterializeNode(args[0])); + return true; + } + }; + + CompilerDirectivesPlugin(Class... parameterTypes) { + this.parameterTypes = parameterTypes; + } + + private final Class[] parameterTypes; + + public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { + return GraphBuilderPlugin.resolveTarget(metaAccess, CompilerDirectives.class, name(), parameterTypes); + } + } +} diff -r d2ec5e56ed31 -r 212299803bf6 mxtool/mx.py --- a/mxtool/mx.py Tue Feb 03 17:02:15 2015 +0100 +++ b/mxtool/mx.py Tue Feb 03 17:03:19 2015 +0100 @@ -3440,7 +3440,10 @@ print 'node [shape=rect];' for p in projects(): for dep in p.canonical_deps(): - print '"' + p.name + '"->"' + dep + '"' + print '"' + p.name + '"->"' + dep + '";' + if hasattr(p, '_declaredAnnotationProcessors'): + for ap in p._declaredAnnotationProcessors: + print '"' + p.name + '"->"' + ap + '" [style="dashed"];' print '}' def _source_locator_memento(deps):