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 */ 23package org.graalvm.compiler.core.gen; 24 25import java.util.ArrayDeque; 26import java.util.Arrays; 27import java.util.Map; 28import java.util.Queue; 29 30import org.graalvm.compiler.debug.Debug; 31import org.graalvm.compiler.debug.DebugCounter; 32import org.graalvm.compiler.debug.GraalError; 33import org.graalvm.compiler.graph.Node; 34import org.graalvm.compiler.lir.ConstantValue; 35import org.graalvm.compiler.lir.LIRFrameState; 36import org.graalvm.compiler.lir.LabelRef; 37import org.graalvm.compiler.lir.Variable; 38import org.graalvm.compiler.nodes.ConstantNode; 39import org.graalvm.compiler.nodes.FrameState; 40import org.graalvm.compiler.nodes.ValueNode; 41import org.graalvm.compiler.nodes.spi.NodeValueMap; 42import org.graalvm.compiler.nodes.util.GraphUtil; 43import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 44import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 45import org.graalvm.compiler.virtual.nodes.MaterializedObjectState; 46import org.graalvm.compiler.virtual.nodes.VirtualObjectState; 47 48import jdk.vm.ci.code.BytecodeFrame; 49import jdk.vm.ci.code.VirtualObject; 50import jdk.vm.ci.meta.JavaKind; 51import jdk.vm.ci.meta.JavaType; 52import jdk.vm.ci.meta.JavaValue; 53import jdk.vm.ci.meta.ResolvedJavaField; 54import jdk.vm.ci.meta.ResolvedJavaType; 55import jdk.vm.ci.meta.Value; 56 57/** 58 * Builds {@link LIRFrameState}s from {@link FrameState}s. 59 */ 60public class DebugInfoBuilder { 61 62 protected final NodeValueMap nodeValueMap; 63 64 public DebugInfoBuilder(NodeValueMap nodeValueMap) { 65 this.nodeValueMap = nodeValueMap; 66 } 67 68 private static final JavaValue[] NO_JAVA_VALUES = {}; 69 private static final JavaKind[] NO_JAVA_KINDS = {}; 70 71 protected final Map<VirtualObjectNode, VirtualObject> virtualObjects = Node.newMap(); 72 protected final Map<VirtualObjectNode, EscapeObjectState> objectStates = Node.newIdentityMap(); 73 74 protected final Queue<VirtualObjectNode> pendingVirtualObjects = new ArrayDeque<>(); 75 76 public LIRFrameState build(FrameState topState, LabelRef exceptionEdge) { 77 assert virtualObjects.size() == 0; 78 assert objectStates.size() == 0; 79 assert pendingVirtualObjects.size() == 0; 80 81 // collect all VirtualObjectField instances: 82 FrameState current = topState; 83 do { 84 if (current.virtualObjectMappingCount() > 0) { 85 for (EscapeObjectState state : current.virtualObjectMappings()) { 86 if (!objectStates.containsKey(state.object())) { 87 if (!(state instanceof MaterializedObjectState) || ((MaterializedObjectState) state).materializedValue() != state.object()) { 88 objectStates.put(state.object(), state); 89 } 90 } 91 } 92 } 93 current = current.outerFrameState(); 94 } while (current != null); 95 96 BytecodeFrame frame = computeFrameForState(topState); 97 98 VirtualObject[] virtualObjectsArray = null; 99 if (virtualObjects.size() != 0) { 100 // fill in the VirtualObject values 101 VirtualObjectNode vobjNode; 102 while ((vobjNode = pendingVirtualObjects.poll()) != null) { 103 VirtualObject vobjValue = virtualObjects.get(vobjNode); 104 assert vobjValue.getValues() == null; 105 106 JavaValue[] values; 107 JavaKind[] slotKinds; 108 int entryCount = vobjNode.entryCount(); 109 if (entryCount == 0) { 110 values = NO_JAVA_VALUES; 111 slotKinds = NO_JAVA_KINDS; 112 } else { 113 values = new JavaValue[entryCount]; 114 slotKinds = new JavaKind[entryCount]; 115 } 116 if (values.length > 0) { 117 VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobjNode); 118 assert currentField != null; 119 int pos = 0; 120 for (int i = 0; i < entryCount; i++) { 121 if (!currentField.values().get(i).isConstant() || currentField.values().get(i).asJavaConstant().getJavaKind() != JavaKind.Illegal) { 122 ValueNode value = currentField.values().get(i); 123 values[pos] = toJavaValue(value); 124 slotKinds[pos] = toSlotKind(value); 125 pos++; 126 } else { 127 assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " + 128 currentField.values().get(i - 1); 129 } 130 } 131 if (pos != entryCount) { 132 values = Arrays.copyOf(values, pos); 133 slotKinds = Arrays.copyOf(slotKinds, pos); 134 } 135 } 136 assert checkValues(vobjValue.getType(), values, slotKinds); 137 vobjValue.setValues(values, slotKinds); 138 } 139 140 virtualObjectsArray = virtualObjects.values().toArray(new VirtualObject[virtualObjects.size()]); 141 virtualObjects.clear(); 142 } 143 objectStates.clear(); 144 145 return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); 146 } 147 148 private boolean checkValues(ResolvedJavaType type, JavaValue[] values, JavaKind[] slotKinds) { 149 assert (values == null) == (slotKinds == null); 150 if (values != null) { 151 assert values.length == slotKinds.length; 152 if (!type.isArray()) { 153 ResolvedJavaField[] fields = type.getInstanceFields(true); 154 int fieldIndex = 0; 155 for (int i = 0; i < values.length; i++) { 156 ResolvedJavaField field = fields[fieldIndex++]; 157 JavaKind valKind = slotKinds[i].getStackKind(); 158 JavaKind fieldKind = storageKind(field.getType()); 159 if (fieldKind == JavaKind.Object) { 160 assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind; 161 } else { 162 if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) { 163 assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int; 164 fieldIndex++; 165 } else { 166 assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind; 167 } 168 } 169 } 170 assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); 171 } else { 172 JavaKind componentKind = storageKind(type.getComponentType()).getStackKind(); 173 if (componentKind == JavaKind.Object) { 174 for (int i = 0; i < values.length; i++) { 175 assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; 176 } 177 } else { 178 for (int i = 0; i < values.length; i++) { 179 assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || 180 (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; 181 } 182 } 183 } 184 } 185 return true; 186 } 187 188 /* 189 * Customization point for subclasses. For example, Word types have a kind Object, but are 190 * internally stored as a primitive value. We do not know about Word types here, but subclasses 191 * do know. 192 */ 193 protected JavaKind storageKind(JavaType type) { 194 return type.getJavaKind(); 195 } 196 197 protected LIRFrameState newLIRFrameState(LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { 198 return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge); 199 } 200 201 protected BytecodeFrame computeFrameForState(FrameState state) { 202 try { 203 assert state.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI; 204 assert state.bci != BytecodeFrame.UNKNOWN_BCI; 205 assert state.bci != BytecodeFrame.BEFORE_BCI || state.locksSize() == 0; 206 assert state.bci != BytecodeFrame.AFTER_BCI || state.locksSize() == 0; 207 assert state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI || state.locksSize() == 0; 208 assert !(state.getMethod().isSynchronized() && state.bci != BytecodeFrame.BEFORE_BCI && state.bci != BytecodeFrame.AFTER_BCI && state.bci != BytecodeFrame.AFTER_EXCEPTION_BCI) || 209 state.locksSize() > 0; 210 assert state.verify(); 211 212 int numLocals = state.localsSize(); 213 int numStack = state.stackSize(); 214 int numLocks = state.locksSize(); 215 216 int numValues = numLocals + numStack + numLocks; 217 int numKinds = numLocals + numStack; 218 219 JavaValue[] values = numValues == 0 ? NO_JAVA_VALUES : new JavaValue[numValues]; 220 JavaKind[] slotKinds = numKinds == 0 ? NO_JAVA_KINDS : new JavaKind[numKinds]; 221 computeLocals(state, numLocals, values, slotKinds); 222 computeStack(state, numLocals, numStack, values, slotKinds); 223 computeLocks(state, values); 224 225 BytecodeFrame caller = null; 226 if (state.outerFrameState() != null) { 227 caller = computeFrameForState(state.outerFrameState()); 228 } 229 230 if (!state.canProduceBytecodeFrame()) { 231 // This typically means a snippet or intrinsic frame state made it to the backend 232 StackTraceElement ste = state.getCode().asStackTraceElement(state.bci); 233 throw new GraalError("Frame state for %s cannot be converted to a BytecodeFrame since the frame state's code is " + 234 "not the same as the frame state method's code", ste); 235 } 236 237 return new BytecodeFrame(caller, state.getMethod(), state.bci, state.rethrowException(), state.duringCall(), values, slotKinds, numLocals, numStack, numLocks); 238 } catch (GraalError e) { 239 throw e.addContext("FrameState: ", state); 240 } 241 } 242 243 protected void computeLocals(FrameState state, int numLocals, JavaValue[] values, JavaKind[] slotKinds) { 244 for (int i = 0; i < numLocals; i++) { 245 ValueNode local = state.localAt(i); 246 values[i] = toJavaValue(local); 247 slotKinds[i] = toSlotKind(local); 248 } 249 } 250 251 protected void computeStack(FrameState state, int numLocals, int numStack, JavaValue[] values, JavaKind[] slotKinds) { 252 for (int i = 0; i < numStack; i++) { 253 ValueNode stack = state.stackAt(i); 254 values[numLocals + i] = toJavaValue(stack); 255 slotKinds[numLocals + i] = toSlotKind(stack); 256 } 257 } 258 259 protected void computeLocks(FrameState state, JavaValue[] values) { 260 for (int i = 0; i < state.locksSize(); i++) { 261 values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i); 262 } 263 } 264 265 protected JavaValue computeLockValue(FrameState state, int i) { 266 return toJavaValue(state.lockAt(i)); 267 } 268 269 private static final DebugCounter STATE_VIRTUAL_OBJECTS = Debug.counter("StateVirtualObjects"); 270 private static final DebugCounter STATE_ILLEGALS = Debug.counter("StateIllegals"); 271 private static final DebugCounter STATE_VARIABLES = Debug.counter("StateVariables"); 272 private static final DebugCounter STATE_CONSTANTS = Debug.counter("StateConstants"); 273 274 private static JavaKind toSlotKind(ValueNode value) { 275 if (value == null) { 276 return JavaKind.Illegal; 277 } else { 278 return value.getStackKind(); 279 } 280 } 281 282 protected JavaValue toJavaValue(ValueNode value) { 283 try { 284 if (value instanceof VirtualObjectNode) { 285 VirtualObjectNode obj = (VirtualObjectNode) value; 286 EscapeObjectState state = objectStates.get(obj); 287 if (state == null && obj.entryCount() > 0) { 288 // null states occur for objects with 0 fields 289 throw new GraalError("no mapping found for virtual object %s", obj); 290 } 291 if (state instanceof MaterializedObjectState) { 292 return toJavaValue(((MaterializedObjectState) state).materializedValue()); 293 } else { 294 assert obj.entryCount() == 0 || state instanceof VirtualObjectState; 295 VirtualObject vobject = virtualObjects.get(obj); 296 if (vobject == null) { 297 vobject = VirtualObject.get(obj.type(), virtualObjects.size()); 298 virtualObjects.put(obj, vobject); 299 pendingVirtualObjects.add(obj); 300 } 301 STATE_VIRTUAL_OBJECTS.increment(); 302 return vobject; 303 } 304 } else { 305 // Remove proxies from constants so the constant can be directly embedded. 306 ValueNode unproxied = GraphUtil.unproxify(value); 307 if (unproxied instanceof ConstantNode) { 308 STATE_CONSTANTS.increment(); 309 return unproxied.asJavaConstant(); 310 311 } else if (value != null) { 312 STATE_VARIABLES.increment(); 313 Value operand = nodeValueMap.operand(value); 314 if (operand instanceof ConstantValue && ((ConstantValue) operand).isJavaConstant()) { 315 return ((ConstantValue) operand).getJavaConstant(); 316 } else { 317 assert operand instanceof Variable : operand + " for " + value; 318 return (JavaValue) operand; 319 } 320 321 } else { 322 // return a dummy value because real value not needed 323 STATE_ILLEGALS.increment(); 324 return Value.ILLEGAL; 325 } 326 } 327 } catch (GraalError e) { 328 throw e.addContext("toValue: ", value); 329 } 330 } 331} 332