# HG changeset patch # User Erik Eckstein # Date 1395993922 -3600 # Node ID 3efd4d8ace0bb07cee456dc8286782df01ba9329 # Parent 8c420f405328c90b5e2a10fcbd44eb071c6ead62# Parent 8e7667515e315542a4d907c05097dc9d0384e5f5 Merge diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Mar 28 09:05:22 2014 +0100 @@ -174,7 +174,7 @@ public static void logInliningDecision(final String msg, final Object... args) { try (Scope s = Debug.scope(inliningDecisionsScopeString)) { // Can't use log here since we are varargs - if (Debug.isLogEnabled()) { + if (Debug.isEnabled()) { Debug.logv(msg, args); } } @@ -1040,7 +1040,7 @@ /** * Determines if inlining is possible at the given invoke node. - * + * * @param invoke the invoke that should be inlined * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke */ @@ -1304,7 +1304,7 @@ /** * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. - * + * * @param invoke the invoke that will be replaced * @param inlineGraph the graph that the invoke will be replaced with * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Fri Mar 28 09:05:22 2014 +0100 @@ -85,7 +85,7 @@ } protected StructuredGraph partialEval(RootNode root, Arguments arguments, final Assumptions assumptions, final boolean canonicalizeReads) { - final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root); + final OptimizedCallTargetImpl compilable = (OptimizedCallTargetImpl) Truffle.getRuntime().createCallTarget(root); // Executed AST so that all classes are loaded and initialized. compilable.call(null, arguments); diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Fri Mar 28 09:05:22 2014 +0100 @@ -132,7 +132,7 @@ ensureProfiling(reprofile, reprofile); } - void reportInterpreterCall() { + public void reportInterpreterCall() { callCount++; callAndLoopCount++; } diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Fri Mar 28 09:05:22 2014 +0100 @@ -77,7 +77,7 @@ if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); + return new OptimizedCallTargetImpl(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); } public CallNode createCallNode(CallTarget target) { @@ -90,7 +90,7 @@ @Override public VirtualFrame createVirtualFrame(PackedFrame caller, Arguments arguments, FrameDescriptor frameDescriptor) { - return OptimizedCallTarget.createFrame(frameDescriptor, caller, arguments); + return OptimizedCallTargetImpl.createFrame(frameDescriptor, caller, arguments); } @Override @@ -173,7 +173,7 @@ private static Method getCallMethod() { Method method; try { - method = OptimizedCallTarget.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class}); + method = OptimizedCallTargetImpl.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class}); } catch (NoSuchMethodException | SecurityException e) { throw GraalInternalError.shouldNotReachHere(); } diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Fri Mar 28 09:05:22 2014 +0100 @@ -33,7 +33,7 @@ /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ -abstract class OptimizedCallNode extends DefaultCallNode { +public abstract class OptimizedCallNode extends DefaultCallNode { protected int callCount; diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Mar 28 09:05:22 2014 +0100 @@ -26,7 +26,6 @@ import java.io.*; import java.util.*; -import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; @@ -39,34 +38,27 @@ /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ -public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver { +public abstract class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, ReplaceObserver { - private static final PrintStream OUT = TTY.out().out(); + protected static final PrintStream OUT = TTY.out().out(); - private InstalledCode installedCode; - private Future installedCodeTask; - private boolean compilationEnabled; + protected InstalledCode installedCode; + protected boolean compilationEnabled; private boolean inlined; - private int callCount; + protected int callCount; - private final TruffleCompiler compiler; - private final CompilationProfile compilationProfile; - private final CompilationPolicy compilationPolicy; - private final SpeculationLog speculationLog = new SpeculationLog(); + protected final CompilationProfile compilationProfile; + protected final CompilationPolicy compilationPolicy; + private SpeculationLog speculationLog = new SpeculationLog(); private OptimizedCallTarget splitSource; - OptimizedCallTarget(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { + public OptimizedCallTarget(RootNode rootNode, int invokeCounter, int compilationThreshold, boolean compilationEnabled, CompilationPolicy compilationPolicy) { super(rootNode); - this.compiler = compiler; - this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); - if (TruffleUseTimeForCompilationDecision.getValue()) { - compilationPolicy = new TimedCompilationPolicy(); - } else { - compilationPolicy = new DefaultCompilationPolicy(); - } this.compilationEnabled = compilationEnabled; + this.compilationPolicy = compilationPolicy; + this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); } @@ -92,15 +84,12 @@ return superString; } - public boolean isOptimized() { - return installedCode != null || installedCodeTask != null; + public CompilationProfile getCompilationProfile() { + return compilationProfile; } - @CompilerDirectives.SlowPath @Override - public Object call(PackedFrame caller, Arguments args) { - return callHelper(caller, args); - } + public abstract Object call(PackedFrame caller, Arguments args); public Object callInlined(PackedFrame caller, Arguments arguments) { if (CompilerDirectives.inInterpreter()) { @@ -109,79 +98,6 @@ return executeHelper(caller, arguments); } - private Object callHelper(PackedFrame caller, Arguments args) { - if (installedCode != null && installedCode.isValid()) { - reinstallCallMethodShortcut(); - } - if (TruffleCallTargetProfiling.getValue()) { - callCount++; - } - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) { - try { - return installedCode.execute(this, caller, args); - } catch (InvalidInstalledCodeException ex) { - return compiledCodeInvalidated(caller, args); - } - } else { - return interpreterCall(caller, args); - } - } - - private static void reinstallCallMethodShortcut() { - if (TraceTruffleCompilation.getValue()) { - OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); - } - GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); - } - - public CompilationProfile getCompilationProfile() { - return compilationProfile; - } - - private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { - invalidate(null, null, "Compiled code invalidated"); - return call(caller, args); - } - - private void invalidate(Node oldNode, Node newNode, CharSequence reason) { - InstalledCode m = this.installedCode; - if (m != null) { - CompilerAsserts.neverPartOfCompilation(); - installedCode = null; - compilationProfile.reportInvalidated(); - logOptimizedInvalidated(this, oldNode, newNode, reason); - } - cancelInstalledTask(oldNode, newNode, reason); - } - - private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) { - Future task = this.installedCodeTask; - if (task != null) { - task.cancel(true); - this.installedCodeTask = null; - logOptimizingUnqueued(this, oldNode, newNode, reason); - compilationProfile.reportInvalidated(); - } - } - - private Object interpreterCall(PackedFrame caller, Arguments args) { - CompilerAsserts.neverPartOfCompilation(); - compilationProfile.reportInterpreterCall(); - - if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) { - InstalledCode code = compile(); - if (code != null && code.isValid()) { - this.installedCode = code; - try { - return code.execute(this, caller, args); - } catch (InvalidInstalledCodeException ex) { - return compiledCodeInvalidated(caller, args); - } - } - } - return executeHelper(caller, args); - } - public void performInlining() { if (!TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { return; @@ -234,61 +150,22 @@ }); } - private boolean isCompiling() { - Future codeTask = this.installedCodeTask; - if (codeTask != null) { - if (codeTask.isCancelled()) { - installedCodeTask = null; - return false; - } - return true; - } - return false; + protected boolean shouldCompile() { + return compilationPolicy.shouldCompile(compilationProfile); } - public InstalledCode compile() { - if (isCompiling()) { - if (installedCodeTask.isDone()) { - return receiveInstalledCode(); - } - return null; - } else { - performInlining(); - logOptimizingQueued(this); - this.installedCodeTask = compiler.compile(this); - if (!TruffleBackgroundCompilation.getValue()) { - return receiveInstalledCode(); - } - } - return null; + protected static boolean shouldInline() { + return TruffleFunctionInlining.getValue(); } - private InstalledCode receiveInstalledCode() { - try { - return installedCodeTask.get(); - } catch (InterruptedException | ExecutionException e) { - compilationEnabled = false; - logOptimizingFailed(this, e.getMessage()); - if (e.getCause() instanceof BailoutException) { - // Bailout => move on. - } else { - if (TraceTruffleCompilationExceptions.getValue()) { - e.printStackTrace(OUT); - } - if (TruffleCompilationExceptionsAreFatal.getValue()) { - System.exit(-1); - } - } - return null; - } - } + protected abstract void invalidate(Node oldNode, Node newNode, CharSequence reason); public Object executeHelper(PackedFrame caller, Arguments args) { VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), caller, args); return getRootNode().execute(frame); } - protected static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { + public static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return new FrameWithoutBoxing(descriptor, caller, args); } @@ -393,13 +270,13 @@ } } - private static void logOptimizingQueued(OptimizedCallTarget target) { + protected static void logOptimizingQueued(OptimizedCallTarget target) { if (TraceTruffleCompilationDetails.getValue()) { log(0, "opt queued", target.toString(), target.getDebugProperties()); } } - private static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { + protected static void logOptimizingUnqueued(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { if (TraceTruffleCompilationDetails.getValue()) { Map properties = new LinkedHashMap<>(); addReplaceProperties(properties, oldNode, newNode); @@ -422,7 +299,7 @@ } } - private static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { + protected static void logOptimizedInvalidated(OptimizedCallTarget target, Node oldNode, Node newNode, CharSequence reason) { if (TraceTruffleCompilation.getValue()) { Map properties = new LinkedHashMap<>(); addReplaceProperties(properties, oldNode, newNode); @@ -431,7 +308,7 @@ } } - private static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) { + protected static void logOptimizingFailed(OptimizedCallTarget callSite, CharSequence reason) { Map properties = new LinkedHashMap<>(); properties.put("Reason", reason); log(0, "opt fail", callSite.toString(), properties); diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetImpl.java Fri Mar 28 09:05:22 2014 +0100 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import static com.oracle.graal.truffle.TruffleCompilerOptions.*; + +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Call target for running truffle on a standard VM (and not in SubstrateVM). + */ +public final class OptimizedCallTargetImpl extends OptimizedCallTarget { + + protected final TruffleCompiler compiler; + private Future installedCodeTask; + + OptimizedCallTargetImpl(RootNode rootNode, TruffleCompiler compiler, int invokeCounter, int compilationThreshold, boolean compilationEnabled) { + super(rootNode, invokeCounter, compilationThreshold, compilationEnabled, TruffleUseTimeForCompilationDecision.getValue() ? new TimedCompilationPolicy() : new DefaultCompilationPolicy()); + this.compiler = compiler; + } + + public boolean isOptimized() { + return installedCode != null || installedCodeTask != null; + } + + @CompilerDirectives.SlowPath + @Override + public Object call(PackedFrame caller, Arguments args) { + return callHelper(caller, args); + } + + private Object callHelper(PackedFrame caller, Arguments args) { + if (installedCode != null && installedCode.isValid()) { + reinstallCallMethodShortcut(); + } + if (TruffleCallTargetProfiling.getValue()) { + callCount++; + } + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, installedCode != null)) { + try { + return installedCode.execute(this, caller, args); + } catch (InvalidInstalledCodeException ex) { + return compiledCodeInvalidated(caller, args); + } + } else { + return interpreterCall(caller, args); + } + } + + private static void reinstallCallMethodShortcut() { + if (TraceTruffleCompilation.getValue()) { + OUT.println("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut."); + } + GraalTruffleRuntime.installOptimizedCallTargetCallMethod(); + } + + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { + invalidate(null, null, "Compiled code invalidated"); + return call(caller, args); + } + + @Override + protected void invalidate(Node oldNode, Node newNode, CharSequence reason) { + InstalledCode m = this.installedCode; + if (m != null) { + CompilerAsserts.neverPartOfCompilation(); + installedCode = null; + compilationProfile.reportInvalidated(); + logOptimizedInvalidated(this, oldNode, newNode, reason); + } + cancelInstalledTask(oldNode, newNode, reason); + } + + private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) { + Future task = this.installedCodeTask; + if (task != null) { + task.cancel(true); + this.installedCodeTask = null; + logOptimizingUnqueued(this, oldNode, newNode, reason); + compilationProfile.reportInvalidated(); + } + } + + private Object interpreterCall(PackedFrame caller, Arguments args) { + CompilerAsserts.neverPartOfCompilation(); + compilationProfile.reportInterpreterCall(); + + if (compilationEnabled && compilationPolicy.shouldCompile(compilationProfile)) { + InstalledCode code = compile(); + if (code != null && code.isValid()) { + this.installedCode = code; + try { + return code.execute(this, caller, args); + } catch (InvalidInstalledCodeException ex) { + return compiledCodeInvalidated(caller, args); + } + } + } + return executeHelper(caller, args); + } + + private boolean isCompiling() { + Future codeTask = this.installedCodeTask; + if (codeTask != null) { + if (codeTask.isCancelled()) { + installedCodeTask = null; + return false; + } + return true; + } + return false; + } + + public InstalledCode compile() { + if (isCompiling()) { + if (installedCodeTask.isDone()) { + return receiveInstalledCode(); + } + return null; + } else { + performInlining(); + logOptimizingQueued(this); + this.installedCodeTask = compiler.compile(this); + if (!TruffleBackgroundCompilation.getValue()) { + return receiveInstalledCode(); + } + return null; + } + } + + private InstalledCode receiveInstalledCode() { + try { + return installedCodeTask.get(); + } catch (InterruptedException | ExecutionException e) { + compilationEnabled = false; + logOptimizingFailed(this, e.getMessage()); + if (e.getCause() instanceof BailoutException) { + // Bailout => move on. + } else { + if (TraceTruffleCompilationExceptions.getValue()) { + e.printStackTrace(OUT); + } + if (TruffleCompilationExceptionsAreFatal.getValue()) { + System.exit(-1); + } + } + return null; + } + } + +} diff -r 8e7667515e31 -r 3efd4d8ace0b 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 Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Mar 28 09:05:22 2014 +0100 @@ -37,7 +37,6 @@ import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.Node; import com.oracle.graal.graph.spi.*; -import com.oracle.graal.java.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -57,7 +56,6 @@ import com.oracle.graal.truffle.phases.*; import com.oracle.graal.virtual.phases.ea.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; /** @@ -66,25 +64,17 @@ public class PartialEvaluator { private final Providers providers; - private final ResolvedJavaMethod executeHelperMethod; private final CanonicalizerPhase canonicalizer; - private final GraphBuilderConfiguration config; private Set constantReceivers; private final TruffleCache truffleCache; private final ResolvedJavaType frameType; - public PartialEvaluator(Providers providers, TruffleCache truffleCache, GraphBuilderConfiguration config) { + public PartialEvaluator(Providers providers, TruffleCache truffleCache) { this.providers = providers; CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection()); this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer); - this.config = config; this.truffleCache = truffleCache; this.frameType = providers.getMetaAccess().lookupJavaType(FrameWithoutBoxing.class); - try { - executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class)); - } catch (NoSuchMethodException ex) { - throw new RuntimeException(ex); - } } public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) { @@ -98,10 +88,10 @@ constantReceivers = new HashSet<>(); } - final StructuredGraph graph = new StructuredGraph(executeHelperMethod); + final StructuredGraph graph = truffleCache.createRootGraph(); + assert graph != null : "no graph for root method"; - try (Scope s = Debug.scope("CreateGraph", graph)) { - new GraphBuilderPhase.Instance(providers.getMetaAccess(), config, TruffleCompilerImpl.Optimizations).apply(graph); + try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph.method())) { // Replace thisNode with constant. ParameterNode thisNode = graph.getParameter(0); @@ -187,42 +177,54 @@ changed = false; for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) { InvokeKind kind = methodCallTargetNode.invokeKind(); - if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) { - if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { - ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); - constantReceivers.add(constantNode.asConstant()); - } - Replacements replacements = providers.getReplacements(); - Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); - if (macroSubstitution != null) { - InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); - changed = true; - continue; - } + try (Indent id1 = Debug.logAndIndent("try inlining %s, kind = %s", methodCallTargetNode.targetMethod(), kind)) { + if (kind == InvokeKind.Static || (kind == InvokeKind.Special && (methodCallTargetNode.receiver().isConstant() || isFrame(methodCallTargetNode.receiver())))) { + if (TraceTruffleCompilationHistogram.getValue() && kind == InvokeKind.Special) { + ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); + constantReceivers.add(constantNode.asConstant()); + } + Replacements replacements = providers.getReplacements(); + Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); + if (macroSubstitution != null) { + InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); + changed = true; + continue; + } + + if (TraceTruffleCompilationDetails.getValue() && kind == InvokeKind.Special) { + ConstantNode constantNode = (ConstantNode) methodCallTargetNode.arguments().first(); + constantReceivers.add(constantNode.asConstant()); + } + + StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) { + inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); + } - StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod()); - if (inlineGraph == null && !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && - methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) { - inlineGraph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); - } + if (inlineGraph != null) { + try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) { - if (inlineGraph != null) { - int nodeCountBefore = graph.getNodeCount(); - Mark mark = graph.getMark(); - if (TraceTruffleExpansion.getValue()) { - expansionLogger.preExpand(methodCallTargetNode, inlineGraph); + int nodeCountBefore = graph.getNodeCount(); + Mark mark = graph.getMark(); + if (TraceTruffleExpansion.getValue()) { + expansionLogger.preExpand(methodCallTargetNode, inlineGraph); + } + List invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot(); + // try (Indent in2 = Debug.logAndIndent(false, "do inlining")) { + Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); + if (TraceTruffleExpansion.getValue()) { + expansionLogger.postExpand(inlined); + } + // } + if (Debug.isDumpEnabled()) { + Debug.log("dump enabled"); + int nodeCountAfter = graph.getNodeCount(); + Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); + } + canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark); + changed = true; + } } - List invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot(); - Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false); - if (TraceTruffleExpansion.getValue()) { - expansionLogger.postExpand(inlined); - } - if (Debug.isDumpEnabled()) { - int nodeCountAfter = graph.getNodeCount(); - Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter); - } - canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark); - changed = true; } } @@ -249,7 +251,7 @@ StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions, canonicalizer); - if (targetMethod.getAnnotation(ExplodeLoop.class) != null) { + if (graph != null && targetMethod.getAnnotation(ExplodeLoop.class) != null) { assert graph.hasLoops() : graph + " does not contain a loop"; final StructuredGraph graphCopy = graph.copy(); final List modifiedNodes = new ArrayList<>(); diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Fri Mar 28 09:05:22 2014 +0100 @@ -44,6 +44,8 @@ this.constantReflection = constantReflection; } + private static final Unsafe unsafe = Unsafe.getUnsafe(); + @Override public Node canonicalize(Node node) { if (node instanceof LoadFieldNode) { @@ -62,8 +64,8 @@ Object array = loadIndexedNode.array().asConstant().asObject(); long index = loadIndexedNode.index().asConstant().asLong(); if (index >= 0 && index < Array.getLength(array)) { - int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass()); - int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass()); + int arrayBaseOffset = unsafe.arrayBaseOffset(array.getClass()); + int arrayIndexScale = unsafe.arrayIndexScale(array.getClass()); Constant constant = constantReflection.readUnsafeConstant(loadIndexedNode.elementKind(), array, arrayBaseOffset + index * arrayIndexScale, loadIndexedNode.elementKind() == Kind.Object); return ConstantNode.forConstant(constant, metaAccess, loadIndexedNode.graph()); diff -r 8e7667515e31 -r 3efd4d8ace0b 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 Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Fri Mar 28 09:05:22 2014 +0100 @@ -22,232 +22,21 @@ */ package com.oracle.graal.truffle; -import static com.oracle.graal.phases.GraalOptions.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.Map.Entry; - import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graph.Graph.Mark; import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.truffle.phases.*; -import com.oracle.graal.virtual.phases.ea.*; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Implementation of a cache for Truffle graphs for improving partial evaluation time. - */ -public final class TruffleCache { - - private final Providers providers; - private final GraphBuilderConfiguration config; - private final OptimisticOptimizations optimisticOptimizations; - - private final HashMap, StructuredGraph> cache = new HashMap<>(); - private final HashMap, Long> lastUsed = new HashMap<>(); - private final StructuredGraph markerGraph = new StructuredGraph(); - private final ResolvedJavaType stringBuilderClass; - private long counter; - - public TruffleCache(Providers providers, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations) { - this.providers = providers; - this.config = config; - this.optimisticOptimizations = optimisticOptimizations; - this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class); - } - - @SuppressWarnings("unused") - public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) { - List key = new ArrayList<>(arguments.size() + 1); - key.add(method); - for (ValueNode v : arguments) { - if (v.getKind() == Kind.Object) { - key.add(v.stamp()); - } - } - StructuredGraph resultGraph = cache.get(key); - if (resultGraph != null) { - lastUsed.put(key, counter++); - return resultGraph; - } - - if (resultGraph == markerGraph) { - // Avoid recursive inline. - return null; - } - - if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) { - List lastUsedList = new ArrayList<>(); - for (long l : lastUsed.values()) { - lastUsedList.add(l); - } - Collections.sort(lastUsedList); - long mid = lastUsedList.get(lastUsedList.size() / 2); - - List> toRemoveList = new ArrayList<>(); - for (Entry, Long> entry : lastUsed.entrySet()) { - if (entry.getValue() < mid) { - toRemoveList.add(entry.getKey()); - } - } - - for (List entry : toRemoveList) { - cache.remove(entry); - lastUsed.remove(entry); - } - } - - lastUsed.put(key, counter++); - cache.put(key, markerGraph); - try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) { - - final StructuredGraph graph = new StructuredGraph(method); - final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false)); - Mark mark = graph.getMark(); - new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph); - - for (ParameterNode param : graph.getNodes(ParameterNode.class)) { - if (param.getKind() == Kind.Object) { - ValueNode actualArgument = arguments.get(param.index()); - param.setStamp(param.stamp().join(actualArgument.stamp())); - } - } - - // Intrinsify methods. - new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph); - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); - - CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue()); - PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase); +public interface TruffleCache { - while (true) { - - partialEscapePhase.apply(graph, phaseContext); - - // Conditional elimination. - ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess()); - conditionalEliminationPhase.apply(graph); - - // Canonicalize / constant propagate. - canonicalizerPhase.apply(graph, phaseContext); - - boolean inliningProgress = false; - for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { - if (!graph.getMark().equals(mark)) { - // Make sure macro substitutions such as - // CompilerDirectives.transferToInterpreter get processed first. - for (Node newNode : graph.getNewNodes(mark)) { - if (newNode instanceof MethodCallTargetNode) { - MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode; - Class macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod()); - if (macroSubstitution != null) { - InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); - } else { - tryCutOffRuntimeExceptions(methodCallTargetNode); - } - } - } - mark = graph.getMark(); - } - if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) { - inliningProgress = true; - List canonicalizerUsages = new ArrayList(); - for (Node n : methodCallTarget.invoke().asNode().usages()) { - if (n instanceof Canonicalizable) { - canonicalizerUsages.add(n); - } - } - List argumentSnapshot = methodCallTarget.arguments().snapshot(); - Mark beforeInvokeMark = graph.getMark(); - expandInvoke(methodCallTarget); - for (Node arg : argumentSnapshot) { - if (arg != null && arg.recordsUsages()) { - for (Node argUsage : arg.usages()) { - if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) { - canonicalizerUsages.add(argUsage); - } - } - } - } - canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages); - } - } - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); + /** + * Creates the graph for the root method, i.e. {@link OptimizedCallTarget#executeHelper}. + */ + StructuredGraph createRootGraph(); - new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext); - - if (!inliningProgress) { - break; - } - } - - cache.put(key, graph); - if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { - TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount())); - } - return graph; - } catch (Throwable e) { - throw Debug.handle(e); - } - - } - - private void expandInvoke(MethodCallTargetNode methodCallTargetNode) { - StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod()); - if (inlineGraph == null) { - inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null); - } - if (inlineGraph == this.markerGraph) { - // Can happen for recursive calls. - throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + - ", must annotate such calls with @CompilerDirectives.SlowPath!")); - } - Invoke invoke = methodCallTargetNode.invoke(); - InliningUtil.inline(invoke, inlineGraph, true); - } - - private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) { - if (methodCallTargetNode.targetMethod().isConstructor()) { - ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class); - ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class); - ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp())); - if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) { - DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); - FixedNode invokeNode = methodCallTargetNode.invoke().asNode(); - invokeNode.replaceAtPredecessor(deoptNode); - GraphUtil.killCFG(invokeNode); - return true; - } - } - return false; - } - - private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) { - return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && - !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null && - methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null && - !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass); - } + /** + * Returns a cached graph for a method with given arguments. + */ + StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer); } diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Fri Mar 28 09:05:22 2014 +0100 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle; + +import static com.oracle.graal.phases.GraalOptions.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graph.Graph.Mark; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.truffle.phases.*; +import com.oracle.graal.virtual.phases.ea.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Implementation of a cache for Truffle graphs for improving partial evaluation time. + */ +public final class TruffleCacheImpl implements TruffleCache { + + private final Providers providers; + private final GraphBuilderConfiguration config; + private final GraphBuilderConfiguration configForRootGraph; + private final OptimisticOptimizations optimisticOptimizations; + + private final HashMap, StructuredGraph> cache = new HashMap<>(); + private final HashMap, Long> lastUsed = new HashMap<>(); + private final StructuredGraph markerGraph = new StructuredGraph(); + private final ResolvedJavaType stringBuilderClass; + private final ResolvedJavaMethod executeHelperMethod; + private long counter; + + public TruffleCacheImpl(Providers providers, GraphBuilderConfiguration config, GraphBuilderConfiguration configForRootGraph, OptimisticOptimizations optimisticOptimizations) { + this.providers = providers; + this.config = config; + this.configForRootGraph = configForRootGraph; + this.optimisticOptimizations = optimisticOptimizations; + this.stringBuilderClass = providers.getMetaAccess().lookupJavaType(StringBuilder.class); + try { + executeHelperMethod = providers.getMetaAccess().lookupJavaMethod(OptimizedCallTarget.class.getDeclaredMethod("executeHelper", PackedFrame.class, Arguments.class)); + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + public StructuredGraph createRootGraph() { + StructuredGraph graph = new StructuredGraph(executeHelperMethod); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), configForRootGraph, TruffleCompilerImpl.Optimizations).apply(graph); + return graph; + } + + @SuppressWarnings("unused") + public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) { + + if (method.getAnnotation(CompilerDirectives.SlowPath.class) != null) { + return null; + } + + List key = new ArrayList<>(arguments.size() + 1); + key.add(method); + for (ValueNode v : arguments) { + if (v.getKind() == Kind.Object) { + key.add(v.stamp()); + } + } + StructuredGraph resultGraph = cache.get(key); + if (resultGraph != null) { + lastUsed.put(key, counter++); + return resultGraph; + } + + if (resultGraph == markerGraph) { + // Avoid recursive inline. + return null; + } + + if (lastUsed.values().size() >= TruffleCompilerOptions.TruffleMaxCompilationCacheSize.getValue()) { + List lastUsedList = new ArrayList<>(); + for (long l : lastUsed.values()) { + lastUsedList.add(l); + } + Collections.sort(lastUsedList); + long mid = lastUsedList.get(lastUsedList.size() / 2); + + List> toRemoveList = new ArrayList<>(); + for (Entry, Long> entry : lastUsed.entrySet()) { + if (entry.getValue() < mid) { + toRemoveList.add(entry.getKey()); + } + } + + for (List entry : toRemoveList) { + cache.remove(entry); + lastUsed.remove(entry); + } + } + + lastUsed.put(key, counter++); + cache.put(key, markerGraph); + try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) { + + final StructuredGraph graph = new StructuredGraph(method); + final PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false)); + Mark mark = graph.getMark(); + new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), config, optimisticOptimizations).apply(graph); + + for (ParameterNode param : graph.getNodes(ParameterNode.class)) { + if (param.getKind() == Kind.Object) { + ValueNode actualArgument = arguments.get(param.index()); + param.setStamp(param.stamp().join(actualArgument.stamp())); + } + } + + // Intrinsify methods. + new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph); + + // Convert deopt to guards. + new ConvertDeoptimizeToGuardPhase().apply(graph); + + CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!ImmutableCode.getValue()); + PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase); + + while (true) { + + partialEscapePhase.apply(graph, phaseContext); + + // Conditional elimination. + ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(phaseContext.getMetaAccess()); + conditionalEliminationPhase.apply(graph); + + // Canonicalize / constant propagate. + canonicalizerPhase.apply(graph, phaseContext); + + boolean inliningProgress = false; + for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { + if (!graph.getMark().equals(mark)) { + // Make sure macro substitutions such as + // CompilerDirectives.transferToInterpreter get processed first. + for (Node newNode : graph.getNewNodes(mark)) { + if (newNode instanceof MethodCallTargetNode) { + MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode; + Class macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod()); + if (macroSubstitution != null) { + InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); + } else { + tryCutOffRuntimeExceptions(methodCallTargetNode); + } + } + } + mark = graph.getMark(); + } + if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) { + inliningProgress = true; + List canonicalizerUsages = new ArrayList(); + for (Node n : methodCallTarget.invoke().asNode().usages()) { + if (n instanceof Canonicalizable) { + canonicalizerUsages.add(n); + } + } + List argumentSnapshot = methodCallTarget.arguments().snapshot(); + Mark beforeInvokeMark = graph.getMark(); + expandInvoke(methodCallTarget); + for (Node arg : argumentSnapshot) { + if (arg != null && arg.recordsUsages()) { + for (Node argUsage : arg.usages()) { + if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) { + canonicalizerUsages.add(argUsage); + } + } + } + } + canonicalizerPhase.applyIncremental(graph, phaseContext, canonicalizerUsages); + } + } + + // Convert deopt to guards. + new ConvertDeoptimizeToGuardPhase().apply(graph); + + new EarlyReadEliminationPhase(canonicalizerPhase).apply(graph, phaseContext); + + if (!inliningProgress) { + break; + } + } + + cache.put(key, graph); + if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) { + TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount())); + } + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + + } + + private void expandInvoke(MethodCallTargetNode methodCallTargetNode) { + StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod()); + if (inlineGraph == null) { + inlineGraph = TruffleCacheImpl.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null); + } + if (inlineGraph == this.markerGraph) { + // Can happen for recursive calls. + throw GraphUtil.approxSourceException(methodCallTargetNode, new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + + ", must annotate such calls with @CompilerDirectives.SlowPath!")); + } + Invoke invoke = methodCallTargetNode.invoke(); + InliningUtil.inline(invoke, inlineGraph, true); + } + + private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) { + if (methodCallTargetNode.targetMethod().isConstructor()) { + ResolvedJavaType runtimeException = providers.getMetaAccess().lookupJavaType(RuntimeException.class); + ResolvedJavaType controlFlowException = providers.getMetaAccess().lookupJavaType(ControlFlowException.class); + ResolvedJavaType exceptionType = Objects.requireNonNull(ObjectStamp.typeOrNull(methodCallTargetNode.receiver().stamp())); + if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass()) && !controlFlowException.isAssignableFrom(exceptionType)) { + DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); + FixedNode invokeNode = methodCallTargetNode.invoke().asNode(); + invokeNode.replaceAtPredecessor(deoptNode); + GraphUtil.killCFG(invokeNode); + return true; + } + } + return false; + } + + private boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) { + return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) && + !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null && + methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null && + !methodCallTargetNode.targetMethod().getDeclaringClass().equals(stringBuilderClass); + } +} diff -r 8e7667515e31 -r 3efd4d8ace0b 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 Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Mar 28 09:05:22 2014 +0100 @@ -98,18 +98,19 @@ ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault(); eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes); - this.truffleCache = new TruffleCache(providers, eagerConfig, TruffleCompilerImpl.Optimizations); - this.config = GraphBuilderConfiguration.getDefault(); this.config.setSkippedExceptionTypes(skippedExceptionTypes); - this.partialEvaluator = new PartialEvaluator(providers, truffleCache, config); + + this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, config, TruffleCompilerImpl.Optimizations); + + this.partialEvaluator = new PartialEvaluator(providers, truffleCache); if (Debug.isEnabled()) { DebugEnvironment.initialize(System.out); } } - private static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); @@ -122,7 +123,7 @@ @Override public InstalledCode call() throws Exception { try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(compilable))) { - return compileMethodImpl(compilable); + return compileMethodImpl((OptimizedCallTargetImpl) compilable); } catch (Throwable e) { throw Debug.handle(e); } @@ -134,11 +135,11 @@ public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); - private InstalledCode compileMethodImpl(final OptimizedCallTarget compilable) { + private InstalledCode compileMethodImpl(final OptimizedCallTargetImpl compilable) { final StructuredGraph graph; if (TraceTruffleCompilation.getValue()) { - OptimizedCallTarget.logOptimizingStart(compilable); + OptimizedCallTargetImpl.logOptimizingStart(compilable); } if (TraceTruffleInliningTree.getValue()) { @@ -178,7 +179,7 @@ properties.put("CodeSize", code != null ? code.length : 0); properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection())); - OptimizedCallTarget.logOptimizingDone(compilable, properties); + OptimizedCallTargetImpl.logOptimizingDone(compilable, properties); } return compiledMethod; } diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Fri Mar 28 09:05:22 2014 +0100 @@ -47,17 +47,17 @@ this.graalReplacements = providers.getReplacements(); } - static Replacements makeInstance() { + public static Replacements makeInstance() { Providers graalProviders = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders(); Replacements truffleReplacements = new TruffleReplacements(graalProviders); truffleReplacements.registerSubstitutions(CompilerAssertsSubstitutions.class); truffleReplacements.registerSubstitutions(CompilerDirectivesSubstitutions.class); truffleReplacements.registerSubstitutions(ExactMathSubstitutions.class); - truffleReplacements.registerSubstitutions(UnexpectedResultExceptionSubstitutions.class); truffleReplacements.registerSubstitutions(FrameWithoutBoxingSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedAssumptionSubstitutions.class); truffleReplacements.registerSubstitutions(OptimizedCallTargetSubstitutions.class); + truffleReplacements.registerSubstitutions(OptimizedCallTargetImplSubstitutions.class); return truffleReplacements; } diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetImplSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetImplSubstitutions.java Fri Mar 28 09:05:22 2014 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.truffle.substitutions; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.truffle.*; +import com.oracle.graal.truffle.nodes.asserts.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; + +@ClassSubstitution(OptimizedCallTargetImpl.class) +public class OptimizedCallTargetImplSubstitutions { + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args); + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args); + + @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) + public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args); +} diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java Fri Mar 28 09:05:22 2014 +0100 @@ -23,9 +23,7 @@ package com.oracle.graal.truffle.substitutions; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.truffle.*; -import com.oracle.graal.truffle.nodes.asserts.*; import com.oracle.graal.truffle.nodes.frame.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; @@ -33,15 +31,6 @@ @ClassSubstitution(OptimizedCallTarget.class) public class OptimizedCallTargetSubstitutions { - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object callHelper(OptimizedCallTarget target, PackedFrame caller, Arguments args); - - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args); - - @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false) - public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args); - @MethodSubstitution private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) { return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, caller, args); diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnexpectedResultExceptionSubstitutions.java Fri Mar 28 08:25:35 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle.substitutions; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Deoptimize on creation of a new UnexpectedResultException instance. - */ -@ClassSubstitution(UnexpectedResultException.class) -public class UnexpectedResultExceptionSubstitutions { - - @SuppressWarnings("unused") - @MethodSubstitution(value = "") - public static void init(Object result) { - DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode); - } -} diff -r 8e7667515e31 -r 3efd4d8ace0b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Fri Mar 28 08:25:35 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Fri Mar 28 09:05:22 2014 +0100 @@ -24,6 +24,8 @@ */ package com.oracle.truffle.api.nodes; +import com.oracle.truffle.api.*; + /** * An exception that should be thrown if the return value cannot be represented as a value of the * return type. The Truffle optimizer has special knowledge of this exception class and will never @@ -41,6 +43,7 @@ * @param result the alternative result */ public UnexpectedResultException(Object result) { + CompilerDirectives.transferToInterpreter(); this.result = result; }