001/* 002 * Copyright (c) 2011, 2014, 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.compiler.gen; 024 025import java.util.*; 026import java.util.Map.*; 027 028import com.oracle.graal.graph.*; 029import com.oracle.graal.lir.*; 030import com.oracle.graal.nodes.*; 031import com.oracle.graal.nodes.spi.*; 032import com.oracle.graal.nodes.util.*; 033import com.oracle.graal.nodes.virtual.*; 034import com.oracle.graal.virtual.nodes.*; 035 036import jdk.internal.jvmci.code.*; 037import jdk.internal.jvmci.common.*; 038import com.oracle.graal.debug.*; 039import jdk.internal.jvmci.meta.*; 040 041/** 042 * Builds {@link LIRFrameState}s from {@link FrameState}s. 043 */ 044public class DebugInfoBuilder { 045 046 protected final NodeValueMap nodeValueMap; 047 048 public DebugInfoBuilder(NodeValueMap nodeValueMap) { 049 this.nodeValueMap = nodeValueMap; 050 } 051 052 protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = Node.newMap(); 053 protected final Map<VirtualObjectNode, EscapeObjectState> objectStates = Node.newIdentityMap(); 054 055 public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) { 056 assert virtualObjects.size() == 0; 057 assert objectStates.size() == 0; 058 059 // collect all VirtualObjectField instances: 060 FrameState current = topState; 061 do { 062 if (current.virtualObjectMappingCount() > 0) { 063 for (EscapeObjectState state : current.virtualObjectMappings()) { 064 if (!objectStates.containsKey(state.object())) { 065 if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) { 066 objectStates.put(state.object(), state); 067 } 068 } 069 } 070 } 071 current = current.outerFrameState(); 072 } while (current != null); 073 074 BytecodeFrame frame = computeFrameForState(topState); 075 076 VirtualObject[] virtualObjectsArray = null; 077 if (virtualObjects.size() != 0) { 078 // fill in the VirtualObject values: 079 // during this process new VirtualObjects might be discovered, so repeat until no more 080 // changes occur. 081 boolean changed; 082 do { 083 changed = false; 084 Map<VirtualObjectNode, VirtualObject> virtualObjectsCopy = Node.newIdentityMap(virtualObjects); 085 for (Entry<VirtualObjectNode, VirtualObject> entry : virtualObjectsCopy.entrySet()) { 086 if (entry.getValue().getValues() == null) { 087 VirtualObjectNode vobj = entry.getKey(); 088 Value[] values = new Value[vobj.entryCount()]; 089 if (values.length > 0) { 090 changed = true; 091 VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); 092 assert currentField != null; 093 int pos = 0; 094 for (int i = 0; i < vobj.entryCount(); i++) { 095 if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asJavaConstant().getKind() != Kind.Illegal) { 096 values[pos++] = toValue(currentField.values().get(i)); 097 } else { 098 assert currentField.values().get(i - 1).getKind() == Kind.Double || currentField.values().get(i - 1).getKind() == Kind.Long : vobj + " " + i + " " + 099 currentField.values().get(i - 1); 100 } 101 } 102 if (pos != vobj.entryCount()) { 103 Value[] newValues = new Value[pos]; 104 System.arraycopy(values, 0, newValues, 0, pos); 105 values = newValues; 106 } 107 } 108 entry.getValue().setValues(values); 109 } 110 } 111 } while (changed); 112 113 virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]); 114 virtualObjects.clear(); 115 } 116 objectStates.clear(); 117 118 return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); 119 } 120 121 protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { 122 return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge); 123 } 124 125 protected BytecodeFrame computeFrameForState(FrameState state) { 126 try { 127 assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI; 128 assert state.bci != BytecodeFrame.UNKNOWN_BCI; 129 assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0; 130 assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0; 131 assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0; 132 assert !(state.method().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) || 133 state.locksSize() > 0; 134 assert state.verify(); 135 136 int numLocals = state.localsSize(); 137 int numStack = state.stackSize(); 138 int numLocks = state.locksSize(); 139 140 Value[] values = new Value[numLocals + numStack + numLocks]; 141 computeLocals(state, numLocals, values); 142 computeStack(state, numLocals, numStack, values); 143 computeLocks(state, values); 144 145 BytecodeFrame caller = null; 146 if (state.outerFrameState() != null) { 147 caller = computeFrameForState(state.outerFrameState()); 148 } 149 return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); 150 } catch (JVMCIError e) { 151 throw e.addContext("FrameState: ", state); 152 } 153 } 154 155 protected void computeLocals(FrameState state, int numLocals, Value[] values) { 156 for (int i = 0; i < numLocals; i++) { 157 values[i] = computeLocalValue(state, i); 158 } 159 } 160 161 protected Value computeLocalValue(FrameState state, int i) { 162 return toValue(state.localAt(i)); 163 } 164 165 protected void computeStack(FrameState state, int numLocals, int numStack, Value[] values) { 166 for (int i = 0; i < numStack; i++) { 167 values[numLocals + i] = computeStackValue(state, i); 168 } 169 } 170 171 protected Value computeStackValue(FrameState state, int i) { 172 return toValue(state.stackAt(i)); 173 } 174 175 protected void computeLocks(FrameState state, Value[] values) { 176 for (int i = 0; i < state.locksSize(); i++) { 177 values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i); 178 } 179 } 180 181 protected Value computeLockValue(FrameState state, int i) { 182 return toValue(state.lockAt(i)); 183 } 184 185 private static final DebugMetric STATE_VIRTUAL_OBJECTS = Debug.metric("StateVirtualObjects"); 186 private static final DebugMetric STATE_ILLEGALS = Debug.metric("StateIllegals"); 187 private static final DebugMetric STATE_VARIABLES = Debug.metric("StateVariables"); 188 private static final DebugMetric STATE_CONSTANTS = Debug.metric("StateConstants"); 189 190 protected Value toValue(ValueNode value) { 191 try { 192 if (value instanceof VirtualObjectNode) { 193 VirtualObjectNode obj = (VirtualObjectNode) value; 194 EscapeObjectState state = objectStates.get(obj); 195 if (state == null && obj.entryCount() > 0) { 196 // null states occur for objects with 0 fields 197 throw new JVMCIError("no mapping found for virtual object %s", obj); 198 } 199 if (state instanceof MaterializedObjectState) { 200 return toValue(((MaterializedObjectState) state).materializedValue()); 201 } else { 202 assert obj.entryCount() == 0 || state instanceof VirtualObjectState; 203 VirtualObject vobject = virtualObjects.get(value); 204 if (vobject == null) { 205 vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); 206 virtualObjects.put(obj, vobject); 207 } 208 STATE_VIRTUAL_OBJECTS.increment(); 209 return vobject; 210 } 211 } else { 212 // Remove proxies from constants so the constant can be directly embedded. 213 ValueNode unproxied = GraphUtil.unproxify(value); 214 if (unproxied instanceof ConstantNode) { 215 STATE_CONSTANTS.increment(); 216 return unproxied.asJavaConstant(); 217 218 } else if (value != null) { 219 STATE_VARIABLES.increment(); 220 Value operand = nodeValueMap.operand(value); 221 assert operand != null && (operand instanceof Variable || operand instanceof JavaConstant) : operand + " for " + value; 222 return operand; 223 224 } else { 225 // return a dummy value because real value not needed 226 STATE_ILLEGALS.increment(); 227 return Value.ILLEGAL; 228 } 229 } 230 } catch (JVMCIError e) { 231 throw e.addContext("toValue: ", value); 232 } 233 } 234}