view graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java @ 9381:addc2a25d727

Implement merging of frame states if they differ at a merge that does not have its own frame state.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 28 Apr 2013 06:25:26 +0200
parents 6c4ac1a8cd20
children da8823658fe0
line wrap: on
line source

/*
 * Copyright (c) 2013, 2013, 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.phases.common;

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.nodes.*;
import com.oracle.graal.nodes.cfg.*;
import com.oracle.graal.nodes.util.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.graph.*;
import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;

public class FrameStateAssignmentPhase extends Phase {

    private static class FrameStateAssignmentState {

        private FrameState framestate;

        public FrameStateAssignmentState(FrameState framestate) {
            this.framestate = framestate;
        }

        public FrameState getFramestate() {
            return framestate;
        }

        public void setFramestate(FrameState framestate) {
            assert framestate != null;
            this.framestate = framestate;
        }

        @Override
        public String toString() {
            return "FrameStateAssignementState: " + framestate;
        }
    }

    private static class FrameStateAssignementClosure extends BlockIteratorClosure<FrameStateAssignmentState> {

        @Override
        protected void processBlock(Block block, FrameStateAssignmentState currentState) {
            FixedNode node = block.getBeginNode();
            while (node != null) {
                if (node instanceof DeoptimizingNode) {
                    DeoptimizingNode deopt = (DeoptimizingNode) node;
                    if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) {
                        FrameState state = currentState.getFramestate();
                        deopt.setDeoptimizationState(state);
                    }
                }

                if (node instanceof StateSplit) {
                    StateSplit stateSplit = (StateSplit) node;
                    if (stateSplit.stateAfter() != null) {
                        currentState.setFramestate(stateSplit.stateAfter());
                        stateSplit.setStateAfter(null);
                    }
                }

                if (node instanceof FixedWithNextNode) {
                    node = ((FixedWithNextNode) node).next();
                } else {
                    node = null;
                }
            }
        }

        @Override
        protected FrameStateAssignmentState merge(Block mergeBlock, List<FrameStateAssignmentState> states) {
            MergeNode merge = (MergeNode) mergeBlock.getBeginNode();
            if (merge.stateAfter() != null) {
                return new FrameStateAssignmentState(merge.stateAfter());
            }
            return new FrameStateAssignmentState(singleFrameState(merge, states));
        }

        @Override
        protected FrameStateAssignmentState cloneState(FrameStateAssignmentState oldState) {
            return new FrameStateAssignmentState(oldState.getFramestate());
        }

        @Override
        protected List<FrameStateAssignmentState> processLoop(Loop loop, FrameStateAssignmentState initialState) {
            return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
        }

    }

    @Override
    protected void run(StructuredGraph graph) {
        assert checkFixedDeopts(graph);
        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
        ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignmentState(null), null);
    }

    private static boolean checkFixedDeopts(StructuredGraph graph) {
        NodePredicate isFloatingNode = GraphUtil.isFloatingNode();
        for (Node n : graph.getNodes().filterInterface(DeoptimizingNode.class)) {
            if (((DeoptimizingNode) n).canDeoptimize() && isFloatingNode.apply(n)) {
                return false;
            }
        }
        return true;
    }

    private static FrameState singleFrameState(MergeNode merge, List<FrameStateAssignmentState> states) {
        if (states.size() == 0) {
            return null;
        }
        FrameState firstState = states.get(0).getFramestate();
        FrameState singleState = firstState;
        if (singleState == null) {
            return null;
        }
        int singleBci = singleState.bci;
        for (int i = 1; i < states.size(); ++i) {
            FrameState cur = states.get(i).getFramestate();
            if (cur == null) {
                return null;
            }

            if (cur != singleState) {
                singleState = null;
            }

            if (cur.bci != singleBci) {
                singleBci = FrameState.INVALID_FRAMESTATE_BCI;
            }

        }
        if (singleState != null) {
            return singleState;
        }

        if (singleBci != FrameState.INVALID_FRAMESTATE_BCI) {
            FrameState outerState = firstState.outerFrameState();
            boolean duringCall = firstState.duringCall();
            boolean rethrowException = firstState.rethrowException();
            int stackSize = firstState.stackSize();
            int localsSize = firstState.localsSize();
            ResolvedJavaMethod method = firstState.method();
            FrameState newState = firstState.duplicate();
            for (int i = 1; i < states.size(); ++i) {
                FrameState curState = states.get(i).getFramestate();
                assert curState.duringCall() == duringCall;
                assert curState.rethrowException() == rethrowException;
                assert curState.stackSize() == stackSize;
                assert curState.localsSize() == localsSize;
                assert curState.method() == method;
                assert curState.outerFrameState() == outerState;

                for (int j = 0; j < localsSize + stackSize; ++j) {
                    ValueNode oldValue = newState.values().get(j);
                    ValueNode curValue = curState.values().get(j);
                    newState.values().set(j, merge(merge, oldValue, curValue, i));
                }
            }

            Debug.log("Created artificial frame state with bci %d ", singleBci);
            return newState;
        }
        return null;
    }

    private static ValueNode merge(MergeNode merge, ValueNode oldValue, ValueNode newValue, int processedPreds) {
        if (oldValue == newValue) {
            return oldValue;
        }

        if (oldValue instanceof PhiNode && ((PhiNode) oldValue).merge() == merge) {
            ((PhiNode) oldValue).addInput(newValue);
            return oldValue;
        } else {
            PhiNode newPhi = merge.graph().add(new PhiNode(oldValue.kind(), merge));
            for (int i = 0; i < processedPreds; ++i) {
                newPhi.addInput(oldValue);
            }
            newPhi.addInput(newValue);
            return newPhi;
        }
    }
}