# HG changeset patch # User Lukas Stadler # Date 1309187613 -7200 # Node ID be5deef7c7a02adcb4e4b0afd709bcd0579de5ae # Parent 8188167cbb0f59cb403e6fbea876ff7819642e84 more escape analysis changes diff -r 8188167cbb0f -r be5deef7c7a0 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 Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Jun 27 17:13:33 2011 +0200 @@ -56,6 +56,7 @@ // escape analysis settings public static int ForcedInlineEscapeWeight = 0; + public static int MaximumEscapeAnalysisArrayLength = 32; // debugging settings public static boolean VerifyPointerMaps = ____; @@ -103,6 +104,7 @@ public static boolean TraceAssembler = ____; public static boolean TraceInlining = ____; public static boolean TraceDeadCodeElimination = ____; + public static boolean TraceEscapeAnalysis = ____; public static int TraceBytecodeParserLevel = 0; public static boolean QuietBailout = ____; diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Mon Jun 27 17:13:33 2011 +0200 @@ -398,7 +398,7 @@ @Override public void visitNewObjectArray(NewObjectArray x) { XirArgument length = toXirArgument(x.length()); - XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType()); + XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementType(), x.exactType()); emitXir(snippet, x, stateFor(x), null, true); } @@ -1598,7 +1598,9 @@ private void walkStateValue(Value value) { if (value != null) { - if (value instanceof Phi && !((Phi) value).isDead()) { + if (value instanceof VirtualObject) { + walkVirtualObject((VirtualObject) value); + } else if (value instanceof Phi && !((Phi) value).isDead()) { // phi's are special operandForPhi((Phi) value); } else if (value.operand().isIllegal()) { @@ -1609,6 +1611,13 @@ } } + private void walkVirtualObject(VirtualObject value) { + walkStateValue(value.input()); + if (value.object() != null) { + walkVirtualObject(value.object()); + } + } + protected LIRDebugInfo stateFor(Value x) { assert lastState != null : "must have state before instruction for " + x; return stateFor(x, lastState); diff -r 8188167cbb0f -r be5deef7c7a0 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 Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MemoryWrite.java Mon Jun 27 17:13:33 2011 +0200 @@ -30,7 +30,6 @@ 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; @@ -63,20 +62,4 @@ 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 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Mon Jun 27 17:13:33 2011 +0200 @@ -22,13 +22,21 @@ */ package com.oracle.max.graal.compiler.ir; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp; +import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; +import com.sun.cri.ri.*; /** * The {@code NewArray} class is the base of all instructions that allocate arrays. */ public abstract class NewArray extends Instruction { + private static final EscapeOp ESCAPE = new NewArrayEscapeOp(); private static final int INPUT_COUNT = 1; private static final int INPUT_LENGTH = 0; @@ -67,4 +75,158 @@ super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); setLength(length); } + + /** + * The list of instructions which produce input for this instruction. + */ + public Value dimension(int index) { + assert index == 0; + return length(); + } + + /** + * The rank of the array allocated by this instruction, i.e. how many array dimensions. + */ + public int dimensionCount() { + return 1; + } + + public abstract CiKind elementKind(); + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == EscapeOp.class) { + return (T) ESCAPE; + } + return super.lookup(clazz); + } + + private static class NewArrayEscapeOp implements EscapeOp { + + @Override + public boolean canAnalyze(Node node) { + NewArray x = (NewArray) node; + CiConstant length = x.dimension(0).asConstant(); + return length != null && length.asInt() >= 0 && length.asInt() < GraalOptions.MaximumEscapeAnalysisArrayLength; + } + + @Override + public boolean escape(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + assert x.object() == node; + return false; + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.object() == node; + return false; + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + assert x.inputs().contains(node); + return true; + } else if (usage instanceof LoadIndexed) { + LoadIndexed x = (LoadIndexed) usage; + assert x.array() == node; + CiConstant index = x.index().asConstant(); + CiConstant length = ((NewArray) node).dimension(0).asConstant(); + if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) { + return true; + } + return false; + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + assert x.value() == node; + return true; + } else if (usage instanceof StoreIndexed) { + StoreIndexed x = (StoreIndexed) usage; + CiConstant index = x.index().asConstant(); + CiConstant length = ((NewArray) node).dimension(0).asConstant(); + if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) { + return true; + } + return x.value() == node; + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + assert x.object() == node; + return false; + } else if (usage instanceof ArrayLength) { + ArrayLength x = (ArrayLength) usage; + assert x.array() == node; + return false; + } else if (usage instanceof VirtualObject) { + VirtualObject x = (VirtualObject) usage; + return false; + } else { + return true; + } + } + + @Override + public void beforeUpdate(Node node, Node usage) { + 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() == ((NewArray) node).exactType(); + 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 AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + x.replace(x.next()); + } else if (usage instanceof ArrayLength) { + ArrayLength x = (ArrayLength) usage; + x.replace(((NewArray) node).dimension(0)); + } + } + + @Override + public void collectField(Node node, Node usage, Map fields) { + if (usage instanceof AccessIndexed) { + AccessIndexed x = (AccessIndexed) usage; + CiConstant index = x.index().asConstant(); + CiConstant length = ((NewArray) node).dimension(0).asConstant(); + assert index != null && length != null && index.asInt() >= 0 && index.asInt() < length.asInt(); + + Integer representation = index.asInt(); + if (!fields.containsKey(representation)) { + fields.put(representation, new EscapeField("[" + representation + "]", representation, ((NewArray) node).elementKind())); + } + } + } + + @Override + public void updateState(Node node, Node current, Map fields, Map fieldState) { + if (current instanceof AccessIndexed) { + int index = ((AccessIndexed) current).index().asConstant().asInt(); + EscapeField field = fields.get(index); + if (current instanceof LoadIndexed) { + LoadIndexed x = (LoadIndexed) current; + if (x.array() == node) { + for (Node usage : new ArrayList(x.usages())) { + assert fieldState.get(field) != null; + usage.inputs().replace(x, fieldState.get(field)); + } + assert x.usages().size() == 0; + x.replace(x.next()); + } + } else if (current instanceof StoreIndexed) { + StoreIndexed x = (StoreIndexed) current; + if (x.array() == node) { + fieldState.put(field, x.value()); + assert x.usages().size() == 0; + x.replace(x.next()); + } + } + } + } + } } diff -r 8188167cbb0f -r be5deef7c7a0 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 Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Mon Jun 27 17:13:33 2011 +0200 @@ -22,9 +22,12 @@ */ package com.oracle.max.graal.compiler.ir; +import java.util.*; + import com.oracle.max.graal.compiler.debug.*; -import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.Escape; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp; +import com.oracle.max.graal.compiler.value.*; import com.oracle.max.graal.graph.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; @@ -99,9 +102,113 @@ } private static class NewInstanceEscapeOp implements EscapeOp { + @Override - public Escape escape(Node node, Node value) { - return Escape.NewValue; + public boolean canAnalyze(Node node) { + return ((NewInstance) node).instanceClass().isResolved(); + } + + @Override + public boolean escape(Node node, Node usage) { + if (usage instanceof IsNonNull) { + IsNonNull x = (IsNonNull) usage; + assert x.object() == node; + return false; + } else if (usage instanceof IsType) { + IsType x = (IsType) usage; + assert x.object() == node; + return false; + } else if (usage instanceof FrameState) { + FrameState x = (FrameState) usage; + assert x.inputs().contains(node); + return true; + } else if (usage instanceof LoadField) { + LoadField x = (LoadField) usage; + assert x.object() == node; + return false; + } else if (usage instanceof StoreField) { + StoreField x = (StoreField) usage; + return x.value() == node; + } else if (usage instanceof StoreIndexed) { + StoreIndexed x = (StoreIndexed) usage; + assert x.value() == node; + return true; + } else if (usage instanceof AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + assert x.object() == node; + return false; + } else if (usage instanceof VirtualObject) { + VirtualObject x = (VirtualObject) usage; + return false; + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + assert x.object() == node; + return false; + } else { + return true; + } + } + + @Override + public void beforeUpdate(Node node, Node usage) { + 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 AccessMonitor) { + AccessMonitor x = (AccessMonitor) usage; + x.replace(x.next()); + } else if (usage instanceof RegisterFinalizer) { + RegisterFinalizer x = (RegisterFinalizer) usage; + x.replace(x.next()); + } + } + + @Override + public void collectField(Node node, Node usage, Map fields) { + if (usage instanceof AccessField) { + AccessField x = (AccessField) usage; + assert x.object() == node; + if (!fields.containsKey(x.field())) { + fields.put(x.field(), new EscapeField(x.field().name(), x.field(), x.field.kind().stackKind())); + } + } + } + + @Override + public void updateState(Node node, Node current, Map fields, Map fieldState) { + if (current instanceof AccessField) { + EscapeField field = fields.get(((AccessField) current).field()); + if (current instanceof LoadField) { + LoadField x = (LoadField) current; + if (x.object() == node) { + for (Node usage : new ArrayList(x.usages())) { + assert fieldState.get(field) != null; + usage.inputs().replace(x, fieldState.get(field)); + } + assert x.usages().size() == 0; + x.replace(x.next()); + } + } else if (current instanceof StoreField) { + StoreField x = (StoreField) current; + if (x.object() == node) { + fieldState.put(field, x.value()); + assert x.usages().size() == 0; + x.replace(x.next()); + } + } + } } } } diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Mon Jun 27 17:13:33 2011 +0200 @@ -50,6 +50,7 @@ /** * The list of instructions which produce input for this instruction. */ + @Override public Value dimension(int index) { assert index >= 0 && index < dimensionCount; return (Value) inputs().get(super.inputCount() + index); @@ -63,6 +64,7 @@ /** * The rank of the array allocated by this instruction, i.e. how many array dimensions. */ + @Override public int dimensionCount() { return dimensionCount; } @@ -105,6 +107,21 @@ } @Override + public CiKind elementKind() { + return elementType.kind(); + } + + @Override + public RiType exactType() { + return elementType.arrayOf(); + } + + @Override + public RiType declaredType() { + return exactType(); + } + + @Override public void print(LogStream out) { out.print("new multi array ["); for (int i = 0; i < dimensionCount; i++) { diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Mon Jun 27 17:13:33 2011 +0200 @@ -52,11 +52,16 @@ * Gets the type of the elements of the array. * @return the element type of the array */ - public RiType elementClass() { + public RiType elementType() { return elementClass; } @Override + public CiKind elementKind() { + return elementClass.kind(); + } + + @Override public RiType exactType() { return elementClass.arrayOf(); } @@ -73,7 +78,7 @@ @Override public void print(LogStream out) { - out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass())); + out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementType())); } @Override diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Mon Jun 27 17:13:33 2011 +0200 @@ -42,6 +42,7 @@ this.elementType = elementType; } + @Override public CiKind elementKind() { return elementType.kind(); } diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java Mon Jun 27 17:13:33 2011 +0200 @@ -0,0 +1,125 @@ +/* + * 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.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +public class VirtualObject extends FloatingNode { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_OBJECT = 0; + private static final int INPUT_INPUT = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that specifies the old state of the virtual object. + */ + public VirtualObject object() { + return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public VirtualObject setObject(VirtualObject n) { + return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * The instruction that contains the new state of the specified field. + */ + public Value input() { + return (Value) inputs().get(super.inputCount() + INPUT_INPUT); + } + + public Value setInput(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n); + } + + private EscapeField field; + private RiType type; + + /** + * Constructs a new ArrayLength instruction. + * @param array the instruction producing the array + * @param newFrameState the state after executing this instruction + */ + public VirtualObject(VirtualObject object, EscapeField field, RiType type, Graph graph) { + super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.field = field; + this.type = type; + setObject(object); + } + + public EscapeField field() { + return field; + } + + public RiType type() { + return type; + } + + @Override + public void accept(ValueVisitor v) { + // nothing to do... + } + + @Override + public Map getDebugProperties() { + Map properties = super.getDebugProperties(); + properties.put("type", type); + properties.put("field", field); + return properties; + } + + @Override + public String shortName() { + return "VirtualObject " + field.name(); + } + + @Override + public void print(LogStream out) { + out.print(object()).print(".").print(field.name()).print("=").print(input()); + } + + @Override + public Node copy(Graph into) { + VirtualObject x = new VirtualObject(null, field, type, into); + return x; + } +} diff -r 8188167cbb0f -r be5deef7c7a0 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java Mon Jun 27 17:13:33 2011 +0200 @@ -27,11 +27,13 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; 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.ci.*; import com.sun.cri.ri.*; @@ -39,37 +41,50 @@ public static class BlockExitState { - public final HashMap fieldState; + public final Map fieldState; public BlockExitState() { - this.fieldState = new HashMap(); + this.fieldState = new HashMap(); } } public class EscapementFixup { private List blocks; - private final HashMap fields = new HashMap(); - - private final HashMap exitStates = new HashMap(); + private final Map fields = new HashMap(); + private final Map exitStates = new HashMap(); + private final EscapeOp op; + private Graph graph; + private final Node node; - public void apply(final Graph graph, final Node node) { - process(node); - removeAllocation(graph, node); + public EscapementFixup(EscapeOp op, Graph graph, Node node) { + this.op = op; + this.graph = graph; + this.node = node; } - public void removeAllocation(final Graph graph, final Node node) { + public void apply() { + process(); + removeAllocation(); + } + + public void removeAllocation() { final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true); identifyBlocksPhase.apply(graph); blocks = identifyBlocksPhase.getBlocks(); - final HashMap phis = new HashMap(); + final HashMap phis = new HashMap(); + final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node); + assert startBlock != null; + final RiType type = ((Value) node).exactType(); Block.iteratePostOrder(blocks, new BlockClosure() { public void apply(Block block) { -// TTY.println("Block %d", block.blockID()); + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("Block %d", block.blockID()); + } // for (Node n : block.getInstructions()) { // TTY.println(" %d %s", n.id(), n.shortName()); // } @@ -78,37 +93,39 @@ // } // 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); + BlockExitState state = new BlockExitState(); + if (block == startBlock) { + for (EscapeField field : fields.values()) { + state.fieldState.put(field, Constant.defaultForKind(field.kind(), graph)); + } + } else { + List predecessors = block.getPredecessors(); + Set mergedFields = new HashSet(); + for (int i = 0; i < predecessors.size(); i++) { + BlockExitState exitState = exitStates.get(predecessors.get(i)); + if (exitState == null) { + mergedFields.addAll(fields.values()); + break; + } else { + for (EscapeField 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 (!mergedFields.isEmpty()) { + assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id(); + for (EscapeField 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(); @@ -116,99 +133,124 @@ 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(); + Node next = ((Instruction) current).next(); + op.updateState(node, current, fields, state.fieldState); + if (!current.isDeleted() && current instanceof Instruction) { + FrameState stateAfter = ((Instruction) current).stateAfter(); + if (stateAfter != null) { + updateFrameState(stateAfter, state, type, null); } - } 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(); } + current = next; } + if (GraalOptions.TraceEscapeAnalysis) { + TTY.print(" block end state: "); + for (Entry entry : state.fieldState.entrySet()) { + TTY.print("%s->%s ", entry.getKey().name(), entry.getValue()); + } + TTY.println(); + } exitStates.put(block, state); } - }); + }, startBlock); - for (Entry entry : phis.entrySet()) { + for (Entry entry : phis.entrySet()) { Phi phi = entry.getKey(); - RiField field = entry.getValue(); + EscapeField field = entry.getValue(); Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge()); List predecessors = block.getPredecessors(); - for (int i = 0; i < predecessors.size(); i++) { + assert predecessors.size() > 0; + Node simple = exitStates.get(predecessors.get(0)).fieldState.get(field); + for (int i = 1; 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); + if (exitState.fieldState.get(field) != simple) { + simple = null; } } - + if (simple != null) { + for (Node usage : new ArrayList(phi.usages())) { + usage.inputs().replace(phi, simple); + } + phi.delete(); + } else { + for (int i = 0; i < predecessors.size(); i++) { + BlockExitState exitState = exitStates.get(predecessors.get(i)); + assert exitState != null; + Node value = exitState.fieldState.get(field); + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("fixing phi %d with %s", phi.id(), value); + } + if (value == null) { + phi.addInput(Constant.defaultForKind(field.kind(), graph)); + } else { + phi.addInput(value); + } + } + } + } + // the rest of the usages should be dead frame states... + for (Node usage : new ArrayList(node.usages())) { + assert usage instanceof FrameState || usage instanceof VirtualObject; + usage.inputs().replace(node, Node.Null); } - node.delete(); + if (node instanceof Instruction) { + node.replace(((Instruction) node).next()); + } else { + 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()); + private VirtualObject updateFrameState(FrameState frameState, BlockExitState currentState, RiType type, VirtualObject current) { + for (int i = 0; i < frameState.inputs().size(); i++) { + if (frameState.inputs().get(i) == node) { + if (current == null) { + for (EscapeField field : fields.values()) { + current = new VirtualObject(current, field, type, graph); + current.setInput((Value) currentState.fieldState.get(field)); + } } - 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; + frameState.inputs().set(i, current); + } else if (frameState.inputs().get(i) instanceof VirtualObject) { + VirtualObject obj = (VirtualObject) frameState.inputs().get(i); + do { + current = updateVirtualObject(obj, currentState, type, current); + obj = obj.object(); + } while (obj != null); + } + } + if (frameState.outerFrameState() != null) { + current = updateFrameState(frameState.outerFrameState(), currentState, type, current); + } + return current; + } + + private VirtualObject updateVirtualObject(VirtualObject obj, BlockExitState currentState, RiType type, VirtualObject current) { + if (obj.input() == node) { + if (current == null) { + for (EscapeField field : fields.values()) { + current = new VirtualObject(current, field, type, graph); + current.setInput((Value) currentState.fieldState.get(field)); + } + } + obj.setInput(current); + } else if (obj.input() instanceof VirtualObject) { + VirtualObject obj2 = (VirtualObject) obj.input(); + do { + current = updateVirtualObject(obj2, currentState, type, current); + obj2 = obj2.object(); + } while (obj2 != null); + } + return current; + } + + private void process() { + for (Node usage : new ArrayList(node.usages())) { + op.beforeUpdate(node, usage); + if (!usage.isDeleted()) { + op.collectField(node, usage, fields); } } } @@ -224,89 +266,120 @@ @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; +// if (!compilation.method.holder().name().contains("jnt")) { +// return; +// } +// if (true) return; + for (Node node : graph.getNodes()) { + EscapeOp op = node.lookup(EscapeOp.class); + if (op != null && op.canAnalyze(node)) { + 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; + int weight; + int minimumWeight = GraalOptions.ForcedInlineEscapeWeight; + do { + weight = analyze(op, node, exits, invokes); + if (exits.size() != 0) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("####### escaping object: %d %s in %s", node.id(), node.shortName(), compilation.method); + 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 (invokes.size() == 0) { - TTY.println("!!!!!!!! non-escaping object: %d in %s", node.id(), compilation.method); - new EscapementFixup().apply(graph, node); - break; + break; + } + if (invokes.size() == 0) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("!!!!!!!! non-escaping object: %d %s in %s", node.id(), node.shortName(), compilation.method); } - for (Invoke invoke : invokes) { - new InliningPhase(compilation, ir, invoke, GraalOptions.TraceInlining).apply(graph); + new EscapementFixup(op, graph, node).apply(); + new PhiSimplifier(graph); + break; + } + if (weight < minimumWeight) { + if (GraalOptions.TraceEscapeAnalysis) { + TTY.println("####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method); } - exits.clear(); - invokes.clear(); - } while (weight >= GraalOptions.ForcedInlineEscapeWeight && iterations++ < 15); - } + break; + } + new InliningPhase(compilation, ir, invokes, GraalOptions.TraceInlining).apply(graph); + exits.clear(); + invokes.clear(); + } while (iterations++ < 3); } -// } + } } - private int analyse(Node node, Collection exits, Collection invokes) { + private int analyze(EscapeOp op, 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); + boolean escapes = op.escape(node, usage); + if (escapes) { + if (usage instanceof FrameState) { + // nothing to do... + } else if (usage instanceof Invoke) { + invokes.add((Invoke) usage); } else { - weight++; + exits.add(usage); + if (!GraalOptions.TraceEscapeAnalysis) { + break; + } } - } else if (usage instanceof AccessMonitor) { - AccessMonitor x = (AccessMonitor) usage; - weight++; - } else if (usage instanceof LoadField) { - LoadField x = (LoadField) usage; + } else { 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 class EscapeField { - public static enum Escape { - NewValue, - DoesNotEscape, - DoesEscape + private String name; + private Object representation; + private CiKind kind; + + public EscapeField(String name, Object representation, CiKind kind) { + this.name = name; + this.representation = representation; + this.kind = kind; + } + + public String name() { + return name; + } + + public Object representation() { + return representation; + } + + public CiKind kind() { + return kind; + } + + @Override + public String toString() { + return name(); + } } public static interface EscapeOp extends Op { - Escape escape(Node node, Node value); + + boolean canAnalyze(Node node); + + boolean escape(Node node, Node usage); + + void beforeUpdate(Node node, Node usage); + + void collectField(Node node, Node usage, Map fields); + + void updateState(Node node, Node current, Map fields, Map fieldState); + } } diff -r 8188167cbb0f -r be5deef7c7a0 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 Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Mon Jun 27 17:13:33 2011 +0200 @@ -49,12 +49,12 @@ private int inliningSize; private final boolean trace; - private final Invoke hint; + private final Collection hints; - public InliningPhase(GraalCompilation compilation, IR ir, Invoke hint, boolean trace) { + public InliningPhase(GraalCompilation compilation, IR ir, Collection hints, boolean trace) { this.compilation = compilation; this.ir = ir; - this.hint = hint; + this.hints = hints; this.trace = trace; } @@ -74,8 +74,8 @@ float ratio = GraalOptions.MaximumInlineRatio; inliningSize = compilation.method.codeSize(); - if (hint != null) { - newInvokes.add(hint); + if (hints != null) { + newInvokes.addAll(hints); } else { for (Invoke invoke : graph.getNodes(Invoke.class)) { newInvokes.add(invoke); @@ -269,7 +269,7 @@ private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) { int maximumSize = GraalOptions.MaximumInlineSize; - if (invoke == hint) { + if (hints != null && hints.contains(invoke)) { maximumSize = GraalOptions.MaximumFreqInlineSize; } if (method.codeSize() > maximumSize) { @@ -293,7 +293,7 @@ maximumSize = GraalOptions.MaximumInlineSize; } } - if (invoke == hint) { + if (hints != null && hints.contains(invoke)) { maximumSize = GraalOptions.MaximumFreqInlineSize; } if (method.codeSize() > maximumSize) { diff -r 8188167cbb0f -r be5deef7c7a0 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 Wed Jun 22 11:56:15 2011 +0200 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Mon Jun 27 17:13:33 2011 +0200 @@ -140,15 +140,22 @@ this.instructions = instructions; } + public static void iteratePostOrder(List blocks, BlockClosure closure) { + ArrayList startBlocks = new ArrayList(); + for (Block block : blocks) { + if (block.getPredecessors().size() == 0) { + startBlocks.add(block); + } + } + iteratePostOrder(blocks, closure, startBlocks.toArray(new Block[startBlocks.size()])); + } - public static void iteratePostOrder(List blocks, BlockClosure closure) { + public static void iteratePostOrder(List blocks, BlockClosure closure, Block... startBlocks) { 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()); - } + for (Block block : startBlocks) { + workList.add(block); + visited.set(block.blockID()); } while (!workList.isEmpty()) { @@ -161,7 +168,6 @@ 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; }