/* * Copyright (c) 2011, 2011, 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.gen; import java.util.*; import java.util.Map.Entry; import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.lir.FrameMap.*; import com.oracle.max.graal.extensions.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.virtual.*; import com.sun.cri.ci.*; public class DebugInfoBuilder { public final GraalCompilation compilation; private final NodeMap<StackBlock> lockDataMap; public DebugInfoBuilder(GraalCompilation compilation) { this.compilation = compilation; if (needLockData()) { lockDataMap = new NodeMap<StackBlock>(compilation.graph); } else { lockDataMap = null; } } public boolean needLockData() { return compilation.compiler.runtime.sizeOfLockData() > 0; } public StackBlock lockDataFor(MonitorObject object, boolean create) { if (!needLockData()) { return null; } if (create) { assert lockDataMap.get(object) == null : "lock data must be created once when processing monitor enter node"; StackBlock result = compilation.frameMap().reserveStackBlock(compilation.compiler.runtime.sizeOfLockData(), false); lockDataMap.set(object, result); return result; } else { StackBlock result = lockDataMap.get(object); assert result != null : "lock data must be created once when processing monitor enter node"; return result; } } private HashMap<VirtualObjectNode, CiVirtualObject> virtualObjects = new HashMap<VirtualObjectNode, CiVirtualObject>(); public LIRDebugInfo build(FrameState topState, List<CiStackSlot> pointerSlots, LabelRef exceptionEdge) { if (compilation.placeholderState != null) { return null; } assert virtualObjects.size() == 0; CiFrame frame = computeFrameForState(topState); CiVirtualObject[] virtualObjectsArray = null; if (virtualObjects.size() != 0) { // collect all VirtualObjectField instances: IdentityHashMap<VirtualObjectNode, VirtualObjectFieldNode> objectStates = new IdentityHashMap<VirtualObjectNode, VirtualObjectFieldNode>(); FrameState current = topState; do { for (Node n : current.virtualObjectMappings()) { VirtualObjectFieldNode field = (VirtualObjectFieldNode) n; // null states occur for objects with 0 fields if (field != null && !objectStates.containsKey(field.object())) { objectStates.put(field.object(), field); } } current = current.outerFrameState(); } while (current != null); // fill in the CiVirtualObject values: // during this process new CiVirtualObjects might be discovered, so repeat until no more changes occur. boolean changed; do { changed = false; IdentityHashMap<VirtualObjectNode, CiVirtualObject> virtualObjectsCopy = new IdentityHashMap<VirtualObjectNode, CiVirtualObject>(virtualObjects); for (Entry<VirtualObjectNode, CiVirtualObject> entry : virtualObjectsCopy.entrySet()) { if (entry.getValue().values() == null) { VirtualObjectNode vobj = entry.getKey(); if (vobj instanceof BoxedVirtualObjectNode) { BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj; entry.getValue().setValues(new CiValue[]{toCiValue(boxedVirtualObjectNode.getUnboxedValue())}); } else { CiValue[] values = new CiValue[vobj.fieldsCount()]; entry.getValue().setValues(values); if (values.length > 0) { changed = true; ValueNode currentField = objectStates.get(vobj); assert currentField != null; do { if (currentField instanceof VirtualObjectFieldNode) { int index = ((VirtualObjectFieldNode) currentField).index(); if (values[index] == null) { values[index] = toCiValue(((VirtualObjectFieldNode) currentField).input()); } currentField = ((VirtualObjectFieldNode) currentField).lastState(); } else { assert currentField instanceof PhiNode : currentField; currentField = ((PhiNode) currentField).valueAt(0); } } while (currentField != null); } } } } } while (changed); virtualObjectsArray = virtualObjects.values().toArray(new CiVirtualObject[virtualObjects.size()]); virtualObjects.clear(); } return new LIRDebugInfo(frame, virtualObjectsArray, pointerSlots, exceptionEdge); } private CiFrame computeFrameForState(FrameState state) { CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; int valueIndex = 0; for (int i = 0; i < state.valuesSize(); i++) { values[valueIndex++] = toCiValue(state.valueAt(i)); } for (int i = 0; i < state.locksSize(); i++) { MonitorObject monitorObject = state.lockAt(i); CiValue owner = toCiValue(monitorObject.owner()); CiValue lockData = lockDataFor(monitorObject, false); boolean eliminated = owner instanceof CiVirtualObject; values[valueIndex++] = new CiMonitorValue(owner, lockData, eliminated); } CiFrame caller = null; if (state.outerFrameState() != null) { caller = computeFrameForState(state.outerFrameState()); } CiFrame frame = new CiFrame(caller, state.method(), state.bci, state.rethrowException(), values, state.localsSize(), state.stackSize(), state.locksSize()); if (GraalOptions.Extend) { frame = overrideFrame(frame); } return frame; } private CiValue toCiValue(ValueNode value) { if (value instanceof VirtualObjectNode) { VirtualObjectNode obj = (VirtualObjectNode) value; CiVirtualObject ciObj = virtualObjects.get(value); if (ciObj == null) { ciObj = CiVirtualObject.get(obj.type(), null, virtualObjects.size()); virtualObjects.put(obj, ciObj); } return ciObj; } else if (value instanceof ConstantNode) { return ((ConstantNode) value).value; } else if (value != null) { CiValue operand = compilation.operand(value); assert operand != null && operand instanceof CiVariable || operand instanceof CiConstant; return operand; } else { // return a dummy value because real value not needed return CiValue.IllegalValue; } } public static ThreadLocal<ServiceLoader<FrameModifier>> frameModifierLoader = new ThreadLocal<ServiceLoader<FrameModifier>>(); private CiFrame overrideFrame(CiFrame frame) { ServiceLoader<FrameModifier> serviceLoader = frameModifierLoader.get(); if (serviceLoader == null) { serviceLoader = ServiceLoader.load(FrameModifier.class); frameModifierLoader.set(serviceLoader); } CiFrame result = frame; for (FrameModifier modifier : serviceLoader) { result = modifier.getFrame(compilation.compiler.runtime, result); } return result; } }