# HG changeset patch # User Lukas Stadler # Date 1347890926 -7200 # Node ID c5afcc2ebd3d7b9203b41148868337957e7d833b # Parent debe42b2b92f7123ce3900ba5f432b34fd5fde87 change of project structure: separate compiler and LIR, put EA into separate project diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Mon Sep 17 16:08:46 2012 +0200 @@ -42,11 +42,14 @@ private final BitSet activeBlocks; // used for recursive processing of blocks private final int[] forwardBranches; // number of incoming forward branches for each block private final List workList; // temporary list (used in markLoops and computeOrder) - private final Block[] loopHeaders; + private final List loopHeaders; private final boolean reorderLoops; public ComputeBlockOrder(int maxBlockId, int loopCount, Block startBlock, boolean reorderLoops) { - loopHeaders = new Block[loopCount]; + loopHeaders = new ArrayList<>(loopCount); + while (loopHeaders.size() < loopCount) { + loopHeaders.add(null); + } visitedBlocks = new BitSet(maxBlockId); activeBlocks = new BitSet(maxBlockId); forwardBranches = new int[maxBlockId]; @@ -225,7 +228,7 @@ codeEmittingOrder.add(cur); if (cur.isLoopEnd() && reorderLoops) { - Block loopHeader = loopHeaders[cur.getLoop().index]; + Block loopHeader = loopHeaders.get(cur.getLoop().index); if (loopHeader != null) { codeEmittingOrder.add(loopHeader); @@ -238,7 +241,7 @@ } } } else { - loopHeaders[cur.getLoop().index] = cur; + loopHeaders.set(cur.getLoop().index, cur); } } } diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/GraalOptions.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2009, 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 com.oracle.graal.nodes.*; + + +/** + * This class encapsulates options that control the behavior of the Graal compiler. + * + * (thomaswue) WARNING: Fields of this class are treated as final by Graal. + */ +public final class GraalOptions { + + // Checkstyle: stop + private static final boolean ____ = false; + // Checkstyle: resume + + public static int Threads = 4; + + // inlining settings + public static boolean Inline = true; + public static boolean Intrinsify = true; + 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; + public static int MaximumInlineLevel = 30; + public static int MaximumDesiredSize = 3000; + public static int MaximumRecursiveInlining = 1; + public static int SmallCompiledCodeSize = 2000; + public static boolean LimitInlinedProbability = ____; + // WeightBasedInliningPolicy (0) + public static boolean ParseBeforeInlining = ____; + public static float InliningSizePenaltyExp = 20; + public static float MaximumInlineWeight = 1.25f; + public static float InliningSizePenalty = 1; + // StaticSizeBasedInliningPolicy (1), MinimumCodeSizeBasedInlining (2), + // DynamicSizeBasedInliningPolicy (3) + public static int MaximumInlineSize = 35; + // GreedySizeBasedInlining (4) + public static int MaximumGreedyInlineSize = 100; + public static int InliningBonusPerTransferredValue = 10; + // Common options for inlining policies 1 to 4 + public static float NestedInliningSizeRatio = 1f; + public static float BoostInliningForEscapeAnalysis = 2f; + public static float ProbabilityCapForInlining = 1f; + + // escape analysis settings + public static boolean PartialEscapeAnalysis = true; + + public static double TailDuplicationProbability = 0.5; + public static int TailDuplicationTrivialSize = 1; + + // absolute probability analysis + public static boolean ProbabilityAnalysis = true; + 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; + + // comilation queue + public static int TimedBootstrap = -1; + public static boolean PriorityCompileQueue = true; + public static int SlowQueueCutoff = 100000; + public static boolean SlowCompileThreads = ____; + public static boolean DynamicCompilePriority = ____; + + // graph caching + public static boolean CacheGraphs = true; + public static int GraphCacheSize = 1000; + public static boolean PrintGraphCache = ____; + + //rematerialize settings + public static float MinimumUsageProbability = 0.95f; + + //loop transform settings TODO (gd) tune + public static boolean LoopPeeling = true; + public static boolean ReassociateInvariants = true; + public static boolean FullUnroll = true; + public static boolean LoopUnswitch = true; + public static int FullUnrollMaxNodes = 150; + public static int ExactFullUnrollMaxNodes = 600; + public static float MinimumPeelProbability = 0.35f; + public static int LoopMaxUnswitch = 3; + public static int LoopUnswitchMaxIncrease = 50; + public static int LoopUnswitchUncertaintyBoost = 5; + + // debugging settings + public static int MethodEndBreakpointGuards = 0; + public static boolean ZapStackOnMethodEntry = ____; + public static boolean DeoptALot = ____; + public static boolean VerifyPhases = true; + public static boolean CreateDeoptInfo = ____; + + public static String PrintFilter = null; + + // printing settings + public static boolean PrintLIR = ____; + public static boolean PrintCFGToFile = ____; + + // Debug settings: + public static boolean Debug = true; + public static boolean PerThreadDebugValues = ____; + public static boolean SummarizeDebugValues = ____; + public static boolean SummarizePerPhase = ____; + public static String Dump = null; + public static String Meter = null; + public static String Time = null; + public static String Log = null; + public static String LogFile = null; + public static String MethodFilter = null; + public static boolean DumpOnError = ____; + + // Ideal graph visualizer output settings + public static boolean PrintBinaryGraphs = ____; + public static boolean PrintCFG = true; + public static boolean PrintIdealGraphFile = ____; + public static String PrintIdealGraphAddress = "127.0.0.1"; + public static int PrintIdealGraphPort = 4444; + public static int PrintBinaryGraphPort = 4445; + + // Other printing settings + public static boolean PrintQueue = ____; + public static boolean PrintCompilation = ____; + public static boolean PrintProfilingInformation = ____; + public static boolean PrintXirTemplates = ____; + public static boolean PrintIRWithLIR = ____; + public static boolean PrintAssembly = ____; + public static boolean PrintCodeBytes = ____; + public static int PrintAssemblyBytesPerLine = 16; + public static boolean PrintBailout = ____; + public static int TraceLinearScanLevel = 0; + public static boolean TraceRegisterAllocation = false; + 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; + + // state merging settings + public static boolean AssumeVerifiedBytecode = true; + + // Code generator settings + public static boolean CheckCastElimination = true; + public static boolean CullFrameStates = ____; + 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; + static boolean UseTypeCheckHints = true; + public static boolean InlineVTableStubs = true; + public static boolean AlwaysInlineVTableStubs = ____; + + public static boolean GenAssertionCode = ____; + public static boolean AlignCallsForPatching = true; + public static boolean ResolveClassBeforeStaticInvoke = true; + + // Translating tableswitch instructions + public static int SequentialSwitchLimit = 4; + public static int RangeTestsSwitchDensity = 5; + public static double MinTableSwitchDensity = 0.5; + + public static boolean DetailedAsserts = ____; + + // Runtime settings + public static int ReadPrefetchInstr = 0; + public static int StackShadowPages = 2; + + // Assembler settings + public static boolean CommentedAssembly = ____; + public static boolean PrintLIRWithAssembly = ____; + + public static boolean SupportJsrBytecodes = true; + + public static boolean OptAssumptions = true; + public static boolean OptReadElimination = true; + public static boolean OptGVN = true; + public static boolean OptCanonicalizer = true; + public static boolean ScheduleOutOfLoops = true; + public static boolean OptReorderLoops = true; + public static boolean OptEliminateGuards = true; + public static boolean OptImplicitNullChecks = true; + public static boolean OptLivenessAnalysis = true; + public static boolean OptLoopTransform = true; + public static boolean OptSafepointElimination = true; + public static boolean FloatingReads = true; + public static boolean OptTailDuplication = true; + + /** + * Insert a counter in the method prologue to track the most frequently called methods that were compiled by Graal. + */ + public static boolean MethodEntryCounters = false; + /** + * Number of caller program counters to distinguish when counting methods. + */ + public static int MethodEntryCountersCallers = 20; + + /** + * Prints all the available GraalOptions. + */ + public static boolean PrintFlags = false; + + /** + * Counts the various paths taken through snippets. + */ + public static boolean SnippetCounters = false; + + /** + * If the probability that a checkcast will hit one the profiled types (up to {@link #CheckcastMaxHints}) + * is below this value, the checkcast will be compiled without hints. + */ + public static double CheckcastMinHintHitProbability = 0.5; + + /** + * The maximum number of hint types that will be used when compiling a checkcast for which + * profiling information is available. Note that {@link #CheckcastMinHintHitProbability} + * also influences whether hints are used. + */ + public static int CheckcastMaxHints = 2; + + /** + * @see #CheckcastMinHintHitProbability + */ + public static double InstanceOfMinHintHitProbability = 0.5; + + /** + * @see #CheckcastMaxHints + */ + public static int InstanceOfMaxHints = 1; + + /** + * Use HIR lowering instead of LIR lowering for certain instructions. + * Only instructions in methods whose fully qualified name contains this option will be HIR lowered. + */ + public static String HIRLowerCheckcast = ""; + public static String HIRLowerInstanceOf = ""; + public static String HIRLowerNewInstance = ""; + public static String HIRLowerNewArray = ""; + public static String HIRLowerMonitors = "MonitorTest"; + + /** + * Use XIR to lower {@link Invoke} nodes. + */ + public static boolean XIRLowerInvokes = false; + + static { + // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this) + assert (DetailedAsserts = true) == true; + assert (CommentedAssembly = true) == true; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/OptimisticOptimizations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/OptimisticOptimizations.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,116 @@ +/* + * 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.api.meta.*; +import com.oracle.graal.debug.*; +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(ResolvedJavaMethod method) { + this.enabledOpts = EnumSet.noneOf(Optimization.class); + + ProfilingInfo profilingInfo = method.profilingInfo(); + if (checkDeoptimizations(profilingInfo, DeoptimizationReason.UnreachedCode)) { + enabledOpts.add(Optimization.RemoveNeverExecutedCode); + } + if (checkDeoptimizations(profilingInfo, DeoptimizationReason.TypeCheckedInliningViolated)) { + enabledOpts.add(Optimization.UseTypeCheckedInlining); + } + if (checkDeoptimizations(profilingInfo, DeoptimizationReason.OptimizedTypeCheckViolated)) { + enabledOpts.add(Optimization.UseTypeCheckHints); + } + if (checkDeoptimizations(profilingInfo, DeoptimizationReason.NotCompiledExceptionHandler)) { + enabledOpts.add(Optimization.UseExceptionProbability); + } + } + + private OptimisticOptimizations(Set enabledOpts) { + this.enabledOpts = enabledOpts; + } + + public void log(JavaMethod method) { + for (Optimization opt: Optimization.values()) { + if (!enabledOpts.contains(opt)) { + if (GraalOptions.PrintDisabledOptimisticOptimizations) { + TTY.println("WARN: deactivated optimistic optimization %s for %s", opt.name(), MetaUtil.format("%H.%n(%p)", method)); + } + disabledOptimisticOptsMetric.increment(); + } + } + } + + public boolean removeNeverExecutedCode() { + return GraalOptions.RemoveNeverExecutedCode && enabledOpts.contains(Optimization.RemoveNeverExecutedCode); + } + + public boolean useTypeCheckHints() { + 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(ProfilingInfo profilingInfo, DeoptimizationReason reason) { + return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/MergeableState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/MergeableState.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.graph; + +import java.util.*; + +import com.oracle.graal.nodes.*; + +public interface MergeableState { + T clone(); + boolean merge(MergeNode merge, List withStates); + void loopBegin(LoopBeginNode loopBegin); + void loopEnds(LoopBeginNode loopBegin, List loopEndStates); + void afterSplit(FixedNode node); +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.graph; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +/** + * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a specified fixed node.
+ * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode}, {@link MergeNode}...) and the {@link FixedWithNextNode#next() next} pointers + * of {@link FixedWithNextNode}.
+ * While iterating it maintains a user-defined state by calling the methods available in {@link MergeableState}. + * + * @param the type of {@link MergeableState} handled by this PostOrderNodeIterator + */ +public abstract class PostOrderNodeIterator> { + + private final NodeBitMap visitedEnds; + private final Deque nodeQueue; + private final IdentityHashMap nodeStates; + private final FixedNode start; + + protected T state; + + public PostOrderNodeIterator(FixedNode start, T initialState) { + visitedEnds = start.graph().createNodeBitMap(); + nodeQueue = new ArrayDeque<>(); + nodeStates = new IdentityHashMap<>(); + this.start = start; + this.state = initialState; + } + + public void apply() { + FixedNode current = start; + + do { + if (current instanceof InvokeWithExceptionNode) { + invoke((Invoke) current); + queueSuccessors(current, null); + current = nextQueuedNode(); + } else if (current instanceof LoopBeginNode) { + state.loopBegin((LoopBeginNode) current); + nodeStates.put(current, state); + state = state.clone(); + loopBegin((LoopBeginNode) current); + current = ((LoopBeginNode) current).next(); + assert current != null; + } else if (current instanceof LoopEndNode) { + loopEnd((LoopEndNode) current); + finishLoopEnds((LoopEndNode) current); + current = nextQueuedNode(); + } else if (current instanceof MergeNode) { + merge((MergeNode) current); + current = ((MergeNode) current).next(); + assert current != null; + } else if (current instanceof FixedWithNextNode) { + FixedNode next = ((FixedWithNextNode) current).next(); + assert next != null : current; + node(current); + current = next; + } else if (current instanceof EndNode) { + end((EndNode) current); + queueMerge((EndNode) current); + current = nextQueuedNode(); + } else if (current instanceof DeoptimizeNode) { + deoptimize((DeoptimizeNode) current); + current = nextQueuedNode(); + } else if (current instanceof ReturnNode) { + returnNode((ReturnNode) current); + current = nextQueuedNode(); + } else if (current instanceof UnwindNode) { + unwind((UnwindNode) current); + current = nextQueuedNode(); + } else if (current instanceof ControlSplitNode) { + Set successors = controlSplit((ControlSplitNode) current); + queueSuccessors(current, successors); + current = nextQueuedNode(); + } else { + assert false : current; + } + } while(current != null); + } + + private void queueSuccessors(FixedNode x, Set successors) { + nodeStates.put(x, state); + if (successors != null) { + for (Node node : successors) { + if (node != null) { + nodeStates.put((FixedNode) node.predecessor(), state); + nodeQueue.addFirst((FixedNode) node); + } + } + } else { + for (Node node : x.successors()) { + if (node != null) { + nodeQueue.addFirst((FixedNode) node); + } + } + } + } + + private FixedNode nextQueuedNode() { + int maxIterations = nodeQueue.size(); + while (maxIterations-- > 0) { + FixedNode node = nodeQueue.removeFirst(); + if (node instanceof MergeNode) { + MergeNode merge = (MergeNode) node; + state = nodeStates.get(merge.forwardEndAt(0)).clone(); + ArrayList states = new ArrayList<>(merge.forwardEndCount() - 1); + for (int i = 1; i < merge.forwardEndCount(); i++) { + T other = nodeStates.get(merge.forwardEndAt(i)); + assert other != null; + states.add(other); + } + boolean ready = state.merge(merge, states); + if (ready) { + return merge; + } else { + nodeQueue.addLast(merge); + } + } else { + assert node.predecessor() != null; + state = nodeStates.get(node.predecessor()).clone(); + state.afterSplit(node); + return node; + } + } + return null; + } + + private void finishLoopEnds(LoopEndNode end) { + assert !visitedEnds.isMarked(end); + assert !nodeStates.containsKey(end); + nodeStates.put(end, state); + visitedEnds.mark(end); + LoopBeginNode begin = end.loopBegin(); + boolean endsVisited = true; + for (LoopEndNode le : begin.loopEnds()) { + if (!visitedEnds.isMarked(le)) { + endsVisited = false; + break; + } + } + if (endsVisited) { + ArrayList states = new ArrayList<>(begin.loopEnds().count()); + for (LoopEndNode le : begin.orderedLoopEnds()) { + states.add(nodeStates.get(le)); + } + T loopBeginState = nodeStates.get(begin); + if (loopBeginState != null) { + loopBeginState.loopEnds(begin, states); + } + } + } + + private void queueMerge(EndNode end) { + assert !visitedEnds.isMarked(end); + assert !nodeStates.containsKey(end); + nodeStates.put(end, state); + visitedEnds.mark(end); + MergeNode merge = end.merge(); + boolean endsVisited = true; + for (int i = 0; i < merge.forwardEndCount(); i++) { + if (!visitedEnds.isMarked(merge.forwardEndAt(i))) { + endsVisited = false; + break; + } + } + if (endsVisited) { + nodeQueue.add(merge); + } + } + + protected abstract void node(FixedNode node); + + protected void end(EndNode endNode) { + node(endNode); + } + + protected void merge(MergeNode merge) { + node(merge); + } + + protected void loopBegin(LoopBeginNode loopBegin) { + node(loopBegin); + } + + protected void loopEnd(LoopEndNode loopEnd) { + node(loopEnd); + } + + protected void deoptimize(DeoptimizeNode deoptimize) { + node(deoptimize); + } + + protected Set controlSplit(ControlSplitNode controlSplit) { + node(controlSplit); + return null; + } + + protected void returnNode(ReturnNode returnNode) { + node(returnNode); + } + + protected void invoke(Invoke invoke) { + node(invoke.node()); + } + + protected void unwind(UnwindNode unwind) { + node(unwind); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/graph/package-info.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * + */ +package com.oracle.graal.compiler.graph; diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; + + +public class BasicInductionVariable extends InductionVariable { + private PhiNode phi; + private ValueNode init; + private ValueNode rawStride; + private IntegerArithmeticNode op; + + public BasicInductionVariable(LoopEx loop, PhiNode phi, ValueNode init, ValueNode rawStride, IntegerArithmeticNode op) { + super(loop); + this.phi = phi; + this.init = init; + this.rawStride = rawStride; + this.op = op; + } + + @Override + public Direction direction() { + Stamp stamp = rawStride.stamp(); + if (stamp instanceof IntegerStamp) { + IntegerStamp integerStamp = (IntegerStamp) stamp; + Direction dir = null; + if (integerStamp.isStrictlyPositive()) { + dir = Direction.Up; + } else if (integerStamp.isStrictlyNegative()) { + dir = Direction.Down; + } + if (dir != null) { + if (op instanceof IntegerAddNode) { + return dir; + } else { + assert op instanceof IntegerSubNode; + return dir.opposite(); + } + } + } + return null; + } + + @Override + public PhiNode valueNode() { + return phi; + } + + @Override + public ValueNode initNode() { + return init; + } + + @Override + public ValueNode strideNode() { + if (op instanceof IntegerAddNode) { + return rawStride; + } + if (op instanceof IntegerSubNode) { + return rawStride.graph().unique(new NegateNode(rawStride)); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public boolean isConstantInit() { + return init.isConstant(); + } + + @Override + public boolean isConstantStride() { + return rawStride.isConstant(); + } + + @Override + public long constantInit() { + return init.asConstant().asLong(); + } + + @Override + public long constantStride() { + if (op instanceof IntegerAddNode) { + return rawStride.asConstant().asLong(); + } + if (op instanceof IntegerSubNode) { + return -rawStride.asConstant().asLong(); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public ValueNode extremumNode() { + return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init); + } + + @Override + public boolean isConstantExtremum() { + return isConstantInit() && isConstantStride() && loop.counted().isConstantMaxTripCount(); + } + + @Override + public long constantExtremum() { + return constantStride() * loop.counted().constantMaxTripCount() + constantInit(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.compiler.loop.InductionVariable.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +public class CountedLoopInfo { + private final LoopEx loop; + private InductionVariable iv; + private ValueNode end; + private boolean oneOff; + + CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) { + this.loop = loop; + this.iv = iv; + this.end = end; + this.oneOff = oneOff; + } + + public ValueNode maxTripCountNode() { + //TODO (gd) stuarte and respect oneOff + return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), iv.strideNode()); + } + + public boolean isConstantMaxTripCount() { + return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride(); + } + + public long constantMaxTripCount() { + long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0; + long max = (((ConstantNode) end).asConstant().asLong() + off - iv.constantInit()) / iv.constantStride(); + return Math.max(0, max); + } + + public boolean isExactTripCount() { + return loop.loopBegin().loopExits().count() == 1; + } + + public ValueNode exactTripCountNode() { + assert isExactTripCount(); + return maxTripCountNode(); + } + + public boolean isConstantExactTripCount() { + assert isExactTripCount(); + return isConstantMaxTripCount(); + } + + public long constantExactTripCount() { + assert isExactTripCount(); + return constantMaxTripCount(); + } + + @Override + public String toString() { + return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : ""); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + + +public class DerivedOffsetInductionVariable extends InductionVariable { + private InductionVariable base; + private ValueNode offset; + private IntegerArithmeticNode value; + + public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, IntegerArithmeticNode value) { + super(loop); + this.base = base; + this.offset = offset; + this.value = value; + } + + @Override + public Direction direction() { + return base.direction(); + } + + @Override + public ValueNode valueNode() { + return value; + } + + @Override + public boolean isConstantInit() { + return offset.isConstant() && base.isConstantInit(); + } + + @Override + public boolean isConstantStride() { + return base.isConstantStride(); + } + + @Override + public long constantInit() { + return op(base.constantInit(), offset.asConstant().asLong()); + } + + @Override + public long constantStride() { + if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { + return -base.constantStride(); + } + return base.constantStride(); + } + + @Override + public ValueNode initNode() { + return op(base.initNode(), offset); + } + + @Override + public ValueNode strideNode() { + if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { + return value.graph().unique(new NegateNode(base.strideNode())); + } + return base.strideNode(); + } + + @Override + public ValueNode extremumNode() { + return op(offset, base.extremumNode()); + } + + @Override + public boolean isConstantExtremum() { + return offset.isConstant() && base.isConstantExtremum(); + } + + @Override + public long constantExtremum() { + return op(base.constantExtremum(), offset.asConstant().asLong()); + } + + private long op(long b, long o) { + if (value instanceof IntegerAddNode) { + return b + o; + } + if (value instanceof IntegerSubNode) { + if (base.valueNode() == value.x()) { + return b - o; + } else { + assert base.valueNode() == value.y(); + return o - b; + } + } + throw GraalInternalError.shouldNotReachHere(); + } + + private ValueNode op(ValueNode b, ValueNode o) { + if (value instanceof IntegerAddNode) { + return IntegerArithmeticNode.add(b, o); + } + if (value instanceof IntegerSubNode) { + if (base.valueNode() == value.x()) { + return IntegerArithmeticNode.sub(b, o); + } else { + assert base.valueNode() == value.y(); + return IntegerArithmeticNode.sub(o, b); + } + } + throw GraalInternalError.shouldNotReachHere(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.type.*; + + +public class DerivedScaledInductionVariable extends InductionVariable { + private InductionVariable base; + private ValueNode scale; + private ValueNode value; + + public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, ValueNode scale, ValueNode value) { + super(loop); + this.base = base; + this.scale = scale; + this.value = value; + } + + public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) { + super(loop); + this.base = base; + this.scale = ConstantNode.forInt(-1, value.graph()); + this.value = value; + } + + @Override + public Direction direction() { + Stamp stamp = scale.stamp(); + if (stamp instanceof IntegerStamp) { + IntegerStamp integerStamp = (IntegerStamp) stamp; + if (integerStamp.isStrictlyPositive()) { + return base.direction(); + } else if (integerStamp.isStrictlyNegative()) { + return base.direction().opposite(); + } + } + return null; + } + + @Override + public ValueNode valueNode() { + return value; + } + + @Override + public ValueNode initNode() { + return IntegerArithmeticNode.mul(base.initNode(), scale); + } + + @Override + public ValueNode strideNode() { + return IntegerArithmeticNode.mul(base.strideNode(), scale); + } + + @Override + public boolean isConstantInit() { + return scale.isConstant() && base.isConstantInit(); + } + + @Override + public boolean isConstantStride() { + return scale.isConstant() && base.isConstantStride(); + } + + @Override + public long constantInit() { + return base.constantInit() * scale.asConstant().asLong(); + } + + @Override + public long constantStride() { + return base.constantStride() * scale.asConstant().asLong(); + } + + @Override + public ValueNode extremumNode() { + return IntegerArithmeticNode.mul(base.extremumNode(), scale); + } + + @Override + public boolean isConstantExtremum() { + return scale.isConstant() && base.isConstantExtremum(); + } + + @Override + public long constantExtremum() { + return base.constantExtremum() * scale.asConstant().asLong(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/InductionVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/InductionVariable.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + + +public abstract class InductionVariable { + public enum Direction { + Up, + Down; + public Direction opposite() { + switch(this) { + case Up: return Down; + case Down: return Up; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + } + + protected final LoopEx loop; + + public InductionVariable(LoopEx loop) { + this.loop = loop; + } + + public abstract Direction direction(); + + public abstract ValueNode valueNode(); + + public abstract ValueNode initNode(); + public abstract ValueNode strideNode(); + + public abstract boolean isConstantInit(); + public abstract boolean isConstantStride(); + + public abstract long constantInit(); + public abstract long constantStride(); + + public abstract ValueNode extremumNode(); + public abstract boolean isConstantExtremum(); + public abstract long constantExtremum(); +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/InductionVariables.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/InductionVariables.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + + +public class InductionVariables { + private final LoopEx loop; + private Map ivs; + + public InductionVariables(LoopEx loop) { + this.loop = loop; + ivs = new IdentityHashMap<>(); + findDerived(findBasic()); + } + + public InductionVariable get(ValueNode v) { + return ivs.get(v); + } + + private Collection findBasic() { + List bivs = new LinkedList<>(); + LoopBeginNode loopBegin = loop.loopBegin(); + EndNode forwardEnd = loopBegin.forwardEnd(); + for (PhiNode phi : loopBegin.phis()) { + ValueNode backValue = phi.singleBackValue(); + if (backValue == null) { + continue; + } + ValueNode stride = addSub(backValue, phi); + if (stride != null) { + BasicInductionVariable biv = new BasicInductionVariable(loop, phi, phi.valueAt(forwardEnd), stride, (IntegerArithmeticNode) backValue); + ivs.put(phi, biv); + bivs.add(biv); + } + } + return bivs; + } + + private void findDerived(Collection bivs) { + Queue scanQueue = new LinkedList(bivs); + while (!scanQueue.isEmpty()) { + InductionVariable baseIv = scanQueue.remove(); + ValueNode baseIvNode = baseIv.valueNode(); + for (ValueNode op : baseIvNode.usages().filter(ValueNode.class)) { + if (loop.isOutsideLoop(op)) { + continue; + } + InductionVariable iv = null; + ValueNode offset = addSub(op, baseIvNode); + ValueNode scale; + if (offset != null) { + iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (IntegerArithmeticNode) op); + } else if (op instanceof NegateNode) { + iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op); + } else if ((scale = mul(op, baseIvNode)) != null) { + iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op); + } + + if (iv != null) { + ivs.put(op, iv); + scanQueue.offer(iv); + } + } + } + } + + private ValueNode addSub(ValueNode op, ValueNode base) { + if (op instanceof IntegerAddNode || op instanceof IntegerSubNode) { + IntegerArithmeticNode aritOp = (IntegerArithmeticNode) op; + if (aritOp.x() == base && loop.isOutsideLoop(aritOp.y())) { + return aritOp.y(); + } else if (aritOp.y() == base && loop.isOutsideLoop(aritOp.x())) { + return aritOp.x(); + } + } + return null; + } + + private ValueNode mul(ValueNode op, ValueNode base) { + if (op instanceof IntegerMulNode) { + IntegerMulNode mul = (IntegerMulNode) op; + if (mul.x() == base && loop.isOutsideLoop(mul.y())) { + return mul.y(); + } else if (mul.y() == base && loop.isOutsideLoop(mul.x())) { + return mul.x(); + } + } + if (op instanceof LeftShiftNode) { + LeftShiftNode shift = (LeftShiftNode) op; + if (shift.x() == base && shift.y().isConstant()) { + return ConstantNode.forInt(1 << shift.y().asConstant().asInt(), base.graph()); + } + } + return null; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopEx.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopEx.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +public class LoopEx { + private final Loop lirLoop; + private LoopFragmentInside inside; + private LoopFragmentWhole whole; + private CountedLoopInfo counted; //TODO (gd) detect + private LoopsData data; + + LoopEx(Loop lirLoop, LoopsData data) { + this.lirLoop = lirLoop; + this.data = data; + } + + public Loop lirLoop() { + return lirLoop; + } + + public LoopFragmentInside inside() { + if (inside == null) { + inside = new LoopFragmentInside(this); + } + return inside; + } + + public LoopFragmentWhole whole() { + if (whole == null) { + whole = new LoopFragmentWhole(this); + } + return whole; + } + + @SuppressWarnings("unused") + public LoopFragmentInsideFrom insideFrom(FixedNode point) { + // TODO (gd) + return null; + } + + @SuppressWarnings("unused") + public LoopFragmentInsideBefore insideBefore(FixedNode point) { + // TODO (gd) + return null; + } + + public boolean isOutsideLoop(Node n) { + return !whole().contains(n); + } + + public LoopBeginNode loopBegin() { + return lirLoop().loopBegin(); + } + + public FixedNode predecessor() { + return (FixedNode) loopBegin().forwardEnd().predecessor(); + } + + public FixedNode entryPoint() { + return loopBegin().forwardEnd(); + } + + public boolean isCounted() { + return counted != null; + } + + public CountedLoopInfo counted() { + return counted; + } + + public LoopEx parent() { + if (lirLoop.parent == null) { + return null; + } + return data.loop(lirLoop.parent); + } + + public int size() { + return whole().nodes().count(); + } + + @Override + public String toString() { + return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().depth + ") " + loopBegin(); + } + + private class InvariantPredicate extends NodePredicate { + @Override + public boolean apply(Node n) { + return isOutsideLoop(n); + } + } + + public void reassociateInvariants() { + InvariantPredicate invariant = new InvariantPredicate(); + StructuredGraph graph = (StructuredGraph) loopBegin().graph(); + for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) { + if (!BinaryNode.canTryReassociate(binary)) { + continue; + } + BinaryNode result = BinaryNode.reassociate(binary, invariant); + if (result != binary) { + Debug.log(MetaUtil.format("%H::%n", Debug.contextLookup(ResolvedJavaMethod.class)) + " : Reassociated %s into %s", binary, result); + graph.replaceFloating(binary, result); + } + } + } + + public void setCounted(CountedLoopInfo countedLoopInfo) { + counted = countedLoopInfo; + } + + public LoopsData loopsData() { + return data; + } + + public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) { + Collection blocks = new LinkedList<>(); + Collection exits = new LinkedList<>(); + Queue work = new LinkedList<>(); + ControlFlowGraph cfg = loopsData().controlFlowGraph(); + work.add(cfg.blockFor(point)); + Block untilBlock = until != null ? cfg.blockFor(until) : null; + while (!work.isEmpty()) { + Block b = work.remove(); + if (b == untilBlock) { + continue; + } + if (lirLoop().exits.contains(b)) { + exits.add(b.getBeginNode()); + } else if (lirLoop().blocks.contains(b)) { + blocks.add(b.getBeginNode()); + work.addAll(b.getDominated()); + } + } + return LoopFragment.computeNodes(point.graph(), blocks, exits); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragment.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.DuplicationReplacement; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.VirtualState.VirtualClosure; + + +public abstract class LoopFragment { + private final LoopEx loop; + private final LoopFragment original; + protected NodeBitMap nodes; + protected boolean nodesReady; + private Map duplicationMap; + + public LoopFragment(LoopEx loop) { + this(loop, null); + this.nodesReady = true; + } + + public LoopFragment(LoopEx loop, LoopFragment original) { + this.loop = loop; + this.original = original; + this.nodesReady = false; + } + + public LoopEx loop() { + return loop; + } + + public abstract LoopFragment duplicate(); + + public abstract void insertBefore(LoopEx l); + + public void disconnect() { + // TODO (gd) possibly abstract + } + + public boolean contains(Node n) { + return nodes().contains(n); + } + + @SuppressWarnings("unchecked") + public New getDuplicatedNode(Old n) { + assert isDuplicate(); + return (New) duplicationMap.get(n); + } + + protected void putDuplicatedNode(Old oldNode, New newNode) { + duplicationMap.put(oldNode, newNode); + } + + public boolean isDuplicate() { + return original != null; + } + + public LoopFragment original() { + return original; + } + + public abstract NodeIterable nodes(); + + public StructuredGraph graph() { + LoopEx l; + if (isDuplicate()) { + l = original().loop(); + } else { + l = loop(); + } + return (StructuredGraph) l.loopBegin().graph(); + } + + protected abstract DuplicationReplacement getDuplicationReplacement(); + + protected abstract void finishDuplication(); + + protected void patchNodes(final DuplicationReplacement dataFix) { + if (isDuplicate() && !nodesReady) { + assert !original.isDuplicate(); + final DuplicationReplacement cfgFix = original().getDuplicationReplacement(); + DuplicationReplacement dr; + if (cfgFix == null && dataFix != null) { + dr = dataFix; + } else if (cfgFix != null && dataFix == null) { + dr = cfgFix; + } else if (cfgFix != null && dataFix != null) { + dr = new DuplicationReplacement() { + @Override + public Node replacement(Node o) { + Node r1 = dataFix.replacement(o); + if (r1 != o) { + assert cfgFix.replacement(o) == o; + return r1; + } + Node r2 = cfgFix.replacement(o); + if (r2 != o) { + return r2; + } + return o; + } + }; + } else { + dr = new DuplicationReplacement() { + @Override + public Node replacement(Node o) { + return o; + } + }; + } + duplicationMap = graph().addDuplicates(original().nodes(), dr); + finishDuplication(); + nodesReady = true; + } else { + //TODO (gd) apply fix ? + } + } + + protected static NodeBitMap computeNodes(Graph graph, Collection blocks) { + return computeNodes(graph, blocks, Collections.emptyList()); + } + + protected static NodeBitMap computeNodes(Graph graph, Collection blocks, Collection earlyExits) { + final NodeBitMap nodes = graph.createNodeBitMap(true); + for (BeginNode b : blocks) { + for (Node n : b.getBlockNodes()) { + if (n instanceof Invoke) { + nodes.mark(((Invoke) n).callTarget()); + } + if (n instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) n).stateAfter(); + if (stateAfter != null) { + nodes.mark(stateAfter); + } + } + nodes.mark(n); + } + } + for (BeginNode earlyExit : earlyExits) { + FrameState stateAfter = earlyExit.stateAfter(); + if (stateAfter != null) { + nodes.mark(stateAfter); + stateAfter.applyToVirtual(new VirtualClosure() { + @Override + public void apply(VirtualState node) { + nodes.mark(node); + } + }); + } + nodes.mark(earlyExit); + for (ValueProxyNode proxy : earlyExit.proxies()) { + nodes.mark(proxy); + } + } + + for (BeginNode b : blocks) { + for (Node n : b.getBlockNodes()) { + for (Node usage : n.usages()) { + markFloating(usage, nodes); + } + } + } + + return nodes; + } + + private static boolean markFloating(Node n, NodeBitMap loopNodes) { + if (loopNodes.isMarked(n)) { + return true; + } + if (n instanceof FixedNode) { + return false; + } + boolean mark = false; + if (n instanceof PhiNode) { + PhiNode phi = (PhiNode) n; + mark = loopNodes.isMarked(phi.merge()); + if (mark) { + loopNodes.mark(n); + } else { + return false; + } + } + for (Node usage : n.usages()) { + if (markFloating(usage, loopNodes)) { + mark = true; + } + } + if (mark) { + loopNodes.mark(n); + return true; + } + return false; + } + + public static Collection toHirBlocks(Collection blocks) { + List hir = new ArrayList<>(blocks.size()); + for (Block b : blocks) { + hir.add(b.getBeginNode()); + } + return hir; + } + + /** + * Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with the original fragment's exits. + */ + protected void mergeEarlyExits() { + assert isDuplicate(); + StructuredGraph graph = graph(); + for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) { + FixedNode next = earlyExit.next(); + if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) { + continue; + } + BeginNode newEarlyExit = getDuplicatedNode(earlyExit); + if (newEarlyExit == null) { + continue; + } + MergeNode merge = graph.add(new MergeNode()); + merge.setProbability(next.probability()); + EndNode originalEnd = graph.add(new EndNode()); + EndNode newEnd = graph.add(new EndNode()); + merge.addForwardEnd(originalEnd); + merge.addForwardEnd(newEnd); + earlyExit.setNext(originalEnd); + newEarlyExit.setNext(newEnd); + merge.setNext(next); + + FrameState exitState = earlyExit.stateAfter(); + FrameState newExitState = newEarlyExit.stateAfter(); + FrameState state = null; + if (exitState != null) { + state = exitState.duplicateWithVirtualState(); + merge.setStateAfter(state); + } + + for (Node anchored : earlyExit.anchored().snapshot()) { + anchored.replaceFirstInput(earlyExit, merge); + } + + for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) { + final ValueNode replaceWith; + ValueProxyNode newVpn = getDuplicatedNode(vpn); + if (newVpn != null) { + PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge)); + phi.addInput(vpn); + phi.addInput(newVpn); + replaceWith = phi; + } else { + replaceWith = vpn.value(); + } + if (state != null) { + state.applyToNonVirtual(new NodeClosure() { + @Override + public void apply(Node from, ValueNode node) { + if (node == vpn) { + from.replaceFirstInput(vpn, replaceWith); + } + } + }); + } + for (Node usage : vpn.usages().snapshot()) { + if (!merge.isPhiAtMerge(usage)) { + if (usage instanceof VirtualState) { + VirtualState stateUsage = (VirtualState) usage; + if (exitState.isPartOfThisState(stateUsage) || newExitState.isPartOfThisState(stateUsage)) { + continue; + } + } + usage.replaceFirstInput(vpn, replaceWith); + } + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import java.util.*; + +import com.oracle.graal.graph.Graph.DuplicationReplacement; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.util.*; + + +public class LoopFragmentInside extends LoopFragment { + /** mergedInitializers. + * When an inside fragment's (loop)ends are merged to create a unique exit point, + * some phis must be created : they phis together all the back-values of the loop-phis + * These can then be used to update the loop-phis' forward edge value ('initializer') in the peeling case. + * In the unrolling case they will be used as the value that replace the loop-phis of the duplicated inside fragment + */ + private Map mergedInitializers; + private final DuplicationReplacement dataFixBefore = new DuplicationReplacement() { + @Override + public Node replacement(Node oriInput) { + if (!(oriInput instanceof ValueNode)) { + return oriInput; + } + return prim((ValueNode) oriInput); + } + }; + + public LoopFragmentInside(LoopEx loop) { + super(loop); + } + + public LoopFragmentInside(LoopFragmentInside original) { + super(null, original); + } + + @Override + public LoopFragmentInside duplicate() { + assert !isDuplicate(); + return new LoopFragmentInside(this); + } + + @Override + public LoopFragmentInside original() { + return (LoopFragmentInside) super.original(); + } + + @SuppressWarnings("unused") + public void appendInside(LoopEx loop) { + // TODO (gd) + } + + @Override + public LoopEx loop() { + assert !this.isDuplicate(); + return super.loop(); + } + + @Override + public void insertBefore(LoopEx loop) { + assert this.isDuplicate() && this.original().loop() == loop; + + patchNodes(dataFixBefore); + + BeginNode end = mergeEnds(); + + original().patchPeeling(this); + + mergeEarlyExits(); + + BeginNode entry = getDuplicatedNode(loop.loopBegin()); + FrameState state = entry.stateAfter(); + if (state != null) { + entry.setStateAfter(null); + GraphUtil.killWithUnusedFloatingInputs(state); + } + loop.entryPoint().replaceAtPredecessor(entry); + end.setProbability(loop.entryPoint().probability()); + end.setNext(loop.entryPoint()); + } + + @Override + public NodeIterable nodes() { + if (nodes == null) { + LoopFragmentWhole whole = loop().whole(); + whole.nodes(); // init nodes bitmap in whole + nodes = whole.nodes.copy(); + // remove the phis + for (PhiNode phi : loop().loopBegin().phis()) { + nodes.clear(phi); + } + } + return nodes; + } + + @Override + protected DuplicationReplacement getDuplicationReplacement() { + final LoopBeginNode loopBegin = loop().loopBegin(); + final StructuredGraph graph = graph(); + return new DuplicationReplacement() { + @Override + public Node replacement(Node original) { + if (original == loopBegin) { + return graph.add(new BeginNode()); + } + if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) { + return graph.add(new BeginNode()); + } + if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) { + return graph.add(new EndNode()); + } + return original; + } + }; + } + + @Override + protected void finishDuplication() { + // TODO (gd) ? + } + + private void patchPeeling(LoopFragmentInside peel) { + LoopBeginNode loopBegin = loop().loopBegin(); + StructuredGraph graph = (StructuredGraph) loopBegin.graph(); + List newPhis = new LinkedList<>(); + for (PhiNode phi : loopBegin.phis().snapshot()) { + ValueNode first; + if (loopBegin.loopEnds().count() == 1) { + ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value + first = peel.prim(b); // corresponding value in the peel + } else { + first = peel.mergedInitializers.get(phi); + } + // create a new phi (we don't patch the old one since some usages of the old one may still be valid) + PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin)); + newPhi.addInput(first); + for (LoopEndNode end : loopBegin.orderedLoopEnds()) { + newPhi.addInput(phi.valueAt(end)); + } + peel.putDuplicatedNode(phi, newPhi); + newPhis.add(newPhi); + for (Node usage : phi.usages().snapshot()) { + if (peel.getDuplicatedNode(usage) != null) { // patch only usages that should use the new phi ie usages that were peeled + usage.replaceFirstInput(phi, newPhi); + } + } + } + // check new phis to see if they have as input some old phis, replace those inputs with the new corresponding phis + for (PhiNode phi : newPhis) { + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode v = phi.valueAt(i); + if (loopBegin.isPhiAtMerge(v)) { + PhiNode newV = peel.getDuplicatedNode((PhiNode) v); + if (newV != null) { + phi.setValueAt(i, newV); + } + } + } + } + } + + /** + * Gets the corresponding value in this fragment. + * + * @param b original value + * @return corresponding value in the peel + */ + private ValueNode prim(ValueNode b) { + assert isDuplicate(); + LoopBeginNode loopBegin = original().loop().loopBegin(); + if (loopBegin.isPhiAtMerge(b)) { + PhiNode phi = (PhiNode) b; + return phi.valueAt(loopBegin.forwardEnd()); + } else if (nodesReady) { + ValueNode v = getDuplicatedNode(b); + if (v == null) { + return b; + } + return v; + } else { + return b; + } + } + + private BeginNode mergeEnds() { + assert isDuplicate(); + List endsToMerge = new LinkedList<>(); + Map reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits + LoopBeginNode loopBegin = original().loop().loopBegin(); + for (LoopEndNode le : loopBegin.loopEnds()) { + EndNode duplicate = getDuplicatedNode(le); + if (duplicate != null) { + endsToMerge.add(duplicate); + reverseEnds.put(duplicate, le); + } + } + mergedInitializers = new IdentityHashMap<>(); + BeginNode newExit; + StructuredGraph graph = graph(); + if (endsToMerge.size() == 1) { + EndNode end = endsToMerge.get(0); + assert end.usages().count() == 0; + newExit = graph.add(new BeginNode()); + end.replaceAtPredecessor(newExit); + end.safeDelete(); + } else { + assert endsToMerge.size() > 1; + MergeNode newExitMerge = graph.add(new MergeNode()); + newExit = newExitMerge; + FrameState state = loopBegin.stateAfter(); + FrameState duplicateState = null; + if (state != null) { + duplicateState = state.duplicateWithVirtualState(); + newExitMerge.setStateAfter(duplicateState); + } + for (EndNode end : endsToMerge) { + newExitMerge.addForwardEnd(end); + } + + for (final PhiNode phi : loopBegin.phis().snapshot()) { + final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge)); + for (EndNode end : newExitMerge.forwardEnds()) { + LoopEndNode loopEnd = reverseEnds.get(end); + ValueNode prim = prim(phi.valueAt(loopEnd)); + assert prim != null; + firstPhi.addInput(prim); + } + ValueNode initializer = firstPhi; + if (duplicateState != null) { + // fix the merge's state after + duplicateState.applyToNonVirtual(new NodeClosure() { + @Override + public void apply(Node from, ValueNode node) { + if (node == phi) { + from.replaceFirstInput(phi, firstPhi); + } + } + }); + } + mergedInitializers.put(phi, initializer); + } + } + return newExit; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; + + +public class LoopFragmentInsideBefore extends LoopFragmentInside { + private final FixedNode point; + + public LoopFragmentInsideBefore(LoopEx loop, FixedNode point) { + super(loop); + this.point = point; + } + + // duplicates lazily + public LoopFragmentInsideBefore(LoopFragmentInsideBefore original) { + super(original); + this.point = original.point(); + } + + public FixedNode point() { + return point; + } + + @Override + public LoopFragmentInsideBefore duplicate() { + return new LoopFragmentInsideBefore(this); + } + + @Override + public NodeIterable nodes() { + // TODO Auto-generated method stub + return null; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; + + +public class LoopFragmentInsideFrom extends LoopFragmentInside { + private final FixedNode point; + + public LoopFragmentInsideFrom(LoopEx loop, FixedNode point) { + super(loop); + this.point = point; + } + + // duplicates lazily + public LoopFragmentInsideFrom(LoopFragmentInsideFrom original) { + super(original); + this.point = original.point(); + } + + public FixedNode point() { + return point; + } + + @Override + public LoopFragmentInsideFrom duplicate() { + return new LoopFragmentInsideFrom(this); + } + + @Override + public NodeIterable nodes() { + // TODO Auto-generated method stub + return null; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.graph.Graph.DuplicationReplacement; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + + +public class LoopFragmentWhole extends LoopFragment { + + public LoopFragmentWhole(LoopEx loop) { + super(loop); + } + + public LoopFragmentWhole(LoopFragmentWhole original) { + super(null, original); + } + + @Override + public LoopFragmentWhole duplicate() { + LoopFragmentWhole loopFragmentWhole = new LoopFragmentWhole(this); + loopFragmentWhole.reify(); + return loopFragmentWhole; + } + + private void reify() { + assert this.isDuplicate(); + + patchNodes(null); + + mergeEarlyExits(); + } + + @Override + public NodeIterable nodes() { + if (nodes == null) { + Loop lirLoop = loop().lirLoop(); + nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.blocks), LoopFragment.toHirBlocks(lirLoop.exits)); + } + return nodes; + } + + @Override + protected DuplicationReplacement getDuplicationReplacement() { + final FixedNode entry = loop().entryPoint(); + final Graph graph = this.graph(); + return new DuplicationReplacement() { + @Override + public Node replacement(Node o) { + if (o == entry) { + return graph.add(new EndNode()); + } + return o; + } + }; + } + + public FixedNode entryPoint() { + if (isDuplicate()) { + LoopBeginNode newLoopBegin = getDuplicatedNode(original().loop().loopBegin()); + return newLoopBegin.forwardEnd(); + } + return loop().entryPoint(); + } + + @Override + protected void finishDuplication() { + // TODO (gd) ? + } + + @Override + public void insertBefore(LoopEx loop) { + // TODO Auto-generated method stub + + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopPolicies.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopPolicies.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + + +public abstract class LoopPolicies { + private LoopPolicies() { + // does not need to be instantiated + } + + // TODO (gd) change when inversion is available + public static boolean shouldPeel(LoopEx loop) { + LoopBeginNode loopBegin = loop.loopBegin(); + double entryProbability = loopBegin.forwardEnd().probability(); + return entryProbability > GraalOptions.MinimumPeelProbability && loop.size() + loopBegin.graph().getNodeCount() < GraalOptions.MaximumDesiredSize; + } + + public static boolean shouldFullUnroll(LoopEx loop) { + if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) { + return false; + } + CountedLoopInfo counted = loop.counted(); + long exactTrips = counted.constantMaxTripCount(); + int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? GraalOptions.ExactFullUnrollMaxNodes : GraalOptions.FullUnrollMaxNodes; + maxNodes = Math.min(maxNodes, GraalOptions.MaximumDesiredSize - loop.loopBegin().graph().getNodeCount()); + int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); + return size * exactTrips <= maxNodes; + } + + public static boolean shouldTryUnswitch(LoopEx loop) { + return loop.loopBegin().unswitches() <= GraalOptions.LoopMaxUnswitch; + } + + public static boolean shouldUnswitch(LoopEx loop, IfNode ifNode) { + Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(ifNode).getPostdominator(); + BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null; + int inTrueBranch = loop.nodesInLoopFrom(ifNode.trueSuccessor(), postDom).cardinality(); + int inFalseBranch = loop.nodesInLoopFrom(ifNode.falseSuccessor(), postDom).cardinality(); + int loopTotal = loop.size(); + int netDiff = loopTotal - (inTrueBranch + inFalseBranch); + double uncertainty = (0.5 - Math.abs(ifNode.probability(IfNode.TRUE_EDGE) - 0.5)) * 2; + int maxDiff = GraalOptions.LoopUnswitchMaxIncrease + (int) (GraalOptions.LoopUnswitchUncertaintyBoost * loop.loopBegin().loopFrequency() * uncertainty); + Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of if", loop, ifNode, netDiff, maxDiff, (double) (inTrueBranch + inFalseBranch) / loopTotal * 100); + return netDiff <= maxDiff; + } + + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopTransformations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopTransformations.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; + + +public abstract class LoopTransformations { + private static final int UNROLL_LIMIT = GraalOptions.FullUnrollMaxNodes * 2; + private static final SimplifierTool simplifier = new SimplifierTool() { + @Override + public TargetDescription target() { + return null; + } + @Override + public CodeCacheProvider runtime() { + return null; + } + @Override + public boolean isImmutable(Constant objectConstant) { + return false; + } + @Override + public Assumptions assumptions() { + return null; + } + @Override + public void deleteBranch(FixedNode branch) { + branch.predecessor().replaceFirstSuccessor(branch, null); + GraphUtil.killCFG(branch); + } + @Override + public void addToWorkList(Node node) { + } + }; + + private LoopTransformations() { + // does not need to be instantiated + } + + public static void invert(LoopEx loop, FixedNode point) { + LoopFragmentInsideBefore head = loop.insideBefore(point); + LoopFragmentInsideBefore duplicate = head.duplicate(); + head.disconnect(); + head.insertBefore(loop); + duplicate.appendInside(loop); + } + + public static void peel(LoopEx loop) { + loop.inside().duplicate().insertBefore(loop); + } + + public static void fullUnroll(LoopEx loop, MetaAccessProvider runtime) { + //assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count + int iterations = 0; + LoopBeginNode loopBegin = loop.loopBegin(); + StructuredGraph graph = (StructuredGraph) loopBegin.graph(); + while (!loopBegin.isDeleted()) { + int mark = graph.getMark(); + peel(loop); + new CanonicalizerPhase(null, runtime, null, mark, null).apply(graph); + if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > GraalOptions.MaximumDesiredSize * 3) { + throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); + } + } + } + + public static void unswitch(LoopEx loop, IfNode ifNode) { + // duplicate will be true case, original will be false case + loop.loopBegin().incUnswitches(); + LoopFragmentWhole originalLoop = loop.whole(); + LoopFragmentWhole duplicateLoop = originalLoop.duplicate(); + StructuredGraph graph = (StructuredGraph) ifNode.graph(); + BeginNode tempBegin = graph.add(new BeginNode()); + originalLoop.entryPoint().replaceAtPredecessor(tempBegin); + double takenProbability = ifNode.probability(ifNode.blockSuccessorIndex(ifNode.trueSuccessor())); + IfNode newIf = graph.add(new IfNode(ifNode.compare(), duplicateLoop.entryPoint(), originalLoop.entryPoint(), takenProbability, ifNode.leafGraphId())); + tempBegin.setNext(newIf); + ifNode.setCompare(graph.unique(ConstantNode.forBoolean(false, graph))); + IfNode duplicateIf = duplicateLoop.getDuplicatedNode(ifNode); + duplicateIf.setCompare(graph.unique(ConstantNode.forBoolean(true, graph))); + ifNode.simplify(simplifier); + duplicateIf.simplify(simplifier); + // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) + } + + public static void unroll(LoopEx loop, int factor) { + assert loop.isCounted(); + if (factor > 0) { + throw new UnsupportedOperationException(); + } + // TODO (gd) implement counted loop + LoopFragmentWhole main = loop.whole(); + LoopFragmentWhole prologue = main.duplicate(); + prologue.insertBefore(loop); + //CountedLoopBeginNode counted = prologue.countedLoop(); + //StructuredGraph graph = (StructuredGraph) counted.graph(); + //ValueNode tripCountPrologue = counted.tripCount(); + //ValueNode tripCountMain = counted.tripCount(); + //graph.replaceFloating(tripCountPrologue, "tripCountPrologue % factor"); + //graph.replaceFloating(tripCountMain, "tripCountMain - (tripCountPrologue % factor)"); + LoopFragmentInside inside = loop.inside(); + for (int i = 0; i < factor; i++) { + inside.duplicate().appendInside(loop); + } + } + + public static IfNode findUnswitchableIf(LoopEx loop) { + for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) { + if (loop.isOutsideLoop(ifNode.compare())) { + return ifNode; + } + } + return null; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopsData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/loop/LoopsData.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.loop; + +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.compiler.loop.InductionVariable.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; + +public class LoopsData { + private Map lirLoopToEx = new IdentityHashMap<>(); + private Map loopBeginToEx = new IdentityHashMap<>(); + private ControlFlowGraph cfg; + + public LoopsData(final StructuredGraph graph) { + + cfg = Debug.scope("ControlFlowGraph", new Callable() { + @Override + public ControlFlowGraph call() throws Exception { + return ControlFlowGraph.compute(graph, true, true, true, true); + } + }); + for (Loop lirLoop : cfg.getLoops()) { + LoopEx ex = new LoopEx(lirLoop, this); + lirLoopToEx.put(lirLoop, ex); + loopBeginToEx.put(ex.loopBegin(), ex); + } + } + + public LoopEx loop(Loop lirLoop) { + return lirLoopToEx.get(lirLoop); + } + + public LoopEx loop(LoopBeginNode loopBegin) { + return loopBeginToEx.get(loopBegin); + } + + public Collection loops() { + return lirLoopToEx.values(); + } + + public List outterFirst() { + ArrayList loops = new ArrayList<>(loops()); + Collections.sort(loops, new Comparator() { + @Override + public int compare(LoopEx o1, LoopEx o2) { + return o1.lirLoop().depth - o2.lirLoop().depth; + } + }); + return loops; + } + + public Collection countedLoops() { + List counted = new LinkedList<>(); + for (LoopEx loop : loops()) { + if (loop.isCounted()) { + counted.add(loop); + } + } + return counted; + } + + public void detectedCountedLoops() { + for (LoopEx loop : loops()) { + InductionVariables ivs = new InductionVariables(loop); + LoopBeginNode loopBegin = loop.loopBegin(); + FixedNode next = loopBegin.next(); + if (next instanceof IfNode) { + IfNode ifNode = (IfNode) next; + boolean negated = false; + if (!loopBegin.isLoopExit(ifNode.falseSuccessor())) { + if (!loopBegin.isLoopExit(ifNode.trueSuccessor())) { + continue; + } + negated = true; + } + BooleanNode ifTest = ifNode.compare(); + if (!(ifTest instanceof IntegerLessThanNode)) { + if (ifTest instanceof IntegerBelowThanNode) { + Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin); + } + continue; + } + IntegerLessThanNode lessThan = (IntegerLessThanNode) ifTest; + Condition condition = null; + InductionVariable iv = null; + ValueNode limit = null; + if (loop.isOutsideLoop(lessThan.x())) { + iv = ivs.get(lessThan.y()); + if (iv != null) { + condition = lessThan.condition().mirror(); + limit = lessThan.x(); + } + } else if (loop.isOutsideLoop(lessThan.y())) { + iv = ivs.get(lessThan.x()); + if (iv != null) { + condition = lessThan.condition(); + limit = lessThan.y(); + } + } + if (condition == null) { + continue; + } + if (negated) { + condition = condition.negate(); + } + boolean oneOff = false; + switch (condition) { + case LE: + oneOff = true; // fall through + case LT: + if (iv.direction() != Direction.Up) { + continue; + } + break; + case GE: + oneOff = true; // fall through + case GT: + if (iv.direction() != Direction.Down) { + continue; + } + break; + default: throw GraalInternalError.shouldNotReachHere(); + } + loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff)); + } + } + } + + public ControlFlowGraph controlFlowGraph() { + return cfg; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import static com.oracle.graal.graph.iterators.NodePredicates.*; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; + +public class BoxingEliminationPhase extends Phase { + + private int virtualIds = Integer.MIN_VALUE; + + @Override + protected void run(StructuredGraph graph) { + if (graph.getNodes(UnboxNode.class).isNotEmpty()) { + + Map phiReplacements = new HashMap<>(); + for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { + tryEliminate(graph, unboxNode, phiReplacements); + } + + new DeadCodeEliminationPhase().apply(graph); + + for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { + tryEliminate(boxNode); + } + } + } + + private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map phiReplacements) { + ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements); + if (unboxedValue != null) { + assert unboxedValue.kind() == unboxNode.kind(); + unboxNode.replaceAtUsages(unboxedValue); + graph.removeFixed(unboxNode); + } + } + + private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map phiReplacements) { + if (!phiReplacements.containsKey(phiNode)) { + PhiNode result = null; + ObjectStamp stamp = phiNode.objectStamp(); + if (stamp.nonNull() && stamp.isExactType()) { + ResolvedJavaType type = stamp.type(); + if (type != null && type.toJava() == kind.toBoxedJavaClass()) { + StructuredGraph graph = (StructuredGraph) phiNode.graph(); + result = graph.add(new PhiNode(kind, phiNode.merge())); + phiReplacements.put(phiNode, result); + virtualizeUsages(phiNode, result, type); + int i = 0; + for (ValueNode n : phiNode.values()) { + ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements); + if (unboxedValue != null) { + assert unboxedValue.kind() == kind; + result.addInput(unboxedValue); + } else { + UnboxNode unboxNode = graph.add(new UnboxNode(kind, n)); + FixedNode pred = phiNode.merge().phiPredecessorAt(i); + graph.addBeforeFixed(pred, unboxNode); + result.addInput(unboxNode); + } + ++i; + } + } + } + } + return phiReplacements.get(phiNode); + } + + private ValueNode unboxedValue(ValueNode n, Kind kind, Map phiReplacements) { + if (n instanceof BoxNode) { + BoxNode boxNode = (BoxNode) n; + return boxNode.source(); + } else if (n instanceof PhiNode) { + PhiNode phiNode = (PhiNode) n; + return getReplacementPhi(phiNode, kind, phiReplacements); + } else { + return null; + } + } + + private void tryEliminate(BoxNode boxNode) { + + assert boxNode.objectStamp().isExactType(); + virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type()); + + if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { + // Elimination failed, because boxing object escapes. + return; + } + + FrameState stateAfter = boxNode.stateAfter(); + boxNode.setStateAfter(null); + stateAfter.safeDelete(); + + ((StructuredGraph) boxNode.graph()).removeFixed(boxNode); + } + + private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) { + ValueNode virtualValueNode = null; + VirtualObjectNode virtualObjectNode = null; + for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { + if (virtualValueNode == null) { + virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement)); + } + n.replaceFirstInput(boxNode, virtualObjectNode); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +public class CanonicalizerPhase extends Phase { + private static final int MAX_ITERATION_PER_NODE = 10; + private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes"); + private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes"); + private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled"); + private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged"); + private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes"); + public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); + + private final int newNodesMark; + private final TargetDescription target; + private final Assumptions assumptions; + private final MetaAccessProvider runtime; + private final IsImmutablePredicate immutabilityPredicate; + private final Iterable initWorkingSet; + + private NodeWorkList workList; + private Tool tool; + private List snapshotTemp; + + public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { + this(target, runtime, assumptions, null, 0, null); + } + + /** + * @param target + * @param runtime + * @param assumptions + * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap + * @param immutabilityPredicate + */ + public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, IsImmutablePredicate immutabilityPredicate) { + this(target, runtime, assumptions, workingSet, 0, immutabilityPredicate); + } + + /** + * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by + * this mark are processed otherwise all nodes in the graph are processed + */ + public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { + this(target, runtime, assumptions, null, newNodesMark, immutabilityPredicate); + } + + private CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { + this.newNodesMark = newNodesMark; + this.target = target; + this.assumptions = assumptions; + this.runtime = runtime; + this.immutabilityPredicate = immutabilityPredicate; + this.initWorkingSet = workingSet; + this.snapshotTemp = new ArrayList<>(); + } + + @Override + protected void run(StructuredGraph graph) { + if (initWorkingSet == null) { + workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); + if (newNodesMark > 0) { + workList.addAll(graph.getNewNodes(newNodesMark)); + } + } else { + workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); + workList.addAll(initWorkingSet); + } + tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate); + processWorkSet(graph); + } + + public interface IsImmutablePredicate { + /** + * Determines if a given constant is an object/array whose current + * fields/elements will never change. + */ + boolean apply(Constant constant); + } + + private void processWorkSet(StructuredGraph graph) { + graph.trackInputChange(new InputChangedListener() { + @Override + public void inputChanged(Node node) { + workList.addAgain(node); + } + }); + + for (Node n : workList) { + processNode(n, graph); + } + + graph.stopTrackingInputChange(); + } + + private void processNode(Node node, StructuredGraph graph) { + if (node.isAlive()) { + METRIC_PROCESSED_NODES.increment(); + + if (tryGlobalValueNumbering(node, graph)) { + return; + } + int mark = graph.getMark(); + if (!tryKillUnused(node)) { + node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); + if (!tryCanonicalize(node, graph, tool)) { + tryInferStamp(node, graph); + } else { + for (Node in : snapshotTemp) { + if (in.isAlive() && in.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(in); + } + } + } + snapshotTemp.clear(); + } + + for (Node newNode : graph.getNewNodes(mark)) { + workList.add(newNode); + } + } + } + + private static boolean tryKillUnused(Node node) { + if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(node); + return true; + } + return false; + } + + public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { + if (node.getNodeClass().valueNumberable()) { + Node newNode = graph.findDuplicate(node); + if (newNode != null) { + assert !(node instanceof FixedNode || newNode instanceof FixedNode); + node.replaceAtUsages(newNode); + node.safeDelete(); + METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment(); + Debug.log("GVN applied and new node is %1s", newNode); + return true; + } + } + return false; + } + + public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) { + if (node instanceof Canonicalizable) { + assert !(node instanceof Simplifiable); + METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); + return Debug.scope("CanonicalizeNode", node, new Callable(){ + public Boolean call() { + ValueNode canonical = ((Canonicalizable) node).canonical(tool); +// cases: original node: +// |Floating|Fixed-unconnected|Fixed-connected| +// -------------------------------------------- +// null| 1 | X | 3 | +// -------------------------------------------- +// Floating| 2 | X | 4 | +// canonical node: -------------------------------------------- +// Fixed-unconnected| X | X | 5 | +// -------------------------------------------- +// Fixed-connected| 2 | X | 6 | +// -------------------------------------------- +// X: must not happen (checked with assertions) + if (canonical == node) { + Debug.log("Canonicalizer: work on %s", node); + return false; + } else { + Debug.log("Canonicalizer: replacing %s with %s", node, canonical); + METRIC_CANONICALIZED_NODES.increment(); + if (node instanceof FloatingNode) { + if (canonical == null) { + // case 1 + graph.removeFloating((FloatingNode) node); + } else { + // case 2 + assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical + + " : replacement should be floating or fixed and connected"; + graph.replaceFloating((FloatingNode) node, canonical); + } + } else { + assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")"; + if (canonical == null) { + // case 3 + graph.removeFixed((FixedWithNextNode) node); + } else if (canonical instanceof FloatingNode) { + // case 4 + graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical); + } else { + assert canonical instanceof FixedNode; + if (canonical.predecessor() == null) { + assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors"; + // case 5 + graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical); + } else { + assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors"; + // case 6 + node.replaceAtUsages(canonical); + graph.removeFixed((FixedWithNextNode) node); + } + } + } + return true; + } + } + }); + } else if (node instanceof Simplifiable) { + Debug.log("Canonicalizer: simplifying %s", node); + METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); + ((Simplifiable) node).simplify(tool); + } + return node.isDeleted(); + } + + /** + * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has + * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp + * now describes a constant integer value, in which case the node is replaced with a constant. + */ + private void tryInferStamp(Node node, StructuredGraph graph) { + if (node.isAlive() && node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + METRIC_INFER_STAMP_CALLED.increment(); + if (valueNode.inferStamp()) { + METRIC_STAMP_CHANGED.increment(); + if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) { + ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph); + Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement); + valueNode.replaceAtUsages(replacement); + } else { + for (Node usage : valueNode.usages()) { + workList.addAgain(usage); + } + } + } + } + } + + private static final class Tool implements SimplifierTool { + + private final NodeWorkList nodeWorkSet; + private final MetaAccessProvider runtime; + private final TargetDescription target; + private final Assumptions assumptions; + private final IsImmutablePredicate immutabilityPredicate; + + public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions, IsImmutablePredicate immutabilityPredicate) { + this.nodeWorkSet = nodeWorkSet; + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + this.immutabilityPredicate = immutabilityPredicate; + } + + @Override + public void deleteBranch(FixedNode branch) { + branch.predecessor().replaceFirstSuccessor(branch, null); + GraphUtil.killCFG(branch); + } + + /** + * @return the current target or {@code null} if no target is available in the current context. + */ + @Override + public TargetDescription target() { + return target; + } + + /** + * @return an object that can be used for recording assumptions or {@code null} if assumptions are not allowed in the current context. + */ + @Override + public Assumptions assumptions() { + return assumptions; + } + + @Override + public MetaAccessProvider runtime() { + return runtime; + } + + @Override + public void addToWorkList(Node node) { + nodeWorkSet.add(node); + } + + @Override + public boolean isImmutable(Constant objectConstant) { + return immutabilityPredicate != null && immutabilityPredicate.apply(objectConstant); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,394 @@ +/* + * 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.phases; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.graph.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +public class CheckCastEliminationPhase extends Phase { + + private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered"); + private static final DebugMetric metricIsTypeRegistered = Debug.metric("IsTypeRegistered"); + private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered"); + private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved"); + private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); + private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); + private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved"); + private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced"); + + private StructuredGraph graph; + + @Override + protected void run(StructuredGraph inputGraph) { + graph = inputGraph; + new EliminateCheckCasts(graph.start(), new State()).apply(); + } + + public static class State implements MergeableState { + + private IdentityHashMap knownTypes; + private HashSet knownNotNull; + private HashSet knownNull; + private IdentityHashMap trueConditions; + private IdentityHashMap falseConditions; + + public State() { + this.knownTypes = new IdentityHashMap<>(); + this.knownNotNull = new HashSet<>(); + this.knownNull = new HashSet<>(); + this.trueConditions = new IdentityHashMap<>(); + this.falseConditions = new IdentityHashMap<>(); + } + + public State(State other) { + this.knownTypes = new IdentityHashMap<>(other.knownTypes); + this.knownNotNull = new HashSet<>(other.knownNotNull); + this.knownNull = new HashSet<>(other.knownNull); + this.trueConditions = new IdentityHashMap<>(other.trueConditions); + this.falseConditions = new IdentityHashMap<>(other.falseConditions); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + IdentityHashMap newKnownTypes = new IdentityHashMap<>(); + HashSet newKnownNotNull = new HashSet<>(); + HashSet newKnownNull = new HashSet<>(); + IdentityHashMap newTrueConditions = new IdentityHashMap<>(); + IdentityHashMap newFalseConditions = new IdentityHashMap<>(); + + for (Map.Entry entry : knownTypes.entrySet()) { + ValueNode node = entry.getKey(); + ResolvedJavaType type = entry.getValue(); + + for (State other : withStates) { + ResolvedJavaType otherType = other.getNodeType(node); + type = widen(type, otherType); + if (type == null) { + break; + } + } + if (type == null && type != node.objectStamp().type()) { + newKnownTypes.put(node, type); + } + } + for (ValueNode node : knownNotNull) { + boolean notNull = true; + for (State other : withStates) { + if (!other.knownNotNull.contains(node)) { + notNull = false; + break; + } + } + if (notNull) { + newKnownNotNull.add(node); + } + } + for (ValueNode node : knownNull) { + boolean nul = true; + for (State other : withStates) { + if (!other.knownNull.contains(node)) { + nul = false; + break; + } + } + if (nul) { + newKnownNull.add(node); + } + } + for (Map.Entry entry : trueConditions.entrySet()) { + BooleanNode check = entry.getKey(); + ValueNode guard = entry.getValue(); + + for (State other : withStates) { + ValueNode otherGuard = other.trueConditions.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newTrueConditions.put(check, guard); + } + } + for (Map.Entry entry : falseConditions.entrySet()) { + BooleanNode check = entry.getKey(); + ValueNode guard = entry.getValue(); + + for (State other : withStates) { + ValueNode otherGuard = other.falseConditions.get(check); + if (otherGuard == null) { + guard = null; + break; + } + if (otherGuard != guard) { + guard = merge; + } + } + if (guard != null) { + newFalseConditions.put(check, guard); + } + } + + /* + // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values) + if (!(merge instanceof LoopBeginNode)) { + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) { + ValueNode firstValue = phi.valueAt(0); + ResolvedJavaType type = getNodeType(firstValue); + boolean notNull = knownNotNull.contains(firstValue); + boolean nul = knownNull.contains(firstValue); + + for (int i = 0; i < withStates.size(); i++) { + State otherState = withStates.get(i); + ValueNode value = phi.valueAt(i + 1); + ResolvedJavaType otherType = otherState.getNodeType(value); + type = widen(type, otherType); + notNull &= otherState.knownNotNull.contains(value); + nul &= otherState.knownNull.contains(value); + } + if (type == null && type != phi.declaredType()) { + newKnownTypes.put(phi, type); + } + if (notNull) { + newKnownNotNull.add(phi); + } + if (nul) { + newKnownNull.add(phi); + } + } + } + } + */ + this.knownTypes = newKnownTypes; + this.knownNotNull = newKnownNotNull; + this.knownNull = newKnownNull; + this.trueConditions = newTrueConditions; + this.falseConditions = newFalseConditions; + return true; + } + + public ResolvedJavaType getNodeType(ValueNode node) { + ResolvedJavaType result = knownTypes.get(node); + return result == null ? node.objectStamp().type() : result; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + } + + @Override + public void afterSplit(FixedNode node) { + } + + @Override + public State clone() { + return new State(this); + } + } + + public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { + if (a == null || b == null) { + return null; + } else if (a == b) { + return a; + } else { + return a.leastCommonAncestor(b); + } + } + + public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) { + if (a == null) { + return b; + } else if (b == null) { + return a; + } else if (a == b) { + return a; + } else if (a.isSubtypeOf(b)) { + return a; + } else if (b.isSubtypeOf(a)) { + return b; + } else { + return a; + } + } + + public class EliminateCheckCasts extends PostOrderNodeIterator { + private BeginNode lastBegin = null; + + public EliminateCheckCasts(FixedNode start, State initialState) { + super(start, initialState); + } + + @Override + protected void node(FixedNode node) { + if (node instanceof BeginNode) { + BeginNode begin = (BeginNode) node; + lastBegin = begin; + Node pred = node.predecessor(); + if (pred != null && pred instanceof IfNode) { + IfNode ifNode = (IfNode) pred; + if (!(ifNode.compare() instanceof ConstantNode)) { + boolean isTrue = (node == ifNode.trueSuccessor()); + if (isTrue) { + state.trueConditions.put(ifNode.compare(), begin); + } else { + state.falseConditions.put(ifNode.compare(), begin); + } + } + if (ifNode.compare() instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare(); + if ((node == ifNode.trueSuccessor())) { + ValueNode object = instanceOf.object(); + state.knownNotNull.add(object); + state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object))); + metricInstanceOfRegistered.increment(); + } + } else if (ifNode.compare() instanceof IsNullNode) { + IsNullNode nullCheck = (IsNullNode) ifNode.compare(); + boolean isNull = (node == ifNode.trueSuccessor()); + if (isNull) { + state.knownNull.add(nullCheck.object()); + } else { + state.knownNotNull.add(nullCheck.object()); + } + metricNullCheckRegistered.increment(); + } else if (ifNode.compare() instanceof IsTypeNode) { + IsTypeNode isType = (IsTypeNode) ifNode.compare(); + if (isType.objectClass() instanceof ReadHubNode && (node == ifNode.trueSuccessor())) { + ReadHubNode readHub = (ReadHubNode) isType.objectClass(); + ValueNode object = readHub.object(); + state.knownNotNull.add(object); + state.knownTypes.put(object, tighten(isType.type(), state.getNodeType(object))); + metricIsTypeRegistered.increment(); + } + } + } + for (GuardNode guard : begin.guards().snapshot()) { + BooleanNode condition = guard.condition(); + ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition); + if (existingGuards != null) { + guard.replaceAtUsages(existingGuards); + GraphUtil.killWithUnusedFloatingInputs(guard); + metricGuardsReplaced.increment(); + } else { + boolean removeCheck = false; + if (condition instanceof IsNullNode) { + IsNullNode isNull = (IsNullNode) condition; + if (guard.negated() && state.knownNotNull.contains(isNull.object())) { + removeCheck = true; + } else if (!guard.negated() && state.knownNull.contains(isNull.object())) { + removeCheck = true; + } + if (removeCheck) { + metricNullCheckGuardRemoved.increment(); + } + } + if (removeCheck) { + guard.replaceAtUsages(begin); + GraphUtil.killWithUnusedFloatingInputs(guard); + } else { + if (guard.negated()) { + state.falseConditions.put(condition, guard); + } else { + state.trueConditions.put(condition, guard); + } + } + } + } + } else if (node instanceof CheckCastNode) { + CheckCastNode checkCast = (CheckCastNode) node; + ResolvedJavaType type = state.getNodeType(checkCast.object()); + if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) { + PiNode piNode; + boolean nonNull = state.knownNotNull.contains(checkCast.object()); + piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type))); + checkCast.replaceAtUsages(piNode); + graph.removeFixed(checkCast); + metricCheckCastRemoved.increment(); + } + } else if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + BooleanNode replaceWith = null; + BooleanNode compare = ifNode.compare(); + + if (state.trueConditions.containsKey(compare)) { + replaceWith = ConstantNode.forBoolean(true, graph); + } else if (state.falseConditions.containsKey(compare)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } else { + if (compare instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) compare; + ValueNode object = instanceOf.object(); + if (state.knownNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } else if (state.knownNotNull.contains(object)) { + ResolvedJavaType type = state.getNodeType(object); + if (type != null && type.isSubtypeOf(instanceOf.targetClass())) { + replaceWith = ConstantNode.forBoolean(true, graph); + } + } + if (replaceWith != null) { + metricInstanceOfRemoved.increment(); + } + } else if (compare instanceof IsNullNode) { + IsNullNode isNull = (IsNullNode) compare; + ValueNode object = isNull.object(); + if (state.knownNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(true, graph); + } else if (state.knownNotNull.contains(object)) { + replaceWith = ConstantNode.forBoolean(false, graph); + } + if (replaceWith != null) { + metricNullCheckRemoved.increment(); + } + } + } + if (replaceWith != null) { + ifNode.setCompare(replaceWith); + if (compare.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(compare); + } + } + } + } + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.graph.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +public class ComputeProbabilityPhase extends Phase { + private static final double EPSILON = 1d / Integer.MAX_VALUE; + + /* + * The computation of absolute probabilities works in three steps: + * + * - The first step, "PropagateProbability", traverses the graph in post order (merges after their ends, ...) and keeps track of the "probability state". + * Whenever it encounters a ControlSplit it uses the split's probability information to divide the probability upon the successors. + * Whenever it encounters an Invoke it assumes that the exception edge is unlikely and propagates the whole probability to the normal successor. + * Whenever it encounters a Merge it sums up the probability of all predecessors. + * It also maintains a set of active loops (whose LoopBegin has been visited) and builds def/use information for the second step. + * + * - The third step propagates the loop frequencies and multiplies each FixedNode's probability with its loop frequency. + * + * TODO: add exception probability information to Invokes + */ + + @Override + protected void run(StructuredGraph graph) { + new PropagateProbability(graph.start()).apply(); + Debug.dump(graph, "After PropagateProbability"); + computeLoopFactors(); + Debug.dump(graph, "After computeLoopFactors"); + new PropagateLoopFrequency(graph.start()).apply(); + + if (GraalOptions.LoopFrequencyPropagationPolicy < 0) { + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + BitSet visitedBlocks = new BitSet(cfg.getBlocks().length); + for (Loop loop : cfg.getLoops()) { + if (loop.parent == null) { + correctLoopFrequencies(loop, 1, visitedBlocks); + } + } + } + } + + private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) { + LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode()); + double frequency = parentFrequency * loopBegin.loopFrequency(); + for (Loop child : loop.children) { + correctLoopFrequencies(child, frequency, visitedBlocks); + } + + double factor = getCorrectionFactor(loopBegin.probability(), frequency); + for (Block block : loop.blocks) { + int blockId = block.getId(); + if (!visitedBlocks.get(blockId)) { + visitedBlocks.set(blockId); + + FixedNode node = block.getBeginNode(); + while (node != block.getEndNode()) { + node.setProbability(node.probability() * factor); + node = ((FixedWithNextNode) node).next(); + } + node.setProbability(node.probability() * factor); + } + } + } + + private static double getCorrectionFactor(double probability, double frequency) { + switch (GraalOptions.LoopFrequencyPropagationPolicy) { + case -1: + return 1 / frequency; + case -2: + return (1 / frequency) * (Math.log(Math.E + frequency) - 1); + case -3: + double originalProbability = probability / frequency; + assert isRelativeProbability(originalProbability); + return (1 / frequency) * Math.max(1, Math.pow(originalProbability, 1.5) * Math.log10(frequency)); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private void computeLoopFactors() { + for (LoopInfo info : loopInfos) { + double frequency = info.loopFrequency(); + assert frequency != -1; + } + } + + private static boolean isRelativeProbability(double prob) { + // 1.01 to allow for some rounding errors + return prob >= 0 && prob <= 1.01; + } + + public static class LoopInfo { + public final LoopBeginNode loopBegin; + + public final NodeMap> requires; + + private double loopFrequency = -1; + public boolean ended = false; + + public LoopInfo(LoopBeginNode loopBegin) { + this.loopBegin = loopBegin; + this.requires = loopBegin.graph().createNodeMap(); + } + + public double loopFrequency() { + if (loopFrequency == -1 && ended) { + double backEdgeProb = 0.0; + for (LoopEndNode le : loopBegin.loopEnds()) { + double factor = 1; + Set requireds = requires.get(le); + for (LoopInfo required : requireds) { + double t = required.loopFrequency(); + if (t == -1) { + return -1; + } + factor *= t; + } + backEdgeProb += le.probability() * factor; + } + double d = loopBegin.probability() - backEdgeProb; + if (d < EPSILON) { + d = EPSILON; + } + loopFrequency = loopBegin.probability() / d; + loopBegin.setLoopFrequency(loopFrequency); + } + return loopFrequency; + } + } + + public Set loopInfos = new HashSet<>(); + public Map> mergeLoops = new IdentityHashMap<>(); + + private class Probability implements MergeableState { + public double probability; + public HashSet loops; + public LoopInfo loopInfo; + + public Probability(double probability, HashSet loops) { + this.probability = probability; + this.loops = new HashSet<>(4); + if (loops != null) { + this.loops.addAll(loops); + } + } + + @Override + public Probability clone() { + return new Probability(probability, loops); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + if (merge.forwardEndCount() > 1) { + HashSet intersection = new HashSet<>(loops); + for (Probability other : withStates) { + intersection.retainAll(other.loops); + } + for (LoopInfo info : loops) { + if (!intersection.contains(info)) { + double loopFrequency = info.loopFrequency(); + if (loopFrequency == -1) { + return false; + } + probability *= loopFrequency; + } + } + for (Probability other : withStates) { + double prob = other.probability; + for (LoopInfo info : other.loops) { + if (!intersection.contains(info)) { + double loopFrequency = info.loopFrequency(); + if (loopFrequency == -1) { + return false; + } + prob *= loopFrequency; + } + } + probability += prob; + } + loops = intersection; + mergeLoops.put(merge, new HashSet<>(intersection)); + assert isRelativeProbability(probability) : probability; + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + loopInfo = new LoopInfo(loopBegin); + loopInfos.add(loopInfo); + loops.add(loopInfo); + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + assert loopInfo != null; + List loopEnds = loopBegin.orderedLoopEnds(); + int i = 0; + for (Probability proba : loopEndStates) { + LoopEndNode loopEnd = loopEnds.get(i++); + Set requires = loopInfo.requires.get(loopEnd); + if (requires == null) { + requires = new HashSet<>(); + loopInfo.requires.set(loopEnd, requires); + } + for (LoopInfo innerLoop : proba.loops) { + if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) { + requires.add(innerLoop); + } + } + } + loopInfo.ended = true; + } + + @Override + public void afterSplit(FixedNode node) { + assert node.predecessor() != null; + Node pred = node.predecessor(); + if (pred instanceof Invoke) { + Invoke x = (Invoke) pred; + if (x.next() != node) { + probability = 0; + } + } else { + assert pred instanceof ControlSplitNode; + ControlSplitNode x = (ControlSplitNode) pred; + double sum = 0; + for (int i = 0; i < x.blockSuccessorCount(); i++) { + if (x.blockSuccessor(i) == node) { + sum += x.probability(i); + } + } + probability *= sum; + } + } + } + + private class PropagateProbability extends PostOrderNodeIterator { + + public PropagateProbability(FixedNode start) { + super(start, new Probability(1d, null)); + } + + @Override + protected void node(FixedNode node) { + node.setProbability(state.probability); + } + } + + private class LoopCount implements MergeableState { + public double count; + + public LoopCount(double count) { + this.count = count; + } + + @Override + public LoopCount clone() { + return new LoopCount(count); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + assert merge.forwardEndCount() == withStates.size() + 1; + if (merge.forwardEndCount() > 1) { + Set loops = mergeLoops.get(merge); + assert loops != null; + double countProd = 1; + for (LoopInfo loop : loops) { + countProd *= loop.loopFrequency(); + } + count = countProd; + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + count *= loopBegin.loopFrequency(); + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + // nothing to do... + } + + @Override + public void afterSplit(FixedNode node) { + // nothing to do... + } + } + + private class PropagateLoopFrequency extends PostOrderNodeIterator { + + private final FrequencyPropagationPolicy policy; + + public PropagateLoopFrequency(FixedNode start) { + super(start, new LoopCount(1d)); + this.policy = createFrequencyPropagationPolicy(); + } + + @Override + protected void node(FixedNode node) { + node.setProbability(policy.compute(node.probability(), state.count)); + } + + } + + private static FrequencyPropagationPolicy createFrequencyPropagationPolicy() { + switch (GraalOptions.LoopFrequencyPropagationPolicy) { + case -3: + case -2: + case -1: + case 0: + return new FullFrequencyPropagation(); + case 1: + return new NoFrequencyPropagation(); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private interface FrequencyPropagationPolicy { + + double compute(double probability, double frequency); + } + + private static class FullFrequencyPropagation implements FrequencyPropagationPolicy { + + @Override + public double compute(double probability, double frequency) { + return probability * frequency; + } + } + + private static class NoFrequencyPropagation implements FrequencyPropagationPolicy { + + @Override + public double compute(double probability, double frequency) { + return probability; + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; + +public class ConvertDeoptimizeToGuardPhase extends Phase { + + private static BeginNode findBeginNode(Node startNode) { + Node n = startNode; + while (true) { + if (n instanceof BeginNode) { + return (BeginNode) n; + } else { + n = n.predecessor(); + } + } + } + + @Override + protected void run(final StructuredGraph graph) { + if (graph.getNodes(DeoptimizeNode.class).isEmpty()) { + return; + } + + for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) { + visitDeoptBegin(findBeginNode(d), d, graph); + } + + new DeadCodeEliminationPhase().apply(graph); + } + + private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) { + if (deoptBegin instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) deoptBegin; + Debug.log("Visiting %s followed by %s", mergeNode, deopt); + List ends = mergeNode.forwardEnds().snapshot(); + for (EndNode end : ends) { + if (!end.isDeleted()) { + BeginNode beginNode = findBeginNode(end); + if (!(beginNode instanceof MergeNode)) { + visitDeoptBegin(beginNode, deopt, graph); + } + } + } + if (mergeNode.isDeleted()) { + if (!deopt.isDeleted()) { + Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt)); + visitDeoptBegin(findBeginNode(deopt), deopt, graph); + } + } + } else if (deoptBegin.predecessor() instanceof IfNode) { + IfNode ifNode = (IfNode) deoptBegin.predecessor(); + BeginNode otherBegin = ifNode.trueSuccessor(); + BooleanNode conditionNode = ifNode.compare(); + boolean negated = false; + if (deoptBegin == ifNode.trueSuccessor()) { + negated = true; + otherBegin = ifNode.falseSuccessor(); + } + 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, deopt.reason(), deopt.action(), negated, deopt.leafGraphId())); + otherBegin.replaceAtUsages(ifBlockBegin); + FixedNode next = otherBegin.next(); + otherBegin.setNext(null); + guard.setNext(next); + ifNode.replaceAtPredecessor(guard); + GraphUtil.killCFG(ifNode); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,71 @@ +/* + * 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.phases; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.util.*; + + +public class ConvertUnreachedToGuardPhase extends Phase { + private OptimisticOptimizations opt; + + public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) { + this.opt = opt; + } + + @Override + protected void run(StructuredGraph graph) { + if (!opt.removeNeverExecutedCode()) { + return; + } + for (Node node : graph.getNodes()) { + if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + BeginNode insertGuard = null; + BeginNode delete = null; + boolean inverted = false; + if (ifNode.probability(IfNode.TRUE_EDGE) == 0) { + insertGuard = ifNode.falseSuccessor(); + delete = ifNode.trueSuccessor(); + inverted = true; + } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) { + insertGuard = ifNode.trueSuccessor(); + delete = ifNode.falseSuccessor(); + } + if (insertGuard != null) { + GuardNode guard = graph.unique(new GuardNode(ifNode.compare(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId())); + graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard))); + GraphUtil.killCFG(delete); + graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE); + } + } + } + + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,115 @@ +/* + * 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.phases; + +import java.util.*; + +import com.oracle.graal.compiler.graph.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; + +/** + * This phase culls unused FrameStates from the graph. + * It does a post order iteration over the graph, and + */ +public class CullFrameStatesPhase extends Phase { + + private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled"); + private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed"); + + @Override + protected void run(StructuredGraph graph) { + new CullFrameStates(graph.start(), new State(null)).apply(); + } + + public static class State implements MergeableState { + + private FrameState lastFrameState; + + public State(FrameState lastFrameState) { + this.lastFrameState = lastFrameState; + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + FrameState stateAfter = merge.stateAfter(); + if (merge instanceof LoopBeginNode) { + if (stateAfter != null) { + lastFrameState = stateAfter; + } + return true; + } + metricMergesTraversed.increment(); + if (stateAfter != null) { + for (State other : withStates) { + if (other.lastFrameState != lastFrameState) { + lastFrameState = stateAfter; + return true; + } + } + metricFrameStatesCulled.increment(); + merge.setStateAfter(null); + if (stateAfter.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + } + + @Override + public void afterSplit(FixedNode node) { + } + + @Override + public State clone() { + return new State(lastFrameState); + } + } + + public static class CullFrameStates extends PostOrderNodeIterator { + + public CullFrameStates(FixedNode start, State initialState) { + super(start, initialState); + } + + @Override + protected void node(FixedNode node) { + if (node instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) node).stateAfter(); + if (stateAfter != null) { + state.lastFrameState = stateAfter; + } + } + } + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + + +public class DeadCodeEliminationPhase extends Phase { + + // Metrics + private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); + + private NodeFlood flood; + + @Override + protected void run(StructuredGraph graph) { + this.flood = graph.createNodeFlood(); + + flood.add(graph.start()); + iterateSuccessors(); + disconnectCFGNodes(graph); + iterateInputs(graph); + deleteNodes(graph); + + // remove chained Merges + for (MergeNode merge : graph.getNodes(MergeNode.class)) { + if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) { + graph.reduceTrivialMerge(merge); + } + } + } + + private void iterateSuccessors() { + for (Node current : flood) { + if (current instanceof EndNode) { + EndNode end = (EndNode) current; + flood.add(end.merge()); + } else { + for (Node successor : current.successors()) { + flood.add(successor); + } + } + } + } + + private void disconnectCFGNodes(StructuredGraph graph) { + for (EndNode node : graph.getNodes(EndNode.class)) { + if (!flood.isMarked(node)) { + MergeNode merge = node.merge(); + if (merge != null && flood.isMarked(merge)) { + // We are a dead end node leading to a live merge. + merge.removeEnd(node); + } + } + } + for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) { + if (flood.isMarked(loop)) { + boolean reachable = false; + for (LoopEndNode end : loop.loopEnds()) { + if (flood.isMarked(end)) { + reachable = true; + break; + } + } + if (!reachable) { + Debug.log("Removing loop with unreachable end: %s", loop); + for (LoopEndNode end : loop.loopEnds().snapshot()) { + loop.removeEnd(end); + } + graph.reduceDegenerateLoopBegin(loop); + } + } + } + } + + private void deleteNodes(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (!flood.isMarked(node)) { + node.clearInputs(); + node.clearSuccessors(); + } + } + for (Node node : graph.getNodes()) { + if (!flood.isMarked(node)) { + metricNodesRemoved.increment(); + node.safeDelete(); + } + } + } + + private void iterateInputs(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (node instanceof LocalNode) { + flood.add(node); + } + if (flood.isMarked(node)) { + for (Node input : node.inputs()) { + flood.add(input); + } + } + } + for (Node current : flood) { + for (Node input : current.inputs()) { + flood.add(input); + } + } + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +public class ExpandBoxingNodesPhase extends Phase { + + private final BoxingMethodPool pool; + + public ExpandBoxingNodesPhase(BoxingMethodPool pool) { + this.pool = pool; + } + + @Override + protected void run(StructuredGraph graph) { + for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { + boxNode.expand(pool); + } + + for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { + unboxNode.expand(pool); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.compiler.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.extended.*; + +public class FloatingReadPhase extends Phase { + + private IdentityHashMap> loopEndStatesMap; + + private static class LoopState { + public LoopBeginNode loopBegin; + public MemoryMap state; + public IdentityHashMap loopPhiLocations = new IdentityHashMap<>(); + public ValueNode loopEntryAnyLocation; + public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) { + this.loopBegin = loopBegin; + this.state = state; + this.loopEntryAnyLocation = loopEntryAnyLocation; + } + + @Override + public String toString() { + return "State@" + loopBegin; + } + } + + private class MemoryMap implements MergeableState { + private IdentityHashMap lastMemorySnapshot; + private LinkedList loops; + + public MemoryMap(MemoryMap memoryMap) { + lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); + loops = new LinkedList<>(memoryMap.loops); + } + + public MemoryMap() { + lastMemorySnapshot = new IdentityHashMap<>(); + loops = new LinkedList<>(); + } + + @Override + public String toString() { + return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString(); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + if (withStates.size() == 0) { + return true; + } + + int minLoops = loops.size(); + for (MemoryMap other : withStates) { + int otherLoops = other.loops.size(); + if (otherLoops < minLoops) { + minLoops = otherLoops; + } + } + while (loops.size() > minLoops) { + loops.pop(); + } + for (MemoryMap other : withStates) { + while (other.loops.size() > minLoops) { + other.loops.pop(); + } + } + + Set keys = new HashSet<>(); + for (Object key : lastMemorySnapshot.keySet()) { + keys.add(key); + } + for (MemoryMap other : withStates) { + assert other.loops.size() == loops.size(); + assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin; + for (Object key : other.lastMemorySnapshot.keySet()) { + keys.add(key); + } + } + + for (Object key : keys) { + ValueNode merged = lastMemorySnapshot.get(key); + if (merged == null) { + merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + } + Iterator it = withStates.iterator(); + int i = 1; + boolean isPhi = false; + while (it.hasNext()) { + MemoryMap other = it.next(); + ValueNode otherValue = other.lastMemorySnapshot.get(key); + if (otherValue == null) { + otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + } + if (isPhi) { + ((PhiNode) merged).addInput(otherValue); + } else if (merged != otherValue) { + PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); + for (int j = 0; j < i; j++) { + phi.addInput(merged); + } + phi.addInput(otherValue); + merged = phi; + isPhi = true; + lastMemorySnapshot.put(key, phi); + } + i++; + } + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION)); + for (Map.Entry entry : lastMemorySnapshot.entrySet()) { + PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin)); + phi.addInput(entry.getValue()); + entry.setValue(phi); + loopState.loopPhiLocations.put(phi, entry.getKey()); + } + loops.push(loopState); + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + loopEndStatesMap.put(loopBegin, loopEndStates); + tryFinishLoopPhis(this, loopBegin); + } + + @Override + public void afterSplit(FixedNode node) { + // nothing + } + + @Override + public MemoryMap clone() { + return new MemoryMap(this); + } + } + + @Override + protected void run(StructuredGraph graph) { + loopEndStatesMap = new IdentityHashMap<>(); + new PostOrderNodeIterator(graph.start(), new MemoryMap()) { + @Override + protected void node(FixedNode node) { + processNode(node, state); + } + }.apply(); + } + + private void processNode(FixedNode node, MemoryMap state) { + if (node instanceof ReadNode) { + processRead((ReadNode) node, state); + } else if (node instanceof WriteNode) { + processWrite((WriteNode) node, state); + } else if (node instanceof MemoryCheckpoint) { + processCheckpoint((MemoryCheckpoint) node, state); + } else if (node instanceof LoopExitNode) { + processLoopExit((LoopExitNode) node, state); + } + } + + private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { + processAnyLocationWrite((ValueNode) checkpoint, state); + } + + private static void processWrite(WriteNode writeNode, MemoryMap state) { + if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) { + processAnyLocationWrite(writeNode, state); + } + state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode); + } + + private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) { + for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { + entry.setValue(modifiying); + } + state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying); + state.loops.clear(); + } + + private void processRead(ReadNode readNode, MemoryMap state) { + StructuredGraph graph = (StructuredGraph) readNode.graph(); + assert readNode.getNullCheck() == false; + Object locationIdentity = readNode.location().locationIdentity(); + ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity); + FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); + floatingRead.setNullCheck(readNode.getNullCheck()); + ValueAnchorNode anchor = null; + for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { + if (anchor == null) { + anchor = graph.add(new ValueAnchorNode()); + } + anchor.addAnchoredNode(guard); + } + if (anchor != null) { + graph.addAfterFixed(readNode, anchor); + } + graph.replaceFixedWithFloating(readNode, floatingRead); + } + + private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) { + ValueNode lastLocationAccess; + if (locationIdentity == LocationNode.FINAL_LOCATION) { + lastLocationAccess = null; + } else { + lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity); + if (lastLocationAccess == null) { + LoopState lastLoop = state.loops.peek(); + if (lastLoop == null) { + lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + } else { + ValueNode phiInit; + if (state.loops.size() > 1) { + phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity); + } else { + phiInit = lastLoop.loopEntryAnyLocation; + } + PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin)); + phi.addInput(phiInit); + lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi); + lastLoop.loopPhiLocations.put(phi, locationIdentity); + tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin); + lastLocationAccess = phi; + } + state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess); + } + } + return lastLocationAccess; + } + + private static void processLoopExit(LoopExitNode exit, MemoryMap state) { + for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { + entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory))); + } + if (!state.loops.isEmpty()) { + state.loops.pop(); + } + } + + private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) { + List loopEndStates = loopEndStatesMap.get(loopBegin); + if (loopEndStates == null) { + return; + } + LoopState loopState = loopMemory.loops.get(0); + int i = 0; + while (loopState.loopBegin != loopBegin) { + loopState = loopMemory.loops.get(++i); + } + for (PhiNode phi : loopBegin.phis()) { + if (phi.type() == PhiType.Memory && phi.valueCount() == 1) { + Object location = loopState.loopPhiLocations.get(phi); + assert location != null : "unknown location for " + phi; + for (MemoryMap endState : loopEndStates) { + ValueNode otherNode = endState.lastMemorySnapshot.get(location); + if (otherNode == null) { + otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + } + phi.addInput(otherNode); + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +public class GlobalValueNumberingPhase extends Phase { + + public static final DebugMetric metricGlobalValueNumberingHits = Debug.metric("GlobalValueNumberingHits"); + + @Override + protected void run(StructuredGraph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + for (Node n : graph.getNodes()) { + apply(n, visited, graph); + } + } + + private void apply(Node n, NodeBitMap visited, StructuredGraph compilerGraph) { + if (!visited.isMarked(n)) { + visited.mark(n); + for (Node input : n.inputs()) { + apply(input, visited, compilerGraph); + } + if (n.getNodeClass().valueNumberable()) { + Node newNode = compilerGraph.findDuplicate(n); + if (newNode != null) { + assert !(n instanceof FixedNode || newNode instanceof FixedNode); + n.replaceAtUsages(newNode); + n.safeDelete(); + metricGlobalValueNumberingHits.increment(); + Debug.log("GVN applied and new node is %1s", newNode); + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; + +public class IdentifyBoxingPhase extends Phase { + + private final BoxingMethodPool pool; + + public IdentifyBoxingPhase(BoxingMethodPool pool) { + this.pool = pool; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke invoke : graph.getInvokes()) { + tryIntrinsify(invoke); + } + } + + public void tryIntrinsify(Invoke invoke) { + if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { + return; + } + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + if (pool.isSpecialMethod(targetMethod)) { + assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument"; + Kind returnKind = callTarget.returnKind(); + ValueNode sourceValue = callTarget.arguments().get(0); + + // Check whether this is a boxing or an unboxing. + Node newNode = null; + if (returnKind == Kind.Object) { + // We have a boxing method here. + assert Modifier.isStatic(targetMethod.accessFlags()) : "boxing method must be static"; + Kind sourceKind = targetMethod.signature().argumentKindAt(0); + newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.holder(), sourceKind, invoke.bci())); + } else { + // We have an unboxing method here. + assert !Modifier.isStatic(targetMethod.accessFlags()) : "unboxing method must be an instance method"; + newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue)); + } + + // Intrinsify the invoke to the special node. + invoke.intrinsify(newNode); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InliningPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InliningPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; +import com.oracle.graal.compiler.util.*; +import com.oracle.graal.compiler.util.InliningUtil.InlineInfo; +import com.oracle.graal.compiler.util.InliningUtil.InliningCallback; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + + +public class InliningPhase extends Phase implements InliningCallback { + /* + * - Detect method which only call another method with some parameters set to constants: void foo(a) -> void foo(a, b) -> void foo(a, b, c) ... + * These should not be taken into account when determining inlining depth. + * - honor the result of overrideInliningDecision(0, caller, invoke.bci, method, true); + */ + + private final TargetDescription target; + private final GraalCodeCacheProvider runtime; + + private final Collection hints; + + private final PriorityQueue inlineCandidates = new PriorityQueue<>(); + private Assumptions assumptions; + + private final PhasePlan plan; + private final GraphCache cache; + 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(TargetDescription target, GraalCodeCacheProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + this.target = target; + this.runtime = runtime; + this.hints = hints; + this.assumptions = assumptions; + this.cache = cache; + this.plan = plan; + this.optimisticOpts = optimisticOpts; + this.weightComputationPolicy = createWeightComputationPolicy(); + this.inliningPolicy = createInliningPolicy(); + } + + @SuppressWarnings("unchecked") + @Override + protected void run(final StructuredGraph graph) { + graph.createNodeMap(); + + if (hints != null) { + scanInvokes((Iterable) Util.uncheckedCast(this.hints)); + } else { + scanInvokes(graph.getNodes(InvokeNode.class)); + scanInvokes(graph.getNodes(InvokeWithExceptionNode.class)); + } + + while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) { + InlineInfo candidate = inlineCandidates.remove(); + if (!candidate.invoke.node().isAlive()) { + continue; + } + // refresh infos + final InlineInfo info = InliningUtil.getInlineInfo(candidate.invoke, candidate.level, runtime, assumptions, this, optimisticOpts); + + boolean inline = Debug.scope("InliningDecisions", new Callable() { + @Override + public Boolean call() throws Exception { + return info != null && inliningPolicy.isWorthInlining(graph, info); + } + }); + + if (inline) { + int mark = graph.getMark(); + Iterable newNodes = null; + try { + info.inline(graph, runtime, this); + Debug.dump(graph, "after %s", info); + newNodes = graph.getNewNodes(mark); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph); + } +// if (GraalOptions.Intrinsify) { +// new IntrinsificationPhase(runtime).apply(graph); +// } + metricInliningPerformed.increment(); + } catch (BailoutException bailout) { + // TODO determine if we should really bail out of the whole compilation. + throw bailout; + } catch (AssertionError e) { + throw new GraalInternalError(e).addContext(info.toString()); + } catch (RuntimeException e) { + throw new GraalInternalError(e).addContext(info.toString()); + } catch (GraalInternalError e) { + throw e.addContext(info.toString()); + } + + if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) { + scanInvokes(newNodes); + } + } + } + + if (GraalOptions.Debug && graph.getNodeCount() >= GraalOptions.MaximumDesiredSize) { + Debug.scope("InliningDecisions", new Runnable() { + public void run() { + for (InlineInfo info : inlineCandidates) { + Debug.log("not inlining %s because inlining cut off by MaximumDesiredSize", InliningUtil.methodName(info)); + } + } + }); + + metricInliningStoppedByMaxDesiredSize.increment(); + } + } + + private void scanInvokes(final Iterable nodes) { + Debug.scope("InliningDecisions", new Runnable() { + public void run() { + for (Node node : nodes) { + if (node != null) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + scanInvoke(invoke); + } + for (Node usage : node.usages().filterInterface(Invoke.class).snapshot()) { + scanInvoke((Invoke) usage); + } + } + } + } + }); + } + + private void scanInvoke(Invoke invoke) { + InlineInfo info = InliningUtil.getInlineInfo(invoke, computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts); + if (info != null) { + metricInliningConsidered.increment(); + inlineCandidates.add(info); + } + } + + public static final Map parsedMethods = new HashMap<>(); + + + + private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); + + @Override + public StructuredGraph buildGraph(final ResolvedJavaMethod method) { + metricInliningRuns.increment(); + if (GraalOptions.CacheGraphs && cache != null) { + StructuredGraph cachedGraph = cache.get(method); + if (cachedGraph != null) { + return cachedGraph; + } + } + StructuredGraph newGraph = new StructuredGraph(method); + if (plan != null) { + plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); + } + assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(newGraph); + new ComputeProbabilityPhase().apply(newGraph); + } + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); + } + if (GraalOptions.Intrinsify) { + new IntrinsificationPhase(runtime).apply(newGraph); + } + if (GraalOptions.CullFrameStates) { + new CullFrameStatesPhase().apply(newGraph); + } + if (GraalOptions.CacheGraphs && cache != null) { + cache.put(newGraph); + } + return newGraph; + } + + @Override + public double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke) { + boolean preferred = hints != null && hints.contains(invoke); + return weightComputationPolicy.computeWeight(caller, method, invoke, preferred); + } + + public static int graphComplexity(StructuredGraph graph) { + int result = 0; + for (Node node : graph.getNodes()) { + if (node instanceof ConstantNode || node instanceof LocalNode || node instanceof BeginNode || node instanceof ReturnNode || node instanceof UnwindNode) { + result += 0; + } else if (node instanceof PhiNode) { + result += 5; + } else if (node instanceof MergeNode || node instanceof Invoke || node instanceof LoopEndNode || node instanceof EndNode) { + result += 0; + } else if (node instanceof ControlSplitNode) { + result += ((ControlSplitNode) node).blockSuccessorCount(); + } else { + result += 1; + } + } + return Math.max(1, result); + } + + + @Override + public void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + assumptions.recordConcreteMethod(method, context, impl); + } + + @Override + public void recordMethodContentsAssumption(ResolvedJavaMethod method) { + if (assumptions != null) { + assumptions.recordMethodContents(method); + } + } + + private static int computeInliningLevel(Invoke invoke) { + int count = -1; + FrameState curState = invoke.stateAfter(); + while (curState != null) { + count++; + curState = curState.outerFrameState(); + } + return count; + } + + private static InliningPolicy createInliningPolicy() { + switch(GraalOptions.InliningPolicy) { + case 0: return new WeightBasedInliningPolicy(); + case 1: return new C1StaticSizeBasedInliningPolicy(); + case 2: return new MinimumCodeSizeBasedInliningPolicy(); + case 3: return new DynamicSizeBasedInliningPolicy(); + case 4: return new GreedySizeBasedInliningPolicy(); + default: + GraalInternalError.shouldNotReachHere(); + return null; + } + } + + private static WeightComputationPolicy createWeightComputationPolicy() { + switch(GraalOptions.WeightComputationPolicy) { + case 0: throw new GraalInternalError("removed because of invokation counter changes"); + case 1: return new BytecodeSizeBasedWeightComputationPolicy(); + case 2: return new ComplexityBasedWeightComputationPolicy(); + default: + GraalInternalError.shouldNotReachHere(); + return null; + } + } + + private interface InliningPolicy { + boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info); + } + + private static class WeightBasedInliningPolicy implements InliningPolicy { + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + if (!checkCompiledCodeSize(info)) { + return false; + } + + double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp; + if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) { + Debug.log("not inlining %s (cut off by weight %e)", InliningUtil.methodName(info), info.weight); + return false; + } + + Debug.log("inlining %s (weight %f): %s", InliningUtil.methodName(info), info.weight); + return true; + } + } + + private static class C1StaticSizeBasedInliningPolicy implements InliningPolicy { + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize); + return decideSizeBasedInlining(info, maxSize); + } + } + + private static class MinimumCodeSizeBasedInliningPolicy implements InliningPolicy { + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + assert GraalOptions.ProbabilityAnalysis; + if (!checkCompiledCodeSize(info)) { + return false; + } + + double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); + double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight; + maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize); + + return decideSizeBasedInlining(info, maxSize); + } + } + + private static class DynamicSizeBasedInliningPolicy implements InliningPolicy { + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + assert GraalOptions.ProbabilityAnalysis; + if (!checkCompiledCodeSize(info)) { + return false; + } + + double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()) + Math.log10(Math.max(1, info.invoke.probability() - GraalOptions.ProbabilityCapForInlining + 1)); + double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize; + maxSize = maxSize + maxSize * inlineBoost; + maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize)); + + return decideSizeBasedInlining(info, maxSize); + } + } + + private static class GreedySizeBasedInliningPolicy implements InliningPolicy { + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + assert GraalOptions.ProbabilityAnalysis; + if (!checkCompiledCodeSize(info)) { + return false; + } + + double maxSize = GraalOptions.MaximumGreedyInlineSize; + if (GraalOptions.InliningBonusPerTransferredValue != 0) { + Signature signature = info.invoke.methodCallTarget().targetMethod().signature(); + int transferredValues = signature.argumentCount(!Modifier.isStatic(info.invoke.methodCallTarget().targetMethod().accessFlags())); + if (signature.returnKind() != Kind.Void) { + transferredValues++; + } + maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue; + } + + double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); + maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio; + maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize); + + return decideSizeBasedInlining(info, maxSize); + } + } + + private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) { + boolean success = info.weight <= maxSize; + if (DebugScope.getInstance().isLogEnabled()) { + String formatterString = success ? "inlining %s (size %f <= %f)" : "not inlining %s (too large %f > %f)"; + Debug.log(formatterString, InliningUtil.methodName(info), info.weight, maxSize); + } + return success; + } + + private static boolean checkCompiledCodeSize(InlineInfo info) { + if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) { + Debug.log("not inlining %s (CompiledCodeSize %d > %d)", InliningUtil.methodName(info), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize); + return false; + } + return true; + } + + + private interface WeightComputationPolicy { + double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke); + } + + private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy { + @Override + public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { + double codeSize = method.codeSize(); + if (preferredInvoke) { + codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; + } + return codeSize; + } + } + + private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy { + @Override + public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { + double complexity = method.compilationComplexity(); + if (preferredInvoke) { + complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis; + } + return complexity; + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class InsertStateAfterPlaceholderPhase extends Phase { + + private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable { + public PlaceholderNode() { + super(StampFactory.forVoid()); + } + + @Override + public void generate(LIRGeneratorTool gen) { + // nothing to do + } + + @Override + public boolean hasSideEffect() { + return false; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (stateAfter() == null) { + return null; + } + return this; + } + } + + @Override + protected void run(StructuredGraph graph) { + for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { + PlaceholderNode p = graph.add(new PlaceholderNode()); + p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); + graph.addBeforeFixed(ret, p); + } + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.util.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; + +public class IntrinsificationPhase extends Phase { + + private final GraalCodeCacheProvider runtime; + + public IntrinsificationPhase(GraalCodeCacheProvider runtime) { + this.runtime = runtime; + } + + @Override + protected void run(StructuredGraph graph) { + for (InvokeNode invoke : graph.getNodes(InvokeNode.class)) { + tryIntrinsify(invoke, runtime); + } + for (InvokeWithExceptionNode invoke : graph.getNodes(InvokeWithExceptionNode.class)) { + tryIntrinsify(invoke, runtime); + } + } + + public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { + return getIntrinsicGraph(invoke, target, runtime) != null; + } + + private static void tryIntrinsify(Invoke invoke, GraalCodeCacheProvider runtime) { + if (invoke.callTarget() instanceof MethodCallTargetNode && invoke.methodCallTarget().targetMethod() != null) { + tryIntrinsify(invoke, invoke.methodCallTarget().targetMethod(), runtime); + } + } + + private static void tryIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { + StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target, runtime); + if (intrinsicGraph != null) { + Debug.log(" > Intrinsify %s", target); + InliningUtil.inline(invoke, intrinsicGraph, true); + } + } + + private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { + StructuredGraph intrinsicGraph = (StructuredGraph) target.compilerStorage().get(Graph.class); + if (intrinsicGraph == null) { + // TODO remove once all intrinsics are available via compilerStorage + intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments()); + } + return intrinsicGraph; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,72 @@ +/* + * 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.phases; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Graph.InputChangedListener; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + + +public class IterativeCheckCastEliminationPhase extends Phase { + private final TargetDescription target; + private final MetaAccessProvider runtime; + private final Assumptions assumptions; + + public IterativeCheckCastEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { + this.target = target; + this.runtime = runtime; + this.assumptions = assumptions; + } + + @Override + protected void run(StructuredGraph graph) { + Set canonicalizationRoots = new HashSet<>(); + CheckCastEliminationPhase eliminate = new CheckCastEliminationPhase(); + Listener listener = new Listener(canonicalizationRoots); + while (true) { + graph.trackInputChange(listener); + eliminate.apply(graph); + graph.stopTrackingInputChange(); + if (canonicalizationRoots.isEmpty()) { + break; + } + new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph); + canonicalizationRoots.clear(); + } + } + + private static class Listener implements InputChangedListener { + private final Set canonicalizationRoots; + public Listener(Set canonicalizationRoots) { + this.canonicalizationRoots = canonicalizationRoots; + } + @Override + public void inputChanged(Node node) { + canonicalizationRoots.add(node); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopFullUnrollPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopFullUnrollPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + + +public class LoopFullUnrollPhase extends Phase { + private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls"); + private final GraalCodeCacheProvider runtime; + + public LoopFullUnrollPhase(GraalCodeCacheProvider runtime) { + this.runtime = runtime; + } + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + boolean peeled; + do { + peeled = false; + final LoopsData dataCounted = new LoopsData(graph); + dataCounted.detectedCountedLoops(); + for (LoopEx loop : dataCounted.countedLoops()) { + if (LoopPolicies.shouldFullUnroll(loop)) { + Debug.log("FullUnroll %s", loop); + LoopTransformations.fullUnroll(loop, runtime); + FULLY_UNROLLED_LOOPS.increment(); + Debug.dump(graph, "After fullUnroll %s", loop); + peeled = true; + break; + } + } + } while(peeled); + } + } + +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.util.*; + +/** + * Adds safepoints to loops. + */ +public class LoopSafepointInsertionPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + nextLoop: + for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) { + if (!loopEnd.canSafepoint()) { + continue; + } + if (GraalOptions.OptSafepointElimination) { + // We 'eliminate' safepoints by simply never placing them into loops that have at least one call + NodeIterable it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin()); + for (FixedNode n : it) { + if (n instanceof Invoke) { + continue nextLoop; + } + } + } + SafepointNode safepoint = graph.add(new SafepointNode()); + graph.addBeforeFixed(loopEnd, safepoint); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopTransformHighPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopTransformHighPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; + +public class LoopTransformHighPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + if (GraalOptions.LoopPeeling) { + LoopsData data = new LoopsData(graph); + for (LoopEx loop : data.outterFirst()) { + if (LoopPolicies.shouldPeel(loop)) { + Debug.log("Peeling %s", loop); + LoopTransformations.peel(loop); + Debug.dump(graph, "After peeling %s", loop); + } + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopTransformLowPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoopTransformLowPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.loop.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; + +public class LoopTransformLowPhase extends Phase { + private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); + + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + if (GraalOptions.ReassociateInvariants) { + final LoopsData dataReassociate = new LoopsData(graph); + Debug.scope("ReassociateInvariants", new Runnable() { + @Override + public void run() { + for (LoopEx loop : dataReassociate.loops()) { + loop.reassociateInvariants(); + } + } + }); + } + if (GraalOptions.LoopUnswitch) { + boolean unswitched; + do { + unswitched = false; + final LoopsData dataUnswitch = new LoopsData(graph); + for (LoopEx loop : dataUnswitch.loops()) { + if (LoopPolicies.shouldTryUnswitch(loop)) { + IfNode ifNode = LoopTransformations.findUnswitchableIf(loop); + if (ifNode != null && LoopPolicies.shouldUnswitch(loop, ifNode)) { + Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(0), ifNode.probability(1)); + LoopTransformations.unswitch(loop, ifNode); + UNSWITCHED.increment(); + Debug.dump(graph, "After unswitch %s", loop); + unswitched = true; + break; + } + } + } + } while(unswitched); + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoweringPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/LoweringPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.schedule.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +/** + * Processes all {@link Lowerable} nodes to do their lowering. + */ +public class LoweringPhase extends Phase { + + final class LoweringToolImpl implements LoweringTool { + + final FixedNode guardAnchor; + final NodeBitMap activeGuards; + FixedWithNextNode lastFixedNode; + + public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) { + this.guardAnchor = guardAnchor; + this.activeGuards = activeGuards; + } + + @Override + public GraalCodeCacheProvider getRuntime() { + return runtime; + } + + @Override + public ValueNode createNullCheckGuard(ValueNode object, long leafGraphId) { + return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, leafGraphId); + } + + @Override + public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId) { + return createGuard(condition, deoptReason, action, false, leafGraphId); + } + + @Override + public Assumptions assumptions() { + return assumptions; + } + + @Override + public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) { + if (GraalOptions.OptEliminateGuards) { + for (Node usage : condition.usages()) { + if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { + return (ValueNode) usage; + } + } + } + GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId)); + if (GraalOptions.OptEliminateGuards) { + activeGuards.grow(); + activeGuards.mark(newGuard); + } + return newGuard; + } + + public FixedWithNextNode lastFixedNode() { + return lastFixedNode; + } + } + + private final GraalCodeCacheProvider runtime; + private final Assumptions assumptions; + + public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { + this.runtime = runtime; + this.assumptions = assumptions; + } + + private static boolean containsLowerable(NodeIterable nodes) { + for (Node n : nodes) { + if (n instanceof Lowerable) { + return true; + } + } + return false; + } + + @Override + protected void run(final StructuredGraph graph) { + int i = 0; + NodeBitMap processed = graph.createNodeBitMap(); + while (true) { + int mark = graph.getMark(); + final SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph, false); + + processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); + Debug.dump(graph, "Lowering iteration %d", i++); + new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph); + + if (!containsLowerable(graph.getNewNodes(mark))) { + // No new lowerable nodes - done! + break; + } + assert graph.verify(); + processed.grow(); + } + } + + private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) { + + FixedNode anchor = parentAnchor; + if (anchor == null) { + anchor = block.getBeginNode(); + } + process(block, activeGuards, anchor, schedule, processed); + + // Process always reached block first. + Block alwaysReachedBlock = block.getPostdominator(); + if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) { + processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed); + } + + // Now go for the other dominators. + for (Block dominated : block.getDominated()) { + if (dominated != alwaysReachedBlock) { + assert dominated.getDominator() == block; + processBlock(dominated, activeGuards, null, schedule, processed); + } + } + + if (parentAnchor == null && GraalOptions.OptEliminateGuards) { + for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { + activeGuards.clear(guard); + } + } + } + + private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) { + + final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards); + + // Lower the instructions of this block. + List nodes = schedule.nodesFor(b); + + for (Node node : nodes) { + FixedNode lastFixedNext = null; + if (node instanceof FixedWithNextNode) { + FixedWithNextNode fixed = (FixedWithNextNode) node; + lastFixedNext = fixed.next(); + loweringTool.lastFixedNode = fixed; + } + + if (node.isAlive() && !processed.isMarked(node)) { + processed.mark(node); + if (node instanceof Lowerable) { + ((Lowerable) node).lower(loweringTool); + } + } + + if (loweringTool.lastFixedNode == node && !node.isAlive()) { + if (lastFixedNext == null) { + loweringTool.lastFixedNode = null; + } else { + Node prev = lastFixedNext.predecessor(); + if (prev != node && prev instanceof FixedWithNextNode) { + loweringTool.lastFixedNode = (FixedWithNextNode) prev; + } else if (lastFixedNext instanceof FixedWithNextNode) { + loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext; + } else { + loweringTool.lastFixedNode = null; + } + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/Phase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/Phase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; + +public abstract class Phase { + + private String name; + private static final DebugMetric metricPhaseRuns = Debug.metric("Runs"); + protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes"); + + protected Phase() { + this.name = this.getClass().getSimpleName(); + if (name.endsWith("Phase")) { + name = name.substring(0, name.length() - "Phase".length()); + } + } + + protected Phase(String name) { + this.name = name; + } + + protected String getDetailedName() { + return getName(); + } + + public final void apply(final StructuredGraph graph) { + apply(graph, true); + } + + public final void apply(final StructuredGraph graph, final boolean dumpGraph) { + Debug.scope(name, this, new Runnable() { + public void run() { + Phase.this.run(graph); + metricPhaseRuns.increment(); + if (dumpGraph) { + Debug.dump(graph, "After phase %s", name); + } + assert graph.verify(); + } + }); + } + + public final String getName() { + return name; + } + + protected abstract void run(StructuredGraph graph); +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhasePlan.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhasePlan.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.nodes.*; + +/** + * Tells the compiler about additional phases that need to be executed during compilation. + */ +public class PhasePlan { + /** + * The compilation is split into the following sections: + * ======================================================================== + * Period 1: High-level nodes. (Graph building) + * ======================================================================== + * Runtime-specific lowering. + * ======================================================================== + * Period 2: Mid-level nodes. (Memory dependence graph) + * ======================================================================== + * Target-specific lowering, de-SSA. + * ======================================================================== + * Period 3: Low-level nodes. (Register allocation, code generation) + * ======================================================================== + * + * A compiler extension phase can chose to run at the end of periods 1-3. + */ + public static enum PhasePosition { + AFTER_PARSING, + HIGH_LEVEL, + MID_LEVEL, + LOW_LEVEL + } + + @SuppressWarnings("unchecked") + private final ArrayList[] phases = new ArrayList[PhasePosition.values().length]; + private final Set> disabledPhases = new HashSet<>(); + + public void addPhase(PhasePosition pos, Phase phase) { + if (phases[pos.ordinal()] == null) { + phases[pos.ordinal()] = new ArrayList<>(); + } + phases[pos.ordinal()].add(phase); + } + + public void runPhases(PhasePosition pos, StructuredGraph graph) { + if (phases[pos.ordinal()] != null) { + for (Phase p : phases[pos.ordinal()]) { + p.apply(graph); + } + } + } + + public void disablePhase(Class clazz) { + disabledPhases.add(clazz); + } + + public boolean isPhaseDisabled(Class clazz) { + return disabledPhases.contains(clazz); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhiStampPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/PhiStampPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import com.oracle.graal.nodes.*; + +public class PhiStampPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + // Infer phis stopping at loop phis. + for (PhiNode phi : graph.getNodes(PhiNode.class)) { + inferPhi(phi); + } + + // Start iterative inference for loop phis. + if (graph.hasLoops()) { + for (PhiNode phi : graph.getNodes(PhiNode.class)) { + if (phi.isLoopPhi()) { + iterativeInferPhi(phi); + } + } + } + } + + private void iterativeInferPhi(PhiNode phi) { + if (phi.inferPhiStamp()) { + for (PhiNode phiUsage : phi.usages().filter(PhiNode.class)) { + iterativeInferPhi(phiUsage); + } + } + } + + private void inferPhi(PhiNode phi) { + for (PhiNode phiInput : phi.values().filter(PhiNode.class)) { + if (!phiInput.isLoopPhi()) { + inferPhi(phiInput); + } + } + phi.inferPhiStamp(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.extended.*; + +public class ReadEliminationPhase extends Phase { + private Queue newPhis; + + @Override + protected void run(StructuredGraph graph) { + newPhis = new LinkedList<>(); + for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) { + if (isReadEliminable(n)) { + NodeMap nodeMap = n.graph().createNodeMap(); + ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap); + Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value); + graph.replaceFloating(n, value); + } + } + } + + private boolean isReadEliminable(FloatingReadNode n) { + return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap()); + } + + private boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) { + if (lastLocationAccess == null) { + return false; + } + if (visited.isMarked(lastLocationAccess)) { + return true; // dataflow loops must come from Phis assume them ok until proven wrong + } + if (lastLocationAccess instanceof ValueProxyNode) { + return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited); + } + if (lastLocationAccess instanceof WriteNode) { + WriteNode other = (WriteNode) lastLocationAccess; + return other.object() == n.object() && other.location() == n.location(); + } + if (lastLocationAccess instanceof PhiNode) { + visited.mark(lastLocationAccess); + for (ValueNode value : ((PhiNode) lastLocationAccess).values()) { + if (!isWrites(n, value, visited)) { + return false; + } + } + return true; + } + return false; + } + + private ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap nodeMap) { + ValueNode exisiting = nodeMap.get(lastLocationAccess); + if (exisiting != null) { + return exisiting; + } + if (lastLocationAccess instanceof ValueProxyNode) { + ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess; + ValueNode value = getValue(n, proxy.value(), nodeMap); + return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value)); + } + if (lastLocationAccess instanceof WriteNode) { + return ((WriteNode) lastLocationAccess).value(); + } + if (lastLocationAccess instanceof PhiNode) { + PhiNode phi = (PhiNode) lastLocationAccess; + PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge())); + nodeMap.set(lastLocationAccess, newPhi); + for (ValueNode value : phi.values()) { + newPhi.addInput(getValue(n, value, nodeMap)); + } + newPhis.add(newPhi); + return newPhi; + } + throw GraalInternalError.shouldNotReachHere(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,44 @@ +/* + * 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.phases; + +import com.oracle.graal.nodes.*; + +public class RemoveValueProxyPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) { + graph.replaceFloating(vpn, vpn.value()); + } + for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) { + FrameState stateAfter = exit.stateAfter(); + if (stateAfter != null) { + exit.setStateAfter(null); + if (stateAfter.usages().count() == 0) { + stateAfter.safeDelete(); + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,546 @@ +/* + * 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.phases; + +import java.util.*; + +import com.oracle.graal.compiler.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.Graph.DuplicationReplacement; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * This class is a phase that looks for opportunities for tail duplication. The static method + * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail duplication from + * other places, e.g., inlining. + */ +public class TailDuplicationPhase extends Phase { + + /* + * Various metrics on the circumstances in which tail duplication was/wasn't performed. + */ + private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors"); + private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd"); + private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed"); + private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther"); + private static final DebugMetric metricDuplicationOtherPerformed = Debug.metric("DuplicationOtherPerformed"); + + /** + * This interface is used by tail duplication to let clients decide if tail duplication should be performed. + */ + public interface TailDuplicationDecision { + + /** + * Queries if tail duplication should be performed at the given merge. If this method returns true then the tail + * duplication will be performed, because all other checks have happened before. + * + * @param merge The merge at which tail duplication can be performed. + * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the duplicated set of nodes. + * @return true if the tail duplication should be performed, false otherwise. + */ + boolean doTransform(MergeNode merge, int fixedNodeCount); + } + + /** + * A tail duplication decision closure that employs the default algorithm: Check if there are any phis on the merge + * whose stamps improve and that have usages within the duplicated set of fixed nodes. + */ + public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() { + + public boolean doTransform(MergeNode merge, int fixedNodeCount) { + if (fixedNodeCount < GraalOptions.TailDuplicationTrivialSize) { + return true; + } + HashSet improvements = new HashSet<>(); + for (PhiNode phi : merge.phis()) { + Stamp phiStamp = phi.stamp(); + for (ValueNode input : phi.values()) { + if (!input.stamp().equals(phiStamp)) { + improvements.add(phi); + break; + } + } + } + if (improvements.isEmpty()) { + return false; + } + FixedNode current = merge; + int opportunities = 0; + while (current instanceof FixedWithNextNode) { + current = ((FixedWithNextNode) current).next(); + for (PhiNode phi : improvements) { + if (current.inputs().contains(phi)) { + opportunities++; + } + } + } + return opportunities > 0; + } + }; + + /** + * A tail duplication decision closure that always returns true. + */ + public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() { + + @Override + public boolean doTransform(MergeNode merge, int fixedNodeCount) { + return true; + } + }; + + @Override + protected void run(StructuredGraph graph) { + // A snapshot is taken here, so that new MergeNode instances aren't considered for tail duplication. + for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { + if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { + tailDuplicate(merge, DEFAULT_DECISION, null); + } + } + } + + /** + * This method attempts to duplicate the tail of the given merge. The merge must not be a {@link LoopBeginNode}. If + * the merge is eligible for duplication (at least one fixed node in its tail, no {@link MonitorEnterNode}/ + * {@link MonitorExitNode}, non-null {@link MergeNode#stateAfter()}) then the decision callback is used to determine + * whether the tail duplication should actually be performed. If replacements is non-null, then this list of + * {@link PiNode}s is used to replace one value per merge end. + * + * @param merge The merge whose tail should be duplicated. + * @param decision A callback that can make the final decision if tail duplication should occur or not. + * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its size needs to match the + * merge's end count. Each entry can either be null or a {@link PiNode}, and is used to replace + * {@link PiNode#object()} with the {@link PiNode} in the duplicated branch that corresponds to the + * entry. + */ + public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { + assert !(merge instanceof LoopBeginNode); + assert replacements == null || replacements.size() == merge.forwardEndCount(); + FixedNode fixed = merge; + int fixedCount = 0; + boolean containsMonitor = false; + while (fixed instanceof FixedWithNextNode) { + if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) { + containsMonitor = true; + } + fixed = ((FixedWithNextNode) fixed).next(); + fixedCount++; + } + if (containsMonitor) { + // cannot currently be handled + // TODO (ls) re-evaluate this limitation after changes to the lock representation and the LIR generator + metricDuplicationMonitors.increment(); + } else if (fixedCount > 1) { + if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) { + metricDuplicationEnd.increment(); + if (decision.doTransform(merge, fixedCount)) { + metricDuplicationEndPerformed.increment(); + new DuplicationOperation(merge, replacements).duplicate(); + } + } else if (merge.stateAfter() != null) { + metricDuplicationOther.increment(); + if (decision.doTransform(merge, fixedCount)) { + metricDuplicationOtherPerformed.increment(); + new DuplicationOperation(merge, replacements).duplicate(); + } + } + } + } + + /** + * This class encapsulates one tail duplication operation on a specific {@link MergeNode}. + */ + private static class DuplicationOperation { + + private final MergeNode merge; + private final StructuredGraph graph; + + private final HashMap bottomPhis = new HashMap<>(); + private final List replacements; + + /** + * Initializes the tail duplication operation without actually performing any work. + * + * @param merge The merge whose tail should be duplicated. + * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null, then the size of the + * list needs to match the number of end nodes at the merge. + */ + public DuplicationOperation(MergeNode merge, List replacements) { + this.merge = merge; + this.replacements = replacements; + this.graph = (StructuredGraph) merge.graph(); + } + + /** + * Performs the actual tail duplication: + *
    + *
  • Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an transfers all + * dependencies from the merge to this anchor.
  • + *
  • Determines the set of fixed nodes to be duplicated.
  • + *
  • Creates the new merge at the bottom of the duplicated area.
  • + *
  • Determines the complete set of duplicated nodes.
  • + *
  • Performs the actual duplication.
  • + *
+ */ + private void duplicate() { + Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability()); + + ValueAnchorNode anchor = addValueAnchor(); + + // determine the fixed nodes that should be duplicated (currently: all nodes up until the first control + // split, end node, deopt or return. + ArrayList fixedNodes = new ArrayList<>(); + FixedNode fixed = merge.next(); + FrameState stateAfter = merge.stateAfter(); + while (fixed instanceof FixedWithNextNode) { + fixedNodes.add(fixed); + if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) { + stateAfter = ((StateSplit) fixed).stateAfter(); + } + fixed = ((FixedWithNextNode) fixed).next(); + } + + EndNode endAfter = createNewMerge(fixed, stateAfter); + MergeNode mergeAfter = endAfter.merge(); + fixedNodes.add(endAfter); + final HashSet duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); + mergeAfter.clearEnds(); + expandDuplicated(duplicatedNodes, mergeAfter); + retargetDependencies(duplicatedNodes, anchor); + + List endSnapshot = merge.forwardEnds().snapshot(); + List phiSnapshot = merge.phis().snapshot(); + + int endIndex = 0; + for (final EndNode forwardEnd : merge.forwardEnds()) { + Map duplicates; + if (replacements == null || replacements.get(endIndex) == null) { + duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null); + } else { + HashMap replace = new HashMap<>(); + replace.put(replacements.get(endIndex).object(), replacements.get(endIndex)); + duplicates = graph.addDuplicates(duplicatedNodes, replace); + } + for (Map.Entry phi : bottomPhis.entrySet()) { + phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey())); + } + mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter)); + + // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding EndNode + FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor); + ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate); + // move dependencies on the ValueAnchorNode to the previous BeginNode + BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate); + anchorDuplicate.replaceAtUsages(prevBegin); + + // re-wire the phi duplicates to the correct input + for (PhiNode phi : phiSnapshot) { + PhiNode phiDuplicate = (PhiNode) duplicates.get(phi); + for (Node usage : phiDuplicate.usages()) { + if (usage instanceof ValueNode) { + ((ValueNode) usage).dependencies().add(prevBegin); + } + } + phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd)); + phiDuplicate.safeDelete(); + } + endIndex++; + } + GraphUtil.killCFG(merge); + for (EndNode forwardEnd : endSnapshot) { + forwardEnd.safeDelete(); + } + for (PhiNode phi : phiSnapshot) { + // these phis should go away, but they still need to be anchored to a merge to be valid... + if (phi.isAlive()) { + phi.setMerge(mergeAfter); + } + } + Debug.dump(graph, "After tail duplication at %s", merge); + } + + /** + * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not phis) to this + * ValueAnchorNode. + * + * @return The new {@link ValueAnchorNode} that was created. + */ + private ValueAnchorNode addValueAnchor() { + ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); + graph.addAfterFixed(merge, anchor); + for (Node usage : merge.usages().snapshot()) { + if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) { + // nothing to do + } else { + usage.replaceFirstInput(merge, anchor); + } + } + return anchor; + } + + /** + * Given a set of fixed nodes, this method determines the set of fixed and floating nodes that needs to be + * duplicated, i.e., all nodes that due to data flow and other dependencies needs to be duplicated. + * + * @param fixedNodes The set of fixed nodes that should be duplicated. + * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All {@link ValueNode}s + * reachable from this state are considered to be reachable from within the duplicated set of nodes. + * @return The set of nodes that need to be duplicated. + */ + private HashSet buildDuplicatedNodeSet(final ArrayList fixedNodes, FrameState stateAfter) { + final NodeBitMap aboveBound = graph.createNodeBitMap(); + final NodeBitMap belowBound = graph.createNodeBitMap(); + + final Deque worklist = new ArrayDeque<>(); + + // Build the set of nodes that have (transitive) usages within the duplicatedNodes. + // This is achieved by iterating all nodes that are reachable via inputs from the the fixed nodes. + aboveBound.markAll(fixedNodes); + worklist.addAll(fixedNodes); + + // the phis at the original merge should always be duplicated + for (PhiNode phi : merge.phis()) { + aboveBound.mark(phi); + worklist.add(phi); + } + + NodeClosure aboveClosure = new NodeClosure() { + + @Override + public void apply(Node usage, Node node) { + if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) { + // stop iterating: phis belonging to outside merges are known to be outside. + } else if (node instanceof FixedNode) { + // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other + // fixed nodes are known to be outside. + } else if (!aboveBound.isMarked(node)) { + worklist.add(node); + aboveBound.mark(node); + } + } + }; + + if (stateAfter != null) { + stateAfter.applyToNonVirtual(aboveClosure); + } + while (!worklist.isEmpty()) { + Node current = worklist.remove(); + for (Node input : current.inputs()) { + aboveClosure.apply(current, input); + } + } + + // Build the set of nodes that have (transitive) inputs within the duplicatedNodes. + // This is achieved by iterating all nodes that are reachable via usages from the fixed nodes. + belowBound.markAll(fixedNodes); + worklist.addAll(fixedNodes); + + // the phis at the original merge should always be duplicated + for (PhiNode phi : merge.phis()) { + belowBound.mark(phi); + worklist.add(phi); + } + + while (!worklist.isEmpty()) { + Node current = worklist.remove(); + for (Node usage : current.usages()) { + if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) { + // stop iterating: phis belonging to outside merges are known to be outside. + } else if (usage instanceof FixedNode) { + // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other + // fixed nodes are known to be outside. + } else if (!belowBound.isMarked(usage)) { + worklist.add(usage); + belowBound.mark(usage); + } + } + } + + // build the intersection + belowBound.intersect(aboveBound); + HashSet result = new HashSet<>(); + for (Node node : belowBound) { + result.add(node); + } + return result; + } + + /** + * Creates a new merge and end node construct at the end of the duplicated area. While it is useless in itself + * (merge with only one end) it simplifies the later duplication step. + * + * @param successor The successor of the duplicated set of nodes, i.e., the first node that should not be + * duplicated. + * @param stateAfterMerge The frame state that should be used for the merge. + * @return The newly created end node. + */ + private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { + MergeNode newBottomMerge = graph.add(new MergeNode()); + newBottomMerge.setProbability(successor.probability()); + EndNode newBottomEnd = graph.add(new EndNode()); + newBottomMerge.addForwardEnd(newBottomEnd); + newBottomMerge.setStateAfter(stateAfterMerge); + ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd); + newBottomMerge.setNext(successor); + return newBottomEnd; + } + + /** + * Expands the set of nodes to be duplicated by looking at a number of conditions: + *
    + *
  • {@link ValueNode}s that have usages on the outside need to be replaced with phis for the outside usages.
  • + *
  • Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object states, ...) need to + * be cloned immediately for the outside usages.
  • + *
  • Nodes that have a {@link StampFactory#extension()} or {@link StampFactory#condition()} stamp need to be + * cloned immediately for the outside usages.
  • + *
  • Dependencies into the duplicated nodes will be replaced with dependencies on the merge.
  • + *
  • Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to also be duplicated. + *
  • + *
  • Outside {@link ValueNode}s with {@link StampFactory#extension()} or {@link StampFactory#condition()} + * stamps that have usages within the duplicated set of nodes need to also be duplicated.
  • + *
+ * + * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded). + * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used for newly created + * phis and to as a target for dependencies that pointed into the duplicated set of nodes. + */ + private void expandDuplicated(HashSet duplicatedNodes, MergeNode newBottomMerge) { + Deque worklist = new ArrayDeque<>(duplicatedNodes); + + while (!worklist.isEmpty()) { + Node duplicated = worklist.remove(); + if (hasUsagesOutside(duplicated, duplicatedNodes)) { + boolean cloneForOutsideUsages = false; + if (duplicated instanceof ValueNode) { + ValueNode node = (ValueNode) duplicated; + if (node.stamp() == StampFactory.dependency()) { + // re-route dependencies to the merge + replaceUsagesOutside(node, newBottomMerge, duplicatedNodes); + // TODO(ls) maybe introduce phis for dependencies + } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) { + cloneForOutsideUsages = true; + } else { + // introduce a new phi + PhiNode newPhi = bottomPhis.get(node); + if (newPhi == null) { + newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge)); + bottomPhis.put(node, newPhi); + newPhi.addInput(node); + } + replaceUsagesOutside(node, newPhi, duplicatedNodes); + } + } else { + cloneForOutsideUsages = true; + } + if (cloneForOutsideUsages) { + // clone the offending node to the outside + Node newOutsideClone = duplicated.copyWithInputs(); + replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes); + // this might cause other nodes to have outside usages, we need to look at those as well + for (Node input : newOutsideClone.inputs()) { + if (duplicatedNodes.contains(input)) { + worklist.add(input); + } + } + } + } + // check if this node has an input that lies outside and cannot be shared + for (Node input : duplicated.inputs()) { + if (!duplicatedNodes.contains(input)) { + boolean duplicateInput = false; + if (input instanceof VirtualState) { + duplicateInput = true; + } else if (input instanceof ValueNode) { + Stamp inputStamp = ((ValueNode) input).stamp(); + if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) { + duplicateInput = true; + } + } + if (duplicateInput) { + duplicatedNodes.add(input); + worklist.add(input); + } + } + } + } + } + + /** + * Moves all depdendencies that point outside the duplicated area to the supplied value anchor node. + * + * @param duplicatedNodes The set of duplicated nodes. + * @param anchor The node that will be the new target for all dependencies that point outside the duplicated set of nodes. + */ + private static void retargetDependencies(HashSet duplicatedNodes, ValueAnchorNode anchor) { + for (Node node : duplicatedNodes) { + if (node instanceof ValueNode) { + NodeInputList dependencies = ((ValueNode) node).dependencies(); + for (int i = 0; i < dependencies.size(); i++) { + Node dependency = dependencies.get(i); + if (dependency != null && !duplicatedNodes.contains(dependency)) { + Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node); + dependencies.set(i, anchor); + } + } + } + } + } + + /** + * Checks if the given node has usages that are not within the given set of nodes. + * + * @param node The node whose usages are checked. + * @param nodeSet The set of nodes that are considered to be "within". + * @return true if the given node has usages on the outside, false otherwise. + */ + private static boolean hasUsagesOutside(Node node, HashSet nodeSet) { + for (Node usage : node.usages()) { + if (!nodeSet.contains(usage)) { + return true; + } + } + return false; + } + + /** + * Replaces the given node with the given replacement at all usages that are not within the given set of nodes. + * + * @param node The node to be replaced at outside usages. + * @param replacement The node that replaced the given node at outside usages. + * @param nodeSet The set of nodes that are considered to be "within". + */ + private static void replaceUsagesOutside(Node node, Node replacement, HashSet nodeSet) { + for (Node usage : node.usages().snapshot()) { + if (!nodeSet.contains(usage)) { + usage.replaceFirstInput(node, replacement); + } + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/BlockClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/BlockClosure.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.schedule; + +import com.oracle.graal.lir.cfg.*; + +/** + * The {@code BlockClosure} interface represents a closure for iterating over blocks. + */ +public interface BlockClosure { + void apply(Block block); +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/SchedulePhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.schedule; + +import java.util.*; + +import com.oracle.max.criutils.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.virtual.*; + +public class SchedulePhase extends Phase { + private ControlFlowGraph cfg; + private NodeMap earliestCache; + + /** + * Map from blocks to the nodes in each block. + */ + private BlockMap> blockToNodesMap; + + public SchedulePhase() { + super("Schedule"); + } + + @Override + protected void run(StructuredGraph graph) { + cfg = ControlFlowGraph.compute(graph, true, true, true, false); + earliestCache = graph.createNodeMap(); + blockToNodesMap = new BlockMap<>(cfg); + + assignBlockToNodes(graph); + sortNodesWithinBlocks(graph); + } + + /** + * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}. + * This method should thus only be called when run has been successfully executed. + */ + public void scheduleGraph() { + assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; + for (Block block : cfg.getBlocks()) { + List nodeList = blockToNodesMap.get(block); + ScheduledNode last = null; + for (ScheduledNode node : nodeList) { + if (last != null) { + last.setScheduledNext(node); + } + last = node; + } + } + } + + public ControlFlowGraph getCFG() { + return cfg; + } + + /** + * Gets the map from each block to the nodes in the block. + */ + public BlockMap> getBlockToNodesMap() { + return blockToNodesMap; + } + + /** + * Gets the nodes in a given block. + */ + public List nodesFor(Block block) { + return blockToNodesMap.get(block); + } + + private void assignBlockToNodes(StructuredGraph graph) { + for (Block block : cfg.getBlocks()) { + List nodes = new ArrayList<>(); + assert blockToNodesMap.get(block) == null; + blockToNodesMap.put(block, nodes); + for (FixedNode node : block.getNodes()) { + nodes.add(node); + } + } + + for (Node n : graph.getNodes()) { + if (n instanceof ScheduledNode) { + assignBlockToNode((ScheduledNode) n); + } + } + } + + /** + * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a block. + */ + private void assignBlockToNode(ScheduledNode node) { + assert !node.isDeleted(); + + Block prevBlock = cfg.getNodeToBlock().get(node); + if (prevBlock != null) { + return; + } + // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks + assert !(node instanceof PhiNode) : node; + assert !(node instanceof FixedNode) : node; + // if in CFG, schedule at the latest position possible in the outermost loop possible + Block latestBlock = latestBlock(node); + Block block; + if (latestBlock == null) { + block = earliestBlock(node); + } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { + Block earliestBlock = earliestBlock(node); + block = scheduleOutOfLoops(node, latestBlock, earliestBlock); + assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; + } else { + block = latestBlock; + } + cfg.getNodeToBlock().set(node, block); + blockToNodesMap.get(block).add(node); + } + + /** + * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages. + * To do so all usages are also assigned to blocks. + */ + private Block latestBlock(ScheduledNode node) { + CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); + for (Node succ : node.successors().nonNull()) { + assert cfg.getNodeToBlock().get(succ) != null; + cdbc.apply(cfg.getNodeToBlock().get(succ)); + } + ensureScheduledUsages(node); + for (Node usage : node.usages()) { + blocksForUsage(node, usage, cdbc); + } + return cdbc.block; + } + + /** + * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method. + */ + private static class CommonDominatorBlockClosure implements BlockClosure { + public Block block; + public CommonDominatorBlockClosure(Block block) { + this.block = block; + } + @Override + public void apply(Block newBlock) { + this.block = getCommonDominator(this.block, newBlock); + } + } + + /** + * Determines the earliest block in which the given node can be scheduled. + */ + private Block earliestBlock(Node node) { + Block earliest = cfg.getNodeToBlock().get(node); + if (earliest != null) { + return earliest; + } + earliest = earliestCache.get(node); + if (earliest != null) { + return earliest; + } + /* + * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the + * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block + * placement for this node we need to find the input block that is dominated by all other input blocks. + * + * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained. + * When the block of an input is not within this set, it becomes the current earliest placement and the list of + * dominator blocks is updated. + */ + BitSet dominators = new BitSet(cfg.getBlocks().length); + + assert node.predecessor() == null; + for (Node input : node.inputs().nonNull()) { + assert input instanceof ValueNode; + Block inputEarliest = earliestBlock(input); + if (!dominators.get(inputEarliest.getId())) { + earliest = inputEarliest; + do { + dominators.set(inputEarliest.getId()); + inputEarliest = inputEarliest.getDominator(); + } while(inputEarliest != null && !dominators.get(inputEarliest.getId())); + } + } + if (earliest == null) { + earliest = cfg.getStartBlock(); + } + earliestCache.set(node, earliest); + return earliest; + } + + + private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) { + assert latestBlock != null : "no latest : " + n; + Block cur = latestBlock; + Block result = latestBlock; + while (cur.getLoop() != null && cur != earliest && cur.getDominator() != null) { + Block dom = cur.getDominator(); + if (dom.getLoopDepth() < result.getLoopDepth()) { + result = dom; + } + cur = dom; + } + return result; + } + + /** + * Passes all blocks that a specific usage of a node is in to a given closure. + * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates. + * + * @param node the node that needs to be scheduled + * @param usage the usage whose blocks need to be considered + * @param closure the closure that will be called for each block + */ + private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { + assert !(node instanceof PhiNode); + + if (usage instanceof PhiNode) { + // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input. + // One PhiNode can use an input multiple times, the closure will be called for each usage. + PhiNode phi = (PhiNode) usage; + MergeNode merge = phi.merge(); + Block mergeBlock = cfg.getNodeToBlock().get(merge); + assert mergeBlock != null : "no block for merge " + merge.toString(Verbosity.Id); + for (int i = 0; i < phi.valueCount(); ++i) { + if (phi.valueAt(i) == node) { + if (mergeBlock.getPredecessors().size() <= i) { + TTY.println(merge.toString()); + TTY.println(phi.toString()); + TTY.println(merge.cfgPredecessors().toString()); + TTY.println(mergeBlock.getPredecessors().toString()); + TTY.println(phi.inputs().toString()); + TTY.println("value count: " + phi.valueCount()); + } + closure.apply(mergeBlock.getPredecessors().get(i)); + } + } + } else if (usage instanceof VirtualState) { + // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes. + for (Node unscheduledUsage : usage.usages()) { + if (unscheduledUsage instanceof VirtualState) { + // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing. + blocksForUsage(node, unscheduledUsage, closure); + } else if (unscheduledUsage instanceof MergeNode) { + // Only FrameStates can be connected to MergeNodes. + assert usage instanceof FrameState; + // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes. + for (Node pred : unscheduledUsage.cfgPredecessors()) { + closure.apply(cfg.getNodeToBlock().get(pred)); + } + } else { + // For the time being, only FrameStates can be connected to StateSplits. + assert usage instanceof FrameState; + assert unscheduledUsage instanceof StateSplit; + // Otherwise: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) unscheduledUsage); + closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); + } + } + } else { + // All other types of usages: Put the input into the same block as the usage. + assignBlockToNode((ScheduledNode) usage); + closure.apply(cfg.getNodeToBlock().get(usage)); + } + } + + private void ensureScheduledUsages(Node node) { + for (Node usage : node.usages().filter(ScheduledNode.class)) { + assignBlockToNode((ScheduledNode) usage); + } + // now true usages are ready + } + + private static Block getCommonDominator(Block a, Block b) { + if (a == null) { + return b; + } + if (b == null) { + return a; + } + return ControlFlowGraph.commonDominator(a, b); + } + + private void sortNodesWithinBlocks(StructuredGraph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + for (Block b : cfg.getBlocks()) { + sortNodesWithinBlock(b, visited); + } + } + + /** + * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs. + * This means that a node is added to the list after all its inputs have been processed. + */ + private void sortNodesWithinBlock(Block b, NodeBitMap visited) { + List instructions = blockToNodesMap.get(b); + List sortedInstructions = new ArrayList<>(instructions.size() + 2); + + assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; + assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + + for (ScheduledNode i : instructions) { + addToSorting(b, i, sortedInstructions, visited); + } + + // Make sure that last node gets really last (i.e. when a frame state successor hangs off it). + Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1); + if (lastSorted != b.getEndNode()) { + int idx = sortedInstructions.indexOf(b.getEndNode()); + boolean canNotMove = false; + for (int i = idx + 1; i < sortedInstructions.size(); i++) { + if (sortedInstructions.get(i).inputs().contains(b.getEndNode())) { + canNotMove = true; + break; + } + } + if (canNotMove) { + if (b.getEndNode() instanceof ControlSplitNode) { + throw new GraalInternalError("Schedule is not possible : needs to move a node after the last node of the block which can not be move"). + addContext(lastSorted). + addContext(b.getEndNode()); + } + + //b.setLastNode(lastSorted); + } else { + sortedInstructions.remove(b.getEndNode()); + sortedInstructions.add(b.getEndNode()); + } + } + blockToNodesMap.put(b, sortedInstructions); + } + + private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { + if (state != null) { + // UnscheduledNodes should never be marked as visited. + assert !visited.isMarked(state); + + for (Node input : state.inputs()) { + if (input instanceof VirtualState) { + addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); + } else { + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + } + } + + private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { + return; + } + + FrameState state = null; + WriteNode write = null; + for (Node input : i.inputs()) { + if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { + assert write == null; + write = (WriteNode) input; + } else if (input instanceof FrameState) { + assert state == null; + state = (FrameState) input; + } else { + addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + + addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + visited.mark(i); + addUnscheduledToSorting(b, state, sortedInstructions, visited); + assert write == null || !visited.isMarked(write); + addToSorting(b, write, sortedInstructions, visited); + + // Now predecessors and inputs are scheduled => we can add this node. + sortedInstructions.add(i); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/ArrayMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/ArrayMap.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.util; + +/** + * The {@code ArrayMap} class implements an efficient one-level map which is implemented + * as an array. Note that because of the one-level array inside, this data structure performs best + * when the range of integer keys is small and densely used. Note that the implementation can + * handle arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. + */ +public class ArrayMap { + + private static final int INITIAL_SIZE = 5; // how big the initial array should be + private static final int EXTRA = 2; // how far on the left or right of a new element to grow + + Object[] map; + int low; + + /** + * Constructs a new {@code ArrayMap} with no initial assumptions. + */ + public ArrayMap() { + } + + /** + * Constructs a new {@code ArrayMap} that initially covers the specified interval. + * Note that this map will automatically expand if necessary later. + * @param low the low index, inclusive + * @param high the high index, exclusive + */ + public ArrayMap(int low, int high) { + this.low = low; + this.map = new Object[high - low + 1]; + } + + /** + * Puts a new value in the map at the specified index. + * @param i the index at which to store the value + * @param value the value to store at the specified index + */ + public void put(int i, T value) { + int index = i - low; + if (map == null) { + // no map yet + map = new Object[INITIAL_SIZE]; + low = index - 2; + map[INITIAL_SIZE / 2] = value; + } else if (index < 0) { + // grow backwards + growBackward(i, value); + } else if (index >= map.length) { + // grow forwards + growForward(i, value); + } else { + // no growth necessary + map[index] = value; + } + } + + /** + * Gets the value at the specified index in the map. + * @param i the index + * @return the value at the specified index; {@code null} if there is no value at the specified index, + * or if the index is out of the currently stored range + */ + public T get(int i) { + int index = i - low; + if (map == null || index < 0 || index >= map.length) { + return null; + } + Class type = null; + return Util.uncheckedCast(type, map[index]); + } + + public int length() { + return map.length; + } + + private void growBackward(int i, T value) { + int nlow = i - EXTRA; + Object[] nmap = new Object[low - nlow + map.length]; + System.arraycopy(map, 0, nmap, low - nlow, map.length); + map = nmap; + low = nlow; + map[i - low] = value; + } + + private void growForward(int i, T value) { + int nlen = i - low + 1 + EXTRA; + Object[] nmap = new Object[nlen]; + System.arraycopy(map, 0, nmap, 0, map.length); + map = nmap; + map[i - low] = value; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BitMap2D.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BitMap2D.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.util; + +import java.util.*; + +/** + * This class implements a two-dimensional bitmap. + */ +public final class BitMap2D { + + private BitSet map; + private final int bitsPerSlot; + + private int bitIndex(int slotIndex, int bitWithinSlotIndex) { + return slotIndex * bitsPerSlot + bitWithinSlotIndex; + } + + private boolean verifyBitWithinSlotIndex(int index) { + assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; + return true; + } + + public BitMap2D(int sizeInSlots, int bitsPerSlot) { + map = new BitSet(sizeInSlots * bitsPerSlot); + this.bitsPerSlot = bitsPerSlot; + } + + public int sizeInBits() { + return map.size(); + } + + // Returns number of full slots that have been allocated + public int sizeInSlots() { + return map.size() / bitsPerSlot; + } + + public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); + } + + public boolean at(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void setBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.set(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void clearBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { + int size = sizeInSlots(); + if (size <= slotIndex) { + while (size <= slotIndex) { + size *= 2; + } + BitSet newBitMap = new BitSet(size * bitsPerSlot); + newBitMap.or(map); + map = newBitMap; + } + + if (value) { + setBit(slotIndex, bitWithinSlotIndex); + } else { + clearBit(slotIndex, bitWithinSlotIndex); + } + } + + public void clear() { + map.clear(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BlockWorkList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/BlockWorkList.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.util; + +import com.oracle.graal.nodes.*; + +/** + * This class implements a worklist for dealing with blocks. The worklist can + * operate either as a stack (i.e. first-in / last-out), or as a sorted list, + * where blocks can be sorted by a supplied number. The latter usage lends itself + * naturally to iterative dataflow analysis problems. + */ +public class BlockWorkList { + MergeNode[] workList; + int[] workListNumbers; + int workListIndex; + + /** + * Adds a block to this list in an unsorted fashion, like a stack. + * @param block the block to add + */ + public void add(MergeNode block) { + if (workList == null) { + // worklist not allocated yet + allocate(); + } else if (workListIndex == workList.length) { + // need to grow the worklist + grow(); + } + // put the block at the end of the array + workList[workListIndex++] = block; + } + + /** + * Adds a block to this list, sorted by the supplied number. The block + * with the lowest number is returned upon subsequent removes. + * @param block the block to add + * @param number the number used to sort the block + */ + public void addSorted(MergeNode block, int number) { + if (workList == null) { + // worklist not allocated yet + allocate(); + } else if (workListIndex == workList.length) { + // need to grow the worklist + grow(); + } + // put the block at the end of the array + workList[workListIndex] = block; + workListNumbers[workListIndex] = number; + workListIndex++; + int i = workListIndex - 2; + // push block towards the beginning of the array + for (; i >= 0; i--) { + int n = workListNumbers[i]; + if (n >= number) { + break; // already in the right position + } + workList[i + 1] = workList[i]; // bubble b down by one + workList[i] = block; // and overwrite its place with block + workListNumbers[i + 1] = n; // bubble n down by one + workListNumbers[i] = number; // and overwrite its place with number + } + } + + /** + * Removes the next block from this work list. If the blocks have been added + * in a sorted order, then the block with the lowest number is returned. Otherwise, + * the last block added is returned. + * @return the next block in the list + */ + public MergeNode removeFromWorkList() { + if (workListIndex != 0) { + return workList[--workListIndex]; + } + return null; + } + + /** + * Checks whether the list is empty. + * @return {@code true} if this list is empty + */ + public boolean isEmpty() { + return workListIndex == 0; + } + + private void allocate() { + workList = new MergeNode[5]; + workListNumbers = new int[5]; + } + + private void grow() { + int prevLength = workList.length; + MergeNode[] nworkList = new MergeNode[prevLength * 3]; + System.arraycopy(workList, 0, nworkList, 0, prevLength); + workList = nworkList; + + int[] nworkListNumbers = new int[prevLength * 3]; + System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength); + workListNumbers = nworkListNumbers; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/GraphOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/GraphOrder.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011, 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.util; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +public class GraphOrder implements Iterable { + + private final ArrayList nodes = new ArrayList<>(); + + private GraphOrder() { + } + + public GraphOrder(Graph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + + for (ReturnNode node : graph.getNodes(ReturnNode.class)) { + visitForward(visited, node); + } + for (UnwindNode node : graph.getNodes(UnwindNode.class)) { + visitForward(visited, node); + } + for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { + visitForward(visited, node); + } + } + + public static GraphOrder forwardGraph(Graph graph) { + GraphOrder result = new GraphOrder(); + + NodeBitMap visited = graph.createNodeBitMap(); + + for (ReturnNode node : graph.getNodes(ReturnNode.class)) { + result.visitForward(visited, node); + } + for (UnwindNode node : graph.getNodes(UnwindNode.class)) { + result.visitForward(visited, node); + } + for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { + result.visitForward(visited, node); + } + return result; + } + + public static GraphOrder backwardGraph(Graph graph) { + GraphOrder result = new GraphOrder(); + + NodeBitMap visited = graph.createNodeBitMap(); + + for (Node node : forwardGraph(graph)) { + result.visitBackward(visited, node); + } + return result; + } + + private void visitForward(NodeBitMap visited, Node node) { + if (node != null && !visited.isMarked(node)) { + visited.mark(node); + if (node.predecessor() != null) { + visitForward(visited, node.predecessor()); + } + if (node instanceof MergeNode) { + // make sure that the cfg predecessors of a MergeNode are processed first + MergeNode merge = (MergeNode) node; + for (int i = 0; i < merge.forwardEndCount(); i++) { + visitForward(visited, merge.forwardEndAt(i)); + } + } + for (Node input : node.inputs()) { + visitForward(visited, input); + } + nodes.add(node); + } + } + + private void visitBackward(NodeBitMap visited, Node node) { + if (node != null && !visited.isMarked(node)) { + visited.mark(node); + for (Node successor : node.successors()) { + visitBackward(visited, successor); + } + for (Node usage : node.usages()) { + visitBackward(visited, usage); + } + nodes.add(node); + } + } + + @Override + public Iterator iterator() { + return new Iterator() { + + private int pos = 0; + + private void removeDeleted() { + while (pos < nodes.size() && nodes.get(pos).isDeleted()) { + pos++; + } + } + + @Override + public boolean hasNext() { + removeDeleted(); + return pos < nodes.size(); + } + + @Override + public Node next() { + return nodes.get(pos++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/InliningUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/InliningUtil.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,954 @@ +/* + * 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.util; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.FrameState.InliningIdentifier; +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.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +public class InliningUtil { + + private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication"); + + public interface InliningCallback { + StructuredGraph buildGraph(ResolvedJavaMethod method); + double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke); + void recordMethodContentsAssumption(ResolvedJavaMethod method); + void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl); + } + + public static String methodName(ResolvedJavaMethod method, Invoke invoke) { + if (!Debug.isLogEnabled()) { + return null; + } else if (invoke != null && invoke.stateAfter() != null) { + return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; + } else { + return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; + } + } + + public static String methodName(InlineInfo info) { + if (!Debug.isLogEnabled()) { + return null; + } else if (info.invoke != null && info.invoke.stateAfter() != null) { + return methodName(info.invoke.stateAfter(), info.invoke.bci()) + ": " + info.toString(); + } else { + return info.toString(); + } + } + + private static String methodName(FrameState frameState, int bci) { + StringBuilder sb = new StringBuilder(); + if (frameState.outerFrameState() != null) { + sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci)); + sb.append("->"); + } + sb.append(MetaUtil.format("%h.%n", frameState.method())); + sb.append("@").append(bci); + return sb.toString(); + } + + /** + * 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. + * The level is the number of nested inlinings that lead to this invoke. + */ + public abstract static class InlineInfo implements Comparable { + public final Invoke invoke; + public final double weight; + public final int level; + + public InlineInfo(Invoke invoke, double weight, int level) { + this.invoke = invoke; + this.weight = weight; + this.level = level; + } + + public abstract int compiledCodeSize(); + + @Override + public int compareTo(InlineInfo o) { + return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0; + } + + protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) { + return Debug.scope("GetInliningGraph", concrete, new Callable() { + @Override + public StructuredGraph call() throws Exception { + return callback.buildGraph(concrete); + } + }); + } + + public abstract boolean canDeopt(); + + /** + * Performs the inlining described by this object and returns the node that represents the return value of the + * inlined method (or null for void methods and methods that have no non-exceptional exit). + * + * @param graph + * @param runtime + * @param callback + */ + public abstract void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback); + } + + /** + * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and + * therefore is able to determine the called method exactly. + */ + private static class ExactInlineInfo extends InlineInfo { + public final ResolvedJavaMethod concrete; + + public ExactInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete) { + super(invoke, weight, level); + this.concrete = concrete; + } + + @Override + public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, final InliningCallback callback) { + StructuredGraph graph = getGraph(concrete, callback); + assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); + callback.recordMethodContentsAssumption(concrete); + InliningUtil.inline(invoke, graph, true); + } + + @Override + public int compiledCodeSize() { + return concrete.compiledCodeSize(); + } + + @Override + public String toString() { + return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete); + } + + @Override + public boolean canDeopt() { + return false; + } + } + + /** + * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which + * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed. + */ + private static class TypeGuardInlineInfo extends InlineInfo { + public final ResolvedJavaMethod concrete; + public final ResolvedJavaType type; + + public TypeGuardInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete, ResolvedJavaType type) { + super(invoke, weight, level); + this.concrete = concrete; + this.type = type; + } + + @Override + public int compiledCodeSize() { + return concrete.compiledCodeSize(); + } + + @Override + public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { + // receiver null check must be before the type check + InliningUtil.receiverNullCheck(invoke); + ValueNode receiver = invoke.methodCallTarget().receiver(); + ReadHubNode objectClass = graph.add(new ReadHubNode(receiver)); + IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type)); + FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId())); + ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); + assert invoke.predecessor() != null; + + ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true); + invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); + + graph.addBeforeFixed(invoke.node(), objectClass); + graph.addBeforeFixed(invoke.node(), guard); + graph.addBeforeFixed(invoke.node(), anchor); + + StructuredGraph calleeGraph = getGraph(concrete, callback); + assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); + callback.recordMethodContentsAssumption(concrete); + InliningUtil.inline(invoke, calleeGraph, false); + } + + @Override + public String toString() { + return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete); + } + + @Override + public boolean canDeopt() { + return true; + } + } + + /** + * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable + * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered. + */ + private static class MultiTypeGuardInlineInfo extends InlineInfo { + public final List concretes; + public final ProfiledType[] ptypes; + public final int[] typesToConcretes; + public final double notRecordedTypeProbability; + + public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List concretes, ProfiledType[] ptypes, + int[] typesToConcretes, double notRecordedTypeProbability) { + super(invoke, weight, level); + assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods"; + assert ptypes.length == typesToConcretes.length : "array lengths must match"; + + this.concretes = concretes; + this.ptypes = ptypes; + this.typesToConcretes = typesToConcretes; + this.notRecordedTypeProbability = notRecordedTypeProbability; + } + + @Override + public int compiledCodeSize() { + int result = 0; + for (ResolvedJavaMethod m: concretes) { + result += m.compiledCodeSize(); + } + return result; + } + + @Override + public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { + int numberOfMethods = concretes.size(); + boolean hasReturnValue = invoke.node().kind() != Kind.Void; + + // receiver null check must be the first node + InliningUtil.receiverNullCheck(invoke); + if (numberOfMethods > 1 || shouldFallbackToInvoke()) { + inlineMultipleMethods(graph, runtime, callback, numberOfMethods, hasReturnValue); + } else { + inlineSingleMethod(graph, runtime, callback); + } + } + + private boolean shouldFallbackToInvoke() { + return notRecordedTypeProbability > 0; + } + + private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) { + FixedNode continuation = invoke.next(); + + ValueNode originalReceiver = invoke.methodCallTarget().receiver(); + // setup merge and phi nodes for results and exceptions + MergeNode returnMerge = graph.add(new MergeNode()); + returnMerge.setProbability(invoke.probability()); + returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci)); + + PhiNode returnValuePhi = null; + if (hasReturnValue) { + returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge)); + } + + MergeNode exceptionMerge = null; + PhiNode exceptionObjectPhi = null; + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; + DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + + exceptionMerge = graph.add(new MergeNode()); + exceptionMerge.setProbability(exceptionEdge.probability()); + + FixedNode exceptionSux = exceptionObject.next(); + graph.addBeforeFixed(exceptionSux, exceptionMerge); + exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge)); + exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi)); + } + + // create one separate block for each invoked method + BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods]; + for (int i = 0; i < numberOfMethods; i++) { + int predecessors = 0; + double probability = 0; + for (int j = 0; j < typesToConcretes.length; j++) { + if (typesToConcretes[j] == i) { + predecessors++; + probability += ptypes[j].probability; + } + } + + calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, invoke.probability() * probability, true); + } + + // create the successor for an unknown type + FixedNode unknownTypeNode; + if (shouldFallbackToInvoke()) { + unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false); + } else { + unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); + } + + // replace the invoke exception edge + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke; + BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + exceptionObject.replaceAtUsages(exceptionObjectPhi); + exceptionObject.setNext(null); + GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge()); + } + + // replace the invoke with a switch on the type of the actual receiver + ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.methodCallTarget().receiver())); + graph.addBeforeFixed(invoke.node(), objectClassNode); + FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, calleeEntryNodes, unknownTypeNode); + + assert invoke.next() == continuation; + invoke.setNext(null); + returnMerge.setNext(continuation); + invoke.node().replaceAtUsages(returnValuePhi); + invoke.node().replaceAndDelete(dispatchOnType); + + ArrayList replacements = new ArrayList<>(); + + // do the actual inlining for every invoke + for (int i = 0; i < calleeEntryNodes.length; i++) { + BeginNode node = calleeEntryNodes[i]; + Invoke invokeForInlining = (Invoke) node.next(); + + ResolvedJavaType commonType = getLeastCommonType(i); + ValueNode receiver = invokeForInlining.methodCallTarget().receiver(); + boolean exact = getTypeCount(i) == 1; + PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); + invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); + + ResolvedJavaMethod concrete = concretes.get(i); + StructuredGraph calleeGraph = getGraph(concrete, callback); + callback.recordMethodContentsAssumption(concrete); + assert !IntrinsificationPhase.canIntrinsify(invokeForInlining, concrete, runtime); + InliningUtil.inline(invokeForInlining, calleeGraph, false); + replacements.add(anchoredReceiver); + } + if (shouldFallbackToInvoke()) { + replacements.add(null); + } + if (GraalOptions.OptTailDuplication) { + /* + * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would + * benefit from the improvement in type information. + */ + FixedNode current = returnMerge; + int opportunities = 0; + do { + if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) { + opportunities++; + } else if (current.inputs().contains(originalReceiver)) { + opportunities++; + } + current = ((FixedWithNextNode) current).next(); + } while (current instanceof FixedWithNextNode); + if (opportunities > 0) { + metricInliningTailDuplication.increment(); + Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); + TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements); + } + } + } + + private int getTypeCount(int concreteMethodIndex) { + int count = 0; + for (int i = 0; i < typesToConcretes.length; i++) { + if (typesToConcretes[i] == concreteMethodIndex) { + count++; + } + } + return count; + } + + private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) { + ResolvedJavaType commonType = null; + for (int i = 0; i < typesToConcretes.length; i++) { + if (typesToConcretes[i] == concreteMethodIndex) { + if (commonType == null) { + commonType = ptypes[i].type; + } else { + commonType = commonType.leastCommonAncestor(ptypes[i].type); + } + } + } + assert commonType != null; + return commonType; + } + + private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { + assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; + + MergeNode calleeEntryNode = graph.add(new MergeNode()); + calleeEntryNode.setProbability(invoke.probability()); + ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.methodCallTarget().receiver())); + graph.addBeforeFixed(invoke.node(), objectClassNode); + + FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); + FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, unknownTypeNode); + + FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); + pred.setNext(dispatchOnType); + calleeEntryNode.setNext(invoke.node()); + + ResolvedJavaMethod concrete = concretes.get(0); + StructuredGraph calleeGraph = getGraph(concrete, callback); + assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); + callback.recordMethodContentsAssumption(concrete); + InliningUtil.inline(invoke, calleeGraph, false); + } + + private FixedNode createDispatchOnType(StructuredGraph graph, ReadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) { + assert ptypes.length > 1; + + ResolvedJavaType[] types = new ResolvedJavaType[ptypes.length]; + double[] probabilities = new double[ptypes.length + 1]; + BeginNode[] successors = new BeginNode[ptypes.length + 1]; + int[] keySuccessors = new int[ptypes.length + 1]; + for (int i = 0; i < ptypes.length; i++) { + types[i] = ptypes[i].type; + probabilities[i] = ptypes[i].probability; + FixedNode entry = calleeEntryNodes[typesToConcretes[i]]; + if (entry instanceof MergeNode) { + EndNode endNode = graph.add(new EndNode()); + ((MergeNode) entry).addForwardEnd(endNode); + entry = endNode; + } + successors[i] = BeginNode.begin(entry); + keySuccessors[i] = i; + } + assert !(unknownTypeSux instanceof MergeNode); + successors[successors.length - 1] = BeginNode.begin(unknownTypeSux); + probabilities[successors.length - 1] = notRecordedTypeProbability; + keySuccessors[successors.length - 1] = successors.length - 1; + + TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(objectClassNode, successors, probabilities, types, probabilities, keySuccessors)); + + return typeSwitch; + } + + private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, + MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, double probability, boolean useForInlining) { + Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability); + BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode()); + calleeEntryNode.setNext(duplicatedInvoke.node()); + calleeEntryNode.setProbability(probability); + + EndNode endNode = graph.add(new EndNode()); + endNode.setProbability(probability); + + duplicatedInvoke.setNext(endNode); + returnMerge.addForwardEnd(endNode); + + if (returnValuePhi != null) { + returnValuePhi.addInput(duplicatedInvoke.node()); + } + return calleeEntryNode; + } + + private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) { + Invoke result = (Invoke) invoke.node().copyWithInputs(); + Node callTarget = result.callTarget().copyWithInputs(); + result.node().replaceFirstInput(result.callTarget(), callTarget); + result.setUseForInlining(useForInlining); + result.setProbability(probability); + + Kind kind = invoke.node().kind(); + if (!kind.isVoid()) { + FrameState stateAfter = invoke.stateAfter(); + stateAfter = stateAfter.duplicate(stateAfter.bci); + stateAfter.replaceFirstInput(invoke.node(), result.node()); + result.setStateAfter(stateAfter); + } + + if (invoke instanceof InvokeWithExceptionNode) { + assert exceptionMerge != null && exceptionObjectPhi != null; + + InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; + BeginNode exceptionEdge = invokeWithException.exceptionEdge(); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + FrameState stateAfterException = exceptionObject.stateAfter(); + + BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); + ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); + // set new state (pop old exception object, push new one) + newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject)); + newExceptionEdge.setNext(newExceptionObject); + + EndNode endNode = graph.add(new EndNode()); + newExceptionObject.setNext(endNode); + exceptionMerge.addForwardEnd(endNode); + exceptionObjectPhi.addInput(newExceptionObject); + + ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge); + } + return result; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic"); + builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length)); + for (int i = 0; i < concretes.size(); i++) { + builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i))); + } + return builder.toString(); + } + + @Override + public boolean canDeopt() { + return true; + } + } + + + /** + * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method, + * but for which an assumption has to be registered because of non-final classes. + */ + private static class AssumptionInlineInfo extends ExactInlineInfo { + public final ResolvedJavaType context; + + public AssumptionInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaType context, ResolvedJavaMethod concrete) { + super(invoke, weight, level, concrete); + this.context = context; + } + + @Override + public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { + if (Debug.isLogEnabled()) { + String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod()); + String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete); + Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName); + } + callback.recordConcreteMethodAssumption(invoke.methodCallTarget().targetMethod(), context, concrete); + + super.inline(graph, runtime, callback); + } + + @Override + public String toString() { + return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete); + } + + @Override + public boolean canDeopt() { + return true; + } + } + + /** + * Determines if inlining is possible at the given invoke node. + * @param invoke the invoke that should be inlined + * @param level the number of nested inlinings that lead to this invoke, or 0 if the invoke was part of the initial graph + * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified + * @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, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) { + if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { + // The invoke has already been lowered , or has been created as a low-level node. We have no method information. + return null; + } + ResolvedJavaMethod parent = invoke.stateAfter().method(); + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod targetMethod = callTarget.targetMethod(); + if (targetMethod == null) { + return null; + } + if (!checkInvokeConditions(invoke)) { + return null; + } + + if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { + if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke); + return new ExactInlineInfo(invoke, weight, level, targetMethod); + } + return null; + } + ObjectStamp receiverStamp = callTarget.receiver().objectStamp(); + ResolvedJavaType receiverType = receiverStamp.type(); + if (receiverStamp.isExactType()) { + assert receiverType.isSubtypeOf(targetMethod.holder()) : receiverType + " subtype of " + targetMethod.holder() + " for " + targetMethod; + ResolvedJavaMethod resolved = receiverType.resolveMethodImpl(targetMethod); + if (checkTargetConditions(invoke, resolved, optimisticOpts)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke); + return new ExactInlineInfo(invoke, weight, level, resolved); + } + return null; + } + ResolvedJavaType holder = targetMethod.holder(); + + if (receiverStamp.type() != null) { + // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...) + // TODO (lstadler) fix this + if (receiverType != null && receiverType.isSubtypeOf(holder)) { + holder = receiverType; + } + } + // TODO (thomaswue) fix this + if (assumptions != null) { + ResolvedJavaMethod concrete = holder.uniqueConcreteMethod(targetMethod); + if (concrete != null) { + if (checkTargetConditions(invoke, concrete, optimisticOpts)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); + } + return null; + } + } + + // type check based inlining + return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts); + } + + private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, ResolvedJavaMethod parent, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { + ProfilingInfo profilingInfo = parent.profilingInfo(); + JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); + if (typeProfile != null) { + ProfiledType[] ptypes = typeProfile.getTypes(); + + if (ptypes != null && ptypes.length > 0) { + double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); + if (ptypes.length == 1 && notRecordedTypeProbability == 0) { + if (optimisticOpts.inlineMonomorphicCalls()) { + ResolvedJavaType type = ptypes[0].type; + ResolvedJavaMethod concrete = type.resolveMethodImpl(targetMethod); + if (checkTargetConditions(invoke, concrete, optimisticOpts)) { + double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); + } + + Debug.log("not inlining %s because method can't be inlined", methodName(targetMethod, invoke)); + return null; + } else { + Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(targetMethod, invoke)); + return null; + } + } else { + invoke.setMegamorphic(true); + 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 + // 3. do the inlining + // a) all seen methods can be inlined -> do so and guard with deopt + // b) some methods can be inlined -> inline them and fall back to invocation if violated + // TODO (chaeubl) sort types by probability + + // determine concrete methods and map type to specific method + ArrayList concreteMethods = new ArrayList<>(); + int[] typesToConcretes = new int[ptypes.length]; + for (int i = 0; i < ptypes.length; i++) { + ResolvedJavaMethod concrete = ptypes[i].type.resolveMethodImpl(targetMethod); + + int index = concreteMethods.indexOf(concrete); + if (index < 0) { + index = concreteMethods.size(); + concreteMethods.add(concrete); + } + typesToConcretes[i] = index; + } + + double totalWeight = 0; + boolean canInline = true; + for (ResolvedJavaMethod concrete: concreteMethods) { + if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { + canInline = false; + break; + } + totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); + } + + if (canInline) { + return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability); + } else { + Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(targetMethod, invoke)); + return null; + } + } else { + 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)); + } + return null; + } + } + } + + Debug.log("not inlining %s because no types/probabilities were recorded", methodName(targetMethod, invoke)); + return null; + } else { + Debug.log("not inlining %s because no type profile exists", methodName(targetMethod, invoke)); + return null; + } + } + + private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { + // to avoid that floating reads on receiver fields float above the type check + return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType))); + } + + private static boolean checkInvokeConditions(Invoke invoke) { + if (invoke.stateAfter() == null) { + Debug.log("not inlining %s because the invoke has no after state", methodName(invoke.methodCallTarget().targetMethod(), invoke)); + return false; + } + if (invoke.predecessor() == null) { + Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.methodCallTarget().targetMethod(), invoke)); + return false; + } + if (!invoke.useForInlining()) { + Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.methodCallTarget().targetMethod(), invoke)); + return false; + } + return true; + } + + private static boolean checkTargetConditions(Invoke invoke, JavaMethod method, OptimisticOptimizations optimisticOpts) { + if (method == null) { + Debug.log("not inlining because method is not resolved"); + return false; + } + if (!(method instanceof ResolvedJavaMethod)) { + Debug.log("not inlining %s because it is unresolved", method.toString()); + return false; + } + ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method; + if (Modifier.isNative(resolvedMethod.accessFlags())) { + 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, invoke)); + return false; + } + if (!resolvedMethod.holder().isInitialized()) { + 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, invoke)); + return false; + } + if (computeRecursiveInliningLevel(invoke.stateAfter(), (ResolvedJavaMethod) method) > GraalOptions.MaximumRecursiveInlining) { + 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; + } + + return true; + } + + private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) { + assert state != null; + + int count = 0; + FrameState curState = state; + while (curState != null) { + if (curState.method() == method) { + count++; + } + curState = curState.outerFrameState(); + } + return count; + } + + /** + * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. + * + * @param invoke the invoke that will be replaced + * @param inlineGraph the graph that the invoke will be replaced with + * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required + */ + public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { + InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke); + NodeInputList parameters = invoke.callTarget().arguments(); + StructuredGraph graph = (StructuredGraph) invoke.node().graph(); + + FrameState stateAfter = invoke.stateAfter(); + assert stateAfter.isAlive(); + + IdentityHashMap replacements = new IdentityHashMap<>(); + ArrayList nodes = new ArrayList<>(); + ReturnNode returnNode = null; + UnwindNode unwindNode = null; + StartNode entryPointNode = inlineGraph.start(); + FixedNode firstCFGNode = entryPointNode.next(); + for (Node node : inlineGraph.getNodes()) { + if (node == entryPointNode || node == entryPointNode.stateAfter()) { + // Do nothing. + } else if (node instanceof LocalNode) { + replacements.put(node, parameters.get(((LocalNode) node).index())); + } else { + nodes.add(node); + if (node instanceof ReturnNode) { + assert returnNode == null; + returnNode = (ReturnNode) node; + } else if (node instanceof UnwindNode) { + assert unwindNode == null; + unwindNode = (UnwindNode) node; + } + } + } + replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode + + assert invoke.node().successors().first() != null : invoke; + assert invoke.node().predecessor() != null; + + Map duplicates = graph.addDuplicates(nodes, replacements); + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + if (receiverNullCheck) { + receiverNullCheck(invoke); + } + invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate); + + FrameState stateAtExceptionEdge = null; + if (invoke instanceof InvokeWithExceptionNode) { + InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); + if (unwindNode != null) { + assert unwindNode.predecessor() != null; + assert invokeWithException.exceptionEdge().successors().count() == 1; + ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next(); + stateAtExceptionEdge = obj.stateAfter(); + UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); + obj.replaceAtUsages(unwindDuplicate.exception()); + unwindDuplicate.clearInputs(); + Node n = obj.next(); + obj.setNext(null); + unwindDuplicate.replaceAndDelete(n); + } else { + invokeWithException.killExceptionEdge(); + } + } else { + if (unwindNode != null) { + UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); + DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId()); + 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!) + if (deoptimizeNode.predecessor() instanceof MonitorExitNode) { + MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor(); + if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) { + FrameState monitorFrameState = monitorExit.stateAfter(); + graph.removeFixed(monitorExit); + monitorFrameState.safeDelete(); + } + } + } + } + + FrameState outerFrameState = null; + double invokeProbability = invoke.node().probability(); + for (Node node : duplicates.values()) { + if (GraalOptions.ProbabilityAnalysis) { + if (node instanceof FixedNode) { + FixedNode fixed = (FixedNode) node; + double newProbability = fixed.probability() * invokeProbability; + if (GraalOptions.LimitInlinedProbability) { + newProbability = Math.min(newProbability, invokeProbability); + } + fixed.setProbability(newProbability); + } + } + if (node instanceof FrameState) { + FrameState frameState = (FrameState) node; + assert frameState.bci != FrameState.BEFORE_BCI; + if (frameState.bci == FrameState.AFTER_BCI) { + frameState.replaceAndDelete(stateAfter); + } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { + if (frameState.isAlive()) { + assert stateAtExceptionEdge != null; + frameState.replaceAndDelete(stateAtExceptionEdge); + } else { + assert stateAtExceptionEdge == null; + } + } else { + if (outerFrameState == null) { + outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); + outerFrameState.setDuringCall(true); + } + frameState.setOuterFrameState(outerFrameState); + frameState.setInliningIdentifier(identifier); + } + } + } + + Node returnValue = null; + if (returnNode != null) { + if (returnNode.result() instanceof LocalNode) { + returnValue = replacements.get(returnNode.result()); + } else { + returnValue = duplicates.get(returnNode.result()); + } + invoke.node().replaceAtUsages(returnValue); + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.clearInputs(); + Node n = invoke.next(); + invoke.setNext(null); + returnDuplicate.replaceAndDelete(n); + } + + invoke.node().clearInputs(); + invoke.node().replaceAtUsages(null); + GraphUtil.killCFG(invoke.node()); + + if (stateAfter.usages().isEmpty()) { + stateAfter.safeDelete(); + } + } + + public static void receiverNullCheck(Invoke invoke) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + StructuredGraph graph = (StructuredGraph) invoke.graph(); + NodeInputList parameters = callTarget.arguments(); + ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); + if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) { + graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId()))); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/IntList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/IntList.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.util; + +import java.util.*; + +/** + * An expandable and indexable list of {@code int}s. + * + * This class avoids the boxing/unboxing incurred by {@code ArrayList}. + */ +public final class IntList { + + private int[] array; + private int size; + + /** + * Creates an int list with a specified initial capacity. + * + * @param initialCapacity + */ + public IntList(int initialCapacity) { + array = new int[initialCapacity]; + } + + /** + * Creates an int list with a specified initial array. + * + * @param array the initial array used for the list (no copy is made) + * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or equal to {@code array.length} + */ + public IntList(int[] array, int initialSize) { + assert initialSize <= array.length; + this.array = array; + this.size = initialSize; + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @return a new int list whose {@linkplain #size() size} and capacity is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length) { + return copy(other, startIndex, length, length); + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @param initialCapacity the initial capacity of the new int list (must be greater or equal to {@code length}) + * @return a new int list whose {@linkplain #size() size} is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) { + assert initialCapacity >= length : "initialCapacity < length"; + int[] array = new int[initialCapacity]; + System.arraycopy(other.array, startIndex, array, 0, length); + return new IntList(array, length); + } + + public int size() { + return size; + } + + /** + * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1. + * + * @param value the value to append + */ + public void add(int value) { + if (size == array.length) { + int newSize = (size * 3) / 2 + 1; + array = Arrays.copyOf(array, newSize); + } + array[size++] = value; + } + + /** + * Gets the value in this list at a given index. + * + * @param index the index of the element to return + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public int get(int index) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + return array[index]; + } + + /** + * Sets the size of this list to 0. + */ + public void clear() { + size = 0; + } + + /** + * Sets a value at a given index in this list. + * + * @param index the index of the element to update + * @param value the new value of the element + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public void set(int index, int value) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + array[index] = value; + } + + /** + * Adjusts the {@linkplain #size() size} of this int list. + * + * If {@code newSize < size()}, the size is changed to {@code newSize}. + * If {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} + * until {@code size() == newSize}. + * + * @param newSize the new size of this int list + */ + public void setSize(int newSize) { + if (newSize < size) { + size = newSize; + } else if (newSize > size) { + array = Arrays.copyOf(array, newSize); + } + } + + @Override + public String toString() { + if (array.length == size) { + return Arrays.toString(array); + } + return Arrays.toString(Arrays.copyOf(array, size)); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/Util.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.phases/src/com/oracle/graal/compiler/util/Util.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.util; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.max.criutils.*; + +/** + * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. + */ +public class Util { + + public static final int PRINTING_LINE_WIDTH = 40; + public static final char SECTION_CHARACTER = '*'; + public static final char SUB_SECTION_CHARACTER = '='; + public static final char SEPERATOR_CHARACTER = '-'; + + public static boolean replaceInList(T a, T b, List list) { + final int max = list.size(); + for (int i = 0; i < max; i++) { + if (list.get(i) == a) { + list.set(i, b); + return true; + } + } + return false; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(@SuppressWarnings("unused") Class type, Object object) { + return (T) object; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(Object object) { + return (T) object; + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the object to add to the hash + * @return the combined hash + */ + public static int hash1(int hash, Object x) { + // always set at least one bit in case the hash wraps to zero + return 0x10000000 | (hash + 7 * System.identityHashCode(x)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @return the combined hash + */ + public static int hash2(int hash, Object x, Object y) { + // always set at least one bit in case the hash wraps to zero + return 0x20000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @return the combined hash + */ + public static int hash3(int hash, Object x, Object y, Object z) { + // always set at least one bit in case the hash wraps to zero + return 0x30000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @param w the fourth object to add to the hash + * @return the combined hash + */ + public static int hash4(int hash, Object x, Object y, Object z, Object w) { + // always set at least one bit in case the hash wraps to zero + return 0x40000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z) + 17 * System.identityHashCode(w)); + } + + static { + assert CodeUtil.log2(2) == 1; + assert CodeUtil.log2(4) == 2; + assert CodeUtil.log2(8) == 3; + assert CodeUtil.log2(16) == 4; + assert CodeUtil.log2(32) == 5; + assert CodeUtil.log2(0x40000000) == 30; + + assert CodeUtil.log2(2L) == 1; + assert CodeUtil.log2(4L) == 2; + assert CodeUtil.log2(8L) == 3; + assert CodeUtil.log2(16L) == 4; + assert CodeUtil.log2(32L) == 5; + assert CodeUtil.log2(0x4000000000000000L) == 62; + + assert !CodeUtil.isPowerOf2(3); + assert !CodeUtil.isPowerOf2(5); + assert !CodeUtil.isPowerOf2(7); + assert !CodeUtil.isPowerOf2(-1); + + assert CodeUtil.isPowerOf2(2); + assert CodeUtil.isPowerOf2(4); + assert CodeUtil.isPowerOf2(8); + assert CodeUtil.isPowerOf2(16); + assert CodeUtil.isPowerOf2(32); + assert CodeUtil.isPowerOf2(64); + } + + /** + * Sets the element at a given position of a list and ensures that this position exists. If the list is current + * shorter than the position, intermediate positions are filled with a given value. + * + * @param list the list to put the element into + * @param pos the position at which to insert the element + * @param x the element that should be inserted + * @param filler the filler element that is used for the intermediate positions in case the list is shorter than pos + */ + public static void atPutGrow(List list, int pos, T x, T filler) { + if (list.size() < pos + 1) { + while (list.size() < pos + 1) { + list.add(filler); + } + assert list.size() == pos + 1; + } + + assert list.size() >= pos + 1; + list.set(pos, x); + } + + public static void breakpoint() { + // do nothing. + } + + public static void guarantee(boolean b, String string) { + if (!b) { + throw new BailoutException(string); + } + } + + public static void warning(String string) { + TTY.println("WARNING: " + string); + } + + public static int safeToInt(long l) { + assert (int) l == l; + return (int) l; + } + + public static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + public static void printSection(String name, char sectionCharacter) { + + String header = " " + name + " "; + int remainingCharacters = PRINTING_LINE_WIDTH - header.length(); + int leftPart = remainingCharacters / 2; + int rightPart = remainingCharacters - leftPart; + for (int i = 0; i < leftPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.print(header); + + for (int i = 0; i < rightPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.println(); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing all the bytes to print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int bytesPerLine) { + printBytes(address, array, 0, array.length, bytesPerLine); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing the bytes to print + * @param offset the offset in {@code array} of the values to print + * @param length the number of values from {@code array} print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int offset, int length, int bytesPerLine) { + assert bytesPerLine > 0; + boolean newLine = true; + for (int i = 0; i < length; i++) { + if (newLine) { + TTY.print("%08x: ", address + i); + newLine = false; + } + TTY.print("%02x ", array[i]); + if (i % bytesPerLine == bytesPerLine - 1) { + TTY.println(); + newLine = true; + } + } + + if (length % bytesPerLine != bytesPerLine) { + TTY.println(); + } + } + + public static boolean isShiftCount(int x) { + return 0 <= x && x < 32; + } + + /** + * Determines if a given {@code int} value is the range of unsigned byte values. + */ + public static boolean isUByte(int x) { + return (x & 0xff) == x; + } + + /** + * Determines if a given {@code int} value is the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if a given {@code long} value is the range of unsigned byte values. + */ + public static boolean isUByte(long x) { + return (x & 0xffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed byte values. + */ + public static boolean isByte(long l) { + return (byte) l == l; + } + + /** + * Determines if a given {@code long} value is the range of unsigned int values. + */ + public static boolean isUInt(long x) { + return (x & 0xffffffffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + /** + * Determines if a given {@code int} value is the range of signed short values. + */ + public static boolean isShort(int x) { + return (short) x == x; + } + + public static boolean is32bit(long x) { + return -0x80000000L <= x && x < 0x80000000L; + } + + public static short safeToShort(int v) { + assert isShort(v); + return (short) v; + } + + public static boolean isFixed(Node n) { + return n instanceof FixedNode; + } + + public static boolean isFloating(Node n) { + return n instanceof FloatingNode; + } + + /** + * Creates an array of integers of length "size", in which each number from 0 to (size - 1) occurs exactly once. The + * integers are sorted using the given comparator. This can be used to create a sorting for arrays that cannot be + * modified directly. + * + * @param size The size of the range to be sorted. + * @param comparator A comparator that is used to compare indexes. + * @return An array of integers that contains each number from 0 to (size - 1) exactly once, sorted using the + * comparator. + */ + public static Integer[] createSortedPermutation(int size, Comparator comparator) { + Integer[] indexes = new Integer[size]; + for (int i = 0; i < size; i++) { + indexes[i] = i; + } + Arrays.sort(indexes, comparator); + return indexes; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Sep 17 16:08:46 2012 +0200 @@ -36,6 +36,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; /** * In these test cases the probability of all invokes is set to a high value, such that an InliningPhase should inline diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, 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.phases.ea; + + +public interface MergeableBlockState { + + T clone(); +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,1148 @@ +/* + * Copyright (c) 2011, 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.phases.ea; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaType.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.schedule.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; + +class EscapeAnalysisIteration { + + // Metrics + private static final DebugMetric metricAllocationRemoved = Debug.metric("AllocationRemoved"); + private static final DebugMetric metricAllocationFieldsRemoved = Debug.metric("AllocationFieldsRemoved"); + private static final DebugMetric metricStoreRemoved = Debug.metric("StoreRemoved"); + private static final DebugMetric metricLoadRemoved = Debug.metric("LoadRemoved"); + private static final DebugMetric metricLockRemoved = Debug.metric("LockRemoved"); + private static final DebugMetric metricOtherRemoved = Debug.metric("OtherRemoved"); + private static final DebugMetric metricMaterializations = Debug.metric("Materializations"); + private static final DebugMetric metricMaterializationFields = Debug.metric("MaterializationFields"); + private static final DebugMetric metricLoopBailouts = Debug.metric("LoopBailouts"); + private static final DebugMetric metricMonitorBailouts = Debug.metric("MonitorBailouts"); + + + private static final ValueNode DUMMY_NODE = new ValueNode(null) { + }; + + public static final void trace(String format, Object... obj) { + if (GraalOptions.TraceEscapeAnalysis) { + Debug.log(format, obj); + } + } + + public static final void error(String format, Object... obj) { + System.out.print(String.format(format, obj)); + } + + private final StructuredGraph graph; + private final MetaAccessProvider runtime; + private final SchedulePhase schedule; + private final NodeBitMap usages; + boolean changed = false; + + private final boolean changeGraph; + + private final HashSet reusedVirtualObjects = new HashSet<>(); + private final HashSet allocations; + private final ArrayList obsoleteNodes = new ArrayList<>(); + private int virtualIds = 0; + + public EscapeAnalysisIteration(StructuredGraph graph, SchedulePhase schedule, MetaAccessProvider runtime, HashSet allocations, boolean changeGraph) { + this.graph = graph; + this.schedule = schedule; + this.runtime = runtime; + this.allocations = allocations; + this.changeGraph = changeGraph; + this.usages = graph.createNodeBitMap(); + } + + public void run() { + new PartialEscapeIterator(graph, schedule.getCFG().getStartBlock()).apply(); + + if (changeGraph) { + Debug.dump(graph, "after PartialEscapeAnalysis"); + + for (ValueNode node : obsoleteNodes) { + if (node.isAlive() && node instanceof FixedWithNextNode) { + FixedWithNextNode x = (FixedWithNextNode) node; + FixedNode next = x.next(); + x.setNext(null); + ((FixedWithNextNode) node.predecessor()).setNext(next); + } + } + new DeadCodeEliminationPhase().apply(graph); + + if (changed) { + Debug.log("escape analysis on %s\n", graph.method()); + } + } + } + + private static class ObjectState { + + public final VirtualObjectNode virtual; + public ValueNode[] fieldState; + public ValueNode materializedValue; + public int lockCount; + public boolean initialized; + + public ObjectState(VirtualObjectNode virtual, ValueNode[] fieldState, int lockCount) { + this.virtual = virtual; + this.fieldState = fieldState; + this.lockCount = lockCount; + this.initialized = false; + } + + public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, int lockCount) { + this.virtual = virtual; + this.materializedValue = materializedValue; + this.lockCount = lockCount; + this.initialized = true; + } + + private ObjectState(ObjectState other) { + virtual = other.virtual; + fieldState = other.fieldState == null ? null : other.fieldState.clone(); + materializedValue = other.materializedValue; + lockCount = other.lockCount; + initialized = other.initialized; + } + + @Override + public ObjectState clone() { + return new ObjectState(this); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder().append('{'); + if (lockCount > 0) { + str.append('l').append(lockCount).append(' '); + } + if (fieldState != null) { + for (int i = 0; i < fieldState.length; i++) { + str.append(virtual.fieldName(i)).append('=').append(fieldState[i]).append(' '); + } + } + if (materializedValue != null) { + str.append("mat=").append(materializedValue); + } + + return str.append('}').toString(); + } + } + + private class BlockState implements MergeableBlockState { + + private final HashMap objectStates = new HashMap<>(); + private final HashMap objectAliases = new HashMap<>(); + + public BlockState() { + } + + public BlockState(BlockState other) { + for (Map.Entry entry : other.objectStates.entrySet()) { + objectStates.put(entry.getKey(), entry.getValue().clone()); + } + for (Map.Entry entry : other.objectAliases.entrySet()) { + objectAliases.put(entry.getKey(), entry.getValue()); + } + } + + public ObjectState objectState(VirtualObjectNode object) { + assert objectStates.containsKey(object); + return objectStates.get(object); + } + + public ObjectState objectState(ValueNode value) { + VirtualObjectNode object = objectAliases.get(value); + return object == null ? null : objectState(object); + } + + @Override + public BlockState clone() { + return new BlockState(this); + } + + public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual) { + if (changeGraph) { + HashSet deferred = new HashSet<>(); + ArrayList deferredStores = new ArrayList<>(); + materializeChangedBefore(fixed, virtual, deferred, deferredStores); + for (FixedWithNextNode write : deferredStores) { + write.setProbability(fixed.probability()); + graph.addBeforeFixed(fixed, write); + } + } else { + materializeUnchangedBefore(virtual); + } + } + + private void materializeUnchangedBefore(VirtualObjectNode virtual) { + trace("materializing %s", virtual); + ObjectState obj = objectState(virtual); + if (obj.lockCount > 0) { + if (changeGraph) { + error("object materialized with lock: %s\n", virtual); + } + metricMonitorBailouts.increment(); + throw new BailoutException("object materialized with lock"); + } + + ValueNode[] fieldState = obj.fieldState; + obj.fieldState = null; + obj.materializedValue = DUMMY_NODE; + for (int i = 0; i < fieldState.length; i++) { + ObjectState valueObj = objectState(fieldState[i]); + if (valueObj != null) { + if (valueObj.materializedValue == null) { + materializeUnchangedBefore(valueObj.virtual); + } + } + } + obj.initialized = true; + } + + private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, HashSet deferred, ArrayList deferredStores) { + trace("materializing %s at %s", virtual, fixed); + ObjectState obj = objectState(virtual); + if (obj.lockCount > 0) { + error("object materialized with lock: %s\n", virtual); + metricMonitorBailouts.increment(); + throw new BailoutException("object materialized with lock"); + } + + MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(virtual)); + materialize.setProbability(fixed.probability()); + ValueNode[] fieldState = obj.fieldState; + metricMaterializations.increment(); + metricMaterializationFields.add(fieldState.length); + obj.fieldState = null; + obj.materializedValue = materialize; + deferred.add(virtual); + for (int i = 0; i < fieldState.length; i++) { + ObjectState valueObj = objectState(fieldState[i]); + if (valueObj != null) { + if (valueObj.materializedValue == null) { + materializeChangedBefore(fixed, valueObj.virtual, deferred, deferredStores); + } + if (deferred.contains(valueObj.virtual)) { + Kind fieldKind; + if (virtual instanceof VirtualArrayNode) { + deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, i))); + fieldKind = ((VirtualArrayNode) virtual).componentType().kind(); + } else { + VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual; + deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, instanceObject.field(i)))); + fieldKind = instanceObject.field(i).type().kind(); + } + materialize.values().set(i, ConstantNode.defaultForKind(fieldKind, graph)); + } else { + assert valueObj.initialized : "should be initialized: " + virtual + " at " + fixed; + materialize.values().set(i, valueObj.materializedValue); + } + } else { + materialize.values().set(i, fieldState[i]); + } + } + deferred.remove(virtual); + + obj.initialized = true; + graph.addBeforeFixed(fixed, materialize); + } + + private void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, boolean remove) { + objectAliases.put(node, virtual); + for (Node usage : node.usages()) { + markVirtualUsages(usage); + } + if (remove) { + obsoleteNodes.add(node); + } + } + + private void markVirtualUsages(Node node) { + if (!usages.isNew(node)) { + usages.mark(node); + } + if (node instanceof VirtualState) { + for (Node usage : node.usages()) { + markVirtualUsages(usage); + } + } + } + + public void addObject(VirtualObjectNode virtual, ObjectState state) { + objectStates.put(virtual, state); + } + + public Iterable states() { + return objectStates.values(); + } + + @Override + public String toString() { + return objectStates.toString(); + } + } + + private class PartialEscapeIterator extends PostOrderBlockIterator { + + public PartialEscapeIterator(StructuredGraph graph, Block start) { + super(graph, start, new BlockState()); + } + + @Override + protected void processBlock(Block block, BlockState state) { + trace("\nBlock: %s (", block); + List nodeList = schedule.getBlockToNodesMap().get(block); + + FixedWithNextNode lastFixedNode = null; + for (Node node : nodeList) { + EscapeOp op = null; + if (node instanceof EscapeAnalyzable) { + op = ((EscapeAnalyzable) node).getEscapeOp(); + } + if (op != null) { + // only escape analyze allocations that were escape analyzed during the first iteration + if (changeGraph && !allocations.contains(node)) { + op = null; + } + } + + if (op != null) { + trace("{{%s}} ", node); + VirtualObjectNode virtualObject = op.virtualObject(virtualIds); + if (virtualObject.isAlive()) { + reusedVirtualObjects.add(virtualObject); + state.addAndMarkAlias(virtualObject, virtualObject, false); + } else { + if (changeGraph) { + virtualObject = graph.add(virtualObject); + } + } + ValueNode[] fieldState = changeGraph ? op.fieldState() : new ValueNode[virtualObject.entryCount()]; + if (changeGraph) { + metricAllocationRemoved.increment(); + metricAllocationFieldsRemoved.add(fieldState.length); + } else { + allocations.add((ValueNode) node); + } + state.addObject(virtualObject, new ObjectState(virtualObject, fieldState, 0)); + state.addAndMarkAlias(virtualObject, (ValueNode) node, true); + virtualIds++; + } else { + if (changeGraph && node instanceof LoopExitNode) { + for (ObjectState obj : state.states()) { + if (obj.fieldState != null) { + for (int i = 0; i < obj.fieldState.length; i++) { + ValueNode value = obj.fieldState[i]; + ObjectState valueObj = state.objectState(value); + if (valueObj == null) { + obj.fieldState[i] = graph.unique(new ValueProxyNode(value, (LoopExitNode) node, PhiType.Value)); + } + } + } else { + obj.materializedValue = graph.unique(new ValueProxyNode(obj.materializedValue, (LoopExitNode) node, PhiType.Value)); + } + } + } + + if (usages.isMarked(node)) { + trace("[[%s]] ", node); + processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state); + } else { + trace("%s ", node); + } + } + + if (node instanceof FixedWithNextNode && node.isAlive()) { + lastFixedNode = (FixedWithNextNode) node; + } + } + trace(")\n end state: %s\n", state); + } + + private void processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) { + boolean usageFound = false; + if (node instanceof PiNode || node instanceof ValueProxyNode) { + ValueNode value = node instanceof PiNode ? ((PiNode) node).object() : ((ValueProxyNode) node).value(); + ObjectState obj = state.objectState(value); + assert obj != null : node; + if (obj.materializedValue == null) { + state.addAndMarkAlias(obj.virtual, node, true); + } else { + if (changeGraph) { + node.replaceFirstInput(value, obj.materializedValue); + } + } + usageFound = true; + } else if (node instanceof CheckCastNode) { + CheckCastNode x = (CheckCastNode) node; + ObjectState obj = state.objectState(x.object()); + assert obj != null : x; + if (obj.materializedValue == null) { + if (x.targetClass() != null && obj.virtual.type().isSubtypeOf(x.targetClass())) { + metricOtherRemoved.increment(); + state.addAndMarkAlias(obj.virtual, x, true); + // throw new UnsupportedOperationException("probably incorrect - losing dependency"); + } else { + replaceWithMaterialized(x.object(), x, state, obj); + } + } else { + if (changeGraph) { + node.replaceFirstInput(x.object(), obj.materializedValue); + } + } + usageFound = true; + } else if (node instanceof IsNullNode) { + IsNullNode x = (IsNullNode) node; + ObjectState obj = state.objectState(x.object()); + assert obj != null : x; + if (changeGraph) { + graph.replaceFloating(x, graph.unique(ConstantNode.forBoolean(false, graph))); + metricOtherRemoved.increment(); + } + usageFound = true; + } else if (node instanceof IsTypeNode) { + throw new GraalInternalError("a newly created object can never be an object hub"); + } else if (node instanceof AccessMonitorNode) { + AccessMonitorNode x = (AccessMonitorNode) node; + ObjectState obj = state.objectState(x.object()); + if (obj != null) { + Debug.log("monitor operation %s on %s\n", x, obj.virtual); + if (node instanceof MonitorEnterNode) { + obj.lockCount++; + } else { + assert node instanceof MonitorExitNode; + obj.lockCount--; + } + if (changeGraph) { + changed = true; + if (obj.materializedValue == null) { + metricLockRemoved.increment(); + node.replaceFirstInput(x.object(), obj.virtual); + x.eliminate(); + } else { + node.replaceFirstInput(x.object(), obj.materializedValue); + } + } + usageFound = true; + } + } else if (node instanceof CyclicMaterializeStoreNode) { + CyclicMaterializeStoreNode x = (CyclicMaterializeStoreNode) node; + ObjectState obj = state.objectState(x.object()); + assert obj != null : x; + if (obj.virtual instanceof VirtualArrayNode) { + obj.fieldState[x.targetIndex()] = x.value(); + } else { + VirtualInstanceNode instance = (VirtualInstanceNode) obj.virtual; + int index = instance.fieldIndex(x.targetField()); + obj.fieldState[index] = x.value(); + } + if (changeGraph) { + graph.removeFixed(x); + } + usageFound = true; + } else if (node instanceof LoadFieldNode) { + LoadFieldNode x = (LoadFieldNode) node; + ObjectState obj = state.objectState(x.object()); + assert obj != null : x; + VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual; + int fieldIndex = virtual.fieldIndex(x.field()); + if (fieldIndex == -1) { + // the field does not exist in the virtual object + ensureMaterialized(state, obj, x); + } + if (obj.materializedValue == null) { + ValueNode result = obj.fieldState[fieldIndex]; + ObjectState resultObj = state.objectState(result); + if (resultObj != null) { + state.addAndMarkAlias(resultObj.virtual, x, true); + } else { + if (changeGraph) { + x.replaceAtUsages(result); + graph.removeFixed(x); + } + } + if (changeGraph) { + metricLoadRemoved.increment(); + } + changed = true; + } else { + if (changeGraph) { + x.replaceFirstInput(x.object(), obj.materializedValue); + } + } + usageFound = true; + } else if (node instanceof StoreFieldNode) { + StoreFieldNode x = (StoreFieldNode) node; + ValueNode object = x.object(); + ValueNode value = x.value(); + ObjectState obj = state.objectState(object); + if (obj != null) { + VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual; + int fieldIndex = virtual.fieldIndex(x.field()); + if (fieldIndex == -1) { + // the field does not exist in the virtual object + ensureMaterialized(state, obj, x); + } + if (obj.materializedValue == null) { + obj.fieldState[fieldIndex] = value; + if (changeGraph) { + graph.removeFixed(x); + metricStoreRemoved.increment(); + } + changed = true; + } else { + if (changeGraph) { + x.replaceFirstInput(object, obj.materializedValue); + } + ObjectState valueObj = state.objectState(value); + if (valueObj != null) { + replaceWithMaterialized(value, x, state, valueObj); + } + } + usageFound = true; + } else { + ObjectState valueObj = state.objectState(value); + if (valueObj != null) { + replaceWithMaterialized(value, x, state, valueObj); + usageFound = true; + } + } + } else if (node instanceof LoadIndexedNode) { + LoadIndexedNode x = (LoadIndexedNode) node; + ValueNode array = x.array(); + ObjectState arrayObj = state.objectState(array); + if (arrayObj != null) { + if (arrayObj.materializedValue == null) { + int index = x.index().isConstant() ? x.index().asConstant().asInt() : -1; + if (index < 0 || index >= arrayObj.fieldState.length) { + // out of bounds or not constant + replaceWithMaterialized(array, x, state, arrayObj); + } else { + ValueNode result = arrayObj.fieldState[index]; + ObjectState resultObj = state.objectState(result); + if (resultObj != null) { + state.addAndMarkAlias(resultObj.virtual, x, true); + } else { + if (changeGraph) { + x.replaceAtUsages(result); + graph.removeFixed(x); + } + } + if (changeGraph) { + metricLoadRemoved.increment(); + } + changed = true; + } + } else { + if (changeGraph) { + x.replaceFirstInput(array, arrayObj.materializedValue); + } + } + usageFound = true; + } + } else if (node instanceof StoreIndexedNode) { + StoreIndexedNode x = (StoreIndexedNode) node; + ValueNode array = x.array(); + ValueNode value = x.value(); + ObjectState arrayObj = state.objectState(array); + ObjectState valueObj = state.objectState(value); + + if (arrayObj != null) { + if (arrayObj.materializedValue == null) { + int index = x.index().isConstant() ? x.index().asConstant().asInt() : -1; + if (index < 0 || index >= arrayObj.fieldState.length) { + // out of bounds or not constant + replaceWithMaterialized(array, x, state, arrayObj); + if (valueObj != null) { + replaceWithMaterialized(value, x, state, valueObj); + } + } else { + arrayObj.fieldState[index] = value; + if (changeGraph) { + graph.removeFixed(x); + metricStoreRemoved.increment(); + } + changed = true; + } + } else { + if (changeGraph) { + x.replaceFirstInput(array, arrayObj.materializedValue); + } + if (valueObj != null) { + replaceWithMaterialized(value, x, state, valueObj); + } + } + usageFound = true; + } else { + if (valueObj != null) { + replaceWithMaterialized(value, x, state, valueObj); + usageFound = true; + } + } + } else if (node instanceof RegisterFinalizerNode) { + RegisterFinalizerNode x = (RegisterFinalizerNode) node; + ObjectState obj = state.objectState(x.object()); + replaceWithMaterialized(x.object(), x, state, obj); + usageFound = true; + } else if (node instanceof ArrayLengthNode) { + ArrayLengthNode x = (ArrayLengthNode) node; + ObjectState obj = state.objectState(x.array()); + assert obj != null : x; + if (changeGraph) { + graph.replaceFixedWithFloating(x, ConstantNode.forInt(((VirtualArrayNode) obj.virtual).entryCount(), graph)); + metricOtherRemoved.increment(); + } + changed = true; + usageFound = true; + } else if (node instanceof ReadHubNode) { + ReadHubNode x = (ReadHubNode) node; + ObjectState obj = state.objectState(x.object()); + assert obj != null : x; + if (changeGraph) { + ConstantNode hub = ConstantNode.forConstant(obj.virtual.type().getEncoding(Representation.ObjectHub), runtime, graph); + graph.replaceFixedWithFloating(x, hub); + metricOtherRemoved.increment(); + } + changed = true; + usageFound = true; + } else if (node instanceof ReturnNode) { + ReturnNode x = (ReturnNode) node; + ObjectState obj = state.objectState(x.result()); + replaceWithMaterialized(x.result(), x, state, obj); + usageFound = true; + } else if (node instanceof MethodCallTargetNode) { + for (ValueNode argument : ((MethodCallTargetNode) node).arguments()) { + ObjectState obj = state.objectState(argument); + if (obj != null) { + replaceWithMaterialized(argument, node, insertBefore, state, obj); + usageFound = true; + } + } + } else if (node instanceof ObjectEqualsNode) { + ObjectEqualsNode x = (ObjectEqualsNode) node; + ObjectState xObj = state.objectState(x.x()); + ObjectState yObj = state.objectState(x.y()); + boolean xVirtual = xObj != null && xObj.materializedValue == null; + boolean yVirtual = yObj != null && yObj.materializedValue == null; + + if (changeGraph) { + if (xVirtual ^ yVirtual) { + // one of them is virtual: they can never be the same objects + graph.replaceFloating(x, ConstantNode.forBoolean(false, graph)); + usageFound = true; + metricOtherRemoved.increment(); + changed = true; + } else if (xVirtual && yVirtual) { + // both are virtual: check if they refer to the same object + graph.replaceFloating(x, ConstantNode.forBoolean(xObj == yObj, graph)); + usageFound = true; + metricOtherRemoved.increment(); + changed = true; + } else { + assert xObj != null || yObj != null; + if (xObj != null) { + assert xObj.materializedValue != null; + node.replaceFirstInput(x.x(), xObj.materializedValue); + } + if (yObj != null) { + assert yObj.materializedValue != null; + node.replaceFirstInput(x.y(), yObj.materializedValue); + } + } + } + usageFound = true; + } else if (node instanceof MergeNode) { + usageFound = true; + } else if (node instanceof UnsafeLoadNode || node instanceof UnsafeStoreNode || node instanceof CompareAndSwapNode || node instanceof SafeReadNode) { + for (ValueNode input : node.inputs().filter(ValueNode.class)) { + ObjectState obj = state.objectState(input); + if (obj != null) { + replaceWithMaterialized(input, node, insertBefore, state, obj); + usageFound = true; + } + } + } + if (node.isAlive() && node instanceof StateSplit) { + StateSplit split = (StateSplit) node; + FrameState stateAfter = split.stateAfter(); + if (stateAfter != null) { + if (changeGraph) { + if (stateAfter.usages().size() > 1) { + stateAfter = (FrameState) stateAfter.copyWithInputs(); + split.setStateAfter(stateAfter); + } + final HashSet virtual = new HashSet<>(); + stateAfter.applyToNonVirtual(new NodeClosure() { + + @Override + public void apply(Node usage, ValueNode value) { + ObjectState valueObj = state.objectState(value); + if (valueObj != null) { + virtual.add(valueObj); + usage.replaceFirstInput(value, valueObj.virtual); + } else if (value instanceof VirtualObjectNode) { + ObjectState virtualObj = null; + for (ObjectState obj : state.states()) { + if (value == obj.virtual) { + virtualObj = obj; + break; + } + } + if (virtualObj != null) { + virtual.add(virtualObj); + } + } + } + }); + for (ObjectState obj : state.states()) { + if (obj.materializedValue == null && obj.lockCount > 0) { + virtual.add(obj); + } + } + + ArrayDeque queue = new ArrayDeque<>(virtual); + while (!queue.isEmpty()) { + ObjectState obj = queue.removeLast(); + if (obj.materializedValue == null) { + for (ValueNode field : obj.fieldState) { + ObjectState fieldObj = state.objectState(field); + if (fieldObj != null) { + if (fieldObj.materializedValue == null && !virtual.contains(fieldObj)) { + virtual.add(fieldObj); + queue.addLast(fieldObj); + } + } + } + } + } + for (ObjectState obj : virtual) { + EscapeObjectState v; + if (obj.materializedValue == null) { + ValueNode[] fieldState = obj.fieldState.clone(); + for (int i = 0; i < fieldState.length; i++) { + ObjectState valueObj = state.objectState(fieldState[i]); + if (valueObj != null) { + if (valueObj.materializedValue == null) { + fieldState[i] = valueObj.virtual; + } else { + fieldState[i] = valueObj.materializedValue; + } + } + } + v = graph.add(new VirtualObjectState(obj.virtual, fieldState)); + } else { + v = graph.add(new MaterializedObjectState(obj.virtual, obj.materializedValue)); + } + for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) { + if (stateAfter.virtualObjectMappingAt(i).object() == v.object()) { + if (reusedVirtualObjects.contains(v.object())) { + stateAfter.virtualObjectMappings().remove(i); + } else { + throw new GraalInternalError("unexpected duplicate virtual state at: %s for %s", node, v.object()); + } + } + } + stateAfter.addVirtualObjectMapping(v); + } + } + usageFound = true; + } + } + if (!usageFound) { + for (ValueNode input : node.inputs().filter(ValueNode.class)) { + ObjectState obj = state.objectState(input); + if (obj != null) { + replaceWithMaterialized(input, node, insertBefore, state, obj); + usageFound = true; + } + } + Debug.log("unexpected usage of %s: %s\n", node, node.inputs().snapshot()); + } + } + + private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore) { + assert obj != null; + if (obj.materializedValue == null) { + state.materializeBefore(materializeBefore, obj.virtual); + } + assert obj.materializedValue != null; + } + + private void replaceWithMaterialized(ValueNode value, FixedNode usage, BlockState state, ObjectState obj) { + ensureMaterialized(state, obj, usage); + if (changeGraph) { + usage.replaceFirstInput(value, obj.materializedValue); + } + } + + private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockState state, ObjectState obj) { + ensureMaterialized(state, obj, materializeBefore); + if (changeGraph) { + usage.replaceFirstInput(value, obj.materializedValue); + } + } + + @Override + protected BlockState merge(MergeNode merge, List states) { + BlockState newState = new BlockState(); + + newState.objectAliases.putAll(states.get(0).objectAliases); + for (int i = 1; i < states.size(); i++) { + BlockState state = states.get(i); + for (Map.Entry entry : states.get(0).objectAliases.entrySet()) { + if (state.objectAliases.containsKey(entry.getKey())) { + assert state.objectAliases.get(entry.getKey()) == entry.getValue(); + } else { + newState.objectAliases.remove(entry.getKey()); + } + } + } + + // Iterative processing: + // Merging the materialized/virtual state of virtual objects can lead to new materializations, which can + // lead to new materializations because of phis, and so on. + + boolean materialized; + do { + materialized = false; + // use a hash set to make the values distinct... + for (VirtualObjectNode object : new HashSet<>(newState.objectAliases.values())) { + ObjectState resultState = newState.objectStates.get(object); + if (resultState == null || resultState.materializedValue == null) { + int virtual = 0; + int lockCount = states.get(0).objectState(object).lockCount; + for (BlockState state : states) { + ObjectState obj = state.objectState(object); + if (obj.materializedValue == null) { + virtual++; + } + assert obj.lockCount == lockCount : "mismatching lock counts"; + } + + if (virtual < states.size()) { + ValueNode materializedValuePhi = changeGraph ? graph.add(new PhiNode(Kind.Object, merge)) : DUMMY_NODE; + for (int i = 0; i < states.size(); i++) { + BlockState state = states.get(i); + ObjectState obj = state.objectState(object); + materialized |= obj.materializedValue == null; + ensureMaterialized(state, obj, merge.forwardEndAt(i)); + if (changeGraph) { + ((PhiNode) materializedValuePhi).addInput(obj.materializedValue); + } + } + newState.addObject(object, new ObjectState(object, materializedValuePhi, lockCount)); + } else { + assert virtual == states.size(); + ValueNode[] values = states.get(0).objectState(object).fieldState.clone(); + PhiNode[] phis = new PhiNode[values.length]; + boolean[] phiCreated = new boolean[values.length]; + int mismatch = 0; + for (int i = 1; i < states.size(); i++) { + BlockState state = states.get(i); + ValueNode[] fields = state.objectState(object).fieldState; + for (int index = 0; index < values.length; index++) { + if (!phiCreated[index] && values[index] != fields[index]) { + mismatch++; + if (changeGraph) { + phis[index] = graph.add(new PhiNode(values[index].kind(), merge)); + } + phiCreated[index] = true; + } + } + } + if (mismatch > 0) { + for (int i = 0; i < states.size(); i++) { + BlockState state = states.get(i); + ValueNode[] fields = state.objectState(object).fieldState; + for (int index = 0; index < values.length; index++) { + if (phiCreated[index]) { + ObjectState obj = state.objectState(fields[index]); + if (obj != null) { + materialized |= obj.materializedValue == null; + ensureMaterialized(state, obj, merge.forwardEndAt(i)); + fields[index] = obj.materializedValue; + } + if (changeGraph) { + phis[index].addInput(fields[index]); + } + } + } + } + for (int index = 0; index < values.length; index++) { + if (phiCreated[index]) { + values[index] = phis[index]; + } + } + } + newState.addObject(object, new ObjectState(object, values, lockCount)); + } + } + } + + for (PhiNode phi : merge.phis().snapshot()) { + if (usages.isMarked(phi) && phi.type() == PhiType.Value) { + materialized |= processPhi(newState, merge, phi, states); + } + } + } while (materialized); + + return newState; + } + + private boolean processPhi(BlockState newState, MergeNode merge, PhiNode phi, List states) { + assert states.size() == phi.valueCount(); + int virtualInputs = 0; + boolean materialized = false; + VirtualObjectNode sameObject = null; + ResolvedJavaType sameType = null; + int sameEntryCount = -1; + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode value = phi.valueAt(i); + ObjectState obj = states.get(i).objectState(value); + if (obj != null) { + if (obj.materializedValue == null) { + virtualInputs++; + if (i == 0) { + sameObject = obj.virtual; + sameType = obj.virtual.type(); + sameEntryCount = obj.virtual.entryCount(); + } else { + if (sameObject != obj.virtual) { + sameObject = null; + } + if (sameType != obj.virtual.type()) { + sameType = null; + } + if (sameEntryCount != obj.virtual.entryCount()) { + sameEntryCount = -1; + } + } + } else { + if (changeGraph) { + phi.setValueAt(i, obj.materializedValue); + } + } + } + } + boolean materialize = false; + if (virtualInputs == 0) { + // nothing to do... + } else if (virtualInputs == phi.valueCount()) { + if (sameObject != null) { + newState.addAndMarkAlias(sameObject, phi, true); + } else if (sameType != null && sameEntryCount != -1) { + materialize = true; + // throw new GraalInternalError("merge required for %s", sameType); + } else { + materialize = true; + } + } else { + materialize = true; + } + + if (materialize) { + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode value = phi.valueAt(i); + ObjectState obj = states.get(i).objectState(value); + if (obj != null) { + materialized |= obj.materializedValue == null; + replaceWithMaterialized(value, phi, merge.forwardEndAt(i), states.get(i), obj); + } + } + } + return materialized; + } + + @Override + protected BlockState loopBegin(LoopBeginNode loopBegin, BlockState beforeLoopState) { + BlockState state = beforeLoopState; + for (ObjectState obj : state.states()) { + if (obj.fieldState != null) { + for (int i = 0; obj.fieldState != null && i < obj.fieldState.length; i++) { + ValueNode value = obj.fieldState[i]; + ObjectState valueObj = state.objectState(value); + if (valueObj != null) { + ensureMaterialized(state, valueObj, loopBegin.forwardEnd()); + value = valueObj.materializedValue; + } + } + } + } + for (ObjectState obj : state.states()) { + if (obj.fieldState != null) { + for (int i = 0; i < obj.fieldState.length; i++) { + ValueNode value = obj.fieldState[i]; + ObjectState valueObj = state.objectState(value); + if (valueObj != null) { + value = valueObj.materializedValue; + } + if (changeGraph) { + assert value != null; + PhiNode valuePhi = graph.add(new PhiNode(value.kind(), loopBegin)); + valuePhi.addInput(value); + obj.fieldState[i] = valuePhi; + } + } + } + } + for (PhiNode phi : loopBegin.phis()) { + ObjectState obj = state.objectState(phi.valueAt(0)); + if (obj != null) { + ensureMaterialized(state, obj, loopBegin.forwardEnd()); + if (changeGraph) { + phi.setValueAt(0, obj.materializedValue); + } + } + } + return state.clone(); + } + + @Override + protected BlockState loopEnds(LoopBeginNode loopBegin, BlockState loopBeginState, List loopEndStates) { + BlockState state = loopBeginState.clone(); + List loopEnds = loopBegin.orderedLoopEnds(); + for (ObjectState obj : state.states()) { + if (obj.fieldState != null) { + Iterator iter = loopEnds.iterator(); + for (BlockState loopEndState : loopEndStates) { + LoopEndNode loopEnd = iter.next(); + ObjectState endObj = loopEndState.objectState(obj.virtual); + if (endObj.fieldState == null) { + if (changeGraph) { + error("object materialized within loop: %s\n", obj.virtual); + } + metricLoopBailouts.increment(); + throw new BailoutException("object materialized within loop"); + } + for (int i = 0; endObj.fieldState != null && i < endObj.fieldState.length; i++) { + ValueNode value = endObj.fieldState[i]; + ObjectState valueObj = loopEndState.objectState(value); + if (valueObj != null) { + ensureMaterialized(loopEndState, valueObj, loopEnd); + value = valueObj.materializedValue; + } + if (changeGraph) { + ((PhiNode) obj.fieldState[i]).addInput(value); + } + } + } + } + } + for (PhiNode phi : loopBegin.phis()) { + if (phi.valueCount() == 1) { + if (changeGraph) { + phi.replaceAtUsages(phi.valueAt(0)); + } + } else { + assert phi.valueCount() == loopEndStates.size() + 1; + for (int i = 0; i < loopEndStates.size(); i++) { + BlockState loopEndState = loopEndStates.get(i); + ObjectState obj = loopEndState.objectState(phi.valueAt(i + 1)); + if (obj != null) { + ensureMaterialized(loopEndState, obj, loopEnds.get(i)); + if (changeGraph) { + phi.setValueAt(i + 1, obj.materializedValue); + } + } + } + } + } + return state; + } + + @Override + protected BlockState afterSplit(FixedNode node, BlockState oldState) { + return oldState.clone(); + } + } +} + +public class PartialEscapeAnalysisPhase extends Phase { + + private final TargetDescription target; + private final GraalCodeCacheProvider runtime; + private final Assumptions assumptions; + + public PartialEscapeAnalysisPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions) { + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + } + + @Override + protected void run(StructuredGraph graph) { + iteration(graph, 0); + } + + + private void iteration(final StructuredGraph graph, final int num) { + HashSet allocations = new HashSet<>(); + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph, false); + EscapeAnalysisIteration iteration = null; + try { + iteration = new EscapeAnalysisIteration(graph, schedule, runtime, allocations, false); + iteration.run(); + } catch (BailoutException e) { + // do nothing if the if the escape analysis bails out during the analysis iteration... + return; + } + if (iteration.changed) { + try { + new EscapeAnalysisIteration(graph, schedule, runtime, allocations, true).run(); + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } catch (BailoutException e) { + throw new GraalInternalError(e); + } + // next round... + if (num < 2) { + Debug.scope("next", new Runnable() { + @Override + public void run() { + iteration(graph, num + 1); + } + }); + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2011, 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.phases.ea; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +public abstract class PostOrderBlockIterator> { + + private final NodeBitMap visitedEnds; + private final Deque blockQueue; + private final IdentityHashMap blockEndStates; + private final IdentityHashMap loopBeginStates; + private final Block start; + + private T state; + + public PostOrderBlockIterator(StructuredGraph graph, Block start, T initialState) { + visitedEnds = graph.createNodeBitMap(); + blockQueue = new ArrayDeque<>(); + blockEndStates = new IdentityHashMap<>(); + loopBeginStates = new IdentityHashMap<>(); + this.start = start; + this.state = initialState; + } + + public void apply() { + Block current = start; + + do { + processBlock(current, state); + + if (current.getSuccessors().isEmpty()) { + // nothing to do... + } else if (current.getSuccessors().size() == 1) { + Block successor = current.getSuccessors().get(0); + if (successor.isLoopHeader()) { + if (current.getEndNode() instanceof LoopEndNode) { + finishLoopEnds((LoopEndNode) current.getEndNode()); + } else { + LoopBeginNode loopBegin = (LoopBeginNode) successor.getBeginNode(); + state = loopBegin(loopBegin, state); + loopBeginStates.put(loopBegin, state); + state = state.clone(); + current = successor; + continue; + } + } else { + if (successor.getBeginNode() instanceof LoopExitNode) { + assert successor.getPredecessors().size() == 1; + current = successor; + continue; + } else { + assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode(); + queueMerge((EndNode) current.getEndNode(), successor); + } + } + } else { + assert current.getSuccessors().size() > 1; + queueSuccessors(current); + } + current = nextQueuedBlock(); + } while (current != null); + } + + protected abstract void processBlock(Block block, T currentState); + + protected abstract T merge(MergeNode merge, List states); + + protected abstract T loopBegin(LoopBeginNode loopBegin, T beforeLoopState); + + protected abstract T loopEnds(LoopBeginNode loopBegin, T loopBeginState, List loopEndStates); + + protected abstract T afterSplit(FixedNode node, T oldState); + + + private void queueSuccessors(Block current) { + blockEndStates.put(current.getEndNode(), state); + for (Block block : current.getSuccessors()) { + blockQueue.addFirst(block); + } + } + + private Block nextQueuedBlock() { + int maxIterations = blockQueue.size(); + while (maxIterations-- > 0) { + Block block = blockQueue.removeFirst(); + if (block.getPredecessors().size() > 1) { + MergeNode merge = (MergeNode) block.getBeginNode(); + ArrayList states = new ArrayList<>(merge.forwardEndCount()); + for (int i = 0; i < merge.forwardEndCount(); i++) { + T other = blockEndStates.get(merge.forwardEndAt(i)); + assert other != null; + states.add(other); + } + state = merge(merge, states); + if (state != null) { + return block; + } else { + blockQueue.addLast(block); + } + } else { + assert block.getPredecessors().size() == 1; + assert block.getBeginNode().predecessor() != null; + state = afterSplit(block.getBeginNode(), blockEndStates.get(block.getBeginNode().predecessor())); + return block; + } + } + return null; + } + + private void queueMerge(EndNode end, Block mergeBlock) { + assert !visitedEnds.isMarked(end); + assert !blockEndStates.containsKey(end); + blockEndStates.put(end, state); + visitedEnds.mark(end); + MergeNode merge = end.merge(); + boolean endsVisited = true; + for (int i = 0; i < merge.forwardEndCount(); i++) { + if (!visitedEnds.isMarked(merge.forwardEndAt(i))) { + endsVisited = false; + break; + } + } + if (endsVisited) { + blockQueue.addFirst(mergeBlock); + } + } + + private void finishLoopEnds(LoopEndNode end) { + assert !visitedEnds.isMarked(end); + assert !blockEndStates.containsKey(end); + blockEndStates.put(end, state); + visitedEnds.mark(end); + LoopBeginNode begin = end.loopBegin(); + boolean endsVisited = true; + for (LoopEndNode le : begin.loopEnds()) { + if (!visitedEnds.isMarked(le)) { + endsVisited = false; + break; + } + } + if (endsVisited) { + ArrayList states = new ArrayList<>(begin.loopEnds().count()); + for (LoopEndNode le : begin.orderedLoopEnds()) { + states.add(blockEndStates.get(le)); + } + T loopBeginState = loopBeginStates.get(begin); + if (loopBeginState != null) { + loopEnds(begin, loopBeginState, states); + } + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/CyclicMaterializeStoreNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/CyclicMaterializeStoreNode.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * The {@code StoreFieldNode} represents a write to a static or instance field. + */ +@NodeInfo(nameTemplate = "MaterializeStore#{p#field/s}") +public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private ValueNode value; + private final Object target; + + public ValueNode object() { + return object; + } + + public ValueNode value() { + return value; + } + + public ResolvedJavaField targetField() { + return (ResolvedJavaField) target; + } + + public int targetIndex() { + return (int) target; + } + + public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, ResolvedJavaField field) { + super(StampFactory.forVoid()); + this.object = object; + this.value = value; + this.target = field; + } + + public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, int index) { + super(StampFactory.forVoid()); + this.object = object; + this.value = value; + this.target = index; + } + + @Override + public void lower(LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) graph(); + ResolvedJavaType type = object.objectStamp().type(); + FixedWithNextNode store; + if (target instanceof Integer) { + store = graph.add(new StoreIndexedNode(object, ConstantNode.forInt((int) target, graph), type.componentType().kind(), value, -1)); + } else { + assert target instanceof ResolvedJavaField; + store = graph.add(new StoreFieldNode(object, (ResolvedJavaField) target, value, -1)); + } + graph.replaceFixedWithFixed(this, store); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializeObjectNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializeObjectNode.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.virtual; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +@NodeInfo(nameTemplate = "Materialize {i#virtualObject}") +public final class MaterializeObjectNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, Node.IterableNodeType, Canonicalizable { + + @Input private final NodeInputList values; + @Input private final VirtualObjectNode virtualObject; + + public MaterializeObjectNode(VirtualObjectNode virtualObject) { + super(StampFactory.exactNonNull(virtualObject.type())); + this.virtualObject = virtualObject; + this.values = new NodeInputList<>(this, virtualObject.entryCount()); + } + + public NodeInputList values() { + return values; + } + + @Override + public void lower(LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) graph(); + if (virtualObject instanceof VirtualInstanceNode) { + VirtualInstanceNode virtual = (VirtualInstanceNode) virtualObject; + + NewInstanceNode newInstance = graph.add(new NewInstanceNode(virtual.type(), false)); + this.replaceAtUsages(newInstance); + graph.addAfterFixed(this, newInstance); + + FixedWithNextNode position = newInstance; + for (int i = 0; i < virtual.entryCount(); i++) { + StoreFieldNode store = graph.add(new StoreFieldNode(newInstance, virtual.field(i), values.get(i), -1)); + graph.addAfterFixed(position, store); + position = store; + } + + graph.removeFixed(this); + } else { + assert virtualObject instanceof VirtualArrayNode; + VirtualArrayNode virtual = (VirtualArrayNode) virtualObject; + + ResolvedJavaType element = virtual.componentType(); + NewArrayNode newArray; + if (element.kind() == Kind.Object) { + newArray = graph.add(new NewObjectArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false)); + } else { + newArray = graph.add(new NewPrimitiveArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false)); + } + this.replaceAtUsages(newArray); + graph.addAfterFixed(this, newArray); + + FixedWithNextNode position = newArray; + for (int i = 0; i < virtual.entryCount(); i++) { + StoreIndexedNode store = graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.kind(), values.get(i), -1)); + graph.addAfterFixed(position, store); + position = store; + } + + graph.removeFixed(this); + } + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (usages().isEmpty()) { + return null; + } else { + return this; + } + } + + @Override + public EscapeOp getEscapeOp() { + return new EscapeOp() { + + @Override + public ValueNode[] fieldState() { + return values.toArray(new ValueNode[values.size()]); + } + + @Override + public VirtualObjectNode virtualObject(int virtualId) { + return virtualObject; + } + }; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 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.nodes.virtual; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This class encapsulated the materialized state of an escape analyzed object. + */ +public final class MaterializedObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable { + + @Input private ValueNode materializedValue; + + public ValueNode materializedValue() { + return materializedValue; + } + + public MaterializedObjectState(VirtualObjectNode object, ValueNode materializedValue) { + super(object); + this.materializedValue = materializedValue; + } + + @Override + public void generate(LIRGeneratorTool generator) { + // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. + } + + @Override + public MaterializedObjectState duplicateWithVirtualState() { + return graph().add(new MaterializedObjectState(object(), materializedValue)); + } + + @Override + public void applyToNonVirtual(NodeClosure< ? super ValueNode> closure) { + closure.apply(this, materializedValue); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.virtual/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 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.nodes.virtual; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This class encapsulated the virtual state of an escape analyzed object. + */ +public final class VirtualObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable { + + @Input private NodeInputList fieldValues; + + public NodeInputList fieldValues() { + return fieldValues; + } + + public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) { + super(object); + assert object.entryCount() == fieldValues.length; + this.fieldValues = new NodeInputList<>(this, fieldValues); + } + + private VirtualObjectState(VirtualObjectNode object, List fieldValues) { + super(object); + assert object.entryCount() == fieldValues.size(); + this.fieldValues = new NodeInputList<>(this, fieldValues); + } + + @Override + public void generate(LIRGeneratorTool generator) { + // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. + } + + @Override + public VirtualObjectState duplicateWithVirtualState() { + return graph().add(new VirtualObjectState(object(), fieldValues)); + } + + @Override + public void applyToNonVirtual(NodeClosure< ? super ValueNode> closure) { + for (ValueNode value : fieldValues) { + closure.apply(this, value); + } + } +} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2009, 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 com.oracle.graal.nodes.*; - - -/** - * This class encapsulates options that control the behavior of the Graal compiler. - * - * (thomaswue) WARNING: Fields of this class are treated as final by Graal. - */ -public final class GraalOptions { - - // Checkstyle: stop - private static final boolean ____ = false; - // Checkstyle: resume - - public static int Threads = 4; - - // inlining settings - public static boolean Inline = true; - public static boolean Intrinsify = true; - 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; - public static int MaximumInlineLevel = 30; - public static int MaximumDesiredSize = 3000; - public static int MaximumRecursiveInlining = 1; - public static int SmallCompiledCodeSize = 2000; - public static boolean LimitInlinedProbability = ____; - // WeightBasedInliningPolicy (0) - public static boolean ParseBeforeInlining = ____; - public static float InliningSizePenaltyExp = 20; - public static float MaximumInlineWeight = 1.25f; - public static float InliningSizePenalty = 1; - // StaticSizeBasedInliningPolicy (1), MinimumCodeSizeBasedInlining (2), - // DynamicSizeBasedInliningPolicy (3) - public static int MaximumInlineSize = 35; - // GreedySizeBasedInlining (4) - public static int MaximumGreedyInlineSize = 100; - public static int InliningBonusPerTransferredValue = 10; - // Common options for inlining policies 1 to 4 - public static float NestedInliningSizeRatio = 1f; - public static float BoostInliningForEscapeAnalysis = 2f; - public static float ProbabilityCapForInlining = 1f; - - // escape analysis settings - public static boolean PartialEscapeAnalysis = true; - - public static double TailDuplicationProbability = 0.5; - public static int TailDuplicationTrivialSize = 1; - - // absolute probability analysis - public static boolean ProbabilityAnalysis = true; - 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; - - // comilation queue - public static int TimedBootstrap = -1; - public static boolean PriorityCompileQueue = true; - public static int SlowQueueCutoff = 100000; - public static boolean SlowCompileThreads = ____; - public static boolean DynamicCompilePriority = ____; - - // graph caching - public static boolean CacheGraphs = true; - public static int GraphCacheSize = 1000; - public static boolean PrintGraphCache = ____; - - //rematerialize settings - public static float MinimumUsageProbability = 0.95f; - - //loop transform settings TODO (gd) tune - public static boolean LoopPeeling = true; - public static boolean ReassociateInvariants = true; - public static boolean FullUnroll = true; - public static boolean LoopUnswitch = true; - public static int FullUnrollMaxNodes = 150; - public static int ExactFullUnrollMaxNodes = 600; - public static float MinimumPeelProbability = 0.35f; - public static int LoopMaxUnswitch = 3; - public static int LoopUnswitchMaxIncrease = 50; - public static int LoopUnswitchUncertaintyBoost = 5; - - // debugging settings - public static int MethodEndBreakpointGuards = 0; - public static boolean ZapStackOnMethodEntry = ____; - public static boolean DeoptALot = ____; - public static boolean VerifyPhases = true; - public static boolean CreateDeoptInfo = ____; - - public static String PrintFilter = null; - - // printing settings - public static boolean PrintLIR = ____; - public static boolean PrintCFGToFile = ____; - - // Debug settings: - public static boolean Debug = true; - public static boolean PerThreadDebugValues = ____; - public static boolean SummarizeDebugValues = ____; - public static boolean SummarizePerPhase = ____; - public static String Dump = null; - public static String Meter = null; - public static String Time = null; - public static String Log = null; - public static String LogFile = null; - public static String MethodFilter = null; - public static boolean DumpOnError = ____; - - // Ideal graph visualizer output settings - public static boolean PrintBinaryGraphs = ____; - public static boolean PrintCFG = true; - public static boolean PrintIdealGraphFile = ____; - public static String PrintIdealGraphAddress = "127.0.0.1"; - public static int PrintIdealGraphPort = 4444; - public static int PrintBinaryGraphPort = 4445; - - // Other printing settings - public static boolean PrintQueue = ____; - public static boolean PrintCompilation = ____; - public static boolean PrintProfilingInformation = ____; - public static boolean PrintXirTemplates = ____; - public static boolean PrintIRWithLIR = ____; - public static boolean PrintAssembly = ____; - public static boolean PrintCodeBytes = ____; - public static int PrintAssemblyBytesPerLine = 16; - public static boolean PrintBailout = ____; - public static int TraceLinearScanLevel = 0; - public static boolean TraceRegisterAllocation = false; - 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; - - // state merging settings - public static boolean AssumeVerifiedBytecode = true; - - // Code generator settings - public static boolean CheckCastElimination = true; - public static boolean CullFrameStates = ____; - 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; - static boolean UseTypeCheckHints = true; - public static boolean InlineVTableStubs = true; - public static boolean AlwaysInlineVTableStubs = ____; - - public static boolean GenAssertionCode = ____; - public static boolean AlignCallsForPatching = true; - public static boolean ResolveClassBeforeStaticInvoke = true; - - // Translating tableswitch instructions - public static int SequentialSwitchLimit = 4; - public static int RangeTestsSwitchDensity = 5; - public static double MinTableSwitchDensity = 0.5; - - public static boolean DetailedAsserts = ____; - - // Runtime settings - public static int ReadPrefetchInstr = 0; - public static int StackShadowPages = 2; - - // Assembler settings - public static boolean CommentedAssembly = ____; - public static boolean PrintLIRWithAssembly = ____; - - public static boolean SupportJsrBytecodes = true; - - public static boolean OptAssumptions = true; - public static boolean OptReadElimination = true; - public static boolean OptGVN = true; - public static boolean OptCanonicalizer = true; - public static boolean ScheduleOutOfLoops = true; - public static boolean OptReorderLoops = true; - public static boolean OptEliminateGuards = true; - public static boolean OptImplicitNullChecks = true; - public static boolean OptLivenessAnalysis = true; - public static boolean OptLoopTransform = true; - public static boolean OptSafepointElimination = true; - public static boolean FloatingReads = true; - public static boolean OptTailDuplication = true; - - /** - * Insert a counter in the method prologue to track the most frequently called methods that were compiled by Graal. - */ - public static boolean MethodEntryCounters = false; - /** - * Number of caller program counters to distinguish when counting methods. - */ - public static int MethodEntryCountersCallers = 20; - - /** - * Prints all the available GraalOptions. - */ - public static boolean PrintFlags = false; - - /** - * Counts the various paths taken through snippets. - */ - public static boolean SnippetCounters = false; - - /** - * If the probability that a checkcast will hit one the profiled types (up to {@link #CheckcastMaxHints}) - * is below this value, the checkcast will be compiled without hints. - */ - public static double CheckcastMinHintHitProbability = 0.5; - - /** - * The maximum number of hint types that will be used when compiling a checkcast for which - * profiling information is available. Note that {@link #CheckcastMinHintHitProbability} - * also influences whether hints are used. - */ - public static int CheckcastMaxHints = 2; - - /** - * @see #CheckcastMinHintHitProbability - */ - public static double InstanceOfMinHintHitProbability = 0.5; - - /** - * @see #CheckcastMaxHints - */ - public static int InstanceOfMaxHints = 1; - - /** - * Use HIR lowering instead of LIR lowering for certain instructions. - * Only instructions in methods whose fully qualified name contains this option will be HIR lowered. - */ - public static String HIRLowerCheckcast = ""; - public static String HIRLowerInstanceOf = ""; - public static String HIRLowerNewInstance = ""; - public static String HIRLowerNewArray = ""; - public static String HIRLowerMonitors = "MonitorTest"; - - /** - * Use XIR to lower {@link Invoke} nodes. - */ - public static boolean XIRLowerInvokes = false; - - static { - // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this) - assert (DetailedAsserts = true) == true; - assert (CommentedAssembly = true) == true; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +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.compiler; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -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(ResolvedJavaMethod method) { - this.enabledOpts = EnumSet.noneOf(Optimization.class); - - ProfilingInfo profilingInfo = method.profilingInfo(); - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.UnreachedCode)) { - enabledOpts.add(Optimization.RemoveNeverExecutedCode); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.TypeCheckedInliningViolated)) { - enabledOpts.add(Optimization.UseTypeCheckedInlining); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.OptimizedTypeCheckViolated)) { - enabledOpts.add(Optimization.UseTypeCheckHints); - } - if (checkDeoptimizations(profilingInfo, DeoptimizationReason.NotCompiledExceptionHandler)) { - enabledOpts.add(Optimization.UseExceptionProbability); - } - } - - private OptimisticOptimizations(Set enabledOpts) { - this.enabledOpts = enabledOpts; - } - - public void log(JavaMethod method) { - for (Optimization opt: Optimization.values()) { - if (!enabledOpts.contains(opt)) { - if (GraalOptions.PrintDisabledOptimisticOptimizations) { - TTY.println("WARN: deactivated optimistic optimization %s for %s", opt.name(), MetaUtil.format("%H.%n(%p)", method)); - } - disabledOptimisticOptsMetric.increment(); - } - } - } - - public boolean removeNeverExecutedCode() { - return GraalOptions.RemoveNeverExecutedCode && enabledOpts.contains(Optimization.RemoveNeverExecutedCode); - } - - public boolean useTypeCheckHints() { - 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(ProfilingInfo profilingInfo, DeoptimizationReason reason) { - return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Mon Sep 17 16:08:46 2012 +0200 @@ -170,6 +170,19 @@ this.blockData = new BlockMap<>(ir.cfg); } + public int getFirstLirInstructionId(Block block) { + int result = ir.lir(block).get(0).id(); + assert result >= 0; + return result; + } + + public int getLastLirInstructionId(Block block) { + List instructions = ir.lir(block); + int result = instructions.get(instructions.size() - 1).id(); + assert result >= 0; + return result; + } + public static boolean isVariableOrRegister(Value value) { return isVariable(value) || isRegister(value); } @@ -494,7 +507,7 @@ int numBlocks = blockCount(); for (int i = 0; i < numBlocks; i++) { Block block = blockAt(i); - List instructions = block.lir; + List instructions = ir.lir(block); int numInst = instructions.size(); // iterate all instructions of the block. skip the first because it is always a label @@ -526,7 +539,7 @@ while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { if (!insertionBuffer.initialized()) { // prepare insertion buffer (appended when all instructions of the block are processed) - insertionBuffer.init(block.lir); + insertionBuffer.init(instructions); } Value fromLocation = interval.location(); @@ -601,7 +614,7 @@ int numBlocks = blockCount(); int numInstructions = 0; for (int i = 0; i < numBlocks; i++) { - numInstructions += blockAt(i).lir.size(); + numInstructions += ir.lir(blockAt(i)).size(); } // initialize with correct length @@ -615,7 +628,7 @@ Block block = blockAt(i); blockData.put(block, new BlockData()); - List instructions = block.lir; + List instructions = ir.lir(block); int numInst = instructions.size(); for (int j = 0; j < numInst; j++) { @@ -659,7 +672,7 @@ final BitSet liveGen = new BitSet(liveSize); final BitSet liveKill = new BitSet(liveSize); - List instructions = block.lir; + List instructions = ir.lir(block); int numInst = instructions.size(); // iterate all instructions of the block. skip the first because it is always a label @@ -875,7 +888,7 @@ if (blockData.get(block).liveGen.get(operandNum)) { usedIn.add(block); TTY.println(" used in block B%d", block.getId()); - for (LIRInstruction ins : block.lir) { + for (LIRInstruction ins : ir.lir(block)) { TTY.println(ins.id() + ": " + ins.toString()); ins.forEachState(new ValueProcedure() { @Override @@ -889,7 +902,7 @@ if (blockData.get(block).liveKill.get(operandNum)) { definedIn.add(block); TTY.println(" defined in block B%d", block.getId()); - for (LIRInstruction ins : block.lir) { + for (LIRInstruction ins : ir.lir(block)) { TTY.println(ins.id() + ": " + ins.toString()); } } @@ -1131,9 +1144,9 @@ // iterate all blocks in reverse order for (int i = blockCount() - 1; i >= 0; i--) { Block block = blockAt(i); - List instructions = block.lir; - final int blockFrom = block.getFirstLirInstructionId(); - int blockTo = block.getLastLirInstructionId(); + List instructions = ir.lir(block); + final int blockFrom = getFirstLirInstructionId(block); + int blockTo = getLastLirInstructionId(block); assert blockFrom == instructions.get(0).id(); assert blockTo == instructions.get(instructions.size() - 1).id(); @@ -1432,14 +1445,14 @@ assert isVariable(operand) : "register number out of bounds"; assert intervalFor(operand) != null : "no interval found"; - return splitChildAtOpId(intervalFor(operand), block.getFirstLirInstructionId(), LIRInstruction.OperandMode.DEF); + return splitChildAtOpId(intervalFor(operand), getFirstLirInstructionId(block), LIRInstruction.OperandMode.DEF); } Interval intervalAtBlockEnd(Block block, Value operand) { assert isVariable(operand) : "register number out of bounds"; assert intervalFor(operand) != null : "no interval found"; - return splitChildAtOpId(intervalFor(operand), block.getLastLirInstructionId() + 1, LIRInstruction.OperandMode.DEF); + return splitChildAtOpId(intervalFor(operand), getLastLirInstructionId(block) + 1, LIRInstruction.OperandMode.DEF); } Interval intervalAtOpId(Value operand, int opId) { @@ -1471,19 +1484,19 @@ } } - static void resolveFindInsertPos(Block fromBlock, Block toBlock, MoveResolver moveResolver) { + void resolveFindInsertPos(Block fromBlock, Block toBlock, MoveResolver moveResolver) { if (fromBlock.numberOfSux() <= 1) { if (GraalOptions.TraceLinearScanLevel >= 4) { TTY.println("inserting moves at end of fromBlock B%d", fromBlock.getId()); } - List instructions = fromBlock.lir; + List instructions = ir.lir(fromBlock); LIRInstruction instr = instructions.get(instructions.size() - 1); if (instr instanceof StandardOp.JumpOp) { // insert moves before branch - moveResolver.setInsertPosition(fromBlock.lir, instructions.size() - 1); + moveResolver.setInsertPosition(instructions, instructions.size() - 1); } else { - moveResolver.setInsertPosition(fromBlock.lir, instructions.size()); + moveResolver.setInsertPosition(instructions, instructions.size()); } } else { @@ -1492,7 +1505,7 @@ } if (GraalOptions.DetailedAsserts) { - assert fromBlock.lir.get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; + assert ir.lir(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label"; // because the number of predecessor edges matches the number of // successor edges, blocks which are reached by switch statements @@ -1503,7 +1516,7 @@ } } - moveResolver.setInsertPosition(toBlock.lir, 1); + moveResolver.setInsertPosition(ir.lir(toBlock), 1); } } @@ -1523,7 +1536,7 @@ // check if block has only one predecessor and only one successor if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) { - List instructions = block.lir; + List instructions = ir.lir(block); assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; @@ -1542,7 +1555,7 @@ // directly resolve between pred and sux (without looking at the empty block between) resolveCollectMappings(pred, sux, moveResolver); if (moveResolver.hasMappings()) { - moveResolver.setInsertPosition(block.lir, 1); + moveResolver.setInsertPosition(instructions, 1); moveResolver.resolveAndAppendMoves(); } } @@ -1645,11 +1658,11 @@ if (opId != -1) { if (GraalOptions.DetailedAsserts) { Block block = blockForId(opId); - if (block.numberOfSux() <= 1 && opId == block.getLastLirInstructionId()) { + if (block.numberOfSux() <= 1 && opId == getLastLirInstructionId(block)) { // check if spill moves could have been appended at the end of this block, but // before the branch instruction. So the split child information for this branch would // be incorrect. - LIRInstruction instr = block.lir.get(block.lir.size() - 1); + LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (blockData.get(block).liveOut.get(operandNumber(operand))) { assert false : "can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow)"; @@ -1739,16 +1752,16 @@ int tempOpId = op.id(); OperandMode mode = OperandMode.USE; Block block = blockForId(tempOpId); - if (block.numberOfSux() == 1 && tempOpId == block.getLastLirInstructionId()) { + if (block.numberOfSux() == 1 && tempOpId == getLastLirInstructionId(block)) { // generating debug information for the last instruction of a block. // if this instruction is a branch, spill moves are inserted before this branch // and so the wrong operand would be returned (spill moves at block boundaries are not // considered in the live ranges of intervals) // Solution: use the first opId of the branch target block instead. - final LIRInstruction instr = block.lir.get(block.lir.size() - 1); + final LIRInstruction instr = ir.lir(block).get(ir.lir(block).size() - 1); if (instr instanceof StandardOp.JumpOp) { if (blockData.get(block).liveOut.get(operandNumber(operand))) { - tempOpId = block.suxAt(0).getFirstLirInstructionId(); + tempOpId = getFirstLirInstructionId(block.suxAt(0)); mode = OperandMode.DEF; } } @@ -1819,7 +1832,7 @@ private void assignLocations() { IntervalWalker iw = initComputeOopMaps(); for (Block block : sortedBlocks) { - assignLocations(block.lir, iw); + assignLocations(ir.lir(block), iw); } } @@ -1878,8 +1891,8 @@ public void run() { printLir("After register number assignment", true); - EdgeMoveOptimizer.optimize(ir.linearScanOrder()); - ControlFlowOptimizer.optimize(ir.codeEmittingOrder()); + EdgeMoveOptimizer.optimize(ir); + ControlFlowOptimizer.optimize(ir); printLir("After control flow optimization", false); } }); @@ -1901,7 +1914,7 @@ TTY.println("--- Basic Blocks ---"); for (i = 0; i < blockCount(); i++) { Block block = blockAt(i); - TTY.print("B%d [%d, %d, %s] ", block.getId(), block.getFirstLirInstructionId(), block.getLastLirInstructionId(), block.getLoop()); + TTY.print("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop()); } TTY.println(); TTY.println(); @@ -2055,7 +2068,7 @@ for (int i = 0; i < blockCount(); i++) { Block block = blockAt(i); - List instructions = block.lir; + List instructions = ir.lir(block); for (int j = 0; j < instructions.size(); j++) { LIRInstruction op = instructions.get(j); diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Mon Sep 17 16:08:46 2012 +0200 @@ -242,19 +242,19 @@ // numbering of instructions is known. // When the block already contains spill moves, the index must be increased until the // correct index is reached. - List list = opBlock.lir; - int index = (opId - list.get(0).id()) >> 1; - assert list.get(index).id() <= opId : "error in calculation"; + List instructions = allocator.ir.lir(opBlock); + int index = (opId - instructions.get(0).id()) >> 1; + assert instructions.get(index).id() <= opId : "error in calculation"; - while (list.get(index).id() != opId) { + while (instructions.get(index).id() != opId) { index++; - assert 0 <= index && index < list.size() : "index out of bounds"; + assert 0 <= index && index < instructions.size() : "index out of bounds"; } - assert 1 <= index && index < list.size() : "index out of bounds"; - assert list.get(index).id() == opId : "error in calculation"; + assert 1 <= index && index < instructions.size() : "index out of bounds"; + assert instructions.get(index).id() == opId : "error in calculation"; // insert new instruction before instruction at position index - moveResolver.moveInsertPosition(opBlock.lir, index); + moveResolver.moveInsertPosition(instructions, index); moveResolver.addMapping(srcIt, dstIt); } @@ -268,9 +268,9 @@ // Try to split at end of maxBlock. If this would be after // maxSplitPos, then use the begin of maxBlock - int optimalSplitPos = maxBlock.getLastLirInstructionId() + 2; + int optimalSplitPos = allocator.getLastLirInstructionId(maxBlock) + 2; if (optimalSplitPos > maxSplitPos) { - optimalSplitPos = maxBlock.getFirstLirInstructionId(); + optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock); } int minLoopDepth = maxBlock.getLoopDepth(); @@ -280,7 +280,7 @@ if (cur.getLoopDepth() < minLoopDepth) { // block with lower loop-depth found . split at the end of this block minLoopDepth = cur.getLoopDepth(); - optimalSplitPos = cur.getLastLirInstructionId() + 2; + optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2; } } assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary"; @@ -340,7 +340,7 @@ if (doLoopOptimization) { // Loop optimization: if a loop-end marker is found between min- and max-position : // then split before this loop - int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, minBlock.getLastLirInstructionId() + 2); + int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, allocator.getLastLirInstructionId(minBlock) + 2); if (GraalOptions.TraceLinearScanLevel >= 4) { TTY.println(" loop optimization: loop end found at pos %d", loopEndPos); } @@ -359,8 +359,8 @@ } assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between"; - optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, loopBlock.getLastLirInstructionId() + 2); - if (optimalSplitPos == loopBlock.getLastLirInstructionId() + 2) { + optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, allocator.getLastLirInstructionId(loopBlock) + 2); + if (optimalSplitPos == allocator.getLastLirInstructionId(loopBlock) + 2) { optimalSplitPos = -1; if (GraalOptions.TraceLinearScanLevel >= 4) { TTY.println(" loop optimization not necessary"); diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/RegisterVerifier.java Mon Sep 17 16:08:46 2012 +0200 @@ -115,7 +115,7 @@ } // process all operations of the block - processOperations(block.lir, inputState); + processOperations(allocator.ir.lir(block), inputState); // iterate all successors for (int i = 0; i < block.numberOfSux(); i++) { diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Sep 17 16:08:46 2012 +0200 @@ -281,7 +281,7 @@ int suxIndex = currentBlock.getSuccessors().indexOf(result); assert suxIndex != -1 : "Block not in successor list of current block"; - return LabelRef.forSuccessor(currentBlock, suxIndex); + return LabelRef.forSuccessor(lir, currentBlock, suxIndex); } public LIRFrameState state() { @@ -327,7 +327,7 @@ TTY.println(op.toStringWithIdPrefix()); TTY.println(); } - currentBlock.lir.add(op); + lir.lir(currentBlock).add(op); } public void doBlock(Block block) { @@ -337,8 +337,8 @@ currentBlock = block; // set up the list of LIR instructions - assert block.lir == null : "LIR list already computed for this block"; - block.lir = new ArrayList<>(); + assert lir.lir(block) == null : "LIR list already computed for this block"; + lir.setLir(block, new ArrayList()); append(new LabelOp(new Label(), block.align)); @@ -486,11 +486,12 @@ return true; } - private static boolean endsWithJump(Block block) { - if (block.lir.size() == 0) { + private boolean endsWithJump(Block block) { + List instructions = lir.lir(block); + if (instructions.size() == 0) { return false; } - LIRInstruction lirInstruction = block.lir.get(block.lir.size() - 1); + LIRInstruction lirInstruction = instructions.get(instructions.size() - 1); if (lirInstruction instanceof LIRXirInstruction) { LIRXirInstruction lirXirInstruction = (LIRXirInstruction) lirInstruction; return (lirXirInstruction.falseSuccessor != null) && (lirXirInstruction.trueSuccessor != null); diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/MergeableState.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/MergeableState.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.graph; - -import java.util.*; - -import com.oracle.graal.nodes.*; - -public interface MergeableState { - T clone(); - boolean merge(MergeNode merge, List withStates); - void loopBegin(LoopBeginNode loopBegin); - void loopEnds(LoopBeginNode loopBegin, List loopEndStates); - void afterSplit(FixedNode node); -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.graph; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -/** - * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a specified fixed node.
- * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode}, {@link MergeNode}...) and the {@link FixedWithNextNode#next() next} pointers - * of {@link FixedWithNextNode}.
- * While iterating it maintains a user-defined state by calling the methods available in {@link MergeableState}. - * - * @param the type of {@link MergeableState} handled by this PostOrderNodeIterator - */ -public abstract class PostOrderNodeIterator> { - - private final NodeBitMap visitedEnds; - private final Deque nodeQueue; - private final IdentityHashMap nodeStates; - private final FixedNode start; - - protected T state; - - public PostOrderNodeIterator(FixedNode start, T initialState) { - visitedEnds = start.graph().createNodeBitMap(); - nodeQueue = new ArrayDeque<>(); - nodeStates = new IdentityHashMap<>(); - this.start = start; - this.state = initialState; - } - - public void apply() { - FixedNode current = start; - - do { - if (current instanceof InvokeWithExceptionNode) { - invoke((Invoke) current); - queueSuccessors(current, null); - current = nextQueuedNode(); - } else if (current instanceof LoopBeginNode) { - state.loopBegin((LoopBeginNode) current); - nodeStates.put(current, state); - state = state.clone(); - loopBegin((LoopBeginNode) current); - current = ((LoopBeginNode) current).next(); - assert current != null; - } else if (current instanceof LoopEndNode) { - loopEnd((LoopEndNode) current); - finishLoopEnds((LoopEndNode) current); - current = nextQueuedNode(); - } else if (current instanceof MergeNode) { - merge((MergeNode) current); - current = ((MergeNode) current).next(); - assert current != null; - } else if (current instanceof FixedWithNextNode) { - FixedNode next = ((FixedWithNextNode) current).next(); - assert next != null : current; - node(current); - current = next; - } else if (current instanceof EndNode) { - end((EndNode) current); - queueMerge((EndNode) current); - current = nextQueuedNode(); - } else if (current instanceof DeoptimizeNode) { - deoptimize((DeoptimizeNode) current); - current = nextQueuedNode(); - } else if (current instanceof ReturnNode) { - returnNode((ReturnNode) current); - current = nextQueuedNode(); - } else if (current instanceof UnwindNode) { - unwind((UnwindNode) current); - current = nextQueuedNode(); - } else if (current instanceof ControlSplitNode) { - Set successors = controlSplit((ControlSplitNode) current); - queueSuccessors(current, successors); - current = nextQueuedNode(); - } else { - assert false : current; - } - } while(current != null); - } - - private void queueSuccessors(FixedNode x, Set successors) { - nodeStates.put(x, state); - if (successors != null) { - for (Node node : successors) { - if (node != null) { - nodeStates.put((FixedNode) node.predecessor(), state); - nodeQueue.addFirst((FixedNode) node); - } - } - } else { - for (Node node : x.successors()) { - if (node != null) { - nodeQueue.addFirst((FixedNode) node); - } - } - } - } - - private FixedNode nextQueuedNode() { - int maxIterations = nodeQueue.size(); - while (maxIterations-- > 0) { - FixedNode node = nodeQueue.removeFirst(); - if (node instanceof MergeNode) { - MergeNode merge = (MergeNode) node; - state = nodeStates.get(merge.forwardEndAt(0)).clone(); - ArrayList states = new ArrayList<>(merge.forwardEndCount() - 1); - for (int i = 1; i < merge.forwardEndCount(); i++) { - T other = nodeStates.get(merge.forwardEndAt(i)); - assert other != null; - states.add(other); - } - boolean ready = state.merge(merge, states); - if (ready) { - return merge; - } else { - nodeQueue.addLast(merge); - } - } else { - assert node.predecessor() != null; - state = nodeStates.get(node.predecessor()).clone(); - state.afterSplit(node); - return node; - } - } - return null; - } - - private void finishLoopEnds(LoopEndNode end) { - assert !visitedEnds.isMarked(end); - assert !nodeStates.containsKey(end); - nodeStates.put(end, state); - visitedEnds.mark(end); - LoopBeginNode begin = end.loopBegin(); - boolean endsVisited = true; - for (LoopEndNode le : begin.loopEnds()) { - if (!visitedEnds.isMarked(le)) { - endsVisited = false; - break; - } - } - if (endsVisited) { - ArrayList states = new ArrayList<>(begin.loopEnds().count()); - for (LoopEndNode le : begin.orderedLoopEnds()) { - states.add(nodeStates.get(le)); - } - T loopBeginState = nodeStates.get(begin); - if (loopBeginState != null) { - loopBeginState.loopEnds(begin, states); - } - } - } - - private void queueMerge(EndNode end) { - assert !visitedEnds.isMarked(end); - assert !nodeStates.containsKey(end); - nodeStates.put(end, state); - visitedEnds.mark(end); - MergeNode merge = end.merge(); - boolean endsVisited = true; - for (int i = 0; i < merge.forwardEndCount(); i++) { - if (!visitedEnds.isMarked(merge.forwardEndAt(i))) { - endsVisited = false; - break; - } - } - if (endsVisited) { - nodeQueue.add(merge); - } - } - - protected abstract void node(FixedNode node); - - protected void end(EndNode endNode) { - node(endNode); - } - - protected void merge(MergeNode merge) { - node(merge); - } - - protected void loopBegin(LoopBeginNode loopBegin) { - node(loopBegin); - } - - protected void loopEnd(LoopEndNode loopEnd) { - node(loopEnd); - } - - protected void deoptimize(DeoptimizeNode deoptimize) { - node(deoptimize); - } - - protected Set controlSplit(ControlSplitNode controlSplit) { - node(controlSplit); - return null; - } - - protected void returnNode(ReturnNode returnNode) { - node(returnNode); - } - - protected void invoke(Invoke invoke) { - node(invoke.node()); - } - - protected void unwind(UnwindNode unwind) { - node(unwind); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/package-info.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/package-info.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * - */ -package com.oracle.graal.compiler.graph; diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/BasicInductionVariable.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - - -public class BasicInductionVariable extends InductionVariable { - private PhiNode phi; - private ValueNode init; - private ValueNode rawStride; - private IntegerArithmeticNode op; - - public BasicInductionVariable(LoopEx loop, PhiNode phi, ValueNode init, ValueNode rawStride, IntegerArithmeticNode op) { - super(loop); - this.phi = phi; - this.init = init; - this.rawStride = rawStride; - this.op = op; - } - - @Override - public Direction direction() { - Stamp stamp = rawStride.stamp(); - if (stamp instanceof IntegerStamp) { - IntegerStamp integerStamp = (IntegerStamp) stamp; - Direction dir = null; - if (integerStamp.isStrictlyPositive()) { - dir = Direction.Up; - } else if (integerStamp.isStrictlyNegative()) { - dir = Direction.Down; - } - if (dir != null) { - if (op instanceof IntegerAddNode) { - return dir; - } else { - assert op instanceof IntegerSubNode; - return dir.opposite(); - } - } - } - return null; - } - - @Override - public PhiNode valueNode() { - return phi; - } - - @Override - public ValueNode initNode() { - return init; - } - - @Override - public ValueNode strideNode() { - if (op instanceof IntegerAddNode) { - return rawStride; - } - if (op instanceof IntegerSubNode) { - return rawStride.graph().unique(new NegateNode(rawStride)); - } - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public boolean isConstantInit() { - return init.isConstant(); - } - - @Override - public boolean isConstantStride() { - return rawStride.isConstant(); - } - - @Override - public long constantInit() { - return init.asConstant().asLong(); - } - - @Override - public long constantStride() { - if (op instanceof IntegerAddNode) { - return rawStride.asConstant().asLong(); - } - if (op instanceof IntegerSubNode) { - return -rawStride.asConstant().asLong(); - } - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init); - } - - @Override - public boolean isConstantExtremum() { - return isConstantInit() && isConstantStride() && loop.counted().isConstantMaxTripCount(); - } - - @Override - public long constantExtremum() { - return constantStride() * loop.counted().constantMaxTripCount() + constantInit(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/CountedLoopInfo.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.compiler.loop.InductionVariable.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class CountedLoopInfo { - private final LoopEx loop; - private InductionVariable iv; - private ValueNode end; - private boolean oneOff; - - CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) { - this.loop = loop; - this.iv = iv; - this.end = end; - this.oneOff = oneOff; - } - - public ValueNode maxTripCountNode() { - //TODO (gd) stuarte and respect oneOff - return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()), iv.strideNode()); - } - - public boolean isConstantMaxTripCount() { - return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride(); - } - - public long constantMaxTripCount() { - long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0; - long max = (((ConstantNode) end).asConstant().asLong() + off - iv.constantInit()) / iv.constantStride(); - return Math.max(0, max); - } - - public boolean isExactTripCount() { - return loop.loopBegin().loopExits().count() == 1; - } - - public ValueNode exactTripCountNode() { - assert isExactTripCount(); - return maxTripCountNode(); - } - - public boolean isConstantExactTripCount() { - assert isExactTripCount(); - return isConstantMaxTripCount(); - } - - public long constantExactTripCount() { - assert isExactTripCount(); - return constantMaxTripCount(); - } - - @Override - public String toString() { - return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : ""); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/DerivedOffsetInductionVariable.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - - -public class DerivedOffsetInductionVariable extends InductionVariable { - private InductionVariable base; - private ValueNode offset; - private IntegerArithmeticNode value; - - public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, IntegerArithmeticNode value) { - super(loop); - this.base = base; - this.offset = offset; - this.value = value; - } - - @Override - public Direction direction() { - return base.direction(); - } - - @Override - public ValueNode valueNode() { - return value; - } - - @Override - public boolean isConstantInit() { - return offset.isConstant() && base.isConstantInit(); - } - - @Override - public boolean isConstantStride() { - return base.isConstantStride(); - } - - @Override - public long constantInit() { - return op(base.constantInit(), offset.asConstant().asLong()); - } - - @Override - public long constantStride() { - if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { - return -base.constantStride(); - } - return base.constantStride(); - } - - @Override - public ValueNode initNode() { - return op(base.initNode(), offset); - } - - @Override - public ValueNode strideNode() { - if (value instanceof IntegerSubNode && base.valueNode() == value.y()) { - return value.graph().unique(new NegateNode(base.strideNode())); - } - return base.strideNode(); - } - - @Override - public ValueNode extremumNode() { - return op(offset, base.extremumNode()); - } - - @Override - public boolean isConstantExtremum() { - return offset.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return op(base.constantExtremum(), offset.asConstant().asLong()); - } - - private long op(long b, long o) { - if (value instanceof IntegerAddNode) { - return b + o; - } - if (value instanceof IntegerSubNode) { - if (base.valueNode() == value.x()) { - return b - o; - } else { - assert base.valueNode() == value.y(); - return o - b; - } - } - throw GraalInternalError.shouldNotReachHere(); - } - - private ValueNode op(ValueNode b, ValueNode o) { - if (value instanceof IntegerAddNode) { - return IntegerArithmeticNode.add(b, o); - } - if (value instanceof IntegerSubNode) { - if (base.valueNode() == value.x()) { - return IntegerArithmeticNode.sub(b, o); - } else { - assert base.valueNode() == value.y(); - return IntegerArithmeticNode.sub(o, b); - } - } - throw GraalInternalError.shouldNotReachHere(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/DerivedScaledInductionVariable.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.type.*; - - -public class DerivedScaledInductionVariable extends InductionVariable { - private InductionVariable base; - private ValueNode scale; - private ValueNode value; - - public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, ValueNode scale, ValueNode value) { - super(loop); - this.base = base; - this.scale = scale; - this.value = value; - } - - public DerivedScaledInductionVariable(LoopEx loop, InductionVariable base, NegateNode value) { - super(loop); - this.base = base; - this.scale = ConstantNode.forInt(-1, value.graph()); - this.value = value; - } - - @Override - public Direction direction() { - Stamp stamp = scale.stamp(); - if (stamp instanceof IntegerStamp) { - IntegerStamp integerStamp = (IntegerStamp) stamp; - if (integerStamp.isStrictlyPositive()) { - return base.direction(); - } else if (integerStamp.isStrictlyNegative()) { - return base.direction().opposite(); - } - } - return null; - } - - @Override - public ValueNode valueNode() { - return value; - } - - @Override - public ValueNode initNode() { - return IntegerArithmeticNode.mul(base.initNode(), scale); - } - - @Override - public ValueNode strideNode() { - return IntegerArithmeticNode.mul(base.strideNode(), scale); - } - - @Override - public boolean isConstantInit() { - return scale.isConstant() && base.isConstantInit(); - } - - @Override - public boolean isConstantStride() { - return scale.isConstant() && base.isConstantStride(); - } - - @Override - public long constantInit() { - return base.constantInit() * scale.asConstant().asLong(); - } - - @Override - public long constantStride() { - return base.constantStride() * scale.asConstant().asLong(); - } - - @Override - public ValueNode extremumNode() { - return IntegerArithmeticNode.mul(base.extremumNode(), scale); - } - - @Override - public boolean isConstantExtremum() { - return scale.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return base.constantExtremum() * scale.asConstant().asLong(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/InductionVariable.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/InductionVariable.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public abstract class InductionVariable { - public enum Direction { - Up, - Down; - public Direction opposite() { - switch(this) { - case Up: return Down; - case Down: return Up; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - } - - protected final LoopEx loop; - - public InductionVariable(LoopEx loop) { - this.loop = loop; - } - - public abstract Direction direction(); - - public abstract ValueNode valueNode(); - - public abstract ValueNode initNode(); - public abstract ValueNode strideNode(); - - public abstract boolean isConstantInit(); - public abstract boolean isConstantStride(); - - public abstract long constantInit(); - public abstract long constantStride(); - - public abstract ValueNode extremumNode(); - public abstract boolean isConstantExtremum(); - public abstract long constantExtremum(); -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/InductionVariables.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/InductionVariables.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - - -public class InductionVariables { - private final LoopEx loop; - private Map ivs; - - public InductionVariables(LoopEx loop) { - this.loop = loop; - ivs = new IdentityHashMap<>(); - findDerived(findBasic()); - } - - public InductionVariable get(ValueNode v) { - return ivs.get(v); - } - - private Collection findBasic() { - List bivs = new LinkedList<>(); - LoopBeginNode loopBegin = loop.loopBegin(); - EndNode forwardEnd = loopBegin.forwardEnd(); - for (PhiNode phi : loopBegin.phis()) { - ValueNode backValue = phi.singleBackValue(); - if (backValue == null) { - continue; - } - ValueNode stride = addSub(backValue, phi); - if (stride != null) { - BasicInductionVariable biv = new BasicInductionVariable(loop, phi, phi.valueAt(forwardEnd), stride, (IntegerArithmeticNode) backValue); - ivs.put(phi, biv); - bivs.add(biv); - } - } - return bivs; - } - - private void findDerived(Collection bivs) { - Queue scanQueue = new LinkedList(bivs); - while (!scanQueue.isEmpty()) { - InductionVariable baseIv = scanQueue.remove(); - ValueNode baseIvNode = baseIv.valueNode(); - for (ValueNode op : baseIvNode.usages().filter(ValueNode.class)) { - if (loop.isOutsideLoop(op)) { - continue; - } - InductionVariable iv = null; - ValueNode offset = addSub(op, baseIvNode); - ValueNode scale; - if (offset != null) { - iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (IntegerArithmeticNode) op); - } else if (op instanceof NegateNode) { - iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op); - } else if ((scale = mul(op, baseIvNode)) != null) { - iv = new DerivedScaledInductionVariable(loop, baseIv, scale, op); - } - - if (iv != null) { - ivs.put(op, iv); - scanQueue.offer(iv); - } - } - } - } - - private ValueNode addSub(ValueNode op, ValueNode base) { - if (op instanceof IntegerAddNode || op instanceof IntegerSubNode) { - IntegerArithmeticNode aritOp = (IntegerArithmeticNode) op; - if (aritOp.x() == base && loop.isOutsideLoop(aritOp.y())) { - return aritOp.y(); - } else if (aritOp.y() == base && loop.isOutsideLoop(aritOp.x())) { - return aritOp.x(); - } - } - return null; - } - - private ValueNode mul(ValueNode op, ValueNode base) { - if (op instanceof IntegerMulNode) { - IntegerMulNode mul = (IntegerMulNode) op; - if (mul.x() == base && loop.isOutsideLoop(mul.y())) { - return mul.y(); - } else if (mul.y() == base && loop.isOutsideLoop(mul.x())) { - return mul.x(); - } - } - if (op instanceof LeftShiftNode) { - LeftShiftNode shift = (LeftShiftNode) op; - if (shift.x() == base && shift.y().isConstant()) { - return ConstantNode.forInt(1 << shift.y().asConstant().asInt(), base.graph()); - } - } - return null; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopEx.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopEx.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class LoopEx { - private final Loop lirLoop; - private LoopFragmentInside inside; - private LoopFragmentWhole whole; - private CountedLoopInfo counted; //TODO (gd) detect - private LoopsData data; - - LoopEx(Loop lirLoop, LoopsData data) { - this.lirLoop = lirLoop; - this.data = data; - } - - public Loop lirLoop() { - return lirLoop; - } - - public LoopFragmentInside inside() { - if (inside == null) { - inside = new LoopFragmentInside(this); - } - return inside; - } - - public LoopFragmentWhole whole() { - if (whole == null) { - whole = new LoopFragmentWhole(this); - } - return whole; - } - - @SuppressWarnings("unused") - public LoopFragmentInsideFrom insideFrom(FixedNode point) { - // TODO (gd) - return null; - } - - @SuppressWarnings("unused") - public LoopFragmentInsideBefore insideBefore(FixedNode point) { - // TODO (gd) - return null; - } - - public boolean isOutsideLoop(Node n) { - return !whole().contains(n); - } - - public LoopBeginNode loopBegin() { - return lirLoop().loopBegin(); - } - - public FixedNode predecessor() { - return (FixedNode) loopBegin().forwardEnd().predecessor(); - } - - public FixedNode entryPoint() { - return loopBegin().forwardEnd(); - } - - public boolean isCounted() { - return counted != null; - } - - public CountedLoopInfo counted() { - return counted; - } - - public LoopEx parent() { - if (lirLoop.parent == null) { - return null; - } - return data.loop(lirLoop.parent); - } - - public int size() { - return whole().nodes().count(); - } - - @Override - public String toString() { - return (isCounted() ? "CountedLoop [" + counted() + "] " : "Loop ") + "(depth=" + lirLoop().depth + ") " + loopBegin(); - } - - private class InvariantPredicate extends NodePredicate { - @Override - public boolean apply(Node n) { - return isOutsideLoop(n); - } - } - - public void reassociateInvariants() { - InvariantPredicate invariant = new InvariantPredicate(); - StructuredGraph graph = (StructuredGraph) loopBegin().graph(); - for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) { - if (!BinaryNode.canTryReassociate(binary)) { - continue; - } - BinaryNode result = BinaryNode.reassociate(binary, invariant); - if (result != binary) { - Debug.log(MetaUtil.format("%H::%n", Debug.contextLookup(ResolvedJavaMethod.class)) + " : Reassociated %s into %s", binary, result); - graph.replaceFloating(binary, result); - } - } - } - - public void setCounted(CountedLoopInfo countedLoopInfo) { - counted = countedLoopInfo; - } - - public LoopsData loopsData() { - return data; - } - - public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) { - Collection blocks = new LinkedList<>(); - Collection exits = new LinkedList<>(); - Queue work = new LinkedList<>(); - ControlFlowGraph cfg = loopsData().controlFlowGraph(); - work.add(cfg.blockFor(point)); - Block untilBlock = until != null ? cfg.blockFor(until) : null; - while (!work.isEmpty()) { - Block b = work.remove(); - if (b == untilBlock) { - continue; - } - if (lirLoop().exits.contains(b)) { - exits.add(b.getBeginNode()); - } else if (lirLoop().blocks.contains(b)) { - blocks.add(b.getBeginNode()); - work.addAll(b.getDominated()); - } - } - return LoopFragment.computeNodes(point.graph(), blocks, exits); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragment.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.VirtualState.VirtualClosure; - - -public abstract class LoopFragment { - private final LoopEx loop; - private final LoopFragment original; - protected NodeBitMap nodes; - protected boolean nodesReady; - private Map duplicationMap; - - public LoopFragment(LoopEx loop) { - this(loop, null); - this.nodesReady = true; - } - - public LoopFragment(LoopEx loop, LoopFragment original) { - this.loop = loop; - this.original = original; - this.nodesReady = false; - } - - public LoopEx loop() { - return loop; - } - - public abstract LoopFragment duplicate(); - - public abstract void insertBefore(LoopEx l); - - public void disconnect() { - // TODO (gd) possibly abstract - } - - public boolean contains(Node n) { - return nodes().contains(n); - } - - @SuppressWarnings("unchecked") - public New getDuplicatedNode(Old n) { - assert isDuplicate(); - return (New) duplicationMap.get(n); - } - - protected void putDuplicatedNode(Old oldNode, New newNode) { - duplicationMap.put(oldNode, newNode); - } - - public boolean isDuplicate() { - return original != null; - } - - public LoopFragment original() { - return original; - } - - public abstract NodeIterable nodes(); - - public StructuredGraph graph() { - LoopEx l; - if (isDuplicate()) { - l = original().loop(); - } else { - l = loop(); - } - return (StructuredGraph) l.loopBegin().graph(); - } - - protected abstract DuplicationReplacement getDuplicationReplacement(); - - protected abstract void finishDuplication(); - - protected void patchNodes(final DuplicationReplacement dataFix) { - if (isDuplicate() && !nodesReady) { - assert !original.isDuplicate(); - final DuplicationReplacement cfgFix = original().getDuplicationReplacement(); - DuplicationReplacement dr; - if (cfgFix == null && dataFix != null) { - dr = dataFix; - } else if (cfgFix != null && dataFix == null) { - dr = cfgFix; - } else if (cfgFix != null && dataFix != null) { - dr = new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - Node r1 = dataFix.replacement(o); - if (r1 != o) { - assert cfgFix.replacement(o) == o; - return r1; - } - Node r2 = cfgFix.replacement(o); - if (r2 != o) { - return r2; - } - return o; - } - }; - } else { - dr = new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - return o; - } - }; - } - duplicationMap = graph().addDuplicates(original().nodes(), dr); - finishDuplication(); - nodesReady = true; - } else { - //TODO (gd) apply fix ? - } - } - - protected static NodeBitMap computeNodes(Graph graph, Collection blocks) { - return computeNodes(graph, blocks, Collections.emptyList()); - } - - protected static NodeBitMap computeNodes(Graph graph, Collection blocks, Collection earlyExits) { - final NodeBitMap nodes = graph.createNodeBitMap(true); - for (BeginNode b : blocks) { - for (Node n : b.getBlockNodes()) { - if (n instanceof Invoke) { - nodes.mark(((Invoke) n).callTarget()); - } - if (n instanceof StateSplit) { - FrameState stateAfter = ((StateSplit) n).stateAfter(); - if (stateAfter != null) { - nodes.mark(stateAfter); - } - } - nodes.mark(n); - } - } - for (BeginNode earlyExit : earlyExits) { - FrameState stateAfter = earlyExit.stateAfter(); - if (stateAfter != null) { - nodes.mark(stateAfter); - stateAfter.applyToVirtual(new VirtualClosure() { - @Override - public void apply(VirtualState node) { - nodes.mark(node); - } - }); - } - nodes.mark(earlyExit); - for (ValueProxyNode proxy : earlyExit.proxies()) { - nodes.mark(proxy); - } - } - - for (BeginNode b : blocks) { - for (Node n : b.getBlockNodes()) { - for (Node usage : n.usages()) { - markFloating(usage, nodes); - } - } - } - - return nodes; - } - - private static boolean markFloating(Node n, NodeBitMap loopNodes) { - if (loopNodes.isMarked(n)) { - return true; - } - if (n instanceof FixedNode) { - return false; - } - boolean mark = false; - if (n instanceof PhiNode) { - PhiNode phi = (PhiNode) n; - mark = loopNodes.isMarked(phi.merge()); - if (mark) { - loopNodes.mark(n); - } else { - return false; - } - } - for (Node usage : n.usages()) { - if (markFloating(usage, loopNodes)) { - mark = true; - } - } - if (mark) { - loopNodes.mark(n); - return true; - } - return false; - } - - public static Collection toHirBlocks(Collection blocks) { - List hir = new ArrayList<>(blocks.size()); - for (Block b : blocks) { - hir.add(b.getBeginNode()); - } - return hir; - } - - /** - * Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with the original fragment's exits. - */ - protected void mergeEarlyExits() { - assert isDuplicate(); - StructuredGraph graph = graph(); - for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) { - FixedNode next = earlyExit.next(); - if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) { - continue; - } - BeginNode newEarlyExit = getDuplicatedNode(earlyExit); - if (newEarlyExit == null) { - continue; - } - MergeNode merge = graph.add(new MergeNode()); - merge.setProbability(next.probability()); - EndNode originalEnd = graph.add(new EndNode()); - EndNode newEnd = graph.add(new EndNode()); - merge.addForwardEnd(originalEnd); - merge.addForwardEnd(newEnd); - earlyExit.setNext(originalEnd); - newEarlyExit.setNext(newEnd); - merge.setNext(next); - - FrameState exitState = earlyExit.stateAfter(); - FrameState newExitState = newEarlyExit.stateAfter(); - FrameState state = null; - if (exitState != null) { - state = exitState.duplicateWithVirtualState(); - merge.setStateAfter(state); - } - - for (Node anchored : earlyExit.anchored().snapshot()) { - anchored.replaceFirstInput(earlyExit, merge); - } - - for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) { - final ValueNode replaceWith; - ValueProxyNode newVpn = getDuplicatedNode(vpn); - if (newVpn != null) { - PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge)); - phi.addInput(vpn); - phi.addInput(newVpn); - replaceWith = phi; - } else { - replaceWith = vpn.value(); - } - if (state != null) { - state.applyToNonVirtual(new NodeClosure() { - @Override - public void apply(Node from, ValueNode node) { - if (node == vpn) { - from.replaceFirstInput(vpn, replaceWith); - } - } - }); - } - for (Node usage : vpn.usages().snapshot()) { - if (!merge.isPhiAtMerge(usage)) { - if (usage instanceof VirtualState) { - VirtualState stateUsage = (VirtualState) usage; - if (exitState.isPartOfThisState(stateUsage) || newExitState.isPartOfThisState(stateUsage)) { - continue; - } - } - usage.replaceFirstInput(vpn, replaceWith); - } - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInside.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; - -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.util.*; - - -public class LoopFragmentInside extends LoopFragment { - /** mergedInitializers. - * When an inside fragment's (loop)ends are merged to create a unique exit point, - * some phis must be created : they phis together all the back-values of the loop-phis - * These can then be used to update the loop-phis' forward edge value ('initializer') in the peeling case. - * In the unrolling case they will be used as the value that replace the loop-phis of the duplicated inside fragment - */ - private Map mergedInitializers; - private final DuplicationReplacement dataFixBefore = new DuplicationReplacement() { - @Override - public Node replacement(Node oriInput) { - if (!(oriInput instanceof ValueNode)) { - return oriInput; - } - return prim((ValueNode) oriInput); - } - }; - - public LoopFragmentInside(LoopEx loop) { - super(loop); - } - - public LoopFragmentInside(LoopFragmentInside original) { - super(null, original); - } - - @Override - public LoopFragmentInside duplicate() { - assert !isDuplicate(); - return new LoopFragmentInside(this); - } - - @Override - public LoopFragmentInside original() { - return (LoopFragmentInside) super.original(); - } - - @SuppressWarnings("unused") - public void appendInside(LoopEx loop) { - // TODO (gd) - } - - @Override - public LoopEx loop() { - assert !this.isDuplicate(); - return super.loop(); - } - - @Override - public void insertBefore(LoopEx loop) { - assert this.isDuplicate() && this.original().loop() == loop; - - patchNodes(dataFixBefore); - - BeginNode end = mergeEnds(); - - original().patchPeeling(this); - - mergeEarlyExits(); - - BeginNode entry = getDuplicatedNode(loop.loopBegin()); - FrameState state = entry.stateAfter(); - if (state != null) { - entry.setStateAfter(null); - GraphUtil.killWithUnusedFloatingInputs(state); - } - loop.entryPoint().replaceAtPredecessor(entry); - end.setProbability(loop.entryPoint().probability()); - end.setNext(loop.entryPoint()); - } - - @Override - public NodeIterable nodes() { - if (nodes == null) { - LoopFragmentWhole whole = loop().whole(); - whole.nodes(); // init nodes bitmap in whole - nodes = whole.nodes.copy(); - // remove the phis - for (PhiNode phi : loop().loopBegin().phis()) { - nodes.clear(phi); - } - } - return nodes; - } - - @Override - protected DuplicationReplacement getDuplicationReplacement() { - final LoopBeginNode loopBegin = loop().loopBegin(); - final StructuredGraph graph = graph(); - return new DuplicationReplacement() { - @Override - public Node replacement(Node original) { - if (original == loopBegin) { - return graph.add(new BeginNode()); - } - if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) { - return graph.add(new BeginNode()); - } - if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) { - return graph.add(new EndNode()); - } - return original; - } - }; - } - - @Override - protected void finishDuplication() { - // TODO (gd) ? - } - - private void patchPeeling(LoopFragmentInside peel) { - LoopBeginNode loopBegin = loop().loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); - List newPhis = new LinkedList<>(); - for (PhiNode phi : loopBegin.phis().snapshot()) { - ValueNode first; - if (loopBegin.loopEnds().count() == 1) { - ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value - first = peel.prim(b); // corresponding value in the peel - } else { - first = peel.mergedInitializers.get(phi); - } - // create a new phi (we don't patch the old one since some usages of the old one may still be valid) - PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin)); - newPhi.addInput(first); - for (LoopEndNode end : loopBegin.orderedLoopEnds()) { - newPhi.addInput(phi.valueAt(end)); - } - peel.putDuplicatedNode(phi, newPhi); - newPhis.add(newPhi); - for (Node usage : phi.usages().snapshot()) { - if (peel.getDuplicatedNode(usage) != null) { // patch only usages that should use the new phi ie usages that were peeled - usage.replaceFirstInput(phi, newPhi); - } - } - } - // check new phis to see if they have as input some old phis, replace those inputs with the new corresponding phis - for (PhiNode phi : newPhis) { - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode v = phi.valueAt(i); - if (loopBegin.isPhiAtMerge(v)) { - PhiNode newV = peel.getDuplicatedNode((PhiNode) v); - if (newV != null) { - phi.setValueAt(i, newV); - } - } - } - } - } - - /** - * Gets the corresponding value in this fragment. - * - * @param b original value - * @return corresponding value in the peel - */ - private ValueNode prim(ValueNode b) { - assert isDuplicate(); - LoopBeginNode loopBegin = original().loop().loopBegin(); - if (loopBegin.isPhiAtMerge(b)) { - PhiNode phi = (PhiNode) b; - return phi.valueAt(loopBegin.forwardEnd()); - } else if (nodesReady) { - ValueNode v = getDuplicatedNode(b); - if (v == null) { - return b; - } - return v; - } else { - return b; - } - } - - private BeginNode mergeEnds() { - assert isDuplicate(); - List endsToMerge = new LinkedList<>(); - Map reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits - LoopBeginNode loopBegin = original().loop().loopBegin(); - for (LoopEndNode le : loopBegin.loopEnds()) { - EndNode duplicate = getDuplicatedNode(le); - if (duplicate != null) { - endsToMerge.add(duplicate); - reverseEnds.put(duplicate, le); - } - } - mergedInitializers = new IdentityHashMap<>(); - BeginNode newExit; - StructuredGraph graph = graph(); - if (endsToMerge.size() == 1) { - EndNode end = endsToMerge.get(0); - assert end.usages().count() == 0; - newExit = graph.add(new BeginNode()); - end.replaceAtPredecessor(newExit); - end.safeDelete(); - } else { - assert endsToMerge.size() > 1; - MergeNode newExitMerge = graph.add(new MergeNode()); - newExit = newExitMerge; - FrameState state = loopBegin.stateAfter(); - FrameState duplicateState = null; - if (state != null) { - duplicateState = state.duplicateWithVirtualState(); - newExitMerge.setStateAfter(duplicateState); - } - for (EndNode end : endsToMerge) { - newExitMerge.addForwardEnd(end); - } - - for (final PhiNode phi : loopBegin.phis().snapshot()) { - final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge)); - for (EndNode end : newExitMerge.forwardEnds()) { - LoopEndNode loopEnd = reverseEnds.get(end); - ValueNode prim = prim(phi.valueAt(loopEnd)); - assert prim != null; - firstPhi.addInput(prim); - } - ValueNode initializer = firstPhi; - if (duplicateState != null) { - // fix the merge's state after - duplicateState.applyToNonVirtual(new NodeClosure() { - @Override - public void apply(Node from, ValueNode node) { - if (node == phi) { - from.replaceFirstInput(phi, firstPhi); - } - } - }); - } - mergedInitializers.put(phi, initializer); - } - } - return newExit; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInsideBefore.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentInsideBefore extends LoopFragmentInside { - private final FixedNode point; - - public LoopFragmentInsideBefore(LoopEx loop, FixedNode point) { - super(loop); - this.point = point; - } - - // duplicates lazily - public LoopFragmentInsideBefore(LoopFragmentInsideBefore original) { - super(original); - this.point = original.point(); - } - - public FixedNode point() { - return point; - } - - @Override - public LoopFragmentInsideBefore duplicate() { - return new LoopFragmentInsideBefore(this); - } - - @Override - public NodeIterable nodes() { - // TODO Auto-generated method stub - return null; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentInsideFrom.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentInsideFrom extends LoopFragmentInside { - private final FixedNode point; - - public LoopFragmentInsideFrom(LoopEx loop, FixedNode point) { - super(loop); - this.point = point; - } - - // duplicates lazily - public LoopFragmentInsideFrom(LoopFragmentInsideFrom original) { - super(original); - this.point = original.point(); - } - - public FixedNode point() { - return point; - } - - @Override - public LoopFragmentInsideFrom duplicate() { - return new LoopFragmentInsideFrom(this); - } - - @Override - public NodeIterable nodes() { - // TODO Auto-generated method stub - return null; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopFragmentWhole.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - - -public class LoopFragmentWhole extends LoopFragment { - - public LoopFragmentWhole(LoopEx loop) { - super(loop); - } - - public LoopFragmentWhole(LoopFragmentWhole original) { - super(null, original); - } - - @Override - public LoopFragmentWhole duplicate() { - LoopFragmentWhole loopFragmentWhole = new LoopFragmentWhole(this); - loopFragmentWhole.reify(); - return loopFragmentWhole; - } - - private void reify() { - assert this.isDuplicate(); - - patchNodes(null); - - mergeEarlyExits(); - } - - @Override - public NodeIterable nodes() { - if (nodes == null) { - Loop lirLoop = loop().lirLoop(); - nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.blocks), LoopFragment.toHirBlocks(lirLoop.exits)); - } - return nodes; - } - - @Override - protected DuplicationReplacement getDuplicationReplacement() { - final FixedNode entry = loop().entryPoint(); - final Graph graph = this.graph(); - return new DuplicationReplacement() { - @Override - public Node replacement(Node o) { - if (o == entry) { - return graph.add(new EndNode()); - } - return o; - } - }; - } - - public FixedNode entryPoint() { - if (isDuplicate()) { - LoopBeginNode newLoopBegin = getDuplicatedNode(original().loop().loopBegin()); - return newLoopBegin.forwardEnd(); - } - return loop().entryPoint(); - } - - @Override - protected void finishDuplication() { - // TODO (gd) ? - } - - @Override - public void insertBefore(LoopEx loop) { - // TODO Auto-generated method stub - - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopPolicies.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopPolicies.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - - -public abstract class LoopPolicies { - private LoopPolicies() { - // does not need to be instantiated - } - - // TODO (gd) change when inversion is available - public static boolean shouldPeel(LoopEx loop) { - LoopBeginNode loopBegin = loop.loopBegin(); - double entryProbability = loopBegin.forwardEnd().probability(); - return entryProbability > GraalOptions.MinimumPeelProbability && loop.size() + loopBegin.graph().getNodeCount() < GraalOptions.MaximumDesiredSize; - } - - public static boolean shouldFullUnroll(LoopEx loop) { - if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) { - return false; - } - CountedLoopInfo counted = loop.counted(); - long exactTrips = counted.constantMaxTripCount(); - int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? GraalOptions.ExactFullUnrollMaxNodes : GraalOptions.FullUnrollMaxNodes; - maxNodes = Math.min(maxNodes, GraalOptions.MaximumDesiredSize - loop.loopBegin().graph().getNodeCount()); - int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count()); - return size * exactTrips <= maxNodes; - } - - public static boolean shouldTryUnswitch(LoopEx loop) { - return loop.loopBegin().unswitches() <= GraalOptions.LoopMaxUnswitch; - } - - public static boolean shouldUnswitch(LoopEx loop, IfNode ifNode) { - Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(ifNode).getPostdominator(); - BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null; - int inTrueBranch = loop.nodesInLoopFrom(ifNode.trueSuccessor(), postDom).cardinality(); - int inFalseBranch = loop.nodesInLoopFrom(ifNode.falseSuccessor(), postDom).cardinality(); - int loopTotal = loop.size(); - int netDiff = loopTotal - (inTrueBranch + inFalseBranch); - double uncertainty = (0.5 - Math.abs(ifNode.probability(IfNode.TRUE_EDGE) - 0.5)) * 2; - int maxDiff = GraalOptions.LoopUnswitchMaxIncrease + (int) (GraalOptions.LoopUnswitchUncertaintyBoost * loop.loopBegin().loopFrequency() * uncertainty); - Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of if", loop, ifNode, netDiff, maxDiff, (double) (inTrueBranch + inFalseBranch) / loopTotal * 100); - return netDiff <= maxDiff; - } - - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformations.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformations.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; - - -public abstract class LoopTransformations { - private static final int UNROLL_LIMIT = GraalOptions.FullUnrollMaxNodes * 2; - private static final SimplifierTool simplifier = new SimplifierTool() { - @Override - public TargetDescription target() { - return null; - } - @Override - public CodeCacheProvider runtime() { - return null; - } - @Override - public boolean isImmutable(Constant objectConstant) { - return false; - } - @Override - public Assumptions assumptions() { - return null; - } - @Override - public void deleteBranch(FixedNode branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); - } - @Override - public void addToWorkList(Node node) { - } - }; - - private LoopTransformations() { - // does not need to be instantiated - } - - public static void invert(LoopEx loop, FixedNode point) { - LoopFragmentInsideBefore head = loop.insideBefore(point); - LoopFragmentInsideBefore duplicate = head.duplicate(); - head.disconnect(); - head.insertBefore(loop); - duplicate.appendInside(loop); - } - - public static void peel(LoopEx loop) { - loop.inside().duplicate().insertBefore(loop); - } - - public static void fullUnroll(LoopEx loop, MetaAccessProvider runtime) { - //assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count - int iterations = 0; - LoopBeginNode loopBegin = loop.loopBegin(); - StructuredGraph graph = (StructuredGraph) loopBegin.graph(); - while (!loopBegin.isDeleted()) { - int mark = graph.getMark(); - peel(loop); - new CanonicalizerPhase(null, runtime, null, mark, null).apply(graph); - if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > GraalOptions.MaximumDesiredSize * 3) { - throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); - } - } - } - - public static void unswitch(LoopEx loop, IfNode ifNode) { - // duplicate will be true case, original will be false case - loop.loopBegin().incUnswitches(); - LoopFragmentWhole originalLoop = loop.whole(); - LoopFragmentWhole duplicateLoop = originalLoop.duplicate(); - StructuredGraph graph = (StructuredGraph) ifNode.graph(); - BeginNode tempBegin = graph.add(new BeginNode()); - originalLoop.entryPoint().replaceAtPredecessor(tempBegin); - double takenProbability = ifNode.probability(ifNode.blockSuccessorIndex(ifNode.trueSuccessor())); - IfNode newIf = graph.add(new IfNode(ifNode.compare(), duplicateLoop.entryPoint(), originalLoop.entryPoint(), takenProbability, ifNode.leafGraphId())); - tempBegin.setNext(newIf); - ifNode.setCompare(graph.unique(ConstantNode.forBoolean(false, graph))); - IfNode duplicateIf = duplicateLoop.getDuplicatedNode(ifNode); - duplicateIf.setCompare(graph.unique(ConstantNode.forBoolean(true, graph))); - ifNode.simplify(simplifier); - duplicateIf.simplify(simplifier); - // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) - } - - public static void unroll(LoopEx loop, int factor) { - assert loop.isCounted(); - if (factor > 0) { - throw new UnsupportedOperationException(); - } - // TODO (gd) implement counted loop - LoopFragmentWhole main = loop.whole(); - LoopFragmentWhole prologue = main.duplicate(); - prologue.insertBefore(loop); - //CountedLoopBeginNode counted = prologue.countedLoop(); - //StructuredGraph graph = (StructuredGraph) counted.graph(); - //ValueNode tripCountPrologue = counted.tripCount(); - //ValueNode tripCountMain = counted.tripCount(); - //graph.replaceFloating(tripCountPrologue, "tripCountPrologue % factor"); - //graph.replaceFloating(tripCountMain, "tripCountMain - (tripCountPrologue % factor)"); - LoopFragmentInside inside = loop.inside(); - for (int i = 0; i < factor; i++) { - inside.duplicate().appendInside(loop); - } - } - - public static IfNode findUnswitchableIf(LoopEx loop) { - for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) { - if (loop.isOutsideLoop(ifNode.compare())) { - return ifNode; - } - } - return null; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopsData.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopsData.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.loop; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.compiler.loop.InductionVariable.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; - -public class LoopsData { - private Map lirLoopToEx = new IdentityHashMap<>(); - private Map loopBeginToEx = new IdentityHashMap<>(); - private ControlFlowGraph cfg; - - public LoopsData(final StructuredGraph graph) { - - cfg = Debug.scope("ControlFlowGraph", new Callable() { - @Override - public ControlFlowGraph call() throws Exception { - return ControlFlowGraph.compute(graph, true, true, true, true); - } - }); - for (Loop lirLoop : cfg.getLoops()) { - LoopEx ex = new LoopEx(lirLoop, this); - lirLoopToEx.put(lirLoop, ex); - loopBeginToEx.put(ex.loopBegin(), ex); - } - } - - public LoopEx loop(Loop lirLoop) { - return lirLoopToEx.get(lirLoop); - } - - public LoopEx loop(LoopBeginNode loopBegin) { - return loopBeginToEx.get(loopBegin); - } - - public Collection loops() { - return lirLoopToEx.values(); - } - - public List outterFirst() { - ArrayList loops = new ArrayList<>(loops()); - Collections.sort(loops, new Comparator() { - @Override - public int compare(LoopEx o1, LoopEx o2) { - return o1.lirLoop().depth - o2.lirLoop().depth; - } - }); - return loops; - } - - public Collection countedLoops() { - List counted = new LinkedList<>(); - for (LoopEx loop : loops()) { - if (loop.isCounted()) { - counted.add(loop); - } - } - return counted; - } - - public void detectedCountedLoops() { - for (LoopEx loop : loops()) { - InductionVariables ivs = new InductionVariables(loop); - LoopBeginNode loopBegin = loop.loopBegin(); - FixedNode next = loopBegin.next(); - if (next instanceof IfNode) { - IfNode ifNode = (IfNode) next; - boolean negated = false; - if (!loopBegin.isLoopExit(ifNode.falseSuccessor())) { - if (!loopBegin.isLoopExit(ifNode.trueSuccessor())) { - continue; - } - negated = true; - } - BooleanNode ifTest = ifNode.compare(); - if (!(ifTest instanceof IntegerLessThanNode)) { - if (ifTest instanceof IntegerBelowThanNode) { - Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin); - } - continue; - } - IntegerLessThanNode lessThan = (IntegerLessThanNode) ifTest; - Condition condition = null; - InductionVariable iv = null; - ValueNode limit = null; - if (loop.isOutsideLoop(lessThan.x())) { - iv = ivs.get(lessThan.y()); - if (iv != null) { - condition = lessThan.condition().mirror(); - limit = lessThan.x(); - } - } else if (loop.isOutsideLoop(lessThan.y())) { - iv = ivs.get(lessThan.x()); - if (iv != null) { - condition = lessThan.condition(); - limit = lessThan.y(); - } - } - if (condition == null) { - continue; - } - if (negated) { - condition = condition.negate(); - } - boolean oneOff = false; - switch (condition) { - case LE: - oneOff = true; // fall through - case LT: - if (iv.direction() != Direction.Up) { - continue; - } - break; - case GE: - oneOff = true; // fall through - case GT: - if (iv.direction() != Direction.Down) { - continue; - } - break; - default: throw GraalInternalError.shouldNotReachHere(); - } - loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff)); - } - } - } - - public ControlFlowGraph controlFlowGraph() { - return cfg; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/package-info.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/package-info.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/package-info.java Mon Sep 17 16:08:46 2012 +0200 @@ -22,9 +22,7 @@ */ /** - * The top-level package in Graal containing options, metrics, timers and the main compiler class - * {@link com.oracle.graal.compiler.GraalCompiler}. - * - * Graal is intended to be used with multiple JVM's so makes no use of or reference to classes for a specific JVM. + * The top-level package in Graal containing the main compiler class {@link com.oracle.graal.compiler.GraalCompiler}. */ package com.oracle.graal.compiler; + diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BoxingEliminationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; - -public class BoxingEliminationPhase extends Phase { - - private int virtualIds = Integer.MIN_VALUE; - - @Override - protected void run(StructuredGraph graph) { - if (graph.getNodes(UnboxNode.class).isNotEmpty()) { - - Map phiReplacements = new HashMap<>(); - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - tryEliminate(graph, unboxNode, phiReplacements); - } - - new DeadCodeEliminationPhase().apply(graph); - - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - tryEliminate(boxNode); - } - } - } - - private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map phiReplacements) { - ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == unboxNode.kind(); - unboxNode.replaceAtUsages(unboxedValue); - graph.removeFixed(unboxNode); - } - } - - private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map phiReplacements) { - if (!phiReplacements.containsKey(phiNode)) { - PhiNode result = null; - ObjectStamp stamp = phiNode.objectStamp(); - if (stamp.nonNull() && stamp.isExactType()) { - ResolvedJavaType type = stamp.type(); - if (type != null && type.toJava() == kind.toBoxedJavaClass()) { - StructuredGraph graph = (StructuredGraph) phiNode.graph(); - result = graph.add(new PhiNode(kind, phiNode.merge())); - phiReplacements.put(phiNode, result); - virtualizeUsages(phiNode, result, type); - int i = 0; - for (ValueNode n : phiNode.values()) { - ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == kind; - result.addInput(unboxedValue); - } else { - UnboxNode unboxNode = graph.add(new UnboxNode(kind, n)); - FixedNode pred = phiNode.merge().phiPredecessorAt(i); - graph.addBeforeFixed(pred, unboxNode); - result.addInput(unboxNode); - } - ++i; - } - } - } - } - return phiReplacements.get(phiNode); - } - - private ValueNode unboxedValue(ValueNode n, Kind kind, Map phiReplacements) { - if (n instanceof BoxNode) { - BoxNode boxNode = (BoxNode) n; - return boxNode.source(); - } else if (n instanceof PhiNode) { - PhiNode phiNode = (PhiNode) n; - return getReplacementPhi(phiNode, kind, phiReplacements); - } else { - return null; - } - } - - private void tryEliminate(BoxNode boxNode) { - - assert boxNode.objectStamp().isExactType(); - virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type()); - - if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { - // Elimination failed, because boxing object escapes. - return; - } - - FrameState stateAfter = boxNode.stateAfter(); - boxNode.setStateAfter(null); - stateAfter.safeDelete(); - - ((StructuredGraph) boxNode.graph()).removeFixed(boxNode); - } - - private void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType) { - ValueNode virtualValueNode = null; - VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { - if (virtualValueNode == null) { - virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(virtualIds++, exactType, replacement)); - } - n.replaceFirstInput(boxNode, virtualObjectNode); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Graph.InputChangedListener; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class CanonicalizerPhase extends Phase { - private static final int MAX_ITERATION_PER_NODE = 10; - private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes"); - private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes"); - private static final DebugMetric METRIC_INFER_STAMP_CALLED = Debug.metric("InferStampCalled"); - private static final DebugMetric METRIC_STAMP_CHANGED = Debug.metric("StampChanged"); - private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes"); - public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); - - private final int newNodesMark; - private final TargetDescription target; - private final Assumptions assumptions; - private final MetaAccessProvider runtime; - private final IsImmutablePredicate immutabilityPredicate; - private final Iterable initWorkingSet; - - private NodeWorkList workList; - private Tool tool; - private List snapshotTemp; - - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this(target, runtime, assumptions, null, 0, null); - } - - /** - * @param target - * @param runtime - * @param assumptions - * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap - * @param immutabilityPredicate - */ - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, IsImmutablePredicate immutabilityPredicate) { - this(target, runtime, assumptions, workingSet, 0, immutabilityPredicate); - } - - /** - * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by - * this mark are processed otherwise all nodes in the graph are processed - */ - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { - this(target, runtime, assumptions, null, newNodesMark, immutabilityPredicate); - } - - private CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, IsImmutablePredicate immutabilityPredicate) { - this.newNodesMark = newNodesMark; - this.target = target; - this.assumptions = assumptions; - this.runtime = runtime; - this.immutabilityPredicate = immutabilityPredicate; - this.initWorkingSet = workingSet; - this.snapshotTemp = new ArrayList<>(); - } - - @Override - protected void run(StructuredGraph graph) { - if (initWorkingSet == null) { - workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); - if (newNodesMark > 0) { - workList.addAll(graph.getNewNodes(newNodesMark)); - } - } else { - workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); - workList.addAll(initWorkingSet); - } - tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate); - processWorkSet(graph); - } - - public interface IsImmutablePredicate { - /** - * Determines if a given constant is an object/array whose current - * fields/elements will never change. - */ - boolean apply(Constant constant); - } - - private void processWorkSet(StructuredGraph graph) { - graph.trackInputChange(new InputChangedListener() { - @Override - public void inputChanged(Node node) { - workList.addAgain(node); - } - }); - - for (Node n : workList) { - processNode(n, graph); - } - - graph.stopTrackingInputChange(); - } - - private void processNode(Node node, StructuredGraph graph) { - if (node.isAlive()) { - METRIC_PROCESSED_NODES.increment(); - - if (tryGlobalValueNumbering(node, graph)) { - return; - } - int mark = graph.getMark(); - if (!tryKillUnused(node)) { - node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); - if (!tryCanonicalize(node, graph, tool)) { - tryInferStamp(node, graph); - } else { - for (Node in : snapshotTemp) { - if (in.isAlive() && in.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(in); - } - } - } - snapshotTemp.clear(); - } - - for (Node newNode : graph.getNewNodes(mark)) { - workList.add(newNode); - } - } - } - - private static boolean tryKillUnused(Node node) { - if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(node); - return true; - } - return false; - } - - public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { - if (node.getNodeClass().valueNumberable()) { - Node newNode = graph.findDuplicate(node); - if (newNode != null) { - assert !(node instanceof FixedNode || newNode instanceof FixedNode); - node.replaceAtUsages(newNode); - node.safeDelete(); - METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment(); - Debug.log("GVN applied and new node is %1s", newNode); - return true; - } - } - return false; - } - - public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) { - if (node instanceof Canonicalizable) { - assert !(node instanceof Simplifiable); - METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); - return Debug.scope("CanonicalizeNode", node, new Callable(){ - public Boolean call() { - ValueNode canonical = ((Canonicalizable) node).canonical(tool); -// cases: original node: -// |Floating|Fixed-unconnected|Fixed-connected| -// -------------------------------------------- -// null| 1 | X | 3 | -// -------------------------------------------- -// Floating| 2 | X | 4 | -// canonical node: -------------------------------------------- -// Fixed-unconnected| X | X | 5 | -// -------------------------------------------- -// Fixed-connected| 2 | X | 6 | -// -------------------------------------------- -// X: must not happen (checked with assertions) - if (canonical == node) { - Debug.log("Canonicalizer: work on %s", node); - return false; - } else { - Debug.log("Canonicalizer: replacing %s with %s", node, canonical); - METRIC_CANONICALIZED_NODES.increment(); - if (node instanceof FloatingNode) { - if (canonical == null) { - // case 1 - graph.removeFloating((FloatingNode) node); - } else { - // case 2 - assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical + - " : replacement should be floating or fixed and connected"; - graph.replaceFloating((FloatingNode) node, canonical); - } - } else { - assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")"; - if (canonical == null) { - // case 3 - graph.removeFixed((FixedWithNextNode) node); - } else if (canonical instanceof FloatingNode) { - // case 4 - graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical); - } else { - assert canonical instanceof FixedNode; - if (canonical.predecessor() == null) { - assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors"; - // case 5 - graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical); - } else { - assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors"; - // case 6 - node.replaceAtUsages(canonical); - graph.removeFixed((FixedWithNextNode) node); - } - } - } - return true; - } - } - }); - } else if (node instanceof Simplifiable) { - Debug.log("Canonicalizer: simplifying %s", node); - METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); - ((Simplifiable) node).simplify(tool); - } - return node.isDeleted(); - } - - /** - * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has - * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp - * now describes a constant integer value, in which case the node is replaced with a constant. - */ - private void tryInferStamp(Node node, StructuredGraph graph) { - if (node.isAlive() && node instanceof ValueNode) { - ValueNode valueNode = (ValueNode) node; - METRIC_INFER_STAMP_CALLED.increment(); - if (valueNode.inferStamp()) { - METRIC_STAMP_CHANGED.increment(); - if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) { - ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph); - Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement); - valueNode.replaceAtUsages(replacement); - } else { - for (Node usage : valueNode.usages()) { - workList.addAgain(usage); - } - } - } - } - } - - private static final class Tool implements SimplifierTool { - - private final NodeWorkList nodeWorkSet; - private final MetaAccessProvider runtime; - private final TargetDescription target; - private final Assumptions assumptions; - private final IsImmutablePredicate immutabilityPredicate; - - public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions, IsImmutablePredicate immutabilityPredicate) { - this.nodeWorkSet = nodeWorkSet; - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.immutabilityPredicate = immutabilityPredicate; - } - - @Override - public void deleteBranch(FixedNode branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); - } - - /** - * @return the current target or {@code null} if no target is available in the current context. - */ - @Override - public TargetDescription target() { - return target; - } - - /** - * @return an object that can be used for recording assumptions or {@code null} if assumptions are not allowed in the current context. - */ - @Override - public Assumptions assumptions() { - return assumptions; - } - - @Override - public MetaAccessProvider runtime() { - return runtime; - } - - @Override - public void addToWorkList(Node node) { - nodeWorkSet.add(node); - } - - @Override - public boolean isImmutable(Constant objectConstant) { - return immutabilityPredicate != null && immutabilityPredicate.apply(objectConstant); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +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.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class CheckCastEliminationPhase extends Phase { - - private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered"); - private static final DebugMetric metricIsTypeRegistered = Debug.metric("IsTypeRegistered"); - private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered"); - private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved"); - private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved"); - private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved"); - private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved"); - private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced"); - - private StructuredGraph graph; - - @Override - protected void run(StructuredGraph inputGraph) { - graph = inputGraph; - new EliminateCheckCasts(graph.start(), new State()).apply(); - } - - public static class State implements MergeableState { - - private IdentityHashMap knownTypes; - private HashSet knownNotNull; - private HashSet knownNull; - private IdentityHashMap trueConditions; - private IdentityHashMap falseConditions; - - public State() { - this.knownTypes = new IdentityHashMap<>(); - this.knownNotNull = new HashSet<>(); - this.knownNull = new HashSet<>(); - this.trueConditions = new IdentityHashMap<>(); - this.falseConditions = new IdentityHashMap<>(); - } - - public State(State other) { - this.knownTypes = new IdentityHashMap<>(other.knownTypes); - this.knownNotNull = new HashSet<>(other.knownNotNull); - this.knownNull = new HashSet<>(other.knownNull); - this.trueConditions = new IdentityHashMap<>(other.trueConditions); - this.falseConditions = new IdentityHashMap<>(other.falseConditions); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - IdentityHashMap newKnownTypes = new IdentityHashMap<>(); - HashSet newKnownNotNull = new HashSet<>(); - HashSet newKnownNull = new HashSet<>(); - IdentityHashMap newTrueConditions = new IdentityHashMap<>(); - IdentityHashMap newFalseConditions = new IdentityHashMap<>(); - - for (Map.Entry entry : knownTypes.entrySet()) { - ValueNode node = entry.getKey(); - ResolvedJavaType type = entry.getValue(); - - for (State other : withStates) { - ResolvedJavaType otherType = other.getNodeType(node); - type = widen(type, otherType); - if (type == null) { - break; - } - } - if (type == null && type != node.objectStamp().type()) { - newKnownTypes.put(node, type); - } - } - for (ValueNode node : knownNotNull) { - boolean notNull = true; - for (State other : withStates) { - if (!other.knownNotNull.contains(node)) { - notNull = false; - break; - } - } - if (notNull) { - newKnownNotNull.add(node); - } - } - for (ValueNode node : knownNull) { - boolean nul = true; - for (State other : withStates) { - if (!other.knownNull.contains(node)) { - nul = false; - break; - } - } - if (nul) { - newKnownNull.add(node); - } - } - for (Map.Entry entry : trueConditions.entrySet()) { - BooleanNode check = entry.getKey(); - ValueNode guard = entry.getValue(); - - for (State other : withStates) { - ValueNode otherGuard = other.trueConditions.get(check); - if (otherGuard == null) { - guard = null; - break; - } - if (otherGuard != guard) { - guard = merge; - } - } - if (guard != null) { - newTrueConditions.put(check, guard); - } - } - for (Map.Entry entry : falseConditions.entrySet()) { - BooleanNode check = entry.getKey(); - ValueNode guard = entry.getValue(); - - for (State other : withStates) { - ValueNode otherGuard = other.falseConditions.get(check); - if (otherGuard == null) { - guard = null; - break; - } - if (otherGuard != guard) { - guard = merge; - } - } - if (guard != null) { - newFalseConditions.put(check, guard); - } - } - - /* - // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values) - if (!(merge instanceof LoopBeginNode)) { - for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value && phi.kind() == Kind.Object) { - ValueNode firstValue = phi.valueAt(0); - ResolvedJavaType type = getNodeType(firstValue); - boolean notNull = knownNotNull.contains(firstValue); - boolean nul = knownNull.contains(firstValue); - - for (int i = 0; i < withStates.size(); i++) { - State otherState = withStates.get(i); - ValueNode value = phi.valueAt(i + 1); - ResolvedJavaType otherType = otherState.getNodeType(value); - type = widen(type, otherType); - notNull &= otherState.knownNotNull.contains(value); - nul &= otherState.knownNull.contains(value); - } - if (type == null && type != phi.declaredType()) { - newKnownTypes.put(phi, type); - } - if (notNull) { - newKnownNotNull.add(phi); - } - if (nul) { - newKnownNull.add(phi); - } - } - } - } - */ - this.knownTypes = newKnownTypes; - this.knownNotNull = newKnownNotNull; - this.knownNull = newKnownNull; - this.trueConditions = newTrueConditions; - this.falseConditions = newFalseConditions; - return true; - } - - public ResolvedJavaType getNodeType(ValueNode node) { - ResolvedJavaType result = knownTypes.get(node); - return result == null ? node.objectStamp().type() : result; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - } - - @Override - public void afterSplit(FixedNode node) { - } - - @Override - public State clone() { - return new State(this); - } - } - - public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { - if (a == null || b == null) { - return null; - } else if (a == b) { - return a; - } else { - return a.leastCommonAncestor(b); - } - } - - public static ResolvedJavaType tighten(ResolvedJavaType a, ResolvedJavaType b) { - if (a == null) { - return b; - } else if (b == null) { - return a; - } else if (a == b) { - return a; - } else if (a.isSubtypeOf(b)) { - return a; - } else if (b.isSubtypeOf(a)) { - return b; - } else { - return a; - } - } - - public class EliminateCheckCasts extends PostOrderNodeIterator { - private BeginNode lastBegin = null; - - public EliminateCheckCasts(FixedNode start, State initialState) { - super(start, initialState); - } - - @Override - protected void node(FixedNode node) { - if (node instanceof BeginNode) { - BeginNode begin = (BeginNode) node; - lastBegin = begin; - Node pred = node.predecessor(); - if (pred != null && pred instanceof IfNode) { - IfNode ifNode = (IfNode) pred; - if (!(ifNode.compare() instanceof ConstantNode)) { - boolean isTrue = (node == ifNode.trueSuccessor()); - if (isTrue) { - state.trueConditions.put(ifNode.compare(), begin); - } else { - state.falseConditions.put(ifNode.compare(), begin); - } - } - if (ifNode.compare() instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare(); - if ((node == ifNode.trueSuccessor())) { - ValueNode object = instanceOf.object(); - state.knownNotNull.add(object); - state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object))); - metricInstanceOfRegistered.increment(); - } - } else if (ifNode.compare() instanceof IsNullNode) { - IsNullNode nullCheck = (IsNullNode) ifNode.compare(); - boolean isNull = (node == ifNode.trueSuccessor()); - if (isNull) { - state.knownNull.add(nullCheck.object()); - } else { - state.knownNotNull.add(nullCheck.object()); - } - metricNullCheckRegistered.increment(); - } else if (ifNode.compare() instanceof IsTypeNode) { - IsTypeNode isType = (IsTypeNode) ifNode.compare(); - if (isType.objectClass() instanceof ReadHubNode && (node == ifNode.trueSuccessor())) { - ReadHubNode readHub = (ReadHubNode) isType.objectClass(); - ValueNode object = readHub.object(); - state.knownNotNull.add(object); - state.knownTypes.put(object, tighten(isType.type(), state.getNodeType(object))); - metricIsTypeRegistered.increment(); - } - } - } - for (GuardNode guard : begin.guards().snapshot()) { - BooleanNode condition = guard.condition(); - ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition); - if (existingGuards != null) { - guard.replaceAtUsages(existingGuards); - GraphUtil.killWithUnusedFloatingInputs(guard); - metricGuardsReplaced.increment(); - } else { - boolean removeCheck = false; - if (condition instanceof IsNullNode) { - IsNullNode isNull = (IsNullNode) condition; - if (guard.negated() && state.knownNotNull.contains(isNull.object())) { - removeCheck = true; - } else if (!guard.negated() && state.knownNull.contains(isNull.object())) { - removeCheck = true; - } - if (removeCheck) { - metricNullCheckGuardRemoved.increment(); - } - } - if (removeCheck) { - guard.replaceAtUsages(begin); - GraphUtil.killWithUnusedFloatingInputs(guard); - } else { - if (guard.negated()) { - state.falseConditions.put(condition, guard); - } else { - state.trueConditions.put(condition, guard); - } - } - } - } - } else if (node instanceof CheckCastNode) { - CheckCastNode checkCast = (CheckCastNode) node; - ResolvedJavaType type = state.getNodeType(checkCast.object()); - if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) { - PiNode piNode; - boolean nonNull = state.knownNotNull.contains(checkCast.object()); - piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, nonNull ? StampFactory.declaredNonNull(type) : StampFactory.declared(type))); - checkCast.replaceAtUsages(piNode); - graph.removeFixed(checkCast); - metricCheckCastRemoved.increment(); - } - } else if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - BooleanNode replaceWith = null; - BooleanNode compare = ifNode.compare(); - - if (state.trueConditions.containsKey(compare)) { - replaceWith = ConstantNode.forBoolean(true, graph); - } else if (state.falseConditions.containsKey(compare)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } else { - if (compare instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) compare; - ValueNode object = instanceOf.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } else if (state.knownNotNull.contains(object)) { - ResolvedJavaType type = state.getNodeType(object); - if (type != null && type.isSubtypeOf(instanceOf.targetClass())) { - replaceWith = ConstantNode.forBoolean(true, graph); - } - } - if (replaceWith != null) { - metricInstanceOfRemoved.increment(); - } - } else if (compare instanceof IsNullNode) { - IsNullNode isNull = (IsNullNode) compare; - ValueNode object = isNull.object(); - if (state.knownNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(true, graph); - } else if (state.knownNotNull.contains(object)) { - replaceWith = ConstantNode.forBoolean(false, graph); - } - if (replaceWith != null) { - metricNullCheckRemoved.increment(); - } - } - } - if (replaceWith != null) { - ifNode.setCompare(replaceWith); - if (compare.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(compare); - } - } - } - } - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ComputeProbabilityPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - -public class ComputeProbabilityPhase extends Phase { - private static final double EPSILON = 1d / Integer.MAX_VALUE; - - /* - * The computation of absolute probabilities works in three steps: - * - * - The first step, "PropagateProbability", traverses the graph in post order (merges after their ends, ...) and keeps track of the "probability state". - * Whenever it encounters a ControlSplit it uses the split's probability information to divide the probability upon the successors. - * Whenever it encounters an Invoke it assumes that the exception edge is unlikely and propagates the whole probability to the normal successor. - * Whenever it encounters a Merge it sums up the probability of all predecessors. - * It also maintains a set of active loops (whose LoopBegin has been visited) and builds def/use information for the second step. - * - * - The third step propagates the loop frequencies and multiplies each FixedNode's probability with its loop frequency. - * - * TODO: add exception probability information to Invokes - */ - - @Override - protected void run(StructuredGraph graph) { - new PropagateProbability(graph.start()).apply(); - Debug.dump(graph, "After PropagateProbability"); - computeLoopFactors(); - Debug.dump(graph, "After computeLoopFactors"); - new PropagateLoopFrequency(graph.start()).apply(); - - if (GraalOptions.LoopFrequencyPropagationPolicy < 0) { - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - BitSet visitedBlocks = new BitSet(cfg.getBlocks().length); - for (Loop loop : cfg.getLoops()) { - if (loop.parent == null) { - correctLoopFrequencies(loop, 1, visitedBlocks); - } - } - } - } - - private void correctLoopFrequencies(Loop loop, double parentFrequency, BitSet visitedBlocks) { - LoopBeginNode loopBegin = ((LoopBeginNode) loop.header.getBeginNode()); - double frequency = parentFrequency * loopBegin.loopFrequency(); - for (Loop child : loop.children) { - correctLoopFrequencies(child, frequency, visitedBlocks); - } - - double factor = getCorrectionFactor(loopBegin.probability(), frequency); - for (Block block : loop.blocks) { - int blockId = block.getId(); - if (!visitedBlocks.get(blockId)) { - visitedBlocks.set(blockId); - - FixedNode node = block.getBeginNode(); - while (node != block.getEndNode()) { - node.setProbability(node.probability() * factor); - node = ((FixedWithNextNode) node).next(); - } - node.setProbability(node.probability() * factor); - } - } - } - - private static double getCorrectionFactor(double probability, double frequency) { - switch (GraalOptions.LoopFrequencyPropagationPolicy) { - case -1: - return 1 / frequency; - case -2: - return (1 / frequency) * (Math.log(Math.E + frequency) - 1); - case -3: - double originalProbability = probability / frequency; - assert isRelativeProbability(originalProbability); - return (1 / frequency) * Math.max(1, Math.pow(originalProbability, 1.5) * Math.log10(frequency)); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - private void computeLoopFactors() { - for (LoopInfo info : loopInfos) { - double frequency = info.loopFrequency(); - assert frequency != -1; - } - } - - private static boolean isRelativeProbability(double prob) { - // 1.01 to allow for some rounding errors - return prob >= 0 && prob <= 1.01; - } - - public static class LoopInfo { - public final LoopBeginNode loopBegin; - - public final NodeMap> requires; - - private double loopFrequency = -1; - public boolean ended = false; - - public LoopInfo(LoopBeginNode loopBegin) { - this.loopBegin = loopBegin; - this.requires = loopBegin.graph().createNodeMap(); - } - - public double loopFrequency() { - if (loopFrequency == -1 && ended) { - double backEdgeProb = 0.0; - for (LoopEndNode le : loopBegin.loopEnds()) { - double factor = 1; - Set requireds = requires.get(le); - for (LoopInfo required : requireds) { - double t = required.loopFrequency(); - if (t == -1) { - return -1; - } - factor *= t; - } - backEdgeProb += le.probability() * factor; - } - double d = loopBegin.probability() - backEdgeProb; - if (d < EPSILON) { - d = EPSILON; - } - loopFrequency = loopBegin.probability() / d; - loopBegin.setLoopFrequency(loopFrequency); - } - return loopFrequency; - } - } - - public Set loopInfos = new HashSet<>(); - public Map> mergeLoops = new IdentityHashMap<>(); - - private class Probability implements MergeableState { - public double probability; - public HashSet loops; - public LoopInfo loopInfo; - - public Probability(double probability, HashSet loops) { - this.probability = probability; - this.loops = new HashSet<>(4); - if (loops != null) { - this.loops.addAll(loops); - } - } - - @Override - public Probability clone() { - return new Probability(probability, loops); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - if (merge.forwardEndCount() > 1) { - HashSet intersection = new HashSet<>(loops); - for (Probability other : withStates) { - intersection.retainAll(other.loops); - } - for (LoopInfo info : loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - probability *= loopFrequency; - } - } - for (Probability other : withStates) { - double prob = other.probability; - for (LoopInfo info : other.loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - prob *= loopFrequency; - } - } - probability += prob; - } - loops = intersection; - mergeLoops.put(merge, new HashSet<>(intersection)); - assert isRelativeProbability(probability) : probability; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - loopInfo = new LoopInfo(loopBegin); - loopInfos.add(loopInfo); - loops.add(loopInfo); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - assert loopInfo != null; - List loopEnds = loopBegin.orderedLoopEnds(); - int i = 0; - for (Probability proba : loopEndStates) { - LoopEndNode loopEnd = loopEnds.get(i++); - Set requires = loopInfo.requires.get(loopEnd); - if (requires == null) { - requires = new HashSet<>(); - loopInfo.requires.set(loopEnd, requires); - } - for (LoopInfo innerLoop : proba.loops) { - if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) { - requires.add(innerLoop); - } - } - } - loopInfo.ended = true; - } - - @Override - public void afterSplit(FixedNode node) { - assert node.predecessor() != null; - Node pred = node.predecessor(); - if (pred instanceof Invoke) { - Invoke x = (Invoke) pred; - if (x.next() != node) { - probability = 0; - } - } else { - assert pred instanceof ControlSplitNode; - ControlSplitNode x = (ControlSplitNode) pred; - double sum = 0; - for (int i = 0; i < x.blockSuccessorCount(); i++) { - if (x.blockSuccessor(i) == node) { - sum += x.probability(i); - } - } - probability *= sum; - } - } - } - - private class PropagateProbability extends PostOrderNodeIterator { - - public PropagateProbability(FixedNode start) { - super(start, new Probability(1d, null)); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(state.probability); - } - } - - private class LoopCount implements MergeableState { - public double count; - - public LoopCount(double count) { - this.count = count; - } - - @Override - public LoopCount clone() { - return new LoopCount(count); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - assert merge.forwardEndCount() == withStates.size() + 1; - if (merge.forwardEndCount() > 1) { - Set loops = mergeLoops.get(merge); - assert loops != null; - double countProd = 1; - for (LoopInfo loop : loops) { - countProd *= loop.loopFrequency(); - } - count = countProd; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - count *= loopBegin.loopFrequency(); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - // nothing to do... - } - - @Override - public void afterSplit(FixedNode node) { - // nothing to do... - } - } - - private class PropagateLoopFrequency extends PostOrderNodeIterator { - - private final FrequencyPropagationPolicy policy; - - public PropagateLoopFrequency(FixedNode start) { - super(start, new LoopCount(1d)); - this.policy = createFrequencyPropagationPolicy(); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(policy.compute(node.probability(), state.count)); - } - - } - - private static FrequencyPropagationPolicy createFrequencyPropagationPolicy() { - switch (GraalOptions.LoopFrequencyPropagationPolicy) { - case -3: - case -2: - case -1: - case 0: - return new FullFrequencyPropagation(); - case 1: - return new NoFrequencyPropagation(); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - private interface FrequencyPropagationPolicy { - - double compute(double probability, double frequency); - } - - private static class FullFrequencyPropagation implements FrequencyPropagationPolicy { - - @Override - public double compute(double probability, double frequency) { - return probability * frequency; - } - } - - private static class NoFrequencyPropagation implements FrequencyPropagationPolicy { - - @Override - public double compute(double probability, double frequency) { - return probability; - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; - -public class ConvertDeoptimizeToGuardPhase extends Phase { - - private static BeginNode findBeginNode(Node startNode) { - Node n = startNode; - while (true) { - if (n instanceof BeginNode) { - return (BeginNode) n; - } else { - n = n.predecessor(); - } - } - } - - @Override - protected void run(final StructuredGraph graph) { - if (graph.getNodes(DeoptimizeNode.class).isEmpty()) { - return; - } - - for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) { - visitDeoptBegin(findBeginNode(d), d, graph); - } - - new DeadCodeEliminationPhase().apply(graph); - } - - private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) { - if (deoptBegin instanceof MergeNode) { - MergeNode mergeNode = (MergeNode) deoptBegin; - Debug.log("Visiting %s followed by %s", mergeNode, deopt); - List ends = mergeNode.forwardEnds().snapshot(); - for (EndNode end : ends) { - if (!end.isDeleted()) { - BeginNode beginNode = findBeginNode(end); - if (!(beginNode instanceof MergeNode)) { - visitDeoptBegin(beginNode, deopt, graph); - } - } - } - if (mergeNode.isDeleted()) { - if (!deopt.isDeleted()) { - Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt)); - visitDeoptBegin(findBeginNode(deopt), deopt, graph); - } - } - } else if (deoptBegin.predecessor() instanceof IfNode) { - IfNode ifNode = (IfNode) deoptBegin.predecessor(); - BeginNode otherBegin = ifNode.trueSuccessor(); - BooleanNode conditionNode = ifNode.compare(); - boolean negated = false; - if (deoptBegin == ifNode.trueSuccessor()) { - negated = true; - otherBegin = ifNode.falseSuccessor(); - } - 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, deopt.reason(), deopt.action(), negated, deopt.leafGraphId())); - otherBegin.replaceAtUsages(ifBlockBegin); - FixedNode next = otherBegin.next(); - otherBegin.setNext(null); - guard.setNext(next); - ifNode.replaceAtPredecessor(guard); - GraphUtil.killCFG(ifNode); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertUnreachedToGuardPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +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.compiler.phases; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.util.*; - - -public class ConvertUnreachedToGuardPhase extends Phase { - private OptimisticOptimizations opt; - - public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) { - this.opt = opt; - } - - @Override - protected void run(StructuredGraph graph) { - if (!opt.removeNeverExecutedCode()) { - return; - } - for (Node node : graph.getNodes()) { - if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - BeginNode insertGuard = null; - BeginNode delete = null; - boolean inverted = false; - if (ifNode.probability(IfNode.TRUE_EDGE) == 0) { - insertGuard = ifNode.falseSuccessor(); - delete = ifNode.trueSuccessor(); - inverted = true; - } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) { - insertGuard = ifNode.trueSuccessor(); - delete = ifNode.falseSuccessor(); - } - if (insertGuard != null) { - GuardNode guard = graph.unique(new GuardNode(ifNode.compare(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId())); - graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard))); - GraphUtil.killCFG(delete); - graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE); - } - } - } - - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +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.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; - -/** - * This phase culls unused FrameStates from the graph. - * It does a post order iteration over the graph, and - */ -public class CullFrameStatesPhase extends Phase { - - private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled"); - private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed"); - - @Override - protected void run(StructuredGraph graph) { - new CullFrameStates(graph.start(), new State(null)).apply(); - } - - public static class State implements MergeableState { - - private FrameState lastFrameState; - - public State(FrameState lastFrameState) { - this.lastFrameState = lastFrameState; - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - FrameState stateAfter = merge.stateAfter(); - if (merge instanceof LoopBeginNode) { - if (stateAfter != null) { - lastFrameState = stateAfter; - } - return true; - } - metricMergesTraversed.increment(); - if (stateAfter != null) { - for (State other : withStates) { - if (other.lastFrameState != lastFrameState) { - lastFrameState = stateAfter; - return true; - } - } - metricFrameStatesCulled.increment(); - merge.setStateAfter(null); - if (stateAfter.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfter); - } - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - } - - @Override - public void afterSplit(FixedNode node) { - } - - @Override - public State clone() { - return new State(lastFrameState); - } - } - - public static class CullFrameStates extends PostOrderNodeIterator { - - public CullFrameStates(FixedNode start, State initialState) { - super(start, initialState); - } - - @Override - protected void node(FixedNode node) { - if (node instanceof StateSplit) { - FrameState stateAfter = ((StateSplit) node).stateAfter(); - if (stateAfter != null) { - state.lastFrameState = stateAfter; - } - } - } - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/DeadCodeEliminationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public class DeadCodeEliminationPhase extends Phase { - - // Metrics - private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); - - private NodeFlood flood; - - @Override - protected void run(StructuredGraph graph) { - this.flood = graph.createNodeFlood(); - - flood.add(graph.start()); - iterateSuccessors(); - disconnectCFGNodes(graph); - iterateInputs(graph); - deleteNodes(graph); - - // remove chained Merges - for (MergeNode merge : graph.getNodes(MergeNode.class)) { - if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) { - graph.reduceTrivialMerge(merge); - } - } - } - - private void iterateSuccessors() { - for (Node current : flood) { - if (current instanceof EndNode) { - EndNode end = (EndNode) current; - flood.add(end.merge()); - } else { - for (Node successor : current.successors()) { - flood.add(successor); - } - } - } - } - - private void disconnectCFGNodes(StructuredGraph graph) { - for (EndNode node : graph.getNodes(EndNode.class)) { - if (!flood.isMarked(node)) { - MergeNode merge = node.merge(); - if (merge != null && flood.isMarked(merge)) { - // We are a dead end node leading to a live merge. - merge.removeEnd(node); - } - } - } - for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) { - if (flood.isMarked(loop)) { - boolean reachable = false; - for (LoopEndNode end : loop.loopEnds()) { - if (flood.isMarked(end)) { - reachable = true; - break; - } - } - if (!reachable) { - Debug.log("Removing loop with unreachable end: %s", loop); - for (LoopEndNode end : loop.loopEnds().snapshot()) { - loop.removeEnd(end); - } - graph.reduceDegenerateLoopBegin(loop); - } - } - } - } - - private void deleteNodes(StructuredGraph graph) { - for (Node node : graph.getNodes()) { - if (!flood.isMarked(node)) { - node.clearInputs(); - node.clearSuccessors(); - } - } - for (Node node : graph.getNodes()) { - if (!flood.isMarked(node)) { - metricNodesRemoved.increment(); - node.safeDelete(); - } - } - } - - private void iterateInputs(StructuredGraph graph) { - for (Node node : graph.getNodes()) { - if (node instanceof LocalNode) { - flood.add(node); - } - if (flood.isMarked(node)) { - for (Node input : node.inputs()) { - flood.add(input); - } - } - } - for (Node current : flood) { - for (Node input : current.inputs()) { - flood.add(input); - } - } - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ExpandBoxingNodesPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; - -public class ExpandBoxingNodesPhase extends Phase { - - private final BoxingMethodPool pool; - - public ExpandBoxingNodesPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - boxNode.expand(pool); - } - - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - unboxNode.expand(pool); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.extended.*; - -public class FloatingReadPhase extends Phase { - - private IdentityHashMap> loopEndStatesMap; - - private static class LoopState { - public LoopBeginNode loopBegin; - public MemoryMap state; - public IdentityHashMap loopPhiLocations = new IdentityHashMap<>(); - public ValueNode loopEntryAnyLocation; - public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) { - this.loopBegin = loopBegin; - this.state = state; - this.loopEntryAnyLocation = loopEntryAnyLocation; - } - - @Override - public String toString() { - return "State@" + loopBegin; - } - } - - private class MemoryMap implements MergeableState { - private IdentityHashMap lastMemorySnapshot; - private LinkedList loops; - - public MemoryMap(MemoryMap memoryMap) { - lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - loops = new LinkedList<>(memoryMap.loops); - } - - public MemoryMap() { - lastMemorySnapshot = new IdentityHashMap<>(); - loops = new LinkedList<>(); - } - - @Override - public String toString() { - return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString(); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - if (withStates.size() == 0) { - return true; - } - - int minLoops = loops.size(); - for (MemoryMap other : withStates) { - int otherLoops = other.loops.size(); - if (otherLoops < minLoops) { - minLoops = otherLoops; - } - } - while (loops.size() > minLoops) { - loops.pop(); - } - for (MemoryMap other : withStates) { - while (other.loops.size() > minLoops) { - other.loops.pop(); - } - } - - Set keys = new HashSet<>(); - for (Object key : lastMemorySnapshot.keySet()) { - keys.add(key); - } - for (MemoryMap other : withStates) { - assert other.loops.size() == loops.size(); - assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin; - for (Object key : other.lastMemorySnapshot.keySet()) { - keys.add(key); - } - } - - for (Object key : keys) { - ValueNode merged = lastMemorySnapshot.get(key); - if (merged == null) { - merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - Iterator it = withStates.iterator(); - int i = 1; - boolean isPhi = false; - while (it.hasNext()) { - MemoryMap other = it.next(); - ValueNode otherValue = other.lastMemorySnapshot.get(key); - if (otherValue == null) { - otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - if (isPhi) { - ((PhiNode) merged).addInput(otherValue); - } else if (merged != otherValue) { - PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); - for (int j = 0; j < i; j++) { - phi.addInput(merged); - } - phi.addInput(otherValue); - merged = phi; - isPhi = true; - lastMemorySnapshot.put(key, phi); - } - i++; - } - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION)); - for (Map.Entry entry : lastMemorySnapshot.entrySet()) { - PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin)); - phi.addInput(entry.getValue()); - entry.setValue(phi); - loopState.loopPhiLocations.put(phi, entry.getKey()); - } - loops.push(loopState); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - loopEndStatesMap.put(loopBegin, loopEndStates); - tryFinishLoopPhis(this, loopBegin); - } - - @Override - public void afterSplit(FixedNode node) { - // nothing - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); - } - } - - @Override - protected void run(StructuredGraph graph) { - loopEndStatesMap = new IdentityHashMap<>(); - new PostOrderNodeIterator(graph.start(), new MemoryMap()) { - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private void processNode(FixedNode node, MemoryMap state) { - if (node instanceof ReadNode) { - processRead((ReadNode) node, state); - } else if (node instanceof WriteNode) { - processWrite((WriteNode) node, state); - } else if (node instanceof MemoryCheckpoint) { - processCheckpoint((MemoryCheckpoint) node, state); - } else if (node instanceof LoopExitNode) { - processLoopExit((LoopExitNode) node, state); - } - } - - private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { - processAnyLocationWrite((ValueNode) checkpoint, state); - } - - private static void processWrite(WriteNode writeNode, MemoryMap state) { - if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) { - processAnyLocationWrite(writeNode, state); - } - state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode); - } - - private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(modifiying); - } - state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying); - state.loops.clear(); - } - - private void processRead(ReadNode readNode, MemoryMap state) { - StructuredGraph graph = (StructuredGraph) readNode.graph(); - assert readNode.getNullCheck() == false; - Object locationIdentity = readNode.location().locationIdentity(); - ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity); - FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); - floatingRead.setNullCheck(readNode.getNullCheck()); - ValueAnchorNode anchor = null; - for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { - if (anchor == null) { - anchor = graph.add(new ValueAnchorNode()); - } - anchor.addAnchoredNode(guard); - } - if (anchor != null) { - graph.addAfterFixed(readNode, anchor); - } - graph.replaceFixedWithFloating(readNode, floatingRead); - } - - private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) { - ValueNode lastLocationAccess; - if (locationIdentity == LocationNode.FINAL_LOCATION) { - lastLocationAccess = null; - } else { - lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity); - if (lastLocationAccess == null) { - LoopState lastLoop = state.loops.peek(); - if (lastLoop == null) { - lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } else { - ValueNode phiInit; - if (state.loops.size() > 1) { - phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity); - } else { - phiInit = lastLoop.loopEntryAnyLocation; - } - PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin)); - phi.addInput(phiInit); - lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi); - lastLoop.loopPhiLocations.put(phi, locationIdentity); - tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin); - lastLocationAccess = phi; - } - state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess); - } - } - return lastLocationAccess; - } - - private static void processLoopExit(LoopExitNode exit, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory))); - } - if (!state.loops.isEmpty()) { - state.loops.pop(); - } - } - - private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) { - List loopEndStates = loopEndStatesMap.get(loopBegin); - if (loopEndStates == null) { - return; - } - LoopState loopState = loopMemory.loops.get(0); - int i = 0; - while (loopState.loopBegin != loopBegin) { - loopState = loopMemory.loops.get(++i); - } - for (PhiNode phi : loopBegin.phis()) { - if (phi.type() == PhiType.Memory && phi.valueCount() == 1) { - Object location = loopState.loopPhiLocations.get(phi); - assert location != null : "unknown location for " + phi; - for (MemoryMap endState : loopEndStates) { - ValueNode otherNode = endState.lastMemorySnapshot.get(location); - if (otherNode == null) { - otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - phi.addInput(otherNode); - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GlobalValueNumberingPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -public class GlobalValueNumberingPhase extends Phase { - - public static final DebugMetric metricGlobalValueNumberingHits = Debug.metric("GlobalValueNumberingHits"); - - @Override - protected void run(StructuredGraph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - for (Node n : graph.getNodes()) { - apply(n, visited, graph); - } - } - - private void apply(Node n, NodeBitMap visited, StructuredGraph compilerGraph) { - if (!visited.isMarked(n)) { - visited.mark(n); - for (Node input : n.inputs()) { - apply(input, visited, compilerGraph); - } - if (n.getNodeClass().valueNumberable()) { - Node newNode = compilerGraph.findDuplicate(n); - if (newNode != null) { - assert !(n instanceof FixedNode || newNode instanceof FixedNode); - n.replaceAtUsages(newNode); - n.safeDelete(); - metricGlobalValueNumberingHits.increment(); - Debug.log("GVN applied and new node is %1s", newNode); - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IdentifyBoxingPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; - -public class IdentifyBoxingPhase extends Phase { - - private final BoxingMethodPool pool; - - public IdentifyBoxingPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - tryIntrinsify(invoke); - } - } - - public void tryIntrinsify(Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - return; - } - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (pool.isSpecialMethod(targetMethod)) { - assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument"; - Kind returnKind = callTarget.returnKind(); - ValueNode sourceValue = callTarget.arguments().get(0); - - // Check whether this is a boxing or an unboxing. - Node newNode = null; - if (returnKind == Kind.Object) { - // We have a boxing method here. - assert Modifier.isStatic(targetMethod.accessFlags()) : "boxing method must be static"; - Kind sourceKind = targetMethod.signature().argumentKindAt(0); - newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.holder(), sourceKind, invoke.bci())); - } else { - // We have an unboxing method here. - assert !Modifier.isStatic(targetMethod.accessFlags()) : "unboxing method must be an instance method"; - newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue)); - } - - // Intrinsify the invoke to the special node. - invoke.intrinsify(newNode); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.compiler.util.InliningUtil.InlineInfo; -import com.oracle.graal.compiler.util.InliningUtil.InliningCallback; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.internal.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - - -public class InliningPhase extends Phase implements InliningCallback { - /* - * - Detect method which only call another method with some parameters set to constants: void foo(a) -> void foo(a, b) -> void foo(a, b, c) ... - * These should not be taken into account when determining inlining depth. - * - honor the result of overrideInliningDecision(0, caller, invoke.bci, method, true); - */ - - private final TargetDescription target; - private final GraalCodeCacheProvider runtime; - - private final Collection hints; - - private final PriorityQueue inlineCandidates = new PriorityQueue<>(); - private Assumptions assumptions; - - private final PhasePlan plan; - private final GraphCache cache; - 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(TargetDescription target, GraalCodeCacheProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { - this.target = target; - this.runtime = runtime; - this.hints = hints; - this.assumptions = assumptions; - this.cache = cache; - this.plan = plan; - this.optimisticOpts = optimisticOpts; - this.weightComputationPolicy = createWeightComputationPolicy(); - this.inliningPolicy = createInliningPolicy(); - } - - @SuppressWarnings("unchecked") - @Override - protected void run(final StructuredGraph graph) { - graph.createNodeMap(); - - if (hints != null) { - scanInvokes((Iterable) Util.uncheckedCast(this.hints)); - } else { - scanInvokes(graph.getNodes(InvokeNode.class)); - scanInvokes(graph.getNodes(InvokeWithExceptionNode.class)); - } - - while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) { - InlineInfo candidate = inlineCandidates.remove(); - if (!candidate.invoke.node().isAlive()) { - continue; - } - // refresh infos - final InlineInfo info = InliningUtil.getInlineInfo(candidate.invoke, candidate.level, runtime, assumptions, this, optimisticOpts); - - boolean inline = Debug.scope("InliningDecisions", new Callable() { - @Override - public Boolean call() throws Exception { - return info != null && inliningPolicy.isWorthInlining(graph, info); - } - }); - - if (inline) { - int mark = graph.getMark(); - Iterable newNodes = null; - try { - info.inline(graph, runtime, this); - Debug.dump(graph, "after %s", info); - newNodes = graph.getNewNodes(mark); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph); - } -// if (GraalOptions.Intrinsify) { -// new IntrinsificationPhase(runtime).apply(graph); -// } - metricInliningPerformed.increment(); - } catch (BailoutException bailout) { - // TODO determine if we should really bail out of the whole compilation. - throw bailout; - } catch (AssertionError e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (RuntimeException e) { - throw new GraalInternalError(e).addContext(info.toString()); - } catch (GraalInternalError e) { - throw e.addContext(info.toString()); - } - - if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) { - scanInvokes(newNodes); - } - } - } - - if (GraalOptions.Debug && graph.getNodeCount() >= GraalOptions.MaximumDesiredSize) { - Debug.scope("InliningDecisions", new Runnable() { - public void run() { - for (InlineInfo info : inlineCandidates) { - Debug.log("not inlining %s because inlining cut off by MaximumDesiredSize", InliningUtil.methodName(info)); - } - } - }); - - metricInliningStoppedByMaxDesiredSize.increment(); - } - } - - private void scanInvokes(final Iterable nodes) { - Debug.scope("InliningDecisions", new Runnable() { - public void run() { - for (Node node : nodes) { - if (node != null) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - scanInvoke(invoke); - } - for (Node usage : node.usages().filterInterface(Invoke.class).snapshot()) { - scanInvoke((Invoke) usage); - } - } - } - } - }); - } - - private void scanInvoke(Invoke invoke) { - InlineInfo info = InliningUtil.getInlineInfo(invoke, computeInliningLevel(invoke), runtime, assumptions, this, optimisticOpts); - if (info != null) { - metricInliningConsidered.increment(); - inlineCandidates.add(info); - } - } - - public static final Map parsedMethods = new HashMap<>(); - - - - private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); - - @Override - public StructuredGraph buildGraph(final ResolvedJavaMethod method) { - metricInliningRuns.increment(); - if (GraalOptions.CacheGraphs && cache != null) { - StructuredGraph cachedGraph = cache.get(method); - if (cachedGraph != null) { - return cachedGraph; - } - } - StructuredGraph newGraph = new StructuredGraph(method); - if (plan != null) { - plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); - } - assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(newGraph); - new ComputeProbabilityPhase().apply(newGraph); - } - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); - } - if (GraalOptions.Intrinsify) { - new IntrinsificationPhase(runtime).apply(newGraph); - } - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(newGraph); - } - if (GraalOptions.CacheGraphs && cache != null) { - cache.put(newGraph); - } - return newGraph; - } - - @Override - public double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke) { - boolean preferred = hints != null && hints.contains(invoke); - return weightComputationPolicy.computeWeight(caller, method, invoke, preferred); - } - - public static int graphComplexity(StructuredGraph graph) { - int result = 0; - for (Node node : graph.getNodes()) { - if (node instanceof ConstantNode || node instanceof LocalNode || node instanceof BeginNode || node instanceof ReturnNode || node instanceof UnwindNode) { - result += 0; - } else if (node instanceof PhiNode) { - result += 5; - } else if (node instanceof MergeNode || node instanceof Invoke || node instanceof LoopEndNode || node instanceof EndNode) { - result += 0; - } else if (node instanceof ControlSplitNode) { - result += ((ControlSplitNode) node).blockSuccessorCount(); - } else { - result += 1; - } - } - return Math.max(1, result); - } - - - @Override - public void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { - assumptions.recordConcreteMethod(method, context, impl); - } - - @Override - public void recordMethodContentsAssumption(ResolvedJavaMethod method) { - if (assumptions != null) { - assumptions.recordMethodContents(method); - } - } - - private static int computeInliningLevel(Invoke invoke) { - int count = -1; - FrameState curState = invoke.stateAfter(); - while (curState != null) { - count++; - curState = curState.outerFrameState(); - } - return count; - } - - private static InliningPolicy createInliningPolicy() { - switch(GraalOptions.InliningPolicy) { - case 0: return new WeightBasedInliningPolicy(); - case 1: return new C1StaticSizeBasedInliningPolicy(); - case 2: return new MinimumCodeSizeBasedInliningPolicy(); - case 3: return new DynamicSizeBasedInliningPolicy(); - case 4: return new GreedySizeBasedInliningPolicy(); - default: - GraalInternalError.shouldNotReachHere(); - return null; - } - } - - private static WeightComputationPolicy createWeightComputationPolicy() { - switch(GraalOptions.WeightComputationPolicy) { - case 0: throw new GraalInternalError("removed because of invokation counter changes"); - case 1: return new BytecodeSizeBasedWeightComputationPolicy(); - case 2: return new ComplexityBasedWeightComputationPolicy(); - default: - GraalInternalError.shouldNotReachHere(); - return null; - } - } - - private interface InliningPolicy { - boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info); - } - - private static class WeightBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - if (!checkCompiledCodeSize(info)) { - return false; - } - - double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp; - if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) { - Debug.log("not inlining %s (cut off by weight %e)", InliningUtil.methodName(info), info.weight); - return false; - } - - Debug.log("inlining %s (weight %f): %s", InliningUtil.methodName(info), info.weight); - return true; - } - } - - private static class C1StaticSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize); - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class MinimumCodeSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double inlineWeight = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); - double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight; - maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class DynamicSizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()) + Math.log10(Math.max(1, info.invoke.probability() - GraalOptions.ProbabilityCapForInlining + 1)); - double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize; - maxSize = maxSize + maxSize * inlineBoost; - maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize)); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static class GreedySizeBasedInliningPolicy implements InliningPolicy { - @Override - public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; - if (!checkCompiledCodeSize(info)) { - return false; - } - - double maxSize = GraalOptions.MaximumGreedyInlineSize; - if (GraalOptions.InliningBonusPerTransferredValue != 0) { - Signature signature = info.invoke.methodCallTarget().targetMethod().signature(); - int transferredValues = signature.argumentCount(!Modifier.isStatic(info.invoke.methodCallTarget().targetMethod().accessFlags())); - if (signature.returnKind() != Kind.Void) { - transferredValues++; - } - maxSize += transferredValues * GraalOptions.InliningBonusPerTransferredValue; - } - - double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); - maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio; - maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize); - - return decideSizeBasedInlining(info, maxSize); - } - } - - private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) { - boolean success = info.weight <= maxSize; - if (DebugScope.getInstance().isLogEnabled()) { - String formatterString = success ? "inlining %s (size %f <= %f)" : "not inlining %s (too large %f > %f)"; - Debug.log(formatterString, InliningUtil.methodName(info), info.weight, maxSize); - } - return success; - } - - private static boolean checkCompiledCodeSize(InlineInfo info) { - if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) { - Debug.log("not inlining %s (CompiledCodeSize %d > %d)", InliningUtil.methodName(info), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize); - return false; - } - return true; - } - - - private interface WeightComputationPolicy { - double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke); - } - - private static class BytecodeSizeBasedWeightComputationPolicy implements WeightComputationPolicy { - @Override - public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { - double codeSize = method.codeSize(); - if (preferredInvoke) { - codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; - } - return codeSize; - } - } - - private static class ComplexityBasedWeightComputationPolicy implements WeightComputationPolicy { - @Override - public double computeWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke, boolean preferredInvoke) { - double complexity = method.compilationComplexity(); - if (preferredInvoke) { - complexity = complexity / GraalOptions.BoostInliningForEscapeAnalysis; - } - return complexity; - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +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.compiler.phases; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class InsertStateAfterPlaceholderPhase extends Phase { - - private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable, Canonicalizable { - public PlaceholderNode() { - super(StampFactory.forVoid()); - } - - @Override - public void generate(LIRGeneratorTool gen) { - // nothing to do - } - - @Override - public boolean hasSideEffect() { - return false; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (stateAfter() == null) { - return null; - } - return this; - } - } - - @Override - protected void run(StructuredGraph graph) { - for (ReturnNode ret : graph.getNodes(ReturnNode.class)) { - PlaceholderNode p = graph.add(new PlaceholderNode()); - p.setStateAfter(graph.add(new FrameState(FrameState.AFTER_BCI))); - graph.addBeforeFixed(ret, p); - } - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IntrinsificationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.util.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; - -public class IntrinsificationPhase extends Phase { - - private final GraalCodeCacheProvider runtime; - - public IntrinsificationPhase(GraalCodeCacheProvider runtime) { - this.runtime = runtime; - } - - @Override - protected void run(StructuredGraph graph) { - for (InvokeNode invoke : graph.getNodes(InvokeNode.class)) { - tryIntrinsify(invoke, runtime); - } - for (InvokeWithExceptionNode invoke : graph.getNodes(InvokeWithExceptionNode.class)) { - tryIntrinsify(invoke, runtime); - } - } - - public static boolean canIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - return getIntrinsicGraph(invoke, target, runtime) != null; - } - - private static void tryIntrinsify(Invoke invoke, GraalCodeCacheProvider runtime) { - if (invoke.callTarget() instanceof MethodCallTargetNode && invoke.methodCallTarget().targetMethod() != null) { - tryIntrinsify(invoke, invoke.methodCallTarget().targetMethod(), runtime); - } - } - - private static void tryIntrinsify(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - StructuredGraph intrinsicGraph = getIntrinsicGraph(invoke, target, runtime); - if (intrinsicGraph != null) { - Debug.log(" > Intrinsify %s", target); - InliningUtil.inline(invoke, intrinsicGraph, true); - } - } - - private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { - StructuredGraph intrinsicGraph = (StructuredGraph) target.compilerStorage().get(Graph.class); - if (intrinsicGraph == null) { - // TODO remove once all intrinsics are available via compilerStorage - intrinsicGraph = runtime.intrinsicGraph(invoke.stateAfter().method(), invoke.bci(), target, invoke.callTarget().arguments()); - } - return intrinsicGraph; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/IterativeCheckCastEliminationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +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.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Graph.InputChangedListener; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - - -public class IterativeCheckCastEliminationPhase extends Phase { - private final TargetDescription target; - private final MetaAccessProvider runtime; - private final Assumptions assumptions; - - public IterativeCheckCastEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this.target = target; - this.runtime = runtime; - this.assumptions = assumptions; - } - - @Override - protected void run(StructuredGraph graph) { - Set canonicalizationRoots = new HashSet<>(); - CheckCastEliminationPhase eliminate = new CheckCastEliminationPhase(); - Listener listener = new Listener(canonicalizationRoots); - while (true) { - graph.trackInputChange(listener); - eliminate.apply(graph); - graph.stopTrackingInputChange(); - if (canonicalizationRoots.isEmpty()) { - break; - } - new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph); - canonicalizationRoots.clear(); - } - } - - private static class Listener implements InputChangedListener { - private final Set canonicalizationRoots; - public Listener(Set canonicalizationRoots) { - this.canonicalizationRoots = canonicalizationRoots; - } - @Override - public void inputChanged(Node node) { - canonicalizationRoots.add(node); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopFullUnrollPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopFullUnrollPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - - -public class LoopFullUnrollPhase extends Phase { - private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls"); - private final GraalCodeCacheProvider runtime; - - public LoopFullUnrollPhase(GraalCodeCacheProvider runtime) { - this.runtime = runtime; - } - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - boolean peeled; - do { - peeled = false; - final LoopsData dataCounted = new LoopsData(graph); - dataCounted.detectedCountedLoops(); - for (LoopEx loop : dataCounted.countedLoops()) { - if (LoopPolicies.shouldFullUnroll(loop)) { - Debug.log("FullUnroll %s", loop); - LoopTransformations.fullUnroll(loop, runtime); - FULLY_UNROLLED_LOOPS.increment(); - Debug.dump(graph, "After fullUnroll %s", loop); - peeled = true; - break; - } - } - } while(peeled); - } - } - -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopSafepointInsertionPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.util.*; - -/** - * Adds safepoints to loops. - */ -public class LoopSafepointInsertionPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - nextLoop: - for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) { - if (!loopEnd.canSafepoint()) { - continue; - } - if (GraalOptions.OptSafepointElimination) { - // We 'eliminate' safepoints by simply never placing them into loops that have at least one call - NodeIterable it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin()); - for (FixedNode n : it) { - if (n instanceof Invoke) { - continue nextLoop; - } - } - } - SafepointNode safepoint = graph.add(new SafepointNode()); - graph.addBeforeFixed(loopEnd, safepoint); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformHighPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformHighPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public class LoopTransformHighPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (GraalOptions.LoopPeeling) { - LoopsData data = new LoopsData(graph); - for (LoopEx loop : data.outterFirst()) { - if (LoopPolicies.shouldPeel(loop)) { - Debug.log("Peeling %s", loop); - LoopTransformations.peel(loop); - Debug.dump(graph, "After peeling %s", loop); - } - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformLowPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformLowPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.loop.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public class LoopTransformLowPhase extends Phase { - private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - if (GraalOptions.ReassociateInvariants) { - final LoopsData dataReassociate = new LoopsData(graph); - Debug.scope("ReassociateInvariants", new Runnable() { - @Override - public void run() { - for (LoopEx loop : dataReassociate.loops()) { - loop.reassociateInvariants(); - } - } - }); - } - if (GraalOptions.LoopUnswitch) { - boolean unswitched; - do { - unswitched = false; - final LoopsData dataUnswitch = new LoopsData(graph); - for (LoopEx loop : dataUnswitch.loops()) { - if (LoopPolicies.shouldTryUnswitch(loop)) { - IfNode ifNode = LoopTransformations.findUnswitchableIf(loop); - if (ifNode != null && LoopPolicies.shouldUnswitch(loop, ifNode)) { - Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(0), ifNode.probability(1)); - LoopTransformations.unswitch(loop, ifNode); - UNSWITCHED.increment(); - Debug.dump(graph, "After unswitch %s", loop); - unswitched = true; - break; - } - } - } - } while(unswitched); - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.schedule.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; - -/** - * Processes all {@link Lowerable} nodes to do their lowering. - */ -public class LoweringPhase extends Phase { - - final class LoweringToolImpl implements LoweringTool { - - final FixedNode guardAnchor; - final NodeBitMap activeGuards; - FixedWithNextNode lastFixedNode; - - public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards) { - this.guardAnchor = guardAnchor; - this.activeGuards = activeGuards; - } - - @Override - public GraalCodeCacheProvider getRuntime() { - return runtime; - } - - @Override - public ValueNode createNullCheckGuard(ValueNode object, long leafGraphId) { - return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, leafGraphId); - } - - @Override - public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, long leafGraphId) { - return createGuard(condition, deoptReason, action, false, leafGraphId); - } - - @Override - public Assumptions assumptions() { - return assumptions; - } - - @Override - public ValueNode createGuard(BooleanNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, long leafGraphId) { - if (GraalOptions.OptEliminateGuards) { - for (Node usage : condition.usages()) { - if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { - return (ValueNode) usage; - } - } - } - GuardNode newGuard = guardAnchor.graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, leafGraphId)); - if (GraalOptions.OptEliminateGuards) { - activeGuards.grow(); - activeGuards.mark(newGuard); - } - return newGuard; - } - - public FixedWithNextNode lastFixedNode() { - return lastFixedNode; - } - } - - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; - - public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { - this.runtime = runtime; - this.assumptions = assumptions; - } - - private static boolean containsLowerable(NodeIterable nodes) { - for (Node n : nodes) { - if (n instanceof Lowerable) { - return true; - } - } - return false; - } - - @Override - protected void run(final StructuredGraph graph) { - int i = 0; - NodeBitMap processed = graph.createNodeBitMap(); - while (true) { - int mark = graph.getMark(); - final SchedulePhase schedule = new SchedulePhase(); - schedule.apply(graph, false); - - processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); - Debug.dump(graph, "Lowering iteration %d", i++); - new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph); - - if (!containsLowerable(graph.getNewNodes(mark))) { - // No new lowerable nodes - done! - break; - } - assert graph.verify(); - processed.grow(); - } - } - - private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) { - - FixedNode anchor = parentAnchor; - if (anchor == null) { - anchor = block.getBeginNode(); - } - process(block, activeGuards, anchor, schedule, processed); - - // Process always reached block first. - Block alwaysReachedBlock = block.getPostdominator(); - if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) { - processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed); - } - - // Now go for the other dominators. - for (Block dominated : block.getDominated()) { - if (dominated != alwaysReachedBlock) { - assert dominated.getDominator() == block; - processBlock(dominated, activeGuards, null, schedule, processed); - } - } - - if (parentAnchor == null && GraalOptions.OptEliminateGuards) { - for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { - activeGuards.clear(guard); - } - } - } - - private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) { - - final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards); - - // Lower the instructions of this block. - List nodes = schedule.nodesFor(b); - - for (Node node : nodes) { - FixedNode lastFixedNext = null; - if (node instanceof FixedWithNextNode) { - FixedWithNextNode fixed = (FixedWithNextNode) node; - lastFixedNext = fixed.next(); - loweringTool.lastFixedNode = fixed; - } - - if (node.isAlive() && !processed.isMarked(node)) { - processed.mark(node); - if (node instanceof Lowerable) { - ((Lowerable) node).lower(loweringTool); - } - } - - if (loweringTool.lastFixedNode == node && !node.isAlive()) { - if (lastFixedNext == null) { - loweringTool.lastFixedNode = null; - } else { - Node prev = lastFixedNext.predecessor(); - if (prev != node && prev instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) prev; - } else if (lastFixedNext instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext; - } else { - loweringTool.lastFixedNode = null; - } - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/Phase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/Phase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; - -public abstract class Phase { - - private String name; - private static final DebugMetric metricPhaseRuns = Debug.metric("Runs"); - protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes"); - - protected Phase() { - this.name = this.getClass().getSimpleName(); - if (name.endsWith("Phase")) { - name = name.substring(0, name.length() - "Phase".length()); - } - } - - protected Phase(String name) { - this.name = name; - } - - protected String getDetailedName() { - return getName(); - } - - public final void apply(final StructuredGraph graph) { - apply(graph, true); - } - - public final void apply(final StructuredGraph graph, final boolean dumpGraph) { - Debug.scope(name, this, new Runnable() { - public void run() { - Phase.this.run(graph); - metricPhaseRuns.increment(); - if (dumpGraph) { - Debug.dump(graph, "After phase %s", name); - } - assert graph.verify(); - } - }); - } - - public final String getName() { - return name; - } - - protected abstract void run(StructuredGraph graph); -} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.nodes.*; - -/** - * Tells the compiler about additional phases that need to be executed during compilation. - */ -public class PhasePlan { - /** - * The compilation is split into the following sections: - * ======================================================================== - * Period 1: High-level nodes. (Graph building) - * ======================================================================== - * Runtime-specific lowering. - * ======================================================================== - * Period 2: Mid-level nodes. (Memory dependence graph) - * ======================================================================== - * Target-specific lowering, de-SSA. - * ======================================================================== - * Period 3: Low-level nodes. (Register allocation, code generation) - * ======================================================================== - * - * A compiler extension phase can chose to run at the end of periods 1-3. - */ - public static enum PhasePosition { - AFTER_PARSING, - HIGH_LEVEL, - MID_LEVEL, - LOW_LEVEL - } - - @SuppressWarnings("unchecked") - private final ArrayList[] phases = new ArrayList[PhasePosition.values().length]; - private final Set> disabledPhases = new HashSet<>(); - - public void addPhase(PhasePosition pos, Phase phase) { - if (phases[pos.ordinal()] == null) { - phases[pos.ordinal()] = new ArrayList<>(); - } - phases[pos.ordinal()].add(phase); - } - - public void runPhases(PhasePosition pos, StructuredGraph graph) { - if (phases[pos.ordinal()] != null) { - for (Phase p : phases[pos.ordinal()]) { - p.apply(graph); - } - } - } - - public void disablePhase(Class clazz) { - disabledPhases.add(clazz); - } - - public boolean isPhaseDisabled(Class clazz) { - return disabledPhases.contains(clazz); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/PhiStampPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/PhiStampPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import com.oracle.graal.nodes.*; - -public class PhiStampPhase extends Phase { - @Override - protected void run(StructuredGraph graph) { - // Infer phis stopping at loop phis. - for (PhiNode phi : graph.getNodes(PhiNode.class)) { - inferPhi(phi); - } - - // Start iterative inference for loop phis. - if (graph.hasLoops()) { - for (PhiNode phi : graph.getNodes(PhiNode.class)) { - if (phi.isLoopPhi()) { - iterativeInferPhi(phi); - } - } - } - } - - private void iterativeInferPhi(PhiNode phi) { - if (phi.inferPhiStamp()) { - for (PhiNode phiUsage : phi.usages().filter(PhiNode.class)) { - iterativeInferPhi(phiUsage); - } - } - } - - private void inferPhi(PhiNode phi) { - for (PhiNode phiInput : phi.values().filter(PhiNode.class)) { - if (!phiInput.isLoopPhi()) { - inferPhi(phiInput); - } - } - phi.inferPhiStamp(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.phases; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.extended.*; - -public class ReadEliminationPhase extends Phase { - private Queue newPhis; - - @Override - protected void run(StructuredGraph graph) { - newPhis = new LinkedList<>(); - for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) { - if (isReadEliminable(n)) { - NodeMap nodeMap = n.graph().createNodeMap(); - ValueNode value = getValue(n, n.lastLocationAccess(), nodeMap); - Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value); - graph.replaceFloating(n, value); - } - } - } - - private boolean isReadEliminable(FloatingReadNode n) { - return isWrites(n, n.lastLocationAccess(), n.graph().createNodeBitMap()); - } - - private boolean isWrites(FloatingReadNode n, Node lastLocationAccess, NodeBitMap visited) { - if (lastLocationAccess == null) { - return false; - } - if (visited.isMarked(lastLocationAccess)) { - return true; // dataflow loops must come from Phis assume them ok until proven wrong - } - if (lastLocationAccess instanceof ValueProxyNode) { - return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited); - } - if (lastLocationAccess instanceof WriteNode) { - WriteNode other = (WriteNode) lastLocationAccess; - return other.object() == n.object() && other.location() == n.location(); - } - if (lastLocationAccess instanceof PhiNode) { - visited.mark(lastLocationAccess); - for (ValueNode value : ((PhiNode) lastLocationAccess).values()) { - if (!isWrites(n, value, visited)) { - return false; - } - } - return true; - } - return false; - } - - private ValueNode getValue(FloatingReadNode n, Node lastLocationAccess, NodeMap nodeMap) { - ValueNode exisiting = nodeMap.get(lastLocationAccess); - if (exisiting != null) { - return exisiting; - } - if (lastLocationAccess instanceof ValueProxyNode) { - ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess; - ValueNode value = getValue(n, proxy.value(), nodeMap); - return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value)); - } - if (lastLocationAccess instanceof WriteNode) { - return ((WriteNode) lastLocationAccess).value(); - } - if (lastLocationAccess instanceof PhiNode) { - PhiNode phi = (PhiNode) lastLocationAccess; - PhiNode newPhi = phi.graph().add(new PhiNode(n.kind(), phi.merge())); - nodeMap.set(lastLocationAccess, newPhi); - for (ValueNode value : phi.values()) { - newPhi.addInput(getValue(n, value, nodeMap)); - } - newPhis.add(newPhi); - return newPhi; - } - throw GraalInternalError.shouldNotReachHere(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +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.compiler.phases; - -import com.oracle.graal.nodes.*; - -public class RemoveValueProxyPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) { - graph.replaceFloating(vpn, vpn.value()); - } - for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) { - FrameState stateAfter = exit.stateAfter(); - if (stateAfter != null) { - exit.setStateAfter(null); - if (stateAfter.usages().count() == 0) { - stateAfter.safeDelete(); - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/TailDuplicationPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,546 +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.compiler.phases; - -import java.util.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -/** - * This class is a phase that looks for opportunities for tail duplication. The static method - * {@link #tailDuplicate(MergeNode, TailDuplicationDecision, List)} can also be used to drive tail duplication from - * other places, e.g., inlining. - */ -public class TailDuplicationPhase extends Phase { - - /* - * Various metrics on the circumstances in which tail duplication was/wasn't performed. - */ - private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors"); - private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd"); - private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed"); - private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther"); - private static final DebugMetric metricDuplicationOtherPerformed = Debug.metric("DuplicationOtherPerformed"); - - /** - * This interface is used by tail duplication to let clients decide if tail duplication should be performed. - */ - public interface TailDuplicationDecision { - - /** - * Queries if tail duplication should be performed at the given merge. If this method returns true then the tail - * duplication will be performed, because all other checks have happened before. - * - * @param merge The merge at which tail duplication can be performed. - * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the duplicated set of nodes. - * @return true if the tail duplication should be performed, false otherwise. - */ - boolean doTransform(MergeNode merge, int fixedNodeCount); - } - - /** - * A tail duplication decision closure that employs the default algorithm: Check if there are any phis on the merge - * whose stamps improve and that have usages within the duplicated set of fixed nodes. - */ - public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() { - - public boolean doTransform(MergeNode merge, int fixedNodeCount) { - if (fixedNodeCount < GraalOptions.TailDuplicationTrivialSize) { - return true; - } - HashSet improvements = new HashSet<>(); - for (PhiNode phi : merge.phis()) { - Stamp phiStamp = phi.stamp(); - for (ValueNode input : phi.values()) { - if (!input.stamp().equals(phiStamp)) { - improvements.add(phi); - break; - } - } - } - if (improvements.isEmpty()) { - return false; - } - FixedNode current = merge; - int opportunities = 0; - while (current instanceof FixedWithNextNode) { - current = ((FixedWithNextNode) current).next(); - for (PhiNode phi : improvements) { - if (current.inputs().contains(phi)) { - opportunities++; - } - } - } - return opportunities > 0; - } - }; - - /** - * A tail duplication decision closure that always returns true. - */ - public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() { - - @Override - public boolean doTransform(MergeNode merge, int fixedNodeCount) { - return true; - } - }; - - @Override - protected void run(StructuredGraph graph) { - // A snapshot is taken here, so that new MergeNode instances aren't considered for tail duplication. - for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { - if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { - tailDuplicate(merge, DEFAULT_DECISION, null); - } - } - } - - /** - * This method attempts to duplicate the tail of the given merge. The merge must not be a {@link LoopBeginNode}. If - * the merge is eligible for duplication (at least one fixed node in its tail, no {@link MonitorEnterNode}/ - * {@link MonitorExitNode}, non-null {@link MergeNode#stateAfter()}) then the decision callback is used to determine - * whether the tail duplication should actually be performed. If replacements is non-null, then this list of - * {@link PiNode}s is used to replace one value per merge end. - * - * @param merge The merge whose tail should be duplicated. - * @param decision A callback that can make the final decision if tail duplication should occur or not. - * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its size needs to match the - * merge's end count. Each entry can either be null or a {@link PiNode}, and is used to replace - * {@link PiNode#object()} with the {@link PiNode} in the duplicated branch that corresponds to the - * entry. - */ - public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { - assert !(merge instanceof LoopBeginNode); - assert replacements == null || replacements.size() == merge.forwardEndCount(); - FixedNode fixed = merge; - int fixedCount = 0; - boolean containsMonitor = false; - while (fixed instanceof FixedWithNextNode) { - if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) { - containsMonitor = true; - } - fixed = ((FixedWithNextNode) fixed).next(); - fixedCount++; - } - if (containsMonitor) { - // cannot currently be handled - // TODO (ls) re-evaluate this limitation after changes to the lock representation and the LIR generator - metricDuplicationMonitors.increment(); - } else if (fixedCount > 1) { - if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) { - metricDuplicationEnd.increment(); - if (decision.doTransform(merge, fixedCount)) { - metricDuplicationEndPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); - } - } else if (merge.stateAfter() != null) { - metricDuplicationOther.increment(); - if (decision.doTransform(merge, fixedCount)) { - metricDuplicationOtherPerformed.increment(); - new DuplicationOperation(merge, replacements).duplicate(); - } - } - } - } - - /** - * This class encapsulates one tail duplication operation on a specific {@link MergeNode}. - */ - private static class DuplicationOperation { - - private final MergeNode merge; - private final StructuredGraph graph; - - private final HashMap bottomPhis = new HashMap<>(); - private final List replacements; - - /** - * Initializes the tail duplication operation without actually performing any work. - * - * @param merge The merge whose tail should be duplicated. - * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null, then the size of the - * list needs to match the number of end nodes at the merge. - */ - public DuplicationOperation(MergeNode merge, List replacements) { - this.merge = merge; - this.replacements = replacements; - this.graph = (StructuredGraph) merge.graph(); - } - - /** - * Performs the actual tail duplication: - *
    - *
  • Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an transfers all - * dependencies from the merge to this anchor.
  • - *
  • Determines the set of fixed nodes to be duplicated.
  • - *
  • Creates the new merge at the bottom of the duplicated area.
  • - *
  • Determines the complete set of duplicated nodes.
  • - *
  • Performs the actual duplication.
  • - *
- */ - private void duplicate() { - Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability()); - - ValueAnchorNode anchor = addValueAnchor(); - - // determine the fixed nodes that should be duplicated (currently: all nodes up until the first control - // split, end node, deopt or return. - ArrayList fixedNodes = new ArrayList<>(); - FixedNode fixed = merge.next(); - FrameState stateAfter = merge.stateAfter(); - while (fixed instanceof FixedWithNextNode) { - fixedNodes.add(fixed); - if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) { - stateAfter = ((StateSplit) fixed).stateAfter(); - } - fixed = ((FixedWithNextNode) fixed).next(); - } - - EndNode endAfter = createNewMerge(fixed, stateAfter); - MergeNode mergeAfter = endAfter.merge(); - fixedNodes.add(endAfter); - final HashSet duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); - mergeAfter.clearEnds(); - expandDuplicated(duplicatedNodes, mergeAfter); - retargetDependencies(duplicatedNodes, anchor); - - List endSnapshot = merge.forwardEnds().snapshot(); - List phiSnapshot = merge.phis().snapshot(); - - int endIndex = 0; - for (final EndNode forwardEnd : merge.forwardEnds()) { - Map duplicates; - if (replacements == null || replacements.get(endIndex) == null) { - duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null); - } else { - HashMap replace = new HashMap<>(); - replace.put(replacements.get(endIndex).object(), replacements.get(endIndex)); - duplicates = graph.addDuplicates(duplicatedNodes, replace); - } - for (Map.Entry phi : bottomPhis.entrySet()) { - phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey())); - } - mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter)); - - // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding EndNode - FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor); - ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate); - // move dependencies on the ValueAnchorNode to the previous BeginNode - BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate); - anchorDuplicate.replaceAtUsages(prevBegin); - - // re-wire the phi duplicates to the correct input - for (PhiNode phi : phiSnapshot) { - PhiNode phiDuplicate = (PhiNode) duplicates.get(phi); - for (Node usage : phiDuplicate.usages()) { - if (usage instanceof ValueNode) { - ((ValueNode) usage).dependencies().add(prevBegin); - } - } - phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd)); - phiDuplicate.safeDelete(); - } - endIndex++; - } - GraphUtil.killCFG(merge); - for (EndNode forwardEnd : endSnapshot) { - forwardEnd.safeDelete(); - } - for (PhiNode phi : phiSnapshot) { - // these phis should go away, but they still need to be anchored to a merge to be valid... - if (phi.isAlive()) { - phi.setMerge(mergeAfter); - } - } - Debug.dump(graph, "After tail duplication at %s", merge); - } - - /** - * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not phis) to this - * ValueAnchorNode. - * - * @return The new {@link ValueAnchorNode} that was created. - */ - private ValueAnchorNode addValueAnchor() { - ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); - graph.addAfterFixed(merge, anchor); - for (Node usage : merge.usages().snapshot()) { - if (usage instanceof PhiNode && ((PhiNode) usage).merge() == merge) { - // nothing to do - } else { - usage.replaceFirstInput(merge, anchor); - } - } - return anchor; - } - - /** - * Given a set of fixed nodes, this method determines the set of fixed and floating nodes that needs to be - * duplicated, i.e., all nodes that due to data flow and other dependencies needs to be duplicated. - * - * @param fixedNodes The set of fixed nodes that should be duplicated. - * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All {@link ValueNode}s - * reachable from this state are considered to be reachable from within the duplicated set of nodes. - * @return The set of nodes that need to be duplicated. - */ - private HashSet buildDuplicatedNodeSet(final ArrayList fixedNodes, FrameState stateAfter) { - final NodeBitMap aboveBound = graph.createNodeBitMap(); - final NodeBitMap belowBound = graph.createNodeBitMap(); - - final Deque worklist = new ArrayDeque<>(); - - // Build the set of nodes that have (transitive) usages within the duplicatedNodes. - // This is achieved by iterating all nodes that are reachable via inputs from the the fixed nodes. - aboveBound.markAll(fixedNodes); - worklist.addAll(fixedNodes); - - // the phis at the original merge should always be duplicated - for (PhiNode phi : merge.phis()) { - aboveBound.mark(phi); - worklist.add(phi); - } - - NodeClosure aboveClosure = new NodeClosure() { - - @Override - public void apply(Node usage, Node node) { - if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) { - // stop iterating: phis belonging to outside merges are known to be outside. - } else if (node instanceof FixedNode) { - // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other - // fixed nodes are known to be outside. - } else if (!aboveBound.isMarked(node)) { - worklist.add(node); - aboveBound.mark(node); - } - } - }; - - if (stateAfter != null) { - stateAfter.applyToNonVirtual(aboveClosure); - } - while (!worklist.isEmpty()) { - Node current = worklist.remove(); - for (Node input : current.inputs()) { - aboveClosure.apply(current, input); - } - } - - // Build the set of nodes that have (transitive) inputs within the duplicatedNodes. - // This is achieved by iterating all nodes that are reachable via usages from the fixed nodes. - belowBound.markAll(fixedNodes); - worklist.addAll(fixedNodes); - - // the phis at the original merge should always be duplicated - for (PhiNode phi : merge.phis()) { - belowBound.mark(phi); - worklist.add(phi); - } - - while (!worklist.isEmpty()) { - Node current = worklist.remove(); - for (Node usage : current.usages()) { - if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) { - // stop iterating: phis belonging to outside merges are known to be outside. - } else if (usage instanceof FixedNode) { - // stop iterating: fixed nodes within the given set are traversal roots anyway, and all other - // fixed nodes are known to be outside. - } else if (!belowBound.isMarked(usage)) { - worklist.add(usage); - belowBound.mark(usage); - } - } - } - - // build the intersection - belowBound.intersect(aboveBound); - HashSet result = new HashSet<>(); - for (Node node : belowBound) { - result.add(node); - } - return result; - } - - /** - * Creates a new merge and end node construct at the end of the duplicated area. While it is useless in itself - * (merge with only one end) it simplifies the later duplication step. - * - * @param successor The successor of the duplicated set of nodes, i.e., the first node that should not be - * duplicated. - * @param stateAfterMerge The frame state that should be used for the merge. - * @return The newly created end node. - */ - private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { - MergeNode newBottomMerge = graph.add(new MergeNode()); - newBottomMerge.setProbability(successor.probability()); - EndNode newBottomEnd = graph.add(new EndNode()); - newBottomMerge.addForwardEnd(newBottomEnd); - newBottomMerge.setStateAfter(stateAfterMerge); - ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd); - newBottomMerge.setNext(successor); - return newBottomEnd; - } - - /** - * Expands the set of nodes to be duplicated by looking at a number of conditions: - *
    - *
  • {@link ValueNode}s that have usages on the outside need to be replaced with phis for the outside usages.
  • - *
  • Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object states, ...) need to - * be cloned immediately for the outside usages.
  • - *
  • Nodes that have a {@link StampFactory#extension()} or {@link StampFactory#condition()} stamp need to be - * cloned immediately for the outside usages.
  • - *
  • Dependencies into the duplicated nodes will be replaced with dependencies on the merge.
  • - *
  • Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to also be duplicated. - *
  • - *
  • Outside {@link ValueNode}s with {@link StampFactory#extension()} or {@link StampFactory#condition()} - * stamps that have usages within the duplicated set of nodes need to also be duplicated.
  • - *
- * - * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded). - * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used for newly created - * phis and to as a target for dependencies that pointed into the duplicated set of nodes. - */ - private void expandDuplicated(HashSet duplicatedNodes, MergeNode newBottomMerge) { - Deque worklist = new ArrayDeque<>(duplicatedNodes); - - while (!worklist.isEmpty()) { - Node duplicated = worklist.remove(); - if (hasUsagesOutside(duplicated, duplicatedNodes)) { - boolean cloneForOutsideUsages = false; - if (duplicated instanceof ValueNode) { - ValueNode node = (ValueNode) duplicated; - if (node.stamp() == StampFactory.dependency()) { - // re-route dependencies to the merge - replaceUsagesOutside(node, newBottomMerge, duplicatedNodes); - // TODO(ls) maybe introduce phis for dependencies - } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) { - cloneForOutsideUsages = true; - } else { - // introduce a new phi - PhiNode newPhi = bottomPhis.get(node); - if (newPhi == null) { - newPhi = graph.add(new PhiNode(node.kind(), newBottomMerge)); - bottomPhis.put(node, newPhi); - newPhi.addInput(node); - } - replaceUsagesOutside(node, newPhi, duplicatedNodes); - } - } else { - cloneForOutsideUsages = true; - } - if (cloneForOutsideUsages) { - // clone the offending node to the outside - Node newOutsideClone = duplicated.copyWithInputs(); - replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes); - // this might cause other nodes to have outside usages, we need to look at those as well - for (Node input : newOutsideClone.inputs()) { - if (duplicatedNodes.contains(input)) { - worklist.add(input); - } - } - } - } - // check if this node has an input that lies outside and cannot be shared - for (Node input : duplicated.inputs()) { - if (!duplicatedNodes.contains(input)) { - boolean duplicateInput = false; - if (input instanceof VirtualState) { - duplicateInput = true; - } else if (input instanceof ValueNode) { - Stamp inputStamp = ((ValueNode) input).stamp(); - if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) { - duplicateInput = true; - } - } - if (duplicateInput) { - duplicatedNodes.add(input); - worklist.add(input); - } - } - } - } - } - - /** - * Moves all depdendencies that point outside the duplicated area to the supplied value anchor node. - * - * @param duplicatedNodes The set of duplicated nodes. - * @param anchor The node that will be the new target for all dependencies that point outside the duplicated set of nodes. - */ - private static void retargetDependencies(HashSet duplicatedNodes, ValueAnchorNode anchor) { - for (Node node : duplicatedNodes) { - if (node instanceof ValueNode) { - NodeInputList dependencies = ((ValueNode) node).dependencies(); - for (int i = 0; i < dependencies.size(); i++) { - Node dependency = dependencies.get(i); - if (dependency != null && !duplicatedNodes.contains(dependency)) { - Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node); - dependencies.set(i, anchor); - } - } - } - } - } - - /** - * Checks if the given node has usages that are not within the given set of nodes. - * - * @param node The node whose usages are checked. - * @param nodeSet The set of nodes that are considered to be "within". - * @return true if the given node has usages on the outside, false otherwise. - */ - private static boolean hasUsagesOutside(Node node, HashSet nodeSet) { - for (Node usage : node.usages()) { - if (!nodeSet.contains(usage)) { - return true; - } - } - return false; - } - - /** - * Replaces the given node with the given replacement at all usages that are not within the given set of nodes. - * - * @param node The node to be replaced at outside usages. - * @param replacement The node that replaced the given node at outside usages. - * @param nodeSet The set of nodes that are considered to be "within". - */ - private static void replaceUsagesOutside(Node node, Node replacement, HashSet nodeSet) { - for (Node usage : node.usages().snapshot()) { - if (!nodeSet.contains(usage)) { - usage.replaceFirstInput(node, replacement); - } - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/MergeableBlockState.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.ea; - - -public interface MergeableBlockState { - - T clone(); -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PartialEscapeAnalysisPhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1148 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.ea; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaType.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.schedule.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.virtual.*; - -class EscapeAnalysisIteration { - - // Metrics - private static final DebugMetric metricAllocationRemoved = Debug.metric("AllocationRemoved"); - private static final DebugMetric metricAllocationFieldsRemoved = Debug.metric("AllocationFieldsRemoved"); - private static final DebugMetric metricStoreRemoved = Debug.metric("StoreRemoved"); - private static final DebugMetric metricLoadRemoved = Debug.metric("LoadRemoved"); - private static final DebugMetric metricLockRemoved = Debug.metric("LockRemoved"); - private static final DebugMetric metricOtherRemoved = Debug.metric("OtherRemoved"); - private static final DebugMetric metricMaterializations = Debug.metric("Materializations"); - private static final DebugMetric metricMaterializationFields = Debug.metric("MaterializationFields"); - private static final DebugMetric metricLoopBailouts = Debug.metric("LoopBailouts"); - private static final DebugMetric metricMonitorBailouts = Debug.metric("MonitorBailouts"); - - - private static final ValueNode DUMMY_NODE = new ValueNode(null) { - }; - - public static final void trace(String format, Object... obj) { - if (GraalOptions.TraceEscapeAnalysis) { - Debug.log(format, obj); - } - } - - public static final void error(String format, Object... obj) { - System.out.print(String.format(format, obj)); - } - - private final StructuredGraph graph; - private final MetaAccessProvider runtime; - private final SchedulePhase schedule; - private final NodeBitMap usages; - boolean changed = false; - - private final boolean changeGraph; - - private final HashSet reusedVirtualObjects = new HashSet<>(); - private final HashSet allocations; - private final ArrayList obsoleteNodes = new ArrayList<>(); - private int virtualIds = 0; - - public EscapeAnalysisIteration(StructuredGraph graph, SchedulePhase schedule, MetaAccessProvider runtime, HashSet allocations, boolean changeGraph) { - this.graph = graph; - this.schedule = schedule; - this.runtime = runtime; - this.allocations = allocations; - this.changeGraph = changeGraph; - this.usages = graph.createNodeBitMap(); - } - - public void run() { - new PartialEscapeIterator(graph, schedule.getCFG().getStartBlock()).apply(); - - if (changeGraph) { - Debug.dump(graph, "after PartialEscapeAnalysis"); - - for (ValueNode node : obsoleteNodes) { - if (node.isAlive() && node instanceof FixedWithNextNode) { - FixedWithNextNode x = (FixedWithNextNode) node; - FixedNode next = x.next(); - x.setNext(null); - ((FixedWithNextNode) node.predecessor()).setNext(next); - } - } - new DeadCodeEliminationPhase().apply(graph); - - if (changed) { - Debug.log("escape analysis on %s\n", graph.method()); - } - } - } - - private static class ObjectState { - - public final VirtualObjectNode virtual; - public ValueNode[] fieldState; - public ValueNode materializedValue; - public int lockCount; - public boolean initialized; - - public ObjectState(VirtualObjectNode virtual, ValueNode[] fieldState, int lockCount) { - this.virtual = virtual; - this.fieldState = fieldState; - this.lockCount = lockCount; - this.initialized = false; - } - - public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, int lockCount) { - this.virtual = virtual; - this.materializedValue = materializedValue; - this.lockCount = lockCount; - this.initialized = true; - } - - private ObjectState(ObjectState other) { - virtual = other.virtual; - fieldState = other.fieldState == null ? null : other.fieldState.clone(); - materializedValue = other.materializedValue; - lockCount = other.lockCount; - initialized = other.initialized; - } - - @Override - public ObjectState clone() { - return new ObjectState(this); - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder().append('{'); - if (lockCount > 0) { - str.append('l').append(lockCount).append(' '); - } - if (fieldState != null) { - for (int i = 0; i < fieldState.length; i++) { - str.append(virtual.fieldName(i)).append('=').append(fieldState[i]).append(' '); - } - } - if (materializedValue != null) { - str.append("mat=").append(materializedValue); - } - - return str.append('}').toString(); - } - } - - private class BlockState implements MergeableBlockState { - - private final HashMap objectStates = new HashMap<>(); - private final HashMap objectAliases = new HashMap<>(); - - public BlockState() { - } - - public BlockState(BlockState other) { - for (Map.Entry entry : other.objectStates.entrySet()) { - objectStates.put(entry.getKey(), entry.getValue().clone()); - } - for (Map.Entry entry : other.objectAliases.entrySet()) { - objectAliases.put(entry.getKey(), entry.getValue()); - } - } - - public ObjectState objectState(VirtualObjectNode object) { - assert objectStates.containsKey(object); - return objectStates.get(object); - } - - public ObjectState objectState(ValueNode value) { - VirtualObjectNode object = objectAliases.get(value); - return object == null ? null : objectState(object); - } - - @Override - public BlockState clone() { - return new BlockState(this); - } - - public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual) { - if (changeGraph) { - HashSet deferred = new HashSet<>(); - ArrayList deferredStores = new ArrayList<>(); - materializeChangedBefore(fixed, virtual, deferred, deferredStores); - for (FixedWithNextNode write : deferredStores) { - write.setProbability(fixed.probability()); - graph.addBeforeFixed(fixed, write); - } - } else { - materializeUnchangedBefore(virtual); - } - } - - private void materializeUnchangedBefore(VirtualObjectNode virtual) { - trace("materializing %s", virtual); - ObjectState obj = objectState(virtual); - if (obj.lockCount > 0) { - if (changeGraph) { - error("object materialized with lock: %s\n", virtual); - } - metricMonitorBailouts.increment(); - throw new BailoutException("object materialized with lock"); - } - - ValueNode[] fieldState = obj.fieldState; - obj.fieldState = null; - obj.materializedValue = DUMMY_NODE; - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = objectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.materializedValue == null) { - materializeUnchangedBefore(valueObj.virtual); - } - } - } - obj.initialized = true; - } - - private void materializeChangedBefore(FixedNode fixed, VirtualObjectNode virtual, HashSet deferred, ArrayList deferredStores) { - trace("materializing %s at %s", virtual, fixed); - ObjectState obj = objectState(virtual); - if (obj.lockCount > 0) { - error("object materialized with lock: %s\n", virtual); - metricMonitorBailouts.increment(); - throw new BailoutException("object materialized with lock"); - } - - MaterializeObjectNode materialize = graph.add(new MaterializeObjectNode(virtual)); - materialize.setProbability(fixed.probability()); - ValueNode[] fieldState = obj.fieldState; - metricMaterializations.increment(); - metricMaterializationFields.add(fieldState.length); - obj.fieldState = null; - obj.materializedValue = materialize; - deferred.add(virtual); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = objectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.materializedValue == null) { - materializeChangedBefore(fixed, valueObj.virtual, deferred, deferredStores); - } - if (deferred.contains(valueObj.virtual)) { - Kind fieldKind; - if (virtual instanceof VirtualArrayNode) { - deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, i))); - fieldKind = ((VirtualArrayNode) virtual).componentType().kind(); - } else { - VirtualInstanceNode instanceObject = (VirtualInstanceNode) virtual; - deferredStores.add(graph.add(new CyclicMaterializeStoreNode(materialize, valueObj.materializedValue, instanceObject.field(i)))); - fieldKind = instanceObject.field(i).type().kind(); - } - materialize.values().set(i, ConstantNode.defaultForKind(fieldKind, graph)); - } else { - assert valueObj.initialized : "should be initialized: " + virtual + " at " + fixed; - materialize.values().set(i, valueObj.materializedValue); - } - } else { - materialize.values().set(i, fieldState[i]); - } - } - deferred.remove(virtual); - - obj.initialized = true; - graph.addBeforeFixed(fixed, materialize); - } - - private void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, boolean remove) { - objectAliases.put(node, virtual); - for (Node usage : node.usages()) { - markVirtualUsages(usage); - } - if (remove) { - obsoleteNodes.add(node); - } - } - - private void markVirtualUsages(Node node) { - if (!usages.isNew(node)) { - usages.mark(node); - } - if (node instanceof VirtualState) { - for (Node usage : node.usages()) { - markVirtualUsages(usage); - } - } - } - - public void addObject(VirtualObjectNode virtual, ObjectState state) { - objectStates.put(virtual, state); - } - - public Iterable states() { - return objectStates.values(); - } - - @Override - public String toString() { - return objectStates.toString(); - } - } - - private class PartialEscapeIterator extends PostOrderBlockIterator { - - public PartialEscapeIterator(StructuredGraph graph, Block start) { - super(graph, start, new BlockState()); - } - - @Override - protected void processBlock(Block block, BlockState state) { - trace("\nBlock: %s (", block); - List nodeList = schedule.getBlockToNodesMap().get(block); - - FixedWithNextNode lastFixedNode = null; - for (Node node : nodeList) { - EscapeOp op = null; - if (node instanceof EscapeAnalyzable) { - op = ((EscapeAnalyzable) node).getEscapeOp(); - } - if (op != null) { - // only escape analyze allocations that were escape analyzed during the first iteration - if (changeGraph && !allocations.contains(node)) { - op = null; - } - } - - if (op != null) { - trace("{{%s}} ", node); - VirtualObjectNode virtualObject = op.virtualObject(virtualIds); - if (virtualObject.isAlive()) { - reusedVirtualObjects.add(virtualObject); - state.addAndMarkAlias(virtualObject, virtualObject, false); - } else { - if (changeGraph) { - virtualObject = graph.add(virtualObject); - } - } - ValueNode[] fieldState = changeGraph ? op.fieldState() : new ValueNode[virtualObject.entryCount()]; - if (changeGraph) { - metricAllocationRemoved.increment(); - metricAllocationFieldsRemoved.add(fieldState.length); - } else { - allocations.add((ValueNode) node); - } - state.addObject(virtualObject, new ObjectState(virtualObject, fieldState, 0)); - state.addAndMarkAlias(virtualObject, (ValueNode) node, true); - virtualIds++; - } else { - if (changeGraph && node instanceof LoopExitNode) { - for (ObjectState obj : state.states()) { - if (obj.fieldState != null) { - for (int i = 0; i < obj.fieldState.length; i++) { - ValueNode value = obj.fieldState[i]; - ObjectState valueObj = state.objectState(value); - if (valueObj == null) { - obj.fieldState[i] = graph.unique(new ValueProxyNode(value, (LoopExitNode) node, PhiType.Value)); - } - } - } else { - obj.materializedValue = graph.unique(new ValueProxyNode(obj.materializedValue, (LoopExitNode) node, PhiType.Value)); - } - } - } - - if (usages.isMarked(node)) { - trace("[[%s]] ", node); - processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state); - } else { - trace("%s ", node); - } - } - - if (node instanceof FixedWithNextNode && node.isAlive()) { - lastFixedNode = (FixedWithNextNode) node; - } - } - trace(")\n end state: %s\n", state); - } - - private void processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) { - boolean usageFound = false; - if (node instanceof PiNode || node instanceof ValueProxyNode) { - ValueNode value = node instanceof PiNode ? ((PiNode) node).object() : ((ValueProxyNode) node).value(); - ObjectState obj = state.objectState(value); - assert obj != null : node; - if (obj.materializedValue == null) { - state.addAndMarkAlias(obj.virtual, node, true); - } else { - if (changeGraph) { - node.replaceFirstInput(value, obj.materializedValue); - } - } - usageFound = true; - } else if (node instanceof CheckCastNode) { - CheckCastNode x = (CheckCastNode) node; - ObjectState obj = state.objectState(x.object()); - assert obj != null : x; - if (obj.materializedValue == null) { - if (x.targetClass() != null && obj.virtual.type().isSubtypeOf(x.targetClass())) { - metricOtherRemoved.increment(); - state.addAndMarkAlias(obj.virtual, x, true); - // throw new UnsupportedOperationException("probably incorrect - losing dependency"); - } else { - replaceWithMaterialized(x.object(), x, state, obj); - } - } else { - if (changeGraph) { - node.replaceFirstInput(x.object(), obj.materializedValue); - } - } - usageFound = true; - } else if (node instanceof IsNullNode) { - IsNullNode x = (IsNullNode) node; - ObjectState obj = state.objectState(x.object()); - assert obj != null : x; - if (changeGraph) { - graph.replaceFloating(x, graph.unique(ConstantNode.forBoolean(false, graph))); - metricOtherRemoved.increment(); - } - usageFound = true; - } else if (node instanceof IsTypeNode) { - throw new GraalInternalError("a newly created object can never be an object hub"); - } else if (node instanceof AccessMonitorNode) { - AccessMonitorNode x = (AccessMonitorNode) node; - ObjectState obj = state.objectState(x.object()); - if (obj != null) { - Debug.log("monitor operation %s on %s\n", x, obj.virtual); - if (node instanceof MonitorEnterNode) { - obj.lockCount++; - } else { - assert node instanceof MonitorExitNode; - obj.lockCount--; - } - if (changeGraph) { - changed = true; - if (obj.materializedValue == null) { - metricLockRemoved.increment(); - node.replaceFirstInput(x.object(), obj.virtual); - x.eliminate(); - } else { - node.replaceFirstInput(x.object(), obj.materializedValue); - } - } - usageFound = true; - } - } else if (node instanceof CyclicMaterializeStoreNode) { - CyclicMaterializeStoreNode x = (CyclicMaterializeStoreNode) node; - ObjectState obj = state.objectState(x.object()); - assert obj != null : x; - if (obj.virtual instanceof VirtualArrayNode) { - obj.fieldState[x.targetIndex()] = x.value(); - } else { - VirtualInstanceNode instance = (VirtualInstanceNode) obj.virtual; - int index = instance.fieldIndex(x.targetField()); - obj.fieldState[index] = x.value(); - } - if (changeGraph) { - graph.removeFixed(x); - } - usageFound = true; - } else if (node instanceof LoadFieldNode) { - LoadFieldNode x = (LoadFieldNode) node; - ObjectState obj = state.objectState(x.object()); - assert obj != null : x; - VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual; - int fieldIndex = virtual.fieldIndex(x.field()); - if (fieldIndex == -1) { - // the field does not exist in the virtual object - ensureMaterialized(state, obj, x); - } - if (obj.materializedValue == null) { - ValueNode result = obj.fieldState[fieldIndex]; - ObjectState resultObj = state.objectState(result); - if (resultObj != null) { - state.addAndMarkAlias(resultObj.virtual, x, true); - } else { - if (changeGraph) { - x.replaceAtUsages(result); - graph.removeFixed(x); - } - } - if (changeGraph) { - metricLoadRemoved.increment(); - } - changed = true; - } else { - if (changeGraph) { - x.replaceFirstInput(x.object(), obj.materializedValue); - } - } - usageFound = true; - } else if (node instanceof StoreFieldNode) { - StoreFieldNode x = (StoreFieldNode) node; - ValueNode object = x.object(); - ValueNode value = x.value(); - ObjectState obj = state.objectState(object); - if (obj != null) { - VirtualInstanceNode virtual = (VirtualInstanceNode) obj.virtual; - int fieldIndex = virtual.fieldIndex(x.field()); - if (fieldIndex == -1) { - // the field does not exist in the virtual object - ensureMaterialized(state, obj, x); - } - if (obj.materializedValue == null) { - obj.fieldState[fieldIndex] = value; - if (changeGraph) { - graph.removeFixed(x); - metricStoreRemoved.increment(); - } - changed = true; - } else { - if (changeGraph) { - x.replaceFirstInput(object, obj.materializedValue); - } - ObjectState valueObj = state.objectState(value); - if (valueObj != null) { - replaceWithMaterialized(value, x, state, valueObj); - } - } - usageFound = true; - } else { - ObjectState valueObj = state.objectState(value); - if (valueObj != null) { - replaceWithMaterialized(value, x, state, valueObj); - usageFound = true; - } - } - } else if (node instanceof LoadIndexedNode) { - LoadIndexedNode x = (LoadIndexedNode) node; - ValueNode array = x.array(); - ObjectState arrayObj = state.objectState(array); - if (arrayObj != null) { - if (arrayObj.materializedValue == null) { - int index = x.index().isConstant() ? x.index().asConstant().asInt() : -1; - if (index < 0 || index >= arrayObj.fieldState.length) { - // out of bounds or not constant - replaceWithMaterialized(array, x, state, arrayObj); - } else { - ValueNode result = arrayObj.fieldState[index]; - ObjectState resultObj = state.objectState(result); - if (resultObj != null) { - state.addAndMarkAlias(resultObj.virtual, x, true); - } else { - if (changeGraph) { - x.replaceAtUsages(result); - graph.removeFixed(x); - } - } - if (changeGraph) { - metricLoadRemoved.increment(); - } - changed = true; - } - } else { - if (changeGraph) { - x.replaceFirstInput(array, arrayObj.materializedValue); - } - } - usageFound = true; - } - } else if (node instanceof StoreIndexedNode) { - StoreIndexedNode x = (StoreIndexedNode) node; - ValueNode array = x.array(); - ValueNode value = x.value(); - ObjectState arrayObj = state.objectState(array); - ObjectState valueObj = state.objectState(value); - - if (arrayObj != null) { - if (arrayObj.materializedValue == null) { - int index = x.index().isConstant() ? x.index().asConstant().asInt() : -1; - if (index < 0 || index >= arrayObj.fieldState.length) { - // out of bounds or not constant - replaceWithMaterialized(array, x, state, arrayObj); - if (valueObj != null) { - replaceWithMaterialized(value, x, state, valueObj); - } - } else { - arrayObj.fieldState[index] = value; - if (changeGraph) { - graph.removeFixed(x); - metricStoreRemoved.increment(); - } - changed = true; - } - } else { - if (changeGraph) { - x.replaceFirstInput(array, arrayObj.materializedValue); - } - if (valueObj != null) { - replaceWithMaterialized(value, x, state, valueObj); - } - } - usageFound = true; - } else { - if (valueObj != null) { - replaceWithMaterialized(value, x, state, valueObj); - usageFound = true; - } - } - } else if (node instanceof RegisterFinalizerNode) { - RegisterFinalizerNode x = (RegisterFinalizerNode) node; - ObjectState obj = state.objectState(x.object()); - replaceWithMaterialized(x.object(), x, state, obj); - usageFound = true; - } else if (node instanceof ArrayLengthNode) { - ArrayLengthNode x = (ArrayLengthNode) node; - ObjectState obj = state.objectState(x.array()); - assert obj != null : x; - if (changeGraph) { - graph.replaceFixedWithFloating(x, ConstantNode.forInt(((VirtualArrayNode) obj.virtual).entryCount(), graph)); - metricOtherRemoved.increment(); - } - changed = true; - usageFound = true; - } else if (node instanceof ReadHubNode) { - ReadHubNode x = (ReadHubNode) node; - ObjectState obj = state.objectState(x.object()); - assert obj != null : x; - if (changeGraph) { - ConstantNode hub = ConstantNode.forConstant(obj.virtual.type().getEncoding(Representation.ObjectHub), runtime, graph); - graph.replaceFixedWithFloating(x, hub); - metricOtherRemoved.increment(); - } - changed = true; - usageFound = true; - } else if (node instanceof ReturnNode) { - ReturnNode x = (ReturnNode) node; - ObjectState obj = state.objectState(x.result()); - replaceWithMaterialized(x.result(), x, state, obj); - usageFound = true; - } else if (node instanceof MethodCallTargetNode) { - for (ValueNode argument : ((MethodCallTargetNode) node).arguments()) { - ObjectState obj = state.objectState(argument); - if (obj != null) { - replaceWithMaterialized(argument, node, insertBefore, state, obj); - usageFound = true; - } - } - } else if (node instanceof ObjectEqualsNode) { - ObjectEqualsNode x = (ObjectEqualsNode) node; - ObjectState xObj = state.objectState(x.x()); - ObjectState yObj = state.objectState(x.y()); - boolean xVirtual = xObj != null && xObj.materializedValue == null; - boolean yVirtual = yObj != null && yObj.materializedValue == null; - - if (changeGraph) { - if (xVirtual ^ yVirtual) { - // one of them is virtual: they can never be the same objects - graph.replaceFloating(x, ConstantNode.forBoolean(false, graph)); - usageFound = true; - metricOtherRemoved.increment(); - changed = true; - } else if (xVirtual && yVirtual) { - // both are virtual: check if they refer to the same object - graph.replaceFloating(x, ConstantNode.forBoolean(xObj == yObj, graph)); - usageFound = true; - metricOtherRemoved.increment(); - changed = true; - } else { - assert xObj != null || yObj != null; - if (xObj != null) { - assert xObj.materializedValue != null; - node.replaceFirstInput(x.x(), xObj.materializedValue); - } - if (yObj != null) { - assert yObj.materializedValue != null; - node.replaceFirstInput(x.y(), yObj.materializedValue); - } - } - } - usageFound = true; - } else if (node instanceof MergeNode) { - usageFound = true; - } else if (node instanceof UnsafeLoadNode || node instanceof UnsafeStoreNode || node instanceof CompareAndSwapNode || node instanceof SafeReadNode) { - for (ValueNode input : node.inputs().filter(ValueNode.class)) { - ObjectState obj = state.objectState(input); - if (obj != null) { - replaceWithMaterialized(input, node, insertBefore, state, obj); - usageFound = true; - } - } - } - if (node.isAlive() && node instanceof StateSplit) { - StateSplit split = (StateSplit) node; - FrameState stateAfter = split.stateAfter(); - if (stateAfter != null) { - if (changeGraph) { - if (stateAfter.usages().size() > 1) { - stateAfter = (FrameState) stateAfter.copyWithInputs(); - split.setStateAfter(stateAfter); - } - final HashSet virtual = new HashSet<>(); - stateAfter.applyToNonVirtual(new NodeClosure() { - - @Override - public void apply(Node usage, ValueNode value) { - ObjectState valueObj = state.objectState(value); - if (valueObj != null) { - virtual.add(valueObj); - usage.replaceFirstInput(value, valueObj.virtual); - } else if (value instanceof VirtualObjectNode) { - ObjectState virtualObj = null; - for (ObjectState obj : state.states()) { - if (value == obj.virtual) { - virtualObj = obj; - break; - } - } - if (virtualObj != null) { - virtual.add(virtualObj); - } - } - } - }); - for (ObjectState obj : state.states()) { - if (obj.materializedValue == null && obj.lockCount > 0) { - virtual.add(obj); - } - } - - ArrayDeque queue = new ArrayDeque<>(virtual); - while (!queue.isEmpty()) { - ObjectState obj = queue.removeLast(); - if (obj.materializedValue == null) { - for (ValueNode field : obj.fieldState) { - ObjectState fieldObj = state.objectState(field); - if (fieldObj != null) { - if (fieldObj.materializedValue == null && !virtual.contains(fieldObj)) { - virtual.add(fieldObj); - queue.addLast(fieldObj); - } - } - } - } - } - for (ObjectState obj : virtual) { - EscapeObjectState v; - if (obj.materializedValue == null) { - ValueNode[] fieldState = obj.fieldState.clone(); - for (int i = 0; i < fieldState.length; i++) { - ObjectState valueObj = state.objectState(fieldState[i]); - if (valueObj != null) { - if (valueObj.materializedValue == null) { - fieldState[i] = valueObj.virtual; - } else { - fieldState[i] = valueObj.materializedValue; - } - } - } - v = graph.add(new VirtualObjectState(obj.virtual, fieldState)); - } else { - v = graph.add(new MaterializedObjectState(obj.virtual, obj.materializedValue)); - } - for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) { - if (stateAfter.virtualObjectMappingAt(i).object() == v.object()) { - if (reusedVirtualObjects.contains(v.object())) { - stateAfter.virtualObjectMappings().remove(i); - } else { - throw new GraalInternalError("unexpected duplicate virtual state at: %s for %s", node, v.object()); - } - } - } - stateAfter.addVirtualObjectMapping(v); - } - } - usageFound = true; - } - } - if (!usageFound) { - for (ValueNode input : node.inputs().filter(ValueNode.class)) { - ObjectState obj = state.objectState(input); - if (obj != null) { - replaceWithMaterialized(input, node, insertBefore, state, obj); - usageFound = true; - } - } - Debug.log("unexpected usage of %s: %s\n", node, node.inputs().snapshot()); - } - } - - private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore) { - assert obj != null; - if (obj.materializedValue == null) { - state.materializeBefore(materializeBefore, obj.virtual); - } - assert obj.materializedValue != null; - } - - private void replaceWithMaterialized(ValueNode value, FixedNode usage, BlockState state, ObjectState obj) { - ensureMaterialized(state, obj, usage); - if (changeGraph) { - usage.replaceFirstInput(value, obj.materializedValue); - } - } - - private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockState state, ObjectState obj) { - ensureMaterialized(state, obj, materializeBefore); - if (changeGraph) { - usage.replaceFirstInput(value, obj.materializedValue); - } - } - - @Override - protected BlockState merge(MergeNode merge, List states) { - BlockState newState = new BlockState(); - - newState.objectAliases.putAll(states.get(0).objectAliases); - for (int i = 1; i < states.size(); i++) { - BlockState state = states.get(i); - for (Map.Entry entry : states.get(0).objectAliases.entrySet()) { - if (state.objectAliases.containsKey(entry.getKey())) { - assert state.objectAliases.get(entry.getKey()) == entry.getValue(); - } else { - newState.objectAliases.remove(entry.getKey()); - } - } - } - - // Iterative processing: - // Merging the materialized/virtual state of virtual objects can lead to new materializations, which can - // lead to new materializations because of phis, and so on. - - boolean materialized; - do { - materialized = false; - // use a hash set to make the values distinct... - for (VirtualObjectNode object : new HashSet<>(newState.objectAliases.values())) { - ObjectState resultState = newState.objectStates.get(object); - if (resultState == null || resultState.materializedValue == null) { - int virtual = 0; - int lockCount = states.get(0).objectState(object).lockCount; - for (BlockState state : states) { - ObjectState obj = state.objectState(object); - if (obj.materializedValue == null) { - virtual++; - } - assert obj.lockCount == lockCount : "mismatching lock counts"; - } - - if (virtual < states.size()) { - ValueNode materializedValuePhi = changeGraph ? graph.add(new PhiNode(Kind.Object, merge)) : DUMMY_NODE; - for (int i = 0; i < states.size(); i++) { - BlockState state = states.get(i); - ObjectState obj = state.objectState(object); - materialized |= obj.materializedValue == null; - ensureMaterialized(state, obj, merge.forwardEndAt(i)); - if (changeGraph) { - ((PhiNode) materializedValuePhi).addInput(obj.materializedValue); - } - } - newState.addObject(object, new ObjectState(object, materializedValuePhi, lockCount)); - } else { - assert virtual == states.size(); - ValueNode[] values = states.get(0).objectState(object).fieldState.clone(); - PhiNode[] phis = new PhiNode[values.length]; - boolean[] phiCreated = new boolean[values.length]; - int mismatch = 0; - for (int i = 1; i < states.size(); i++) { - BlockState state = states.get(i); - ValueNode[] fields = state.objectState(object).fieldState; - for (int index = 0; index < values.length; index++) { - if (!phiCreated[index] && values[index] != fields[index]) { - mismatch++; - if (changeGraph) { - phis[index] = graph.add(new PhiNode(values[index].kind(), merge)); - } - phiCreated[index] = true; - } - } - } - if (mismatch > 0) { - for (int i = 0; i < states.size(); i++) { - BlockState state = states.get(i); - ValueNode[] fields = state.objectState(object).fieldState; - for (int index = 0; index < values.length; index++) { - if (phiCreated[index]) { - ObjectState obj = state.objectState(fields[index]); - if (obj != null) { - materialized |= obj.materializedValue == null; - ensureMaterialized(state, obj, merge.forwardEndAt(i)); - fields[index] = obj.materializedValue; - } - if (changeGraph) { - phis[index].addInput(fields[index]); - } - } - } - } - for (int index = 0; index < values.length; index++) { - if (phiCreated[index]) { - values[index] = phis[index]; - } - } - } - newState.addObject(object, new ObjectState(object, values, lockCount)); - } - } - } - - for (PhiNode phi : merge.phis().snapshot()) { - if (usages.isMarked(phi) && phi.type() == PhiType.Value) { - materialized |= processPhi(newState, merge, phi, states); - } - } - } while (materialized); - - return newState; - } - - private boolean processPhi(BlockState newState, MergeNode merge, PhiNode phi, List states) { - assert states.size() == phi.valueCount(); - int virtualInputs = 0; - boolean materialized = false; - VirtualObjectNode sameObject = null; - ResolvedJavaType sameType = null; - int sameEntryCount = -1; - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = phi.valueAt(i); - ObjectState obj = states.get(i).objectState(value); - if (obj != null) { - if (obj.materializedValue == null) { - virtualInputs++; - if (i == 0) { - sameObject = obj.virtual; - sameType = obj.virtual.type(); - sameEntryCount = obj.virtual.entryCount(); - } else { - if (sameObject != obj.virtual) { - sameObject = null; - } - if (sameType != obj.virtual.type()) { - sameType = null; - } - if (sameEntryCount != obj.virtual.entryCount()) { - sameEntryCount = -1; - } - } - } else { - if (changeGraph) { - phi.setValueAt(i, obj.materializedValue); - } - } - } - } - boolean materialize = false; - if (virtualInputs == 0) { - // nothing to do... - } else if (virtualInputs == phi.valueCount()) { - if (sameObject != null) { - newState.addAndMarkAlias(sameObject, phi, true); - } else if (sameType != null && sameEntryCount != -1) { - materialize = true; - // throw new GraalInternalError("merge required for %s", sameType); - } else { - materialize = true; - } - } else { - materialize = true; - } - - if (materialize) { - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = phi.valueAt(i); - ObjectState obj = states.get(i).objectState(value); - if (obj != null) { - materialized |= obj.materializedValue == null; - replaceWithMaterialized(value, phi, merge.forwardEndAt(i), states.get(i), obj); - } - } - } - return materialized; - } - - @Override - protected BlockState loopBegin(LoopBeginNode loopBegin, BlockState beforeLoopState) { - BlockState state = beforeLoopState; - for (ObjectState obj : state.states()) { - if (obj.fieldState != null) { - for (int i = 0; obj.fieldState != null && i < obj.fieldState.length; i++) { - ValueNode value = obj.fieldState[i]; - ObjectState valueObj = state.objectState(value); - if (valueObj != null) { - ensureMaterialized(state, valueObj, loopBegin.forwardEnd()); - value = valueObj.materializedValue; - } - } - } - } - for (ObjectState obj : state.states()) { - if (obj.fieldState != null) { - for (int i = 0; i < obj.fieldState.length; i++) { - ValueNode value = obj.fieldState[i]; - ObjectState valueObj = state.objectState(value); - if (valueObj != null) { - value = valueObj.materializedValue; - } - if (changeGraph) { - assert value != null; - PhiNode valuePhi = graph.add(new PhiNode(value.kind(), loopBegin)); - valuePhi.addInput(value); - obj.fieldState[i] = valuePhi; - } - } - } - } - for (PhiNode phi : loopBegin.phis()) { - ObjectState obj = state.objectState(phi.valueAt(0)); - if (obj != null) { - ensureMaterialized(state, obj, loopBegin.forwardEnd()); - if (changeGraph) { - phi.setValueAt(0, obj.materializedValue); - } - } - } - return state.clone(); - } - - @Override - protected BlockState loopEnds(LoopBeginNode loopBegin, BlockState loopBeginState, List loopEndStates) { - BlockState state = loopBeginState.clone(); - List loopEnds = loopBegin.orderedLoopEnds(); - for (ObjectState obj : state.states()) { - if (obj.fieldState != null) { - Iterator iter = loopEnds.iterator(); - for (BlockState loopEndState : loopEndStates) { - LoopEndNode loopEnd = iter.next(); - ObjectState endObj = loopEndState.objectState(obj.virtual); - if (endObj.fieldState == null) { - if (changeGraph) { - error("object materialized within loop: %s\n", obj.virtual); - } - metricLoopBailouts.increment(); - throw new BailoutException("object materialized within loop"); - } - for (int i = 0; endObj.fieldState != null && i < endObj.fieldState.length; i++) { - ValueNode value = endObj.fieldState[i]; - ObjectState valueObj = loopEndState.objectState(value); - if (valueObj != null) { - ensureMaterialized(loopEndState, valueObj, loopEnd); - value = valueObj.materializedValue; - } - if (changeGraph) { - ((PhiNode) obj.fieldState[i]).addInput(value); - } - } - } - } - } - for (PhiNode phi : loopBegin.phis()) { - if (phi.valueCount() == 1) { - if (changeGraph) { - phi.replaceAtUsages(phi.valueAt(0)); - } - } else { - assert phi.valueCount() == loopEndStates.size() + 1; - for (int i = 0; i < loopEndStates.size(); i++) { - BlockState loopEndState = loopEndStates.get(i); - ObjectState obj = loopEndState.objectState(phi.valueAt(i + 1)); - if (obj != null) { - ensureMaterialized(loopEndState, obj, loopEnds.get(i)); - if (changeGraph) { - phi.setValueAt(i + 1, obj.materializedValue); - } - } - } - } - } - return state; - } - - @Override - protected BlockState afterSplit(FixedNode node, BlockState oldState) { - return oldState.clone(); - } - } -} - -public class PartialEscapeAnalysisPhase extends Phase { - - private final TargetDescription target; - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; - - public PartialEscapeAnalysisPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions) { - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - } - - @Override - protected void run(StructuredGraph graph) { - iteration(graph, 0); - } - - - private void iteration(final StructuredGraph graph, final int num) { - HashSet allocations = new HashSet<>(); - SchedulePhase schedule = new SchedulePhase(); - schedule.apply(graph, false); - EscapeAnalysisIteration iteration = null; - try { - iteration = new EscapeAnalysisIteration(graph, schedule, runtime, allocations, false); - iteration.run(); - } catch (BailoutException e) { - // do nothing if the if the escape analysis bails out during the analysis iteration... - return; - } - if (iteration.changed) { - try { - new EscapeAnalysisIteration(graph, schedule, runtime, allocations, true).run(); - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } catch (BailoutException e) { - throw new GraalInternalError(e); - } - // next round... - if (num < 2) { - Debug.scope("next", new Runnable() { - @Override - public void run() { - iteration(graph, num + 1); - } - }); - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ea/PostOrderBlockIterator.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.ea; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - -public abstract class PostOrderBlockIterator> { - - private final NodeBitMap visitedEnds; - private final Deque blockQueue; - private final IdentityHashMap blockEndStates; - private final IdentityHashMap loopBeginStates; - private final Block start; - - private T state; - - public PostOrderBlockIterator(StructuredGraph graph, Block start, T initialState) { - visitedEnds = graph.createNodeBitMap(); - blockQueue = new ArrayDeque<>(); - blockEndStates = new IdentityHashMap<>(); - loopBeginStates = new IdentityHashMap<>(); - this.start = start; - this.state = initialState; - } - - public void apply() { - Block current = start; - - do { - processBlock(current, state); - - if (current.getSuccessors().isEmpty()) { - // nothing to do... - } else if (current.getSuccessors().size() == 1) { - Block successor = current.getSuccessors().get(0); - if (successor.isLoopHeader()) { - if (current.getEndNode() instanceof LoopEndNode) { - finishLoopEnds((LoopEndNode) current.getEndNode()); - } else { - LoopBeginNode loopBegin = (LoopBeginNode) successor.getBeginNode(); - state = loopBegin(loopBegin, state); - loopBeginStates.put(loopBegin, state); - state = state.clone(); - current = successor; - continue; - } - } else { - if (successor.getBeginNode() instanceof LoopExitNode) { - assert successor.getPredecessors().size() == 1; - current = successor; - continue; - } else { - assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode(); - queueMerge((EndNode) current.getEndNode(), successor); - } - } - } else { - assert current.getSuccessors().size() > 1; - queueSuccessors(current); - } - current = nextQueuedBlock(); - } while (current != null); - } - - protected abstract void processBlock(Block block, T currentState); - - protected abstract T merge(MergeNode merge, List states); - - protected abstract T loopBegin(LoopBeginNode loopBegin, T beforeLoopState); - - protected abstract T loopEnds(LoopBeginNode loopBegin, T loopBeginState, List loopEndStates); - - protected abstract T afterSplit(FixedNode node, T oldState); - - - private void queueSuccessors(Block current) { - blockEndStates.put(current.getEndNode(), state); - for (Block block : current.getSuccessors()) { - blockQueue.addFirst(block); - } - } - - private Block nextQueuedBlock() { - int maxIterations = blockQueue.size(); - while (maxIterations-- > 0) { - Block block = blockQueue.removeFirst(); - if (block.getPredecessors().size() > 1) { - MergeNode merge = (MergeNode) block.getBeginNode(); - ArrayList states = new ArrayList<>(merge.forwardEndCount()); - for (int i = 0; i < merge.forwardEndCount(); i++) { - T other = blockEndStates.get(merge.forwardEndAt(i)); - assert other != null; - states.add(other); - } - state = merge(merge, states); - if (state != null) { - return block; - } else { - blockQueue.addLast(block); - } - } else { - assert block.getPredecessors().size() == 1; - assert block.getBeginNode().predecessor() != null; - state = afterSplit(block.getBeginNode(), blockEndStates.get(block.getBeginNode().predecessor())); - return block; - } - } - return null; - } - - private void queueMerge(EndNode end, Block mergeBlock) { - assert !visitedEnds.isMarked(end); - assert !blockEndStates.containsKey(end); - blockEndStates.put(end, state); - visitedEnds.mark(end); - MergeNode merge = end.merge(); - boolean endsVisited = true; - for (int i = 0; i < merge.forwardEndCount(); i++) { - if (!visitedEnds.isMarked(merge.forwardEndAt(i))) { - endsVisited = false; - break; - } - } - if (endsVisited) { - blockQueue.addFirst(mergeBlock); - } - } - - private void finishLoopEnds(LoopEndNode end) { - assert !visitedEnds.isMarked(end); - assert !blockEndStates.containsKey(end); - blockEndStates.put(end, state); - visitedEnds.mark(end); - LoopBeginNode begin = end.loopBegin(); - boolean endsVisited = true; - for (LoopEndNode le : begin.loopEnds()) { - if (!visitedEnds.isMarked(le)) { - endsVisited = false; - break; - } - } - if (endsVisited) { - ArrayList states = new ArrayList<>(begin.loopEnds().count()); - for (LoopEndNode le : begin.orderedLoopEnds()) { - states.add(blockEndStates.get(le)); - } - T loopBeginState = loopBeginStates.get(begin); - if (loopBeginState != null) { - loopEnds(begin, loopBeginState, states); - } - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/BlockClosure.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/BlockClosure.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.schedule; - -import com.oracle.graal.lir.cfg.*; - -/** - * The {@code BlockClosure} interface represents a closure for iterating over blocks. - */ -public interface BlockClosure { - void apply(Block block); -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.schedule; - -import java.util.*; - -import com.oracle.max.criutils.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Verbosity; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.virtual.*; - -public class SchedulePhase extends Phase { - private ControlFlowGraph cfg; - private NodeMap earliestCache; - - /** - * Map from blocks to the nodes in each block. - */ - private BlockMap> blockToNodesMap; - - public SchedulePhase() { - super("Schedule"); - } - - @Override - protected void run(StructuredGraph graph) { - cfg = ControlFlowGraph.compute(graph, true, true, true, false); - earliestCache = graph.createNodeMap(); - blockToNodesMap = new BlockMap<>(cfg); - - assignBlockToNodes(graph); - sortNodesWithinBlocks(graph); - } - - /** - * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the scheduling built by @link {@link #run(StructuredGraph)}. - * This method should thus only be called when run has been successfully executed. - */ - public void scheduleGraph() { - assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; - for (Block block : cfg.getBlocks()) { - List nodeList = blockToNodesMap.get(block); - ScheduledNode last = null; - for (ScheduledNode node : nodeList) { - if (last != null) { - last.setScheduledNext(node); - } - last = node; - } - } - } - - public ControlFlowGraph getCFG() { - return cfg; - } - - /** - * Gets the map from each block to the nodes in the block. - */ - public BlockMap> getBlockToNodesMap() { - return blockToNodesMap; - } - - /** - * Gets the nodes in a given block. - */ - public List nodesFor(Block block) { - return blockToNodesMap.get(block); - } - - private void assignBlockToNodes(StructuredGraph graph) { - for (Block block : cfg.getBlocks()) { - List nodes = new ArrayList<>(); - assert blockToNodesMap.get(block) == null; - blockToNodesMap.put(block, nodes); - for (FixedNode node : block.getNodes()) { - nodes.add(node); - } - } - - for (Node n : graph.getNodes()) { - if (n instanceof ScheduledNode) { - assignBlockToNode((ScheduledNode) n); - } - } - } - - /** - * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are already assigned to a block. - */ - private void assignBlockToNode(ScheduledNode node) { - assert !node.isDeleted(); - - Block prevBlock = cfg.getNodeToBlock().get(node); - if (prevBlock != null) { - return; - } - // PhiNodes and FixedNodes should already have been placed in blocks by ControlFlowGraph.identifyBlocks - assert !(node instanceof PhiNode) : node; - assert !(node instanceof FixedNode) : node; - // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(node); - Block block; - if (latestBlock == null) { - block = earliestBlock(node); - } else if (GraalOptions.ScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(node); - block = scheduleOutOfLoops(node, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; - } else { - block = latestBlock; - } - cfg.getNodeToBlock().set(node, block); - blockToNodesMap.get(block).add(node); - } - - /** - * Calculates the last block that the given node could be scheduled in, i.e., the common dominator of all usages. - * To do so all usages are also assigned to blocks. - */ - private Block latestBlock(ScheduledNode node) { - CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); - for (Node succ : node.successors().nonNull()) { - assert cfg.getNodeToBlock().get(succ) != null; - cdbc.apply(cfg.getNodeToBlock().get(succ)); - } - ensureScheduledUsages(node); - for (Node usage : node.usages()) { - blocksForUsage(node, usage, cdbc); - } - return cdbc.block; - } - - /** - * A closure that will calculate the common dominator of all blocks passed to its {@link #apply(Block)} method. - */ - private static class CommonDominatorBlockClosure implements BlockClosure { - public Block block; - public CommonDominatorBlockClosure(Block block) { - this.block = block; - } - @Override - public void apply(Block newBlock) { - this.block = getCommonDominator(this.block, newBlock); - } - } - - /** - * Determines the earliest block in which the given node can be scheduled. - */ - private Block earliestBlock(Node node) { - Block earliest = cfg.getNodeToBlock().get(node); - if (earliest != null) { - return earliest; - } - earliest = earliestCache.get(node); - if (earliest != null) { - return earliest; - } - /* - * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This implies that the - * inputs' blocks have a total ordering via their dominance relation. So in order to find the earliest block - * placement for this node we need to find the input block that is dominated by all other input blocks. - * - * While iterating over the inputs a set of dominator blocks of the current earliest placement is maintained. - * When the block of an input is not within this set, it becomes the current earliest placement and the list of - * dominator blocks is updated. - */ - BitSet dominators = new BitSet(cfg.getBlocks().length); - - assert node.predecessor() == null; - for (Node input : node.inputs().nonNull()) { - assert input instanceof ValueNode; - Block inputEarliest = earliestBlock(input); - if (!dominators.get(inputEarliest.getId())) { - earliest = inputEarliest; - do { - dominators.set(inputEarliest.getId()); - inputEarliest = inputEarliest.getDominator(); - } while(inputEarliest != null && !dominators.get(inputEarliest.getId())); - } - } - if (earliest == null) { - earliest = cfg.getStartBlock(); - } - earliestCache.set(node, earliest); - return earliest; - } - - - private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) { - assert latestBlock != null : "no latest : " + n; - Block cur = latestBlock; - Block result = latestBlock; - while (cur.getLoop() != null && cur != earliest && cur.getDominator() != null) { - Block dom = cur.getDominator(); - if (dom.getLoopDepth() < result.getLoopDepth()) { - result = dom; - } - cur = dom; - } - return result; - } - - /** - * Passes all blocks that a specific usage of a node is in to a given closure. - * This is more complex than just taking the usage's block because of of PhiNodes and FrameStates. - * - * @param node the node that needs to be scheduled - * @param usage the usage whose blocks need to be considered - * @param closure the closure that will be called for each block - */ - private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { - assert !(node instanceof PhiNode); - - if (usage instanceof PhiNode) { - // An input to a PhiNode is used at the end of the predecessor block that corresponds to the PhiNode input. - // One PhiNode can use an input multiple times, the closure will be called for each usage. - PhiNode phi = (PhiNode) usage; - MergeNode merge = phi.merge(); - Block mergeBlock = cfg.getNodeToBlock().get(merge); - assert mergeBlock != null : "no block for merge " + merge.toString(Verbosity.Id); - for (int i = 0; i < phi.valueCount(); ++i) { - if (phi.valueAt(i) == node) { - if (mergeBlock.getPredecessors().size() <= i) { - TTY.println(merge.toString()); - TTY.println(phi.toString()); - TTY.println(merge.cfgPredecessors().toString()); - TTY.println(mergeBlock.getPredecessors().toString()); - TTY.println(phi.inputs().toString()); - TTY.println("value count: " + phi.valueCount()); - } - closure.apply(mergeBlock.getPredecessors().get(i)); - } - } - } else if (usage instanceof VirtualState) { - // The following logic does not work if node is a PhiNode, but this method is never called for PhiNodes. - for (Node unscheduledUsage : usage.usages()) { - if (unscheduledUsage instanceof VirtualState) { - // If a FrameState is an outer FrameState this method behaves as if the inner FrameState was the actual usage, by recursing. - blocksForUsage(node, unscheduledUsage, closure); - } else if (unscheduledUsage instanceof MergeNode) { - // Only FrameStates can be connected to MergeNodes. - assert usage instanceof FrameState; - // If a FrameState belongs to a MergeNode then it's inputs will be placed at the common dominator of all EndNodes. - for (Node pred : unscheduledUsage.cfgPredecessors()) { - closure.apply(cfg.getNodeToBlock().get(pred)); - } - } else { - // For the time being, only FrameStates can be connected to StateSplits. - assert usage instanceof FrameState; - assert unscheduledUsage instanceof StateSplit; - // Otherwise: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) unscheduledUsage); - closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); - } - } - } else { - // All other types of usages: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) usage); - closure.apply(cfg.getNodeToBlock().get(usage)); - } - } - - private void ensureScheduledUsages(Node node) { - for (Node usage : node.usages().filter(ScheduledNode.class)) { - assignBlockToNode((ScheduledNode) usage); - } - // now true usages are ready - } - - private static Block getCommonDominator(Block a, Block b) { - if (a == null) { - return b; - } - if (b == null) { - return a; - } - return ControlFlowGraph.commonDominator(a, b); - } - - private void sortNodesWithinBlocks(StructuredGraph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - for (Block b : cfg.getBlocks()) { - sortNodesWithinBlock(b, visited); - } - } - - /** - * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over all inputs. - * This means that a node is added to the list after all its inputs have been processed. - */ - private void sortNodesWithinBlock(Block b, NodeBitMap visited) { - List instructions = blockToNodesMap.get(b); - List sortedInstructions = new ArrayList<>(instructions.size() + 2); - - assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; - - for (ScheduledNode i : instructions) { - addToSorting(b, i, sortedInstructions, visited); - } - - // Make sure that last node gets really last (i.e. when a frame state successor hangs off it). - Node lastSorted = sortedInstructions.get(sortedInstructions.size() - 1); - if (lastSorted != b.getEndNode()) { - int idx = sortedInstructions.indexOf(b.getEndNode()); - boolean canNotMove = false; - for (int i = idx + 1; i < sortedInstructions.size(); i++) { - if (sortedInstructions.get(i).inputs().contains(b.getEndNode())) { - canNotMove = true; - break; - } - } - if (canNotMove) { - if (b.getEndNode() instanceof ControlSplitNode) { - throw new GraalInternalError("Schedule is not possible : needs to move a node after the last node of the block which can not be move"). - addContext(lastSorted). - addContext(b.getEndNode()); - } - - //b.setLastNode(lastSorted); - } else { - sortedInstructions.remove(b.getEndNode()); - sortedInstructions.add(b.getEndNode()); - } - } - blockToNodesMap.put(b, sortedInstructions); - } - - private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { - if (state != null) { - // UnscheduledNodes should never be marked as visited. - assert !visited.isMarked(state); - - for (Node input : state.inputs()) { - if (input instanceof VirtualState) { - addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); - } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); - } - } - } - } - - private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { - if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { - return; - } - - FrameState state = null; - WriteNode write = null; - for (Node input : i.inputs()) { - if (input instanceof WriteNode && !visited.isMarked(input) && cfg.getNodeToBlock().get(input) == b) { - assert write == null; - write = (WriteNode) input; - } else if (input instanceof FrameState) { - assert state == null; - state = (FrameState) input; - } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); - } - } - - addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); - visited.mark(i); - addUnscheduledToSorting(b, state, sortedInstructions, visited); - assert write == null || !visited.isMarked(write); - addToSorting(b, write, sortedInstructions, visited); - - // Now predecessors and inputs are scheduled => we can add this node. - sortedInstructions.add(i); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/ArrayMap.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/ArrayMap.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -/** - * The {@code ArrayMap} class implements an efficient one-level map which is implemented - * as an array. Note that because of the one-level array inside, this data structure performs best - * when the range of integer keys is small and densely used. Note that the implementation can - * handle arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. - */ -public class ArrayMap { - - private static final int INITIAL_SIZE = 5; // how big the initial array should be - private static final int EXTRA = 2; // how far on the left or right of a new element to grow - - Object[] map; - int low; - - /** - * Constructs a new {@code ArrayMap} with no initial assumptions. - */ - public ArrayMap() { - } - - /** - * Constructs a new {@code ArrayMap} that initially covers the specified interval. - * Note that this map will automatically expand if necessary later. - * @param low the low index, inclusive - * @param high the high index, exclusive - */ - public ArrayMap(int low, int high) { - this.low = low; - this.map = new Object[high - low + 1]; - } - - /** - * Puts a new value in the map at the specified index. - * @param i the index at which to store the value - * @param value the value to store at the specified index - */ - public void put(int i, T value) { - int index = i - low; - if (map == null) { - // no map yet - map = new Object[INITIAL_SIZE]; - low = index - 2; - map[INITIAL_SIZE / 2] = value; - } else if (index < 0) { - // grow backwards - growBackward(i, value); - } else if (index >= map.length) { - // grow forwards - growForward(i, value); - } else { - // no growth necessary - map[index] = value; - } - } - - /** - * Gets the value at the specified index in the map. - * @param i the index - * @return the value at the specified index; {@code null} if there is no value at the specified index, - * or if the index is out of the currently stored range - */ - public T get(int i) { - int index = i - low; - if (map == null || index < 0 || index >= map.length) { - return null; - } - Class type = null; - return Util.uncheckedCast(type, map[index]); - } - - public int length() { - return map.length; - } - - private void growBackward(int i, T value) { - int nlow = i - EXTRA; - Object[] nmap = new Object[low - nlow + map.length]; - System.arraycopy(map, 0, nmap, low - nlow, map.length); - map = nmap; - low = nlow; - map[i - low] = value; - } - - private void growForward(int i, T value) { - int nlen = i - low + 1 + EXTRA; - Object[] nmap = new Object[nlen]; - System.arraycopy(map, 0, nmap, 0, map.length); - map = nmap; - map[i - low] = value; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/BitMap2D.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/BitMap2D.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -/** - * This class implements a two-dimensional bitmap. - */ -public final class BitMap2D { - - private BitSet map; - private final int bitsPerSlot; - - private int bitIndex(int slotIndex, int bitWithinSlotIndex) { - return slotIndex * bitsPerSlot + bitWithinSlotIndex; - } - - private boolean verifyBitWithinSlotIndex(int index) { - assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; - return true; - } - - public BitMap2D(int sizeInSlots, int bitsPerSlot) { - map = new BitSet(sizeInSlots * bitsPerSlot); - this.bitsPerSlot = bitsPerSlot; - } - - public int sizeInBits() { - return map.size(); - } - - // Returns number of full slots that have been allocated - public int sizeInSlots() { - return map.size() / bitsPerSlot; - } - - public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); - } - - public boolean at(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void setBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.set(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void clearBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { - int size = sizeInSlots(); - if (size <= slotIndex) { - while (size <= slotIndex) { - size *= 2; - } - BitSet newBitMap = new BitSet(size * bitsPerSlot); - newBitMap.or(map); - map = newBitMap; - } - - if (value) { - setBit(slotIndex, bitWithinSlotIndex); - } else { - clearBit(slotIndex, bitWithinSlotIndex); - } - } - - public void clear() { - map.clear(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/BlockWorkList.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/BlockWorkList.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import com.oracle.graal.nodes.*; - -/** - * This class implements a worklist for dealing with blocks. The worklist can - * operate either as a stack (i.e. first-in / last-out), or as a sorted list, - * where blocks can be sorted by a supplied number. The latter usage lends itself - * naturally to iterative dataflow analysis problems. - */ -public class BlockWorkList { - MergeNode[] workList; - int[] workListNumbers; - int workListIndex; - - /** - * Adds a block to this list in an unsorted fashion, like a stack. - * @param block the block to add - */ - public void add(MergeNode block) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex++] = block; - } - - /** - * Adds a block to this list, sorted by the supplied number. The block - * with the lowest number is returned upon subsequent removes. - * @param block the block to add - * @param number the number used to sort the block - */ - public void addSorted(MergeNode block, int number) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex] = block; - workListNumbers[workListIndex] = number; - workListIndex++; - int i = workListIndex - 2; - // push block towards the beginning of the array - for (; i >= 0; i--) { - int n = workListNumbers[i]; - if (n >= number) { - break; // already in the right position - } - workList[i + 1] = workList[i]; // bubble b down by one - workList[i] = block; // and overwrite its place with block - workListNumbers[i + 1] = n; // bubble n down by one - workListNumbers[i] = number; // and overwrite its place with number - } - } - - /** - * Removes the next block from this work list. If the blocks have been added - * in a sorted order, then the block with the lowest number is returned. Otherwise, - * the last block added is returned. - * @return the next block in the list - */ - public MergeNode removeFromWorkList() { - if (workListIndex != 0) { - return workList[--workListIndex]; - } - return null; - } - - /** - * Checks whether the list is empty. - * @return {@code true} if this list is empty - */ - public boolean isEmpty() { - return workListIndex == 0; - } - - private void allocate() { - workList = new MergeNode[5]; - workListNumbers = new int[5]; - } - - private void grow() { - int prevLength = workList.length; - MergeNode[] nworkList = new MergeNode[prevLength * 3]; - System.arraycopy(workList, 0, nworkList, 0, prevLength); - workList = nworkList; - - int[] nworkListNumbers = new int[prevLength * 3]; - System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength); - workListNumbers = nworkListNumbers; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/GraphOrder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/GraphOrder.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2011, 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.util; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -public class GraphOrder implements Iterable { - - private final ArrayList nodes = new ArrayList<>(); - - private GraphOrder() { - } - - public GraphOrder(Graph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { - visitForward(visited, node); - } - } - - public static GraphOrder forwardGraph(Graph graph) { - GraphOrder result = new GraphOrder(); - - NodeBitMap visited = graph.createNodeBitMap(); - - for (ReturnNode node : graph.getNodes(ReturnNode.class)) { - result.visitForward(visited, node); - } - for (UnwindNode node : graph.getNodes(UnwindNode.class)) { - result.visitForward(visited, node); - } - for (DeoptimizeNode node : graph.getNodes(DeoptimizeNode.class)) { - result.visitForward(visited, node); - } - return result; - } - - public static GraphOrder backwardGraph(Graph graph) { - GraphOrder result = new GraphOrder(); - - NodeBitMap visited = graph.createNodeBitMap(); - - for (Node node : forwardGraph(graph)) { - result.visitBackward(visited, node); - } - return result; - } - - private void visitForward(NodeBitMap visited, Node node) { - if (node != null && !visited.isMarked(node)) { - visited.mark(node); - if (node.predecessor() != null) { - visitForward(visited, node.predecessor()); - } - if (node instanceof MergeNode) { - // make sure that the cfg predecessors of a MergeNode are processed first - MergeNode merge = (MergeNode) node; - for (int i = 0; i < merge.forwardEndCount(); i++) { - visitForward(visited, merge.forwardEndAt(i)); - } - } - for (Node input : node.inputs()) { - visitForward(visited, input); - } - nodes.add(node); - } - } - - private void visitBackward(NodeBitMap visited, Node node) { - if (node != null && !visited.isMarked(node)) { - visited.mark(node); - for (Node successor : node.successors()) { - visitBackward(visited, successor); - } - for (Node usage : node.usages()) { - visitBackward(visited, usage); - } - nodes.add(node); - } - } - - @Override - public Iterator iterator() { - return new Iterator() { - - private int pos = 0; - - private void removeDeleted() { - while (pos < nodes.size() && nodes.get(pos).isDeleted()) { - pos++; - } - } - - @Override - public boolean hasNext() { - removeDeleted(); - return pos < nodes.size(); - } - - @Override - public Node next() { - return nodes.get(pos++); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d 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 Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,954 +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.compiler.util; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.FrameState.InliningIdentifier; -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.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -public class InliningUtil { - - private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication"); - - public interface InliningCallback { - StructuredGraph buildGraph(ResolvedJavaMethod method); - double inliningWeight(ResolvedJavaMethod caller, ResolvedJavaMethod method, Invoke invoke); - void recordMethodContentsAssumption(ResolvedJavaMethod method); - void recordConcreteMethodAssumption(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl); - } - - public static String methodName(ResolvedJavaMethod method, Invoke invoke) { - if (!Debug.isLogEnabled()) { - return null; - } else if (invoke != null && invoke.stateAfter() != null) { - return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; - } else { - return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.codeSize() + " bytes)"; - } - } - - public static String methodName(InlineInfo info) { - if (!Debug.isLogEnabled()) { - return null; - } else if (info.invoke != null && info.invoke.stateAfter() != null) { - return methodName(info.invoke.stateAfter(), info.invoke.bci()) + ": " + info.toString(); - } else { - return info.toString(); - } - } - - private static String methodName(FrameState frameState, int bci) { - StringBuilder sb = new StringBuilder(); - if (frameState.outerFrameState() != null) { - sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci)); - sb.append("->"); - } - sb.append(MetaUtil.format("%h.%n", frameState.method())); - sb.append("@").append(bci); - return sb.toString(); - } - - /** - * 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. - * The level is the number of nested inlinings that lead to this invoke. - */ - public abstract static class InlineInfo implements Comparable { - public final Invoke invoke; - public final double weight; - public final int level; - - public InlineInfo(Invoke invoke, double weight, int level) { - this.invoke = invoke; - this.weight = weight; - this.level = level; - } - - public abstract int compiledCodeSize(); - - @Override - public int compareTo(InlineInfo o) { - return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0; - } - - protected static StructuredGraph getGraph(final ResolvedJavaMethod concrete, final InliningCallback callback) { - return Debug.scope("GetInliningGraph", concrete, new Callable() { - @Override - public StructuredGraph call() throws Exception { - return callback.buildGraph(concrete); - } - }); - } - - public abstract boolean canDeopt(); - - /** - * Performs the inlining described by this object and returns the node that represents the return value of the - * inlined method (or null for void methods and methods that have no non-exceptional exit). - * - * @param graph - * @param runtime - * @param callback - */ - public abstract void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback); - } - - /** - * Represents an inlining opportunity where the compiler can statically determine a monomorphic target method and - * therefore is able to determine the called method exactly. - */ - private static class ExactInlineInfo extends InlineInfo { - public final ResolvedJavaMethod concrete; - - public ExactInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete) { - super(invoke, weight, level); - this.concrete = concrete; - } - - @Override - public void inline(StructuredGraph compilerGraph, GraalCodeCacheProvider runtime, final InliningCallback callback) { - StructuredGraph graph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, graph, true); - } - - @Override - public int compiledCodeSize() { - return concrete.compiledCodeSize(); - } - - @Override - public String toString() { - return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return false; - } - } - - /** - * Represents an inlining opportunity for which profiling information suggests a monomorphic receiver, but for which - * the receiver type cannot be proven. A type check guard will be generated if this inlining is performed. - */ - private static class TypeGuardInlineInfo extends InlineInfo { - public final ResolvedJavaMethod concrete; - public final ResolvedJavaType type; - - public TypeGuardInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaMethod concrete, ResolvedJavaType type) { - super(invoke, weight, level); - this.concrete = concrete; - this.type = type; - } - - @Override - public int compiledCodeSize() { - return concrete.compiledCodeSize(); - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - // receiver null check must be before the type check - InliningUtil.receiverNullCheck(invoke); - ValueNode receiver = invoke.methodCallTarget().receiver(); - ReadHubNode objectClass = graph.add(new ReadHubNode(receiver)); - IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type)); - FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, invoke.leafGraphId())); - ValueAnchorNode anchor = graph.add(new ValueAnchorNode()); - assert invoke.predecessor() != null; - - ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true); - invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); - - graph.addBeforeFixed(invoke.node(), objectClass); - graph.addBeforeFixed(invoke.node(), guard); - graph.addBeforeFixed(invoke.node(), anchor); - - StructuredGraph calleeGraph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, calleeGraph, false); - } - - @Override - public String toString() { - return "type-checked " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - /** - * Polymorphic inlining of m methods with n type checks (n >= m) in case that the profiling information suggests a reasonable - * amounts of different receiver types and different methods. If an unknown type is encountered a deoptimization is triggered. - */ - private static class MultiTypeGuardInlineInfo extends InlineInfo { - public final List concretes; - public final ProfiledType[] ptypes; - public final int[] typesToConcretes; - public final double notRecordedTypeProbability; - - public MultiTypeGuardInlineInfo(Invoke invoke, double weight, int level, List concretes, ProfiledType[] ptypes, - int[] typesToConcretes, double notRecordedTypeProbability) { - super(invoke, weight, level); - assert concretes.size() > 0 && concretes.size() <= ptypes.length : "must have at least one method but no more than types methods"; - assert ptypes.length == typesToConcretes.length : "array lengths must match"; - - this.concretes = concretes; - this.ptypes = ptypes; - this.typesToConcretes = typesToConcretes; - this.notRecordedTypeProbability = notRecordedTypeProbability; - } - - @Override - public int compiledCodeSize() { - int result = 0; - for (ResolvedJavaMethod m: concretes) { - result += m.compiledCodeSize(); - } - return result; - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - int numberOfMethods = concretes.size(); - boolean hasReturnValue = invoke.node().kind() != Kind.Void; - - // receiver null check must be the first node - InliningUtil.receiverNullCheck(invoke); - if (numberOfMethods > 1 || shouldFallbackToInvoke()) { - inlineMultipleMethods(graph, runtime, callback, numberOfMethods, hasReturnValue); - } else { - inlineSingleMethod(graph, runtime, callback); - } - } - - private boolean shouldFallbackToInvoke() { - return notRecordedTypeProbability > 0; - } - - private void inlineMultipleMethods(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback, int numberOfMethods, boolean hasReturnValue) { - FixedNode continuation = invoke.next(); - - ValueNode originalReceiver = invoke.methodCallTarget().receiver(); - // setup merge and phi nodes for results and exceptions - MergeNode returnMerge = graph.add(new MergeNode()); - returnMerge.setProbability(invoke.probability()); - returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci)); - - PhiNode returnValuePhi = null; - if (hasReturnValue) { - returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge)); - } - - MergeNode exceptionMerge = null; - PhiNode exceptionObjectPhi = null; - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - - exceptionMerge = graph.add(new MergeNode()); - exceptionMerge.setProbability(exceptionEdge.probability()); - - FixedNode exceptionSux = exceptionObject.next(); - graph.addBeforeFixed(exceptionSux, exceptionMerge); - exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge)); - exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Void, exceptionObjectPhi)); - } - - // create one separate block for each invoked method - BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods]; - for (int i = 0; i < numberOfMethods; i++) { - int predecessors = 0; - double probability = 0; - for (int j = 0; j < typesToConcretes.length; j++) { - if (typesToConcretes[j] == i) { - predecessors++; - probability += ptypes[j].probability; - } - } - - calleeEntryNodes[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, predecessors, invoke.probability() * probability, true); - } - - // create the successor for an unknown type - FixedNode unknownTypeNode; - if (shouldFallbackToInvoke()) { - unknownTypeNode = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, 1, notRecordedTypeProbability, false); - } else { - unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); - } - - // replace the invoke exception edge - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke; - BeginNode exceptionEdge = invokeWithExceptionNode.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - exceptionObject.replaceAtUsages(exceptionObjectPhi); - exceptionObject.setNext(null); - GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge()); - } - - // replace the invoke with a switch on the type of the actual receiver - ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.methodCallTarget().receiver())); - graph.addBeforeFixed(invoke.node(), objectClassNode); - FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, calleeEntryNodes, unknownTypeNode); - - assert invoke.next() == continuation; - invoke.setNext(null); - returnMerge.setNext(continuation); - invoke.node().replaceAtUsages(returnValuePhi); - invoke.node().replaceAndDelete(dispatchOnType); - - ArrayList replacements = new ArrayList<>(); - - // do the actual inlining for every invoke - for (int i = 0; i < calleeEntryNodes.length; i++) { - BeginNode node = calleeEntryNodes[i]; - Invoke invokeForInlining = (Invoke) node.next(); - - ResolvedJavaType commonType = getLeastCommonType(i); - ValueNode receiver = invokeForInlining.methodCallTarget().receiver(); - boolean exact = getTypeCount(i) == 1; - PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); - invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); - - ResolvedJavaMethod concrete = concretes.get(i); - StructuredGraph calleeGraph = getGraph(concrete, callback); - callback.recordMethodContentsAssumption(concrete); - assert !IntrinsificationPhase.canIntrinsify(invokeForInlining, concrete, runtime); - InliningUtil.inline(invokeForInlining, calleeGraph, false); - replacements.add(anchoredReceiver); - } - if (shouldFallbackToInvoke()) { - replacements.add(null); - } - if (GraalOptions.OptTailDuplication) { - /* - * We might want to perform tail duplication at the merge after a type switch, if there are invokes that would - * benefit from the improvement in type information. - */ - FixedNode current = returnMerge; - int opportunities = 0; - do { - if (current instanceof InvokeNode && ((InvokeNode) current).methodCallTarget().receiver() == originalReceiver) { - opportunities++; - } else if (current.inputs().contains(originalReceiver)) { - opportunities++; - } - current = ((FixedWithNextNode) current).next(); - } while (current instanceof FixedWithNextNode); - if (opportunities > 0) { - metricInliningTailDuplication.increment(); - Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements); - } - } - } - - private int getTypeCount(int concreteMethodIndex) { - int count = 0; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { - count++; - } - } - return count; - } - - private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) { - ResolvedJavaType commonType = null; - for (int i = 0; i < typesToConcretes.length; i++) { - if (typesToConcretes[i] == concreteMethodIndex) { - if (commonType == null) { - commonType = ptypes[i].type; - } else { - commonType = commonType.leastCommonAncestor(ptypes[i].type); - } - } - } - assert commonType != null; - return commonType; - } - - private void inlineSingleMethod(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - assert concretes.size() == 1 && ptypes.length > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; - - MergeNode calleeEntryNode = graph.add(new MergeNode()); - calleeEntryNode.setProbability(invoke.probability()); - ReadHubNode objectClassNode = graph.add(new ReadHubNode(invoke.methodCallTarget().receiver())); - graph.addBeforeFixed(invoke.node(), objectClassNode); - - FixedNode unknownTypeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated, invoke.leafGraphId())); - FixedNode dispatchOnType = createDispatchOnType(graph, objectClassNode, new BeginNode[] {calleeEntryNode}, unknownTypeNode); - - FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); - pred.setNext(dispatchOnType); - calleeEntryNode.setNext(invoke.node()); - - ResolvedJavaMethod concrete = concretes.get(0); - StructuredGraph calleeGraph = getGraph(concrete, callback); - assert !IntrinsificationPhase.canIntrinsify(invoke, concrete, runtime); - callback.recordMethodContentsAssumption(concrete); - InliningUtil.inline(invoke, calleeGraph, false); - } - - private FixedNode createDispatchOnType(StructuredGraph graph, ReadHubNode objectClassNode, BeginNode[] calleeEntryNodes, FixedNode unknownTypeSux) { - assert ptypes.length > 1; - - ResolvedJavaType[] types = new ResolvedJavaType[ptypes.length]; - double[] probabilities = new double[ptypes.length + 1]; - BeginNode[] successors = new BeginNode[ptypes.length + 1]; - int[] keySuccessors = new int[ptypes.length + 1]; - for (int i = 0; i < ptypes.length; i++) { - types[i] = ptypes[i].type; - probabilities[i] = ptypes[i].probability; - FixedNode entry = calleeEntryNodes[typesToConcretes[i]]; - if (entry instanceof MergeNode) { - EndNode endNode = graph.add(new EndNode()); - ((MergeNode) entry).addForwardEnd(endNode); - entry = endNode; - } - successors[i] = BeginNode.begin(entry); - keySuccessors[i] = i; - } - assert !(unknownTypeSux instanceof MergeNode); - successors[successors.length - 1] = BeginNode.begin(unknownTypeSux); - probabilities[successors.length - 1] = notRecordedTypeProbability; - keySuccessors[successors.length - 1] = successors.length - 1; - - TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(objectClassNode, successors, probabilities, types, probabilities, keySuccessors)); - - return typeSwitch; - } - - private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, - MergeNode exceptionMerge, PhiNode exceptionObjectPhi, int predecessors, double probability, boolean useForInlining) { - Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability); - BeginNode calleeEntryNode = graph.add(predecessors > 1 ? new MergeNode() : new BeginNode()); - calleeEntryNode.setNext(duplicatedInvoke.node()); - calleeEntryNode.setProbability(probability); - - EndNode endNode = graph.add(new EndNode()); - endNode.setProbability(probability); - - duplicatedInvoke.setNext(endNode); - returnMerge.addForwardEnd(endNode); - - if (returnValuePhi != null) { - returnValuePhi.addInput(duplicatedInvoke.node()); - } - return calleeEntryNode; - } - - private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) { - Invoke result = (Invoke) invoke.node().copyWithInputs(); - Node callTarget = result.callTarget().copyWithInputs(); - result.node().replaceFirstInput(result.callTarget(), callTarget); - result.setUseForInlining(useForInlining); - result.setProbability(probability); - - Kind kind = invoke.node().kind(); - if (!kind.isVoid()) { - FrameState stateAfter = invoke.stateAfter(); - stateAfter = stateAfter.duplicate(stateAfter.bci); - stateAfter.replaceFirstInput(invoke.node(), result.node()); - result.setStateAfter(stateAfter); - } - - if (invoke instanceof InvokeWithExceptionNode) { - assert exceptionMerge != null && exceptionObjectPhi != null; - - InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - BeginNode exceptionEdge = invokeWithException.exceptionEdge(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); - FrameState stateAfterException = exceptionObject.stateAfter(); - - BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); - ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); - // set new state (pop old exception object, push new one) - newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject)); - newExceptionEdge.setNext(newExceptionObject); - - EndNode endNode = graph.add(new EndNode()); - newExceptionObject.setNext(endNode); - exceptionMerge.addForwardEnd(endNode); - exceptionObjectPhi.addInput(newExceptionObject); - - ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge); - } - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic"); - builder.append(String.format(", %d methods with %d type checks:", concretes.size(), ptypes.length)); - for (int i = 0; i < concretes.size(); i++) { - builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i))); - } - return builder.toString(); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - - /** - * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic target method, - * but for which an assumption has to be registered because of non-final classes. - */ - private static class AssumptionInlineInfo extends ExactInlineInfo { - public final ResolvedJavaType context; - - public AssumptionInlineInfo(Invoke invoke, double weight, int level, ResolvedJavaType context, ResolvedJavaMethod concrete) { - super(invoke, weight, level, concrete); - this.context = context; - } - - @Override - public void inline(StructuredGraph graph, GraalCodeCacheProvider runtime, InliningCallback callback) { - if (Debug.isLogEnabled()) { - String targetName = MetaUtil.format("%H.%n(%p):%r", invoke.methodCallTarget().targetMethod()); - String concreteName = MetaUtil.format("%H.%n(%p):%r", concrete); - Debug.log("recording concrete method assumption: %s on receiver type %s -> %s", targetName, context, concreteName); - } - callback.recordConcreteMethodAssumption(invoke.methodCallTarget().targetMethod(), context, concrete); - - super.inline(graph, runtime, callback); - } - - @Override - public String toString() { - return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete); - } - - @Override - public boolean canDeopt() { - return true; - } - } - - /** - * Determines if inlining is possible at the given invoke node. - * @param invoke the invoke that should be inlined - * @param level the number of nested inlinings that lead to this invoke, or 0 if the invoke was part of the initial graph - * @param runtime a GraalRuntime instance used to determine of the invoke can be inlined and/or should be intrinsified - * @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, GraalCodeCacheProvider runtime, Assumptions assumptions, InliningCallback callback, OptimisticOptimizations optimisticOpts) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - // The invoke has already been lowered , or has been created as a low-level node. We have no method information. - return null; - } - ResolvedJavaMethod parent = invoke.stateAfter().method(); - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (targetMethod == null) { - return null; - } - if (!checkInvokeConditions(invoke)) { - return null; - } - - if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - if (checkTargetConditions(invoke, targetMethod, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, targetMethod, invoke); - return new ExactInlineInfo(invoke, weight, level, targetMethod); - } - return null; - } - ObjectStamp receiverStamp = callTarget.receiver().objectStamp(); - ResolvedJavaType receiverType = receiverStamp.type(); - if (receiverStamp.isExactType()) { - assert receiverType.isSubtypeOf(targetMethod.holder()) : receiverType + " subtype of " + targetMethod.holder() + " for " + targetMethod; - ResolvedJavaMethod resolved = receiverType.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, resolved, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, resolved, invoke); - return new ExactInlineInfo(invoke, weight, level, resolved); - } - return null; - } - ResolvedJavaType holder = targetMethod.holder(); - - if (receiverStamp.type() != null) { - // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...) - // TODO (lstadler) fix this - if (receiverType != null && receiverType.isSubtypeOf(holder)) { - holder = receiverType; - } - } - // TODO (thomaswue) fix this - if (assumptions != null) { - ResolvedJavaMethod concrete = holder.uniqueConcreteMethod(targetMethod); - if (concrete != null) { - if (checkTargetConditions(invoke, concrete, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new AssumptionInlineInfo(invoke, weight, level, holder, concrete); - } - return null; - } - } - - // type check based inlining - return getTypeCheckedInlineInfo(invoke, level, callback, parent, targetMethod, optimisticOpts); - } - - private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, int level, InliningCallback callback, ResolvedJavaMethod parent, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { - ProfilingInfo profilingInfo = parent.profilingInfo(); - JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); - if (typeProfile != null) { - ProfiledType[] ptypes = typeProfile.getTypes(); - - if (ptypes != null && ptypes.length > 0) { - double notRecordedTypeProbability = typeProfile.getNotRecordedProbability(); - if (ptypes.length == 1 && notRecordedTypeProbability == 0) { - if (optimisticOpts.inlineMonomorphicCalls()) { - ResolvedJavaType type = ptypes[0].type; - ResolvedJavaMethod concrete = type.resolveMethodImpl(targetMethod); - if (checkTargetConditions(invoke, concrete, optimisticOpts)) { - double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); - } - - Debug.log("not inlining %s because method can't be inlined", methodName(targetMethod, invoke)); - return null; - } else { - Debug.log("not inlining %s because GraalOptions.InlineMonomorphicCalls == false", methodName(targetMethod, invoke)); - return null; - } - } else { - invoke.setMegamorphic(true); - 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 - // 3. do the inlining - // a) all seen methods can be inlined -> do so and guard with deopt - // b) some methods can be inlined -> inline them and fall back to invocation if violated - // TODO (chaeubl) sort types by probability - - // determine concrete methods and map type to specific method - ArrayList concreteMethods = new ArrayList<>(); - int[] typesToConcretes = new int[ptypes.length]; - for (int i = 0; i < ptypes.length; i++) { - ResolvedJavaMethod concrete = ptypes[i].type.resolveMethodImpl(targetMethod); - - int index = concreteMethods.indexOf(concrete); - if (index < 0) { - index = concreteMethods.size(); - concreteMethods.add(concrete); - } - typesToConcretes[i] = index; - } - - double totalWeight = 0; - boolean canInline = true; - for (ResolvedJavaMethod concrete: concreteMethods) { - if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { - canInline = false; - break; - } - totalWeight += callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); - } - - if (canInline) { - return new MultiTypeGuardInlineInfo(invoke, totalWeight, level, concreteMethods, ptypes, typesToConcretes, notRecordedTypeProbability); - } else { - Debug.log("not inlining %s because it is a polymorphic method call and at least one invoked method cannot be inlined", methodName(targetMethod, invoke)); - return null; - } - } else { - 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)); - } - return null; - } - } - } - - Debug.log("not inlining %s because no types/probabilities were recorded", methodName(targetMethod, invoke)); - return null; - } else { - Debug.log("not inlining %s because no type profile exists", methodName(targetMethod, invoke)); - return null; - } - } - - private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { - // to avoid that floating reads on receiver fields float above the type check - return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType))); - } - - private static boolean checkInvokeConditions(Invoke invoke) { - if (invoke.stateAfter() == null) { - Debug.log("not inlining %s because the invoke has no after state", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - if (invoke.predecessor() == null) { - Debug.log("not inlining %s because the invoke is dead code", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - if (!invoke.useForInlining()) { - Debug.log("not inlining %s because invoke is marked to be not used for inlining", methodName(invoke.methodCallTarget().targetMethod(), invoke)); - return false; - } - return true; - } - - private static boolean checkTargetConditions(Invoke invoke, JavaMethod method, OptimisticOptimizations optimisticOpts) { - if (method == null) { - Debug.log("not inlining because method is not resolved"); - return false; - } - if (!(method instanceof ResolvedJavaMethod)) { - Debug.log("not inlining %s because it is unresolved", method.toString()); - return false; - } - ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method; - if (Modifier.isNative(resolvedMethod.accessFlags())) { - 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, invoke)); - return false; - } - if (!resolvedMethod.holder().isInitialized()) { - 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, invoke)); - return false; - } - if (computeRecursiveInliningLevel(invoke.stateAfter(), (ResolvedJavaMethod) method) > GraalOptions.MaximumRecursiveInlining) { - 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; - } - - return true; - } - - private static int computeRecursiveInliningLevel(FrameState state, ResolvedJavaMethod method) { - assert state != null; - - int count = 0; - FrameState curState = state; - while (curState != null) { - if (curState.method() == method) { - count++; - } - curState = curState.outerFrameState(); - } - return count; - } - - /** - * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. - * - * @param invoke the invoke that will be replaced - * @param inlineGraph the graph that the invoke will be replaced with - * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required - */ - public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { - InliningIdentifier identifier = new InliningIdentifier(inlineGraph.method(), invoke); - NodeInputList parameters = invoke.callTarget().arguments(); - StructuredGraph graph = (StructuredGraph) invoke.node().graph(); - - FrameState stateAfter = invoke.stateAfter(); - assert stateAfter.isAlive(); - - IdentityHashMap replacements = new IdentityHashMap<>(); - ArrayList nodes = new ArrayList<>(); - ReturnNode returnNode = null; - UnwindNode unwindNode = null; - StartNode entryPointNode = inlineGraph.start(); - FixedNode firstCFGNode = entryPointNode.next(); - for (Node node : inlineGraph.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else if (node instanceof LocalNode) { - replacements.put(node, parameters.get(((LocalNode) node).index())); - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - assert returnNode == null; - returnNode = (ReturnNode) node; - } else if (node instanceof UnwindNode) { - assert unwindNode == null; - unwindNode = (UnwindNode) node; - } - } - } - replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode - - assert invoke.node().successors().first() != null : invoke; - assert invoke.node().predecessor() != null; - - Map duplicates = graph.addDuplicates(nodes, replacements); - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - if (receiverNullCheck) { - receiverNullCheck(invoke); - } - invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate); - - FrameState stateAtExceptionEdge = null; - if (invoke instanceof InvokeWithExceptionNode) { - InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke); - if (unwindNode != null) { - assert unwindNode.predecessor() != null; - assert invokeWithException.exceptionEdge().successors().count() == 1; - ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge().next(); - stateAtExceptionEdge = obj.stateAfter(); - UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - obj.replaceAtUsages(unwindDuplicate.exception()); - unwindDuplicate.clearInputs(); - Node n = obj.next(); - obj.setNext(null); - unwindDuplicate.replaceAndDelete(n); - } else { - invokeWithException.killExceptionEdge(); - } - } else { - if (unwindNode != null) { - UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); - DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler, invoke.leafGraphId()); - 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!) - if (deoptimizeNode.predecessor() instanceof MonitorExitNode) { - MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor(); - if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) { - FrameState monitorFrameState = monitorExit.stateAfter(); - graph.removeFixed(monitorExit); - monitorFrameState.safeDelete(); - } - } - } - } - - FrameState outerFrameState = null; - double invokeProbability = invoke.node().probability(); - for (Node node : duplicates.values()) { - if (GraalOptions.ProbabilityAnalysis) { - if (node instanceof FixedNode) { - FixedNode fixed = (FixedNode) node; - double newProbability = fixed.probability() * invokeProbability; - if (GraalOptions.LimitInlinedProbability) { - newProbability = Math.min(newProbability, invokeProbability); - } - fixed.setProbability(newProbability); - } - } - if (node instanceof FrameState) { - FrameState frameState = (FrameState) node; - assert frameState.bci != FrameState.BEFORE_BCI; - if (frameState.bci == FrameState.AFTER_BCI) { - frameState.replaceAndDelete(stateAfter); - } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { - if (frameState.isAlive()) { - assert stateAtExceptionEdge != null; - frameState.replaceAndDelete(stateAtExceptionEdge); - } else { - assert stateAtExceptionEdge == null; - } - } else { - if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); - outerFrameState.setDuringCall(true); - } - frameState.setOuterFrameState(outerFrameState); - frameState.setInliningIdentifier(identifier); - } - } - } - - Node returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = replacements.get(returnNode.result()); - } else { - returnValue = duplicates.get(returnNode.result()); - } - invoke.node().replaceAtUsages(returnValue); - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.clearInputs(); - Node n = invoke.next(); - invoke.setNext(null); - returnDuplicate.replaceAndDelete(n); - } - - invoke.node().clearInputs(); - invoke.node().replaceAtUsages(null); - GraphUtil.killCFG(invoke.node()); - - if (stateAfter.usages().isEmpty()) { - stateAfter.safeDelete(); - } - } - - public static void receiverNullCheck(Invoke invoke) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - StructuredGraph graph = (StructuredGraph) invoke.graph(); - NodeInputList parameters = callTarget.arguments(); - ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); - if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) { - graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, true, invoke.leafGraphId()))); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/IntList.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/IntList.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -/** - * An expandable and indexable list of {@code int}s. - * - * This class avoids the boxing/unboxing incurred by {@code ArrayList}. - */ -public final class IntList { - - private int[] array; - private int size; - - /** - * Creates an int list with a specified initial capacity. - * - * @param initialCapacity - */ - public IntList(int initialCapacity) { - array = new int[initialCapacity]; - } - - /** - * Creates an int list with a specified initial array. - * - * @param array the initial array used for the list (no copy is made) - * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or equal to {@code array.length} - */ - public IntList(int[] array, int initialSize) { - assert initialSize <= array.length; - this.array = array; - this.size = initialSize; - } - - /** - * Makes a new int list by copying a range from a given int list. - * - * @param other the list from which a range of values is to be copied into the new list - * @param startIndex the index in {@code other} at which to start copying - * @param length the number of values to copy from {@code other} - * @return a new int list whose {@linkplain #size() size} and capacity is {@code length} - */ - public static IntList copy(IntList other, int startIndex, int length) { - return copy(other, startIndex, length, length); - } - - /** - * Makes a new int list by copying a range from a given int list. - * - * @param other the list from which a range of values is to be copied into the new list - * @param startIndex the index in {@code other} at which to start copying - * @param length the number of values to copy from {@code other} - * @param initialCapacity the initial capacity of the new int list (must be greater or equal to {@code length}) - * @return a new int list whose {@linkplain #size() size} is {@code length} - */ - public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) { - assert initialCapacity >= length : "initialCapacity < length"; - int[] array = new int[initialCapacity]; - System.arraycopy(other.array, startIndex, array, 0, length); - return new IntList(array, length); - } - - public int size() { - return size; - } - - /** - * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1. - * - * @param value the value to append - */ - public void add(int value) { - if (size == array.length) { - int newSize = (size * 3) / 2 + 1; - array = Arrays.copyOf(array, newSize); - } - array[size++] = value; - } - - /** - * Gets the value in this list at a given index. - * - * @param index the index of the element to return - * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} - */ - public int get(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - return array[index]; - } - - /** - * Sets the size of this list to 0. - */ - public void clear() { - size = 0; - } - - /** - * Sets a value at a given index in this list. - * - * @param index the index of the element to update - * @param value the new value of the element - * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} - */ - public void set(int index, int value) { - if (index >= size) { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - array[index] = value; - } - - /** - * Adjusts the {@linkplain #size() size} of this int list. - * - * If {@code newSize < size()}, the size is changed to {@code newSize}. - * If {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} - * until {@code size() == newSize}. - * - * @param newSize the new size of this int list - */ - public void setSize(int newSize) { - if (newSize < size) { - size = newSize; - } else if (newSize > size) { - array = Arrays.copyOf(array, newSize); - } - } - - @Override - public String toString() { - if (array.length == size) { - return Arrays.toString(array); - } - return Arrays.toString(Arrays.copyOf(array, size)); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.util; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.max.criutils.*; - -/** - * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. - */ -public class Util { - - public static final int PRINTING_LINE_WIDTH = 40; - public static final char SECTION_CHARACTER = '*'; - public static final char SUB_SECTION_CHARACTER = '='; - public static final char SEPERATOR_CHARACTER = '-'; - - public static boolean replaceInList(T a, T b, List list) { - final int max = list.size(); - for (int i = 0; i < max; i++) { - if (list.get(i) == a) { - list.set(i, b); - return true; - } - } - return false; - } - - /** - * Statically cast an object to an arbitrary Object type. Dynamically checked. - */ - @SuppressWarnings("unchecked") - public static T uncheckedCast(@SuppressWarnings("unused") Class type, Object object) { - return (T) object; - } - - /** - * Statically cast an object to an arbitrary Object type. Dynamically checked. - */ - @SuppressWarnings("unchecked") - public static T uncheckedCast(Object object) { - return (T) object; - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the object to add to the hash - * @return the combined hash - */ - public static int hash1(int hash, Object x) { - // always set at least one bit in case the hash wraps to zero - return 0x10000000 | (hash + 7 * System.identityHashCode(x)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @return the combined hash - */ - public static int hash2(int hash, Object x, Object y) { - // always set at least one bit in case the hash wraps to zero - return 0x20000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @param z the third object to add to the hash - * @return the combined hash - */ - public static int hash3(int hash, Object x, Object y, Object z) { - // always set at least one bit in case the hash wraps to zero - return 0x30000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @param z the third object to add to the hash - * @param w the fourth object to add to the hash - * @return the combined hash - */ - public static int hash4(int hash, Object x, Object y, Object z, Object w) { - // always set at least one bit in case the hash wraps to zero - return 0x40000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z) + 17 * System.identityHashCode(w)); - } - - static { - assert CodeUtil.log2(2) == 1; - assert CodeUtil.log2(4) == 2; - assert CodeUtil.log2(8) == 3; - assert CodeUtil.log2(16) == 4; - assert CodeUtil.log2(32) == 5; - assert CodeUtil.log2(0x40000000) == 30; - - assert CodeUtil.log2(2L) == 1; - assert CodeUtil.log2(4L) == 2; - assert CodeUtil.log2(8L) == 3; - assert CodeUtil.log2(16L) == 4; - assert CodeUtil.log2(32L) == 5; - assert CodeUtil.log2(0x4000000000000000L) == 62; - - assert !CodeUtil.isPowerOf2(3); - assert !CodeUtil.isPowerOf2(5); - assert !CodeUtil.isPowerOf2(7); - assert !CodeUtil.isPowerOf2(-1); - - assert CodeUtil.isPowerOf2(2); - assert CodeUtil.isPowerOf2(4); - assert CodeUtil.isPowerOf2(8); - assert CodeUtil.isPowerOf2(16); - assert CodeUtil.isPowerOf2(32); - assert CodeUtil.isPowerOf2(64); - } - - /** - * Sets the element at a given position of a list and ensures that this position exists. If the list is current - * shorter than the position, intermediate positions are filled with a given value. - * - * @param list the list to put the element into - * @param pos the position at which to insert the element - * @param x the element that should be inserted - * @param filler the filler element that is used for the intermediate positions in case the list is shorter than pos - */ - public static void atPutGrow(List list, int pos, T x, T filler) { - if (list.size() < pos + 1) { - while (list.size() < pos + 1) { - list.add(filler); - } - assert list.size() == pos + 1; - } - - assert list.size() >= pos + 1; - list.set(pos, x); - } - - public static void breakpoint() { - // do nothing. - } - - public static void guarantee(boolean b, String string) { - if (!b) { - throw new BailoutException(string); - } - } - - public static void warning(String string) { - TTY.println("WARNING: " + string); - } - - public static int safeToInt(long l) { - assert (int) l == l; - return (int) l; - } - - public static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; - } - - public static void printSection(String name, char sectionCharacter) { - - String header = " " + name + " "; - int remainingCharacters = PRINTING_LINE_WIDTH - header.length(); - int leftPart = remainingCharacters / 2; - int rightPart = remainingCharacters - leftPart; - for (int i = 0; i < leftPart; i++) { - TTY.print(sectionCharacter); - } - - TTY.print(header); - - for (int i = 0; i < rightPart; i++) { - TTY.print(sectionCharacter); - } - - TTY.println(); - } - - /** - * Prints entries in a byte array as space separated hex values to {@link TTY}. - * - * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. - * @param array the array containing all the bytes to print - * @param bytesPerLine the number of values to print per line of output - */ - public static void printBytes(long address, byte[] array, int bytesPerLine) { - printBytes(address, array, 0, array.length, bytesPerLine); - } - - /** - * Prints entries in a byte array as space separated hex values to {@link TTY}. - * - * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. - * @param array the array containing the bytes to print - * @param offset the offset in {@code array} of the values to print - * @param length the number of values from {@code array} print - * @param bytesPerLine the number of values to print per line of output - */ - public static void printBytes(long address, byte[] array, int offset, int length, int bytesPerLine) { - assert bytesPerLine > 0; - boolean newLine = true; - for (int i = 0; i < length; i++) { - if (newLine) { - TTY.print("%08x: ", address + i); - newLine = false; - } - TTY.print("%02x ", array[i]); - if (i % bytesPerLine == bytesPerLine - 1) { - TTY.println(); - newLine = true; - } - } - - if (length % bytesPerLine != bytesPerLine) { - TTY.println(); - } - } - - public static boolean isShiftCount(int x) { - return 0 <= x && x < 32; - } - - /** - * Determines if a given {@code int} value is the range of unsigned byte values. - */ - public static boolean isUByte(int x) { - return (x & 0xff) == x; - } - - /** - * Determines if a given {@code int} value is the range of signed byte values. - */ - public static boolean isByte(int x) { - return (byte) x == x; - } - - /** - * Determines if a given {@code long} value is the range of unsigned byte values. - */ - public static boolean isUByte(long x) { - return (x & 0xffL) == x; - } - - /** - * Determines if a given {@code long} value is the range of signed byte values. - */ - public static boolean isByte(long l) { - return (byte) l == l; - } - - /** - * Determines if a given {@code long} value is the range of unsigned int values. - */ - public static boolean isUInt(long x) { - return (x & 0xffffffffL) == x; - } - - /** - * Determines if a given {@code long} value is the range of signed int values. - */ - public static boolean isInt(long l) { - return (int) l == l; - } - /** - * Determines if a given {@code int} value is the range of signed short values. - */ - public static boolean isShort(int x) { - return (short) x == x; - } - - public static boolean is32bit(long x) { - return -0x80000000L <= x && x < 0x80000000L; - } - - public static short safeToShort(int v) { - assert isShort(v); - return (short) v; - } - - public static boolean isFixed(Node n) { - return n instanceof FixedNode; - } - - public static boolean isFloating(Node n) { - return n instanceof FloatingNode; - } - - /** - * Creates an array of integers of length "size", in which each number from 0 to (size - 1) occurs exactly once. The - * integers are sorted using the given comparator. This can be used to create a sorting for arrays that cannot be - * modified directly. - * - * @param size The size of the range to be sorted. - * @param comparator A comparator that is used to compare indexes. - * @return An array of integers that contains each number from 0 to (size - 1) exactly once, sorted using the - * comparator. - */ - public static Integer[] createSortedPermutation(int size, Comparator comparator) { - Integer[] indexes = new Integer[size]; - for (int i = 0; i < size; i++) { - indexes[i] = i; - } - Arrays.sort(indexes, comparator); - return indexes; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java Mon Sep 17 16:08:46 2012 +0200 @@ -34,11 +34,11 @@ /** * Performs control flow optimizations on the given LIR graph. - * @param blocks the blocks that should be optimized */ - public static void optimize(List blocks) { - ControlFlowOptimizer.deleteEmptyBlocks(blocks); - ControlFlowOptimizer.deleteUnnecessaryJumps(blocks); + public static void optimize(LIR ir) { + List blocks = ir.codeEmittingOrder(); + ControlFlowOptimizer.deleteEmptyBlocks(ir, blocks); + ControlFlowOptimizer.deleteUnnecessaryJumps(ir, blocks); } private ControlFlowOptimizer() { @@ -50,30 +50,30 @@ * @param block the block checked for deletion * @return whether the block can be deleted */ - private static boolean canDeleteBlock(Block block) { + private static boolean canDeleteBlock(LIR ir, Block block) { if (block.numberOfSux() != 1 || block.numberOfPreds() == 0 || block.suxAt(0) == block) { return false; } - List instructions = block.lir; + List instructions = ir.lir(block); assert instructions.size() >= 2 : "block must have label and branch"; assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label"; assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch"; - assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) block.suxAt(0).lir.get(0)).getLabel() : "branch target must be the successor"; + assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) ir.lir(block.suxAt(0)).get(0)).getLabel() : "branch target must be the successor"; // Block must have exactly one successor. return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState(); } - private static void deleteEmptyBlocks(List blocks) { + private static void deleteEmptyBlocks(LIR ir, List blocks) { assert verify(blocks); Iterator iterator = blocks.iterator(); while (iterator.hasNext()) { Block block = iterator.next(); - if (canDeleteBlock(block)) { + if (canDeleteBlock(ir, block)) { // adjust successor and predecessor lists Block other = block.suxAt(0); for (Block pred : block.getPredecessors()) { @@ -94,18 +94,18 @@ assert verify(blocks); } - private static void deleteUnnecessaryJumps(List blocks) { + private static void deleteUnnecessaryJumps(LIR ir, List blocks) { // skip the last block because there a branch is always necessary for (int i = blocks.size() - 2; i >= 0; i--) { Block block = blocks.get(i); - List instructions = block.lir; + List instructions = ir.lir(block); LIRInstruction lastOp = instructions.get(instructions.size() - 1); if (lastOp instanceof StandardOp.JumpOp) { StandardOp.JumpOp lastJump = (StandardOp.JumpOp) lastOp; if (!lastOp.hasState()) { - if (lastJump.destination().label() == ((StandardOp.LabelOp) blocks.get(i + 1).lir.get(0)).getLabel()) { + if (lastJump.destination().label() == ((StandardOp.LabelOp) ir.lir(blocks.get(i + 1)).get(0)).getLabel()) { // delete last branch instruction instructions.remove(instructions.size() - 1); } else { @@ -113,7 +113,7 @@ if (prevOp instanceof StandardOp.BranchOp) { StandardOp.BranchOp prevBranch = (StandardOp.BranchOp) prevOp; - if (prevBranch.destination().label() == ((StandardOp.LabelOp) blocks.get(i + 1).lir.get(0)).getLabel() && !prevOp.hasState()) { + if (prevBranch.destination().label() == ((StandardOp.LabelOp) ir.lir(blocks.get(i + 1)).get(0)).getLabel() && !prevOp.hasState()) { // eliminate a conditional branch to the immediate successor prevBranch.negate(lastJump.destination()); instructions.remove(instructions.size() - 1); diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java Mon Sep 17 16:08:46 2012 +0200 @@ -51,12 +51,11 @@ /** * Optimizes moves on block edges. - * - * @param blockList a list of blocks whose moves should be optimized */ - public static void optimize(List blockList) { - EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(); + public static void optimize(LIR ir) { + EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(ir); + List blockList = ir.linearScanOrder(); // ignore the first block in the list (index 0 is not processed) for (int i = blockList.size() - 1; i >= 1; i--) { Block block = blockList.get(i); @@ -71,8 +70,10 @@ } private final List> edgeInstructionSeqences; + private LIR ir; - private EdgeMoveOptimizer() { + public EdgeMoveOptimizer(LIR ir) { + this.ir = ir; edgeInstructionSeqences = new ArrayList<>(4); } @@ -120,8 +121,8 @@ // setup a list with the LIR instructions of all predecessors for (Block pred : block.getPredecessors()) { assert pred != null; - assert pred.lir != null; - List predInstructions = pred.lir; + assert ir.lir(pred) != null; + List predInstructions = ir.lir(pred); if (pred.numberOfSux() != 1) { // this can happen with switch-statements where multiple edges are between @@ -162,7 +163,7 @@ } // insert the instruction at the beginning of the current block - block.lir.add(1, op); + ir.lir(block).add(1, op); // delete the instruction at the end of all predecessors for (int i = 0; i < numPreds; i++) { @@ -182,7 +183,7 @@ edgeInstructionSeqences.clear(); int numSux = block.numberOfSux(); - List instructions = block.lir; + List instructions = ir.lir(block); assert numSux == 2 : "method should not be called otherwise"; @@ -213,7 +214,7 @@ // setup a list with the lir-instructions of all successors for (int i = 0; i < numSux; i++) { Block sux = block.suxAt(i); - List suxInstructions = sux.lir; + List suxInstructions = ir.lir(sux); assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; @@ -247,7 +248,7 @@ } // insert instruction at end of current block - block.lir.add(insertIdx, op); + ir.lir(block).add(insertIdx, op); insertIdx++; // delete the instructions at the beginning of all successors diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Mon Sep 17 16:08:46 2012 +0200 @@ -65,6 +65,8 @@ public SpillMoveFactory spillMoveFactory; + public final BlockMap> lirInstructions; + public interface SpillMoveFactory { LIRInstruction createMove(Value result, Value input); LIRInstruction createExchange(Value input1, Value input2); @@ -91,6 +93,7 @@ this.blockToNodesMap = blockToNodesMap; this.codeEmittingOrder = codeEmittingOrder; this.linearScanOrder = linearScanOrder; + this.lirInstructions = new BlockMap<>(cfg); stubs = new ArrayList<>(); } @@ -107,7 +110,7 @@ */ public boolean hasDebugInfo() { for (Block b : linearScanOrder()) { - for (LIRInstruction op : b.lir) { + for (LIRInstruction op : lir(b)) { if (op.hasState()) { return true; } @@ -116,6 +119,15 @@ return false; } + public List lir(Block block) { + return lirInstructions.get(block); + } + + public void setLir(Block block, List list) { + assert lir(block) == null : "lir instruction list should only be initialized once"; + lirInstructions.put(block, list); + } + /** * Gets the linear scan ordering of blocks as a list. * @return the blocks in linear scan order @@ -151,12 +163,12 @@ } } - private static void emitBlock(TargetMethodAssembler tasm, Block block) { + private void emitBlock(TargetMethodAssembler tasm, Block block) { if (Debug.isDumpEnabled()) { tasm.blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); } - for (LIRInstruction op : block.lir) { + for (LIRInstruction op : lir(block)) { if (Debug.isDumpEnabled()) { tasm.blockComment(String.format("%d %s", op.id(), op)); } diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Mon Sep 17 16:08:46 2012 +0200 @@ -111,16 +111,16 @@ curVariablesLive.or(liveOutFor(block.getDominator())); } - assert block.lir.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + assert lir.lir(block).get(0) instanceof StandardOp.LabelOp : "block must start with label"; if (block.numberOfPreds() > 1) { - assert block.lir.get(0) instanceof StandardOp.PhiLabelOp : "phi mapping required for multiple predecessors"; - Value[] phiDefinitions = ((StandardOp.PhiLabelOp) block.lir.get(0)).getPhiDefinitions(); + assert lir.lir(block).get(0) instanceof StandardOp.PhiLabelOp : "phi mapping required for multiple predecessors"; + Value[] phiDefinitions = ((StandardOp.PhiLabelOp) lir.lir(block).get(0)).getPhiDefinitions(); if (!beforeRegisterAllocation) { assert phiDefinitions.length == 0; } for (Block pred : block.getPredecessors()) { assert pred.numberOfSux() == 1; - LIRInstruction last = pred.lir.get(pred.lir.size() - 1); + LIRInstruction last = lir.lir(pred).get(lir.lir(pred).size() - 1); assert last instanceof StandardOp.PhiJumpOp : "phi mapping required for multiple successors"; Value[] phiUses = ((StandardOp.PhiJumpOp) last).getPhiInputs(); if (!beforeRegisterAllocation) { @@ -130,11 +130,11 @@ } if (block.numberOfSux() > 0) { - LIRInstruction last = block.lir.get(block.lir.size() - 1); + LIRInstruction last = lir.lir(block).get(lir.lir(block).size() - 1); assert last instanceof StandardOp.JumpOp || last instanceof LIRXirInstruction : "block with successor must end with unconditional jump"; } - for (LIRInstruction op : block.lir) { + for (LIRInstruction op : lir.lir(block)) { curInstruction = op; op.forEachInput(useProc); diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Mon Sep 17 16:08:46 2012 +0200 @@ -68,11 +68,11 @@ * @param suxIndex The index of the successor. * @return The newly created label reference. */ - public static LabelRef forSuccessor(final Block block, final int suxIndex) { + public static LabelRef forSuccessor(final LIR lir, final Block block, final int suxIndex) { return new LabelRef() { @Override public Label label() { - return ((StandardOp.LabelOp) block.suxAt(suxIndex).lir.get(0)).getLabel(); + return ((StandardOp.LabelOp) lir.lir(block.suxAt(suxIndex)).get(0)).getLabel(); } @Override diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2009, 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.lir.cfg; - -import java.util.*; - -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -public class Block { - protected int id; - - protected BeginNode beginNode; - protected FixedNode endNode; - protected Loop loop; - protected double probability; - - protected List predecessors; - protected List successors; - - protected Block dominator; - protected List dominated; - protected Block postdominator; - - // Fields that still need to be worked on, try to remove them later. - public List lir; - public boolean align; - public int linearScanNumber; - - public Block() { - id = ControlFlowGraph.BLOCK_ID_INITIAL; - } - - public int getId() { - return id; - } - - public BeginNode getBeginNode() { - return beginNode; - } - - public FixedNode getEndNode() { - return endNode; - } - - public Loop getLoop() { - return loop; - } - - public int getLoopDepth() { - return loop == null ? 0 : loop.depth; - } - - public boolean isLoopHeader() { - return getBeginNode() instanceof LoopBeginNode; - } - - public boolean isLoopEnd() { - return getEndNode() instanceof LoopEndNode; - } - - public boolean isExceptionEntry() { - return getBeginNode().next() instanceof ExceptionObjectNode; - } - - public List getPredecessors() { - return predecessors; - } - - public List getSuccessors() { - return successors; - } - - public Block getDominator() { - return dominator; - } - - public Block getEarliestPostDominated() { - Block b = this; - while (true) { - Block dom = b.getDominator(); - if (dom != null && dom.getPostdominator() == b) { - b = dom; - } else { - break; - } - } - return b; - } - - public List getDominated() { - if (dominated == null) { - return Collections.emptyList(); - } - return dominated; - } - - public Block getPostdominator() { - return postdominator; - } - - private class NodeIterator implements Iterator { - private FixedNode cur; - - public NodeIterator() { - cur = getBeginNode(); - } - - @Override - public boolean hasNext() { - return cur != null; - } - - @Override - public FixedNode next() { - FixedNode result = cur; - if (cur == getEndNode()) { - cur = null; - } else { - cur = ((FixedWithNextNode) cur).next(); - } - assert !(cur instanceof BeginNode); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - public Iterable getNodes() { - return new Iterable() { - @Override - public Iterator iterator() { - return new NodeIterator(); - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder().append('['); - for (FixedNode node : this) { - str.append(node).append(", "); - } - if (str.length() > 1) { - str.setLength(str.length() - 2); - } - return str.append(']').toString(); - } - }; - } - - public int getFirstLirInstructionId() { - int result = lir.get(0).id(); - assert result >= 0; - return result; - } - - public int getLastLirInstructionId() { - int result = lir.get(lir.size() - 1).id(); - assert result >= 0; - return result; - } - - @Override - public String toString() { - return "B" + id; - } - - -// to be inlined later on - public int numberOfPreds() { - return getPredecessors().size(); - } - - public int numberOfSux() { - return getSuccessors().size(); - } - - public Block predAt(int i) { - return getPredecessors().get(i); - } - - public Block suxAt(int i) { - return getSuccessors().get(i); - } -// end to be inlined later on - - public boolean dominates(Block block) { - return block.isDominatedBy(this); - } - - public boolean isDominatedBy(Block block) { - if (block == this) { - return true; - } - if (dominator == null) { - return false; - } - return dominator.isDominatedBy(block); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/BlockMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/BlockMap.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.cfg; - -public class BlockMap { - private final T[] data; - - @SuppressWarnings("unchecked") - public BlockMap(ControlFlowGraph cfg) { - data = (T[]) new Object[cfg.getBlocks().length]; - } - - public T get(Block block) { - return data[block.getId()]; - } - - public void put(Block block, T value) { - data[block.getId()] = value; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.cfg; - -public class CFGVerifier { - public static boolean verify(ControlFlowGraph cfg) { - for (Block block : cfg.getBlocks()) { - assert block.getId() >= 0; - assert cfg.getBlocks()[block.getId()] == block; - - for (Block pred : block.getPredecessors()) { - assert pred.getSuccessors().contains(block); - assert pred.getId() < block.getId() || pred.isLoopEnd(); - } - - for (Block sux : block.getSuccessors()) { - assert sux.getPredecessors().contains(block); - assert sux.getId() > block.getId() || sux.isLoopHeader(); - } - - if (block.getDominator() != null) { - assert block.getDominator().getId() < block.getId(); - assert block.getDominator().getDominated().contains(block); - } - for (Block dominated : block.getDominated()) { - assert dominated.getId() > block.getId(); - assert dominated.getDominator() == block; - } - - assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode; - } - - if (cfg.getLoops() != null) { - for (Loop loop : cfg.getLoops()) { - assert loop.header.isLoopHeader(); - - for (Block block : loop.blocks) { - assert block.getId() >= loop.header.getId(); - - Loop blockLoop = block.getLoop(); - while (blockLoop != loop) { - assert blockLoop != null; - blockLoop = blockLoop.parent; - } - - if (!(block.isLoopHeader() && block.getLoop() == loop)) { - for (Block pred : block.getPredecessors()) { - if (!loop.blocks.contains(pred)) { - return false; - } - } - } - } - - for (Block block : loop.exits) { - assert block.getId() >= loop.header.getId(); - - Loop blockLoop = block.getLoop(); - while (blockLoop != null) { - blockLoop = blockLoop.parent; - assert blockLoop != loop; - } - } - } - } - - return true; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2011, 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.lir.cfg; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -public class ControlFlowGraph { - - public final StructuredGraph graph; - - private final NodeMap nodeToBlock; - private Block[] reversePostOrder; - private Loop[] loops; - - public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { - ControlFlowGraph cfg = new ControlFlowGraph(graph); - cfg.identifyBlocks(); - if (connectBlocks || computeLoops || computeDominators || computePostdominators) { - cfg.connectBlocks(); - } - if (computeLoops) { - cfg.computeLoopInformation(); - } - if (computeDominators) { - cfg.computeDominators(); - } - if (computePostdominators) { - cfg.computePostdominators(); - } - assert CFGVerifier.verify(cfg); - return cfg; - } - - protected ControlFlowGraph(StructuredGraph graph) { - this.graph = graph; - this.nodeToBlock = graph.createNodeMap(); - } - - public Block[] getBlocks() { - return reversePostOrder; - } - - public Block getStartBlock() { - return reversePostOrder[0]; - } - - public Iterable postOrder() { - return new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - private int nextIndex = reversePostOrder.length - 1; - @Override - public boolean hasNext() { - return nextIndex >= 0; - } - - @Override - public Block next() { - return reversePostOrder[nextIndex--]; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }; - } - - public NodeMap getNodeToBlock() { - return nodeToBlock; - } - - public Block blockFor(Node node) { - return nodeToBlock.get(node); - } - - public Loop[] getLoops() { - return loops; - } - - protected static final int BLOCK_ID_INITIAL = -1; - protected static final int BLOCK_ID_VISITED = -2; - - private void identifyBlocks() { - // Find all block headers - int numBlocks = 0; - for (Node node : graph.getNodes()) { - if (node instanceof BeginNode) { - Block block = new Block(); - numBlocks++; - - block.beginNode = (BeginNode) node; - Node cur = node; - Node last; - do { - assert !cur.isDeleted(); - - assert nodeToBlock.get(cur) == null; - nodeToBlock.set(cur, block); - if (cur instanceof MergeNode) { - for (PhiNode phi : ((MergeNode) cur).phis()) { - nodeToBlock.set(phi, block); - } - } - - if (cur instanceof FixedNode) { - double probability = ((FixedNode) cur).probability(); - if (probability > block.probability) { - block.probability = probability; - } - } - - last = cur; - cur = cur.successors().first(); - } while (cur != null && !(cur instanceof BeginNode)); - - block.endNode = (FixedNode) last; - } - } - - // Compute postorder. - ArrayList postOrder = new ArrayList<>(numBlocks); - ArrayList stack = new ArrayList<>(); - stack.add(blockFor(graph.start())); - - do { - Block block = stack.get(stack.size() - 1); - if (block.id == BLOCK_ID_INITIAL) { - // First time we see this block: push all successors. - for (Node suxNode : block.getEndNode().cfgSuccessors()) { - Block suxBlock = blockFor(suxNode); - if (suxBlock.id == BLOCK_ID_INITIAL) { - stack.add(suxBlock); - } - } - block.id = BLOCK_ID_VISITED; - } else if (block.id == BLOCK_ID_VISITED) { - // Second time we see this block: All successors have been processed, so add block to postorder list. - stack.remove(stack.size() - 1); - postOrder.add(block); - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } while (!stack.isEmpty()); - - // Compute reverse postorder and number blocks. - assert postOrder.size() <= numBlocks : "some blocks originally created can be unreachable, so actual block list can be shorter"; - numBlocks = postOrder.size(); - reversePostOrder = new Block[numBlocks]; - for (int i = 0; i < numBlocks; i++) { - reversePostOrder[i] = postOrder.get(numBlocks - i - 1); - reversePostOrder[i].id = i; - } - } - - // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0). - private void connectBlocks() { - for (Block block : reversePostOrder) { - List predecessors = new ArrayList<>(); - for (Node predNode : block.getBeginNode().cfgPredecessors()) { - Block predBlock = nodeToBlock.get(predNode); - if (predBlock.id >= 0) { - predecessors.add(predBlock); - } - } - if (block.getBeginNode() instanceof LoopBeginNode) { - for (LoopEndNode predNode : ((LoopBeginNode) block.getBeginNode()).orderedLoopEnds()) { - Block predBlock = nodeToBlock.get(predNode); - if (predBlock.id >= 0) { - predecessors.add(predBlock); - } - } - } - block.predecessors = predecessors; - - List successors = new ArrayList<>(); - for (Node suxNode : block.getEndNode().cfgSuccessors()) { - Block suxBlock = nodeToBlock.get(suxNode); - assert suxBlock.id >= 0; - successors.add(suxBlock); - } - if (block.getEndNode() instanceof LoopEndNode) { - Block suxBlock = nodeToBlock.get(((LoopEndNode) block.getEndNode()).loopBegin()); - assert suxBlock.id >= 0; - successors.add(suxBlock); - } - block.successors = successors; - } - } - - private void computeLoopInformation() { - List loopsList = new ArrayList<>(); - for (Block block : reversePostOrder) { - Node beginNode = block.getBeginNode(); - if (beginNode instanceof LoopBeginNode) { - Loop loop = new Loop(block.getLoop(), loopsList.size(), block); - loopsList.add(loop); - - LoopBeginNode loopBegin = (LoopBeginNode) beginNode; - for (LoopEndNode end : loopBegin.loopEnds()) { - Block endBlock = nodeToBlock.get(end); - computeLoopBlocks(endBlock, loop); - } - - for (LoopExitNode exit : loopBegin.loopExits()) { - Block exitBlock = nodeToBlock.get(exit); - List predecessors = exitBlock.getPredecessors(); - assert predecessors.size() == 1; - computeLoopBlocks(predecessors.get(0), loop); - loop.exits.add(exitBlock); - } - List unexpected = new LinkedList<>(); - for (Block b : loop.blocks) { - for (Block sux : b.getSuccessors()) { - if (sux.loop != loop) { - BeginNode begin = sux.getBeginNode(); - if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { - Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux); - unexpected.add(sux); - } - } - } - } - for (Block b : unexpected) { - addBranchToLoop(loop, b); - } - } - } - loops = loopsList.toArray(new Loop[loopsList.size()]); - } - - private static void addBranchToLoop(Loop l, Block b) { - if (l.blocks.contains(b)) { - return; - } - l.blocks.add(b); - b.loop = l; - for (Block sux : b.getSuccessors()) { - addBranchToLoop(l, sux); - } - } - - private static void computeLoopBlocks(Block block, Loop loop) { - if (block.getLoop() == loop) { - return; - } - assert block.loop == loop.parent; - block.loop = loop; - - assert !loop.blocks.contains(block); - loop.blocks.add(block); - - if (block != loop.header) { - for (Block pred : block.getPredecessors()) { - computeLoopBlocks(pred, loop); - } - } - } - - private void computeDominators() { - assert reversePostOrder[0].getPredecessors().size() == 0 : "start block has no predecessor and therefore no dominator"; - for (int i = 1; i < reversePostOrder.length; i++) { - Block block = reversePostOrder[i]; - List predecessors = block.getPredecessors(); - assert predecessors.size() > 0; - - Block dominator = predecessors.get(0); - for (int j = 1; j < predecessors.size(); j++) { - Block pred = predecessors.get(j); - if (!pred.isLoopEnd()) { - dominator = commonDominator(dominator, pred); - } - } - setDominator(block, dominator); - } - } - - private static void setDominator(Block block, Block dominator) { - block.dominator = dominator; - if (dominator.dominated == null) { - dominator.dominated = new ArrayList<>(); - } - dominator.dominated.add(block); - } - - public static Block commonDominator(Block a, Block b) { - Block iterA = a; - Block iterB = b; - while (iterA != iterB) { - if (iterA.getId() > iterB.getId()) { - iterA = iterA.getDominator(); - } else { - assert iterB.getId() > iterA.getId(); - iterB = iterB.getDominator(); - } - } - return iterA; - } - - private void computePostdominators() { - for (Block block : postOrder()) { - if (block.isLoopEnd()) { - // We do not want the loop header registered as the postdominator of the loop end. - continue; - } - Block postdominator = null; - for (Block sux : block.getSuccessors()) { - if (sux.isExceptionEntry()) { - // We ignore exception handlers. - } else if (postdominator == null) { - postdominator = sux; - } else { - postdominator = commonPostdominator(postdominator, sux); - } - } - block.postdominator = postdominator; - } - } - - private static Block commonPostdominator(Block a, Block b) { - Block iterA = a; - Block iterB = b; - while (iterA != iterB) { - if (iterA.getId() < iterB.getId()) { - iterA = iterA.getPostdominator(); - if (iterA == null) { - return null; - } - } else { - assert iterB.getId() < iterA.getId(); - iterB = iterB.getPostdominator(); - if (iterB == null) { - return null; - } - } - } - return iterA; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.lir.cfg; - -import java.util.*; - -import com.oracle.graal.nodes.*; - -public class Loop { - public final Loop parent; - public final List children; - - public final int depth; - public final int index; - public final Block header; - public final List blocks; - public final List exits; - - protected Loop(Loop parent, int index, Block header) { - this.parent = parent; - if (parent != null) { - this.depth = parent.depth + 1; - parent.children.add(this); - } else { - this.depth = 1; - } - this.index = index; - this.header = header; - this.blocks = new ArrayList<>(); - this.children = new ArrayList<>(); - this.exits = new ArrayList<>(); - } - - @Override - public String toString() { - return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); - } - - public LoopBeginNode loopBegin() { - return (LoopBeginNode) header.getBeginNode(); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/Block.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/Block.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2009, 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.lir.cfg; + +import java.util.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +public class Block { + + protected int id; + + protected BeginNode beginNode; + protected FixedNode endNode; + protected Loop loop; + protected double probability; + + protected List predecessors; + protected List successors; + + protected Block dominator; + protected List dominated; + protected Block postdominator; + + // Fields that still need to be worked on, try to remove them later. + public boolean align; + public int linearScanNumber; + + protected Block() { + id = ControlFlowGraph.BLOCK_ID_INITIAL; + } + + public int getId() { + return id; + } + + public BeginNode getBeginNode() { + return beginNode; + } + + public FixedNode getEndNode() { + return endNode; + } + + public Loop getLoop() { + return loop; + } + + public int getLoopDepth() { + return loop == null ? 0 : loop.depth; + } + + public boolean isLoopHeader() { + return getBeginNode() instanceof LoopBeginNode; + } + + public boolean isLoopEnd() { + return getEndNode() instanceof LoopEndNode; + } + + public boolean isExceptionEntry() { + return getBeginNode().next() instanceof ExceptionObjectNode; + } + + public List getPredecessors() { + return predecessors; + } + + public List getSuccessors() { + return successors; + } + + public Block getDominator() { + return dominator; + } + + public Block getEarliestPostDominated() { + Block b = this; + while (true) { + Block dom = b.getDominator(); + if (dom != null && dom.getPostdominator() == b) { + b = dom; + } else { + break; + } + } + return b; + } + + public List getDominated() { + if (dominated == null) { + return Collections.emptyList(); + } + return dominated; + } + + public Block getPostdominator() { + return postdominator; + } + + private class NodeIterator implements Iterator { + private FixedNode cur; + + public NodeIterator() { + cur = getBeginNode(); + } + + @Override + public boolean hasNext() { + return cur != null; + } + + @Override + public FixedNode next() { + FixedNode result = cur; + if (cur == getEndNode()) { + cur = null; + } else { + cur = ((FixedWithNextNode) cur).next(); + } + assert !(cur instanceof BeginNode); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public Iterable getNodes() { + return new Iterable() { + @Override + public Iterator iterator() { + return new NodeIterator(); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder().append('['); + for (FixedNode node : this) { + str.append(node).append(", "); + } + if (str.length() > 1) { + str.setLength(str.length() - 2); + } + return str.append(']').toString(); + } + }; + } + + @Override + public String toString() { + return "B" + id; + } + + +// to be inlined later on + public int numberOfPreds() { + return getPredecessors().size(); + } + + public int numberOfSux() { + return getSuccessors().size(); + } + + public Block predAt(int i) { + return getPredecessors().get(i); + } + + public Block suxAt(int i) { + return getSuccessors().get(i); + } +// end to be inlined later on + + public boolean dominates(Block block) { + return block.isDominatedBy(this); + } + + public boolean isDominatedBy(Block block) { + if (block == this) { + return true; + } + if (dominator == null) { + return false; + } + return dominator.isDominatedBy(block); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/BlockMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/BlockMap.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.cfg; + +public class BlockMap { + private final T[] data; + + @SuppressWarnings("unchecked") + public BlockMap(ControlFlowGraph cfg) { + data = (T[]) new Object[cfg.getBlocks().length]; + } + + public T get(Block block) { + return data[block.getId()]; + } + + public void put(Block block, T value) { + data[block.getId()] = value; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/CFGVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/CFGVerifier.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.cfg; + +public class CFGVerifier { + public static boolean verify(ControlFlowGraph cfg) { + for (Block block : cfg.getBlocks()) { + assert block.getId() >= 0; + assert cfg.getBlocks()[block.getId()] == block; + + for (Block pred : block.getPredecessors()) { + assert pred.getSuccessors().contains(block); + assert pred.getId() < block.getId() || pred.isLoopEnd(); + } + + for (Block sux : block.getSuccessors()) { + assert sux.getPredecessors().contains(block); + assert sux.getId() > block.getId() || sux.isLoopHeader(); + } + + if (block.getDominator() != null) { + assert block.getDominator().getId() < block.getId(); + assert block.getDominator().getDominated().contains(block); + } + for (Block dominated : block.getDominated()) { + assert dominated.getId() > block.getId(); + assert dominated.getDominator() == block; + } + + assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode; + } + + if (cfg.getLoops() != null) { + for (Loop loop : cfg.getLoops()) { + assert loop.header.isLoopHeader(); + + for (Block block : loop.blocks) { + assert block.getId() >= loop.header.getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != loop) { + assert blockLoop != null; + blockLoop = blockLoop.parent; + } + + if (!(block.isLoopHeader() && block.getLoop() == loop)) { + for (Block pred : block.getPredecessors()) { + if (!loop.blocks.contains(pred)) { + return false; + } + } + } + } + + for (Block block : loop.exits) { + assert block.getId() >= loop.header.getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != null) { + blockLoop = blockLoop.parent; + assert blockLoop != loop; + } + } + } + } + + return true; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2011, 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.lir.cfg; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +public class ControlFlowGraph { + + public final StructuredGraph graph; + + private final NodeMap nodeToBlock; + private Block[] reversePostOrder; + private Loop[] loops; + + + public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { + ControlFlowGraph cfg = new ControlFlowGraph(graph); + cfg.identifyBlocks(); + if (connectBlocks || computeLoops || computeDominators || computePostdominators) { + cfg.connectBlocks(); + } + if (computeLoops) { + cfg.computeLoopInformation(); + } + if (computeDominators) { + cfg.computeDominators(); + } + if (computePostdominators) { + cfg.computePostdominators(); + } + assert CFGVerifier.verify(cfg); + return cfg; + } + + protected ControlFlowGraph(StructuredGraph graph) { + this.graph = graph; + this.nodeToBlock = graph.createNodeMap(); + } + + public Block[] getBlocks() { + return reversePostOrder; + } + + public Block getStartBlock() { + return reversePostOrder[0]; + } + + public Iterable postOrder() { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private int nextIndex = reversePostOrder.length - 1; + @Override + public boolean hasNext() { + return nextIndex >= 0; + } + + @Override + public Block next() { + return reversePostOrder[nextIndex--]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + public NodeMap getNodeToBlock() { + return nodeToBlock; + } + + public Block blockFor(Node node) { + return nodeToBlock.get(node); + } + + public Loop[] getLoops() { + return loops; + } + + protected static final int BLOCK_ID_INITIAL = -1; + protected static final int BLOCK_ID_VISITED = -2; + + private void identifyBlocks() { + // Find all block headers + int numBlocks = 0; + for (Node node : graph.getNodes()) { + if (node instanceof BeginNode) { + Block block = new Block(); + numBlocks++; + + block.beginNode = (BeginNode) node; + Node cur = node; + Node last; + do { + assert !cur.isDeleted(); + + assert nodeToBlock.get(cur) == null; + nodeToBlock.set(cur, block); + if (cur instanceof MergeNode) { + for (PhiNode phi : ((MergeNode) cur).phis()) { + nodeToBlock.set(phi, block); + } + } + + if (cur instanceof FixedNode) { + double probability = ((FixedNode) cur).probability(); + if (probability > block.probability) { + block.probability = probability; + } + } + + last = cur; + cur = cur.successors().first(); + } while (cur != null && !(cur instanceof BeginNode)); + + block.endNode = (FixedNode) last; + } + } + + // Compute postorder. + ArrayList postOrder = new ArrayList<>(numBlocks); + ArrayList stack = new ArrayList<>(); + stack.add(blockFor(graph.start())); + + do { + Block block = stack.get(stack.size() - 1); + if (block.id == BLOCK_ID_INITIAL) { + // First time we see this block: push all successors. + for (Node suxNode : block.getEndNode().cfgSuccessors()) { + Block suxBlock = blockFor(suxNode); + if (suxBlock.id == BLOCK_ID_INITIAL) { + stack.add(suxBlock); + } + } + block.id = BLOCK_ID_VISITED; + } else if (block.id == BLOCK_ID_VISITED) { + // Second time we see this block: All successors have been processed, so add block to postorder list. + stack.remove(stack.size() - 1); + postOrder.add(block); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } while (!stack.isEmpty()); + + // Compute reverse postorder and number blocks. + assert postOrder.size() <= numBlocks : "some blocks originally created can be unreachable, so actual block list can be shorter"; + numBlocks = postOrder.size(); + reversePostOrder = new Block[numBlocks]; + for (int i = 0; i < numBlocks; i++) { + Block block = postOrder.get(numBlocks - i - 1); + block.id = i; + reversePostOrder[i] = block; + } + } + + // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0). + private void connectBlocks() { + for (Block block : reversePostOrder) { + List predecessors = new ArrayList<>(); + for (Node predNode : block.getBeginNode().cfgPredecessors()) { + Block predBlock = nodeToBlock.get(predNode); + if (predBlock.id >= 0) { + predecessors.add(predBlock); + } + } + if (block.getBeginNode() instanceof LoopBeginNode) { + for (LoopEndNode predNode : ((LoopBeginNode) block.getBeginNode()).orderedLoopEnds()) { + Block predBlock = nodeToBlock.get(predNode); + if (predBlock.id >= 0) { + predecessors.add(predBlock); + } + } + } + block.predecessors = predecessors; + + List successors = new ArrayList<>(); + for (Node suxNode : block.getEndNode().cfgSuccessors()) { + Block suxBlock = nodeToBlock.get(suxNode); + assert suxBlock.id >= 0; + successors.add(suxBlock); + } + if (block.getEndNode() instanceof LoopEndNode) { + Block suxBlock = nodeToBlock.get(((LoopEndNode) block.getEndNode()).loopBegin()); + assert suxBlock.id >= 0; + successors.add(suxBlock); + } + block.successors = successors; + } + } + + private void computeLoopInformation() { + ArrayList loopsList = new ArrayList<>(); + for (Block block : reversePostOrder) { + Node beginNode = block.getBeginNode(); + if (beginNode instanceof LoopBeginNode) { + Loop loop = new Loop(block.getLoop(), loopsList.size(), block); + loopsList.add(loop); + + LoopBeginNode loopBegin = (LoopBeginNode) beginNode; + for (LoopEndNode end : loopBegin.loopEnds()) { + Block endBlock = nodeToBlock.get(end); + computeLoopBlocks(endBlock, loop); + } + + for (LoopExitNode exit : loopBegin.loopExits()) { + Block exitBlock = nodeToBlock.get(exit); + List predecessors = exitBlock.getPredecessors(); + assert predecessors.size() == 1; + computeLoopBlocks(predecessors.get(0), loop); + loop.exits.add(exitBlock); + } + List unexpected = new LinkedList<>(); + for (Block b : loop.blocks) { + for (Block sux : b.getSuccessors()) { + if (sux.loop != loop) { + BeginNode begin = sux.getBeginNode(); + if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { + Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux); + unexpected.add(sux); + } + } + } + } + for (Block b : unexpected) { + addBranchToLoop(loop, b); + } + } + } + loops = loopsList.toArray(new Loop[loopsList.size()]); + } + + private static void addBranchToLoop(Loop l, Block b) { + if (l.blocks.contains(b)) { + return; + } + l.blocks.add(b); + b.loop = l; + for (Block sux : b.getSuccessors()) { + addBranchToLoop(l, sux); + } + } + + private static void computeLoopBlocks(Block block, Loop loop) { + if (block.getLoop() == loop) { + return; + } + assert block.loop == loop.parent; + block.loop = loop; + + assert !loop.blocks.contains(block); + loop.blocks.add(block); + + if (block != loop.header) { + for (Block pred : block.getPredecessors()) { + computeLoopBlocks(pred, loop); + } + } + } + + private void computeDominators() { + assert reversePostOrder[0].getPredecessors().size() == 0 : "start block has no predecessor and therefore no dominator"; + for (int i = 1; i < reversePostOrder.length; i++) { + Block block = reversePostOrder[i]; + List predecessors = block.getPredecessors(); + assert predecessors.size() > 0; + + Block dominator = predecessors.get(0); + for (int j = 1; j < predecessors.size(); j++) { + Block pred = predecessors.get(j); + if (!pred.isLoopEnd()) { + dominator = commonDominator(dominator, pred); + } + } + setDominator(block, dominator); + } + } + + private static void setDominator(Block block, Block dominator) { + block.dominator = dominator; + if (dominator.dominated == null) { + dominator.dominated = new ArrayList<>(); + } + dominator.dominated.add(block); + } + + public static Block commonDominator(Block a, Block b) { + Block iterA = a; + Block iterB = b; + while (iterA != iterB) { + if (iterA.getId() > iterB.getId()) { + iterA = iterA.getDominator(); + } else { + assert iterB.getId() > iterA.getId(); + iterB = iterB.getDominator(); + } + } + return iterA; + } + + private void computePostdominators() { + for (Block block : postOrder()) { + if (block.isLoopEnd()) { + // We do not want the loop header registered as the postdominator of the loop end. + continue; + } + Block postdominator = null; + for (Block sux : block.getSuccessors()) { + if (sux.isExceptionEntry()) { + // We ignore exception handlers. + } else if (postdominator == null) { + postdominator = sux; + } else { + postdominator = commonPostdominator(postdominator, sux); + } + } + block.postdominator = postdominator; + } + } + + private static Block commonPostdominator(Block a, Block b) { + Block iterA = a; + Block iterB = b; + while (iterA != iterB) { + if (iterA.getId() < iterB.getId()) { + iterA = iterA.getPostdominator(); + if (iterA == null) { + return null; + } + } else { + assert iterB.getId() < iterA.getId(); + iterB = iterB.getPostdominator(); + if (iterB == null) { + return null; + } + } + } + return iterA; + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/Loop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/lir/cfg/Loop.java Mon Sep 17 16:08:46 2012 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir.cfg; + +import java.util.*; + +import com.oracle.graal.nodes.*; + +public class Loop { + public final Loop parent; + public final List children; + + public final int depth; + public final int index; + public final Block header; + public final List blocks; + public final List exits; + + protected Loop(Loop parent, int index, Block header) { + this.parent = parent; + if (parent != null) { + this.depth = parent.depth + 1; + parent.children.add(this); + } else { + this.depth = 1; + } + this.index = index; + this.header = header; + this.blocks = new ArrayList<>(); + this.children = new ArrayList<>(); + this.exits = new ArrayList<>(); + } + + @Override + public String toString() { + return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); + } + + public LoopBeginNode loopBegin() { + return (LoopBeginNode) header.getBeginNode(); + } +} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CyclicMaterializeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CyclicMaterializeStoreNode.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.java; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * The {@code StoreFieldNode} represents a write to a static or instance field. - */ -@NodeInfo(nameTemplate = "MaterializeStore#{p#field/s}") -public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable { - - @Input private ValueNode object; - @Input private ValueNode value; - private final Object target; - - public ValueNode object() { - return object; - } - - public ValueNode value() { - return value; - } - - public ResolvedJavaField targetField() { - return (ResolvedJavaField) target; - } - - public int targetIndex() { - return (int) target; - } - - public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, ResolvedJavaField field) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.target = field; - } - - public CyclicMaterializeStoreNode(ValueNode object, ValueNode value, int index) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.target = index; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) graph(); - ResolvedJavaType type = object.objectStamp().type(); - FixedWithNextNode store; - if (target instanceof Integer) { - store = graph.add(new StoreIndexedNode(object, ConstantNode.forInt((int) target, graph), type.componentType().kind(), value, -1)); - } else { - assert target instanceof ResolvedJavaField; - store = graph.add(new StoreFieldNode(object, (ResolvedJavaField) target, value, -1)); - } - graph.replaceFixedWithFixed(this, store); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MaterializeObjectNode.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.java; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; - -@NodeInfo(nameTemplate = "Materialize {i#virtualObject}") -public final class MaterializeObjectNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, Node.IterableNodeType, Canonicalizable { - - @Input private final NodeInputList values; - @Input private final VirtualObjectNode virtualObject; - - public MaterializeObjectNode(VirtualObjectNode virtualObject) { - super(StampFactory.exactNonNull(virtualObject.type())); - this.virtualObject = virtualObject; - this.values = new NodeInputList<>(this, virtualObject.entryCount()); - } - - public NodeInputList values() { - return values; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) graph(); - if (virtualObject instanceof VirtualInstanceNode) { - VirtualInstanceNode virtual = (VirtualInstanceNode) virtualObject; - - NewInstanceNode newInstance = graph.add(new NewInstanceNode(virtual.type(), false)); - this.replaceAtUsages(newInstance); - graph.addAfterFixed(this, newInstance); - - FixedWithNextNode position = newInstance; - for (int i = 0; i < virtual.entryCount(); i++) { - StoreFieldNode store = graph.add(new StoreFieldNode(newInstance, virtual.field(i), values.get(i), -1)); - graph.addAfterFixed(position, store); - position = store; - } - - graph.removeFixed(this); - } else { - assert virtualObject instanceof VirtualArrayNode; - VirtualArrayNode virtual = (VirtualArrayNode) virtualObject; - - ResolvedJavaType element = virtual.componentType(); - NewArrayNode newArray; - if (element.kind() == Kind.Object) { - newArray = graph.add(new NewObjectArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false)); - } else { - newArray = graph.add(new NewPrimitiveArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), false)); - } - this.replaceAtUsages(newArray); - graph.addAfterFixed(this, newArray); - - FixedWithNextNode position = newArray; - for (int i = 0; i < virtual.entryCount(); i++) { - StoreIndexedNode store = graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.kind(), values.get(i), -1)); - graph.addAfterFixed(position, store); - position = store; - } - - graph.removeFixed(this); - } - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (usages().isEmpty()) { - return null; - } else { - return this; - } - } - - @Override - public EscapeOp getEscapeOp() { - return new EscapeOp() { - - @Override - public ValueNode[] fieldState() { - return values.toArray(new ValueNode[values.size()]); - } - - @Override - public VirtualObjectNode virtualObject(int virtualId) { - return virtualObject; - } - }; - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/MaterializedObjectState.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2009, 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.nodes.virtual; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * This class encapsulated the materialized state of an escape analyzed object. - */ -public final class MaterializedObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable { - - @Input private ValueNode materializedValue; - - public ValueNode materializedValue() { - return materializedValue; - } - - public MaterializedObjectState(VirtualObjectNode object, ValueNode materializedValue) { - super(object); - this.materializedValue = materializedValue; - } - - @Override - public void generate(LIRGeneratorTool generator) { - // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. - } - - @Override - public MaterializedObjectState duplicateWithVirtualState() { - return graph().add(new MaterializedObjectState(object(), materializedValue)); - } - - @Override - public void applyToNonVirtual(NodeClosure< ? super ValueNode> closure) { - closure.apply(this, materializedValue); - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectState.java Mon Sep 17 13:35:55 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2009, 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.nodes.virtual; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -/** - * This class encapsulated the virtual state of an escape analyzed object. - */ -public final class VirtualObjectState extends EscapeObjectState implements Node.IterableNodeType, LIRLowerable { - - @Input private NodeInputList fieldValues; - - public NodeInputList fieldValues() { - return fieldValues; - } - - public VirtualObjectState(VirtualObjectNode object, ValueNode[] fieldValues) { - super(object); - assert object.entryCount() == fieldValues.length; - this.fieldValues = new NodeInputList<>(this, fieldValues); - } - - private VirtualObjectState(VirtualObjectNode object, List fieldValues) { - super(object); - assert object.entryCount() == fieldValues.size(); - this.fieldValues = new NodeInputList<>(this, fieldValues); - } - - @Override - public void generate(LIRGeneratorTool generator) { - // Nothing to do, virtual object states are processed as part of the handling of StateSplit nodes. - } - - @Override - public VirtualObjectState duplicateWithVirtualState() { - return graph().add(new VirtualObjectState(object(), fieldValues)); - } - - @Override - public void applyToNonVirtual(NodeClosure< ? super ValueNode> closure) { - for (ValueNode value : fieldValues) { - closure.apply(this, value); - } - } -} diff -r debe42b2b92f -r c5afcc2ebd3d graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Mon Sep 17 13:35:55 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Mon Sep 17 16:08:46 2012 +0200 @@ -419,7 +419,7 @@ * @param block the block to print */ private void printLIR(Block block) { - List lirInstructions = block.lir; + List lirInstructions = lir.lir(block); if (lirInstructions == null) { return; } diff -r debe42b2b92f -r c5afcc2ebd3d mx/projects --- a/mx/projects Mon Sep 17 13:35:55 2012 +0200 +++ b/mx/projects Mon Sep 17 16:08:46 2012 +0200 @@ -137,10 +137,24 @@ project@com.oracle.graal.interpreter@checkstyle=com.oracle.graal.graph project@com.oracle.graal.interpreter@javaCompliance=1.7 +# graal.compiler.phases +project@com.oracle.graal.compiler.phases@subDir=graal +project@com.oracle.graal.compiler.phases@sourceDirs=src +project@com.oracle.graal.compiler.phases@dependencies=com.oracle.graal.nodes +project@com.oracle.graal.compiler.phases@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.compiler.phases@javaCompliance=1.7 + +# graal.compiler.virtual +project@com.oracle.graal.compiler.virtual@subDir=graal +project@com.oracle.graal.compiler.virtual@sourceDirs=src +project@com.oracle.graal.compiler.virtual@dependencies=com.oracle.graal.compiler.phases +project@com.oracle.graal.compiler.virtual@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.compiler.virtual@javaCompliance=1.7 + # graal.compiler project@com.oracle.graal.compiler@subDir=graal project@com.oracle.graal.compiler@sourceDirs=src -project@com.oracle.graal.compiler@dependencies=com.oracle.graal.lir.amd64,com.oracle.graal.alloc +project@com.oracle.graal.compiler@dependencies=com.oracle.graal.compiler.phases,com.oracle.graal.compiler.virtual,com.oracle.graal.lir.amd64,com.oracle.graal.alloc project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler@javaCompliance=1.7 diff -r debe42b2b92f -r c5afcc2ebd3d src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Sep 17 13:35:55 2012 +0200 +++ b/src/share/vm/runtime/arguments.cpp Mon Sep 17 16:08:46 2012 +0200 @@ -2157,6 +2157,8 @@ "com.oracle.graal.alloc", "com.oracle.graal.snippets", "com.oracle.graal.compiler", + "com.oracle.graal.compiler.phases", + "com.oracle.graal.compiler.virtual", "com.oracle.graal.nodes", "com.oracle.graal.printer", "com.oracle.max.cri",