/* * Copyright (c) 2009, 2012, 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.lir; import java.util.*; import com.oracle.max.graal.compiler.lir.FrameMap.StackBlock; import com.oracle.max.graal.compiler.util.*; import com.sun.cri.ci.*; /** * This class represents debugging and deoptimization information attached to a LIR instruction. */ public class LIRDebugInfo { public final CiFrame topFrame; private final CiVirtualObject[] virtualObjects; private final List<CiStackSlot> pointerSlots; public final LabelRef exceptionEdge; private CiDebugInfo debugInfo; public LIRDebugInfo(CiFrame topFrame, CiVirtualObject[] virtualObjects, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge) { this.topFrame = topFrame; this.virtualObjects = virtualObjects; this.pointerSlots = pointerSlots; this.exceptionEdge = exceptionEdge; } public CiDebugInfo debugInfo() { assert debugInfo != null : "debug info not allocated yet"; return debugInfo; } public boolean hasDebugInfo() { return debugInfo != null; } /** * Iterator interface for iterating all variables of a frame state. */ public interface ValueProcedure { /** * The iterator method. * * @param value The variable that is iterated. * @return The new value that should replace variable, or {@code null} if the variable should remain unchanged. */ CiValue doValue(CiValue value); } /** * Iterates the frame state and calls the {@link ValueProcedure} for every variable. * * @param proc The procedure called for variables. */ public void forEachLiveStateValue(ValueProcedure proc) { for (CiFrame cur = topFrame; cur != null; cur = cur.caller()) { processValues(cur.values, proc); } if (virtualObjects != null) { for (CiVirtualObject obj : virtualObjects) { processValues(obj.values(), proc); } } } private void processValues(CiValue[] values, ValueProcedure proc) { for (int i = 0; i < values.length; i++) { CiValue value = values[i]; if (value instanceof CiMonitorValue) { CiMonitorValue monitor = (CiMonitorValue) value; if (monitor.owner instanceof CiVariable) { CiValue newValue = proc.doValue(monitor.owner); if (newValue != null) { values[i] = new CiMonitorValue(newValue, monitor.lockData, monitor.eliminated); } } } else { if (value instanceof CiVariable) { CiValue newValue = proc.doValue(value); if (newValue != null) { values[i] = newValue; } } else { // Nothing to do for these types. assert value == CiValue.IllegalValue || value instanceof CiConstant || value instanceof CiStackSlot || (value instanceof CiVirtualObject && Arrays.asList(virtualObjects).contains(value)); } } } } /** * Create the initial {@link CiDebugInfo} object. This initializes the reference maps. * This method requires the size of the stack frame to be known, i.e., this method must be called * after the register allocator has allocated all spill slots and finalized the frame. * * @param op The instruction that contains this debug info. * @param frameMap The frame map used for the compilation. */ public void initDebugInfo(LIRInstruction op, FrameMap frameMap) { CiBitMap frameRefMap = frameMap.initFrameRefMap(); CiBitMap regRefMap = op.hasCall() ? null : new CiBitMap(frameMap.target.arch.registerReferenceMapBitCount); debugInfo = new CiDebugInfo(topFrame, regRefMap, frameRefMap); // Add locks that are in the designated frame area. for (CiFrame cur = topFrame; cur != null; cur = cur.caller()) { for (int i = 0; i < cur.numLocks; i++) { CiMonitorValue lock = (CiMonitorValue) cur.values[i + cur.numLocals + cur.numStack]; if (!lock.lockData.isIllegal()) { cur.values[i + cur.numLocals + cur.numStack] = new CiMonitorValue(lock.owner, frameMap.toStackSlot((StackBlock) lock.lockData), lock.eliminated); } } } // Add additional stack slots for outgoing method parameters. if (pointerSlots != null) { for (CiStackSlot v : pointerSlots) { setReference(v, frameMap); } } } /** * Marks the specified location as a reference in the reference map of the debug information. * The location must be a {@link CiRegisterValue} or a {@link CiStackSlot}. Note that a {@link CiAddress} * cannot be tracked by reference maps, and that a {@link CiConstant} does not have to be added * manually because it is automatically tracked. * * @param location The stack slot or register to be added to the reference map. * @param frameMap The frame map used for the compilation. */ public void setReference(CiValue location, FrameMap frameMap) { if (location instanceof CiStackSlot) { CiStackSlot stackSlot = (CiStackSlot) location; int offset = frameMap.offsetForStackSlot(stackSlot); assert offset % frameMap.target.wordSize == 0 : "must be aligned"; setBit(debugInfo.frameRefMap, offset / frameMap.target.wordSize); } else if (location instanceof CiRegisterValue) { CiRegister register = ((CiRegisterValue) location).reg; setBit(debugInfo.registerRefMap, register.number); } else { throw Util.shouldNotReachHere(); } } private static void setBit(CiBitMap refMap, int bit) { assert bit >= 0 && bit < refMap.size() : "register out of range"; assert !refMap.get(bit) : "Ref map entry already set"; refMap.set(bit); } @Override public String toString() { return debugInfo != null ? debugInfo.toString() : topFrame.toString(); } }