view graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java @ 7530:5e3d1a68664e

applied mx eclipseformat to all Java files
author Doug Simon <doug.simon@oracle.com>
date Wed, 23 Jan 2013 16:34:57 +0100
parents b1ebd583be14
children 4c0a36672095
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.graal.phases.common;

import java.util.*;

import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.PhiNode.PhiType;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.graph.*;

public class FloatingReadPhase extends Phase {

    private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap;

    private static class LoopState {

        public LoopBeginNode loopBegin;
        public MemoryMap state;
        public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>();
        public ValueNode loopEntryAnyLocation;

        public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) {
            this.loopBegin = loopBegin;
            this.state = state;
            this.loopEntryAnyLocation = loopEntryAnyLocation;
        }

        @Override
        public String toString() {
            return "State@" + loopBegin;
        }
    }

    private class MemoryMap implements MergeableState<MemoryMap> {

        private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
        private LinkedList<LoopState> loops;

        public MemoryMap(MemoryMap memoryMap) {
            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
            loops = new LinkedList<>(memoryMap.loops);
        }

        public MemoryMap() {
            lastMemorySnapshot = new IdentityHashMap<>();
            loops = new LinkedList<>();
        }

        @Override
        public String toString() {
            return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString();
        }

        @Override
        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
            if (withStates.size() == 0) {
                return true;
            }

            int minLoops = loops.size();
            for (MemoryMap other : withStates) {
                int otherLoops = other.loops.size();
                if (otherLoops < minLoops) {
                    minLoops = otherLoops;
                }
            }
            while (loops.size() > minLoops) {
                loops.pop();
            }
            for (MemoryMap other : withStates) {
                while (other.loops.size() > minLoops) {
                    other.loops.pop();
                }
            }

            Set<Object> keys = new HashSet<>();
            for (Object key : lastMemorySnapshot.keySet()) {
                keys.add(key);
            }
            for (MemoryMap other : withStates) {
                assert other.loops.size() == loops.size();
                assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin;
                for (Object key : other.lastMemorySnapshot.keySet()) {
                    keys.add(key);
                }
            }
            @SuppressWarnings("unchecked")
            IdentityHashMap<Object, ValueNode> newMemorySnapshot = (IdentityHashMap<Object, ValueNode>) lastMemorySnapshot.clone();

            for (Object key : keys) {
                ValueNode merged = lastMemorySnapshot.get(key);
                if (merged == null) {
                    merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
                }
                int mergedStatesCount = 1;
                boolean isPhi = false;
                for (MemoryMap other : withStates) {
                    ValueNode otherValue = other.lastMemorySnapshot.get(key);
                    if (otherValue == null) {
                        otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
                    }
                    if (isPhi) {
                        ((PhiNode) merged).addInput(otherValue);
                    } else if (merged != otherValue) {
                        PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
                        for (int j = 0; j < mergedStatesCount; j++) {
                            phi.addInput(merged);
                        }
                        phi.addInput(otherValue);
                        merged = phi;
                        isPhi = true;
                        newMemorySnapshot.put(key, phi);
                    }
                    mergedStatesCount++;
                }
            }

            lastMemorySnapshot = newMemorySnapshot;
            return true;
        }

        @Override
        public void loopBegin(LoopBeginNode loopBegin) {
            LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION));
            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
                PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin));
                phi.addInput(entry.getValue());
                entry.setValue(phi);
                loopState.loopPhiLocations.put(phi, entry.getKey());
            }
            loops.push(loopState);
        }

        @Override
        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
            loopEndStatesMap.put(loopBegin, loopEndStates);
            tryFinishLoopPhis(this, loopBegin);
        }

        @Override
        public void afterSplit(BeginNode node) {
            // nothing
        }

        @Override
        public MemoryMap clone() {
            return new MemoryMap(this);
        }
    }

    @Override
    protected void run(StructuredGraph graph) {
        loopEndStatesMap = new IdentityHashMap<>();
        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {

            @Override
            protected void node(FixedNode node) {
                processNode(node, state);
            }
        }.apply();
    }

    private void processNode(FixedNode node, MemoryMap state) {
        if (node instanceof ReadNode) {
            processRead((ReadNode) node, state);
        } else if (node instanceof WriteNode) {
            processWrite((WriteNode) node, state);
        } else if (node instanceof MemoryCheckpoint) {
            processCheckpoint((MemoryCheckpoint) node, state);
        } else if (node instanceof LoopExitNode) {
            processLoopExit((LoopExitNode) node, state);
        }
    }

    private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
        processAnyLocationWrite((ValueNode) checkpoint, state);
    }

    private static void processWrite(WriteNode writeNode, MemoryMap state) {
        if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) {
            processAnyLocationWrite(writeNode, state);
        }
        state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode);
    }

    private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) {
        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
            entry.setValue(modifiying);
        }
        state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying);
        state.loops.clear();
    }

    private void processRead(ReadNode readNode, MemoryMap state) {
        StructuredGraph graph = (StructuredGraph) readNode.graph();
        assert readNode.getNullCheck() == false;
        Object locationIdentity = readNode.location().locationIdentity();
        ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity);
        FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
        floatingRead.setNullCheck(readNode.getNullCheck());
        ValueAnchorNode anchor = null;
        for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
            if (anchor == null) {
                anchor = graph.add(new ValueAnchorNode());
            }
            anchor.addAnchoredNode(guard);
        }
        if (anchor != null) {
            graph.addAfterFixed(readNode, anchor);
        }
        graph.replaceFixedWithFloating(readNode, floatingRead);
    }

    private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) {
        ValueNode lastLocationAccess;
        if (locationIdentity == LocationNode.FINAL_LOCATION) {
            lastLocationAccess = null;
        } else {
            lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity);
            if (lastLocationAccess == null) {
                LoopState lastLoop = state.loops.peek();
                if (lastLoop == null) {
                    lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
                } else {
                    ValueNode phiInit;
                    if (state.loops.size() > 1) {
                        phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity);
                    } else {
                        phiInit = lastLoop.loopEntryAnyLocation;
                    }
                    PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin));
                    phi.addInput(phiInit);
                    lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi);
                    lastLoop.loopPhiLocations.put(phi, locationIdentity);
                    tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin);
                    lastLocationAccess = phi;
                }
                state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess);
            }
        }
        return lastLocationAccess;
    }

    private static void processLoopExit(LoopExitNode exit, MemoryMap state) {
        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
            entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory)));
        }
        if (!state.loops.isEmpty()) {
            state.loops.pop();
        }
    }

    private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) {
        List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin);
        if (loopEndStates == null) {
            return;
        }
        LoopState loopState = loopMemory.loops.get(0);
        int i = 0;
        while (loopState.loopBegin != loopBegin) {
            loopState = loopMemory.loops.get(++i);
        }
        for (PhiNode phi : loopBegin.phis()) {
            if (phi.type() == PhiType.Memory && phi.valueCount() == 1) {
                Object location = loopState.loopPhiLocations.get(phi);
                assert location != null : "unknown location for " + phi;
                for (MemoryMap endState : loopEndStates) {
                    ValueNode otherNode = endState.lastMemorySnapshot.get(location);
                    if (otherNode == null) {
                        otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
                    }
                    phi.addInput(otherNode);
                }
            }
        }
    }
}