jdk/src/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2000-2003 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.jdi;
       
    27 
       
    28 import com.sun.jdi.*;
       
    29 
       
    30 import java.util.List;
       
    31 import java.util.Map;
       
    32 import java.util.Iterator;
       
    33 import java.util.ListIterator;
       
    34 import java.util.HashMap;
       
    35 import java.util.ArrayList;
       
    36 import java.util.Collections;
       
    37 import java.lang.ref.SoftReference;
       
    38 
       
    39 /**
       
    40  * Represents methods with method bodies.
       
    41  * That is, non-native non-abstract methods.
       
    42  * Private to MethodImpl.
       
    43  */
       
    44 public class ConcreteMethodImpl extends MethodImpl {
       
    45 
       
    46     /*
       
    47      * A subset of the line number info that is softly cached
       
    48      */
       
    49     static private class SoftLocationXRefs {
       
    50         final String stratumID;   // The stratum of this information
       
    51         final Map<Integer, List<Location>> lineMapper;     // Maps line number to location(s)
       
    52         final List<Location> lineLocations; // List of locations ordered by code index
       
    53 
       
    54         /*
       
    55          * Note: these do not necessarily correspond to
       
    56          * the line numbers of the first and last elements
       
    57          * in the lineLocations list. Use these only for bounds
       
    58          * checking and with lineMapper.
       
    59          */
       
    60         final int lowestLine;
       
    61         final int highestLine;
       
    62 
       
    63         SoftLocationXRefs(String stratumID, Map<Integer, List<Location>> lineMapper, List<Location> lineLocations,
       
    64                      int lowestLine, int highestLine) {
       
    65             this.stratumID = stratumID;
       
    66             this.lineMapper = Collections.unmodifiableMap(lineMapper);
       
    67             this.lineLocations =
       
    68                 Collections.unmodifiableList(lineLocations);
       
    69             this.lowestLine = lowestLine;
       
    70             this.highestLine = highestLine;
       
    71         }
       
    72     }
       
    73 
       
    74     private Location location = null;
       
    75     private SoftReference<SoftLocationXRefs> softBaseLocationXRefsRef;
       
    76     private SoftReference<SoftLocationXRefs> softOtherLocationXRefsRef;
       
    77     private SoftReference<List<LocalVariable>> variablesRef = null;
       
    78     private boolean absentVariableInformation = false;
       
    79     private long firstIndex = -1;
       
    80     private long lastIndex = -1;
       
    81     private SoftReference<byte[]> bytecodesRef = null;
       
    82     private int argSlotCount = -1;
       
    83 
       
    84     ConcreteMethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType,
       
    85                        long ref,
       
    86                        String name, String signature,
       
    87                        String genericSignature, int modifiers) {
       
    88 
       
    89         // The generic signature is set when this is created
       
    90         super(vm, declaringType, ref, name, signature,
       
    91               genericSignature, modifiers);
       
    92     }
       
    93 
       
    94     public Location location() {
       
    95         if (location == null) {
       
    96             getBaseLocations();
       
    97         }
       
    98         return location;
       
    99     }
       
   100 
       
   101     List<Location> sourceNameFilter(List<Location> list,
       
   102                           SDE.Stratum stratum,
       
   103                           String sourceName)
       
   104                             throws AbsentInformationException {
       
   105         if (sourceName == null) {
       
   106             return list;
       
   107         } else {
       
   108             /* needs sourceName filteration */
       
   109             List<Location> locs = new ArrayList<Location>();
       
   110             for (Location loc : list) {
       
   111                 if (((LocationImpl)loc).sourceName(stratum).equals(sourceName)) {
       
   112                     locs.add(loc);
       
   113                 }
       
   114             }
       
   115             return locs;
       
   116         }
       
   117     }
       
   118 
       
   119     List<Location> allLineLocations(SDE.Stratum stratum,
       
   120                           String sourceName)
       
   121                             throws AbsentInformationException {
       
   122         List<Location> lineLocations = getLocations(stratum).lineLocations;
       
   123 
       
   124         if (lineLocations.size() == 0) {
       
   125             throw new AbsentInformationException();
       
   126         }
       
   127 
       
   128         return Collections.unmodifiableList(
       
   129           sourceNameFilter(lineLocations, stratum, sourceName));
       
   130     }
       
   131 
       
   132     List<Location> locationsOfLine(SDE.Stratum stratum,
       
   133                          String sourceName,
       
   134                          int lineNumber)
       
   135                             throws AbsentInformationException {
       
   136         SoftLocationXRefs info = getLocations(stratum);
       
   137 
       
   138         if (info.lineLocations.size() == 0) {
       
   139             throw new AbsentInformationException();
       
   140         }
       
   141 
       
   142         /*
       
   143          * Find the locations which match the line number
       
   144          * passed in.
       
   145          */
       
   146         List<Location> list = info.lineMapper.get(new Integer(lineNumber));
       
   147 
       
   148         if (list == null) {
       
   149             list = new ArrayList<Location>(0);
       
   150         }
       
   151         return Collections.unmodifiableList(
       
   152           sourceNameFilter(list, stratum, sourceName));
       
   153     }
       
   154 
       
   155 
       
   156     public Location locationOfCodeIndex(long codeIndex) {
       
   157         if (firstIndex == -1) {
       
   158             getBaseLocations();
       
   159         }
       
   160 
       
   161         /*
       
   162          * Check for invalid code index.
       
   163          */
       
   164         if (codeIndex < firstIndex || codeIndex > lastIndex) {
       
   165             return null;
       
   166         }
       
   167 
       
   168         return new LocationImpl(virtualMachine(), this, codeIndex);
       
   169     }
       
   170 
       
   171 
       
   172     LineInfo codeIndexToLineInfo(SDE.Stratum stratum,
       
   173                                  long codeIndex) {
       
   174         if (firstIndex == -1) {
       
   175             getBaseLocations();
       
   176         }
       
   177 
       
   178         /*
       
   179          * Check for invalid code index.
       
   180          */
       
   181         if (codeIndex < firstIndex || codeIndex > lastIndex) {
       
   182             throw new InternalError(
       
   183                     "Location with invalid code index");
       
   184         }
       
   185 
       
   186         List<Location> lineLocations = getLocations(stratum).lineLocations;
       
   187 
       
   188         /*
       
   189          * Check for absent line numbers.
       
   190          */
       
   191         if (lineLocations.size() == 0) {
       
   192             return super.codeIndexToLineInfo(stratum, codeIndex);
       
   193         }
       
   194 
       
   195         Iterator iter = lineLocations.iterator();
       
   196         /*
       
   197          * Treat code before the beginning of the first line table
       
   198          * entry as part of the first line.  javac will generate
       
   199          * code like this for some local classes. This "prolog"
       
   200          * code contains assignments from locals in the enclosing
       
   201          * scope to synthetic fields in the local class.  Same for
       
   202          * other language prolog code.
       
   203          */
       
   204         LocationImpl bestMatch = (LocationImpl)iter.next();
       
   205         while (iter.hasNext()) {
       
   206             LocationImpl current = (LocationImpl)iter.next();
       
   207             if (current.codeIndex() > codeIndex) {
       
   208                 break;
       
   209             }
       
   210             bestMatch = current;
       
   211         }
       
   212         return bestMatch.getLineInfo(stratum);
       
   213     }
       
   214 
       
   215 
       
   216     public List<LocalVariable> variables() throws AbsentInformationException {
       
   217         return getVariables();
       
   218     }
       
   219 
       
   220     public List<LocalVariable> variablesByName(String name) throws AbsentInformationException {
       
   221         List<LocalVariable> variables = getVariables();
       
   222 
       
   223         List<LocalVariable> retList = new ArrayList<LocalVariable>(2);
       
   224         Iterator iter = variables.iterator();
       
   225         while(iter.hasNext()) {
       
   226             LocalVariable variable = (LocalVariable)iter.next();
       
   227             if (variable.name().equals(name)) {
       
   228                 retList.add(variable);
       
   229             }
       
   230         }
       
   231         return retList;
       
   232     }
       
   233 
       
   234     public List<LocalVariable> arguments() throws AbsentInformationException {
       
   235         List<LocalVariable> variables = getVariables();
       
   236 
       
   237         List<LocalVariable> retList = new ArrayList<LocalVariable>(variables.size());
       
   238         Iterator iter = variables.iterator();
       
   239         while(iter.hasNext()) {
       
   240             LocalVariable variable = (LocalVariable)iter.next();
       
   241             if (variable.isArgument()) {
       
   242                 retList.add(variable);
       
   243             }
       
   244         }
       
   245         return retList;
       
   246     }
       
   247 
       
   248     public byte[] bytecodes() {
       
   249         byte[] bytecodes = (bytecodesRef == null) ? null :
       
   250                                      (byte[])bytecodesRef.get();
       
   251         if (bytecodes == null) {
       
   252             try {
       
   253                 bytecodes = JDWP.Method.Bytecodes.
       
   254                                  process(vm, declaringType, ref).bytes;
       
   255             } catch (JDWPException exc) {
       
   256                 throw exc.toJDIException();
       
   257             }
       
   258             bytecodesRef = new SoftReference<byte[]>(bytecodes);
       
   259         }
       
   260         /*
       
   261          * Arrays are always modifiable, so it is a little unsafe
       
   262          * to return the cached bytecodes directly; instead, we
       
   263          * make a clone at the cost of using more memory.
       
   264          */
       
   265         return (byte[])bytecodes.clone();
       
   266     }
       
   267 
       
   268     int argSlotCount() throws AbsentInformationException {
       
   269         if (argSlotCount == -1) {
       
   270             getVariables();
       
   271         }
       
   272         return argSlotCount;
       
   273     }
       
   274 
       
   275     private SoftLocationXRefs getLocations(SDE.Stratum stratum) {
       
   276         if (stratum.isJava()) {
       
   277             return getBaseLocations();
       
   278         }
       
   279         String stratumID = stratum.id();
       
   280         SoftLocationXRefs info =
       
   281             (softOtherLocationXRefsRef == null) ? null :
       
   282                (SoftLocationXRefs)softOtherLocationXRefsRef.get();
       
   283         if (info != null && info.stratumID.equals(stratumID)) {
       
   284             return info;
       
   285         }
       
   286 
       
   287         List<Location> lineLocations = new ArrayList<Location>();
       
   288         Map<Integer, List<Location>> lineMapper = new HashMap<Integer, List<Location>>();
       
   289         int lowestLine = -1;
       
   290         int highestLine = -1;
       
   291         SDE.LineStratum lastLineStratum = null;
       
   292         SDE.Stratum baseStratum =
       
   293             declaringType.stratum(SDE.BASE_STRATUM_NAME);
       
   294         Iterator it = getBaseLocations().lineLocations.iterator();
       
   295         while(it.hasNext()) {
       
   296             LocationImpl loc = (LocationImpl)it.next();
       
   297             int baseLineNumber = loc.lineNumber(baseStratum);
       
   298             SDE.LineStratum lineStratum =
       
   299                   stratum.lineStratum(declaringType,
       
   300                                       baseLineNumber);
       
   301 
       
   302             if (lineStratum == null) {
       
   303                 // location not mapped in this stratum
       
   304                 continue;
       
   305             }
       
   306 
       
   307             int lineNumber = lineStratum.lineNumber();
       
   308 
       
   309             // remove unmapped and dup lines
       
   310             if ((lineNumber != -1) &&
       
   311                           (!lineStratum.equals(lastLineStratum))) {
       
   312                 lastLineStratum = lineStratum;
       
   313 
       
   314                 // Remember the largest/smallest line number
       
   315                 if (lineNumber > highestLine) {
       
   316                     highestLine = lineNumber;
       
   317                 }
       
   318                 if ((lineNumber < lowestLine) || (lowestLine == -1)) {
       
   319                     lowestLine = lineNumber;
       
   320                 }
       
   321 
       
   322                 loc.addStratumLineInfo(
       
   323                   new StratumLineInfo(stratumID,
       
   324                                       lineNumber,
       
   325                                       lineStratum.sourceName(),
       
   326                                       lineStratum.sourcePath()));
       
   327 
       
   328                 // Add to the location list
       
   329                 lineLocations.add(loc);
       
   330 
       
   331                 // Add to the line -> locations map
       
   332                 Integer key = new Integer(lineNumber);
       
   333                 List<Location> mappedLocs = lineMapper.get(key);
       
   334                 if (mappedLocs == null) {
       
   335                     mappedLocs = new ArrayList<Location>(1);
       
   336                     lineMapper.put(key, mappedLocs);
       
   337                 }
       
   338                 mappedLocs.add(loc);
       
   339             }
       
   340         }
       
   341 
       
   342         info = new SoftLocationXRefs(stratumID,
       
   343                                 lineMapper, lineLocations,
       
   344                                 lowestLine, highestLine);
       
   345         softOtherLocationXRefsRef = new SoftReference<SoftLocationXRefs>(info);
       
   346         return info;
       
   347     }
       
   348 
       
   349     private SoftLocationXRefs getBaseLocations() {
       
   350         SoftLocationXRefs info = (softBaseLocationXRefsRef == null) ? null :
       
   351                                      (SoftLocationXRefs)softBaseLocationXRefsRef.get();
       
   352         if (info != null) {
       
   353             return info;
       
   354         }
       
   355 
       
   356         JDWP.Method.LineTable lntab = null;
       
   357         try {
       
   358             lntab = JDWP.Method.LineTable.process(vm, declaringType, ref);
       
   359         } catch (JDWPException exc) {
       
   360             /*
       
   361              * Note: the absent info error shouldn't happen here
       
   362              * because the first and last index are always available.
       
   363              */
       
   364             throw exc.toJDIException();
       
   365         }
       
   366 
       
   367         int count  = lntab.lines.length;
       
   368 
       
   369         List<Location> lineLocations = new ArrayList<Location>(count);
       
   370         Map<Integer, List<Location>>lineMapper = new HashMap<Integer, List<Location>>();
       
   371         int lowestLine = -1;
       
   372         int highestLine = -1;
       
   373         for (int i = 0; i < count; i++) {
       
   374             long bci = lntab.lines[i].lineCodeIndex;
       
   375             int lineNumber = lntab.lines[i].lineNumber;
       
   376 
       
   377             /*
       
   378              * Some compilers will point multiple consecutive
       
   379              * lines at the same location. We need to choose
       
   380              * one of them so that we can consistently map back
       
   381              * and forth between line and location. So we choose
       
   382              * to record only the last line entry at a particular
       
   383              * location.
       
   384              */
       
   385             if ((i + 1 == count) || (bci != lntab.lines[i+1].lineCodeIndex)) {
       
   386                 // Remember the largest/smallest line number
       
   387                 if (lineNumber > highestLine) {
       
   388                     highestLine = lineNumber;
       
   389                 }
       
   390                 if ((lineNumber < lowestLine) || (lowestLine == -1)) {
       
   391                     lowestLine = lineNumber;
       
   392                 }
       
   393                 LocationImpl loc =
       
   394                     new LocationImpl(virtualMachine(), this, bci);
       
   395                 loc.addBaseLineInfo(
       
   396                     new BaseLineInfo(lineNumber, declaringType));
       
   397 
       
   398                 // Add to the location list
       
   399                 lineLocations.add(loc);
       
   400 
       
   401                 // Add to the line -> locations map
       
   402                 Integer key = new Integer(lineNumber);
       
   403                 List<Location> mappedLocs = lineMapper.get(key);
       
   404                 if (mappedLocs == null) {
       
   405                     mappedLocs = new ArrayList<Location>(1);
       
   406                     lineMapper.put(key, mappedLocs);
       
   407                 }
       
   408                 mappedLocs.add(loc);
       
   409             }
       
   410         }
       
   411 
       
   412         /*
       
   413          * firstIndex, lastIndex, and startLocation need to be
       
   414          * retrieved only once since they are strongly referenced.
       
   415          */
       
   416         if (location == null) {
       
   417             firstIndex = lntab.start;
       
   418             lastIndex = lntab.end;
       
   419             /*
       
   420              * The startLocation is the first one in the
       
   421              * location list if we have one;
       
   422              * otherwise, we construct a location for a
       
   423              * method start with no line info
       
   424              */
       
   425             if (count > 0) {
       
   426                 location = lineLocations.get(0);
       
   427             } else {
       
   428                 location = new LocationImpl(virtualMachine(), this,
       
   429                                             firstIndex);
       
   430             }
       
   431         }
       
   432 
       
   433         info = new SoftLocationXRefs(SDE.BASE_STRATUM_NAME,
       
   434                                 lineMapper, lineLocations,
       
   435                                 lowestLine, highestLine);
       
   436         softBaseLocationXRefsRef = new SoftReference<SoftLocationXRefs>(info);
       
   437         return info;
       
   438     }
       
   439 
       
   440     private List<LocalVariable> getVariables1_4() throws AbsentInformationException {
       
   441         JDWP.Method.VariableTable vartab = null;
       
   442         try {
       
   443             vartab = JDWP.Method.VariableTable.
       
   444                                      process(vm, declaringType, ref);
       
   445         } catch (JDWPException exc) {
       
   446             if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
       
   447                 absentVariableInformation = true;
       
   448                 throw new AbsentInformationException();
       
   449             } else {
       
   450                 throw exc.toJDIException();
       
   451             }
       
   452         }
       
   453 
       
   454         // Get the number of slots used by argument variables
       
   455         argSlotCount = vartab.argCnt;
       
   456         int count = vartab.slots.length;
       
   457         List<LocalVariable> variables = new ArrayList<LocalVariable>(count);
       
   458         for (int i=0; i<count; i++) {
       
   459             JDWP.Method.VariableTable.SlotInfo si = vartab.slots[i];
       
   460 
       
   461             /*
       
   462              * Skip "this*" entries because they are never real
       
   463              * variables from the JLS perspective.
       
   464              */
       
   465             if (!si.name.startsWith("this$") && !si.name.equals("this")) {
       
   466                 Location scopeStart = new LocationImpl(virtualMachine(),
       
   467                                                        this, si.codeIndex);
       
   468                 Location scopeEnd =
       
   469                     new LocationImpl(virtualMachine(), this,
       
   470                                      si.codeIndex + si.length - 1);
       
   471                 LocalVariable variable =
       
   472                     new LocalVariableImpl(virtualMachine(), this,
       
   473                                           si.slot, scopeStart, scopeEnd,
       
   474                                           si.name, si.signature, null);
       
   475                 // Add to the variable list
       
   476                 variables.add(variable);
       
   477             }
       
   478         }
       
   479         return variables;
       
   480     }
       
   481 
       
   482     private List<LocalVariable> getVariables1() throws AbsentInformationException {
       
   483 
       
   484         if (!vm.canGet1_5LanguageFeatures()) {
       
   485             return getVariables1_4();
       
   486         }
       
   487 
       
   488         JDWP.Method.VariableTableWithGeneric vartab = null;
       
   489         try {
       
   490             vartab = JDWP.Method.VariableTableWithGeneric.
       
   491                                      process(vm, declaringType, ref);
       
   492         } catch (JDWPException exc) {
       
   493             if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
       
   494                 absentVariableInformation = true;
       
   495                 throw new AbsentInformationException();
       
   496             } else {
       
   497                 throw exc.toJDIException();
       
   498             }
       
   499         }
       
   500 
       
   501         // Get the number of slots used by argument variables
       
   502         argSlotCount = vartab.argCnt;
       
   503         int count = vartab.slots.length;
       
   504         List<LocalVariable> variables = new ArrayList<LocalVariable>(count);
       
   505         for (int i=0; i<count; i++) {
       
   506             JDWP.Method.VariableTableWithGeneric.SlotInfo si = vartab.slots[i];
       
   507 
       
   508             /*
       
   509              * Skip "this*" entries because they are never real
       
   510              * variables from the JLS perspective.
       
   511              */
       
   512             if (!si.name.startsWith("this$") && !si.name.equals("this")) {
       
   513                 Location scopeStart = new LocationImpl(virtualMachine(),
       
   514                                                        this, si.codeIndex);
       
   515                 Location scopeEnd =
       
   516                     new LocationImpl(virtualMachine(), this,
       
   517                                      si.codeIndex + si.length - 1);
       
   518                 LocalVariable variable =
       
   519                     new LocalVariableImpl(virtualMachine(), this,
       
   520                                           si.slot, scopeStart, scopeEnd,
       
   521                                           si.name, si.signature,
       
   522                                           si.genericSignature);
       
   523                 // Add to the variable list
       
   524                 variables.add(variable);
       
   525             }
       
   526         }
       
   527         return variables;
       
   528     }
       
   529 
       
   530     private List<LocalVariable> getVariables() throws AbsentInformationException {
       
   531         if (absentVariableInformation) {
       
   532             throw new AbsentInformationException();
       
   533         }
       
   534 
       
   535         List<LocalVariable> variables = (variablesRef == null) ? null :
       
   536                                         variablesRef.get();
       
   537         if (variables != null) {
       
   538             return variables;
       
   539         }
       
   540         variables = getVariables1();
       
   541         variables = Collections.unmodifiableList(variables);
       
   542         variablesRef = new SoftReference<List<LocalVariable>>(variables);
       
   543         return variables;
       
   544     }
       
   545 }