Mercurial > hg > truffle
view graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/Inlining.java @ 2874:d90bf514d647
Renamed packages.
author | Thomas Wuerthinger <thomas@wuerthinger.net> |
---|---|
date | Wed, 08 Jun 2011 08:59:54 +0200 |
parents | graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/Inlining.java@0341b6424579 |
children | 3570f1f7903e |
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.graph; import java.lang.reflect.*; import java.util.*; import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.ir.*; 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 Inlining extends Phase { private final C1XCompilation compilation; private final IR ir; private final Queue<Invoke> invokes = new ArrayDeque<Invoke>(); private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>(); private int inliningSize; public Inlining(C1XCompilation compilation, IR ir) { this.compilation = compilation; this.ir = ir; } private void addToQueue(Invoke invoke, RiMethod method) { invokes.add(invoke); methods.add(method); inliningSize += method.code().length; } @Override protected void run(Graph graph) { if (!C1XOptions.Inline) { return; } inliningSize = compilation.method.code().length; int iterations = C1XOptions.MaximumRecursiveInlineLevel; do { for (Node node : graph.getNodes()) { if (node instanceof Invoke) { Invoke invoke = (Invoke) node; RiMethod target = invoke.target; if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { continue; } if (target.canBeStaticallyBound()) { if (checkInliningConditions(invoke.target)) { addToQueue(invoke, invoke.target); } } else { RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { if (checkInliningConditions(concrete)) { if (C1XOptions.TraceInlining) { System.out.println("registering concrete method assumption..."); } compilation.assumptions.recordConcreteMethod(invoke.target, concrete); addToQueue(invoke, concrete); } } } if (inliningSize > C1XOptions.MaximumInstructionCount) { break; } } } assert invokes.size() == methods.size(); if (invokes.isEmpty()) { break; } Invoke invoke; while ((invoke = invokes.poll()) != null) { RiMethod method = methods.remove(); inlineMethod(invoke, method); } DeadCodeElimination dce = new DeadCodeElimination(); dce.apply(graph); if (dce.deletedNodeCount > 0) { ir.verifyAndPrint("After dead code elimination"); } ir.verifyAndPrint("After inlining iteration"); if (inliningSize > C1XOptions.MaximumInstructionCount) { if (C1XOptions.TraceInlining) { System.out.println("inlining stopped: MaximumInstructionCount reached"); } break; } } while(--iterations > 0); } private boolean checkInliningConditions(Invoke invoke) { String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); if (invoke.predecessors().size() == 0) { if (C1XOptions.TraceInlining) { System.out.println("not inlining " + name + " because the invoke is dead code"); } return false; } return true; } private boolean checkInliningConditions(RiMethod method) { String name = null; if (C1XOptions.TraceInlining) { name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; } if (method.code().length > C1XOptions.MaximumInlineSize) { if (C1XOptions.TraceInlining) { System.out.println("not inlining " + name + " because of code size"); } return false; } if (!method.holder().isInitialized()) { if (C1XOptions.TraceInlining) { System.out.println("not inlining " + name + " because of non-initialized class"); } return false; } return true; } private void inlineMethod(Invoke invoke, RiMethod method) { String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; FrameState stateAfter = invoke.stateAfter(); Instruction exceptionEdge = invoke.exceptionEdge(); if (C1XOptions.TraceInlining) { System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); } CompilerGraph graph = new CompilerGraph(); new GraphBuilder(compilation, method, graph).build(true); boolean withReceiver = !Modifier.isStatic(method.accessFlags()); int argumentCount = method.signature().argumentCount(false); Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; int slot = withReceiver ? 1 : 0; int param = withReceiver ? 1 : 0; for (int i = 0; i < argumentCount; i++) { parameters[param++] = invoke.argument(slot); slot += method.signature().argumentKindAt(i).sizeInSlots(); } if (withReceiver) { parameters[0] = invoke.argument(0); } HashMap<Node, Node> replacements = new HashMap<Node, Node>(); ArrayList<Node> nodes = new ArrayList<Node>(); ArrayList<Node> frameStates = new ArrayList<Node>(); Return returnNode = null; Unwind unwindNode = null; StartNode startNode = graph.start(); for (Node node : graph.getNodes()) { if (node != null) { if (node instanceof StartNode) { assert startNode == node; } else if (node instanceof Local) { replacements.put(node, parameters[((Local) node).index()]); } else { nodes.add(node); if (node instanceof Return) { returnNode = (Return) node; } else if (node instanceof Unwind) { unwindNode = (Unwind) node; } else if (node instanceof FrameState) { frameStates.add(node); } } } } if (C1XOptions.TraceInlining) { ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); } assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); Instruction pred; if (withReceiver) { pred = new NullCheck(parameters[0], compilation.graph); } else { pred = new Merge(compilation.graph); } invoke.predecessors().get(0).successors().replace(invoke, pred); replacements.put(startNode, pred); Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements); if (returnNode != null) { List<Node> usages = new ArrayList<Node>(invoke.usages()); for (Node usage : usages) { if (returnNode.result() instanceof Local) { usage.inputs().replace(invoke, replacements.get(returnNode.result())); } else { usage.inputs().replace(invoke, duplicates.get(returnNode.result())); } } Node returnDuplicate = duplicates.get(returnNode); returnDuplicate.inputs().clearAll(); assert returnDuplicate.predecessors().size() == 1; Node returnPred = returnDuplicate.predecessors().get(0); int index = returnDuplicate.predecessorsIndex().get(0); returnPred.successors().setAndClear(index, invoke, 0); returnDuplicate.delete(); } // if (invoke.next() instanceof Merge) { // ((Merge) invoke.next()).removePhiPredecessor(invoke); // } // invoke.successors().clearAll(); invoke.inputs().clearAll(); invoke.setExceptionEdge(null); // invoke.delete(); if (exceptionEdge != null) { if (unwindNode != null) { assert unwindNode.predecessors().size() == 1; assert exceptionEdge.successors().size() == 1; ExceptionObject obj = (ExceptionObject) exceptionEdge; List<Node> usages = new ArrayList<Node>(obj.usages()); for (Node usage : usages) { if (replacements.containsKey(unwindNode.exception())) { usage.inputs().replace(obj, replacements.get(unwindNode.exception())); } else { usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); } } Node unwindDuplicate = duplicates.get(unwindNode); unwindDuplicate.inputs().clearAll(); assert unwindDuplicate.predecessors().size() == 1; Node unwindPred = unwindDuplicate.predecessors().get(0); int index = unwindDuplicate.predecessorsIndex().get(0); unwindPred.successors().setAndClear(index, obj, 0); obj.inputs().clearAll(); obj.delete(); unwindDuplicate.delete(); } } // adjust all frame states that were copied if (frameStates.size() > 0) { FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); for (Node frameState : frameStates) { ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); } } if (C1XOptions.TraceInlining) { ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); } } }