Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java
38920 views
/*1* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.jdi;2627import com.sun.jdi.*;2829import java.util.List;30import java.util.Map;31import java.util.Iterator;32import java.util.ListIterator;33import java.util.HashMap;34import java.util.ArrayList;35import java.util.Collections;36import java.lang.ref.SoftReference;3738/**39* Represents methods with method bodies.40* That is, non-native non-abstract methods.41* Private to MethodImpl.42*/43public class ConcreteMethodImpl extends MethodImpl {4445/*46* A subset of the line number info that is softly cached47*/48static private class SoftLocationXRefs {49final String stratumID; // The stratum of this information50final Map<Integer, List<Location>> lineMapper; // Maps line number to location(s)51final List<Location> lineLocations; // List of locations ordered by code index5253/*54* Note: these do not necessarily correspond to55* the line numbers of the first and last elements56* in the lineLocations list. Use these only for bounds57* checking and with lineMapper.58*/59final int lowestLine;60final int highestLine;6162SoftLocationXRefs(String stratumID, Map<Integer, List<Location>> lineMapper, List<Location> lineLocations,63int lowestLine, int highestLine) {64this.stratumID = stratumID;65this.lineMapper = Collections.unmodifiableMap(lineMapper);66this.lineLocations =67Collections.unmodifiableList(lineLocations);68this.lowestLine = lowestLine;69this.highestLine = highestLine;70}71}7273private Location location = null;74private SoftReference<SoftLocationXRefs> softBaseLocationXRefsRef;75private SoftReference<SoftLocationXRefs> softOtherLocationXRefsRef;76private SoftReference<List<LocalVariable>> variablesRef = null;77private boolean absentVariableInformation = false;78private long firstIndex = -1;79private long lastIndex = -1;80private SoftReference<byte[]> bytecodesRef = null;81private int argSlotCount = -1;8283ConcreteMethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType,84long ref,85String name, String signature,86String genericSignature, int modifiers) {8788// The generic signature is set when this is created89super(vm, declaringType, ref, name, signature,90genericSignature, modifiers);91}9293public Location location() {94if (location == null) {95getBaseLocations();96}97return location;98}99100List<Location> sourceNameFilter(List<Location> list,101SDE.Stratum stratum,102String sourceName)103throws AbsentInformationException {104if (sourceName == null) {105return list;106} else {107/* needs sourceName filteration */108List<Location> locs = new ArrayList<Location>();109for (Location loc : list) {110if (((LocationImpl)loc).sourceName(stratum).equals(sourceName)) {111locs.add(loc);112}113}114return locs;115}116}117118List<Location> allLineLocations(SDE.Stratum stratum,119String sourceName)120throws AbsentInformationException {121List<Location> lineLocations = getLocations(stratum).lineLocations;122123if (lineLocations.size() == 0) {124throw new AbsentInformationException();125}126127return Collections.unmodifiableList(128sourceNameFilter(lineLocations, stratum, sourceName));129}130131List<Location> locationsOfLine(SDE.Stratum stratum,132String sourceName,133int lineNumber)134throws AbsentInformationException {135SoftLocationXRefs info = getLocations(stratum);136137if (info.lineLocations.size() == 0) {138throw new AbsentInformationException();139}140141/*142* Find the locations which match the line number143* passed in.144*/145List<Location> list = info.lineMapper.get(new Integer(lineNumber));146147if (list == null) {148list = new ArrayList<Location>(0);149}150return Collections.unmodifiableList(151sourceNameFilter(list, stratum, sourceName));152}153154155public Location locationOfCodeIndex(long codeIndex) {156if (firstIndex == -1) {157getBaseLocations();158}159160/*161* Check for invalid code index.162*/163if (codeIndex < firstIndex || codeIndex > lastIndex) {164return null;165}166167return new LocationImpl(virtualMachine(), this, codeIndex);168}169170171LineInfo codeIndexToLineInfo(SDE.Stratum stratum,172long codeIndex) {173if (firstIndex == -1) {174getBaseLocations();175}176177/*178* Check for invalid code index.179*/180if (codeIndex < firstIndex || codeIndex > lastIndex) {181throw new InternalError(182"Location with invalid code index");183}184185List<Location> lineLocations = getLocations(stratum).lineLocations;186187/*188* Check for absent line numbers.189*/190if (lineLocations.size() == 0) {191return super.codeIndexToLineInfo(stratum, codeIndex);192}193194Iterator<Location> iter = lineLocations.iterator();195/*196* Treat code before the beginning of the first line table197* entry as part of the first line. javac will generate198* code like this for some local classes. This "prolog"199* code contains assignments from locals in the enclosing200* scope to synthetic fields in the local class. Same for201* other language prolog code.202*/203LocationImpl bestMatch = (LocationImpl)iter.next();204while (iter.hasNext()) {205LocationImpl current = (LocationImpl)iter.next();206if (current.codeIndex() > codeIndex) {207break;208}209bestMatch = current;210}211return bestMatch.getLineInfo(stratum);212}213214215public List<LocalVariable> variables() throws AbsentInformationException {216return getVariables();217}218219public List<LocalVariable> variablesByName(String name) throws AbsentInformationException {220List<LocalVariable> variables = getVariables();221222List<LocalVariable> retList = new ArrayList<LocalVariable>(2);223Iterator<LocalVariable> iter = variables.iterator();224while(iter.hasNext()) {225LocalVariable variable = iter.next();226if (variable.name().equals(name)) {227retList.add(variable);228}229}230return retList;231}232233public List<LocalVariable> arguments() throws AbsentInformationException {234List<LocalVariable> variables = getVariables();235236List<LocalVariable> retList = new ArrayList<LocalVariable>(variables.size());237Iterator<LocalVariable> iter = variables.iterator();238while(iter.hasNext()) {239LocalVariable variable = iter.next();240if (variable.isArgument()) {241retList.add(variable);242}243}244return retList;245}246247public byte[] bytecodes() {248byte[] bytecodes = (bytecodesRef == null) ? null :249bytecodesRef.get();250if (bytecodes == null) {251try {252bytecodes = JDWP.Method.Bytecodes.253process(vm, declaringType, ref).bytes;254} catch (JDWPException exc) {255throw exc.toJDIException();256}257bytecodesRef = new SoftReference<byte[]>(bytecodes);258}259/*260* Arrays are always modifiable, so it is a little unsafe261* to return the cached bytecodes directly; instead, we262* make a clone at the cost of using more memory.263*/264return bytecodes.clone();265}266267int argSlotCount() throws AbsentInformationException {268if (argSlotCount == -1) {269getVariables();270}271return argSlotCount;272}273274private SoftLocationXRefs getLocations(SDE.Stratum stratum) {275if (stratum.isJava()) {276return getBaseLocations();277}278String stratumID = stratum.id();279SoftLocationXRefs info =280(softOtherLocationXRefsRef == null) ? null :281softOtherLocationXRefsRef.get();282if (info != null && info.stratumID.equals(stratumID)) {283return info;284}285286List<Location> lineLocations = new ArrayList<Location>();287Map<Integer, List<Location>> lineMapper = new HashMap<Integer, List<Location>>();288int lowestLine = -1;289int highestLine = -1;290SDE.LineStratum lastLineStratum = null;291SDE.Stratum baseStratum =292declaringType.stratum(SDE.BASE_STRATUM_NAME);293Iterator<Location> it = getBaseLocations().lineLocations.iterator();294while(it.hasNext()) {295LocationImpl loc = (LocationImpl)it.next();296int baseLineNumber = loc.lineNumber(baseStratum);297SDE.LineStratum lineStratum =298stratum.lineStratum(declaringType,299baseLineNumber);300301if (lineStratum == null) {302// location not mapped in this stratum303continue;304}305306int lineNumber = lineStratum.lineNumber();307308// remove unmapped and dup lines309if ((lineNumber != -1) &&310(!lineStratum.equals(lastLineStratum))) {311lastLineStratum = lineStratum;312313// Remember the largest/smallest line number314if (lineNumber > highestLine) {315highestLine = lineNumber;316}317if ((lineNumber < lowestLine) || (lowestLine == -1)) {318lowestLine = lineNumber;319}320321loc.addStratumLineInfo(322new StratumLineInfo(stratumID,323lineNumber,324lineStratum.sourceName(),325lineStratum.sourcePath()));326327// Add to the location list328lineLocations.add(loc);329330// Add to the line -> locations map331Integer key = new Integer(lineNumber);332List<Location> mappedLocs = lineMapper.get(key);333if (mappedLocs == null) {334mappedLocs = new ArrayList<Location>(1);335lineMapper.put(key, mappedLocs);336}337mappedLocs.add(loc);338}339}340341info = new SoftLocationXRefs(stratumID,342lineMapper, lineLocations,343lowestLine, highestLine);344softOtherLocationXRefsRef = new SoftReference<SoftLocationXRefs>(info);345return info;346}347348private SoftLocationXRefs getBaseLocations() {349SoftLocationXRefs info = (softBaseLocationXRefsRef == null) ? null :350softBaseLocationXRefsRef.get();351if (info != null) {352return info;353}354355JDWP.Method.LineTable lntab = null;356try {357lntab = JDWP.Method.LineTable.process(vm, declaringType, ref);358} catch (JDWPException exc) {359/*360* Note: the absent info error shouldn't happen here361* because the first and last index are always available.362*/363throw exc.toJDIException();364}365366int count = lntab.lines.length;367368List<Location> lineLocations = new ArrayList<Location>(count);369Map<Integer, List<Location>>lineMapper = new HashMap<Integer, List<Location>>();370int lowestLine = -1;371int highestLine = -1;372for (int i = 0; i < count; i++) {373long bci = lntab.lines[i].lineCodeIndex;374int lineNumber = lntab.lines[i].lineNumber;375376/*377* Some compilers will point multiple consecutive378* lines at the same location. We need to choose379* one of them so that we can consistently map back380* and forth between line and location. So we choose381* to record only the last line entry at a particular382* location.383*/384if ((i + 1 == count) || (bci != lntab.lines[i+1].lineCodeIndex)) {385// Remember the largest/smallest line number386if (lineNumber > highestLine) {387highestLine = lineNumber;388}389if ((lineNumber < lowestLine) || (lowestLine == -1)) {390lowestLine = lineNumber;391}392LocationImpl loc =393new LocationImpl(virtualMachine(), this, bci);394loc.addBaseLineInfo(395new BaseLineInfo(lineNumber, declaringType));396397// Add to the location list398lineLocations.add(loc);399400// Add to the line -> locations map401Integer key = new Integer(lineNumber);402List<Location> mappedLocs = lineMapper.get(key);403if (mappedLocs == null) {404mappedLocs = new ArrayList<Location>(1);405lineMapper.put(key, mappedLocs);406}407mappedLocs.add(loc);408}409}410411/*412* firstIndex, lastIndex, and startLocation need to be413* retrieved only once since they are strongly referenced.414*/415if (location == null) {416firstIndex = lntab.start;417lastIndex = lntab.end;418/*419* The startLocation is the first one in the420* location list if we have one;421* otherwise, we construct a location for a422* method start with no line info423*/424if (count > 0) {425location = lineLocations.get(0);426} else {427location = new LocationImpl(virtualMachine(), this,428firstIndex);429}430}431432info = new SoftLocationXRefs(SDE.BASE_STRATUM_NAME,433lineMapper, lineLocations,434lowestLine, highestLine);435softBaseLocationXRefsRef = new SoftReference<SoftLocationXRefs>(info);436return info;437}438439private List<LocalVariable> getVariables1_4() throws AbsentInformationException {440JDWP.Method.VariableTable vartab = null;441try {442vartab = JDWP.Method.VariableTable.443process(vm, declaringType, ref);444} catch (JDWPException exc) {445if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {446absentVariableInformation = true;447throw new AbsentInformationException();448} else {449throw exc.toJDIException();450}451}452453// Get the number of slots used by argument variables454argSlotCount = vartab.argCnt;455int count = vartab.slots.length;456List<LocalVariable> variables = new ArrayList<LocalVariable>(count);457for (int i=0; i<count; i++) {458JDWP.Method.VariableTable.SlotInfo si = vartab.slots[i];459460/*461* Skip "this*" entries because they are never real462* variables from the JLS perspective.463*/464if (!si.name.startsWith("this$") && !si.name.equals("this")) {465Location scopeStart = new LocationImpl(virtualMachine(),466this, si.codeIndex);467Location scopeEnd =468new LocationImpl(virtualMachine(), this,469si.codeIndex + si.length - 1);470LocalVariable variable =471new LocalVariableImpl(virtualMachine(), this,472si.slot, scopeStart, scopeEnd,473si.name, si.signature, null);474// Add to the variable list475variables.add(variable);476}477}478return variables;479}480481private List<LocalVariable> getVariables1() throws AbsentInformationException {482483if (!vm.canGet1_5LanguageFeatures()) {484return getVariables1_4();485}486487JDWP.Method.VariableTableWithGeneric vartab = null;488try {489vartab = JDWP.Method.VariableTableWithGeneric.490process(vm, declaringType, ref);491} catch (JDWPException exc) {492if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {493absentVariableInformation = true;494throw new AbsentInformationException();495} else {496throw exc.toJDIException();497}498}499500// Get the number of slots used by argument variables501argSlotCount = vartab.argCnt;502int count = vartab.slots.length;503List<LocalVariable> variables = new ArrayList<LocalVariable>(count);504for (int i=0; i<count; i++) {505JDWP.Method.VariableTableWithGeneric.SlotInfo si = vartab.slots[i];506507/*508* Skip "this*" entries because they are never real509* variables from the JLS perspective.510*/511if (!si.name.startsWith("this$") && !si.name.equals("this")) {512Location scopeStart = new LocationImpl(virtualMachine(),513this, si.codeIndex);514Location scopeEnd =515new LocationImpl(virtualMachine(), this,516si.codeIndex + si.length - 1);517LocalVariable variable =518new LocalVariableImpl(virtualMachine(), this,519si.slot, scopeStart, scopeEnd,520si.name, si.signature,521si.genericSignature);522// Add to the variable list523variables.add(variable);524}525}526return variables;527}528529private List<LocalVariable> getVariables() throws AbsentInformationException {530if (absentVariableInformation) {531throw new AbsentInformationException();532}533534List<LocalVariable> variables = (variablesRef == null) ? null :535variablesRef.get();536if (variables != null) {537return variables;538}539variables = getVariables1();540variables = Collections.unmodifiableList(variables);541variablesRef = new SoftReference<List<LocalVariable>>(variables);542return variables;543}544}545546547