# HG changeset patch # User Lukas Stadler # Date 1308736542 -7200 # Node ID 02e2c1c4ac535a3ab61acbec1400b86d6307e110 # Parent f08a810b84498cbc33c9e0500c290c257b3a1d7e InliningPhase can take a hint on what to inline, initial work on EscapeAnalysisPhase diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Wed Jun 22 11:55:42 2011 +0200 @@ -54,6 +54,9 @@ public static int MaximumDesiredSize = 8000; public static int MaximumShortLoopSize = 5; + // escape analysis settings + public static int ForcedInlineEscapeWeight = 0; + // debugging settings public static boolean VerifyPointerMaps = ____; public static int MethodEndBreakpointGuards = 0; diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Wed Jun 22 11:55:42 2011 +0200 @@ -90,7 +90,7 @@ //printGraph("After DeadCodeElimination", compilation.graph); if (GraalOptions.Inline) { - new InliningPhase(compilation, this, GraalOptions.TraceInlining).apply(compilation.graph); + new InliningPhase(compilation, this, null, GraalOptions.TraceInlining).apply(compilation.graph); } Graph graph = compilation.graph; @@ -99,8 +99,11 @@ new CanonicalizerPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); } -// -// new EscapeAnalysisPhase().apply(graph); + + new EscapeAnalysisPhase(compilation, this).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); if (GraalOptions.OptLoops) { new LoopPhase().apply(graph); diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Wed Jun 22 11:55:42 2011 +0200 @@ -84,7 +84,6 @@ public final RiMethod target; public final RiType returnType; public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL - public final RiTypeProfile profile; /** * Constructs a new Invoke instruction. @@ -95,13 +94,12 @@ * @param isStatic {@code true} if this call is static (no receiver object) * @param target the target method being called */ - public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, RiTypeProfile profile, Graph graph) { + public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) { super(result, args.length, SUCCESSOR_COUNT, graph); this.opcode = opcode; this.target = target; this.returnType = returnType; this.bci = bci; - this.profile = profile; this.argumentCount = args.length; for (int i = 0; i < args.length; i++) { @@ -148,10 +146,6 @@ return target; } - public RiTypeProfile profile() { - return profile; - } - /** * Checks whether this invocation has a receiver object. * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a @@ -201,7 +195,7 @@ @Override public Node copy(Graph into) { - Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, profile, into); + Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into); return x; } } diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryWrite.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryWrite.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryWrite.java Wed Jun 22 11:55:42 2011 +0200 @@ -23,11 +23,15 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.NewInstance.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; public final class MemoryWrite extends MemoryAccess { + private static final EscapeOp ESCAPE = new NewInstanceEscapeOp(); + private static final int INPUT_COUNT = 1; private static final int INPUT_VALUE = 0; private static final int SUCCESSOR_COUNT = 0; @@ -59,4 +63,20 @@ public Node copy(Graph into) { return new MemoryWrite(super.kind, null, displacement(), into); } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == EscapeOp.class) { + return (T) ESCAPE; + } + return super.lookup(clazz); + } + + private static class NewInstanceEscapeOp implements EscapeOp { + @Override + public Escape escape(Node node, Node value) { + return Escape.NewValue; + } + } } diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Wed Jun 22 11:55:42 2011 +0200 @@ -23,6 +23,8 @@ package com.oracle.max.graal.compiler.ir; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.Escape; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -31,6 +33,7 @@ * The {@code NewInstance} instruction represents the allocation of an instance class object. */ public final class NewInstance extends FloatingNode { + private static final EscapeOp ESCAPE = new NewInstanceEscapeOp(); private static final int INPUT_COUNT = 0; private static final int SUCCESSOR_COUNT = 0; @@ -85,4 +88,20 @@ NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into); return x; } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == EscapeOp.class) { + return (T) ESCAPE; + } + return super.lookup(clazz); + } + + private static class NewInstanceEscapeOp implements EscapeOp { + @Override + public Escape escape(Node node, Node value) { + return Escape.NewValue; + } + } } diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java Wed Jun 22 11:55:42 2011 +0200 @@ -29,6 +29,7 @@ import com.oracle.max.graal.compiler.gen.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; public class DeadCodeEliminationPhase extends Phase { @@ -53,20 +54,29 @@ } } // remove if nodes with constant-value comparison -// for (If ifNode : graph.getNodes(If.class)) { -// Compare compare = ifNode.compare(); -// if (compare.x().isConstant() && compare.y().isConstant()) { -// CiConstant constX = compare.x().asConstant(); -// CiConstant constY = compare.y().asConstant(); -// Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime); -// if (result != null) { -// Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); -// ifNode.replace(actualSuccessor); -// } else { -// TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); -// } -// } -// } + for (If ifNode : graph.getNodes(If.class)) { + BooleanNode bool = ifNode.compare(); + if (bool instanceof Compare) { + Compare compare = (Compare) bool; + if (compare.x().isConstant() && compare.y().isConstant()) { + CiConstant constX = compare.x().asConstant(); + CiConstant constY = compare.y().asConstant(); + Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime); + if (result != null) { + Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor(); + ifNode.replace(actualSuccessor); + } else { + TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind); + } + } + } + } + // remove unnecessary FixedGuards + for (FixedGuard guard : graph.getNodes(FixedGuard.class)) { + if (guard.node() instanceof IsNonNull && ((IsNonNull) guard.node()).object() instanceof NewInstance) { + guard.replace(guard.next()); + } + } flood.add(graph.start()); diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Wed Jun 22 11:55:42 2011 +0200 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.phases; + +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ri.*; + + +public class EscapeAnalysisPhase extends Phase { + + + public static class BlockExitState { + public final HashMap fieldState; + + public BlockExitState() { + this.fieldState = new HashMap(); + } + } + + public class EscapementFixup { + + private List blocks; + private final HashMap fields = new HashMap(); + + private final HashMap exitStates = new HashMap(); + + + public void apply(final Graph graph, final Node node) { + process(node); + removeAllocation(graph, node); + } + + public void removeAllocation(final Graph graph, final Node node) { + final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true); + identifyBlocksPhase.apply(graph); + blocks = identifyBlocksPhase.getBlocks(); + + final HashMap phis = new HashMap(); + + Block.iteratePostOrder(blocks, new BlockClosure() { + + public void apply(Block block) { +// TTY.println("Block %d", block.blockID()); +// for (Node n : block.getInstructions()) { +// TTY.println(" %d %s", n.id(), n.shortName()); +// } +// for (Block b : block.getSuccessors()) { +// TTY.print(" %d", b.blockID()); +// } +// TTY.println(); + + BlockExitState state; + List predecessors = block.getPredecessors(); + Set mergedFields = new HashSet(); + state = new BlockExitState(); + for (int i = 0; i < predecessors.size(); i++) { + BlockExitState exitState = exitStates.get(predecessors.get(i)); + if (exitState == null) { + mergedFields.addAll(fields.values()); + } else { + for (RiField field : fields.values()) { + if (state.fieldState.get(field) == null) { + state.fieldState.put(field, exitState.fieldState.get(field)); + } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) { + mergedFields.add(field); + } + } + } + } + if (!mergedFields.isEmpty()) { + assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id(); + for (RiField field : mergedFields) { + Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph); + state.fieldState.put(field, phi); + phis.put(phi, field); + } + } + + if (identifyBlocksPhase.getNodeToBlock().get(node) == block) { + state = new BlockExitState(); + } + + Node current; + if (block.firstNode() instanceof StartNode) { + current = ((StartNode) block.firstNode()).start(); + } else { + current = block.firstNode(); + } + while (current != block.lastNode()) { + if (current instanceof LoadField) { + LoadField x = (LoadField) current; + if (x.object() == node) { + for (Node usage : new ArrayList(x.usages())) { + assert state.fieldState.get(x.field()) != null; + usage.inputs().replace(x, state.fieldState.get(x.field())); + } + current = ((Instruction) current).next(); + x.replace(x.next()); + } else { + current = ((Instruction) current).next(); + } + } else if (current instanceof StoreField) { + StoreField x = (StoreField) current; + if (x.object() == node) { + state.fieldState.put(x.field(), x.value()); + current = ((Instruction) current).next(); + x.replace(x.next()); + } else { + current = ((Instruction) current).next(); + } + } else { + current = ((Instruction) current).next(); + } + } + + exitStates.put(block, state); + } + }); + + for (Entry entry : phis.entrySet()) { + Phi phi = entry.getKey(); + RiField field = entry.getValue(); + Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge()); + + List predecessors = block.getPredecessors(); + for (int i = 0; i < predecessors.size(); i++) { + BlockExitState exitState = exitStates.get(predecessors.get(i)); + assert exitState != null; + Node value = exitState.fieldState.get(field); + TTY.println("fixing phi %d with %s", phi.id(), value); + if (value == null) { + phi.addInput(Constant.defaultForKind(field.kind(), graph)); + } else { + phi.addInput(value); + } + } + + } + + node.delete(); + } + + + private void process(Node node) { + for (Node usage : new ArrayList(node.usages())) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replace(guard.next()); + } + x.delete(); + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.type() == ((NewInstance) node).instanceClass(); + if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) { + FixedGuard guard = (FixedGuard) x.usages().get(0); + guard.replace(guard.next()); + } + x.delete(); + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + x.inputs().replace(node, Node.Null); + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + assert x.object() == node; + assert fields.get(x.field().name()) == null || fields.get(x.field().name()) == x.field(); + fields.put(x.field().name(), x.field()); + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + TTY.println("replacing %d with %d (%s)", x.id(), x.next().id(), x.shortName()); + x.replace(x.next()); + } else if (usage instanceof LoadField) { + LoadField x = (LoadField) usage; + assert x.object() == node; + assert fields.get(x.field().name()) == null || fields.get(x.field().name()) == x.field(); + fields.put(x.field().name(), x.field()); + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + x.replace(x.next()); + } else { + assert false; + } + } + } + } + + private final GraalCompilation compilation; + private final IR ir; + + public EscapeAnalysisPhase(GraalCompilation compilation, IR ir) { + this.compilation = compilation; + this.ir = ir; + } + + @Override + protected void run(Graph graph) { +// if (compilation.method.holder().name().contains("jnt")) { + for (Node node : graph.getNodes()) { + if (node instanceof NewInstance && ((NewInstance) node).instanceClass().isResolved()) { + Set exits = new HashSet(); + Set invokes = new HashSet(); + int iterations = 0; + + int weight; + do { + weight = analyse(node, exits, invokes); +// TTY.print("%d: new value: %d %s, weight %d, escapes at ", iterations, node.id(), node.shortName(), weight); +// for (Node n : exits) { +// TTY.print("%d %s, ", n.id(), n.shortName()); +// } +// for (Node n : invokes) { +// TTY.print("%d %s, ", n.id(), n.shortName()); +// } +// TTY.println(); + if (exits.size() != 0) { + TTY.println("####### escaping object: %d in %s", node.id(), compilation.method); + break; + } + if (invokes.size() == 0) { + TTY.println("!!!!!!!! non-escaping object: %d in %s", node.id(), compilation.method); + new EscapementFixup().apply(graph, node); + break; + } + for (Invoke invoke : invokes) { + new InliningPhase(compilation, ir, invoke, GraalOptions.TraceInlining).apply(graph); + } + exits.clear(); + invokes.clear(); + } while (weight >= GraalOptions.ForcedInlineEscapeWeight && iterations++ < 15); + } + } +// } + } + + private int analyse(Node node, Collection exits, Collection invokes) { + int weight = 0; + for (Node usage : node.usages()) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + weight++; + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + weight++; + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + if (x.value() == node) { + exits.add(x); + } else { + weight++; + } + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + weight++; + } else if (usage instanceof LoadField) { + LoadField x = (LoadField) usage; + weight++; + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + weight++; + } else if (usage instanceof Invoke) { + Invoke x = (Invoke) usage; + invokes.add(x); + } else { + exits.add(usage); + } + } + return weight; + } + + + public static enum Escape { + NewValue, + DoesNotEscape, + DoesEscape + } + + public static interface EscapeOp extends Op { + Escape escape(Node node, Node value); + } +} diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java Wed Jun 22 11:55:42 2011 +0200 @@ -953,7 +953,7 @@ append(deoptimize); frameState.pushReturn(resultType, Constant.defaultForKind(resultType, graph)); } else { - Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), method.typeProfile(bci()), graph); + Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph); Value result = appendWithBCI(invoke); invoke.setExceptionEdge(handleException(null, bci())); frameState.pushReturn(resultType, result); diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Wed Jun 22 11:55:42 2011 +0200 @@ -32,25 +32,29 @@ import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction; import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; public class InliningPhase extends Phase { + public static HashMap methodCount = new HashMap(); + private final GraalCompilation compilation; private final IR ir; private final Queue invokes = new ArrayDeque(); private final Queue methods = new ArrayDeque(); - private final Map parentMethod = new HashMap(); private int inliningSize; private final boolean trace; + private final Invoke hint; - public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) { + public InliningPhase(GraalCompilation compilation, IR ir, Invoke hint, boolean trace) { this.compilation = compilation; this.ir = ir; + this.hint = hint; this.trace = trace; } @@ -60,59 +64,33 @@ inliningSize += method.codeSize(); } - public static HashMap methodCount = new HashMap(); + private Queue newInvokes = new ArrayDeque(); + private Graph graph; + @Override protected void run(Graph graph) { + this.graph = graph; + float ratio = GraalOptions.MaximumInlineRatio; inliningSize = compilation.method.codeSize(); - for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { + + if (hint != null) { + newInvokes.add(hint); + } else { for (Invoke invoke : graph.getNodes(Invoke.class)) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } - RiTypeProfile profile = parent.typeProfile(invoke.bci); - if (!checkInvokeConditions(invoke)) { - continue; - } - if (invoke.target.canBeStaticallyBound()) { - if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) { - addToQueue(invoke, invoke.target); + newInvokes.add(invoke); + } + } + + for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { + Queue queue = newInvokes; + newInvokes = new ArrayDeque(); + for (Invoke invoke : queue) { + if (!invoke.isDeleted()) { + inlineInvoke(invoke, iterations, ratio); + if (inliningSize > GraalOptions.MaximumInstructionCount) { + break; } - } else { - RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); - if (concrete != null) { - if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { - if (trace) { - String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false); - String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false); - TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName); - } - compilation.assumptions.recordConcreteMethod(invoke.target, concrete); - addToQueue(invoke, concrete); - } - } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { - if (GraalOptions.InlineWithTypeCheck) { - // type check and inlining... - concrete = profile.types[0].resolveMethodImpl(invoke.target); - if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { - IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph); - FixedGuard guard = new FixedGuard(graph); - guard.setNode(isType); - assert invoke.predecessors().size() == 1; - invoke.predecessors().get(0).successors().replace(invoke, guard); - guard.setNext(invoke); - - if (trace) { - TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]); - } - addToQueue(invoke, concrete); - } - } - } - } - if (inliningSize > GraalOptions.MaximumInstructionCount) { - break; } } @@ -157,16 +135,65 @@ } } + private void inlineInvoke(Invoke invoke, int iterations, float ratio) { + RiMethod parent = invoke.stateAfter().method(); + RiTypeProfile profile = parent.typeProfile(invoke.bci); + if (!checkInvokeConditions(invoke)) { + return; + } + if (invoke.opcode() == Bytecodes.INVOKESPECIAL || invoke.target.canBeStaticallyBound()) { + if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) { + addToQueue(invoke, invoke.target); + } + } else { + RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); + if (concrete != null) { + if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { + if (trace) { + String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false); + String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false); + TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + addToQueue(invoke, concrete); + } + } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) { + if (GraalOptions.InlineWithTypeCheck) { + // type check and inlining... + concrete = profile.types[0].resolveMethodImpl(invoke.target); + if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) { + IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph); + FixedGuard guard = new FixedGuard(graph); + guard.setNode(isType); + assert invoke.predecessors().size() == 1; + invoke.predecessors().get(0).successors().replace(invoke, guard); + guard.setNext(invoke); + + if (trace) { + TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]); + } + addToQueue(invoke, concrete); + } + } else { + if (trace) { + TTY.println("not inlining %s because GraalOptions.InlineWithTypeCheck is false", methodName(invoke.target, invoke)); + } + } + } else { + if (trace) { + TTY.println("not inlining %s because no monomorphic receiver could be found", methodName(invoke.target, invoke)); + } + } + } + } + private String methodName(RiMethod method) { return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; } private String methodName(RiMethod method, Invoke invoke) { if (invoke != null) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } + RiMethod parent = invoke.stateAfter().method(); return parent.name() + "@" + invoke.bci + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; } else { return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)"; @@ -241,7 +268,11 @@ } private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) { - if (method.codeSize() > GraalOptions.MaximumInlineSize) { + int maximumSize = GraalOptions.MaximumInlineSize; + if (invoke == hint) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } + if (method.codeSize() > maximumSize) { if (trace) { TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize); } @@ -254,10 +285,7 @@ int maximumSize = GraalOptions.MaximumTrivialSize; float ratio = 0; if (profile != null && profile.count > 0) { - RiMethod parent = parentMethod.get(invoke); - if (parent == null) { - parent = compilation.method; - } + RiMethod parent = invoke.stateAfter().method(); ratio = profile.count / (float) parent.invocationCount(); if (ratio >= GraalOptions.FreqInlineRatio) { maximumSize = GraalOptions.MaximumFreqInlineSize; @@ -265,6 +293,9 @@ maximumSize = GraalOptions.MaximumInlineSize; } } + if (invoke == hint) { + maximumSize = GraalOptions.MaximumFreqInlineSize; + } if (method.codeSize() > maximumSize) { if (trace) { TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile); @@ -356,7 +387,7 @@ for (Node node : duplicates.values()) { if (node instanceof Invoke) { - parentMethod.put((Invoke) node, method); + newInvokes.add((Invoke) node); } } diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Wed Jun 22 11:55:42 2011 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.ir.*; import com.oracle.max.graal.graph.*; @@ -138,4 +139,40 @@ public void setInstructions(List instructions) { this.instructions = instructions; } + + + public static void iteratePostOrder(List blocks, BlockClosure closure) { + BitMap visited = new BitMap(blocks.size()); + LinkedList workList = new LinkedList(); + for (Block block : blocks) { + if (block.getPredecessors().size() == 0) { + workList.add(block); + visited.set(block.blockID()); + } + } + + while (!workList.isEmpty()) { + Block b = workList.remove(); + + closure.apply(b); + + for (Block succ : b.getSuccessors()) { + if (!visited.get(succ.blockID())) { + boolean delay = false; + for (Block pred : succ.getPredecessors()) { + if (!visited.get(pred.blockID()) && !(pred.lastNode instanceof LoopEnd)) { + TTY.println("missing pred: %d", pred.blockID()); + delay = true; + break; + } + } + + if (!delay) { + visited.set(succ.blockID()); + workList.add(succ); + } + } + } + } + } } diff -r f08a810b8449 -r 02e2c1c4ac53 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Tue Jun 21 14:32:12 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Wed Jun 22 11:55:42 2011 +0200 @@ -121,6 +121,10 @@ return rethrowException; } + public RiMethod method() { + return method; + } + /** * Gets a copy of this frame state. */