Mercurial > hg > truffle
diff agent/src/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | c18cbe5936b8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/ConcreteMethodImpl.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,467 @@ +/* + * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.jdi; + +import com.sun.jdi.*; +import sun.jvm.hotspot.oops.Symbol; +import sun.jvm.hotspot.oops.LocalVariableTableElement; +import sun.jvm.hotspot.oops.LineNumberTableElement; +import java.util.List; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Comparator; +import java.lang.ref.SoftReference; +import java.util.Collections; + +public class ConcreteMethodImpl extends MethodImpl { + + /* + * A subset of the line number info that is softly cached + */ + static private class SoftLocationXRefs { + final String stratumID; // The stratum of this information + final Map lineMapper; // Maps line number to location(s) + final List lineLocations; // List of locations ordered by code index + + /* + * Note: these do not necessarily correspond to + * the line numbers of the first and last elements + * in the lineLocations list. Use these only for bounds + * checking and with lineMapper. + */ + final int lowestLine; + final int highestLine; + + SoftLocationXRefs(String stratumID, Map lineMapper, List lineLocations, + int lowestLine, int highestLine) { + this.stratumID = stratumID; + this.lineMapper = Collections.unmodifiableMap(lineMapper); + this.lineLocations = + Collections.unmodifiableList(lineLocations); + this.lowestLine = lowestLine; + this.highestLine = highestLine; + } + } + + private SoftReference softBaseLocationXRefsRef; + private SoftReference softOtherLocationXRefsRef; + private SoftReference variablesRef = null; + private int firstIndex = -1; + private int lastIndex = -1; + private Location location; + private SoftReference bytecodesRef = null; + + ConcreteMethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, + sun.jvm.hotspot.oops.Method saMethod ) { + super(vm, declaringType, saMethod); + } + + int argSlotCount() throws AbsentInformationException { + return (int) saMethod.getSizeOfParameters(); + } + + private SoftLocationXRefs getLocations(SDE.Stratum stratum) { + if (stratum.isJava()) { + return getBaseLocations(); + } + String stratumID = stratum.id(); + SoftLocationXRefs info = + (softOtherLocationXRefsRef == null) ? null : + (SoftLocationXRefs)softOtherLocationXRefsRef.get(); + if (info != null && info.stratumID.equals(stratumID)) { + return info; + } + + List lineLocations = new ArrayList(); + Map lineMapper = new HashMap(); + int lowestLine = -1; + int highestLine = -1; + SDE.LineStratum lastLineStratum = null; + SDE.Stratum baseStratum = + declaringType.stratum(SDE.BASE_STRATUM_NAME); + Iterator it = getBaseLocations().lineLocations.iterator(); + while(it.hasNext()) { + LocationImpl loc = (LocationImpl)it.next(); + int baseLineNumber = loc.lineNumber(baseStratum); + SDE.LineStratum lineStratum = + stratum.lineStratum(declaringType, + baseLineNumber); + + if (lineStratum == null) { + // location not mapped in this stratum + continue; + } + + int lineNumber = lineStratum.lineNumber(); + + // remove unmapped and dup lines + if ((lineNumber != -1) && + (!lineStratum.equals(lastLineStratum))) { + lastLineStratum = lineStratum; + // Remember the largest/smallest line number + if (lineNumber > highestLine) { + highestLine = lineNumber; + } + if ((lineNumber < lowestLine) || (lowestLine == -1)) { + lowestLine = lineNumber; + } + + loc.addStratumLineInfo( + new StratumLineInfo(stratumID, + lineNumber, + lineStratum.sourceName(), + lineStratum.sourcePath())); + + // Add to the location list + lineLocations.add(loc); + + // Add to the line -> locations map + Integer key = new Integer(lineNumber); + List mappedLocs = (List)lineMapper.get(key); + if (mappedLocs == null) { + mappedLocs = new ArrayList(1); + lineMapper.put(key, mappedLocs); + } + mappedLocs.add(loc); + } + } + + info = new SoftLocationXRefs(stratumID, + lineMapper, lineLocations, + lowestLine, highestLine); + softOtherLocationXRefsRef = new SoftReference(info); + return info; + } + + private SoftLocationXRefs getBaseLocations() { + SoftLocationXRefs info = (softBaseLocationXRefsRef == null) ? null : + (SoftLocationXRefs)softBaseLocationXRefsRef.get(); + if (info != null) { + return info; + } + + byte[] codeBuf = bytecodes(); + firstIndex = 0; + lastIndex = codeBuf.length - 1; + // This is odd; what is the Location of a Method? + // A StackFrame can have a location, but a Method? + // I guess it must be the Location for bci 0. + location = new LocationImpl(virtualMachine(), this, 0); + + boolean hasLineInfo = saMethod.hasLineNumberTable(); + LineNumberTableElement[] lntab = null; + int count; + + if (hasLineInfo) { + lntab = saMethod.getLineNumberTable(); + count = lntab.length; + } else { + count = 0; + } + + List lineLocations = new ArrayList(count); + Map lineMapper = new HashMap(); + int lowestLine = -1; + int highestLine = -1; + for (int i = 0; i < count; i++) { + long bci = lntab[i].getStartBCI(); + int lineNumber = lntab[i].getLineNumber(); + + /* + * Some compilers will point multiple consecutive + * lines at the same location. We need to choose + * one of them so that we can consistently map back + * and forth between line and location. So we choose + * to record only the last line entry at a particular + * location. + */ + if ((i + 1 == count) || (bci != lntab[i+1].getStartBCI())) { + // Remember the largest/smallest line number + if (lineNumber > highestLine) { + highestLine = lineNumber; + } + if ((lineNumber < lowestLine) || (lowestLine == -1)) { + lowestLine = lineNumber; + } + LocationImpl loc = + new LocationImpl(virtualMachine(), this, bci); + loc.addBaseLineInfo( + new BaseLineInfo(lineNumber, declaringType)); + + // Add to the location list + lineLocations.add(loc); + + // Add to the line -> locations map + Integer key = new Integer(lineNumber); + List mappedLocs = (List)lineMapper.get(key); + if (mappedLocs == null) { + mappedLocs = new ArrayList(1); + lineMapper.put(key, mappedLocs); + } + mappedLocs.add(loc); + } + } + + info = new SoftLocationXRefs(SDE.BASE_STRATUM_NAME, + lineMapper, lineLocations, + lowestLine, highestLine); + softBaseLocationXRefsRef = new SoftReference(info); + return info; + } + + List sourceNameFilter(List list, + SDE.Stratum stratum, + String sourceName) + throws AbsentInformationException { + if (sourceName == null) { + return list; + } else { + /* needs sourceName filteration */ + List locs = new ArrayList(); + Iterator it = list.iterator(); + while (it.hasNext()) { + LocationImpl loc = (LocationImpl)it.next(); + if (loc.sourceName(stratum).equals(sourceName)) { + locs.add(loc); + } + } + return locs; + } + } + + public List allLineLocations(SDE.Stratum stratum, String sourceName) + throws AbsentInformationException { + List lineLocations = getLocations(stratum).lineLocations; + + if (lineLocations.size() == 0) { + throw new AbsentInformationException(); + } + + return Collections.unmodifiableList( + sourceNameFilter(lineLocations, stratum, sourceName)); + } + + public List locationsOfLine(SDE.Stratum stratum, String sourceName, + int lineNumber) throws AbsentInformationException { + SoftLocationXRefs info = getLocations(stratum); + + if (info.lineLocations.size() == 0) { + throw new AbsentInformationException(); + } + + /* + * Find the locations which match the line number + * passed in. + */ + List list = (List)info.lineMapper.get( + new Integer(lineNumber)); + + if (list == null) { + list = new ArrayList(0); + } + return Collections.unmodifiableList( + sourceNameFilter(list, stratum, sourceName)); + } + + LineInfo codeIndexToLineInfo(SDE.Stratum stratum, + long codeIndex) { + if (firstIndex == -1) { + getBaseLocations(); + } + + /* + * Check for invalid code index. + */ + if (codeIndex < firstIndex || codeIndex > lastIndex) { + throw new InternalError( + "Location with invalid code index"); + } + + List lineLocations = getLocations(stratum).lineLocations; + + /* + * Check for absent line numbers. + */ + if (lineLocations.size() == 0) { + return super.codeIndexToLineInfo(stratum, codeIndex); + } + + Iterator iter = lineLocations.iterator(); + /* + * Treat code before the beginning of the first line table + * entry as part of the first line. javac will generate + * code like this for some local classes. This "prolog" + * code contains assignments from locals in the enclosing + * scope to synthetic fields in the local class. Same for + * other language prolog code. + */ + LocationImpl bestMatch = (LocationImpl)iter.next(); + while (iter.hasNext()) { + LocationImpl current = (LocationImpl)iter.next(); + if (current.codeIndex() > codeIndex) { + break; + } + bestMatch = current; + } + return bestMatch.getLineInfo(stratum); + } + + public Location locationOfCodeIndex(long codeIndex) { + if (firstIndex == -1) { + getBaseLocations(); + } + + /* + * Check for invalid code index. + */ + if (codeIndex < firstIndex || codeIndex > lastIndex) { + return null; + } + + return new LocationImpl(virtualMachine(), this, codeIndex); + } + + public List variables() throws AbsentInformationException { + return getVariables(); + } + + public List variablesByName(String name) throws AbsentInformationException { + List variables = getVariables(); + + List retList = new ArrayList(2); + Iterator iter = variables.iterator(); + while(iter.hasNext()) { + LocalVariable variable = (LocalVariable)iter.next(); + if (variable.name().equals(name)) { + retList.add(variable); + } + } + return retList; + } + + public List arguments() throws AbsentInformationException { + if (argumentTypeNames().size() == 0) { + return new ArrayList(0); + } + List variables = getVariables(); + List retList = new ArrayList(variables.size()); + Iterator iter = variables.iterator(); + while(iter.hasNext()) { + LocalVariable variable = (LocalVariable)iter.next(); + if (variable.isArgument()) { + retList.add(variable); + } + } + return retList; + } + + public byte[] bytecodes() { + byte[] bytecodes = (bytecodesRef == null) ? null : + (byte[])bytecodesRef.get(); + if (bytecodes == null) { + bytecodes = saMethod.getByteCode(); + bytecodesRef = new SoftReference(bytecodes); + } + /* + * Arrays are always modifiable, so it is a little unsafe + * to return the cached bytecodes directly; instead, we + * make a clone at the cost of using more memory. + */ + return (byte[])bytecodes.clone(); + } + + public Location location() { + if (location == null) { + getBaseLocations(); + } + return location; + } + + private List getVariables() throws AbsentInformationException { + List variables = (variablesRef == null) ? null : + (List)variablesRef.get(); + if (variables != null) { + return variables; + } + + // if there are no locals, there won't be a LVT + if (saMethod.getMaxLocals() == 0) { + variables = Collections.unmodifiableList(new ArrayList(0)); + variablesRef = new SoftReference(variables); + return variables; + } + + if (! saMethod.hasLocalVariableTable()) { + throw new AbsentInformationException(); + } + //Build up the JDI view of local variable table. + LocalVariableTableElement[] locals = saMethod.getLocalVariableTable(); + int localCount = locals.length; + variables = new ArrayList(localCount); + for (int ii = 0; ii < localCount; ii++) { + String name = + saMethod.getConstants().getSymbolAt(locals[ii].getNameCPIndex()).asString(); + /* + * Skip "this$*", "this+*", "this" entries because they are never real + * variables from the JLS perspective. "this+*" is new with 1.5. + * Instead of using '+', we check for java letter or digit to avoid + * depending on javac's current choice of '+'. + */ + boolean isInternalName = name.startsWith("this") && + (name.length() == 4 || name.charAt(4)=='$' || !Character.isJavaIdentifierPart(name.charAt(4))); + if (! isInternalName) { + int slot = locals[ii].getSlot(); + long codeIndex = locals[ii].getStartBCI(); + int length = locals[ii].getLength(); + Location scopeStart = new LocationImpl(virtualMachine(), + this, codeIndex); + Location scopeEnd = + new LocationImpl(virtualMachine(), this, + codeIndex + length - 1); + String signature = + saMethod.getConstants().getSymbolAt(locals[ii].getDescriptorCPIndex()).asString(); + + int genericSigIndex = locals[ii].getSignatureCPIndex(); + String genericSignature = null; + if (genericSigIndex != 0) { + genericSignature = saMethod.getConstants().getSymbolAt(genericSigIndex).asString(); + } + + LocalVariable variable = + new LocalVariableImpl(virtualMachine(), this, + slot, scopeStart, scopeEnd, + name, signature, genericSignature); + // Add to the variable list + variables.add(variable); + } + } + + variables = Collections.unmodifiableList(variables); + variablesRef = new SoftReference(variables); + return variables; + } +}