# HG changeset patch # User Thomas Wuerthinger # Date 1332334650 -3600 # Node ID 4d8ebb0fc4847c8103ca30cf58407c5259ed2b4c # Parent 09f66048738e4e7cf6a0685c4eef69d05fb4da5c# Parent 7b2efb5ff2eaf7f5157d711cacf36c5a87abfb9a Merge. diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,10 +26,6 @@ import java.util.*; import java.util.concurrent.*; -import com.oracle.max.asm.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.xir.*; import com.oracle.graal.alloc.simple.*; import com.oracle.graal.compiler.alloc.*; import com.oracle.graal.compiler.gen.*; @@ -44,6 +40,10 @@ import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; +import com.oracle.max.asm.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.xir.*; public class GraalCompiler { @@ -74,11 +74,7 @@ this.backend = backend; } - public CiTargetMethod compileMethod(RiResolvedMethod method, int osrBCI, PhasePlan plan) { - return compileMethod(method, new StructuredGraph(method), osrBCI, plan); - } - - public CiTargetMethod compileMethod(final RiResolvedMethod method, final StructuredGraph graph, int osrBCI, final PhasePlan plan) { + public CiTargetMethod compileMethod(final RiResolvedMethod method, final StructuredGraph graph, int osrBCI, final PhasePlan plan, final OptimisticOptimizations optimisticOpts) { assert (method.accessFlags() & Modifier.NATIVE) == 0 : "compiling native methods is not supported"; if (osrBCI != -1) { throw new CiBailout("No OSR supported"); @@ -89,7 +85,7 @@ final CiAssumptions assumptions = GraalOptions.OptAssumptions ? new CiAssumptions() : null; final LIR lir = Debug.scope("FrontEnd", new Callable() { public LIR call() { - return emitHIR(graph, assumptions, plan); + return emitHIR(graph, assumptions, plan, optimisticOpts); } }); final FrameMap frameMap = Debug.scope("BackEnd", lir, new Callable() { @@ -109,7 +105,7 @@ /** * Builds the graph, optimizes it. */ - public LIR emitHIR(StructuredGraph graph, CiAssumptions assumptions, PhasePlan plan) { + public LIR emitHIR(StructuredGraph graph, CiAssumptions assumptions, PhasePlan plan, OptimisticOptimizations optimisticOpts) { if (graph.start().next() == null) { plan.runPhases(PhasePosition.AFTER_PARSING, graph); @@ -141,7 +137,7 @@ } if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { - new InliningPhase(target, runtime, null, assumptions, plan).apply(graph); + new InliningPhase(target, runtime, null, assumptions, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); new PhiStampPhase().apply(graph); } @@ -161,7 +157,7 @@ } if (GraalOptions.EscapeAnalysis && !plan.isPhaseDisabled(EscapeAnalysisPhase.class)) { - new EscapeAnalysisPhase(target, runtime, assumptions, plan).apply(graph); + new EscapeAnalysisPhase(target, runtime, assumptions, plan, optimisticOpts).apply(graph); new PhiStampPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(target, runtime, assumptions).apply(graph); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Wed Mar 21 13:57:30 2012 +0100 @@ -44,9 +44,9 @@ public static boolean Inline = true; public static boolean Intrinsify = true; public static boolean CacheGraphs = ____; - public static boolean InlineMonomorphicCalls = true; - public static boolean InlinePolymorphicCalls = true; - public static boolean InlineMegamorphicCalls = ____; + static boolean InlineMonomorphicCalls = true; + static boolean InlinePolymorphicCalls = true; + static boolean InlineMegamorphicCalls = ____; public static int InliningPolicy = 4; public static int WeightComputationPolicy = 2; public static int MaximumTrivialSize = 10; @@ -81,6 +81,8 @@ public static int LoopFrequencyPropagationPolicy = -2; // profiling information + public static int DeoptsToDisableOptimisticOptimization = 40; + public static boolean PrintDisabledOptimisticOptimizations = true; public static int MatureExecutionsBranch = 1; public static int MatureExecutionsPerSwitchCase = 1; public static int MatureExecutionsTypeProfile = 1; @@ -139,6 +141,7 @@ public static int TraceLIRGeneratorLevel = 0; public static boolean TraceEscapeAnalysis = ____; public static int TraceBytecodeParserLevel = 0; + public static boolean PrintBailouts = true; public static boolean ExitVMOnBailout = ____; public static boolean ExitVMOnException = true; @@ -147,13 +150,14 @@ // Code generator settings public static boolean PropagateTypes = ____; - public static boolean UseBranchPrediction = true; - public static boolean UseExceptionProbability = true; + public static boolean UseProfilingInformation = true; + static boolean RemoveNeverExecutedCode = true; + static boolean UseExceptionProbability = true; public static boolean AllowExplicitExceptionChecks = true; public static boolean OmitHotExceptionStacktrace = ____; public static boolean GenSafepoints = true; public static boolean GenLoopSafepoints = true; - public static boolean UseTypeCheckHints = true; + static boolean UseTypeCheckHints = true; public static boolean InlineVTableStubs = ____; public static boolean AlwaysInlineVTableStubs = ____; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java Wed Mar 21 13:57:30 2012 +0100 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; + + + +public final class OptimisticOptimizations { + public static final OptimisticOptimizations ALL = new OptimisticOptimizations(EnumSet.allOf(Optimization.class)); + public static final OptimisticOptimizations NONE = new OptimisticOptimizations(EnumSet.noneOf(Optimization.class)); + private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts"); + + private static enum Optimization { + RemoveNeverExecutedCode, + UseTypeCheckedInlining, + UseTypeCheckHints, + UseExceptionProbability + } + + private final Set enabledOpts; + + public OptimisticOptimizations(RiResolvedMethod method) { + this.enabledOpts = EnumSet.noneOf(Optimization.class); + + RiProfilingInfo profilingInfo = method.profilingInfo(); + if (checkDeoptimizations(profilingInfo, RiDeoptReason.UnreachedCode)) { + enabledOpts.add(Optimization.RemoveNeverExecutedCode); + } + if (checkDeoptimizations(profilingInfo, RiDeoptReason.TypeCheckedInliningViolated)) { + enabledOpts.add(Optimization.UseTypeCheckedInlining); + } + if (checkDeoptimizations(profilingInfo, RiDeoptReason.OptimizedTypeCheckViolated)) { + enabledOpts.add(Optimization.UseTypeCheckHints); + } + if (checkDeoptimizations(profilingInfo, RiDeoptReason.NotCompiledExceptionHandler)) { + enabledOpts.add(Optimization.UseExceptionProbability); + } + } + + private OptimisticOptimizations(Set enabledOpts) { + this.enabledOpts = enabledOpts; + } + + public void log(RiMethod method) { + for (Optimization opt: Optimization.values()) { + if (!enabledOpts.contains(opt)) { + if (GraalOptions.PrintDisabledOptimisticOptimizations) { + TTY.println("WARN: deactivated optimistic optimization %s for %s", opt.name(), CiUtil.format("%H.%n(%p)", method)); + } + disabledOptimisticOptsMetric.increment(); + } + } + } + + public boolean removeNeverExecutedCode() { + return GraalOptions.RemoveNeverExecutedCode && enabledOpts.contains(Optimization.RemoveNeverExecutedCode); + } + + public boolean useUseTypeCheckHints() { + return GraalOptions.UseTypeCheckHints && enabledOpts.contains(Optimization.UseTypeCheckHints); + } + + public boolean inlineMonomorphicCalls() { + return GraalOptions.InlineMonomorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); + } + + public boolean inlinePolymorphicCalls() { + return GraalOptions.InlinePolymorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); + } + + public boolean inlineMegamorphicCalls() { + return GraalOptions.InlineMegamorphicCalls && enabledOpts.contains(Optimization.UseTypeCheckedInlining); + } + + public boolean useExceptionProbability() { + return GraalOptions.UseExceptionProbability && enabledOpts.contains(Optimization.UseExceptionProbability); + } + + public boolean lessOptimisticThan(OptimisticOptimizations other) { + for (Optimization opt: Optimization.values()) { + if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) { + return true; + } + } + return false; + } + + private static boolean checkDeoptimizations(RiProfilingInfo profilingInfo, RiDeoptReason reason) { + return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization; + } +} diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Mar 21 13:57:30 2012 +0100 @@ -56,7 +56,6 @@ import com.oracle.graal.lir.StandardOp.PhiLabelOp; import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -745,7 +744,7 @@ } @Override - public void emitGuardCheck(BooleanNode comp) { + public void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason) { if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) { emitNullCheckGuard((NullCheckNode) comp); } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) { @@ -753,7 +752,7 @@ } else { // Fall back to a normal branch. LIRDebugInfo info = state(); - LabelRef stubEntry = createDeoptStub(DeoptAction.InvalidateReprofile, info, comp); + LabelRef stubEntry = createDeoptStub(RiDeoptAction.InvalidateReprofile, deoptReason, info, comp); emitBranch(comp, null, stubEntry, info); } } @@ -986,7 +985,7 @@ } - protected abstract LabelRef createDeoptStub(DeoptAction action, LIRDebugInfo info, Object deoptInfo); + protected abstract LabelRef createDeoptStub(RiDeoptAction action, RiDeoptReason reason, LIRDebugInfo info, Object deoptInfo); @Override public Variable emitCallToRuntime(CiRuntimeCall runtimeCall, boolean canTrap, CiValue... args) { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Wed Mar 21 13:57:30 2012 +0100 @@ -84,7 +84,7 @@ } BeginNode ifBlockBegin = findBeginNode(ifNode); Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode)); + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason())); otherBegin.replaceAtUsages(ifBlockBegin); FixedNode next = otherBegin.next(); otherBegin.setNext(null); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Wed Mar 21 13:57:30 2012 +0100 @@ -215,12 +215,14 @@ private final GraalRuntime runtime; private final CiAssumptions assumptions; private final PhasePlan plan; + private final OptimisticOptimizations optimisticOpts; - public EscapeAnalysisPhase(CiTarget target, GraalRuntime runtime, CiAssumptions assumptions, PhasePlan plan) { + public EscapeAnalysisPhase(CiTarget target, GraalRuntime runtime, CiAssumptions assumptions, PhasePlan plan, OptimisticOptimizations optimisticOpts) { this.runtime = runtime; this.target = target; this.assumptions = assumptions; this.plan = plan; + this.optimisticOpts = optimisticOpts; } public static class EscapeRecord { @@ -387,7 +389,7 @@ if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { TTY.println("Trying inlining to get a non-escaping object for %s", node); } - new InliningPhase(target, runtime, invokes, assumptions, plan).apply(graph); + new InliningPhase(target, runtime, invokes, assumptions, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); if (node.isDeleted()) { if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java Wed Mar 21 13:57:30 2012 +0100 @@ -56,18 +56,20 @@ private final PhasePlan plan; private final WeightComputationPolicy weightComputationPolicy; private final InliningPolicy inliningPolicy; + private final OptimisticOptimizations optimisticOpts; // Metrics private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed"); private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered"); private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); - public InliningPhase(CiTarget target, GraalRuntime runtime, Collection hints, CiAssumptions assumptions, PhasePlan plan) { + public InliningPhase(CiTarget target, GraalRuntime runtime, Collection hints, CiAssumptions assumptions, PhasePlan plan, OptimisticOptimizations optimisticOpts) { this.target = target; this.runtime = runtime; this.hints = hints; this.assumptions = assumptions; this.plan = plan; + this.optimisticOpts = optimisticOpts; this.weightComputationPolicy = createWeightComputationPolicy(); this.inliningPolicy = createInliningPolicy(); } @@ -139,7 +141,7 @@ } private void scanInvoke(Invoke invoke, int level) { - InlineInfo info = InliningUtil.getInlineInfo(invoke, level >= 0 ? level : computeInliningLevel(invoke), runtime, assumptions, this); + InlineInfo info = InliningUtil.getInlineInfo(invoke, level >= 0 ? level : computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts); if (info != null) { assert level == -1 || computeInliningLevel(invoke) == level : "outer FramesStates must match inlining level"; metricInliningConsidered.increment(); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java Wed Mar 21 13:57:30 2012 +0100 @@ -28,6 +28,7 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ri.*; public class LoweringPhase extends Phase { @@ -59,8 +60,8 @@ } @Override - public Node createGuard(Node condition) { - // TODO (thomaswue): Docuemnt why this must not be called on floating nodes. + public Node createGuard(Node condition, RiDeoptReason deoptReason) { + // TODO (thomaswue): Document why this must not be called on floating nodes. throw new UnsupportedOperationException(); } }; @@ -117,7 +118,7 @@ } @Override - public Node createGuard(Node condition) { + public Node createGuard(Node condition, RiDeoptReason deoptReason) { FixedNode guardAnchor = (FixedNode) getGuardAnchor(); if (GraalOptions.OptEliminateGuards) { for (Node usage : condition.usages()) { @@ -126,7 +127,7 @@ } } } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor)); + GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, deoptReason)); activeGuards.grow(); activeGuards.mark(newGuard); return newGuard; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/PhasePlan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/PhasePlan.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/PhasePlan.java Wed Mar 21 13:57:30 2012 +0100 @@ -53,11 +53,8 @@ LOW_LEVEL } - public static final PhasePlan DEFAULT = new PhasePlan(); - @SuppressWarnings("unchecked") private final ArrayList[] phases = new ArrayList[PhasePosition.values().length]; - private final Set> disabledPhases = new HashSet<>(); public void addPhase(PhasePosition pos, Phase phase) { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Wed Mar 21 13:57:30 2012 +0100 @@ -24,29 +24,29 @@ import java.util.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; import com.oracle.max.asm.*; import com.oracle.max.asm.target.amd64.*; import com.oracle.max.cri.ci.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; +import com.oracle.max.cri.ri.*; public class AMD64DeoptimizationStub extends AMD64SlowPath { public final Label label = new Label(); public final LIRDebugInfo info; - public final DeoptAction action; + public final RiDeoptAction action; + public final RiDeoptReason reason; public final Object deoptInfo; - public AMD64DeoptimizationStub(DeoptAction action, LIRDebugInfo info, Object deoptInfo) { + public AMD64DeoptimizationStub(RiDeoptAction action, RiDeoptReason reason, LIRDebugInfo info, Object deoptInfo) { this.action = action; + this.reason = reason; this.info = info; this.deoptInfo = deoptInfo; } - private static ArrayList keepAlive = new ArrayList<>(); @Override @@ -62,28 +62,9 @@ // TODO Make this an explicit calling convention instead of using a scratch register AMD64Call.directCall(tasm, masm, CiRuntimeCall.SetDeoptInfo, info); } - int code; - switch(action) { - case None: - code = 0; - break; - case Recompile: - code = 1; - break; - case InvalidateReprofile: - code = 2; - break; - case InvalidateRecompile: - code = 3; - break; - case InvalidateStopCompiling: - code = 4; - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - masm.movq(scratch, code); - // TODO Make this an explicit calling convention instead of using a scratch register + + masm.movl(scratch, tasm.runtime.encodeDeoptActionAndReason(action, reason)); + // TODO Make this an explicit calling convention instead of using a scratch register AMD64Call.directCall(tasm, masm, CiRuntimeCall.Deoptimize, info); AMD64Call.shouldNotReachHere(tasm, masm); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Mar 21 13:57:30 2012 +0100 @@ -66,7 +66,6 @@ import com.oracle.graal.lir.amd64.AMD64Move.NullCheckOp; import com.oracle.graal.lir.amd64.AMD64Move.SpillMoveOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -500,9 +499,9 @@ @Override - public void emitDeoptimizeOn(Condition cond, DeoptAction action, Object deoptInfo) { + public void emitDeoptimizeOn(Condition cond, RiDeoptAction action, RiDeoptReason reason, Object deoptInfo) { LIRDebugInfo info = state(); - LabelRef stubEntry = createDeoptStub(action, info, deoptInfo); + LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo); if (cond != null) { append(new BranchOp(cond, stubEntry, info)); } else { @@ -547,9 +546,9 @@ } @Override - protected LabelRef createDeoptStub(DeoptAction action, LIRDebugInfo info, Object deoptInfo) { + protected LabelRef createDeoptStub(RiDeoptAction action, RiDeoptReason reason, LIRDebugInfo info, Object deoptInfo) { assert info.topFrame.bci >= 0 : "invalid bci for deopt framestate"; - AMD64DeoptimizationStub stub = new AMD64DeoptimizationStub(action, info, deoptInfo); + AMD64DeoptimizationStub stub = new AMD64DeoptimizationStub(action, reason, info, deoptInfo); lir.deoptimizationStubs.add(stub); return LabelRef.forLabel(stub.label); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java Wed Mar 21 13:57:30 2012 +0100 @@ -35,7 +35,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -52,23 +51,23 @@ void recordConcreteMethodAssumption(RiResolvedMethod method, RiResolvedType context, RiResolvedMethod impl); } - public static String methodName(RiResolvedMethod method) { - return CiUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; - } - private static String methodName(RiResolvedMethod method, Invoke invoke) { if (Debug.isLogEnabled()) { if (invoke != null && invoke.stateAfter() != null) { RiMethod parent = invoke.stateAfter().method(); - return parent.name() + "@" + invoke.bci() + ": " + CiUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; + return parent.name() + "@" + invoke.bci() + ": " + methodNameAndCodeSize(method); } else { - return CiUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; + return methodNameAndCodeSize(method); } } else { return null; } } + private static String methodNameAndCodeSize(RiResolvedMethod method) { + return CiUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; + } + /** * Represents an opportunity for inlining at the given invoke, with the given weight and level. * The weight is the amortized weight of the additional code - so smaller is better. @@ -176,7 +175,7 @@ ValueNode receiver = invoke.callTarget().receiver(); ReadHubNode objectClass = graph.add(new ReadHubNode(receiver)); IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type)); - FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode)); + FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode, RiDeoptReason.TypeCheckedInliningViolated)); AnchorNode anchor = graph.add(new AnchorNode()); assert invoke.predecessor() != null; @@ -304,7 +303,7 @@ if (shouldFallbackToInvoke()) { unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false); } else { - unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + unknownTypeNode = graph.add(new DeoptimizeNode(RiDeoptAction.InvalidateReprofile, RiDeoptReason.TypeCheckedInliningViolated)); } // replace the invoke exception edge @@ -369,7 +368,7 @@ ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.callTarget().receiver())); graph.addBeforeFixed(invoke.node(), objectClassNode); - FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(RiDeoptAction.InvalidateReprofile, RiDeoptReason.TypeCheckedInliningViolated)); FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, unknownTypeNode); FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); @@ -541,19 +540,19 @@ * @param callback a callback that is used to determine the weight of a specific inlining * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke */ - public static InlineInfo getInlineInfo(Invoke invoke, int level, GraalRuntime runtime, CiAssumptions assumptions, InliningCallback callback) { - if (!checkInvokeConditions(invoke)) { - return null; - } + public static InlineInfo getInlineInfo(Invoke invoke, int level, GraalRuntime runtime, CiAssumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) { RiResolvedMethod parent = invoke.stateAfter().method(); MethodCallTargetNode callTarget = invoke.callTarget(); RiResolvedMethod targetMethod = callTarget.targetMethod(); - if (targetMethod == null) { return null; } + if (!checkInvokeConditions(invoke)) { + return null; + } + if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - if (checkTargetConditions(invoke, targetMethod)) { + if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) { double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke); return new ExactInlineInfo(invoke, weight, level, targetMethod); } @@ -563,7 +562,7 @@ RiResolvedType exact = callTarget.receiver().exactType(); assert exact.isSubtypeOf(targetMethod.holder()) : exact + " subtype of " + targetMethod.holder() + " for " + targetMethod; RiResolvedMethod resolved = exact.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, resolved)) { + if (checkTargetConditions(invoke, resolved, optimisticOpts)) { double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke); return new ExactInlineInfo(invoke, weight, level, resolved); } @@ -583,7 +582,7 @@ if (assumptions != null) { RiResolvedMethod concrete = holder.uniqueConcreteMethod(targetMethod); if (concrete != null) { - if (checkTargetConditions(invoke, concrete)) { + if (checkTargetConditions(invoke, concrete, optimisticOpts)) { double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); } @@ -592,6 +591,10 @@ } // type check based inlining + return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts); + } + + private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, RiResolvedMethod parent, RiResolvedMethod targetMethod, OptimisticOptimizations optimisticOpts) { RiProfilingInfo profilingInfo = parent.profilingInfo(); RiTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); if (typeProfile != null) { @@ -602,10 +605,10 @@ assert types.length == probabilities.length : "length must match"; double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); if (types.length == 1 && notRecordedTypeProbability == 0) { - if (GraalOptions.InlineMonomorphicCalls) { + if (optimisticOpts.inlineMonomorphicCalls()) { RiResolvedType type = types[0]; RiResolvedMethod concrete = type.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, concrete)) { + if (checkTargetConditions(invoke, concrete, optimisticOpts)) { double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); } @@ -618,7 +621,7 @@ } } else { invoke.setMegamorph(true); - if (GraalOptions.InlinePolymorphicCalls && notRecordedTypeProbability == 0 || GraalOptions.InlineMegamorphicCalls && notRecordedTypeProbability > 0) { + if (optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0 || optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) { // TODO (chaeubl) inlining of multiple methods should work differently // 1. check which methods can be inlined // 2. for those methods, use weight and probability to compute which of them should be inlined @@ -644,7 +647,7 @@ double totalWeight = 0; boolean canInline = true; for (RiResolvedMethod concrete: concreteMethods) { - if (!checkTargetConditions(invoke, concrete)) { + if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { canInline = false; break; } @@ -658,7 +661,7 @@ return null; } } else { - if (!GraalOptions.InlinePolymorphicCalls && notRecordedTypeProbability == 0) { + if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) { Debug.log("not inlining %s because GraalOptions.InlinePolymorphicCalls == false", methodName(targetMethod, invoke)); } else { Debug.log("not inlining %s because GraalOptions.InlineMegamorphicCalls == false", methodName(targetMethod, invoke)); @@ -699,7 +702,7 @@ return true; } - private static boolean checkTargetConditions(Invoke invoke, RiMethod method) { + private static boolean checkTargetConditions(Invoke invoke, RiMethod method, OptimisticOptimizations optimisticOpts) { if (method == null) { Debug.log("not inlining because method is not resolved"); return false; @@ -710,23 +713,28 @@ } RiResolvedMethod resolvedMethod = (RiResolvedMethod) method; if (Modifier.isNative(resolvedMethod.accessFlags())) { - Debug.log("not inlining %s because it is a native method", methodName(resolvedMethod)); + Debug.log("not inlining %s because it is a native method", methodName(resolvedMethod, invoke)); return false; } if (Modifier.isAbstract(resolvedMethod.accessFlags())) { - Debug.log("not inlining %s because it is an abstract method", methodName(resolvedMethod)); + Debug.log("not inlining %s because it is an abstract method", methodName(resolvedMethod, invoke)); return false; } if (!resolvedMethod.holder().isInitialized()) { - Debug.log("not inlining %s because of non-initialized class", methodName(resolvedMethod)); + Debug.log("not inlining %s because of non-initialized class", methodName(resolvedMethod, invoke)); return false; } if (!resolvedMethod.canBeInlined()) { - Debug.log("not inlining %s because it is marked non-inlinable", methodName(resolvedMethod)); + Debug.log("not inlining %s because it is marked non-inlinable", methodName(resolvedMethod, invoke)); return false; } if (computeRecursiveInliningLevel(invoke.stateAfter(), (RiResolvedMethod) method) > GraalOptions.MaximumRecursiveInlining) { - Debug.log("not inlining %s because it exceeds the maximum recursive inlining depth", methodName(resolvedMethod)); + Debug.log("not inlining %s because it exceeds the maximum recursive inlining depth", methodName(resolvedMethod, invoke)); + return false; + } + OptimisticOptimizations calleeOpts = new OptimisticOptimizations(resolvedMethod); + if (calleeOpts.lessOptimisticThan(optimisticOpts)) { + Debug.log("not inlining %s because callee uses less optimistic optimizations than caller", methodName(resolvedMethod, invoke)); return false; } @@ -812,7 +820,7 @@ } else { if (unwindNode != null) { UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptAction.InvalidateRecompile); + DeoptimizeNode deoptimizeNode = new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.NotCompiledExceptionHandler); unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode)); // move the deopt upwards if there is a monitor exit that tries to use the "after exception" frame state // (because there is no "after exception" frame state!) @@ -900,7 +908,7 @@ 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))))); + graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)), RiDeoptReason.ClassCastException))); } } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,9 +26,8 @@ import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.phases.PhasePlan.*; import com.oracle.graal.debug.*; -import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.criutils.*; @@ -39,21 +38,21 @@ private final Compiler compiler; private final PhasePlan plan; private final RiResolvedMethod method; + private final OptimisticOptimizations optimisticOpts; - public static CompilationTask create(Compiler compiler, PhasePlan plan, RiResolvedMethod method) { - return new CompilationTask(compiler, plan, method); + public static CompilationTask create(Compiler compiler, PhasePlan plan, OptimisticOptimizations optimisticOpts, RiResolvedMethod method) { + return new CompilationTask(compiler, plan, optimisticOpts, method); } - private CompilationTask(Compiler compiler, PhasePlan plan, RiResolvedMethod method) { + private CompilationTask(Compiler compiler, PhasePlan plan, OptimisticOptimizations optimisticOpts, RiResolvedMethod method) { this.compiler = compiler; this.plan = plan; this.method = method; + this.optimisticOpts = optimisticOpts; } public void run() { try { - GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime()); - plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); final boolean printCompilation = GraalOptions.PrintCompilation && !TTY.isSuppressed(); if (printCompilation) { TTY.println(String.format("Graal %-70s %-45s %-50s ...", method.holder().name(), method.name(), method.signature().asString())); @@ -66,7 +65,8 @@ @Override public CiTargetMethod call() throws Exception { - return compiler.getCompiler().compileMethod(method, -1, plan); + StructuredGraph graph = new StructuredGraph(method); + return compiler.getCompiler().compileMethod(method, graph, -1, plan, optimisticOpts); } }); } finally { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Wed Mar 21 13:57:30 2012 +0100 @@ -76,6 +76,7 @@ // methodData information public int methodDataOopDataOffset; + public int methodDataOopTrapHistoryOffset; public int dataLayoutHeaderSize; public int dataLayoutTagOffset; public int dataLayoutFlagsOffset; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Mar 21 13:57:30 2012 +0100 @@ -27,9 +27,6 @@ import java.util.*; import java.util.concurrent.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; @@ -40,7 +37,11 @@ import com.oracle.graal.hotspot.ri.*; import com.oracle.graal.hotspot.server.*; import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.java.*; import com.oracle.graal.snippets.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; /** * Exits from the HotSpot VM into Java code. @@ -93,10 +94,10 @@ @Override public void run() { VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime); - GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget(), PhasePlan.DEFAULT); - Snippets.install(runtime, runtime.getCompiler().getTarget(), new SystemSnippets(), PhasePlan.DEFAULT); - Snippets.install(runtime, runtime.getCompiler().getTarget(), new UnsafeSnippets(), PhasePlan.DEFAULT); - Snippets.install(runtime, runtime.getCompiler().getTarget(), new ArrayCopySnippets(), PhasePlan.DEFAULT); + GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget()); + Snippets.install(runtime, runtime.getCompiler().getTarget(), new SystemSnippets()); + Snippets.install(runtime, runtime.getCompiler().getTarget(), new UnsafeSnippets()); + Snippets.install(runtime, runtime.getCompiler().getTarget(), new ArrayCopySnippets()); } }); @@ -275,7 +276,8 @@ } } - Runnable task = CompilationTask.create(compiler, getDefaultPhasePlan(), method); + final OptimisticOptimizations optimisticOpts = new OptimisticOptimizations(method); + Runnable task = CompilationTask.create(compiler, createHotSpotSpecificPhasePlan(optimisticOpts), optimisticOpts, method); if (blocking) { task.run(); } else { @@ -378,8 +380,11 @@ return CiConstant.forObject(object); } - private PhasePlan getDefaultPhasePlan() { + + private PhasePlan createHotSpotSpecificPhasePlan(OptimisticOptimizations optimisticOpts) { PhasePlan phasePlan = new PhasePlan(); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime(), GraphBuilderConfiguration.getDefault(), optimisticOpts); + phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); if (GraalOptions.Intrinsify) { phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,10 +26,10 @@ import sun.misc.*; -import com.oracle.max.cri.ri.*; import com.oracle.graal.compiler.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.Compiler; +import com.oracle.max.cri.ri.*; public final class HotSpotMethodData extends CompilerObject { @@ -80,6 +80,11 @@ return position >= 0 && position < normalDataSize + extraDataSize; } + public int getDeoptimizationCount(RiDeoptReason reason) { + int reasonIndex = compiler.getRuntime().convertDeoptReason(reason); + return unsafe.getByte(hotspotMirror, (long) config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; + } + public HotSpotMethodDataAccessor getNormalData(int position) { if (position >= normalDataSize) { return null; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Wed Mar 21 13:57:30 2012 +0100 @@ -30,6 +30,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.criutils.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.java.bytecode.*; /** @@ -213,12 +214,13 @@ @Override public RiProfilingInfo profilingInfo() { - if (methodData == null) { + if (GraalOptions.UseProfilingInformation && methodData == null) { methodData = compiler.getVMEntries().RiMethod_methodData(this); } if (methodData == null) { - return new HotSpotNoProfilingInfo(compiler); + // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in case of a deoptimization. + return BaseProfilingInfo.get(RiExceptionSeen.FALSE); } else { return new HotSpotProfilingInfo(compiler, methodData); } @@ -279,6 +281,18 @@ } } } + + boolean firstDeoptReason = true; + for (RiDeoptReason reason: RiDeoptReason.values()) { + int count = profilingInfo.getDeoptimizationCount(reason); + if (count > 0) { + if (firstDeoptReason) { + TTY.println("Deopt History"); + firstDeoptReason = false; + } + TTY.println(" %s: %d", reason.name(), count); + } + } } @Override diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotNoProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotNoProfilingInfo.java Wed Mar 21 13:49:34 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.ri; - -import com.oracle.max.cri.ri.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.Compiler; - -/** - * Dummy profiling information in case that a method was not executed frequently enough so that - * no profiling information does exist yet. - */ -public final class HotSpotNoProfilingInfo extends CompilerObject implements RiProfilingInfo { - /** - * - */ - private static final long serialVersionUID = 4357945025049704109L; - // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in case of a deoptimization. - private static final HotSpotMethodDataAccessor noData = HotSpotMethodData.getNoDataAccessor(false); - - 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 RiExceptionSeen getExceptionSeen(int bci) { - return noData.getExceptionSeen(null, -1); - } - - @Override - public int getExecutionCount(int bci) { - return noData.getExecutionCount(null, -1); - } -} diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotProfilingInfo.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotProfilingInfo.java Wed Mar 21 13:57:30 2012 +0100 @@ -79,6 +79,11 @@ return dataAccessor.getExecutionCount(methodData, position); } + @Override + public int getDeoptimizationCount(RiDeoptReason reason) { + return methodData.getDeoptimizationCount(reason); + } + private void findBCI(int targetBCI, boolean searchExtraData) { assert targetBCI >= 0 : "invalid BCI"; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java Wed Mar 21 13:57:30 2012 +0100 @@ -229,7 +229,7 @@ int displacement = ((HotSpotField) field.field()).offset(); assert field.kind() != CiKind.Illegal; ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().kind(true), displacement, graph), field.stamp())); - memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)))); + memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), RiDeoptReason.NullCheckException)); graph.replaceFixedWithFixed(field, memoryRead); } else if (n instanceof StoreFieldNode) { StoreFieldNode storeField = (StoreFieldNode) n; @@ -238,7 +238,7 @@ } HotSpotField field = (HotSpotField) storeField.field(); WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(storeField.field(), storeField.field().kind(true), field.offset(), graph))); - memoryWrite.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)))); + memoryWrite.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), RiDeoptReason.NullCheckException)); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); @@ -277,7 +277,7 @@ } else { AnchorNode anchor = graph.add(new AnchorNode()); graph.addBeforeFixed(storeIndexed, anchor); - GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false))); + GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException); ReadNode arrayClass = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull())); arrayClass.setGuard(guard); graph.addBeforeFixed(storeIndexed, arrayClass); @@ -300,7 +300,7 @@ IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph); location.setIndexScalingEnabled(false); ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); - memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)))); + memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), RiDeoptReason.NullCheckException)); graph.replaceFixedWithFixed(load, memoryRead); } else if (n instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) n; @@ -318,7 +318,7 @@ ReadHubNode objectClassNode = (ReadHubNode) n; LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph); ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull())); - memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)))); + memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException)); graph.replaceFixed(objectClassNode, memoryRead); } } @@ -328,7 +328,7 @@ } private static GuardNode createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool) { - return (GuardNode) tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length()))); + return (GuardNode) tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())), RiDeoptReason.BoundsCheckException); } @Override @@ -424,8 +424,50 @@ @Override public CiTargetMethod compile(RiResolvedMethod method, StructuredGraph graph) { final PhasePlan plan = new PhasePlan(); - GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime()); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime(), GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); - return compiler.getCompiler().compileMethod(method, graph, -1, plan); + return compiler.getCompiler().compileMethod(method, graph, -1, plan, OptimisticOptimizations.ALL); + } + + @Override + public int encodeDeoptActionAndReason(RiDeoptAction action, RiDeoptReason reason) { + final int actionShift = 0; + final int reasonShift = 3; + + int actionValue = convertDeoptAction(action); + int reasonValue = convertDeoptReason(reason); + return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift))); + } + + @Override + public int convertDeoptAction(RiDeoptAction action) { + switch(action) { + case None: return 0; + case RecompileIfTooManyDeopts: return 1; + case InvalidateReprofile: return 2; + case InvalidateRecompile: return 3; + case InvalidateStopCompiling: return 4; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public int convertDeoptReason(RiDeoptReason reason) { + switch(reason) { + case None: return 0; + case NullCheckException: return 1; + case BoundsCheckException: return 2; + case ClassCastException: return 3; + case ArrayStoreException: return 4; + case UnreachedCode: return 5; + case TypeCheckedInliningViolated: return 6; + case OptimizedTypeCheckViolated: return 7; + case NotCompiledExceptionHandler: return 8; + case Unresolved: return 9; + case JavaSubroutineMismatch: return 10; + case ArithmeticException: return 11; + case RuntimeConstraint: return 12; + default: throw GraalInternalError.shouldNotReachHere(); + } } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,25 +22,29 @@ */ package com.oracle.graal.hotspot.ri; +import static com.oracle.graal.hotspot.ri.TemplateFlag.*; import static com.oracle.max.cri.ci.CiCallingConvention.Type.*; import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.graal.hotspot.ri.TemplateFlag.*; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiAddress.*; -import com.oracle.max.cri.ci.CiRegister.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.ri.RiType.*; -import com.oracle.max.cri.xir.*; -import com.oracle.max.cri.xir.CiXirAssembler.*; import com.oracle.graal.compiler.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.Compiler; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.CiAddress.Scale; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.ri.RiType.Representation; +import com.oracle.max.cri.xir.*; +import com.oracle.max.cri.xir.CiXirAssembler.XirConstant; +import com.oracle.max.cri.xir.CiXirAssembler.XirLabel; +import com.oracle.max.cri.xir.CiXirAssembler.XirMark; +import com.oracle.max.cri.xir.CiXirAssembler.XirOperand; +import com.oracle.max.cri.xir.CiXirAssembler.XirParameter; public class HotSpotXirGenerator implements RiXirGenerator { @@ -73,6 +77,7 @@ private final RiRegisterConfig registerConfig; private final Compiler compiler; + private CiXirAssembler globalAsm; public HotSpotXirGenerator(HotSpotVMConfig config, CiTarget target, RiRegisterConfig registerConfig, Compiler compiler) { @@ -710,10 +715,10 @@ asm.jneq(end, objHub, asm.o(null)); } } + + RiDeoptReason deoptReason = is(EXACT_HINTS, flags) ? RiDeoptReason.OptimizedTypeCheckViolated : RiDeoptReason.ClassCastException; XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - - asm.mov(scratch, wordConst(asm, 2)); - + asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.InvalidateReprofile, deoptReason))); asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.shouldNotReachHere(); @@ -891,7 +896,7 @@ if (is(BOUNDS_CHECK, flags)) { asm.bindOutOfLine(failBoundsCheck); XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - asm.mov(scratch, wordConst(asm, 0)); + asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.None, RiDeoptReason.BoundsCheckException))); asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.shouldNotReachHere(); } @@ -1081,7 +1086,7 @@ checkSubtype(asm, temp, valueHub, compHub); asm.jneq(store, temp, wordConst(asm, 0)); XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - asm.mov(scratch, wordConst(asm, 0)); + asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.None, RiDeoptReason.ClassCastException))); asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.jmp(store); } @@ -1162,7 +1167,7 @@ if (is(BOUNDS_CHECK, flags)) { asm.bindOutOfLine(failBoundsCheck); XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - asm.mov(scratch, wordConst(asm, 0)); + asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.None, RiDeoptReason.BoundsCheckException))); asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.shouldNotReachHere(); } @@ -1172,7 +1177,7 @@ checkSubtype(asm, temp, valueHub, compHub); asm.jneq(store, temp, wordConst(asm, 0)); XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10); - asm.mov(scratch, wordConst(asm, 0)); + asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.None, RiDeoptReason.ArrayStoreException))); asm.callRuntime(CiRuntimeCall.Deoptimize, null); asm.shouldNotReachHere(); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,14 +26,13 @@ import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.java.bytecode.*; import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; /** * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow @@ -183,35 +182,28 @@ * The blocks found in this method, in reverse postorder. */ public final List blocks; - public final RiResolvedMethod method; - - private final BytecodeStream stream; - - private final RiExceptionHandler[] exceptionHandlers; - - private Block[] blockMap; - public final BitSet canTrap; - public boolean hasJsrBytecodes; - public Block startBlock; - public final boolean useBranchPrediction; + private final OptimisticOptimizations optimisticOpts; + private final BytecodeStream stream; + private final RiExceptionHandler[] exceptionHandlers; + private Block[] blockMap; /** * Creates a new BlockMap instance from bytecode of the given method . * @param method the compiler interface method containing the code */ - public BciBlockMapping(RiResolvedMethod method, boolean useBranchPrediction) { + public BciBlockMapping(RiResolvedMethod method, OptimisticOptimizations optimisticOpts) { this.method = method; + this.optimisticOpts = optimisticOpts; exceptionHandlers = method.exceptionHandlers(); stream = new BytecodeStream(method.code()); this.blockMap = new Block[method.codeSize()]; this.canTrap = new BitSet(blockMap.length); this.blocks = new ArrayList<>(); - this.useBranchPrediction = useBranchPrediction; } public RiExceptionHandler[] exceptionHandlers() { @@ -383,8 +375,10 @@ case SALOAD: case PUTFIELD: case GETFIELD: { - if (GraalOptions.AllowExplicitExceptionChecks && profilingInfo.getExceptionSeen(bci) != RiExceptionSeen.FALSE) { - canTrap.set(bci); + if (GraalOptions.AllowExplicitExceptionChecks) { + if (!optimisticOpts.useExceptionProbability() || profilingInfo.getExceptionSeen(bci) != RiExceptionSeen.FALSE) { + canTrap.set(bci); + } } } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,9 +22,8 @@ */ package com.oracle.graal.java; +import com.oracle.graal.compiler.phases.*; import com.oracle.max.cri.ri.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; public class GraphBuilderConfiguration { @@ -32,22 +31,15 @@ Default, EagerForSnippets, Eager, } - private final boolean useBranchPrediction; private final ResolvePolicy resolving; private final PhasePlan plan; private RiResolvedType[] skippedExceptionTypes; - public GraphBuilderConfiguration(boolean useBranchPrediction, ResolvePolicy resolving, PhasePlan plan) { - this.useBranchPrediction = useBranchPrediction; + public GraphBuilderConfiguration(ResolvePolicy resolving, PhasePlan plan) { this.resolving = resolving; this.plan = plan; } - public boolean useBranchPrediction() { - return useBranchPrediction; - } - - public void setSkippedExceptionTypes(RiResolvedType[] skippedExceptionTypes) { this.skippedExceptionTypes = skippedExceptionTypes; } @@ -73,7 +65,7 @@ } public static GraphBuilderConfiguration getDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(GraalOptions.UseBranchPrediction, ResolvePolicy.Default, plan); + return new GraphBuilderConfiguration(ResolvePolicy.Default, plan); } public static GraphBuilderConfiguration getSnippetDefault() { @@ -81,6 +73,6 @@ } public static GraphBuilderConfiguration getSnippetDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(false, ResolvePolicy.EagerForSnippets, plan); + return new GraphBuilderConfiguration(ResolvePolicy.EagerForSnippets, plan); } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Mar 21 13:57:30 2012 +0100 @@ -28,11 +28,6 @@ import java.lang.reflect.*; import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.ri.RiType.Representation; -import com.oracle.max.criutils.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.util.*; @@ -42,13 +37,16 @@ import com.oracle.graal.java.BciBlockMapping.ExceptionBlock; import com.oracle.graal.java.bytecode.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.ri.RiType.Representation; +import com.oracle.max.criutils.*; /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. @@ -91,7 +89,8 @@ public static final Map cachedGraphs = new WeakHashMap<>(); - private final GraphBuilderConfiguration config; + private final GraphBuilderConfiguration graphBuilderConfig; + private final OptimisticOptimizations optimisticOpts; /** @@ -106,13 +105,9 @@ } } - - public GraphBuilderPhase(RiRuntime runtime) { - this(runtime, GraphBuilderConfiguration.getDefault()); - } - - public GraphBuilderPhase(RiRuntime runtime, GraphBuilderConfiguration config) { - this.config = config; + public GraphBuilderPhase(RiRuntime runtime, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; this.runtime = runtime; this.log = GraalOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; } @@ -129,7 +124,7 @@ methodSynchronizedObject = null; exceptionHandlers = null; this.currentGraph = graph; - this.frameState = new FrameStateBuilder(method, graph, config.eagerResolving()); + this.frameState = new FrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving()); build(); } @@ -139,7 +134,7 @@ } private BciBlockMapping createBlockMap() { - BciBlockMapping map = new BciBlockMapping(method, config.useBranchPrediction()); + BciBlockMapping map = new BciBlockMapping(method, optimisticOpts); map.build(); Debug.dump(map, CiUtil.format("After block building %f %R %H.%n(%P)", method)); @@ -255,7 +250,7 @@ private BeginNode handleException(ValueNode exceptionObject, int bci) { assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci"; - if (GraalOptions.UseExceptionProbability) { + if (optimisticOpts.useExceptionProbability()) { // be conservative if information was not recorded (could result in endless recompiles otherwise) if (bci != FrameState.BEFORE_BCI && exceptionObject == null && profilingInfo.getExceptionSeen(bci) == RiExceptionSeen.FALSE) { return null; @@ -328,7 +323,7 @@ if (riType instanceof RiResolvedType) { frameState.push(CiKind.Object, append(ConstantNode.forCiConstant(((RiResolvedType) riType).getEncoding(Representation.JavaClass), runtime, currentGraph))); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.push(CiKind.Object, append(ConstantNode.forObject(null, runtime, currentGraph))); } } else if (con instanceof CiConstant) { @@ -587,7 +582,7 @@ private void genThrow(int bci) { ValueNode exception = frameState.apop(); - FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false)))); + FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false)), RiDeoptReason.NullCheckException)); append(node); append(handleException(exception, bci)); } @@ -595,39 +590,39 @@ private RiType lookupType(int cpi, int bytecode) { eagerResolvingForSnippets(cpi, bytecode); RiType result = constantPool.lookupType(cpi, bytecode); - assert !config.eagerResolvingForSnippets() || result instanceof RiResolvedType; + assert !graphBuilderConfig.eagerResolvingForSnippets() || result instanceof RiResolvedType; return result; } private RiMethod lookupMethod(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); RiMethod result = constantPool.lookupMethod(cpi, opcode); - assert !config.eagerResolvingForSnippets() || ((result instanceof RiResolvedMethod) && ((RiResolvedMethod) result).holder().isInitialized()); + assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof RiResolvedMethod) && ((RiResolvedMethod) result).holder().isInitialized()); return result; } private RiField lookupField(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); RiField result = constantPool.lookupField(cpi, opcode); - assert !config.eagerResolvingForSnippets() || (result instanceof RiResolvedField && ((RiResolvedField) result).holder().isInitialized()); + assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof RiResolvedField && ((RiResolvedField) result).holder().isInitialized()); return result; } private Object lookupConstant(int cpi, int opcode) { eagerResolving(cpi, opcode); Object result = constantPool.lookupConstant(cpi); - assert !config.eagerResolving() || !(result instanceof RiType) || (result instanceof RiResolvedType); + assert !graphBuilderConfig.eagerResolving() || !(result instanceof RiType) || (result instanceof RiResolvedType); return result; } private void eagerResolving(int cpi, int bytecode) { - if (config.eagerResolving()) { + if (graphBuilderConfig.eagerResolving()) { constantPool.loadReferencedType(cpi, bytecode); } } private void eagerResolvingForSnippets(int cpi, int bytecode) { - if (config.eagerResolvingForSnippets()) { + if (graphBuilderConfig.eagerResolvingForSnippets()) { constantPool.loadReferencedType(cpi, bytecode); } } @@ -635,7 +630,7 @@ private static final RiResolvedType[] EMPTY_TYPE_ARRAY = new RiResolvedType[0]; private RiResolvedType[] getTypeCheckHints(RiResolvedType type, int maxHints) { - if (!GraalOptions.UseTypeCheckHints || Util.isFinalClass(type)) { + if (!optimisticOpts.useUseTypeCheckHints() || Util.isFinalClass(type)) { return new RiResolvedType[] {type}; } else { RiResolvedType uniqueSubtype = type.uniqueConcreteSubtype(); @@ -679,7 +674,7 @@ frameState.apush(checkCast); } else { ValueNode object = frameState.apop(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph)))))); + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph))), RiDeoptReason.Unresolved))); frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } } @@ -697,7 +692,7 @@ frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph))); } else { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); - DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)); + DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved)); IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(object, true)), trueSucc, deopt, 1)); append(ifNode); lastInstr = trueSucc; @@ -711,7 +706,7 @@ NewInstanceNode n = currentGraph.add(new NewInstanceNode((RiResolvedType) type)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } } @@ -752,7 +747,7 @@ NewArrayNode n = currentGraph.add(new NewObjectArrayNode((RiResolvedType) type, length)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } @@ -769,7 +764,7 @@ FixedWithNextNode n = currentGraph.add(new NewMultiArrayNode((RiResolvedType) type, dims)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); } } @@ -783,7 +778,7 @@ LoadFieldNode load = currentGraph.add(new LoadFieldNode(receiver, (RiResolvedField) field)); appendOptimizedLoadField(kind, load); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.push(kind.stackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); } } @@ -884,7 +879,7 @@ StoreFieldNode store = currentGraph.add(new StoreFieldNode(receiver, (RiResolvedField) field, value)); appendOptimizedStoreField(store); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); } } @@ -926,7 +921,7 @@ if (initialized) { return appendConstant(((RiResolvedType) holder).getEncoding(representation)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); return null; } } @@ -987,7 +982,7 @@ } private void genInvokeDeopt(RiMethod unresolvedTarget, boolean withReceiver) { - append(currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + append(currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved))); frameState.popArguments(unresolvedTarget.signature().argumentSlots(withReceiver), unresolvedTarget.signature().argumentCount(withReceiver)); CiKind kind = unresolvedTarget.signature().returnKind(false); if (kind != CiKind.Void) { @@ -1024,7 +1019,7 @@ private void appendInvoke(InvokeKind invokeKind, RiResolvedMethod targetMethod, ValueNode[] args) { CiKind resultType = targetMethod.signature().returnKind(false); if (GraalOptions.DeoptALot) { - DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptAction.None)); + DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(RiDeoptAction.None, RiDeoptReason.RuntimeConstraint)); deoptimize.setMessage("invoke " + targetMethod.name()); append(deoptimize); frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph)); @@ -1113,7 +1108,7 @@ ValueNode local = frameState.loadLocal(localIndex); JsrScope scope = currentBlock.jsrScope; int retAddress = scope.nextReturnAddress(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph)))))); + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph))), RiDeoptReason.JavaSubroutineMismatch))); if (!successor.jsrScope.equals(scope.pop())) { throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); } @@ -1198,8 +1193,8 @@ private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1; - if (probability == 0 && config.useBranchPrediction()) { - return currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile)); + if (probability == 0 && optimisticOpts.removeNeverExecutedCode()) { + return currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateReprofile, RiDeoptReason.UnreachedCode)); } else { return createTarget(block, stateAfter); } @@ -1403,13 +1398,13 @@ assert frameState.stackSize() == 1 : frameState; RiType catchType = block.handler.catchType(); - if (config.eagerResolving()) { + if (graphBuilderConfig.eagerResolving()) { catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF); } boolean initialized = (catchType instanceof RiResolvedType); - if (initialized && config.getSkippedExceptionTypes() != null) { + if (initialized && graphBuilderConfig.getSkippedExceptionTypes() != null) { RiResolvedType resolvedCatchType = (RiResolvedType) catchType; - for (RiResolvedType skippedType : config.getSkippedExceptionTypes()) { + for (RiResolvedType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { initialized &= !resolvedCatchType.isSubtypeOf(skippedType); if (!initialized) { break; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java Wed Mar 21 13:57:30 2012 +0100 @@ -23,10 +23,11 @@ package com.oracle.graal.cri; import com.oracle.graal.graph.*; +import com.oracle.max.cri.ri.*; public interface CiLoweringTool { GraalRuntime getRuntime(); Node getGuardAnchor(); - Node createGuard(Node condition); + Node createGuard(Node condition, RiDeoptReason deoptReason); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Wed Mar 21 13:57:30 2012 +0100 @@ -25,28 +25,19 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ri.*; @NodeInfo(shortName = "Deopt") public class DeoptimizeNode extends FixedNode implements Node.IterableNodeType, LIRLowerable { - public static enum DeoptAction { - None, // just interpret, do not invalidate nmethod - Recompile, // recompile the nmethod; need not invalidate - InvalidateReprofile, // invalidate the nmethod, reset IC, maybe recompile - InvalidateRecompile, // invalidate the nmethod, recompile (probably) - InvalidateStopCompiling, // invalidate the nmethod and do not compile - } + @Data private String message; + @Data private final RiDeoptAction action; + @Data private final RiDeoptReason reason; - @Data private String message; - @Data private final DeoptAction action; - - public DeoptimizeNode() { - this(DeoptAction.InvalidateReprofile); - } - - public DeoptimizeNode(DeoptAction action) { + public DeoptimizeNode(RiDeoptAction action, RiDeoptReason reason) { super(StampFactory.illegal()); this.action = action; + this.reason = reason; } public void setMessage(String message) { @@ -57,13 +48,17 @@ return message; } - public DeoptAction action() { + public RiDeoptAction action() { return action; } + public RiDeoptReason reason() { + return reason; + } + @Override public void generate(LIRGeneratorTool gen) { - gen.emitDeoptimizeOn(null, action, message); + gen.emitDeoptimizeOn(null, action, reason, message); } @NodeIntrinsic diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Mar 21 13:57:30 2012 +0100 @@ -24,23 +24,25 @@ import com.oracle.graal.cri.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ri.*; public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType { @Input private final NodeInputList conditions; + @Data private final RiDeoptReason deoptReason; - public FixedGuardNode(BooleanNode condition) { + public FixedGuardNode(BooleanNode condition, RiDeoptReason deoptReason) { super(StampFactory.illegal()); this.conditions = new NodeInputList<>(this, new BooleanNode[] {condition}); + this.deoptReason = deoptReason; } @Override public void generate(LIRGeneratorTool gen) { for (BooleanNode condition : conditions()) { - gen.emitGuardCheck(condition); + gen.emitGuardCheck(condition, deoptReason); } } @@ -64,7 +66,7 @@ if (next != null) { tool.deleteBranch(next); } - setNext(graph().add(new DeoptimizeNode(DeoptAction.InvalidateRecompile))); + setNext(graph().add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, deoptReason))); return; } } @@ -78,7 +80,7 @@ public void lower(CiLoweringTool tool) { AnchorNode newAnchor = graph().add(new AnchorNode()); for (BooleanNode b : conditions) { - newAnchor.addGuard((GuardNode) tool.createGuard(b)); + newAnchor.addGuard((GuardNode) tool.createGuard(b, deoptReason)); } ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Wed Mar 21 13:57:30 2012 +0100 @@ -27,11 +27,13 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.types.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ri.*; public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType { @Input private BooleanNode condition; @Input(notDataflow = true) private FixedNode anchor; + @Data private RiDeoptReason reason; public FixedNode anchor() { return anchor; @@ -54,15 +56,20 @@ condition = x; } - public GuardNode(BooleanNode condition, FixedNode anchor) { + public RiDeoptReason reason() { + return reason; + } + + public GuardNode(BooleanNode condition, FixedNode anchor, RiDeoptReason reason) { super(StampFactory.illegal()); this.condition = condition; this.anchor = anchor; + this.reason = reason; } @Override public void generate(LIRGeneratorTool gen) { - gen.emitGuardCheck(condition()); + gen.emitGuardCheck(condition(), reason()); } @Override diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java Wed Mar 21 13:57:30 2012 +0100 @@ -27,6 +27,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ri.*; public class SafeReadNode extends SafeAccessNode implements Lowerable { @@ -39,7 +40,7 @@ @Override public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) graph(); - GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false))); + GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException); ReadNode read = graph.add(new ReadNode(object(), location(), stamp())); read.setGuard(guard); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,12 +22,13 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.max.cri.ci.*; import com.oracle.graal.cri.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.max.cri.ci.*; import com.oracle.graal.nodes.type.*; +import com.oracle.max.cri.ri.*; public class SafeWriteNode extends SafeAccessNode implements Lowerable{ @@ -46,7 +47,7 @@ @Override public void lower(CiLoweringTool tool) { StructuredGraph graph = (StructuredGraph) graph(); - GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false))); + GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException); WriteNode write = graph.add(new WriteNode(object(), value(), location())); write.setGuard(guard); graph.replaceFixedWithFixed(this, write); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,12 +22,12 @@ */ package com.oracle.graal.nodes.spi; -import com.oracle.max.cri.ci.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; public abstract class LIRGeneratorTool { public abstract CiTarget target(); @@ -79,12 +79,12 @@ public abstract CiValue emitConvert(ConvertNode.Op opcode, CiValue inputVal); public abstract void emitMembar(int barriers); - public abstract void emitDeoptimizeOn(Condition of, DeoptAction action, Object deoptInfo); + public abstract void emitDeoptimizeOn(Condition of, RiDeoptAction action, RiDeoptReason reason, Object deoptInfo); public abstract CiValue emitCallToRuntime(CiRuntimeCall runtimeCall, boolean canTrap, CiValue... args); public abstract void emitIf(IfNode i); public abstract void emitConditional(ConditionalNode i); - public abstract void emitGuardCheck(BooleanNode comp); + public abstract void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason); public abstract void emitLookupSwitch(LookupSwitchNode i); public abstract void emitTableSwitch(TableSwitchNode i); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,21 +22,20 @@ */ package com.oracle.graal.snippets; +import com.oracle.graal.compiler.*; +import com.oracle.graal.cri.*; import com.oracle.max.cri.ci.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.cri.*; /** * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. */ public class GraalIntrinsics { - public static void installIntrinsics(GraalRuntime runtime, CiTarget target, PhasePlan plan) { + public static void installIntrinsics(GraalRuntime runtime, CiTarget target) { if (GraalOptions.Intrinsify) { - Snippets.install(runtime, target, new MathSnippetsX86(), plan); - Snippets.install(runtime, target, new DoubleSnippets(), plan); - Snippets.install(runtime, target, new FloatSnippets(), plan); - Snippets.install(runtime, target, new NodeClassSnippets(), plan); + Snippets.install(runtime, target, new MathSnippetsX86()); + Snippets.install(runtime, target, new DoubleSnippets()); + Snippets.install(runtime, target, new FloatSnippets()); + Snippets.install(runtime, target, new NodeClassSnippets()); } } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java Wed Mar 21 13:57:30 2012 +0100 @@ -43,17 +43,17 @@ */ public class Snippets { - public static void install(GraalRuntime runtime, CiTarget target, SnippetsInterface obj, PhasePlan plan) { + public static void install(GraalRuntime runtime, CiTarget target, SnippetsInterface obj) { Class clazz = obj.getClass(); BoxingMethodPool pool = new BoxingMethodPool(runtime); if (clazz.isAnnotationPresent(ClassSubstitution.class)) { - installSubstitution(runtime, target, plan, clazz, pool, clazz.getAnnotation(ClassSubstitution.class).value()); + installSubstitution(runtime, target, clazz, pool, clazz.getAnnotation(ClassSubstitution.class).value()); } else { - installSnippets(runtime, target, plan, clazz, pool); + installSnippets(runtime, target, clazz, pool); } } - private static void installSnippets(GraalRuntime runtime, CiTarget target, PhasePlan plan, Class< ? extends SnippetsInterface> clazz, + private static void installSnippets(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) { for (Method snippet : clazz.getDeclaredMethods()) { int modifiers = snippet.getModifiers(); @@ -62,12 +62,12 @@ } RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet); if (snippetRiMethod.compilerStorage().get(Graph.class) == null) { - buildSnippetGraph(snippetRiMethod, runtime, target, pool, plan); + buildSnippetGraph(snippetRiMethod, runtime, target, pool); } } } - private static void installSubstitution(GraalRuntime runtime, CiTarget target, PhasePlan plan, Class< ? extends SnippetsInterface> clazz, + private static void installSubstitution(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool, Class original) throws GraalInternalError { for (Method snippet : clazz.getDeclaredMethods()) { try { @@ -80,7 +80,7 @@ throw new RuntimeException("Snippet must not be abstract or native"); } RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet); - StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool, plan); + StructuredGraph graph = buildSnippetGraph(snippetRiMethod, runtime, target, pool); runtime.getRiMethod(method).compilerStorage().put(Graph.class, graph); } catch (NoSuchMethodException e) { throw new RuntimeException("Could not resolve method to substitute with: " + snippet.getName(), e); @@ -88,13 +88,13 @@ } } - private static StructuredGraph buildSnippetGraph(final RiResolvedMethod snippetRiMethod, final GraalRuntime runtime, final CiTarget target, final BoxingMethodPool pool, final PhasePlan plan) { + private static StructuredGraph buildSnippetGraph(final RiResolvedMethod snippetRiMethod, final GraalRuntime runtime, final CiTarget target, final BoxingMethodPool pool) { return Debug.scope("BuildSnippetGraph", snippetRiMethod, new Callable() { @Override public StructuredGraph call() throws Exception { GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); StructuredGraph graph = new StructuredGraph(snippetRiMethod); graphBuilder.apply(graph); @@ -109,7 +109,7 @@ if (holder.isSubtypeOf(runtime.getType(SnippetsInterface.class))) { StructuredGraph targetGraph = (StructuredGraph) targetMethod.compilerStorage().get(Graph.class); if (targetGraph == null) { - targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool, plan); + targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool); } InliningUtil.inline(invoke, targetGraph, true); if (GraalOptions.OptCanonicalizer) { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -28,6 +28,7 @@ import org.junit.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; import com.oracle.graal.debug.*; @@ -123,7 +124,8 @@ for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); } - new InliningPhase(null, runtime(), hints, null, phasePlan).apply(graph); + + new InliningPhase(null, runtime(), hints, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); Debug.dump(graph, "Graph"); new BoxingEliminationPhase().apply(graph); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,13 +26,14 @@ import org.junit.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.cri.ri.RiCompiledMethod.MethodInvalidatedException; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.graph.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.cri.ri.RiCompiledMethod.MethodInvalidatedException; /** * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. Then @@ -78,7 +79,7 @@ Method method = CompilableObjectImpl.class.getDeclaredMethod("executeHelper", ObjectCompiler.class, String.class); RiResolvedMethod riMethod = runtime.getRiMethod(method); StructuredGraph graph = new StructuredGraph(riMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault()).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); new CanonicalizerPhase(null, runtime, null).apply(graph); new DeadCodeEliminationPhase().apply(graph); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -22,15 +22,16 @@ */ package com.oracle.graal.compiler.tests; -import junit.framework.*; +import junit.framework.Assert; import org.junit.Test; -import com.oracle.max.cri.ci.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.max.cri.ci.*; /** * In these test cases the probability of all invokes is set to a high value, such that an InliningPhase should inline them all. @@ -121,10 +122,10 @@ n.node().setProbability(100000); } - new InliningPhase(null, runtime(), null, null, getDefaultPhasePlan()).apply(graph); + new InliningPhase(null, runtime(), null, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); Debug.dump(graph, "Graph"); - new EscapeAnalysisPhase(null, runtime(), null, getDefaultPhasePlan()).apply(graph); + new EscapeAnalysisPhase(null, runtime(), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); int retCount = 0; for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -50,7 +50,7 @@ } block = block.getDominator(); } - Assert.assertTrue(block == aBlock); + Assert.assertSame(block, aBlock); } } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -24,15 +24,16 @@ import java.lang.reflect.*; -import junit.framework.Assert; +import junit.framework.*; -import com.oracle.max.cri.ri.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.phases.PhasePlan.*; +import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; import com.oracle.graal.cri.*; import com.oracle.graal.debug.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.max.cri.ri.*; /** * Base class for Graal compiler unit tests. These are white box tests @@ -110,7 +111,7 @@ protected StructuredGraph parse(Method m) { RiResolvedMethod riMethod = runtime.getRiMethod(m); StructuredGraph graph = new StructuredGraph(riMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault()).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph); return graph; } @@ -120,13 +121,13 @@ protected StructuredGraph parseProfiled(Method m) { RiResolvedMethod riMethod = runtime.getRiMethod(m); StructuredGraph graph = new StructuredGraph(riMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault()).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); return graph; } protected PhasePlan getDefaultPhasePlan() { PhasePlan plan = new PhasePlan(); - plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault())); + plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL)); return plan; } } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,6 +26,7 @@ import org.junit.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; import com.oracle.graal.debug.*; @@ -84,7 +85,7 @@ for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); } - new InliningPhase(null, runtime(), hints, null, phasePlan).apply(graph); + new InliningPhase(null, runtime(), hints, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); new PhiStampPhase().apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -26,6 +26,7 @@ import org.junit.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.nodes.*; @@ -62,7 +63,7 @@ for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); } - new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan()).apply(graph); + new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); new DeadCodeEliminationPhase().apply(graph); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -28,6 +28,7 @@ import org.junit.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -81,7 +82,7 @@ for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); } - new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan()).apply(graph); + new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); new DeadCodeEliminationPhase().apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java Wed Mar 21 13:57:30 2012 +0100 @@ -31,6 +31,7 @@ import org.junit.Assert; import org.junit.Test; +import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; @@ -93,7 +94,7 @@ for (Invoke invoke : graph.getInvokes()) { hints.add(invoke); } - new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan()).apply(graph); + new InliningPhase(null, runtime(), hints, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new CanonicalizerPhase(null, runtime(), null).apply(graph); new DeadCodeEliminationPhase().apply(graph); return graph; diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiDeoptAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiDeoptAction.java Wed Mar 21 13:57:30 2012 +0100 @@ -0,0 +1,32 @@ +/* + * 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; + + +public enum RiDeoptAction { + None, // just interpret, do not invalidate nmethod + RecompileIfTooManyDeopts, // recompile the nmethod; need not invalidate + InvalidateReprofile, // invalidate the nmethod, reset IC, maybe recompile + InvalidateRecompile, // invalidate the nmethod, recompile (probably) + InvalidateStopCompiling; // invalidate the nmethod and do not compile +} diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiDeoptReason.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiDeoptReason.java Wed Mar 21 13:57:30 2012 +0100 @@ -0,0 +1,40 @@ +/* + * 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; + + +public enum RiDeoptReason { + None, + NullCheckException, + BoundsCheckException, + ClassCastException, + ArrayStoreException, + UnreachedCode, + TypeCheckedInliningViolated, + OptimizedTypeCheckViolated, + NotCompiledExceptionHandler, + Unresolved, + JavaSubroutineMismatch, + ArithmeticException, + RuntimeConstraint; +} diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java Wed Mar 21 13:57:30 2012 +0100 @@ -64,4 +64,12 @@ * @return the estimated execution count or -1 if not available. */ int getExecutionCount(int bci); + + /** + * Returns how frequently a method was deoptimized for the given deoptimization reason. This only indicates how + * often the method did fall back to the interpreter for the execution and does not indicate how often it was recompiled. + * @param reason the reason for which the number of deoptimizations should be queried + * @return the number of times the compiled method deoptimized for the given reason. + */ + int getDeoptimizationCount(RiDeoptReason reason); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java Wed Mar 21 13:49:34 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java Wed Mar 21 13:57:30 2012 +0100 @@ -195,4 +195,22 @@ * @return a reference to the compiled and ready-to-run code */ RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code); + + /** + * Encodes a deoptimization action and a deoptimization reason in an integer value. + * @return the encoded value as an integer + */ + int encodeDeoptActionAndReason(RiDeoptAction action, RiDeoptReason reason); + + /** + * Converts a RiDeoptReason into an integer value. + * @return An integer value representing the given RiDeoptReason. + */ + int convertDeoptReason(RiDeoptReason reason); + + /** + * Converts a RiDeoptAction into an integer value. + * @return An integer value representing the given RiDeoptAction. + */ + int convertDeoptAction(RiDeoptAction action); } diff -r 09f66048738e -r 4d8ebb0fc484 graal/com.oracle.max.criutils/src/com/oracle/max/criutils/BaseProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/BaseProfilingInfo.java Wed Mar 21 13:57:30 2012 +0100 @@ -0,0 +1,78 @@ +/* + * 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.criutils; + +import com.oracle.max.cri.ri.*; + + +/** + * Dummy profiling information in case that a method was not executed frequently enough so that + * no profiling information does exist yet, or in case that the profiling information should not be used. + */ +public final class BaseProfilingInfo implements RiProfilingInfo { + private static final RiProfilingInfo[] NO_PROFILING_INFO = new RiProfilingInfo[] { + new BaseProfilingInfo(RiExceptionSeen.TRUE), + new BaseProfilingInfo(RiExceptionSeen.FALSE), + new BaseProfilingInfo(RiExceptionSeen.NOT_SUPPORTED) + }; + + private final RiExceptionSeen exceptionSeen; + + BaseProfilingInfo(RiExceptionSeen exceptionSeen) { + this.exceptionSeen = exceptionSeen; + } + + @Override + public RiTypeProfile getTypeProfile(int bci) { + return null; + } + + @Override + public double getBranchTakenProbability(int bci) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(int bci) { + return null; + } + + @Override + public RiExceptionSeen getExceptionSeen(int bci) { + return exceptionSeen; + } + + @Override + public int getExecutionCount(int bci) { + return -1; + } + + public static RiProfilingInfo get(RiExceptionSeen exceptionSeen) { + return NO_PROFILING_INFO[exceptionSeen.ordinal()]; + } + + @Override + public int getDeoptimizationCount(RiDeoptReason reason) { + return 0; + } +} diff -r 09f66048738e -r 4d8ebb0fc484 mx/commands.py --- a/mx/commands.py Wed Mar 21 13:49:34 2012 +0100 +++ b/mx/commands.py Wed Mar 21 13:57:30 2012 +0100 @@ -384,6 +384,12 @@ log.close() return ret +def jdkhome(args, vm=None): + """prints the JDK directory selected for the 'vm' command""" + + build = _vmbuild if _vmSourcesAvailable else 'product' + print join(_graal_home, 'jdk' + mx.java().version, build) + def build(args, vm=None): """build the VM binary @@ -894,6 +900,7 @@ 'hsdis': [hsdis, '[att]'], 'igv' : [igv, ''], 'intro': [intro, ''], + 'jdkhome': [jdkhome, ''], 'dacapo': [dacapo, '[[n] benchmark] [VM options|@DaCapo options]'], 'scaladacapo': [scaladacapo, '[[n] benchmark] [VM options|@Scala DaCapo options]'], 'specjvm2008': [specjvm2008, '[VM options|@specjvm2008 options]'], diff -r 09f66048738e -r 4d8ebb0fc484 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -97,12 +97,23 @@ if (oop_result2->is_valid()) { movptr(Address(thread, JavaThread::vm_result_2_offset()), NULL_WORD); } +#ifdef GRAAL // (thomaswue) Deoptimize in case of an exception. restore_live_registers(this, false); movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); leave(); - movl(rscratch1, 2); // InvalidateRecompile + movl(rscratch1, Deoptimization::make_trap_request(Deoptimization::Reason_constraint, Deoptimization::Action_reinterpret)); jump(RuntimeAddress(SharedRuntime::deopt_blob()->uncommon_trap())); +#else + if (frame_size() == no_frame_size) { + leave(); + jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + } else if (_stub_id == Runtime1::forward_exception_id) { + should_not_reach_here(); + } else { + jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); + } +#endif bind(L); } // get oop results if there are any and reset the values in the thread diff -r 09f66048738e -r 4d8ebb0fc484 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -3015,9 +3015,9 @@ #ifdef GRAAL __ jmp(cont); - int jmp_uncommon_trap_offset = __ pc() - start; + int implicit_exception_uncommon_trap_offset = __ pc() - start; __ pushptr(Address(r15_thread, in_bytes(JavaThread::ScratchA_offset()))); - __ movptr(rscratch1, 2); // InvalidateRecompile + __ movptr(rscratch1, Address(r15_thread, in_bytes(JavaThread::ScratchB_offset()))); int uncommon_trap_offset = __ pc() - start; @@ -3028,8 +3028,7 @@ assert(r10 == rscratch1, "scratch register should be r10"); __ movl(c_rarg1, Address(rsp, RegisterSaver::r10_offset_in_bytes())); - __ orq(c_rarg1, ~(int32_t)Deoptimization::make_trap_request(Deoptimization::Reason_unreached, Deoptimization::Action_none)); - __ notq(c_rarg1); + __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); __ mov(c_rarg0, r15_thread); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); @@ -3039,7 +3038,7 @@ Label after_fetch_unroll_info_call; __ jmp(after_fetch_unroll_info_call); -#endif +#endif // GRAAL __ bind(cont); @@ -3245,7 +3244,7 @@ _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); #ifdef GRAAL _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); - _deopt_blob->set_jmp_uncommon_trap_offset(jmp_uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); #endif } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/c1/c1_Runtime1.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -169,7 +169,7 @@ RegisterMap reg_map(thread, false); frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); assert(caller_is_deopted(), "Must be deoptimized"); } } @@ -434,7 +434,7 @@ if (osr_nm != NULL) { RegisterMap map(thread, false); frame fr = thread->last_frame().sender(&map); - Deoptimization::deoptimize_frame(thread, fr.id()); + Deoptimization::deoptimize_frame(thread, fr.id(), Deoptimization::Reason_constraint); } JRT_BLOCK_END return NULL; @@ -505,7 +505,7 @@ // We don't really want to deoptimize the nmethod itself since we // can actually continue in the exception handler ourselves but I // don't see an easy way to have the desired effect. - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); assert(caller_is_deopted(), "Must be deoptimized"); return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); @@ -763,7 +763,7 @@ assert(CodeCache::find_nmethod(caller_frame.pc()) != NULL, "sanity"); // Deoptimize the caller frame. - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); // Return to the now deoptimized frame. JRT_END @@ -975,7 +975,7 @@ nm->make_not_entrant(); } - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); // Return to the now deoptimized frame. } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/code/codeBlob.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -407,7 +407,7 @@ // (thomaswue) Offset when graal calls uncommon_trap. int _uncommon_trap_offset; - int _jmp_uncommon_trap_offset; + int _implicit_exception_uncommon_trap_offset; // Creation support @@ -469,11 +469,11 @@ assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); } address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } - void set_jmp_uncommon_trap_offset(int offset) { - _jmp_uncommon_trap_offset = offset; - assert(contains(code_begin() + _jmp_uncommon_trap_offset), "must be PC inside codeblob"); + void set_implicit_exception_uncommon_trap_offset(int offset) { + _implicit_exception_uncommon_trap_offset = offset; + assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); } - address jmp_uncommon_trap() const { return code_begin() + _jmp_uncommon_trap_offset; } + address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } }; diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -179,6 +179,7 @@ oop type = CiVirtualObject::type(value); int id = CiVirtualObject::id(value); klassOop klass = java_lang_Class::as_klassOop(HotSpotTypeResolved::javaMirror(type)); + bool isLongArray = klass == Universe::longArrayKlassObj(); for (jint i = 0; i < objects->length(); i++) { ObjectValue* obj = (ObjectValue*) objects->at(i); @@ -198,6 +199,17 @@ ScopeValue* cur_second = NULL; ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], total_frame_size, objects, cur_second); + if (isLongArray && cur_second == NULL) { + // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. + // add an int 0 constant +#ifdef BIG_ENDIAN + cur_second = value; + value = new ConstantIntValue(0); +#else + cur_second = new ConstantIntValue(0); +#endif + } + if (cur_second != NULL) { sv->field_values()->append(cur_second); } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/graal/graalCompiler.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -276,7 +276,7 @@ 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, !CompilerOracle::should_not_inline(method)); + HotSpotMethodResolved::set_canBeInlined(obj, !method->is_not_compilable() && !CompilerOracle::should_not_inline(method)); method->set_graal_mirror(obj()); return obj; diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -775,6 +775,7 @@ set_int(env, config, "classMirrorOffset", in_bytes(Klass::java_mirror_offset())); set_int(env, config, "methodDataOopDataOffset", in_bytes(methodDataOopDesc::data_offset())); + set_int(env, config, "methodDataOopTrapHistoryOffset", in_bytes(methodDataOopDesc::trap_history_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())); diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/oops/methodDataOop.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -1206,7 +1206,11 @@ // Whole-method sticky bits and flags public: enum { +#ifdef GRAAL + _trap_hist_limit = 13, // decoupled from Deoptimization::Reason_LIMIT +#else _trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT +#endif _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -1481,17 +1485,13 @@ uint inc_trap_count(int reason) { // Count another trap, anywhere in this method. assert(reason >= 0, "must be single trap"); - if ((uint)reason < _trap_hist_limit) { - uint cnt1 = 1 + _trap_hist._array[reason]; - if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... - _trap_hist._array[reason] = cnt1; - return cnt1; - } else { - return _trap_hist_mask + (++_nof_overflow_traps); - } + assert((uint)reason < _trap_hist_limit, "oob"); + uint cnt1 = 1 + _trap_hist._array[reason]; + if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... + _trap_hist._array[reason] = cnt1; + return cnt1; } else { - // Could not represent the count in the histogram. - return (++_nof_overflow_traps); + return _trap_hist_mask + (++_nof_overflow_traps); } } @@ -1514,6 +1514,10 @@ return byte_offset_of(methodDataOopDesc, _data[0]); } + static ByteSize trap_history_offset() { + return byte_offset_of(methodDataOopDesc, _trap_hist._array); + } + static ByteSize invocation_counter_offset() { return byte_offset_of(methodDataOopDesc, _invocation_counter); } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/oops/methodOop.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -51,6 +51,9 @@ #include "runtime/signature.hpp" #include "utilities/quickSort.hpp" #include "utilities/xmlstream.hpp" +#ifdef GRAAL +#include "graal/graalJavaAccess.hpp" +#endif // Implementation of methodOopDesc @@ -658,6 +661,13 @@ } } CompilationPolicy::policy()->disable_compilation(this); + +#ifdef GRAAL + oop graal_mirror = this->graal_mirror(); + if (graal_mirror != NULL) { + HotSpotMethodResolved::set_canBeInlined(graal_mirror, false); + } +#endif } // Revert to using the interpreter and clear out the nmethod diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/opto/runtime.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -1149,7 +1149,7 @@ frame caller_frame = stub_frame.sender(®_map); // Deoptimize the caller frame. - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); } } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/prims/jvmtiEnv.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -1457,7 +1457,7 @@ // If any of the top 2 frames is a compiled one, need to deoptimize it for (int i = 0; i < 2; i++) { if (!is_interpreted[i]) { - Deoptimization::deoptimize_frame(java_thread, frame_sp[i]); + Deoptimization::deoptimize_frame(java_thread, frame_sp[i], Deoptimization::Reason_constraint); } } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -1340,7 +1340,7 @@ if (!vf->fr().can_be_deoptimized()) { return JVMTI_ERROR_OPAQUE_FRAME; } - Deoptimization::deoptimize_frame(java_thread, jvf->fr().id()); + Deoptimization::deoptimize_frame(java_thread, jvf->fr().id(), Deoptimization::Reason_constraint); } // Get information about method return type diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/prims/jvmtiImpl.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -767,7 +767,7 @@ // Schedule deoptimization so that eventually the local // update will be written to an interpreter frame. - Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id()); + Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id(), Deoptimization::Reason_constraint); // Now store a new value for the local which will be applied // once deoptimization occurs. Note however that while this diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/compilationPolicy.hpp --- a/src/share/vm/runtime/compilationPolicy.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/compilationPolicy.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -118,7 +118,7 @@ // StackWalkCompPolicy - existing C2 policy -//#ifdef COMPILER2 +#if defined(COMPILER2) || defined(GRAAL) class StackWalkCompPolicy : public NonTieredCompPolicy { public: virtual void method_invocation_event(methodHandle m, JavaThread* thread); @@ -138,6 +138,6 @@ // negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg }; -//#endif +#endif #endif // SHARE_VM_RUNTIME_COMPILATIONPOLICY_HPP diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -1133,17 +1133,17 @@ } -void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) { +void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) { assert(fr.can_be_deoptimized(), "checking frame type"); - gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal); + gather_statistics(reason, Action_none, Bytecodes::_illegal); // Patch the nmethod so that when execution returns to it we will // deopt the execution state and return to the interpreter. fr.deoptimize(thread); } -void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) { +void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) { // Deoptimize only if the frame comes from compile code. // Do not deoptimize the frame which is already patched // during the execution of the loops below. @@ -1155,12 +1155,12 @@ if (UseBiasedLocking) { revoke_biases_of_monitors(thread, fr, map); } - deoptimize_single_frame(thread, fr); + deoptimize_single_frame(thread, fr, reason); } -void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), "can only deoptimize other thread at a safepoint"); // Compute frame and register map based on thread and sp. @@ -1169,15 +1169,15 @@ while (fr.id() != id) { fr = fr.sender(®_map); } - deoptimize(thread, fr, ®_map); + deoptimize(thread, fr, ®_map, reason); } -void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) { if (thread == Thread::current()) { - Deoptimization::deoptimize_frame_internal(thread, id); + Deoptimization::deoptimize_frame_internal(thread, id, reason); } else { - VM_DeoptimizeFrame deopt(thread, id); + VM_DeoptimizeFrame deopt(thread, id, reason); VMThread::execute(&deopt); } } @@ -1502,7 +1502,7 @@ uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; - pdata = query_update_method_data(trap_mdo, trap_bci, reason, + pdata = query_update_method_data(trap_mdo, trap_bci, reason, true, //outputs: this_trap_count, maybe_prior_trap, @@ -1636,25 +1636,31 @@ Deoptimization::query_update_method_data(methodDataHandle trap_mdo, int trap_bci, Deoptimization::DeoptReason reason, + bool update_total_trap_count, //outputs: uint& ret_this_trap_count, bool& ret_maybe_prior_trap, bool& ret_maybe_prior_recompile) { - uint prior_trap_count = trap_mdo->trap_count(reason); - uint this_trap_count = trap_mdo->inc_trap_count(reason); + bool maybe_prior_trap = false; + bool maybe_prior_recompile = false; + uint this_trap_count = 0; + if (update_total_trap_count) { + uint prior_trap_count = trap_mdo->trap_count(reason); + this_trap_count = trap_mdo->inc_trap_count(reason); - // If the runtime cannot find a place to store trap history, - // it is estimated based on the general condition of the method. - // If the method has ever been recompiled, or has ever incurred - // a trap with the present reason , then this BCI is assumed - // (pessimistically) to be the culprit. - bool maybe_prior_trap = (prior_trap_count != 0); - bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0); - ProfileData* pdata = NULL; - + // If the runtime cannot find a place to store trap history, + // it is estimated based on the general condition of the method. + // If the method has ever been recompiled, or has ever incurred + // a trap with the present reason , then this BCI is assumed + // (pessimistically) to be the culprit. + maybe_prior_trap = (prior_trap_count != 0); + maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + } // For reasons which are recorded per bytecode, we check per-BCI data. + ProfileData* pdata = NULL; DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason); + assert(per_bc_reason != Reason_none || update_total_trap_count, "must be"); if (per_bc_reason != Reason_none) { // Find the profile data for this BCI. If there isn't one, // try to allocate one from the MDO's set of spares. @@ -1699,8 +1705,11 @@ uint ignore_this_trap_count; bool ignore_maybe_prior_trap; bool ignore_maybe_prior_recompile; + // Graal uses the total counts to determine if deoptimizations are happening too frequently -> do not adjust total counts + bool update_total_counts = IS_GRAAL(false) NOT_GRAAL(true); query_update_method_data(trap_mdo, trap_bci, (DeoptReason)reason, + update_total_counts, ignore_this_trap_count, ignore_maybe_prior_trap, ignore_maybe_prior_recompile); @@ -1813,6 +1822,21 @@ Deoptimization::DeoptAction Deoptimization::_unloaded_action = Deoptimization::Action_reinterpret; const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = { +#ifdef GRAAL + "none", + "null_check", + "range_check", + "class_check", + "array_check", + "unreached", + "type_checked_inlining", + "optimized_type_check", + "not_compiled_exception_handler", + "unresolved", + "jsr_mismatch", + "div0_check", + "constraint" +#else // Note: Keep this in sync. with enum DeoptReason. "none", "null_check", @@ -1831,6 +1855,7 @@ "age", "predicate", "loop_limit_check" +#endif }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { // Note: Keep this in sync. with enum DeoptAction. diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/deoptimization.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -37,8 +37,35 @@ friend class VMStructs; public: - // What condition caused the deoptimization? + // What condition caused the deoptimization enum DeoptReason { +#ifdef GRAAL + Reason_many = -1, // indicates presence of several reasons + Reason_none = 0, // indicates absence of a relevant deopt. + // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits. + // This is more complicated for Graal as Graal may deoptimize to *some* bytecode before the + // bytecode that actually caused the deopt (with inlining, Graal may even deoptimize to a + // bytecode in another method): + // - bytecode y in method b() causes deopt + // - Graal deoptimizes to bytecode x in method a() + // -> the deopt reason will be recorded for method a() at bytecode x + Reason_null_check, + Reason_range_check, + Reason_class_check, + Reason_array_check, + Reason_unreached, + Reason_type_checked_inlining, + Reason_optimized_type_check, + + // recorded per method + Reason_not_compiled_exception_handler, + Reason_unresolved, + Reason_jsr_mismatch, + Reason_div0_check, + Reason_constraint, + Reason_LIMIT, + Reason_RECORDED_LIMIT = Reason_optimized_type_check +#else Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits @@ -50,7 +77,7 @@ Reason_intrinsic, // saw unexpected operand to intrinsic (@bci) Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci) - Reason_unloaded, // unloaded class or constant pool entry + Reason_unloaded, // unloaded or class constant pool entry Reason_uninitialized, // bad class state (uninitialized) Reason_unreached, // code is not reached, compiler Reason_unhandled, // arbitrary compiler limitation @@ -60,12 +87,13 @@ Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed Reason_LIMIT, + Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc +#endif // Note: Keep this enum in sync. with _trap_reason_name. - Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of // DataLayout::trap_bits. This dependency is enforced indirectly // via asserts, to avoid excessive direct header-to-header dependencies. - // See Deoptimization::trap_state_reason and class DataLayout. + // See Deoptimization::trap_state_reason and class DataLayout }; // What action must be taken by the runtime? @@ -99,11 +127,11 @@ static int deoptimize_dependents(); // Deoptimizes a frame lazily. nmethod gets patched deopt happens on return to the frame - static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map); + static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason); private: // Does the actual work for deoptimizing a single frame - static void deoptimize_single_frame(JavaThread* thread, frame fr); + static void deoptimize_single_frame(JavaThread* thread, frame fr, DeoptReason reason); // Helper function to revoke biases of all monitors in frame if UseBiasedLocking // is enabled @@ -233,11 +261,11 @@ // Only called from VMDeoptimizeFrame // @argument thread. Thread where stub_frame resides. // @argument id. id of frame that should be deoptimized. - static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id); + static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason); - // If thread is not the current thread then execute + // if thread is not the current thread then execute // VM_DeoptimizeFrame otherwise deoptimize directly. - static void deoptimize_frame(JavaThread* thread, intptr_t* id); + static void deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason); // Statistics static void gather_statistics(DeoptReason reason, DeoptAction action, @@ -251,37 +279,60 @@ // trap_request codes static DeoptReason trap_request_reason(int trap_request) { - if (trap_request < 0) + if (trap_request < 0) { return (DeoptReason) ((~(trap_request) >> _reason_shift) & right_n_bits(_reason_bits)); - else + } else { +#ifdef GRAAL + ShouldNotReachHere(); + return Reason_none; +#else // standard reason for unloaded CP entry return Reason_unloaded; +#endif // GRAAL + } } static DeoptAction trap_request_action(int trap_request) { - if (trap_request < 0) + if (trap_request < 0) { return (DeoptAction) ((~(trap_request) >> _action_shift) & right_n_bits(_action_bits)); - else + } else { +#ifdef GRAAL + ShouldNotReachHere(); + return Action_make_not_compilable; +#else // standard action for unloaded CP entry return _unloaded_action; +#endif // GRAAL + } } static int trap_request_index(int trap_request) { - if (trap_request < 0) + if (trap_request < 0) { return -1; - else + } else { +#ifdef GRAAL + ShouldNotReachHere(); + return -1; +#else return trap_request; +#endif // GRAAL + } } static int make_trap_request(DeoptReason reason, DeoptAction action, int index = -1) { +#ifdef GRAAL + assert(index == -1, "Graal does not use index"); +#endif + assert((1 << _reason_bits) >= Reason_LIMIT, "enough bits"); assert((1 << _action_bits) >= Action_LIMIT, "enough bits"); int trap_request; - if (index != -1) + if (index != -1) { trap_request = index; - else + } else { trap_request = (~(((reason) << _reason_shift) + ((action) << _action_shift))); + } assert(reason == trap_request_reason(trap_request), "valid reason"); assert(action == trap_request_action(trap_request), "valid action"); assert(index == trap_request_index(trap_request), "valid index"); @@ -337,6 +388,7 @@ static ProfileData* query_update_method_data(methodDataHandle trap_mdo, int trap_bci, DeoptReason reason, + bool update_total_trap_count, //outputs: uint& ret_this_trap_count, bool& ret_maybe_prior_trap, diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/safepoint.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -1060,7 +1060,7 @@ // as otherwise we may never deliver it. if (thread()->has_async_condition()) { ThreadInVMfromJavaNoAsyncException __tiv(thread()); - Deoptimization::deoptimize_frame(thread(), caller_fr.id()); + Deoptimization::deoptimize_frame(thread(), caller_fr.id(), Deoptimization::Reason_constraint); } // If an exception has been installed we must check for a pending deoptimization diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -665,7 +665,7 @@ RegisterMap reg_map(thread); frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); - Deoptimization::deoptimize_frame(thread, caller_frame.id()); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_not_compiled_exception_handler); return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); } @@ -789,14 +789,17 @@ throw_and_post_jvmti_exception(thread, exception); JRT_END -address SharedRuntime::deoptimization_continuation(JavaThread* thread, address pc, nmethod* nm) -{ +#ifdef GRAAL +address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { + assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); if (TraceSignals) { tty->print_cr(err_msg("Deoptimizing on implicit exception at relative pc=%d in method %s", pc - nm->entry_point(), nm->method()->name()->as_C_string())); } thread->_ScratchA = (intptr_t)pc; - return (SharedRuntime::deopt_blob()->jmp_uncommon_trap()); + thread->_ScratchB = Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret); + return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); } +#endif JRT_ENTRY(void, SharedRuntime::throw_WrongMethodTypeException(JavaThread* thread, oopDesc* required, oopDesc* actual)) assert(thread == JavaThread::current() && required->is_oop() && actual->is_oop(), "bad args"); @@ -891,7 +894,7 @@ _implicit_null_throws++; #endif #ifdef GRAAL - target_pc = deoptimization_continuation(thread, pc, nm); + target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check); #else target_pc = nm->continuation_for_implicit_exception(pc); #endif @@ -914,7 +917,7 @@ if (TraceSignals) { tty->print_cr("graal implicit div0"); } - target_pc = deoptimization_continuation(thread, pc, nm); + target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check); #else target_pc = nm->continuation_for_implicit_exception(pc); #endif diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/sharedRuntime.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -187,11 +187,13 @@ static void throw_NullPointerException(JavaThread* thread); static void throw_NullPointerException_at_call(JavaThread* thread); static void throw_StackOverflowError(JavaThread* thread); - static address deoptimization_continuation(JavaThread* thread, address pc, nmethod* nm); static void throw_WrongMethodTypeException(JavaThread* thread, oopDesc* required, oopDesc* actual); static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); +#ifdef GRAAL + static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason); +#endif // Shared stub locations static address get_poll_stub(address pc); diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/thread.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -2058,7 +2058,7 @@ RegisterMap reg_map(this, UseBiasedLocking); frame compiled_frame = f.sender(®_map); if (compiled_frame.can_be_deoptimized()) { - Deoptimization::deoptimize(this, compiled_frame, ®_map); + Deoptimization::deoptimize(this, compiled_frame, ®_map, Deoptimization::Reason_constraint); } } } @@ -2490,7 +2490,7 @@ trace_frames(); trace_stack(); } - Deoptimization::deoptimize(this, *fst.current(), fst.register_map()); + Deoptimization::deoptimize(this, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint); } } @@ -2520,7 +2520,7 @@ StackFrameStream fst(this, UseBiasedLocking); for(; !fst.is_done(); fst.next()) { if (fst.current()->should_be_deoptimized()) { - Deoptimization::deoptimize(this, *fst.current(), fst.register_map()); + Deoptimization::deoptimize(this, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint); } } } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -2452,26 +2452,32 @@ declare_constant(Location::on_stack) \ declare_constant(Location::in_register) \ \ - declare_constant(Deoptimization::Reason_many) \ - declare_constant(Deoptimization::Reason_none) \ - declare_constant(Deoptimization::Reason_null_check) \ - declare_constant(Deoptimization::Reason_null_assert) \ - declare_constant(Deoptimization::Reason_range_check) \ - declare_constant(Deoptimization::Reason_class_check) \ - declare_constant(Deoptimization::Reason_array_check) \ - declare_constant(Deoptimization::Reason_intrinsic) \ - declare_constant(Deoptimization::Reason_bimorphic) \ - declare_constant(Deoptimization::Reason_unloaded) \ - declare_constant(Deoptimization::Reason_uninitialized) \ - declare_constant(Deoptimization::Reason_unreached) \ - declare_constant(Deoptimization::Reason_unhandled) \ - declare_constant(Deoptimization::Reason_constraint) \ - declare_constant(Deoptimization::Reason_div0_check) \ - declare_constant(Deoptimization::Reason_age) \ - declare_constant(Deoptimization::Reason_predicate) \ - declare_constant(Deoptimization::Reason_loop_limit_check) \ - declare_constant(Deoptimization::Reason_LIMIT) \ - declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ + /* TODO (chaeubl) those constants should be graal/c1/c2 specific */ \ + /*declare_constant(Deoptimization::Reason_many)*/ \ + /*declare_constant(Deoptimization::Reason_none)*/ \ + /*declare_constant(Deoptimization::Reason_null_check)*/ \ + /*declare_constant(Deoptimization::Reason_range_check)*/ \ + /*declare_constant(Deoptimization::Reason_class_check)*/ \ + /*declare_constant(Deoptimization::Reason_array_check)*/ \ + /*declare_constant(Deoptimization::Reason_unreached)*/ \ + /*declare_constant(Deoptimization::Reason_constraint)*/ \ + /*declare_constant(Deoptimization::Reason_div0_check)*/ \ + /*declare_constant(Deoptimization::Reason_type_checked_inlining)*/ \ + /*declare_constant(Deoptimization::Reason_optimized_type_check)*/ \ + /*declare_constant(Deoptimization::Reason_not_compiled_exception_handler)*/ \ + /*declare_constant(Deoptimization::Reason_unresolved)*/ \ + /*declare_constant(Deoptimization::Reason_jsr_mismatch)*/ \ + /*declare_constant(Deoptimization::Reason_LIMIT)*/ \ + /*declare_constant(Deoptimization::Reason_RECORDED_LIMIT)*/ \ + /*declare_constant(Deoptimization::Reason_null_assert)*/ \ + /*declare_constant(Deoptimization::Reason_intrinsic)*/ \ + /*declare_constant(Deoptimization::Reason_bimorphic)*/ \ + /*declare_constant(Deoptimization::Reason_unloaded)*/ \ + /*declare_constant(Deoptimization::Reason_uninitialized) */ \ + /*declare_constant(Deoptimization::Reason_unhandled)*/ \ + /*declare_constant(Deoptimization::Reason_age)*/ \ + /*declare_constant(Deoptimization::Reason_predicate)*/ \ + /*declare_constant(Deoptimization::Reason_loop_limit_check)*/ \ \ /*********************/ \ /* Matcher (C2 only) */ \ diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/vm_operations.cpp Wed Mar 21 13:57:30 2012 +0100 @@ -117,14 +117,16 @@ } -VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id) { +VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) { _thread = thread; _id = id; + _reason = reason; } void VM_DeoptimizeFrame::doit() { - Deoptimization::deoptimize_frame_internal(_thread, _id); + assert(_reason > Deoptimization::Reason_none && _reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + Deoptimization::deoptimize_frame_internal(_thread, _id, (Deoptimization::DeoptReason)_reason); } @@ -156,7 +158,7 @@ if (fst.current()->can_be_deoptimized()) { if (fcount++ == fnum) { fcount = 0; - Deoptimization::deoptimize(thread, *fst.current(), fst.register_map()); + Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_constraint); } } } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/runtime/vm_operations.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -251,7 +251,8 @@ private: JavaThread* _thread; intptr_t* _id; - VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); + int _reason; + VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason); public: VMOp_Type type() const { return VMOp_DeoptimizeFrame; } diff -r 09f66048738e -r 4d8ebb0fc484 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Wed Mar 21 13:49:34 2012 +0100 +++ b/src/share/vm/utilities/macros.hpp Wed Mar 21 13:57:30 2012 +0100 @@ -76,8 +76,10 @@ #ifdef GRAAL #define IS_GRAAL(code) code +#define NOT_GRAAL(code) #else #define IS_GRAAL(code) +#define NOT_GRAAL(code) code #endif #ifdef TIERED