Mercurial > hg > graal-compiler
view graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java @ 3092:f34c90b89f54
fixes to escape analysis: propagation of VirtualObject
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Tue, 28 Jun 2011 19:54:51 +0200 |
parents | 536528f48708 |
children | 2fb14099d069 |
line wrap: on
line source
/* * 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.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.*; public class EscapeAnalysisPhase extends Phase { public static class BlockExitState { public final Map<EscapeField, Node> fieldState; public VirtualObject obj; public BlockExitState() { this.fieldState = new HashMap<EscapeField, Node>(); } } public class EscapementFixup { private List<Block> blocks; private final Map<Object, EscapeField> fields = new HashMap<Object, EscapeField>(); private final Map<Block, BlockExitState> exitStates = new HashMap<Block, BlockExitState>(); private final EscapeOp op; private Graph graph; private final Node node; private RiType type; private EscapeField[] escapeFields; public EscapementFixup(EscapeOp op, Graph graph, Node node) { this.op = op; this.graph = graph; this.node = node; } public void apply() { process(); removeAllocation(); } public void removeAllocation() { final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true); identifyBlocksPhase.apply(graph); blocks = identifyBlocksPhase.getBlocks(); final HashMap<Phi, EscapeField> phis = new HashMap<Phi, EscapeField>(); final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node); assert startBlock != null; type = ((Value) node).exactType(); escapeFields = op.fields(node); for (EscapeField field : escapeFields) { fields.put(field.representation(), field); } Block.iteratePostOrder(blocks, new BlockClosure() { public void apply(Block block) { if (GraalOptions.TraceEscapeAnalysis) { 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 = new BlockExitState(); if (block == startBlock) { state.obj = null; for (EscapeField field : fields.values()) { Constant value = Constant.defaultForKind(field.kind(), graph); state.fieldState.put(field, value); state.obj = new VirtualObject(state.obj, value, field, type, escapeFields, graph); } } else { List<Block> predecessors = block.getPredecessors(); Set<EscapeField> mergedFields = new HashSet<EscapeField>(); BlockExitState predState = exitStates.get(predecessors.get(0)); state.obj = predState == null ? null : predState.obj; for (int i = 0; i < predecessors.size(); i++) { BlockExitState exitState = exitStates.get(predecessors.get(i)); if (exitState == null) { mergedFields.addAll(fields.values()); state.obj = null; 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 (EscapeField field : mergedFields) { Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph); state.fieldState.put(field, phi); phis.put(phi, field); state.obj = new VirtualObject(state.obj, phi, field, type, escapeFields, graph); } } } Node current; if (block.firstNode() instanceof StartNode) { current = ((StartNode) block.firstNode()).start(); } else { current = block.firstNode(); } while (current != block.lastNode()) { Node next = ((FixedNodeWithNext) current).next(); op.updateState(node, current, fields, state.fieldState); if (!current.isDeleted() && current instanceof StateSplit) { FrameState stateAfter = ((StateSplit) current).stateAfter(); if (stateAfter != null) { updateFrameState(stateAfter, state.obj); } } current = next; } if (GraalOptions.TraceEscapeAnalysis) { TTY.print(" block end state: "); for (Entry<EscapeField, Node> entry : state.fieldState.entrySet()) { TTY.print("%s->%s ", entry.getKey().name(), entry.getValue()); } TTY.println(); } exitStates.put(block, state); } }, startBlock); for (Entry<Phi, EscapeField> entry : phis.entrySet()) { Phi phi = entry.getKey(); EscapeField field = entry.getValue(); Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge()); List<Block> predecessors = block.getPredecessors(); 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)); if (exitState.fieldState.get(field) != simple) { simple = null; } } if (simple != null) { for (Node usage : new ArrayList<Node>(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>(node.usages())) { assert usage instanceof FrameState || usage instanceof VirtualObject; usage.inputs().replace(node, Node.Null); } if (node instanceof FixedNodeWithNext) { node.replaceAndDelete(((FixedNodeWithNext) node).next()); } else { node.delete(); } } private VirtualObject updateFrameState(FrameState frameState, VirtualObject current) { for (int i = 0; i < frameState.inputs().size(); i++) { if (frameState.inputs().get(i) == node) { frameState.inputs().set(i, current); } else if (frameState.inputs().get(i) instanceof VirtualObject) { VirtualObject obj = (VirtualObject) frameState.inputs().get(i); do { current = updateVirtualObject(obj, current); obj = obj.object(); } while (obj != null); } } if (frameState.outerFrameState() != null) { current = updateFrameState(frameState.outerFrameState(), current); } return current; } private VirtualObject updateVirtualObject(VirtualObject obj, VirtualObject current) { if (obj.input() == node) { obj.setInput(current); } else if (obj.input() instanceof VirtualObject) { VirtualObject obj2 = (VirtualObject) obj.input(); do { current = updateVirtualObject(obj2, current); obj2 = obj2.object(); } while (obj2 != null); } return current; } private void process() { for (Node usage : new ArrayList<Node>(node.usages())) { op.beforeUpdate(node, usage); } } } 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")) { // return; // } // if (true) return; for (Node node : graph.getNodes()) { EscapeOp op = node.lookup(EscapeOp.class); if (op != null && op.canAnalyze(node)) { Set<Node> exits = new HashSet<Node>(); Set<Invoke> invokes = new HashSet<Invoke>(); int iterations = 0; 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 (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), 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(); } break; } if (invokes.size() == 0) { if (GraalOptions.TraceEscapeAnalysis) { TTY.println("!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method); } 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); } break; } new InliningPhase(compilation, ir, invokes, GraalOptions.TraceInlining).apply(graph); exits.clear(); invokes.clear(); } while (iterations++ < 3); } } } private int analyze(EscapeOp op, Node node, Collection<Node> exits, Collection<Invoke> invokes) { int weight = 0; for (Node usage : node.usages()) { 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 { exits.add(usage); if (!GraalOptions.TraceEscapeAnalysis) { break; } } } else { weight++; } } return weight; } public static class EscapeField { 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 { boolean canAnalyze(Node node); boolean escape(Node node, Node usage); EscapeField[] fields(Node node); void beforeUpdate(Node node, Node usage); void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState); } }