# HG changeset patch # User Christian Haeubl # Date 1328550076 28800 # Node ID 11a4af4a6621d2de508b10cac6b2b29aebb1a458 # Parent 87a12a816e9964ac9235d456d3219ec13200e439# Parent 0312460af9fc052223bd5522ee685fa29a601e96 Merge diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java Mon Feb 06 09:41:16 2012 -0800 @@ -311,6 +311,7 @@ } public CiConstant readUnsafeConstant(Object value, long displacement) { + assert value != null; Unsafe u = Unsafe.getUnsafe(); switch(this) { case Boolean: diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.cri.ri; + + +/** + * Represents profiling information for one specific method. + * Every accessor method returns the information that is available at the time of its invocation. + * If a method is invoked multiple times, it may return a significantly different results for every invocation. + */ +public interface RiProfilingInfo { + /** + * Returns an estimate of how often the branch at the given byte code was taken. + * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if this information is not available. + */ + double getBranchTakenProbability(int bci); + + /** + * Returns an estimate of how often the switch cases are taken at the given BCI. + * The default case is stored as the last entry. + * @return A double value that contains the estimated probabilities, with 0.0 meaning never and 1.0 meaning always, + * or -1 if this information is not available. + */ + double[] getSwitchProbabilities(int bci); + + /** + * Returns the TypeProfile for the given BCI. + * @return Returns an RiTypeProfile object, or null if not available. + */ + RiTypeProfile getTypeProfile(int bci); + + /** + * Returns true if the instruction at least once an exception was thrown at the given BCI. + * @return true if an exception was encountered during profiling, false otherwise. + */ + boolean getExceptionSeen(int bci); + + /** + * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts to each other, + * as the returned value highly depends on the time of invocation. + * @return the estimated execution count or -1 if not available. + */ + int getExecutionCount(int bci); +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java Mon Feb 06 09:41:16 2012 -0800 @@ -159,29 +159,10 @@ int invocationCount(); /** - * Returns an estimate of hot often an exception was seen at the given bytecode. - * @return The estimate in percent (0-100), with 0 meaning never and 100 meaning always, or -1 if this information isn't available. - */ - int exceptionProbability(int bci); - - /** - * Returns the type profile of the instruction at the given byte code index. - * @return The RiTypeProfile information, or null if it isn't available. + * Returns an object that provides access to the method's profiling information. + * @return The profiling information recorded for this method. */ - RiTypeProfile typeProfile(int bci); - - /** - * Returns an estimate of how often the branch at the given byte code was taken. - * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if this information isn't available. - */ - double branchProbability(int bci); - - /** - * Returns an estimate of how often the branches of the switch at the given byte code were taken. - * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or NULL if this information isn't available. - * The default case is specified at the last index. - */ - double[] switchProbability(int bci); + RiProfilingInfo profilingInfo(); /** * Returns a map that the compiler can use to store objects that should survive the current compilation. diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Mon Feb 06 09:41:16 2012 -0800 @@ -25,37 +25,47 @@ import java.io.*; /** - * This profile object represents the type profile of one call site, cast or instanceof instruction. The precision of - * the supplied values may vary, but a runtime that provides this information should be aware that it will be used to - * guide performance-critical decisions like speculative inlining, etc. + * This profile object represents the type profile at a specific BCI. The precision of the supplied values may vary, + * but a runtime that provides this information should be aware that it will be used to guide performance-critical + * decisions like speculative inlining, etc. */ -public class RiTypeProfile implements Serializable { - +public final class RiTypeProfile implements Serializable { /** - * + * */ private static final long serialVersionUID = -6877016333706838441L; - /** - * How often the instruction was executed, which may be used to judge the maturity of this profile. - */ - public int count; + private final RiResolvedType[] types; + private final double notRecordedProbability; + private final double[] probabilities; + + public RiTypeProfile(RiResolvedType[] types, double notRecordedProbability, double[] probabilites) { + this.types = types; + this.notRecordedProbability = notRecordedProbability; + this.probabilities = probabilites; + } /** - * An estimation of how many different receiver types were encountered. This may or may not be the same as - * probabilities.length/types.length, as the runtime may store probabilities for a limited number of receivers. + * The estimated probabilities of the different receivers. This array needs to have the same length as the array returned by + * {@link RiTypeProfile#types}. */ - public int morphism; + public double[] getProbabilities() { + return probabilities; + } + + /** + * Returns the estimated probability of all types that could not be recorded due to profiling limitations. + * @return double value >= 0.0 and <= 1.0 + */ + public double getNotRecordedProbability() { + return notRecordedProbability; + } /** * A list of receivers for which the runtime has recorded probability information. This array needs to have the same * length as {@link RiTypeProfile#probabilities}. */ - public RiResolvedType[] types; - - /** - * The estimated probabilities of the different receivers. This array needs to have the same length as - * {@link RiTypeProfile#types}. - */ - public float[] probabilities; + public RiResolvedType[] getTypes() { + return types; + } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java Mon Feb 06 09:41:16 2012 -0800 @@ -102,12 +102,12 @@ * an object is identical to a given hub constant. In pseudo code: *
      *     if (object.getHub() != hub) {
-     *         uncommonTrap();
+     *       jump(falseSuccessor)
      *     }
      * 
