001/*
002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir;
024
025import static jdk.internal.jvmci.code.ValueUtil.*;
026
027import java.util.*;
028
029import jdk.internal.jvmci.code.*;
030import jdk.internal.jvmci.meta.*;
031
032import com.oracle.graal.lir.LIRInstruction.OperandFlag;
033import com.oracle.graal.lir.LIRInstruction.OperandMode;
034import com.oracle.graal.lir.framemap.*;
035import com.oracle.graal.lir.util.*;
036
037/**
038 * This class represents garbage collection and deoptimization information attached to a LIR
039 * instruction.
040 */
041public class LIRFrameState {
042
043    public final BytecodeFrame topFrame;
044    private final VirtualObject[] virtualObjects;
045    public final LabelRef exceptionEdge;
046    protected DebugInfo debugInfo;
047
048    private IndexedValueMap liveBasePointers;
049
050    public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
051        this.topFrame = topFrame;
052        this.virtualObjects = virtualObjects;
053        this.exceptionEdge = exceptionEdge;
054    }
055
056    public boolean hasDebugInfo() {
057        return debugInfo != null;
058    }
059
060    public DebugInfo debugInfo() {
061        assert debugInfo != null : "debug info not allocated yet";
062        return debugInfo;
063    }
064
065    /**
066     * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
067     *
068     * @param proc The procedure called for variables.
069     */
070    public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
071        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
072            processValues(inst, cur.values, proc);
073        }
074        if (virtualObjects != null) {
075            for (VirtualObject obj : virtualObjects) {
076                processValues(inst, obj.getValues(), proc);
077            }
078        }
079        if (liveBasePointers != null) {
080            liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
081        }
082    }
083
084    /**
085     * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
086     *
087     * @param proc The procedure called for variables.
088     */
089    public void forEachState(LIRInstruction inst, InstructionValueConsumer proc) {
090        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
091            processValues(inst, cur.values, proc);
092        }
093        if (virtualObjects != null) {
094            for (VirtualObject obj : virtualObjects) {
095                processValues(inst, obj.getValues(), proc);
096            }
097        }
098        if (liveBasePointers != null) {
099            liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
100        }
101    }
102
103    /**
104     * We filter out constant and illegal values ourself before calling the procedure, so
105     * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
106     */
107    protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
108
109    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueProcedure proc) {
110        for (int i = 0; i < values.length; i++) {
111            Value value = values[i];
112            if (isIllegal(value)) {
113                continue;
114            }
115            if (value instanceof AllocatableValue) {
116                Value result = proc.doValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
117                if (!value.identityEquals(result)) {
118                    values[i] = result;
119                }
120            } else if (value instanceof StackLockValue) {
121                StackLockValue monitor = (StackLockValue) value;
122                Value owner = monitor.getOwner();
123                if (owner instanceof AllocatableValue) {
124                    monitor.setOwner(proc.doValue(inst, owner, OperandMode.ALIVE, STATE_FLAGS));
125                }
126                Value slot = monitor.getSlot();
127                if (isVirtualStackSlot(slot)) {
128                    monitor.setSlot(asStackSlotValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
129                }
130            } else {
131                assert unprocessed(value);
132            }
133        }
134    }
135
136    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueConsumer proc) {
137        for (int i = 0; i < values.length; i++) {
138            Value value = values[i];
139            if (isIllegal(value)) {
140                continue;
141            } else if (value instanceof AllocatableValue) {
142                proc.visitValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
143            } else if (value instanceof StackLockValue) {
144                StackLockValue monitor = (StackLockValue) value;
145                Value owner = monitor.getOwner();
146                if (owner instanceof AllocatableValue) {
147                    proc.visitValue(inst, owner, OperandMode.ALIVE, STATE_FLAGS);
148                }
149                Value slot = monitor.getSlot();
150                if (isVirtualStackSlot(slot)) {
151                    proc.visitValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS);
152                }
153            } else {
154                assert unprocessed(value);
155            }
156        }
157    }
158
159    private boolean unprocessed(Value value) {
160        if (isIllegal(value)) {
161            // Ignore dead local variables.
162            return true;
163        } else if (isConstant(value)) {
164            // Ignore constants, the register allocator does not need to see them.
165            return true;
166        } else if (isVirtualObject(value)) {
167            assert Arrays.asList(virtualObjects).contains(value);
168            return true;
169        } else {
170            return false;
171        }
172    }
173
174    /**
175     * Called by the register allocator to initialize the frame state.
176     *
177     * @param frameMap The frame map.
178     * @param canHaveRegisters True if there can be any register map entries.
179     */
180    public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
181        debugInfo = new DebugInfo(topFrame, virtualObjects);
182    }
183
184    public IndexedValueMap getLiveBasePointers() {
185        return liveBasePointers;
186    }
187
188    public void setLiveBasePointers(IndexedValueMap liveBasePointers) {
189        this.liveBasePointers = liveBasePointers;
190    }
191
192    @Override
193    public String toString() {
194        return debugInfo != null ? debugInfo.toString() : topFrame != null ? topFrame.toString() : "<empty>";
195    }
196}