1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.core.gen; 24 25 import java.util.ArrayDeque; 26 import java.util.Arrays; 27 import java.util.Queue; 28 29 import org.graalvm.compiler.debug.CounterKey; 30 import org.graalvm.compiler.debug.DebugContext; 31 import org.graalvm.compiler.debug.GraalError; 32 import org.graalvm.compiler.lir.ConstantValue; 33 import org.graalvm.compiler.lir.LIRFrameState; 34 import org.graalvm.compiler.lir.LabelRef; 35 import org.graalvm.compiler.lir.Variable; 36 import org.graalvm.compiler.nodes.ConstantNode; 37 import org.graalvm.compiler.nodes.FrameState; 38 import org.graalvm.compiler.nodes.ValueNode; 39 import org.graalvm.compiler.nodes.spi.NodeValueMap; 40 import org.graalvm.compiler.nodes.util.GraphUtil; 41 import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 42 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 43 import org.graalvm.compiler.virtual.nodes.MaterializedObjectState; 44 import org.graalvm.compiler.virtual.nodes.VirtualObjectState; 45 import org.graalvm.util.EconomicMap; 46 import org.graalvm.util.Equivalence; 47 48 import jdk.vm.ci.code.BytecodeFrame; 49 import jdk.vm.ci.code.VirtualObject; 50 import jdk.vm.ci.meta.JavaConstant; 51 import jdk.vm.ci.meta.JavaKind; 52 import jdk.vm.ci.meta.JavaType; 53 import jdk.vm.ci.meta.JavaValue; 54 import jdk.vm.ci.meta.ResolvedJavaField; 55 import jdk.vm.ci.meta.ResolvedJavaType; 56 import jdk.vm.ci.meta.Value; 57 58 /** 59 * Builds {@link LIRFrameState}s from {@link FrameState}s. 60 */ 61 public class DebugInfoBuilder { 62 63 protected final NodeValueMap nodeValueMap; 64 protected final DebugContext debug; 65 66 public DebugInfoBuilder(NodeValueMap nodeValueMap, DebugContext debug) { 67 this.nodeValueMap = nodeValueMap; 68 this.debug = debug; 69 } 70 71 private static final JavaValue[] NO_JAVA_VALUES = {}; 72 private static final JavaKind[] NO_JAVA_KINDS = {}; 73 74 protected final EconomicMap<VirtualObjectNode, VirtualObject> virtualObjects = EconomicMap.create(Equivalence.IDENTITY); 75 protected final EconomicMap<VirtualObjectNode, EscapeObjectState> objectStates = EconomicMap.create(Equivalence.IDENTITY); 76 77 protected final Queue<VirtualObjectNode> pendingVirtualObjects = new ArrayDeque<>(); 78 79 public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) { 80 assert virtualObjects.size() == 0; 81 assert objectStates.size() == 0; 82 assert pendingVirtualObjects.size() == 0; 83 84 // collect all VirtualObjectField instances: 85 FrameState current = topState; 86 do { 87 if (current.virtualObjectMappingCount() > 0) { 88 for (EscapeObjectState state : current.virtualObjectMappings()) { 89 if (!objectStates.containsKey(state.object())) { 90 if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) { 91 objectStates.put(state.object(), state); 92 } 93 } 94 } 95 } 96 current = current.outerFrameState(); 97 } while (current != null); 98 99 BytecodeFrame frame = computeFrameForState(topState); 100 101 VirtualObject[] virtualObjectsArray = null; 102 if (virtualObjects.size() != 0) { 103 // fill in the VirtualObject values 104 VirtualObjectNode vobjNode; 105 while ((vobjNode = pendingVirtualObjects.poll()) != null) { 106 VirtualObject vobjValue = virtualObjects.get(vobjNode); 107 assert vobjValue.getValues() == null; 108 109 JavaValue[] values; 110 JavaKind[] slotKinds; 111 int entryCount = vobjNode.entryCount(); 112 if (entryCount == 0) { 113 values = NO_JAVA_VALUES; 114 slotKinds = NO_JAVA_KINDS; 115 } else { 116 values = new JavaValue[entryCount]; 117 slotKinds = new JavaKind[entryCount]; 118 } 119 if (values.length > 0) { 120 VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobjNode); 121 assert currentField != null; 122 int pos = 0; 123 for (int i = 0; i < entryCount; i++) { 124 ValueNode value = currentField.values().get(i); 125 if (value == null) { 126 JavaKind entryKind = vobjNode.entryKind(i); 127 values[pos] = JavaConstant.defaultForKind(entryKind.getStackKind()); 128 slotKinds[pos] = entryKind.getStackKind(); 129 pos++; 130 } else if (!value.isConstant() || value.asJavaConstant().getJavaKind() != JavaKind.Illegal) { 131 values[pos] = toJavaValue(value); 132 slotKinds[pos] = toSlotKind(value); 133 pos++; 134 } else { 135 assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " + 136 currentField.values().get(i - 1); 137 } 138 } 139 if (pos != entryCount) { 140 values = Arrays.copyOf(values, pos); 141 slotKinds = Arrays.copyOf(slotKinds, pos); 142 } 143 } 144 assert checkValues(vobjValue.getType(), values, slotKinds); 145 vobjValue.setValues(values, slotKinds); 146 } 147 148 virtualObjectsArray = new VirtualObject[virtualObjects.size()]; 149 int index = 0; 150 for (VirtualObject value : virtualObjects.getValues()) { 151 virtualObjectsArray[index++] = value; 152 } 153 virtualObjects.clear(); 154 } 155 objectStates.clear(); 156 157 return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); 158 } 159 160 private boolean checkValues(ResolvedJavaType type, JavaValue[] values, JavaKind[] slotKinds) { 161 assert (values == null) == (slotKinds == null); 162 if (values != null) { 163 assert values.length == slotKinds.length; 164 if (!type.isArray()) { 165 ResolvedJavaField[] fields = type.getInstanceFields(true); 166 int fieldIndex = 0; 167 for (int i = 0; i < values.length; i++) { 168 ResolvedJavaField field = fields[fieldIndex++]; 169 JavaKind valKind = slotKinds[i].getStackKind(); 170 JavaKind fieldKind = storageKind(field.getType()); 171 if (fieldKind == JavaKind.Object) { 172 assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind; 173 } else { 174 if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) { 175 assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int; 176 fieldIndex++; 177 } else { 178 assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind; 179 } 180 } 181 } 182 assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); 183 } else { 184 JavaKind componentKind = storageKind(type.getComponentType()).getStackKind(); 185 if (componentKind == JavaKind.Object) { 186 for (int i = 0; i < values.length; i++) { 187 assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; 188 } 189 } else { 190 for (int i = 0; i < values.length; i++) { 191 assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || 192 (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; 193 } 194 } 195 } 196 } 197 return true; 198 } 199 200 /* 201 * Customization point for subclasses. For example, Word types have a kind Object, but are 202 * internally stored as a primitive value. We do not know about Word types here, but subclasses 203 * do know. 204 */ 205 protected JavaKind storageKind(JavaType type) { 206 return type.getJavaKind(); 207 } 208 209 protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { 210 return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge); 211 } 212 213 protected BytecodeFrame computeFrameForState(FrameState state) { 214 try { 215 assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI; 216 assert state.bci != BytecodeFrame.UNKNOWN_BCI; 217 assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0; 218 assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0; 219 assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0; 220 assert !(state.getMethod().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) || 221 state.locksSize() > 0; 222 assert state.verify(); 223 224 int numLocals = state.localsSize(); 225 int numStack = state.stackSize(); 226 int numLocks = state.locksSize(); 227 228 int numValues = numLocals + numStack + numLocks; 229 int numKinds = numLocals + numStack; 230 231 JavaValue[] values = numValues == 0 ? NO_JAVA_VALUES : new JavaValue[numValues]; 232 JavaKind[] slotKinds = numKinds == 0 ? NO_JAVA_KINDS : new JavaKind[numKinds]; 233 computeLocals(state, numLocals, values, slotKinds); 234 computeStack(state, numLocals, numStack, values, slotKinds); 235 computeLocks(state, values); 236 237 BytecodeFrame caller = null; 238 if (state.outerFrameState() != null) { 239 caller = computeFrameForState(state.outerFrameState()); 240 } 241 242 if (!state.canProduceBytecodeFrame()) { 243 // This typically means a snippet or intrinsic frame state made it to the backend 244 StackTraceElement ste = state.getCode().asStackTraceElement(state.bci); 245 throw new GraalError("Frame state for %s cannot be converted to a BytecodeFrame since the frame state's code is " + 246 "not the same as the frame state method's code", ste); 247 } 248 249 return new BytecodeFrame(caller, state.getMethod(), state.bci, state.rethrowException(), state.duringCall(), values, slotKinds, numLocals, numStack, numLocks); 250 } catch (GraalError e) { 251 throw e.addContext("FrameState: ", state); 252 } 253 } 254 255 protected void computeLocals(FrameState state, int numLocals, JavaValue[] values, JavaKind[] slotKinds) { 256 for (int i = 0; i < numLocals; i++) { 257 ValueNode local = state.localAt(i); 258 values[i] = toJavaValue(local); 259 slotKinds[i] = toSlotKind(local); 260 } 261 } 262 263 protected void computeStack(FrameState state, int numLocals, int numStack, JavaValue[] values, JavaKind[] slotKinds) { 264 for (int i = 0; i < numStack; i++) { 265 ValueNode stack = state.stackAt(i); 266 values[numLocals + i] = toJavaValue(stack); 267 slotKinds[numLocals + i] = toSlotKind(stack); 268 } 269 } 270 271 protected void computeLocks(FrameState state, JavaValue[] values) { 272 for (int i = 0; i < state.locksSize(); i++) { 273 values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i); 274 } 275 } 276 277 protected JavaValue computeLockValue(FrameState state, int i) { 278 return toJavaValue(state.lockAt(i)); 279 } 280 281 private static final CounterKey STATE_VIRTUAL_OBJECTS = DebugContext.counter("StateVirtualObjects"); 282 private static final CounterKey STATE_ILLEGALS = DebugContext.counter("StateIllegals"); 283 private static final CounterKey STATE_VARIABLES = DebugContext.counter("StateVariables"); 284 private static final CounterKey STATE_CONSTANTS = DebugContext.counter("StateConstants"); 285 286 private static JavaKind toSlotKind(ValueNode value) { 287 if (value == null) { 288 return JavaKind.Illegal; 289 } else { 290 return value.getStackKind(); 291 } 292 } 293 294 protected JavaValue toJavaValue(ValueNode value) { 295 try { 296 if (value instanceof VirtualObjectNode) { 297 VirtualObjectNode obj = (VirtualObjectNode) value; 298 EscapeObjectState state = objectStates.get(obj); 299 if (state == null && obj.entryCount() > 0) { 300 // null states occur for objects with 0 fields 301 throw new GraalError("no mapping found for virtual object %s", obj); 302 } 303 if (state instanceof MaterializedObjectState) { 304 return toJavaValue(((MaterializedObjectState) state).materializedValue()); 305 } else { 306 assert obj.entryCount() == 0 || state instanceof VirtualObjectState; 307 VirtualObject vobject = virtualObjects.get(obj); 308 if (vobject == null) { 309 vobject = VirtualObject.get(obj.type(), virtualObjects.size()); 310 virtualObjects.put(obj, vobject); 311 pendingVirtualObjects.add(obj); 312 } 313 STATE_VIRTUAL_OBJECTS.increment(debug); 314 return vobject; 315 } 316 } else { 317 // Remove proxies from constants so the constant can be directly embedded. 318 ValueNode unproxied = GraphUtil.unproxify(value); 319 if (unproxied instanceof ConstantNode) { 320 STATE_CONSTANTS.increment(debug); 321 return unproxied.asJavaConstant(); 322 323 } else if (value != null) { 324 STATE_VARIABLES.increment(debug); 325 Value operand = nodeValueMap.operand(value); 326 if (operand instanceof ConstantValue && ((ConstantValue) operand).isJavaConstant()) { 327 return ((ConstantValue) operand).getJavaConstant(); 328 } else { 329 assert operand instanceof Variable : operand + " for " + value; 330 return (JavaValue) operand; 331 } 332 333 } else { 334 // return a dummy value because real value not needed 335 STATE_ILLEGALS.increment(debug); 336 return Value.ILLEGAL; 337 } 338 } 339 } catch (GraalError e) { 340 throw e.addContext("toValue: ", value); 341 } 342 } 343 }