* This snippet should only be used when the object is guaranteed not to be null. */ - XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type); + XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type); /** * Initializes the XIR generator for the given XIR assembler. diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Feb 06 09:41:16 2012 -0800 @@ -42,9 +42,12 @@ public static boolean Inline = true; public static boolean Intrinsify = true; public static boolean CacheGraphs = ____; - public static boolean InlineWithTypeCheck = ____; + public static boolean InlineMonomorphicCalls = true; + public static boolean InlinePolymorphicCalls = true; + public static int InliningPolicy = 0; public static int MaximumInlineSize = 35; public static int MaximumFreqInlineSize = 300; + public static float NestedInliningSizeRatio = 0.9f; public static int FreqInlineRatio = 20; public static int MaximumTrivialSize = 6; public static int MaximumInlineLevel = 30; diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Mon Feb 06 09:41:16 2012 -0800 @@ -701,9 +701,7 @@ @Override public void emitGuardCheck(BooleanNode comp) { - if (comp instanceof IsTypeNode) { - emitTypeGuard((IsTypeNode) comp); - } else if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) { + if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) { emitNullCheckGuard((NullCheckNode) comp); } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) { // True constant, nothing to emit. @@ -717,15 +715,6 @@ protected abstract void emitNullCheckGuard(NullCheckNode node); - private void emitTypeGuard(IsTypeNode node) { - load(operand(node.object())); - LIRDebugInfo info = state(); - XirArgument clazz = toXirArgument(node.type().getEncoding(Representation.ObjectHub)); - XirSnippet typeCheck = xir.genTypeCheck(site(node), toXirArgument(node.object()), clazz, node.type()); - emitXir(typeCheck, node, info, false); - } - - public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { if (node instanceof NullCheckNode) { emitNullCheckBranch((NullCheckNode) node, trueSuccessor, falseSuccessor, info); @@ -735,6 +724,8 @@ emitInstanceOfBranch((InstanceOfNode) node, trueSuccessor, falseSuccessor, info); } else if (node instanceof ConstantNode) { emitConstantBranch(((ConstantNode) node).asConstant().asBoolean(), trueSuccessor, falseSuccessor, info); + } else if (node instanceof IsTypeNode) { + emitTypeBranch((IsTypeNode) node, trueSuccessor, falseSuccessor, info); } else { throw Util.unimplemented(node.toString()); } @@ -761,7 +752,6 @@ emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor); } - public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) { LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; if (block != null) { @@ -769,6 +759,16 @@ } } + public void emitTypeBranch(IsTypeNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) { + XirArgument thisClass = toXirArgument(x.objectClass()); + XirArgument otherClass = toXirArgument(x.type().getEncoding(Representation.ObjectHub)); + XirSnippet snippet = xir.genTypeBranch(site(x), thisClass, otherClass, x.type()); + emitXir(snippet, x, info, null, false, trueSuccessor, falseSuccessor); + if (trueSuccessor != null) { + emitJump(trueSuccessor, null); + } + } + @Override public void emitConditional(ConditionalNode conditional) { CiValue tVal = operand(conditional.trueValue()); diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java Mon Feb 06 09:41:16 2012 -0800 @@ -219,7 +219,7 @@ pred.replaceFirstSuccessor(replacedSux, next); FrameState stateAfter = merge.stateAfter(); merge.setStateAfter(null); - if (stateAfter.usages().isEmpty()) { + if (stateAfter != null && stateAfter.usages().isEmpty()) { stateAfter.safeDelete(); } merge.safeDelete(); diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Mon Feb 06 09:41:16 2012 -0800 @@ -316,7 +316,7 @@ assert ((NullCheckNode) usage).object() == node; return null; } else if (usage instanceof IsTypeNode) { - assert ((IsTypeNode) usage).object() == node; + assert ((IsTypeNode) usage).objectClass() == node; return null; } else if (usage instanceof AccessMonitorNode) { assert ((AccessMonitorNode) usage).object() == node; diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Mon Feb 06 09:41:16 2012 -0800 @@ -53,6 +53,7 @@ private CiAssumptions assumptions; private final PhasePlan plan; + private final InliningPolicy inliningPolicy; // Metrics private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed"); @@ -64,6 +65,7 @@ this.hints = hints; this.assumptions = assumptions; this.plan = plan; + this.inliningPolicy = createInliningPolicy(); } @SuppressWarnings("unchecked") @@ -80,39 +82,36 @@ while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) { InlineInfo info = inlineCandidates.remove(); - double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, graph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp; - if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) { - Debug.log("not inlining (cut off by weight): %e", info.weight); - return; - } - Iterable newNodes = null; - if (info.invoke.node().isAlive()) { - try { - info.inline(graph, runtime, this); - Debug.log("inlining %f: %s", info.weight, info); - Debug.dump(graph, "after inlining %s", info); - // get the new nodes here, the canonicalizer phase will reset the mark - newNodes = graph.getNewNodes(); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, true, assumptions).apply(graph); + if (inliningPolicy.isWorthInlining(graph, info)) { + Iterable newNodes = null; + if (info.invoke.node().isAlive()) { + try { + info.inline(graph, runtime, this); + Debug.log("inlining %f: %s", info.weight, info); + Debug.dump(graph, "after inlining %s", info); + // get the new nodes here, the canonicalizer phase will reset the mark + newNodes = graph.getNewNodes(); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, true, assumptions).apply(graph); + } + if (GraalOptions.Intrinsify) { + new IntrinsificationPhase(runtime).apply(graph); + } + metricInliningPerformed.increment(); + } catch (CiBailout bailout) { + // TODO determine if we should really bail out of the whole compilation. + throw bailout; + } catch (AssertionError e) { + throw new GraalInternalError(e).addContext(info.toString()); + } catch (RuntimeException e) { + throw new GraalInternalError(e).addContext(info.toString()); + } catch (GraalInternalError e) { + throw e.addContext(info.toString()); } - if (GraalOptions.Intrinsify) { - new IntrinsificationPhase(runtime).apply(graph); - } - metricInliningPerformed.increment(); - } catch (CiBailout bailout) { - // TODO determine if we should really bail out of the whole compilation. - throw bailout; - } catch (AssertionError e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (RuntimeException e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (GraalInternalError e) { - throw e.addContext(info.toString()); } - } - if (newNodes != null && info.level <= GraalOptions.MaximumInlineLevel) { - scanInvokes(newNodes, info.level + 1, graph); + if (newNodes != null && info.level <= GraalOptions.MaximumInlineLevel) { + scanInvokes(newNodes, info.level + 1, graph); + } } } } @@ -160,61 +159,10 @@ @Override public double inliningWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke) { - double ratio; - if (hints != null && hints.contains(invoke)) { - ratio = 1000000; - } else { - if (GraalOptions.ProbabilityAnalysis) { - ratio = invoke.node().probability(); - } else { - RiTypeProfile profile = caller.typeProfile(invoke.bci()); - if (profile != null && profile.count > 0) { - RiResolvedMethod parent = invoke.stateAfter().method(); - ratio = profile.count / (float) parent.invocationCount(); - } else { - ratio = 1; - } - } - } - - final double normalSize; - // TODO(ls) get rid of this magic, it's here to emulate the old behavior for the time being - if (ratio < 0.01) { - ratio = 0.01; - } - if (ratio < 0.5) { - normalSize = 10 * ratio / 0.5; - } else if (ratio < 2) { - normalSize = 10 + (35 - 10) * (ratio - 0.5) / 1.5; - } else if (ratio < 20) { - normalSize = 35; - } else if (ratio < 40) { - normalSize = 35 + (350 - 35) * (ratio - 20) / 20; - } else { - normalSize = 350; - } - - int count; - if (GraalOptions.ParseBeforeInlining) { - if (!parsedMethods.containsKey(method)) { - StructuredGraph newGraph = new StructuredGraph(method); - if (plan != null) { - plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); - } - new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); - count = graphComplexity(newGraph); - parsedMethods.put(method, count); - } else { - count = parsedMethods.get(method); - } - } else { - count = method.codeSize(); - } - - return count / normalSize; + boolean preferred = hints != null && hints.contains(invoke); + return inliningPolicy.computeWeight(caller, method, invoke, preferred); } - public static int graphComplexity(StructuredGraph graph) { int result = 0; for (Node node : graph.getNodes()) { @@ -239,4 +187,105 @@ assumptions.recordConcreteMethod(method, context, impl); } + private InliningPolicy createInliningPolicy() { + if (GraalOptions.InliningPolicy == 0) { + return new WeightBasedInliningPolicy(); + } else if (GraalOptions.InliningPolicy == 1) { + return new SizeBasedInliningPolicy(); + } else { + Util.shouldNotReachHere(); + return null; + } + } + + private interface InliningPolicy { + double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke); + boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info); + } + + private class WeightBasedInliningPolicy implements InliningPolicy { + @Override + public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) { + double ratio; + if (preferredInvoke) { + ratio = 1000000; + } else { + if (GraalOptions.ProbabilityAnalysis) { + ratio = invoke.node().probability(); + } else { + RiProfilingInfo profilingInfo = method.profilingInfo(); + int executionCount = profilingInfo.getExecutionCount(invoke.bci()); + if (executionCount > 0) { + RiResolvedMethod parent = invoke.stateAfter().method(); + ratio = executionCount / (float) parent.invocationCount(); + } else { + ratio = 1; + } + } + } + + final double normalSize; + // TODO(ls) get rid of this magic, it's here to emulate the old behavior for the time being + if (ratio < 0.01) { + ratio = 0.01; + } + if (ratio < 0.5) { + normalSize = 10 * ratio / 0.5; + } else if (ratio < 2) { + normalSize = 10 + (35 - 10) * (ratio - 0.5) / 1.5; + } else if (ratio < 20) { + normalSize = 35; + } else if (ratio < 40) { + normalSize = 35 + (350 - 35) * (ratio - 20) / 20; + } else { + normalSize = 350; + } + + int count; + if (GraalOptions.ParseBeforeInlining) { + if (!parsedMethods.containsKey(method)) { + StructuredGraph newGraph = new StructuredGraph(method); + if (plan != null) { + plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); + } + new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); + count = graphComplexity(newGraph); + parsedMethods.put(method, count); + } else { + count = parsedMethods.get(method); + } + } else { + count = method.codeSize(); + } + + return count / normalSize; + } + + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp; + if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) { + Debug.log("not inlining (cut off by weight): %e", info.weight); + return false; + } + return true; + } + } + + private class SizeBasedInliningPolicy implements InliningPolicy { + @Override + public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) { + if (preferredInvoke) { + return method.codeSize() / 2; + } else { + return method.codeSize(); + } + } + + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize); + return info.weight <= maxSize; + } + } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Mon Feb 06 09:41:16 2012 -0800 @@ -34,7 +34,9 @@ import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; +import com.oracle.max.graal.nodes.PhiNode.PhiType; import com.oracle.max.graal.nodes.calc.*; +import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.java.*; import com.oracle.max.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.max.graal.nodes.util.*; @@ -85,6 +87,15 @@ return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0; } + protected static StructuredGraph getGraph(final RiResolvedMethod concrete, final InliningCallback callback) { + return Debug.scope("Inlining", concrete, new Callable() { + @Override + public StructuredGraph call() throws Exception { + return callback.buildGraph(concrete); + } + }); + } + public abstract boolean canDeopt(); /** @@ -94,10 +105,8 @@ * @param graph * @param runtime * @param callback - * @return The node that represents the return value, or null for void methods and methods that have no - * non-exceptional exit. */ - public abstract Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback); + public abstract void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback); } /** @@ -113,14 +122,9 @@ } @Override - public Node inline(StructuredGraph compilerGraph, GraalRuntime runtime, final InliningCallback callback) { - StructuredGraph graph = Debug.scope("Inlining", concrete, new Callable() { - @Override - public StructuredGraph call() throws Exception { - return callback.buildGraph(concrete); - } - }); - return InliningUtil.inline(invoke, graph, true); + public void inline(StructuredGraph compilerGraph, GraalRuntime runtime, final InliningCallback callback) { + StructuredGraph graph = getGraph(concrete, callback); + InliningUtil.inline(invoke, graph, true); } @Override @@ -138,26 +142,32 @@ * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed. */ - private static class TypeGuardInlineInfo extends ExactInlineInfo { - + private static class TypeGuardInlineInfo extends InlineInfo { + public final RiResolvedMethod concrete; public final RiResolvedType type; - public final double probability; - public TypeGuardInlineInfo(Invoke invoke, double weight, int level, RiResolvedMethod concrete, RiResolvedType type, double probability) { - super(invoke, weight, level, concrete); + public TypeGuardInlineInfo(Invoke invoke, double weight, int level, RiResolvedMethod concrete, RiResolvedType type) { + super(invoke, weight, level); + this.concrete = concrete; this.type = type; - this.probability = probability; } @Override - public Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { - IsTypeNode isType = graph.unique(new IsTypeNode(invoke.callTarget().receiver(), type)); - FixedGuardNode guard = graph.add(new FixedGuardNode(isType)); + public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { + // receiver null check must be before the type check + InliningUtil.receiverNullCheck(invoke); + ReadHubNode objectClass = graph.add(new ReadHubNode(invoke.callTarget().receiver())); + IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type)); + FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode)); assert invoke.predecessor() != null; + + graph.addBeforeFixed(invoke.node(), objectClass); graph.addBeforeFixed(invoke.node(), guard); - Debug.log("inlining with type check, type probability: %5.3f", probability); - return super.inline(graph, runtime, callback); + Debug.log("inlining 1 method using 1 type check"); + + StructuredGraph calleeGraph = getGraph(concrete, callback); + InliningUtil.inline(invoke, calleeGraph, false); } @Override @@ -172,6 +182,223 @@ } /** + * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable + * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered. + */ + private static class MultiTypeGuardInlineInfo extends InlineInfo { + public final List concretes; + public final RiResolvedType[] types; + public final int[] typesToConcretes; + public final double[] branchProbabilities; + + public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List concretes, RiResolvedType[] types, int[] typesToConcretes, double[] branchProbabilities) { + super(invoke, weight, level); + assert concretes.size() > 0 && concretes.size() <= types.length : "must have at least one method but no more than types methods"; + assert types.length == typesToConcretes.length && types.length == branchProbabilities.length : "array length must match"; + + this.concretes = concretes; + this.types = types; + this.typesToConcretes = typesToConcretes; + this.branchProbabilities = branchProbabilities; + } + + @Override + public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { + int numberOfMethods = concretes.size(); + boolean hasReturnValue = invoke.node().kind() != CiKind.Void; + + // receiver null check must be the first node + InliningUtil.receiverNullCheck(invoke); + if (numberOfMethods > 1) { + inlineMultipleMethods(graph, callback, numberOfMethods, hasReturnValue); + } else { + inlineSingleMethod(graph, callback); + } + + Debug.log("inlining %d methods with %d type checks", numberOfMethods, types.length); + } + + private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) { + assert concretes.size() > 1; + + FixedNode continuation = invoke.next(); + + // setup merge and phi nodes for results and exceptions + MergeNode returnMerge = graph.add(new MergeNode()); + returnMerge.setProbability(invoke.probability()); + returnMerge.setStateAfter(invoke.stateAfter()); + + PhiNode returnValuePhi = null; + if (hasReturnValue) { + returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge, PhiType.Value)); + } + + MergeNode exceptionMerge = null; + PhiNode exceptionObjectPhi = null; + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; + BeginNode exceptionEdge = invokeWithException.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + + exceptionMerge = graph.add(new MergeNode()); + exceptionMerge.setProbability(exceptionEdge.probability()); + exceptionMerge.setStateAfter(exceptionEdge.stateAfter()); + + FixedNode exceptionSux = exceptionObject.next(); + graph.addBeforeFixed(exceptionSux, exceptionMerge); + exceptionObjectPhi = graph.unique(new PhiNode(CiKind.Object, exceptionMerge, PhiType.Value)); + } + + // create one separate block for each invoked method + BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods]; + for (int i = 0; i < numberOfMethods; i++) { + Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi); + int predecessors = getPredecessorCount(i); + // TODO (ch) set probabilities + BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode()); + calleeEntryNode.setNext(duplicatedInvoke.node()); + calleeEntryNodes[i] = calleeEntryNode; + + EndNode endNode = graph.add(new EndNode()); + // TODO (ch) set probability + duplicatedInvoke.setNext(endNode); + returnMerge.addEnd(endNode); + if (returnValuePhi != null) { + returnValuePhi.addInput(duplicatedInvoke.node()); + } + } + + // replace the invoke exception edge + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke; + BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + exceptionObject.replaceAtUsages(exceptionObjectPhi); + exceptionObject.setNext(null); + GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge()); + } + + // replace the invoke with a cascade of if nodes + ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver())); + graph.addBeforeFixed(invoke.node(), objectClassNode); + + FixedNode deoptNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, calleeEntryNodes, deoptNode); + + assert invoke.next() == continuation; + invoke.setNext(null); + returnMerge.setNext(continuation); + invoke.node().replaceAtUsages(returnValuePhi); + invoke.node().replaceAndDelete(dispatchOnType); + + // do the actual inlining for every invoke + for (int i = 0; i < calleeEntryNodes.length; i++) { + BeginNode node = calleeEntryNodes[i]; + Invoke invokeForInlining = (Invoke) node.next(); + StructuredGraph calleeGraph = getGraph(concretes.get(i), callback); + InliningUtil.inline(invokeForInlining, calleeGraph, false); + } + } + + private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback) { + assert concretes.size() == 1 && types.length > 1; + + MergeNode calleeEntryNode = graph.add(new MergeNode()); + calleeEntryNode.setProbability(invoke.probability()); + ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver())); + graph.addBeforeFixed(invoke.node(), objectClassNode); + + FixedNode deoptNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, deoptNode); + + FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); + pred.setNext(dispatchOnType); + calleeEntryNode.setNext(invoke.node()); + + StructuredGraph calleeGraph = getGraph(concretes.get(0), callback); + InliningUtil.inline(invoke, calleeGraph, false); + } + + private FixedNode createDispatchOnType(StructuredGraph graph, ReadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) { + assert types.length > 1; + + // TODO (ch) set probabilities for all fixed nodes... + int lastIndex = types.length - 1; + FixedNode nextNode = createTypeCheck(graph, objectClassNode, types[lastIndex], calleeEntryNodes[typesToConcretes[lastIndex]], unknownTypeSux, branchProbabilities[lastIndex]); + for (int i = lastIndex - 1; i >= 0; i--) { + nextNode = createTypeCheck(graph, objectClassNode, types[i], calleeEntryNodes[typesToConcretes[i]], nextNode, branchProbabilities[i]); + } + + return nextNode; + } + + private static FixedNode createTypeCheck(StructuredGraph graph, ReadHubNode objectClassNode, RiResolvedType type, BeginNode tsux, FixedNode nextNode, double tsuxProbability) { + IfNode result; + IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClassNode, type)); + if (tsux instanceof MergeNode) { + EndNode endNode = graph.add(new EndNode()); + result = graph.add(new IfNode(isTypeNode, endNode, nextNode, tsuxProbability)); + ((MergeNode) tsux).addEnd(endNode); + } else { + result = graph.add(new IfNode(isTypeNode, tsux, nextNode, tsuxProbability)); + } + return result; + } + + private int getPredecessorCount(int concreteMethodIndex) { + if (concretes.size() == types.length) { + return 1; + } else { + int count = 0; + for (int i = 0; i < typesToConcretes.length; i++) { + if (typesToConcretes[i] == concreteMethodIndex) { + count++; + } + } + return count; + } + } + + private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi) { + Invoke result = (Invoke) invoke.node().copyWithInputs(); + if (invoke instanceof InvokeWithExceptionNode) { + assert exceptionMerge != null && exceptionObjectPhi != null; + + InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; + BeginNode exceptionEdge = invokeWithException.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + + BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); + ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); + newExceptionEdge.setNext(newExceptionObject); + + EndNode endNode = graph.add(new EndNode()); + newExceptionObject.setNext(endNode); + exceptionMerge.addEnd(endNode); + exceptionObjectPhi.addInput(newExceptionObject); + + ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge); + } + return result; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(String.format("type-checked inlining of %d methods with %d type checks: ", concretes.size(), types.length)); + for (int i = 0; i < concretes.size(); i++) { + builder.append(CiUtil.format(" %H.%n(%p):%r", concretes.get(i))); + } + return builder.toString(); + } + + @Override + public boolean canDeopt() { + return true; + } + } + + + /** * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method, * but for which an assumption has to be registered because of non-final classes. */ @@ -184,14 +411,15 @@ } @Override - public Node inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { + public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { if (Debug.isLogEnabled()) { String targetName = CiUtil.format("%H.%n(%p):%r", invoke.callTarget().targetMethod()); String concreteName = CiUtil.format("%H.%n(%p):%r", concrete); Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName); } callback.recordConcreteMethodAssumption(invoke.callTarget().targetMethod(), context, concrete); - return super.inline(graph, runtime, callback); + + super.inline(graph, runtime, callback); } @Override @@ -248,35 +476,108 @@ } } // TODO (tw) fix this - if (assumptions == null) { - return null; + if (assumptions != null) { + RiResolvedMethod concrete = holder.uniqueConcreteMethod(callTarget.targetMethod()); + if (concrete != null) { + if (checkTargetConditions(concrete)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); + } + return null; + } } - RiResolvedMethod concrete = holder.uniqueConcreteMethod(callTarget.targetMethod()); - if (concrete != null) { - if (checkTargetConditions(concrete)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); + + // type check based inlining + RiProfilingInfo profilingInfo = parent.profilingInfo(); + RiTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); + if (typeProfile != null) { + RiResolvedType[] types = typeProfile.getTypes(); + double[] probabilities = typeProfile.getProbabilities(); + + if (types != null && probabilities != null && types.length > 0) { + assert types.length == probabilities.length : "length must match"; + double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); + if (types.length == 1 && notRecordedTypeProbability == 0) { + if (GraalOptions.InlineMonomorphicCalls) { + RiResolvedType type = types[0]; + RiResolvedMethod concrete = type.resolveMethodImpl(callTarget.targetMethod()); + if (concrete != null && checkTargetConditions(concrete)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); + } + + Debug.log("not inlining %s because method can't be inlined", methodName(callTarget.targetMethod(), invoke)); + return null; + } else { + Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(callTarget.targetMethod(), invoke)); + return null; + } + } else { + if (GraalOptions.InlinePolymorphicCalls) { + if (notRecordedTypeProbability > 0) { + // TODO (ch) allow inlining only the most frequent calls (e.g. 8 different methods, inline only 2 and invoke others) + // may affect peak performance negatively if immature profiling information is used + Debug.log("not inlining %s because not all seen types were could be recorded during profiling", methodName(callTarget.targetMethod(), invoke)); + return null; + } + + // TODO (ch) sort types by probability + + // determine concrete methods and map type to specific method + ArrayList concreteMethods = new ArrayList<>(); + int[] typesToConcretes = new int[types.length]; + for (int i = 0; i < types.length; i++) { + RiResolvedMethod concrete = types[i].resolveMethodImpl(callTarget.targetMethod()); + + int index = concreteMethods.indexOf(concrete); + if (index < 0) { + index = concreteMethods.size(); + concreteMethods.add(concrete); + } + typesToConcretes[i] = index; + } + + double totalWeight = 0; + boolean canInline = true; + for (RiResolvedMethod concrete: concreteMethods) { + if (concrete == null || !checkTargetConditions(concrete)) { + canInline = false; + break; + } + totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + } + + if (canInline) { + convertTypeToBranchProbabilities(probabilities, notRecordedTypeProbability); + return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, types, typesToConcretes, probabilities); + } else { + Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(callTarget.targetMethod(), invoke)); + return null; + } + } else { + Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(callTarget.targetMethod(), invoke)); + return null; + } + } } + + Debug.log("not inlining %s because no types/probabilities were recorded", methodName(callTarget.targetMethod(), invoke)); + return null; + } else { + Debug.log("not inlining %s because no type profile exists", methodName(callTarget.targetMethod(), invoke)); return null; } - RiTypeProfile profile = parent.typeProfile(invoke.bci()); - if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { - if (GraalOptions.InlineWithTypeCheck) { - // type check and inlining... - concrete = profile.types[0].resolveMethodImpl(callTarget.targetMethod()); - if (concrete != null && checkTargetConditions(concrete)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new TypeGuardInlineInfo(invoke, weight, level, concrete, profile.types[0], profile.probabilities[0]); - } - return null; - } else { - Debug.log("not inlining %s because GraalOptions.InlineWithTypeCheck == false", methodName(callTarget.targetMethod(), invoke)); - return null; - } - } else { - Debug.log("not inlining %s because no monomorphic receiver could be found", methodName(callTarget.targetMethod(), invoke)); - return null; + } + + private static void convertTypeToBranchProbabilities(double[] typeProbabilities, double notRecordedTypeProbability) { + // avoid branches with 0.0/1.0 probability + double total = Math.max(1E-10, notRecordedTypeProbability); + + for (int i = typeProbabilities.length - 1; i >= 0; i--) { + total += typeProbabilities[i]; + typeProbabilities[i] = typeProbabilities[i] / total; } + assert total > 0.99 && total < 1.01; } private static boolean checkInvokeConditions(Invoke invoke) { @@ -323,7 +624,7 @@ * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required * @return The node that represents the return value, or null for void methods and methods that have no non-exceptional exit. */ - public static Node inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { + public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { NodeInputList parameters = invoke.callTarget().arguments(); StructuredGraph graph = (StructuredGraph) invoke.node().graph(); @@ -332,7 +633,6 @@ IdentityHashMap replacements = new IdentityHashMap<>(); ArrayList nodes = new ArrayList<>(); - ArrayList frameStates = new ArrayList<>(); ReturnNode returnNode = null; UnwindNode unwindNode = null; BeginNode entryPointNode = inlineGraph.start(); @@ -348,8 +648,6 @@ returnNode = (ReturnNode) node; } else if (node instanceof UnwindNode) { unwindNode = (UnwindNode) node; - } else if (node instanceof FrameState) { - frameStates.add(node); } } } @@ -358,11 +656,9 @@ assert invoke.node().predecessor() != null; Map duplicates = graph.addDuplicates(nodes, replacements); - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - MethodCallTargetNode callTarget = invoke.callTarget(); - if (!callTarget.isStatic() && receiverNullCheck && parameters.get(0).kind() == CiKind.Object && !parameters.get(0).stamp().nonNull()) { - graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(parameters.get(0), false))))); + if (receiverNullCheck) { + receiverNullCheck(invoke); } invoke.node().replaceAtPredecessors(firstCFGNodeDuplicate); @@ -375,9 +671,7 @@ ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next(); stateAtExceptionEdge = obj.stateAfter(); UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - for (Node usage : obj.usages().snapshot()) { - usage.replaceFirstInput(obj, unwindDuplicate.exception()); - } + obj.replaceAtUsages(unwindDuplicate.exception()); unwindDuplicate.clearInputs(); Node n = obj.next(); obj.setNext(null); @@ -404,6 +698,7 @@ } FrameState stateBefore = null; + FrameState outerFrameState = null; double invokeProbability = invoke.node().probability(); for (Node node : duplicates.values()) { if (GraalOptions.ProbabilityAnalysis) { @@ -428,6 +723,11 @@ } else { assert stateAtExceptionEdge == null; } + } else { + if (outerFrameState == null) { + outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); + } + frameState.setOuterFrameState(outerFrameState); } } } @@ -439,13 +739,7 @@ } else { returnValue = duplicates.get(returnNode.result()); } - for (Node usage : invoke.node().usages().snapshot()) { - if (returnNode.result() instanceof LocalNode) { - usage.replaceFirstInput(invoke.node(), returnValue); - } else { - usage.replaceFirstInput(invoke.node(), returnValue); - } - } + invoke.node().replaceAtUsages(returnValue); Node returnDuplicate = duplicates.get(returnNode); returnDuplicate.clearInputs(); Node n = invoke.next(); @@ -465,20 +759,18 @@ invoke.node().replaceAtUsages(null); GraphUtil.killCFG(invoke.node()); - // adjust all frame states that were copied - if (frameStates.size() > 0) { - FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); - for (Node node : frameStates) { - FrameState frameState = (FrameState) duplicates.get(node); - if (!frameState.isDeleted()) { - frameState.setOuterFrameState(outerFrameState); - } - } - } - if (stateAfter.usages().isEmpty()) { stateAfter.safeDelete(); } - return returnValue; + } + + public static void receiverNullCheck(Invoke invoke) { + MethodCallTargetNode callTarget = invoke.callTarget(); + StructuredGraph graph = (StructuredGraph) invoke.graph(); + NodeInputList parameters = callTarget.arguments(); + ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); + if (!callTarget.isStatic() && firstParam.kind() == CiKind.Object && !firstParam.stamp().nonNull()) { + graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false))))); + } } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotVMConfig.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotVMConfig.java Mon Feb 06 09:41:16 2012 -0800 @@ -30,7 +30,7 @@ public final class HotSpotVMConfig extends CompilerObject { /** - * + * */ private static final long serialVersionUID = -4744897993263044184L; @@ -70,8 +70,20 @@ public int runtimeCallStackSize; public int klassModifierFlagsOffset; public int klassOopOffset; + public int graalMirrorKlassOffset; public int nmethodEntryOffset; + // methodData information + public int methodDataOopDataOffset; + public int dataLayoutHeaderSize; + public int dataLayoutTagOffset; + public int dataLayoutFlagsOffset; + public int dataLayoutBCIOffset; + public int dataLayoutCellsOffset; + public int dataLayoutCellSize; + public int bciProfileWidth; + public int typeProfileWidth; + // runtime stubs public long debugStub; public long instanceofStub; diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java Mon Feb 06 09:41:16 2012 -0800 @@ -49,13 +49,9 @@ int RiMethod_invocationCount(HotSpotMethodResolved method); - int RiMethod_exceptionProbability(HotSpotMethodResolved method, int bci); - - RiTypeProfile RiMethod_typeProfile(HotSpotMethodResolved method, int bci); + HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method); - double RiMethod_branchProbability(HotSpotMethodResolved method, int bci); - - double[] RiMethod_switchProbability(HotSpotMethodResolved method, int bci); + boolean HotSpotMethodData_isMature(HotSpotMethodData methodData); RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java Mon Feb 06 09:41:16 2012 -0800 @@ -60,18 +60,6 @@ public native int RiMethod_invocationCount(HotSpotMethodResolved method); @Override - public native int RiMethod_exceptionProbability(HotSpotMethodResolved method, int bci); - - @Override - public native RiTypeProfile RiMethod_typeProfile(HotSpotMethodResolved method, int bci); - - @Override - public native double RiMethod_branchProbability(HotSpotMethodResolved method, int bci); - - @Override - public native double[] RiMethod_switchProbability(HotSpotMethodResolved method, int bci); - - @Override public native RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); @Override @@ -123,6 +111,12 @@ public native boolean RiType_isInitialized(HotSpotTypeResolved klass); @Override + public native HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method); + + @Override + public native boolean HotSpotMethodData_isMature(HotSpotMethodData methodData); + + @Override public native RiType getType(Class javaClass); @Override diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java Mon Feb 06 09:41:16 2012 -0800 @@ -276,6 +276,7 @@ } compiler.getRuntime().installMethod(method, result); } catch (CiBailout bailout) { + Debug.metric("Bailouts").increment(); if (GraalOptions.ExitVMOnBailout) { bailout.printStackTrace(TTY.cachedOut); System.exit(-1); @@ -391,7 +392,9 @@ private PhasePlan getDefaultPhasePlan() { PhasePlan phasePlan = new PhasePlan(); - phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy); + if (GraalOptions.Intrinsify) { + phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy); + } return phasePlan; } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.hotspot.ri; + +import sun.misc.*; + +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.hotspot.*; +import com.oracle.max.graal.hotspot.Compiler; + + +public final class HotSpotMethodData extends CompilerObject { + + /** + * + */ + private static final long serialVersionUID = -8873133496591225071L; + + static { + config = CompilerImpl.getInstance().getConfig(); + } + + // TODO (ch) use same logic as in NodeClass? + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final HotSpotMethodDataAccessor NO_DATA_ACCESSOR = new NoMethodData(); + private static final HotSpotVMConfig config; + // sorted by tag + private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { + null, new BitData(), new CounterData(), new JumpData(), + new TypeCheckData(), new VirtualCallData(), new RetData(), + new BranchData(), new MultiBranchData(), new ArgInfoData() + }; + + private Object hotspotMirror; + private int normalDataSize; + private int extraDataSize; + private boolean mature; + + private HotSpotMethodData(Compiler compiler) { + super(compiler); + throw new IllegalStateException("this constructor is never actually called, because the objects are allocated from within the VM"); + } + + public boolean hasNormalData() { + return normalDataSize > 0; + } + + public boolean hasExtraData() { + return extraDataSize > 0; + } + + public boolean isMature() { + // TODO (ch) maturity of profiling information is an issue in general. Not all optimizations require mature data as long as the code + // does deoptimize/recompile on violations (might decrease startup and increase peak performance). + // Maturity is currently used on several levels: + // 1) whole method data + // 2) individual branch/switch profiling data + // 3) MatureInvocationCount for eliminating exception edges + if (!mature) { + mature = compiler.getVMEntries().HotSpotMethodData_isMature(this); + } + return mature; + } + + public boolean isWithin(int position) { + return position >= 0 && position < normalDataSize + extraDataSize; + } + + public HotSpotMethodDataAccessor getNormalData(int position) { + if (position >= normalDataSize) { + return null; + } + + HotSpotMethodDataAccessor result = getData(position, 0); + assert result != null : "NO_DATA tag is not allowed"; + return result; + } + + public HotSpotMethodDataAccessor getExtraData(int position) { + if (position >= extraDataSize) { + return null; + } + return getData(position, normalDataSize); + } + + public static HotSpotMethodDataAccessor getNoMethodData() { + return NO_DATA_ACCESSOR; + } + + private HotSpotMethodDataAccessor getData(int position, int displacement) { + assert position >= 0 : "out of bounds"; + int tag = AbstractMethodData.readTag(this, displacement + position); + assert tag >= 0 && tag < PROFILE_DATA_ACCESSORS.length : "illegal tag"; + return PROFILE_DATA_ACCESSORS[tag]; + } + + private int readUnsignedByte(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return unsafe.getByte(hotspotMirror, fullOffsetInBytes) & 0xFF; + } + + private int readUnsignedShort(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return unsafe.getShort(hotspotMirror, fullOffsetInBytes) & 0xFFFF; + } + + private long readUnsignedInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return unsafe.getInt(hotspotMirror, fullOffsetInBytes) & 0xFFFFFFFFL; + } + + private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { + long value = readUnsignedInt(position, offsetInBytes); + return truncateLongToInt(value); + } + + private int readInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return unsafe.getInt(hotspotMirror, fullOffsetInBytes); + } + + private Object readObject(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return unsafe.getObject(hotspotMirror, fullOffsetInBytes); + } + + private static int truncateLongToInt(long value) { + return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; + } + + private static int computeFullOffset(int position, int offsetInBytes) { + return config.methodDataOopDataOffset + position + offsetInBytes; + } + + private static int cellIndexToOffset(int cells) { + return config.dataLayoutHeaderSize + cellsToBytes(cells); + } + + private static int cellsToBytes(int cells) { + return cells * config.dataLayoutCellSize; + } + + private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { + private static final int EXCEPTIONS_MASK = 0x80; + + private final int tag; + private final int staticSize; + + protected AbstractMethodData(int tag, int staticSize) { + this.tag = tag; + this.staticSize = staticSize; + } + + public int getTag() { + return tag; + } + + public static int readTag(HotSpotMethodData data, int position) { + return data.readUnsignedByte(position, config.dataLayoutTagOffset); + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return data.readUnsignedShort(position, config.dataLayoutBCIOffset); + } + + @Override + public int getSize(HotSpotMethodData data, int position) { + return staticSize + getDynamicSize(data, position); + } + + @Override + public boolean getExceptionSeen(HotSpotMethodData data, int position) { + return (getFlags(data, position) & EXCEPTIONS_MASK) != 0; + } + + @Override + public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + return null; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + protected int getFlags(HotSpotMethodData data, int position) { + return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); + } + + protected int getDynamicSize(@SuppressWarnings("unused") HotSpotMethodData data, @SuppressWarnings("unused") int position) { + return 0; + } + } + + private static class NoMethodData extends AbstractMethodData { + private static final int NO_DATA_TAG = 0; + private static final int NO_DATA_SIZE = cellIndexToOffset(0); + + protected NoMethodData() { + super(NO_DATA_TAG, NO_DATA_SIZE); + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return -1; + } + + + @Override + public boolean getExceptionSeen(HotSpotMethodData data, int position) { + return false; + } + } + + private static class BitData extends AbstractMethodData { + private static final int BIT_DATA_TAG = 1; + private static final int BIT_DATA_SIZE = cellIndexToOffset(0); + private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; + + private BitData() { + super(BIT_DATA_TAG, BIT_DATA_SIZE); + } + + protected BitData(int tag, int staticSize) { + super(tag, staticSize); + } + + @SuppressWarnings("unused") + public boolean getNullSeen(HotSpotMethodData data, int position) { + return (getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0; + } + } + + private static class CounterData extends BitData { + private static final int COUNTER_DATA_TAG = 2; + private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); + private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); + + public CounterData() { + super(COUNTER_DATA_TAG, COUNTER_DATA_SIZE); + } + + protected CounterData(int tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + protected int getCounterValue(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); + } + } + + private static class JumpData extends AbstractMethodData { + private static final int JUMP_DATA_TAG = 3; + private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); + protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); + protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); + + public JumpData() { + super(JUMP_DATA_TAG, JUMP_DATA_SIZE); + } + + protected JumpData(int tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return 1; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); + } + + @SuppressWarnings("unused") + public int getTakenDisplacement(HotSpotMethodData data, int position) { + return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); + } + } + + private abstract static class AbstractTypeData extends CounterData { + private static final int RECEIVER_TYPE_DATA_ROW_SIZE = cellsToBytes(2); + private static final int RECEIVER_TYPE_DATA_SIZE = cellIndexToOffset(1) + RECEIVER_TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + private static final int RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET = cellIndexToOffset(1); + private static final int RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET = cellIndexToOffset(2); + + protected AbstractTypeData(int tag) { + super(tag, RECEIVER_TYPE_DATA_SIZE); + } + + @Override + public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + int typeProfileWidth = config.typeProfileWidth; + + RiResolvedType[] sparseTypes = new RiResolvedType[typeProfileWidth]; + double[] counts = new double[typeProfileWidth]; + long totalCount = 0; + int entries = 0; + + for (int i = 0; i < typeProfileWidth; i++) { + Object receiverKlassOop = data.readObject(position, getReceiverOffset(i)); + if (receiverKlassOop != null) { + Object graalMirror = unsafe.getObject(receiverKlassOop, (long) config.graalMirrorKlassOffset); + if (graalMirror == null) { + Class javaClass = (Class) unsafe.getObject(receiverKlassOop, (long) config.classMirrorOffset); + graalMirror = CompilerImpl.getInstance().getVMEntries().getType(javaClass); + assert graalMirror != null : "must not return null"; + } + sparseTypes[entries] = (RiResolvedType) graalMirror; + + long count = data.readUnsignedInt(position, getCountOffset(i)); + totalCount += count; + counts[entries] = count; + + entries++; + } + } + + totalCount += getTypesNotRecordedExecutionCount(data, position); + return createRiTypeProfile(sparseTypes, counts, totalCount, entries); + } + + protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + + private static RiTypeProfile createRiTypeProfile(RiResolvedType[] sparseTypes, double[] counts, long totalCount, int entries) { + RiResolvedType[] types; + double[] probabilities; + + if (entries <= 0) { + return null; + } else if (entries < sparseTypes.length) { + RiResolvedType[] compactedTypes = new RiResolvedType[entries]; + System.arraycopy(sparseTypes, 0, compactedTypes, 0, entries); + types = compactedTypes; + probabilities = new double[entries]; + } else { + types = sparseTypes; + probabilities = counts; + } + + double totalProbability = 0.0; + for (int i = 0; i < entries; i++) { + double p = counts[i] / totalCount; + probabilities[i] = p; + totalProbability += p; + } + + double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + return new RiTypeProfile(types, notRecordedTypeProbability, probabilities); + } + + private static int getReceiverOffset(int row) { + return RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE; + } + + protected static int getCountOffset(int row) { + return RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET + row * RECEIVER_TYPE_DATA_ROW_SIZE; + } + } + + private static class TypeCheckData extends AbstractTypeData { + private static final int RECEIVER_TYPE_DATA_TAG = 4; + + public TypeCheckData() { + super(RECEIVER_TYPE_DATA_TAG); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + // TODO (ch) if types do not fit, profiling is skipped for typechecks + return 0; + } + } + + private static class VirtualCallData extends AbstractTypeData { + private static final int VIRTUAL_CALL_DATA_TAG = 5; + + public VirtualCallData() { + super(VIRTUAL_CALL_DATA_TAG); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + int typeProfileWidth = config.typeProfileWidth; + + long total = 0; + for (int i = 0; i < typeProfileWidth; i++) { + total += data.readUnsignedInt(position, getCountOffset(i)); + } + + total += getCounterValue(data, position); + return truncateLongToInt(total); + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + } + + private static class RetData extends CounterData { + private static final int RET_DATA_TAG = 6; + private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); + private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; + + public RetData() { + super(RET_DATA_TAG, RET_DATA_SIZE); + } + } + + private static class BranchData extends JumpData { + private static final int BRANCH_DATA_TAG = 7; + private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); + private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); + private static final int BRANCH_DATA_MATURE_COUNT = 40; + + public BranchData() { + super(BRANCH_DATA_TAG, BRANCH_DATA_SIZE); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); + long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + long total = takenCount + notTakenCount; + + if (total < BRANCH_DATA_MATURE_COUNT) { + return -1; + } else { + return takenCount / (double) total; + } + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + return truncateLongToInt(count); + } + } + + private static class ArrayData extends AbstractMethodData { + private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); + protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); + + public ArrayData(int tag, int staticSize) { + super(tag, staticSize); + } + + @Override + protected int getDynamicSize(HotSpotMethodData data, int position) { + return cellsToBytes(getLength(data, position)); + } + + protected static int getLength(HotSpotMethodData data, int position) { + return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); + } + } + + private static class MultiBranchData extends ArrayData { + private static final int MULTI_BRANCH_DATA_TAG = 8; + private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); + private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; + private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); + private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); + private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); + + public MultiBranchData() { + super(MULTI_BRANCH_DATA_TAG, MULTI_BRANCH_DATA_SIZE); + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + double[] result = new double[length]; + + // default case is first in HotSpot but last for the compiler + long count = readCount(data, position, 0); + totalCount += count; + result[length - 1] = count; + + for (int i = 1; i < length; i++) { + count = readCount(data, position, i); + totalCount += count; + result[i - 1] = count; + } + + if (totalCount < 10 * (length + 2)) { + return null; + } else { + for (int i = 0; i < length; i++) { + result[i] = result[i] / totalCount; + } + return result; + } + } + + private static long readCount(HotSpotMethodData data, int position, int i) { + int offset; + long count; + offset = getCountOffset(i); + count = data.readUnsignedInt(position, offset); + return count; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + for (int i = 0; i < length; i++) { + int offset = getCountOffset(i); + totalCount += data.readUnsignedInt(position, offset); + } + + return truncateLongToInt(totalCount); + } + + private static int getCountOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + @SuppressWarnings("unused") + private static int getDisplacementOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + } + + private static class ArgInfoData extends ArrayData { + private static final int ARG_INFO_DATA_TAG = 9; + private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); + + public ArgInfoData() { + super(ARG_INFO_DATA_TAG, ARG_INFO_DATA_SIZE); + } + } +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.hotspot.ri; + +import com.oracle.max.cri.ri.*; + +/** + * Interface for accessor objects that encapsulate the logic for accessing the different kinds of data in a HotSpot methodDataOop. + * This interface is similar to the interface {@link RiProfilingInfo}, but most methods require a MethodDataObject and the + * exact position within the methodData. + */ +public interface HotSpotMethodDataAccessor { + /** + * Returns the tag stored in the LayoutData header. + * @return An integer >= 0 or -1 if not supported. + */ + int getTag(); + + /** + * Returns the BCI stored in the LayoutData header. + * @return An integer >= 0 and <= Short.MAX_VALUE, or -1 if not supported. + */ + int getBCI(HotSpotMethodData data, int position); + + /** + * Computes the size for the specific data at the given position. + * @return An integer > 0. + */ + int getSize(HotSpotMethodData data, int position); + + RiTypeProfile getTypeProfile(HotSpotMethodData data, int position); + double getBranchTakenProbability(HotSpotMethodData data, int position); + double[] getSwitchProbabilities(HotSpotMethodData data, int position); + boolean getExceptionSeen(HotSpotMethodData data, int position); + int getExecutionCount(HotSpotMethodData data, int position); +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Mon Feb 06 09:41:16 2012 -0800 @@ -55,6 +55,7 @@ private Boolean hasBalancedMonitors; private Map compilerStorage; private RiResolvedType holder; + private HotSpotMethodData methodData; private byte[] code; private boolean canBeInlined; private CiGenericCallback callback; @@ -187,24 +188,22 @@ return null; } + @Override public int invocationCount() { return compiler.getVMEntries().RiMethod_invocationCount(this); } - public int exceptionProbability(int bci) { - return compiler.getVMEntries().RiMethod_exceptionProbability(this, bci); - } + @Override + public RiProfilingInfo profilingInfo() { + if (methodData == null) { + methodData = compiler.getVMEntries().RiMethod_methodData(this); + } - public RiTypeProfile typeProfile(int bci) { - return compiler.getVMEntries().RiMethod_typeProfile(this, bci); - } - - public double branchProbability(int bci) { - return compiler.getVMEntries().RiMethod_branchProbability(this, bci); - } - - public double[] switchProbability(int bci) { - return compiler.getVMEntries().RiMethod_switchProbability(this, bci); + if (methodData == null || !methodData.isMature()) { + return new HotSpotNoProfilingInfo(compiler); + } else { + return new HotSpotProfilingInfo(compiler, methodData); + } } @Override @@ -224,25 +223,40 @@ TTY.println("profile info for %s", this); TTY.println("canBeStaticallyBound: " + canBeStaticallyBound()); TTY.println("invocationCount: " + invocationCount()); + RiProfilingInfo profilingInfo = this.profilingInfo(); for (int i = 0; i < codeSize(); i++) { - if (branchProbability(i) != -1) { - TTY.println(" branchProbability@%d: %f", i, branchProbability(i)); - } - if (exceptionProbability(i) > 0) { - TTY.println(" exceptionProbability@%d: %d", i, exceptionProbability(i)); + if (profilingInfo.getExecutionCount(i) != -1) { + TTY.println(" executionCount@%d: %d", i, profilingInfo.getExecutionCount(i)); } - RiTypeProfile profile = typeProfile(i); - if (profile != null && profile.count > 0) { - TTY.print(" profile@%d: count: %d, morphism: %d", i, profile.count, profile.morphism); - if (profile.types != null) { - TTY.print(", types:"); - for (int i2 = 0; i2 < profile.types.length; i2++) { - TTY.print(" %s (%f)", profile.types[i2], profile.probabilities[i2]); - } + + if (profilingInfo.getBranchTakenProbability(i) != -1) { + TTY.println(" branchProbability@%d: %f", i, profilingInfo.getBranchTakenProbability(i)); + } + + double[] switchProbabilities = profilingInfo.getSwitchProbabilities(i); + if (switchProbabilities != null) { + TTY.print(" switchProbabilities@%d:", i); + for (int j = 0; j < switchProbabilities.length; j++) { + TTY.print(" %f", switchProbabilities[j]); } TTY.println(); - if (exceptionProbability(i) > 0) { - TTY.println(" exceptionProbability@%d: %d", i, exceptionProbability(i)); + } + + if (profilingInfo.getExceptionSeen(i)) { + TTY.println(" exceptionSeen@%d: true", i); + } + + RiTypeProfile typeProfile = profilingInfo.getTypeProfile(i); + if (typeProfile != null) { + RiResolvedType[] types = typeProfile.getTypes(); + double[] probabilities = typeProfile.getProbabilities(); + if (types != null && probabilities != null) { + assert types.length == probabilities.length : "length must match"; + TTY.print(" types@%d:", i); + for (int j = 0; j < types.length; j++) { + TTY.print(" %s (%f)", types[j], probabilities[j]); + } + TTY.println(" not recorded (%f)", typeProfile.getNotRecordedProbability()); } } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.hotspot.ri; + +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.hotspot.*; +import com.oracle.max.graal.hotspot.Compiler; + + +public final class HotSpotNoProfilingInfo extends CompilerObject implements RiProfilingInfo { + /** + * + */ + private static final long serialVersionUID = 4357945025049704109L; + private static final HotSpotMethodDataAccessor noData = HotSpotMethodData.getNoMethodData(); + + public HotSpotNoProfilingInfo(Compiler compiler) { + super(compiler); + } + + @Override + public RiTypeProfile getTypeProfile(int bci) { + return noData.getTypeProfile(null, -1); + } + + @Override + public double getBranchTakenProbability(int bci) { + return noData.getBranchTakenProbability(null, -1); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + return noData.getSwitchProbabilities(null, -1); + } + + @Override + public boolean getExceptionSeen(int bci) { + return noData.getExceptionSeen(null, -1); + } + + @Override + public int getExecutionCount(int bci) { + return noData.getExecutionCount(null, -1); + } +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.hotspot.ri; + +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.hotspot.*; +import com.oracle.max.graal.hotspot.Compiler; + + +public final class HotSpotProfilingInfo extends CompilerObject implements RiProfilingInfo { + + /** + * + */ + private static final long serialVersionUID = -8307682725047864875L; + + private int position; + private int hintPosition; + private int hintBCI; + private HotSpotMethodDataAccessor dataAccessor; + private HotSpotMethodData methodData; + + public HotSpotProfilingInfo(Compiler compiler, HotSpotMethodData methodData) { + super(compiler); + this.methodData = methodData; + hintPosition = 0; + hintBCI = -1; + } + + @Override + public RiTypeProfile getTypeProfile(int bci) { + findBCI(bci, false); + return dataAccessor.getTypeProfile(methodData, position); + } + + @Override + public double getBranchTakenProbability(int bci) { + findBCI(bci, false); + return dataAccessor.getBranchTakenProbability(methodData, position); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + findBCI(bci, false); + return dataAccessor.getSwitchProbabilities(methodData, position); + } + + @Override + public boolean getExceptionSeen(int bci) { + findBCI(bci, true); + return dataAccessor.getExceptionSeen(methodData, position); + } + + @Override + public int getExecutionCount(int bci) { + findBCI(bci, false); + return dataAccessor.getExecutionCount(methodData, position); + } + + private void findBCI(int targetBCI, boolean searchExtraData) { + assert targetBCI >= 0 : "invalid BCI"; + + if (methodData.hasNormalData()) { + int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + normalDataFound(currentAccessor, currentPosition, currentBCI); + return; + } else if (currentBCI > targetBCI) { + break; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + + if (searchExtraData && methodData.hasExtraData()) { + int currentPosition = 0; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + extraDataFound(currentAccessor, currentPosition); + return; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + + noDataFound(); + } + + private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { + setCurrentData(data, pos); + this.hintPosition = position; + this.hintBCI = bci; + } + + private void extraDataFound(HotSpotMethodDataAccessor data, int pos) { + setCurrentData(data, pos); + } + + private void noDataFound() { + setCurrentData(HotSpotMethodData.getNoMethodData(), -1); + } + + private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { + this.dataAccessor = dataAccessor; + this.position = position; + } +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java Mon Feb 06 09:41:16 2012 -0800 @@ -314,6 +314,12 @@ } else if (n instanceof ArrayHeaderSizeNode) { ArrayHeaderSizeNode arrayHeaderSize = (ArrayHeaderSizeNode) n; graph.replaceFloating(arrayHeaderSize, ConstantNode.forLong(config.getArrayOffset(arrayHeaderSize.elementKind()), n.graph())); + } else if (n instanceof ReadHubNode) { + ReadHubNode objectClassNode = (ReadHubNode) n; + LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph); + ReadNode memoryRead = graph.add(new ReadNode(CiKind.Object, objectClassNode.object(), location)); + memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)))); + graph.replaceFixed(objectClassNode, memoryRead); } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Mon Feb 06 09:41:16 2012 -0800 @@ -1174,32 +1174,21 @@ @Override protected XirTemplate create(CiXirAssembler asm, long flags) { asm.restart(); - XirParameter object = asm.createInputParameter("object", CiKind.Object); + XirParameter objHub = asm.createInputParameter("objectHub", CiKind.Object); XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object); + XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor); - XirOperand objHub = asm.createTemp("objHub", CiKind.Object); XirOperand checkHub = asm.createTemp("checkHub", CiKind.Object); - XirLabel slowPath = asm.createOutOfLineLabel("deopt"); - if (is(NULL_CHECK, flags)) { asm.mark(MARK_IMPLICIT_NULL); } - asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); asm.mov(checkHub, hub); // if we get an exact match: continue - asm.jneq(slowPath, objHub, checkHub); + asm.jneq(falseSucc, objHub, checkHub); - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(slowPath); - XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - asm.mov(scratch, wordConst(asm, 2)); - - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.shouldNotReachHere(); - - return asm.finishTemplate(object, "typeCheck"); + return asm.finishTemplate(objHub, "typeCheck"); } }; @@ -1411,9 +1400,9 @@ } @Override - public XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type) { + public XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type) { assert type instanceof RiResolvedType; - return new XirSnippet(typeCheckTemplates.get(site), object, hub); + return new XirSnippet(typeCheckTemplates.get(site), thisHub, otherHub); } @Override diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/snippets/ArrayCopySnippets.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/snippets/ArrayCopySnippets.java Mon Feb 06 09:41:16 2012 -0800 @@ -21,7 +21,6 @@ * questions. */ package com.oracle.max.graal.hotspot.snippets; - import com.oracle.max.cri.ci.*; import com.oracle.max.graal.cri.*; import com.oracle.max.graal.hotspot.*; @@ -285,7 +284,6 @@ DirectObjectStoreNode.store(dest, i + (destOffset + header), a); } } - /** * Copies {@code length} bytes from {@code src} starting at {@code srcPos} to {@code dest} starting at {@code destPos}. * @param src source object @@ -347,7 +345,6 @@ DirectObjectStoreNode.store(dest, i + (destOffset + header), a); } } - private static class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable { @Input private ValueNode object; @@ -398,6 +395,44 @@ gen.emitStore(new CiAddress(v.kind, gen.operand(address)), v, false); } } + private static class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { + @Input private ValueNode object; + @Input private ValueNode value; + @Input private ValueNode offset; + + public DirectObjectStoreNode(ValueNode object, ValueNode offset, ValueNode value) { + super(StampFactory.illegal()); + this.object = object; + this.value = value; + this.offset = offset; + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static void store(Object obj, long offset, long value) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static void store(Object obj, long offset, boolean value) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unused") + @NodeIntrinsic + public static void store(Object obj, long offset, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public void lower(CiLoweringTool tool) { + StructuredGraph graph = (StructuredGraph) this.graph(); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), 0, offset, graph, false); + WriteNode write = graph.add(new WriteNode(object, value, location)); + graph.replaceFixedWithFixed(this, write); + } + } private static class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { @Input private ValueNode object; diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Mon Feb 06 09:41:16 2012 -0800 @@ -236,6 +236,7 @@ // mark the entrypoints of basic blocks and build lists of successors for // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) byte[] code = method.code(); + RiProfilingInfo profilingInfo = method.profilingInfo(); Block current = null; int bci = 0; while (bci < code.length) { @@ -282,7 +283,7 @@ case IFNULL: // fall through case IFNONNULL: { current = null; - double probability = useBranchPrediction ? method.branchProbability(bci) : -1; + double probability = useBranchPrediction ? profilingInfo.getBranchTakenProbability(bci) : -1; Block b1 = probability == 0.0 ? new DeoptBlock(bci + Bytes.beS2(code, bci + 1)) : makeBlock(bci + Bytes.beS2(code, bci + 1)); Block b2 = probability == 1.0 ? new DeoptBlock(bci + 3) : makeBlock(bci + 3); @@ -351,7 +352,7 @@ break; } default: { - if (canTrap(opcode, bci)) { + if (canTrap(opcode, bci, profilingInfo)) { canTrap.set(bci); } } @@ -360,7 +361,7 @@ } } - public boolean canTrap(int opcode, int bci) { + private static boolean canTrap(int opcode, int bci, RiProfilingInfo profilingInfo) { switch (opcode) { case INVOKESTATIC: case INVOKESPECIAL: @@ -387,7 +388,7 @@ case PUTFIELD: case GETFIELD: { if (GraalOptions.AllowExplicitExceptionChecks) { - return method.exceptionProbability(bci) > 0; + return profilingInfo.getExceptionSeen(bci); } } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Mon Feb 06 09:41:16 2012 -0800 @@ -72,6 +72,7 @@ private RiConstantPool constantPool; private RiExceptionHandler[] exceptionHandlers; private RiResolvedMethod method; + private RiProfilingInfo profilingInfo; private BytecodeStream stream; // the bytecode stream private final LogStream log; @@ -116,6 +117,7 @@ @Override protected void run(StructuredGraph graph) { method = graph.method(); + profilingInfo = method.profilingInfo(); assert method.code() != null : "method must contain bytecodes: " + method; this.stream = new BytecodeStream(method.code()); this.constantPool = method.getConstantPool(); @@ -321,7 +323,7 @@ assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci"; if (GraalOptions.UseExceptionProbability && method.invocationCount() > GraalOptions.MatureInvocationCount) { - if (bci != FrameState.BEFORE_BCI && exceptionObject == null && method.exceptionProbability(bci) == 0) { + if (bci != FrameState.BEFORE_BCI && exceptionObject == null && !profilingInfo.getExceptionSeen(bci)) { return null; } } @@ -602,7 +604,7 @@ private void ifNode(ValueNode x, Condition cond, ValueNode y) { assert !x.isDeleted() && !y.isDeleted(); - double probability = method.branchProbability(bci()); + double probability = profilingInfo.getBranchTakenProbability(bci()); if (probability < 0) { Debug.log("missing probability in %s at bci %d", method, bci()); probability = 0.5; @@ -1185,7 +1187,7 @@ } private double[] switchProbability(int numberOfCases, int bci) { - double[] prob = method.switchProbability(bci); + double[] prob = profilingInfo.getSwitchProbabilities(bci); if (prob != null) { assert prob.length == numberOfCases; } else { diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -44,8 +44,8 @@ return compare; } - public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double probability) { - super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {probability, 1 - probability}); + public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability) { + super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability}); this.compare = condition; } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/Invoke.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/Invoke.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/Invoke.java Mon Feb 06 09:41:16 2012 -0800 @@ -46,4 +46,6 @@ void intrinsify(Node node); Graph graph(); + + double probability(); } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/LookupSwitchNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/LookupSwitchNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/LookupSwitchNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -29,7 +29,7 @@ * The {@code LookupSwitchNode} represents a lookup switch bytecode, which has a sorted * array of key values. */ -public final class LookupSwitchNode extends SwitchNode implements LIRLowerable { +public final class LookupSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable { @Data private final int[] keys; @@ -66,4 +66,32 @@ public void generate(LIRGeneratorTool gen) { gen.emitLookupSwitch(this); } + + @Override + public void simplify(SimplifierTool tool) { + if (value() instanceof ConstantNode) { + ConstantNode constant = (ConstantNode) value(); + int value = constant.value.asInt(); + + BeginNode remainingSux = (BeginNode) defaultSuccessor(); + int remainingSuxIndex = blockSuccessorCount() - 1; + for (int i = 0; i < keys.length; i++) { + if (value == keys[i]) { + remainingSux = blockSuccessor(i); + remainingSuxIndex = i; + break; + } + } + + for (int i = 0; i < blockSuccessorCount(); i++) { + BeginNode sux = blockSuccessor(i); + if (sux != remainingSux) { + tool.deleteBranch(sux); + } + } + + tool.addToWorkList(remainingSux); + ((StructuredGraph) graph()).removeSplit(this, remainingSuxIndex); + } + } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ReadHubNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ReadHubNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.nodes.extended; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.cri.*; +import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.spi.*; +import com.oracle.max.graal.nodes.type.*; + +// TODO (ch) this should be a FloatingNode but Lowering crashes in that case +public final class ReadHubNode extends FixedWithNextNode implements Lowerable { + @Input private ValueNode object; + + public ValueNode object() { + return object; + } + + public ReadHubNode(ValueNode object) { + super(StampFactory.forKind(CiKind.Object)); + this.object = object; + } + + @Override + public void lower(CiLoweringTool tool) { + tool.getRuntime().lower(this, tool); + } +} diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TableSwitchNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TableSwitchNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TableSwitchNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -28,7 +28,7 @@ /** * The {@code TableSwitchNode} represents a table switch. */ -public final class TableSwitchNode extends SwitchNode implements LIRLowerable { +public final class TableSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable { @Data private final int lowKey; @@ -67,4 +67,30 @@ public void generate(LIRGeneratorTool gen) { gen.emitTableSwitch(this); } + + @Override + public void simplify(SimplifierTool tool) { + if (value() instanceof ConstantNode) { + ConstantNode constant = (ConstantNode) value(); + int value = constant.value.asInt(); + + int remainingSuxIndex; + if (value >= lowKey() && value <= highKey()) { + remainingSuxIndex = value - lowKey(); + } else { + remainingSuxIndex = blockSuccessorCount() - 1; + } + + BeginNode remainingSux = blockSuccessor(remainingSuxIndex); + for (int i = 0; i < blockSuccessorCount(); i++) { + BeginNode sux = blockSuccessor(i); + if (sux != remainingSux) { + tool.deleteBranch(sux); + } + } + + tool.addToWorkList(remainingSux); + ((StructuredGraph) graph()).removeSplit(this, remainingSuxIndex); + } + } } diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/ArrayLengthNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/ArrayLengthNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/ArrayLengthNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -58,7 +58,7 @@ return length; } CiConstant constantValue = null; - if (array().isConstant()) { + if (array().isConstant() && !array().isNullConstant()) { constantValue = array().asConstant(); if (constantValue != null && constantValue.isNonNull()) { RiRuntime runtime = tool.runtime(); diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -27,30 +27,30 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.spi.*; import com.oracle.max.graal.nodes.type.*; public final class IsTypeNode extends BooleanNode implements Canonicalizable, LIRLowerable { - @Input private ValueNode object; + @Input private ValueNode objectClass; + @Data private final RiResolvedType type; - public ValueNode object() { - return object; + public ValueNode objectClass() { + return objectClass; } - private final RiResolvedType type; - /** * Constructs a new IsTypeNode. * * @param object the instruction producing the object to check against the given type * @param type the type for this check */ - public IsTypeNode(ValueNode object, RiResolvedType type) { + public IsTypeNode(ValueNode objectClass, RiResolvedType type) { super(StampFactory.illegal()); - assert object == null || object.kind() == CiKind.Object; + assert objectClass == null || objectClass.kind() == CiKind.Object; this.type = type; - this.object = object; + this.objectClass = objectClass; } public RiResolvedType type() { @@ -71,8 +71,9 @@ @Override public ValueNode canonical(CanonicalizerTool tool) { - if (object().exactType() != null) { - return ConstantNode.forBoolean(object().exactType() == type(), graph()); + RiResolvedType exactType = objectClass() instanceof ReadHubNode ? ((ReadHubNode) objectClass()).object().exactType() : null; + if (exactType != null) { + return ConstantNode.forBoolean(exactType == type(), graph()); } // constants return the correct exactType, so they are handled by the code above return this; diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/LoadFieldNode.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/LoadFieldNode.java Mon Feb 06 09:41:16 2012 -0800 @@ -69,7 +69,7 @@ CiConstant constant = null; if (isStatic()) { constant = field().constantValue(null); - } else if (object().isConstant()) { + } else if (object().isConstant() && !object().isNullConstant()) { constant = field().constantValue(object().asConstant()); } if (constant != null) { diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java --- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java Sat Feb 04 15:43:40 2012 +0100 +++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java Mon Feb 06 09:41:16 2012 -0800 @@ -41,7 +41,7 @@ assert ((NullCheckNode) usage).object() == node; return false; } else if (usage instanceof IsTypeNode) { - assert ((IsTypeNode) usage).object() == node; + assert ((IsTypeNode) usage).objectClass() == node; return false; } else if (usage instanceof FrameState) { assert usage.inputs().contains(node); diff -r 0312460af9fc -r 11a4af4a6621 graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/LIRGeneratorTool.java diff -r 0312460af9fc -r 11a4af4a6621 make/windows/makefiles/projectcreator.make --- a/make/windows/makefiles/projectcreator.make Sat Feb 04 15:43:40 2012 +0100 +++ b/make/windows/makefiles/projectcreator.make Mon Feb 06 09:41:16 2012 -0800 @@ -89,7 +89,7 @@ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ -prelink "" "Generating vm.def..." "cd %o set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \ - -postbuild "" "Building hotspot.exe..." "cd %o HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) nmake -f $(HOTSPOTWORKSPACE)\make\windows\projectfiles\common\Makefile LOCAL_MAKE=$(HOTSPOTBUILDSPACE)\%f\local.make JAVA_HOME=$(HOTSPOTJDKDIST) launcher" \ + -postbuild "" "Building hotspot.exe..." "cd %o set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) nmake -f $(HOTSPOTWORKSPACE)\make\windows\projectfiles\common\Makefile LOCAL_MAKE=$(HOTSPOTBUILDSPACE)\%f\local.make JAVA_HOME=$(HOTSPOTJDKDIST) launcher" \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvStub.cpp \ diff -r 0312460af9fc -r 11a4af4a6621 src/cpu/x86/vm/c1_globals_x86.hpp --- a/src/cpu/x86/vm/c1_globals_x86.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/cpu/x86/vm/c1_globals_x86.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -47,7 +47,7 @@ define_pd_global(intx, FreqInlineSize, 325 ); define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(intx, InitialCodeCacheSize, 4*M); // changed for GRAAL -define_pd_global(intx, ReservedCodeCacheSize, 50*M ); // changed for GRAAL +define_pd_global(intx, ReservedCodeCacheSize, 48*M ); // changed for GRAAL define_pd_global(bool, ProfileInterpreter, true ); // changed for GRAAL define_pd_global(intx, CodeCacheExpansionSize, 64*K ); // changed for GRAAL define_pd_global(uintx,CodeCacheMinBlockLength, 4); // changed for GRAAL @@ -57,7 +57,7 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); define_pd_global(bool, CICompileOSR, true ); #endif // !TIERED -define_pd_global(bool, UseTypeProfile, true ); // changed for GRAAL +define_pd_global(intx, TypeProfileWidth, 8 ); // changed for GRAAL define_pd_global(bool, RoundFPResults, true ); define_pd_global(bool, LIRFillDelaySlots, false); diff -r 0312460af9fc -r 11a4af4a6621 src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -39,6 +39,7 @@ define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); +define_pd_global(intx, TypeProfileWidth, 2 ); #ifdef CC_INTERP define_pd_global(bool, ProfileInterpreter, false); #else diff -r 0312460af9fc -r 11a4af4a6621 src/share/tools/ProjectCreator/BuildConfig.java --- a/src/share/tools/ProjectCreator/BuildConfig.java Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/tools/ProjectCreator/BuildConfig.java Mon Feb 06 09:41:16 2012 -0800 @@ -69,7 +69,7 @@ outDir = value; } if (!build.equals("product")) { - outDir += Util.sep + "fastdebug"; + outDir += Util.sep + build; } outDir += Util.sep + "jre" + Util.sep + "bin"; if (flavour.equals("compiler1")) { diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/classfile/systemDictionary.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -193,6 +193,7 @@ template(HotSpotField_klass, com_oracle_max_graal_hotspot_HotSpotField, Opt) \ template(HotSpotCompiledMethod_klass, com_oracle_max_graal_hotspot_HotSpotCompiledMethod, Opt) \ template(HotSpotMethodResolved_klass, com_oracle_max_graal_hotspot_ri_HotSpotMethodResolved, Opt) \ + template(HotSpotMethodData_klass, com_oracle_max_graal_hotspot_ri_HotSpotMethodData, Opt) \ template(HotSpotTargetMethod_klass, com_oracle_max_graal_hotspot_HotSpotTargetMethod, Opt) \ template(HotSpotExceptionHandler_klass, com_oracle_max_graal_hotspot_HotSpotExceptionHandler, Opt) \ template(HotSpotProxy_klass, com_oracle_max_graal_hotspot_HotSpotProxy, Opt) \ @@ -223,7 +224,6 @@ template(RiType_klass, com_oracle_max_cri_ri_RiType, Opt) \ template(RiResolvedField_klass, com_oracle_max_cri_ri_RiResolvedField, Opt) \ template(RiExceptionHandler_klass, com_oracle_max_cri_ri_RiExceptionHandler, Opt) \ - template(RiTypeProfile_klass, com_oracle_max_cri_ri_RiTypeProfile, Opt) \ /*end*/ diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -272,6 +272,7 @@ template(com_oracle_max_graal_hotspot_bridge_VMToCompiler, "com/oracle/max/graal/hotspot/bridge/VMToCompiler") \ template(com_oracle_max_graal_hotspot_ri_HotSpotMethodResolved, "com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl") \ template(com_oracle_max_graal_hotspot_HotSpotTargetMethod, "com/oracle/max/graal/hotspot/HotSpotTargetMethod") \ + template(com_oracle_max_graal_hotspot_ri_HotSpotMethodData, "com/oracle/max/graal/hotspot/ri/HotSpotMethodData") \ template(com_oracle_max_graal_hotspot_HotSpotField, "com/oracle/max/graal/hotspot/ri/HotSpotField") \ template(com_oracle_max_graal_hotspot_HotSpotCompiledMethod, "com/oracle/max/graal/hotspot/ri/HotSpotCompiledMethod") \ template(com_oracle_max_graal_hotspot_HotSpotOptions, "com/oracle/max/graal/hotspot/HotSpotOptions") \ @@ -284,7 +285,6 @@ template(com_oracle_max_cri_ri_RiMethod, "com/oracle/max/cri/ri/RiMethod") \ template(com_oracle_max_cri_ri_RiResolvedField, "com/oracle/max/cri/ri/RiResolvedField") \ template(com_oracle_max_cri_ri_RiType, "com/oracle/max/cri/ri/RiType") \ - template(com_oracle_max_cri_ri_RiTypeProfile, "com/oracle/max/cri/ri/RiTypeProfile") \ template(com_oracle_max_cri_ri_RiConstantPool, "com/oracle/max/cri/ri/RiConstantPool") \ template(com_oracle_max_cri_ri_RiExceptionHandler, "com/oracle/max/cri/ri/RiExceptionHandler") \ template(com_oracle_max_cri_ci_CiAssumptions, "com/oracle/max/cri/ci/CiAssumptions") \ diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/graal/graalCompiler.cpp Mon Feb 06 09:41:16 2012 -0800 @@ -29,6 +29,7 @@ #include "graal/graalVmIds.hpp" #include "graal/graalEnv.hpp" #include "c1/c1_Runtime1.hpp" +#include "compiler/compilerOracle.hpp" #include "runtime/arguments.hpp" GraalCompiler* GraalCompiler::_instance = NULL; @@ -270,10 +271,30 @@ HotSpotMethodResolved::set_accessFlags(obj, method->access_flags().as_int()); HotSpotMethodResolved::set_maxLocals(obj, method->max_locals()); HotSpotMethodResolved::set_maxStackSize(obj, method->max_stack()); - HotSpotMethodResolved::set_canBeInlined(obj, true); + HotSpotMethodResolved::set_canBeInlined(obj, !CompilerOracle::should_not_inline(method)); method->set_graal_mirror(obj()); - return obj(); + return obj; +} + +Handle GraalCompiler::createHotSpotMethodData(methodDataHandle method_data, TRAPS) { + if(method_data->graal_mirror() != NULL) { + assert(method_data->graal_mirror()->is_a(HotSpotMethodData::klass()), "unexpected class"); + return method_data->graal_mirror(); + } + + instanceKlass::cast(HotSpotMethodData::klass())->initialize(CHECK_NULL); + Handle obj = instanceKlass::cast(HotSpotMethodData::klass())->allocate_instance(CHECK_NULL); + assert(obj.not_null(), "must succeed in allocating instance"); + + HotSpotMethodData::set_compiler(obj, VMToCompiler::compilerInstance()()); + HotSpotMethodData::set_hotspotMirror(obj, method_data()); + HotSpotMethodData::set_normalDataSize(obj, method_data()->data_size()); + HotSpotMethodData::set_extraDataSize(obj, method_data()->extra_data_size()); + HotSpotMethodData::set_mature(obj, method_data()->is_mature()); + + method_data->set_graal_mirror(obj()); + return obj; } BasicType GraalCompiler::kindToBasicType(jchar ch) { diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/graal/graalCompiler.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -67,6 +67,7 @@ static Handle createHotSpotTypeResolved(KlassHandle klass, Handle name, TRAPS); static Handle createHotSpotMethodResolved(methodHandle method, TRAPS); + static Handle createHotSpotMethodData(methodDataHandle method_data, TRAPS); void exit(); diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Feb 06 09:41:16 2012 -0800 @@ -44,6 +44,10 @@ return (methodOop)HotSpotMethodResolved::javaMirror(hotspot_method); } +methodDataOop getMethodDataFromHotSpotMethodData(jobject hotspot_method_data) { + return (methodDataOop)HotSpotMethodData::hotspotMirror(JNIHandles::resolve(hotspot_method_data)); +} + // public byte[] RiMethod_code(HotSpotResolvedMethod method); JNIEXPORT jbyteArray JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1code(JNIEnv *env, jobject, jobject hotspot_method) { TRACE_graal_3("CompilerToVM::RiMethod_code"); @@ -182,26 +186,25 @@ return getMethodFromHotSpotMethod(hotspot_method)->invocation_count(); } -// public native int RiMethod_exceptionProbability(long vmId, int bci); -JNIEXPORT jint JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2exceptionProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) { - TRACE_graal_3("CompilerToVM::RiMethod_exceptionProbability"); +// public native HotSpotMethodData RiMethod_methodData(HotSpotMethodResolved method); +JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1methodData(JNIEnv *, jobject, jobject hotspot_method) { + TRACE_graal_3("CompilerToVM::RiMethod_methodData"); VM_ENTRY_MARK; - ResourceMark rm; - methodHandle method = getMethodFromHotSpotMethod(hotspot_method); - methodDataHandle method_data = method->method_data(); - if (method_data == NULL || !method_data->is_mature()) { - return -1; + + methodDataHandle method_data = getMethodFromHotSpotMethod(hotspot_method)->method_data(); + if(method_data.is_null()) { + return NULL; + } else { + Handle graalMethodData = GraalCompiler::createHotSpotMethodData(method_data, THREAD); + return JNIHandles::make_local(THREAD, graalMethodData()); } - ProfileData* data = method_data->bci_to_data(bci); - if (data == NULL) { - return 0; - } - uint trap = Deoptimization::trap_state_is_recompiled(data->trap_state())? 1: 0; - if (trap > 0) { - return 100; - } else { - return trap; - } +} + +JNIEXPORT jboolean JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_HotSpotMethodData_1isMature(JNIEnv *, jobject, jobject hotspot_method_data) { + TRACE_graal_3("CompilerToVM::HotSpotMethodData_isMature"); + VM_ENTRY_MARK; + methodDataHandle method_data = getMethodDataFromHotSpotMethodData(hotspot_method_data); + return method_data->is_mature(); } // ------------------------------------------------------------------ @@ -230,137 +233,6 @@ return count; } -// public native RiTypeProfile RiMethod_typeProfile(long vmId, int bci); -JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2typeProfile(JNIEnv *, jobject, jobject hotspot_method, jint bci) { - TRACE_graal_3("CompilerToVM::RiMethod_typeProfile"); - VM_ENTRY_MARK; - Handle obj; - - methodHandle method = getMethodFromHotSpotMethod(hotspot_method); - methodDataHandle method_data = method->method_data(); - if (method_data == NULL || !method_data->is_mature()) { - return NULL; - } - ResourceMark rm; - ProfileData* data = method_data->bci_to_data(bci); - if (data != NULL && data->is_ReceiverTypeData()) { - ReceiverTypeData* recv = data->as_ReceiverTypeData(); - GrowableArray receivers; - GrowableArray counts; - // determine morphism - uint total_count = 0; - for (uint i = 0; i < recv->row_limit(); i++) { - klassOop receiver = recv->receiver(i); - if (receiver == NULL) continue; - uint count = recv->receiver_count(i); - total_count += count; - receivers.append(receiver); - counts.append(count); - } - - instanceKlass::cast(RiTypeProfile::klass())->initialize(CHECK_NULL); - obj = instanceKlass::cast(RiTypeProfile::klass())->allocate_instance(CHECK_NULL); - assert(obj() != NULL, "must succeed in allocating instance"); - - int count = MAX2(total_count, recv->count()); - RiTypeProfile::set_count(obj, scale_count(method_data(), count)); - RiTypeProfile::set_morphism(obj, receivers.length()); - - if (receivers.length() > 0) { - typeArrayHandle probabilities = oopFactory::new_typeArray(T_FLOAT, receivers.length(), CHECK_NULL); - objArrayHandle types = oopFactory::new_objArray(SystemDictionary::RiType_klass(), receivers.length(), CHECK_NULL); - for (int i = 0; i < receivers.length(); i++) { - KlassHandle receiver = receivers.at(i); - - float prob = counts.at(i) / (float) total_count; - Handle type = GraalCompiler::get_RiType(receiver, CHECK_NULL); - - probabilities->float_at_put(i, prob); - types->obj_at_put(i, type()); - - } - - RiTypeProfile::set_probabilities(obj, probabilities()); - RiTypeProfile::set_types(obj, types()); - } else { - RiTypeProfile::set_probabilities(obj, NULL); - RiTypeProfile::set_types(obj, NULL); - } - } - return JNIHandles::make_local(obj()); -} - -JNIEXPORT jdouble JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2branchProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) { - TRACE_graal_3("CompilerToVM::RiMethod_typeProfile"); - ResourceMark rm; - methodHandle method = getMethodFromHotSpotMethod(hotspot_method); - methodDataHandle method_data = method->method_data(); - - if (method_data == NULL || !method_data->is_mature()) return -1; - method_data->bci_to_data(bci); - - ProfileData* data = method_data->bci_to_data(bci); - if (data == NULL || !data->is_JumpData()) return -1; - - // get taken and not taken values - int taken = data->as_JumpData()->taken(); - int not_taken = 0; - if (data->is_BranchData()) { - not_taken = data->as_BranchData()->not_taken(); - } - - // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful. - // We also check that individual counters are positive first, otherwise the sum can become positive. - if (taken < 0 || not_taken < 0 || taken + not_taken < 40) return -1; - - // Pin probability to sane limits - if (taken == 0) - return 0; - else if (not_taken == 0) - return 1; - else { // Compute probability of true path - return (jdouble)(taken) / (taken + not_taken); - } -} - -JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_2switchProbability(JNIEnv *, jobject, jobject hotspot_method, jint bci) { - TRACE_graal_3("CompilerToVM::RiMethod_typeProfile"); - VM_ENTRY_MARK; - ResourceMark rm; - methodHandle method = getMethodFromHotSpotMethod(hotspot_method); - methodDataHandle method_data = method->method_data(); - - if (method_data == NULL || !method_data->is_mature()) return NULL; - - ProfileData* data = method_data->bci_to_data(bci); - if (data == NULL || !data->is_MultiBranchData()) return NULL; - - MultiBranchData* branch_data = data->as_MultiBranchData(); - - long sum = 0; - int cases = branch_data->number_of_cases(); - GrowableArray* counts = new GrowableArray(cases + 1); - - for (int i = 0; i < cases; i++) { - uint value = branch_data->count_at(i); - sum += value; - counts->append(value); - } - uint value = branch_data->default_count(); - sum += value; - counts->append(value); - - // Give up if too few (or too many, in which case the sum will overflow) counts to be meaningful. - // We also check that individual counters are positive first, otherwise the sum can become positive. - if (sum < 10 * (cases + 3)) return NULL; - - typeArrayOop probability = oopFactory::new_typeArray(T_DOUBLE, cases + 1, CHECK_NULL); - for (int i = 0; i < cases + 1; i++) { - probability->double_at_put(i, counts->at(i) / (double) sum); - } - return JNIHandles::make_local(probability); -} - // public native boolean RiMethod_hasCompiledCode(HotSpotMethodResolved method); JNIEXPORT jboolean JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1hasCompiledCode(JNIEnv *, jobject, jobject hotspot_method) { TRACE_graal_3("CompilerToVM::RiMethod_hasCompiledCode"); @@ -875,6 +747,16 @@ set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); set_int(env, config, "threadMultiNewArrayStorage", in_bytes(JavaThread::graal_multinewarray_storage_offset())); set_int(env, config, "classMirrorOffset", klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes()); + + set_int(env, config, "methodDataOopDataOffset", in_bytes(methodDataOopDesc::data_offset())); + set_int(env, config, "dataLayoutHeaderSize", DataLayout::header_size_in_bytes()); + set_int(env, config, "dataLayoutTagOffset", in_bytes(DataLayout::tag_offset())); + set_int(env, config, "dataLayoutFlagsOffset", in_bytes(DataLayout::flags_offset())); + set_int(env, config, "dataLayoutBCIOffset", in_bytes(DataLayout::bci_offset())); + set_int(env, config, "dataLayoutCellsOffset", in_bytes(DataLayout::cell_offset(0))); + set_int(env, config, "dataLayoutCellSize", DataLayout::cell_size); + set_int(env, config, "bciProfileWidth", BciProfileWidth); + set_int(env, config, "typeProfileWidth", TypeProfileWidth); set_long(env, config, "debugStub", VmIds::addStub((address)warning)); set_long(env, config, "instanceofStub", VmIds::addStub(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); @@ -898,7 +780,9 @@ set_long(env, config, "safepointPollingAddress", (jlong)(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()))); set_int(env, config, "runtimeCallStackSize", (jint)frame::arg_reg_save_area_bytes); set_int(env, config, "klassModifierFlagsOffset", Klass::modifier_flags_offset_in_bytes() + sizeof(oopDesc)); + set_int(env, config, "graalMirrorKlassOffset", klassOopDesc::klass_part_offset_in_bytes() + Klass::graal_mirror_offset_in_bytes()); set_int(env, config, "klassOopOffset", java_lang_Class::klass_offset_in_bytes()); + set_boolean(env, config, "isPollingPageFar", Assembler::is_polling_page_far()); set_int(env, config, "nmethodEntryOffset", nmethod::verified_entry_point_offset()); @@ -1023,7 +907,6 @@ #define METHOD "Lcom/oracle/max/cri/ri/RiMethod;" #define RESOLVED_METHOD "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethodResolved;" #define REFLECT_METHOD "Ljava/lang/reflect/Method;" -#define TYPE_PROFILE "Lcom/oracle/max/cri/ri/RiTypeProfile;" #define SIGNATURE "Lcom/oracle/max/cri/ri/RiSignature;" #define FIELD "Lcom/oracle/max/cri/ri/RiField;" #define RESOLVED_FIELD "Lcom/oracle/max/cri/ri/RiResolvedField;" @@ -1033,6 +916,7 @@ #define CONFIG "Lcom/oracle/max/graal/hotspot/HotSpotVMConfig;" #define HS_METHOD "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethod;" #define HS_COMP_METHOD "Lcom/oracle/max/graal/hotspot/ri/HotSpotCompiledMethod;" +#define METHOD_DATA "Lcom/oracle/max/graal/hotspot/ri/HotSpotMethodData;" #define CI_CONSTANT "Lcom/oracle/max/cri/ci/CiConstant;" #define CI_KIND "Lcom/oracle/max/cri/ci/CiKind;" #define CI_RUNTIME_CALL "Lcom/oracle/max/cri/ci/CiRuntimeCall;" @@ -1047,11 +931,9 @@ {CC"RiMethod_hasBalancedMonitors", CC"("RESOLVED_METHOD")Z", FN_PTR(RiMethod_1hasBalancedMonitors)}, {CC"RiMethod_uniqueConcreteMethod", CC"("RESOLVED_METHOD")"METHOD, FN_PTR(RiMethod_1uniqueConcreteMethod)}, {CC"getRiMethod", CC"("REFLECT_METHOD")"METHOD, FN_PTR(getRiMethod)}, - {CC"RiMethod_typeProfile", CC"("RESOLVED_METHOD"I)"TYPE_PROFILE, FN_PTR(RiMethod_2typeProfile)}, - {CC"RiMethod_branchProbability", CC"("RESOLVED_METHOD"I)D", FN_PTR(RiMethod_2branchProbability)}, - {CC"RiMethod_switchProbability", CC"("RESOLVED_METHOD"I)[D", FN_PTR(RiMethod_2switchProbability)}, + {CC"RiMethod_methodData", CC"("RESOLVED_METHOD")"METHOD_DATA, FN_PTR(RiMethod_1methodData)}, + {CC"HotSpotMethodData_isMature", CC"("METHOD_DATA")Z", FN_PTR(HotSpotMethodData_1isMature)}, {CC"RiMethod_invocationCount", CC"("RESOLVED_METHOD")I", FN_PTR(RiMethod_1invocationCount)}, - {CC"RiMethod_exceptionProbability", CC"("RESOLVED_METHOD"I)I", FN_PTR(RiMethod_2exceptionProbability)}, {CC"RiMethod_hasCompiledCode", CC"("RESOLVED_METHOD")Z", FN_PTR(RiMethod_1hasCompiledCode)}, {CC"RiSignature_lookupType", CC"("STRING RESOLVED_TYPE")"TYPE, FN_PTR(RiSignature_1lookupType)}, {CC"RiConstantPool_lookupConstant", CC"("RESOLVED_TYPE"I)"OBJECT, FN_PTR(RiConstantPool_1lookupConstant)}, diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/graal/graalJavaAccess.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -70,6 +70,13 @@ boolean_field(HotSpotMethodResolved, canBeInlined) \ oop_field(HotSpotMethodResolved, callback, "Lcom/oracle/max/cri/ci/CiGenericCallback;") \ end_class \ + start_class(HotSpotMethodData) \ + oop_field(HotSpotMethodData, compiler, "Lcom/oracle/max/graal/hotspot/Compiler;") \ + oop_field(HotSpotMethodData, hotspotMirror, "Ljava/lang/Object;") \ + int_field(HotSpotMethodData, normalDataSize) \ + int_field(HotSpotMethodData, extraDataSize) \ + boolean_field(HotSpotMethodData, mature) \ + end_class \ start_class(HotSpotType) \ oop_field(HotSpotType, name, "Ljava/lang/String;") \ end_class \ @@ -228,12 +235,6 @@ oop_field(CiMonitorValue, lockData, "Lcom/oracle/max/cri/ci/CiValue;") \ boolean_field(CiMonitorValue, eliminated) \ end_class \ - start_class(RiTypeProfile) \ - int_field(RiTypeProfile, count) \ - int_field(RiTypeProfile, morphism) \ - oop_field(RiTypeProfile, probabilities, "[F") \ - oop_field(RiTypeProfile, types, "[Lcom/oracle/max/cri/ri/RiResolvedType;") \ - end_class \ /* end*/ #define START_CLASS(name) \ diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/oops/klass.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -386,6 +386,7 @@ static int secondary_super_cache_offset_in_bytes() { return offset_of(Klass, _secondary_super_cache); } static int secondary_supers_offset_in_bytes() { return offset_of(Klass, _secondary_supers); } static int java_mirror_offset_in_bytes() { return offset_of(Klass, _java_mirror); } + static int graal_mirror_offset_in_bytes() { return offset_of(Klass, _graal_mirror); } static int modifier_flags_offset_in_bytes(){ return offset_of(Klass, _modifier_flags); } static int layout_helper_offset_in_bytes() { return offset_of(Klass, _layout_helper); } static int access_flags_offset_in_bytes() { return offset_of(Klass, _access_flags); } diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/oops/methodDataKlass.cpp --- a/src/share/vm/oops/methodDataKlass.cpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/oops/methodDataKlass.cpp Mon Feb 06 09:41:16 2012 -0800 @@ -84,6 +84,7 @@ obj->follow_header(); MarkSweep::mark_and_push(m->adr_method()); + MarkSweep::mark_and_push(m->adr_graal_mirror()); ResourceMark rm; for (ProfileData* data = m->first_data(); m->is_valid(data); @@ -100,6 +101,7 @@ obj->follow_header(cm); PSParallelCompact::mark_and_push(cm, m->adr_method()); + PSParallelCompact::mark_and_push(cm, m->adr_graal_mirror()); ResourceMark rm; for (ProfileData* data = m->first_data(); m->is_valid(data); @@ -119,6 +121,7 @@ obj->oop_iterate_header(blk); blk->do_oop(m->adr_method()); + blk->do_oop(m->adr_graal_mirror()); ResourceMark rm; for (ProfileData* data = m->first_data(); m->is_valid(data); @@ -140,6 +143,11 @@ if (mr.contains(adr)) { blk->do_oop(m->adr_method()); } + adr = m->adr_graal_mirror(); + if(mr.contains(adr)) { + blk->do_oop(m->adr_graal_mirror()); + } + ResourceMark rm; for (ProfileData* data = m->first_data(); m->is_valid(data); @@ -158,6 +166,7 @@ obj->adjust_header(); MarkSweep::adjust_pointer(m->adr_method()); + MarkSweep::adjust_pointer(m->adr_graal_mirror()); ResourceMark rm; ProfileData* data; for (data = m->first_data(); m->is_valid(data); data = m->next_data(data)) { @@ -173,6 +182,11 @@ methodDataOop m = methodDataOop(obj); // This should never point into the young gen. assert(!PSScavenge::should_scavenge(m->adr_method()), "Sanity"); + + oop* adr = m->adr_graal_mirror(); + if(PSScavenge::should_scavenge(adr)) { + pm->claim_or_forward_depth(adr); + } } int methodDataKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { @@ -180,6 +194,7 @@ methodDataOop m = methodDataOop(obj); PSParallelCompact::adjust_pointer(m->adr_method()); + PSParallelCompact::adjust_pointer(m->adr_graal_mirror()); ResourceMark rm; ProfileData* data; diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/oops/methodDataOop.cpp --- a/src/share/vm/oops/methodDataOop.cpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/oops/methodDataOop.cpp Mon Feb 06 09:41:16 2012 -0800 @@ -749,6 +749,7 @@ ResourceMark rm; // Set the method back-pointer. _method = method(); + _graal_mirror = NULL; if (TieredCompilation) { _invocation_counter.init(); diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/oops/methodDataOop.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -1194,6 +1194,9 @@ // Back pointer to the methodOop methodOop _method; + // com/oracle/max/graal/hotspot/HotSpotProfilingInfo mirroring this method + oop _graal_mirror; + // Size of this oop in bytes int _size; @@ -1423,6 +1426,10 @@ // Accessors methodOop method() { return _method; } + // graal mirror + oop graal_mirror() const { return _graal_mirror; } + void set_graal_mirror(oop m) { oop_store((oop*) &_graal_mirror, m); } + // Get the data at an arbitrary (sort of) data index. ProfileData* data_at(int data_index); @@ -1520,6 +1527,7 @@ // GC support oop* adr_method() const { return (oop*)&_method; } + oop* adr_graal_mirror() const { return (oop*)&_graal_mirror; } bool object_is_parsable() const { return _size != 0; } void set_object_is_parsable(int object_size_in_bytes) { _size = object_size_in_bytes; } diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/runtime/globals.hpp Mon Feb 06 09:41:16 2012 -0800 @@ -3124,7 +3124,7 @@ "if non-zero, start verifying C heap after Nth call to " \ "malloc/realloc/free") \ \ - product(intx, TypeProfileWidth, 2, \ + product_pd(intx, TypeProfileWidth, \ "number of receiver types to record in call/cast profile") \ \ develop(intx, BciProfileWidth, 2, \ diff -r 0312460af9fc -r 11a4af4a6621 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Sat Feb 04 15:43:40 2012 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Feb 06 09:41:16 2012 -0800 @@ -359,6 +359,7 @@ nonstatic_field(methodDataOopDesc, _arg_local, intx) \ nonstatic_field(methodDataOopDesc, _arg_stack, intx) \ nonstatic_field(methodDataOopDesc, _arg_returned, intx) \ + nonstatic_field(methodDataOopDesc, _graal_mirror, oop) \ nonstatic_field(methodOopDesc, _constMethod, constMethodOop) \ nonstatic_field(methodOopDesc, _constants, constantPoolOop) \ nonstatic_field(methodOopDesc, _method_data, methodDataOop) \