# HG changeset patch # User Josef Eisl # Date 1423054277 -3600 # Node ID a5f47cb74b1b8fc2f6117a6f002f506d06f5ab78 # Parent 0f3c0639dc3f9679360ad3844600944507cfbb1b# Parent 036c0b9bd4f5d36a18550327505befc35cef89c2 Merge. diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Wed Feb 04 13:51:17 2015 +0100 @@ -67,7 +67,7 @@ StructuredGraph graph = new StructuredGraph(javaMethod); GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(); - new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, conf, OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph); HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); new CanonicalizerPhase(true).apply(graph, context); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java Wed Feb 04 13:51:17 2015 +0100 @@ -0,0 +1,72 @@ +/* + * 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.compiler.test; + +import static org.junit.Assert.*; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy; + +public class SchedulingTest extends GraphScheduleTest { + + public static int testValueProxyInputsSnippet(int s) { + int i = 0; + while (true) { + i++; + int v = i - s * 2; + if (i == s) { + return v; + } + } + } + + @Test + public void testValueProxyInputs() { + StructuredGraph graph = parseEager("testValueProxyInputsSnippet"); + for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) { + fs.replaceAtUsages(null); + GraphUtil.killWithUnusedFloatingInputs(fs); + } + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.LATEST); + schedule.apply(graph); + NodeMap nodeToBlock = schedule.getCFG().getNodeToBlock(); + assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1); + LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first(); + List list = schedule.nodesFor(nodeToBlock.get(loopExit)); + for (BinaryArithmeticNode node : graph.getNodes().filter(BinaryArithmeticNode.class)) { + if (!(node instanceof AddNode)) { + assertTrue(nodeToBlock.get(node) == nodeToBlock.get(loopExit)); + assertTrue(list.indexOf(node) < list.indexOf(loopExit)); + } + } + } +} diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Feb 04 13:51:17 2015 +0100 @@ -152,7 +152,8 @@ graph = new StructuredGraph(method); try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) { Assumptions assumptions = new Assumptions(false); - new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), + OptimisticOptimizations.ALL).apply(graph); context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); new DeadCodeEliminationPhase().apply(graph); diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java Wed Feb 04 13:51:17 2015 +0100 @@ -238,7 +238,7 @@ OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; Assumptions assumptions = new Assumptions(false); - GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts); + GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, null, graphBuilderConfig, optimisticOpts); graphBuilder.apply(graph); } catch (Throwable ex) { Debug.handle(ex); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Feb 04 13:51:17 2015 +0100 @@ -166,7 +166,7 @@ isLeafNode = inputs.getCount() + successors.getCount() == 0; canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz); - startGVNNumber = clazz.hashCode(); + startGVNNumber = clazz.getName().hashCode(); NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class); assert info != null : "Missing NodeInfo annotation on " + clazz; diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Feb 04 13:51:17 2015 +0100 @@ -37,11 +37,13 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.nodes.*; @@ -108,17 +110,24 @@ public static final ArrayList staticCounters = new ArrayList<>(); @SuppressFBWarnings(value = "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION", justification = "concurrent abstraction calls are in synchronized block") - private static int getIndex(DynamicCounterNode counter) { + private static int getIndex(DynamicCounterNode counter, StructuredGraph currentGraph) { if (!enabled) { throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName()); } String name; String group = counter.getGroup(); if (counter.isWithContext()) { - StructuredGraph graph = counter.graph(); - name = counter.getName() + " @ " + graph.graphId() + ":" + (graph.method() == null ? "" : graph.method().format("%h.%n")); - if (graph.name != null) { - name += " (" + graph.name + ")"; + name = counter.getName() + " @ "; + if (currentGraph.method() != null) { + StackTraceElement stackTraceElement = currentGraph.method().asStackTraceElement(0); + if (stackTraceElement != null) { + name += " " + stackTraceElement.toString(); + } else { + name += currentGraph.method().format("%h.%n"); + } + } + if (currentGraph.name != null) { + name += " (" + currentGraph.name + ")"; } name += "#" + group; @@ -374,20 +383,41 @@ } } + private static final LocationIdentity COUNTER_ARRAY_LOCATION = NamedLocationIdentity.mutable("COUNTER_ARRAY_LOCATION"); private static final LocationIdentity COUNTER_LOCATION = NamedLocationIdentity.mutable("COUNTER_LOCATION"); + @NodeInfo(nameTemplate = "CounterIndex") + private static class CounterIndexNode extends FloatingNode implements LIRLowerable { + + protected final Object counter; + protected final int countersSize; + + protected CounterIndexNode(Stamp stamp, DynamicCounterNode counter, int countersSize) { + super(stamp); + this.countersSize = countersSize; + this.counter = counter; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + int index = BenchmarkCounters.getIndex((DynamicCounterNode) counter, graph()); + if (index >= countersSize) { + throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + countersSize + ")"); + } + + generator.setResult(this, JavaConstant.forIntegerKind(getKind(), index)); + } + } + public static void lower(DynamicCounterNode counter, HotSpotRegistersProvider registers, HotSpotVMConfig config, Kind wordKind) { StructuredGraph graph = counter.graph(); ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), wordKind, true, false)); - int index = BenchmarkCounters.getIndex(counter); - if (index >= config.graalCountersSize) { - throw new GraalInternalError("too many counters, reduce number of counters or increase -XX:GraalCounterSize=... (current value: " + config.graalCountersSize + ")"); - } - ConstantLocationNode arrayLocation = graph.unique(new ConstantLocationNode(COUNTER_LOCATION, config.graalCountersThreadOffset)); + CounterIndexNode index = graph.unique(new CounterIndexNode(StampFactory.forKind(wordKind), counter, config.graalCountersSize)); + ConstantLocationNode arrayLocation = graph.unique(new ConstantLocationNode(COUNTER_ARRAY_LOCATION, config.graalCountersThreadOffset)); ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE)); - ConstantLocationNode location = graph.unique(new ConstantLocationNode(COUNTER_LOCATION, Unsafe.ARRAY_LONG_INDEX_SCALE * index)); + IndexedLocationNode location = graph.unique(new IndexedLocationNode(COUNTER_LOCATION, 0, index, Unsafe.ARRAY_LONG_INDEX_SCALE)); ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE)); AddNode add = graph.unique(new AddNode(read, counter.getIncrement())); WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE)); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSnippetReflectionProvider.java Wed Feb 04 13:51:17 2015 +0100 @@ -41,12 +41,18 @@ @Override public Object asObject(ResolvedJavaType type, JavaConstant constant) { + if (constant.isNull()) { + return null; + } HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant; return hsConstant.asObject(type); } @Override public T asObject(Class type, JavaConstant constant) { + if (constant.isNull()) { + return null; + } HotSpotObjectConstant hsConstant = (HotSpotObjectConstant) constant; return hsConstant.asObject(type); } diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java Wed Feb 04 13:51:17 2015 +0100 @@ -25,6 +25,9 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.java.*; +import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin; +import com.oracle.graal.java.GraphBuilderPlugins.Registration; +import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @@ -35,17 +38,9 @@ @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) { - assert args.length == 1; - ValueNode rcvr = args[0]; + Registration r = new Registration(plugins, metaAccess, Object.class); + r.register1("getClass", Receiver.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode rcvr) { GuardingPiNode pi = builder.append(new GuardingPiNode(rcvr)); StampProvider stampProvider = builder.getStampProvider(); LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, pi)); @@ -53,10 +48,6 @@ builder.push(Kind.Object, mirror); return true; } - }; - - public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { - return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, name()); - } + }); } } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Wed Feb 04 13:51:17 2015 +0100 @@ -36,6 +36,7 @@ import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.debug.*; import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.nodes.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; @@ -687,7 +688,10 @@ Kind kind = field.getKind(); T receiver = frameState.apop(); if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); + GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ValueNode) receiver, (ResolvedJavaField) field)) { + appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); + } } else { handleUnresolvedLoadField(field, receiver); } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java Wed Feb 04 13:51:17 2015 +0100 @@ -0,0 +1,62 @@ +/* + * 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.java; + +import java.util.*; +import java.util.stream.*; + +import com.oracle.graal.api.meta.*; + +/** + * Default implementation of {@link GraphBuilderPlugins} that uses a map. + */ +public class DefaultGraphBuilderPlugins implements GraphBuilderPlugins { + + private final Map plugins = new HashMap<>(); + + /** + * Registers an invocation plugin for a given method. There must be no plugin currently + * registered for {@code method}. + */ + public void register(ResolvedJavaMethod method, InvocationPlugin plugin) { + assert InvocationPluginChecker.check(method, plugin); + GraphBuilderPlugin oldValue = plugins.put(method, plugin); + // System.out.println("registered: " + plugin); + assert oldValue == null; + } + + /** + * Gets the plugin for a given method. + * + * @param method the method to lookup + * @return the plugin associated with {@code method} or {@code null} if none exists + */ + public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) { + return plugins.get(method); + } + + @Override + public String toString() { + return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", ")); + } +} diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * 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.java; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -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) { - ValueNode object = args[0]; - if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) { - builder.append(new RegisterFinalizerNode(object)); - } - return true; - } - - public ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess) { - return GraphBuilderPlugin.resolveTarget(metaAccess, Object.class, ""); - } - }; - - @Override - public String toString() { - 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 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Feb 04 13:51:17 2015 +0100 @@ -37,6 +37,8 @@ private final DebugInfoMode debugInfoMode; private final boolean doLivenessAnalysis; private final boolean inlineTrivial; + private GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin; + private GraphBuilderPlugins.ParameterPlugin parameterPlugin; public static enum DebugInfoMode { SafePointsOnly, @@ -72,6 +74,12 @@ this.inlineTrivial = inlineTrivial; } + public GraphBuilderConfiguration copy() { + GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, inlineTrivial); + result.loadFieldPlugin = loadFieldPlugin; + return result; + } + public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, inlineTrivial); } @@ -93,6 +101,14 @@ return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newInlineTrivial); } + public GraphBuilderPlugins.LoadFieldPlugin getLoadFieldPlugin() { + return loadFieldPlugin; + } + + public void setLoadFieldPlugin(GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin) { + this.loadFieldPlugin = loadFieldPlugin; + } + public ResolvedJavaType[] getSkippedExceptionTypes() { return skippedExceptionTypes; } @@ -145,4 +161,12 @@ public boolean shouldInlineTrivial() { return inlineTrivial; } + + public GraphBuilderPlugins.ParameterPlugin getParameterPlugin() { + return parameterPlugin; + } + + public void setParameterPlugin(GraphBuilderPlugins.ParameterPlugin parameterPlugin) { + this.parameterPlugin = parameterPlugin; + } } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Feb 04 13:51:17 2015 +0100 @@ -42,6 +42,7 @@ import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; import com.oracle.graal.java.BciBlockMapping.LocalLiveness; +import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.calc.*; @@ -63,12 +64,13 @@ public GraphBuilderPhase(GraphBuilderConfiguration config) { this.graphBuilderConfig = config; - this.graphBuilderPlugins = new GraphBuilderPlugins(); + this.graphBuilderPlugins = new DefaultGraphBuilderPlugins(); } @Override protected void run(StructuredGraph graph, HighTierContext context) { - new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph); + new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins, + context.getOptimisticOptimizations()).run(graph); } public GraphBuilderConfiguration getGraphBuilderConfig() { @@ -92,6 +94,7 @@ private final OptimisticOptimizations optimisticOpts; private final StampProvider stampProvider; private final Assumptions assumptions; + private final ConstantReflectionProvider constantReflectionProvider; /** * Gets the graph being processed by this builder. @@ -100,19 +103,21 @@ return currentGraph; } - public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, - OptimisticOptimizations optimisticOpts) { + public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider, + GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.metaAccess = metaAccess; this.stampProvider = stampProvider; this.assumptions = assumptions; this.graphBuilderPlugins = graphBuilderPlugins; + this.constantReflectionProvider = constantReflectionProvider; assert metaAccess != null; } - public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - this(metaAccess, stampProvider, assumptions, graphBuilderConfig, null, optimisticOpts); + public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider, + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + this(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, null, optimisticOpts); } @Override @@ -123,7 +128,7 @@ assert method.getCode() != null : "method must contain bytecodes: " + method; this.currentGraph = graph; HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, null); - frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving()); + frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin()); TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method); try { BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI); @@ -557,7 +562,7 @@ @Override protected ValueNode genObjectEquals(ValueNode x, ValueNode y) { - return new ObjectEqualsNode(x, y); + return ObjectEqualsNode.create(x, y, constantReflectionProvider); } @Override @@ -773,11 +778,10 @@ if (GraalOptions.InlineDuringParsing.getValue() && invokeKind.isDirect()) { if (graphBuilderPlugins != null) { - GraphBuilderPlugin plugin = graphBuilderPlugins.getPlugin(targetMethod); + InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod); if (plugin != null) { int beforeStackSize = frameState.stackSize; - if (plugin.handleInvocation(this, args)) { - // System.out.println("used plugin: " + plugin); + if (plugin.apply(this, args)) { assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize; return; } @@ -998,7 +1002,6 @@ } public T append(T v) { - assert !(v instanceof ConstantNode); T added = currentGraph.unique(v); return added; } @@ -1482,11 +1485,24 @@ } condition = genUnique(condition); - ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); - ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); + if (condition instanceof LogicConstantNode) { + LogicConstantNode constantLogicNode = (LogicConstantNode) condition; + boolean value = constantLogicNode.getValue(); + if (negate) { + value = !value; + } + BciBlock nextBlock = falseBlock; + if (value) { + nextBlock = trueBlock; + } + appendGoto(createTarget(nextBlock, frameState)); + } else { + ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState); + ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState); - ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability); - append(ifNode); + ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability); + append(ifNode); + } } public StampProvider getStampProvider() { diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java Wed Feb 04 13:51:17 2015 +0100 @@ -22,43 +22,14 @@ */ package com.oracle.graal.java; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.nodes.*; - /** - * Extensions for handling certain bytecode instructions while building a - * {@linkplain StructuredGraph graph} from a bytecode stream. + * Marker interface for graph builder plugins. + * + * Concrete plugins implement one of the sub-interfaces of this interface. + * + * @see GraphBuilderPluginsProvider + * @see GraphBuilderPlugins + * @see GraphBuilderPlugins.Registration */ public interface GraphBuilderPlugin { - - /** - * Processes an invocation parsed in a bytecode stream and add nodes to a graph being - * constructed that implement the semantics of the invocation. - * - * @param builder object being used to build a graph - * @param args the arguments to the invocation - */ - boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args); - - /** - * Gets the method handled by {@link #handleInvocation(GraphBuilderContext, ValueNode[])} . - */ - ResolvedJavaMethod getInvocationTarget(MetaAccessProvider metaAccess); - - /** - * 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("") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(methodName, parameterTypes)); - } catch (NoSuchMethodException | SecurityException e) { - throw new GraalInternalError(e); - } - } } diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java Wed Feb 04 13:51:17 2015 +0100 @@ -22,45 +22,225 @@ */ package com.oracle.graal.java; +import static java.lang.String.*; + +import java.lang.reflect.*; import java.util.*; -import java.util.stream.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; /** - * A repository of {@link GraphBuilderPlugin}s. + * Interface for managing a set of graph builder {@link GraphBuilderPlugin}s. */ -public class GraphBuilderPlugins { +public interface GraphBuilderPlugins { - private final Map map = new HashMap<>(); + public interface LoadFieldPlugin extends GraphBuilderPlugin { + boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field); + } + + public interface ParameterPlugin extends GraphBuilderPlugin { + FloatingNode interceptParameter(int index); + } /** - * Registers all the constants of an enum that implements {@link GraphBuilderPlugin}. + * Plugin for handling a method invocation. */ - public & GraphBuilderPlugin> void register(MetaAccessProvider metaAccess, Class enumClass) { - assert Enum.class.isAssignableFrom(enumClass); - Object[] enumConstants = enumClass.getEnumConstants(); - for (Object o : enumConstants) { - GraphBuilderPlugin gbp = (GraphBuilderPlugin) o; - ResolvedJavaMethod target = gbp.getInvocationTarget(metaAccess); - GraphBuilderPlugin oldValue = map.put(target, gbp); - // System.out.println("registered: " + gbp); - assert oldValue == null; + public interface InvocationPlugin extends GraphBuilderPlugin { + /** + * Tries to handle an invocation to a method with no arguments. + * + * @return {@code true} this plugin handled the invocation + */ + default boolean apply(GraphBuilderContext builder) { + throw invalidHandler(builder); + } + + /** + * Tries to handle an invocation to a method with one argument. + * + * @return {@code true} this plugin handled the invocation + */ + default boolean apply(GraphBuilderContext builder, ValueNode arg) { + throw invalidHandler(builder, arg); + } + + /** + * Tries to handle an invocation to a method with two arguments. + * + * @return {@code true} this plugin handled the invocation + */ + default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) { + throw invalidHandler(builder, arg1, arg2); + } + + /** + * Tries to handle an invocation to a method with three arguments. + * + * @return {@code true} this plugin handled the invocation + */ + default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + throw invalidHandler(builder, arg1, arg2, arg3); + } + + default boolean apply(GraphBuilderContext builder, ValueNode[] args) { + if (args.length == 0) { + return apply(builder); + } else if (args.length == 1) { + return apply(builder, args[0]); + } else if (args.length == 2) { + return apply(builder, args[0], args[1]); + } else if (args.length == 3) { + return apply(builder, args[0], args[1], args[2]); + } else { + throw invalidHandler(builder, args); + } + } + + default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) { + return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length); } } /** - * Gets the plugin for a given method registered in the object. + * Utility for {@linkplain GraphBuilderPlugins#register(ResolvedJavaMethod, InvocationPlugin) + * registration} of plugins. + */ + public static class Registration { + + /** + * Sentinel class for use with {@link Registration#register1}, + * {@link Registration#register2} or {@link Registration#register3} to denote the receiver + * argument for a non-static method. + */ + public static final class Receiver { + private Receiver() { + throw GraalInternalError.shouldNotReachHere(); + } + } + + private final GraphBuilderPlugins plugins; + private final MetaAccessProvider metaAccess; + private final Class declaringClass; + + /** + * Creates an object for registering plugins for methods declared by a given class. + * + * @param plugins where to register the plugins + * @param metaAccess used to resolve classes and methods + * @param declaringClass the class declaring the methods for which plugins will be + * registered via this object + */ + public Registration(GraphBuilderPlugins plugins, MetaAccessProvider metaAccess, Class declaringClass) { + this.plugins = plugins; + this.metaAccess = metaAccess; + this.declaringClass = declaringClass; + } + + /** + * Registers a plugin for a method with no arguments. + * + * @param name the name of the method + * @param plugin the plugin to be registered + */ + public void register0(String name, InvocationPlugin plugin) { + plugins.register(resolve(metaAccess, declaringClass, name), plugin); + } + + /** + * Registers a plugin for a method with 1 argument. + * + * @param name the name of the method + * @param plugin the plugin to be registered + */ + public void register1(String name, Class arg, InvocationPlugin plugin) { + ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg); + plugins.register(method, plugin); + } + + /** + * Registers a plugin for a method with 2 arguments. + * + * @param name the name of the method + * @param plugin the plugin to be registered + */ + public void register2(String name, Class arg1, Class arg2, InvocationPlugin plugin) { + ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2); + plugins.register(method, plugin); + } + + /** + * Registers a plugin for a method with 3 arguments. + * + * @param name the name of the method + * @param plugin the plugin to be registered + */ + public void register3(String name, Class arg1, Class arg2, Class arg3, InvocationPlugin plugin) { + ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3); + plugins.register(method, plugin); + } + + /** + * Resolves a method given a declaring class, name and parameter types. + */ + public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class declaringClass, String name, Class... parameterTypes) { + try { + return metaAccess.lookupJavaMethod(name.equals("") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes)); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } + } + + public static class InvocationPluginChecker { + static final Class[] APPLY0 = {GraphBuilderContext.class}; + static final Class[] APPLY1 = {GraphBuilderContext.class, ValueNode.class}; + static final Class[] APPLY2 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class}; + static final Class[] APPLY3 = {GraphBuilderContext.class, ValueNode.class, ValueNode.class, ValueNode.class}; + static final Class[][] SIGS = {APPLY0, APPLY1, APPLY2, APPLY3}; + + public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) { + int arguments = method.getSignature().getParameterCount(!method.isStatic()); + assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)")); + Method expected = null; + for (Method m : plugin.getClass().getDeclaredMethods()) { + if (m.getName().equals("apply")) { + Class[] parameterTypes = m.getParameterTypes(); + assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n actual: (%s)", method.format("%H.%n(%p)"), + sigString(SIGS[arguments]), sigString(m.getParameterTypes())); + expected = m; + } + } + assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin); + return true; + } + + protected static String sigString(Class... sig) { + StringBuilder sb = new StringBuilder(); + for (Class t : sig) { + if (sb.length() != 0) { + sb.append(", "); + } + sb.append(t.getSimpleName()); + } + return sb.toString(); + } + + } + + /** + * Registers an {@link InvocationPlugin} for a given method. There must be no plugin currently + * registered for {@code method}. + */ + void register(ResolvedJavaMethod method, InvocationPlugin plugin); + + /** + * Gets the {@link InvocationPlugin} for a given method. * * @param method the method to lookup * @return the plugin associated with {@code method} or {@code null} if none exists */ - public GraphBuilderPlugin getPlugin(ResolvedJavaMethod method) { - return map.get(method); - } - - @Override - public String toString() { - return map.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", ")); - } + InvocationPlugin lookupInvocation(ResolvedJavaMethod method); } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java Wed Feb 04 13:51:17 2015 +0100 @@ -30,9 +30,7 @@ */ public interface GraphBuilderPluginsProvider extends Service { /** - * Registers the plugins provided by this object with a plugins registry. - * - * @param plugins registry of plugins + * Registers the plugins provided by this object. */ void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins); } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Wed Feb 04 13:51:17 2015 +0100 @@ -31,6 +31,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.debug.*; +import com.oracle.graal.java.GraphBuilderPlugins.ParameterPlugin; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -81,14 +82,20 @@ } } - public final void initializeForMethodStart(boolean eagerResolve) { + public final void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { int javaIndex = 0; int index = 0; if (!method.isStatic()) { // add the receiver - ParameterNode receiver = graph.unique(new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()))); - storeLocal(javaIndex, receiver); + FloatingNode receiver = null; + if (parameterPlugin != null) { + receiver = parameterPlugin.interceptParameter(index); + } + if (receiver == null) { + receiver = new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass())); + } + storeLocal(javaIndex, graph.unique(receiver)); javaIndex = 1; index = 1; } @@ -107,8 +114,14 @@ } else { stamp = StampFactory.forKind(kind); } - ParameterNode param = graph.unique(new ParameterNode(index, stamp)); - storeLocal(javaIndex, param); + FloatingNode param = null; + if (parameterPlugin != null) { + param = parameterPlugin.interceptParameter(index); + } + if (param == null) { + param = new ParameterNode(index, stamp); + } + storeLocal(javaIndex, graph.unique(param)); javaIndex += kind.getSlotCount(); index++; } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java Wed Feb 04 13:51:17 2015 +0100 @@ -0,0 +1,97 @@ +/* + * 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.java; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin; +import com.oracle.graal.java.GraphBuilderPlugins.Registration; +import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver; +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 StandardGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider { + public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + Registration r = new Registration(plugins, metaAccess, Object.class); + r.register1("", Receiver.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode object) { + if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) { + builder.append(new RegisterFinalizerNode(object)); + } + return true; + } + }); + + for (Kind kind : Kind.values()) { + if (kind.isPrimitive() && kind != Kind.Void) { + new BoxPlugin(kind).register(metaAccess, plugins); + new UnboxPlugin(kind).register(metaAccess, plugins); + } + } + } + + static class BoxPlugin implements InvocationPlugin { + + private final Kind kind; + + BoxPlugin(Kind kind) { + this.kind = kind; + } + + public boolean apply(GraphBuilderContext builder, ValueNode value) { + ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); + builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind))); + return true; + } + + void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass()); + plugins.register(method, this); + } + } + + static class UnboxPlugin implements InvocationPlugin { + + private final Kind kind; + + UnboxPlugin(Kind kind) { + this.kind = kind; + } + + public boolean apply(GraphBuilderContext builder, ValueNode value) { + builder.push(kind, builder.append(new UnboxNode(value, kind))); + return true; + } + + void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) { + String name = kind.toJavaClass().getSimpleName() + "Value"; + ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name); + plugins.register(method, this); + } + } +} diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -69,18 +69,21 @@ @Override public void lower(LoweringTool tool) { - /* - * Don't allow guards with action None and reason RuntimeConstraint to float. In cases where - * 2 guards are testing equivalent conditions they might be lowered at the same location. If - * the guard with the None action is lowered before the the other guard then the code will - * be stuck repeatedly deoptimizing without invalidating the code. Conditional elimination - * will eliminate the guard if it's truly redundant in this case. - */ - if (graph().getGuardsStage().allowsFloatingGuards() && (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint)) { - ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode(); - this.replaceAtUsages(guard); - ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode())); - graph().replaceFixedWithFixed(this, newAnchor); + if (graph().getGuardsStage().allowsFloatingGuards()) { + /* + * Don't allow guards with action None and reason RuntimeConstraint to float. In cases + * where 2 guards are testing equivalent conditions they might be lowered at the same + * location. If the guard with the None action is lowered before the the other guard + * then the code will be stuck repeatedly deoptimizing without invalidating the code. + * Conditional elimination will eliminate the guard if it's truly redundant in this + * case. + */ + if (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint) { + ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode(); + this.replaceAtUsages(guard); + ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode())); + graph().replaceFixedWithFixed(this, newAnchor); + } } else { lowerToIf().lower(tool); } diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -39,14 +39,19 @@ @NodeInfo public abstract class CompareNode extends BinaryOpLogicNode { + protected final Condition condition; + protected final boolean unorderedIsTrue; + /** * Constructs a new Compare instruction. * * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ - public CompareNode(ValueNode x, ValueNode y) { + public CompareNode(Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) { super(x, y); + this.condition = condition; + this.unorderedIsTrue = unorderedIsTrue; } /** @@ -54,14 +59,18 @@ * * @return the condition */ - public abstract Condition condition(); + public final Condition condition() { + return condition; + } /** * Checks whether unordered inputs mean true or false (only applies to float operations). * * @return {@code true} if unordered inputs produce true */ - public abstract boolean unorderedIsTrue(); + public final boolean unorderedIsTrue() { + return this.unorderedIsTrue; + } private ValueNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) { Constant trueConstant = conditionalNode.trueValue().asConstant(); @@ -93,8 +102,10 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - if (forX.isConstant() && forY.isConstant()) { - return LogicConstantNode.forBoolean(condition().foldCondition(forX.asConstant(), forY.asConstant(), tool.getConstantReflection(), unorderedIsTrue())); + ConstantReflectionProvider constantReflection = tool.getConstantReflection(); + LogicNode constantCondition = tryConstantFold(condition(), forX, forY, constantReflection, unorderedIsTrue()); + if (constantCondition != null) { + return constantCondition; } ValueNode result; if (forX.isConstant()) { @@ -115,7 +126,14 @@ return this; } - protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY); + public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { + if (forX.isConstant() && forY.isConstant() && constantReflection != null) { + return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue)); + } + return null; + } + + protected abstract LogicNode duplicateModified(ValueNode newX, ValueNode newY); protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) { if (nonConstant instanceof ConditionalNode) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; @@ -31,22 +32,21 @@ import com.oracle.graal.nodes.util.*; @NodeInfo(shortName = "==") -public class FloatEqualsNode extends CompareNode { +public final class FloatEqualsNode extends CompareNode { public FloatEqualsNode(ValueNode x, ValueNode y) { - super(x, y); + super(Condition.EQ, false, x, y); assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp : x.stamp() + " " + y.stamp(); assert x.stamp().isCompatible(y.stamp()); } - @Override - public Condition condition() { - return Condition.EQ; - } - - @Override - public boolean unorderedIsTrue() { - return false; + public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { + LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + if (result != null) { + return result; + } else { + return new FloatEqualsNode(x, y); + } } @Override diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -33,23 +33,10 @@ @NodeInfo(shortName = "<") public class FloatLessThanNode extends CompareNode { - protected final boolean unorderedIsTrue; - public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) { - super(x, y); + super(Condition.LT, unorderedIsTrue, x, y); assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp; assert x.stamp().isCompatible(y.stamp()); - this.unorderedIsTrue = unorderedIsTrue; - } - - @Override - public Condition condition() { - return Condition.LT; - } - - @Override - public boolean unorderedIsTrue() { - return unorderedIsTrue; } @Override diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -33,22 +33,12 @@ public class IntegerBelowNode extends CompareNode { public IntegerBelowNode(ValueNode x, ValueNode y) { - super(x, y); + super(Condition.BT, false, x, y); assert x.stamp() instanceof IntegerStamp; assert y.stamp() instanceof IntegerStamp; } @Override - public Condition condition() { - return Condition.BT; - } - - @Override - public boolean unorderedIsTrue() { - return false; - } - - @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode result = super.canonical(tool, forX, forY); if (result != this) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -35,22 +35,12 @@ public class IntegerEqualsNode extends CompareNode { public IntegerEqualsNode(ValueNode x, ValueNode y) { - super(x, y); + super(Condition.EQ, false, x, y); assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object; assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } @Override - public Condition condition() { - return Condition.EQ; - } - - @Override - public boolean unorderedIsTrue() { - return false; - } - - @Override protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { PrimitiveConstant primitive = (PrimitiveConstant) constant; if (primitive.getKind() == Kind.Int && primitive.asInt() == 0) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -35,22 +35,12 @@ public class IntegerLessThanNode extends CompareNode { public IntegerLessThanNode(ValueNode x, ValueNode y) { - super(x, y); + super(Condition.LT, false, x, y); assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object; assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } @Override - public Condition condition() { - return Condition.LT; - } - - @Override - public boolean unorderedIsTrue() { - return false; - } - - @Override protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { PrimitiveConstant primitive = (PrimitiveConstant) constant; assert condition() == Condition.LT; diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -44,7 +44,7 @@ if (forX.isConstant() && forY.isConstant()) { return LogicConstantNode.forBoolean((forX.asJavaConstant().asLong() & forY.asJavaConstant().asLong()) == 0); } - if (getX().stamp() instanceof IntegerStamp && getY().stamp() instanceof IntegerStamp) { + if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { IntegerStamp xStamp = (IntegerStamp) forX.stamp(); IntegerStamp yStamp = (IntegerStamp) forY.stamp(); if ((xStamp.upMask() & yStamp.upMask()) == 0) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -55,7 +55,7 @@ LogicNode equalComp; LogicNode lessComp; if (getX().stamp() instanceof FloatStamp) { - equalComp = graph().unique(new FloatEqualsNode(getX(), getY())); + equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection())); lessComp = graph().unique(new FloatLessThanNode(getX(), getY(), isUnorderedLess)); } else { equalComp = graph().unique(new IntegerEqualsNode(getX(), getY())); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -24,6 +24,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; @@ -38,6 +39,15 @@ assert y.stamp() instanceof AbstractObjectStamp; } + public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { + LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + if (result != null) { + return result; + } else { + return new ObjectEqualsNode(x, y); + } + } + private void virtualizeNonVirtualComparison(State state, ValueNode other, VirtualizerTool tool) { if (!state.getVirtualObject().hasIdentity() && state.getVirtualObject().entryKind(0) == Kind.Boolean) { if (other.isConstant()) { @@ -75,7 +85,7 @@ /* * One of the two objects has identity, the other doesn't. In code, this looks like * "Integer.valueOf(a) == new Integer(b)", which is always false. - * + * * In other words: an object created via valueOf can never be equal to one created * by new in the same compilation unit. */ diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java Wed Feb 04 13:51:17 2015 +0100 @@ -33,22 +33,12 @@ public class PointerEqualsNode extends CompareNode { public PointerEqualsNode(ValueNode x, ValueNode y) { - super(x, y); + super(Condition.EQ, false, x, y); assert x.stamp() instanceof AbstractPointerStamp; assert y.stamp() instanceof AbstractPointerStamp; } @Override - public Condition condition() { - return Condition.EQ; - } - - @Override - public boolean unorderedIsTrue() { - return false; - } - - @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return LogicConstantNode.tautology(); diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Wed Feb 04 13:51:17 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 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Feb 04 13:51:17 2015 +0100 @@ -619,8 +619,8 @@ if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) { graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null))); } else { - createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply( - graph); + createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, replacements.providers.getConstantReflection(), + GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); } afterParsing(graph); @@ -633,9 +633,9 @@ return graph; } - protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts) { - return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, graphBuilderConfig, optimisticOpts); + protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflectionProvider, + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, constantReflectionProvider, graphBuilderConfig, optimisticOpts); } protected void afterParsing(StructuredGraph graph) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Wed Feb 04 13:51:17 2015 +0100 @@ -177,7 +177,8 @@ Suites suites = suitesProvider.createSuites(); removeInliningPhase(suites); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), + OptimisticOptimizations.ALL).apply(graph); PhaseSuite graphBuilderSuite = getGraphBuilderSuite(suitesProvider); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java Wed Feb 04 13:51:17 2015 +0100 @@ -38,14 +38,14 @@ public DefaultTruffleSplittingStrategyNew(OptimizedDirectCallNode call) { this.call = call; this.splitStart = TruffleCompilerOptions.TruffleSplittingStartCallCount.getValue(); - this.splittingEnabled = isSplittingEnabled(); + this.splittingEnabled = isSplittingEnabled(call); this.argumentStamp = DefaultTruffleStamp.getInstance(); if (TruffleCompilerOptions.TruffleSplittingAggressive.getValue()) { splittingForced = true; } } - private boolean isSplittingEnabled() { + private static boolean isSplittingEnabled(OptimizedDirectCallNode call) { if (!TruffleCompilerOptions.TruffleSplitting.getValue()) { return false; } diff -r 0f3c0639dc3f -r a5f47cb74b1b 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 Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Feb 04 13:51:17 2015 +0100 @@ -36,9 +36,11 @@ import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node; +import com.oracle.graal.java.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; @@ -70,15 +72,26 @@ private final TruffleCache truffleCache; private final SnippetReflectionProvider snippetReflection; private final ResolvedJavaMethod callDirectMethod; + private final ResolvedJavaMethod callInlinedMethod; private final ResolvedJavaMethod callSiteProxyMethod; + protected final ResolvedJavaMethod callRootMethod; + private final GraphBuilderConfiguration configForRoot; - public PartialEvaluator(Providers providers, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) { + public PartialEvaluator(Providers providers, GraphBuilderConfiguration configForRoot, TruffleCache truffleCache, SnippetReflectionProvider snippetReflection) { this.providers = providers; this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue()); this.snippetReflection = snippetReflection; this.truffleCache = truffleCache; this.callDirectMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod()); + this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod()); this.callSiteProxyMethod = providers.getMetaAccess().lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD); + this.configForRoot = configForRoot; + + try { + callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class)); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } } public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) { @@ -91,65 +104,34 @@ } catch (Throwable e) { throw Debug.handle(e); } - final StructuredGraph graph = truffleCache.createRootGraph(callTarget.toString()); + + final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod); assert graph != null : "no graph for root method"; try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph)) { - // Canonicalize / constant propagate. - PhaseContext baseContext = new PhaseContext(providers, assumptions); - - injectConstantCallTarget(graph, callTarget, baseContext); - - Debug.dump(graph, "Before expansion"); - - TruffleExpansionLogger expansionLogger = null; - if (TraceTruffleExpansion.getValue()) { - expansionLogger = new TruffleExpansionLogger(providers, graph); - } - expandTree(graph, assumptions, expansionLogger); + Map graphCache = null; + if (CacheGraphs.getValue()) { + graphCache = new HashMap<>(); + } + PhaseContext baseContext = new PhaseContext(providers, assumptions); + HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite(), OptimisticOptimizations.NONE); - TruffleInliningCache inliningCache = null; - if (TruffleFunctionInlining.getValue()) { - callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); - if (TruffleFunctionInliningCache.getValue()) { - inliningCache = new TruffleInliningCache(); - } + if (TruffleCompilerOptions.FastPE.getValue()) { + fastPartialEvaluation(callTarget, assumptions, graph, baseContext, tierContext); + } else { + createRootGraph(graph); + partialEvaluation(callTarget, assumptions, graph, baseContext, tierContext); } - expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache); - if (Thread.currentThread().isInterrupted()) { return null; } new VerifyFrameDoesNotEscapePhase().apply(graph, false); - if (TraceTruffleCompilationHistogram.getValue() && constantReceivers != null) { createHistogram(); } - - canonicalizer.apply(graph, baseContext); - Map graphCache = null; - if (CacheGraphs.getValue()) { - graphCache = new HashMap<>(); - } - HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite(), OptimisticOptimizations.NONE); - - // EA frame and clean up. - 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); - } - postPartialEvaluation(graph); } catch (Throwable e) { @@ -159,6 +141,104 @@ return graph; } + private class InterceptLoadFieldPlugin implements GraphBuilderPlugins.LoadFieldPlugin { + + public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) { + System.out.println("Load field plugin called for receiver: " + receiver + " and field " + field); + + if (receiver.isConstant()) { + JavaConstant asJavaConstant = receiver.asJavaConstant(); + JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant); + if (result != null) { + ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess())); + builder.push(constantNode.getKind(), constantNode); + return true; + } + } + return false; + } + } + + private class InterceptReceiverPlugin implements GraphBuilderPlugins.ParameterPlugin { + + private final Object receiver; + + public InterceptReceiverPlugin(Object receiver) { + this.receiver = receiver; + } + + public FloatingNode interceptParameter(int index) { + if (index == 0) { + return ConstantNode.forConstant(snippetReflection.forObject(receiver), providers.getMetaAccess()); + } + return null; + } + } + + @SuppressWarnings("unused") + private void fastPartialEvaluation(OptimizedCallTarget callTarget, Assumptions assumptions, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { + GraphBuilderConfiguration newConfig = configForRoot.copy(); + newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin()); + newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget)); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph); + Debug.dump(graph, "After FastPE"); + } + + private void partialEvaluation(final OptimizedCallTarget callTarget, final Assumptions assumptions, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { + injectConstantCallTarget(graph, callTarget, baseContext); + + Debug.dump(graph, "Before expansion"); + + TruffleExpansionLogger expansionLogger = null; + if (TraceTruffleExpansion.getValue()) { + expansionLogger = new TruffleExpansionLogger(providers, graph); + } + + expandTree(graph, assumptions, expansionLogger); + + TruffleInliningCache inliningCache = null; + if (TruffleFunctionInlining.getValue()) { + callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); + if (TruffleFunctionInliningCache.getValue()) { + inliningCache = new TruffleInliningCache(); + } + } + + expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache); + + if (Thread.currentThread().isInterrupted()) { + return; + } + + canonicalizer.apply(graph, baseContext); + // EA frame and clean up. + 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); + } + } + + public StructuredGraph createRootGraph(StructuredGraph graph) { + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot, + TruffleCompilerImpl.Optimizations).apply(graph); + return graph; + } + + public StructuredGraph createInlineGraph(String name) { + StructuredGraph graph = new StructuredGraph(name, callInlinedMethod); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot, + TruffleCompilerImpl.Optimizations).apply(graph); + return graph; + } + private static void postPartialEvaluation(final StructuredGraph graph) { NeverPartOfCompilationNode.verifyNotFoundIn(graph); for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) { @@ -464,7 +544,7 @@ private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, TruffleInliningDecision decision) { try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) { OptimizedCallTarget target = decision.getTarget(); - StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString()); + StructuredGraph inlineGraph = createInlineGraph(target.toString()); injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext); TruffleExpansionLogger expansionLogger = null; if (TraceTruffleExpansion.getValue()) { diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Wed Feb 04 13:51:17 2015 +0100 @@ -30,13 +30,6 @@ public interface TruffleCache { /** - * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#callBoundary}. - */ - StructuredGraph createRootGraph(String name); - - StructuredGraph createInlineGraph(String name); - - /** * Returns a cached graph for a method with given arguments. */ StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final CanonicalizerPhase finalCanonicalizer); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Wed Feb 04 13:51:17 2015 +0100 @@ -56,7 +56,6 @@ private final Providers providers; private final GraphBuilderConfiguration config; - private final GraphBuilderConfiguration configForRoot; private final OptimisticOptimizations optimisticOptimizations; private final HashMap, StructuredGraph> cache = new HashMap<>(); @@ -68,40 +67,17 @@ private final ResolvedJavaType errorClass; private final ResolvedJavaType controlFlowExceptionClass; - protected final ResolvedJavaMethod callRootMethod; - protected final ResolvedJavaMethod callInlinedMethod; - private long counter; - public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRoot, OptimisticOptimizations optimisticOptimizations) { + public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) { this.providers = providers; this.config = config; - this.configForRoot = configForRoot; this.optimisticOptimizations = optimisticOptimizations; this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class); this.runtimeExceptionClass = providers.getMetaAccess().lookupJavaType(RuntimeException.class); this.errorClass = providers.getMetaAccess().lookupJavaType(Error.class); this.controlFlowExceptionClass = providers.getMetaAccess().lookupJavaType(ControlFlowException.class); - - try { - callRootMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("callRoot", Object[].class)); - } catch (NoSuchMethodException ex) { - throw new RuntimeException(ex); - } - this.callInlinedMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallInlinedMethod()); - } - - public StructuredGraph createInlineGraph(String name) { - StructuredGraph graph = new StructuredGraph(name, callInlinedMethod); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), config, TruffleCompilerImpl.Optimizations).apply(graph); - return graph; - } - - public StructuredGraph createRootGraph(String name) { - StructuredGraph graph = new StructuredGraph(name, callRootMethod); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph); - return graph; } private static List computeCacheKey(ResolvedJavaMethod method, NodeInputList arguments) { @@ -294,7 +270,7 @@ protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) { final StructuredGraph graph = new StructuredGraph(method); - new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), config, optimisticOptimizations).apply(graph); + new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), null, config, optimisticOptimizations).apply(graph); return graph; } diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Feb 04 13:51:17 2015 +0100 @@ -84,9 +84,9 @@ ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes); this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes); - this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations); + this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations); - this.partialEvaluator = new PartialEvaluator(providers, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class)); + this.partialEvaluator = new PartialEvaluator(providers, config, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class)); if (Debug.isEnabled()) { DebugEnvironment.initialize(System.out); diff -r 0f3c0639dc3f -r a5f47cb74b1b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Wed Feb 04 11:31:26 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPluginsProvider.java Wed Feb 04 13:51:17 2015 +0100 @@ -28,6 +28,8 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.java.*; +import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin; +import com.oracle.graal.java.GraphBuilderPlugins.Registration; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.truffle.nodes.frame.*; @@ -39,96 +41,69 @@ @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)); + Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class); + r.register0("inInterpreter", new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder) { + builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(false))); return true; } - }, - inCompiledCode() { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { - builder.append(ConstantNode.forBoolean(true)); + }); + r.register0("inCompiledCode", new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder) { + builder.push(Kind.Boolean, builder.append(ConstantNode.forBoolean(true))); return true; } - }, - transferToInterpreter() { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + }); + r.register0("transferToInterpreter", new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder) { builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); return true; } - }, - transferToInterpreterAndInvalidate() { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + }); + r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder) { builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); return true; } - }, - interpreterOnly(Runnable.class) { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + }); + r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode arg) { return true; } - }, - interpreterOnly$(Callable.class) { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { + }); + r.register1("interpreterOnly", Callable.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode arg) { return true; } - }, - injectBranchProbability(double.class, boolean.class) { - public boolean handleInvocation(GraphBuilderContext builder, ValueNode[] args) { - ValueNode probability = args[0]; - ValueNode condition = args[1]; + }); + r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) { 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]; + }); + r.register1("bailout", String.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode message) { 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()) { + }); + r.register1("isCompilationConstant", Object.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode value) { + if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).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])); + }); + r.register1("materialize", Object.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext builder, ValueNode value) { + builder.append(new ForceMaterializeNode(value)); 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 0f3c0639dc3f -r a5f47cb74b1b mxtool/mx.py --- a/mxtool/mx.py Wed Feb 04 11:31:26 2015 +0100 +++ b/mxtool/mx.py Wed Feb 04 13:51:17 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): diff -r 0f3c0639dc3f -r a5f47cb74b1b test/blacklist_sparc.txt --- a/test/blacklist_sparc.txt Wed Feb 04 11:31:26 2015 +0100 +++ b/test/blacklist_sparc.txt Wed Feb 04 13:51:17 2015 +0100 @@ -1,5 +1,4 @@ com.oracle.graal.replacements.test.StandardMethodSubstitutionsTest com.oracle.graal.hotspot.amd64.test.CompressedNullCheckTest -com.oracle.graal.compiler.test.ea.UnsafeEATest -com.oracle.graal.truffle.test.SimplePartialEvaluationTest -com.oracle.graal.replacements.test.ArraysSubstitutionsTest +com.oracle.graal.hotspot.test.HotSpotCryptoSubstitutionTest +