Mercurial > hg > truffle
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
1 /* | |
2 * Copyright 2003-2004 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. | |
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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 package sun.jvm.hotspot.jdi; | |
26 | |
27 import com.sun.jdi.*; | |
28 import sun.jvm.hotspot.oops.Symbol; | |
29 import sun.jvm.hotspot.oops.LocalVariableTableElement; | |
30 import sun.jvm.hotspot.oops.LineNumberTableElement; | |
31 import java.util.List; | |
32 import java.util.Iterator; | |
33 import java.util.Map; | |
34 import java.util.HashMap; | |
35 import java.util.ArrayList; | |
36 import java.util.Comparator; | |
37 import java.lang.ref.SoftReference; | |
38 import java.util.Collections; | |
39 | |
40 public class ConcreteMethodImpl extends MethodImpl { | |
41 | |
42 /* | |
43 * A subset of the line number info that is softly cached | |
44 */ | |
45 static private class SoftLocationXRefs { | |
46 final String stratumID; // The stratum of this information | |
47 final Map lineMapper; // Maps line number to location(s) | |
48 final List lineLocations; // List of locations ordered by code index | |
49 | |
50 /* | |
51 * Note: these do not necessarily correspond to | |
52 * the line numbers of the first and last elements | |
53 * in the lineLocations list. Use these only for bounds | |
54 * checking and with lineMapper. | |
55 */ | |
56 final int lowestLine; | |
57 final int highestLine; | |
58 | |
59 SoftLocationXRefs(String stratumID, Map lineMapper, List lineLocations, | |
60 int lowestLine, int highestLine) { | |
61 this.stratumID = stratumID; | |
62 this.lineMapper = Collections.unmodifiableMap(lineMapper); | |
63 this.lineLocations = | |
64 Collections.unmodifiableList(lineLocations); | |
65 this.lowestLine = lowestLine; | |
66 this.highestLine = highestLine; | |
67 } | |
68 } | |
69 | |
70 private SoftReference softBaseLocationXRefsRef; | |
71 private SoftReference softOtherLocationXRefsRef; | |
72 private SoftReference variablesRef = null; | |
73 private int firstIndex = -1; | |
74 private int lastIndex = -1; | |
75 private Location location; | |
76 private SoftReference bytecodesRef = null; | |
77 | |
78 ConcreteMethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, | |
79 sun.jvm.hotspot.oops.Method saMethod ) { | |
80 super(vm, declaringType, saMethod); | |
81 } | |
82 | |
83 int argSlotCount() throws AbsentInformationException { | |
84 return (int) saMethod.getSizeOfParameters(); | |
85 } | |
86 | |
87 private SoftLocationXRefs getLocations(SDE.Stratum stratum) { | |
88 if (stratum.isJava()) { | |
89 return getBaseLocations(); | |
90 } | |
91 String stratumID = stratum.id(); | |
92 SoftLocationXRefs info = | |
93 (softOtherLocationXRefsRef == null) ? null : | |
94 (SoftLocationXRefs)softOtherLocationXRefsRef.get(); | |
95 if (info != null && info.stratumID.equals(stratumID)) { | |
96 return info; | |
97 } | |
98 | |
99 List lineLocations = new ArrayList(); | |
100 Map lineMapper = new HashMap(); | |
101 int lowestLine = -1; | |
102 int highestLine = -1; | |
103 SDE.LineStratum lastLineStratum = null; | |
104 SDE.Stratum baseStratum = | |
105 declaringType.stratum(SDE.BASE_STRATUM_NAME); | |
106 Iterator it = getBaseLocations().lineLocations.iterator(); | |
107 while(it.hasNext()) { | |
108 LocationImpl loc = (LocationImpl)it.next(); | |
109 int baseLineNumber = loc.lineNumber(baseStratum); | |
110 SDE.LineStratum lineStratum = | |
111 stratum.lineStratum(declaringType, | |
112 baseLineNumber); | |
113 | |
114 if (lineStratum == null) { | |
115 // location not mapped in this stratum | |
116 continue; | |
117 } | |
118 | |
119 int lineNumber = lineStratum.lineNumber(); | |
120 | |
121 // remove unmapped and dup lines | |
122 if ((lineNumber != -1) && | |
123 (!lineStratum.equals(lastLineStratum))) { | |
124 lastLineStratum = lineStratum; | |
125 // Remember the largest/smallest line number | |
126 if (lineNumber > highestLine) { | |
127 highestLine = lineNumber; | |
128 } | |
129 if ((lineNumber < lowestLine) || (lowestLine == -1)) { | |
130 lowestLine = lineNumber; | |
131 } | |
132 | |
133 loc.addStratumLineInfo( | |
134 new StratumLineInfo(stratumID, | |
135 lineNumber, | |
136 lineStratum.sourceName(), | |
137 lineStratum.sourcePath())); | |
138 | |
139 // Add to the location list | |
140 lineLocations.add(loc); | |
141 | |
142 // Add to the line -> locations map | |
143 Integer key = new Integer(lineNumber); | |
144 List mappedLocs = (List)lineMapper.get(key); | |
145 if (mappedLocs == null) { | |
146 mappedLocs = new ArrayList(1); | |
147 lineMapper.put(key, mappedLocs); | |
148 } | |
149 mappedLocs.add(loc); | |
150 } | |
151 } | |
152 | |
153 info = new SoftLocationXRefs(stratumID, | |
154 lineMapper, lineLocations, | |
155 lowestLine, highestLine); | |
156 softOtherLocationXRefsRef = new SoftReference(info); | |
157 return info; | |
158 } | |
159 | |
160 private SoftLocationXRefs getBaseLocations() { | |
161 SoftLocationXRefs info = (softBaseLocationXRefsRef == null) ? null : | |
162 (SoftLocationXRefs)softBaseLocationXRefsRef.get(); | |
163 if (info != null) { | |
164 return info; | |
165 } | |
166 | |
167 byte[] codeBuf = bytecodes(); | |
168 firstIndex = 0; | |
169 lastIndex = codeBuf.length - 1; | |
170 // This is odd; what is the Location of a Method? | |
171 // A StackFrame can have a location, but a Method? | |
172 // I guess it must be the Location for bci 0. | |
173 location = new LocationImpl(virtualMachine(), this, 0); | |
174 | |
175 boolean hasLineInfo = saMethod.hasLineNumberTable(); | |
176 LineNumberTableElement[] lntab = null; | |
177 int count; | |
178 | |
179 if (hasLineInfo) { | |
180 lntab = saMethod.getLineNumberTable(); | |
181 count = lntab.length; | |
182 } else { | |
183 count = 0; | |
184 } | |
185 | |
186 List lineLocations = new ArrayList(count); | |
187 Map lineMapper = new HashMap(); | |
188 int lowestLine = -1; | |
189 int highestLine = -1; | |
190 for (int i = 0; i < count; i++) { | |
191 long bci = lntab[i].getStartBCI(); | |
192 int lineNumber = lntab[i].getLineNumber(); | |
193 | |
194 /* | |
195 * Some compilers will point multiple consecutive | |
196 * lines at the same location. We need to choose | |
197 * one of them so that we can consistently map back | |
198 * and forth between line and location. So we choose | |
199 * to record only the last line entry at a particular | |
200 * location. | |
201 */ | |
202 if ((i + 1 == count) || (bci != lntab[i+1].getStartBCI())) { | |
203 // Remember the largest/smallest line number | |
204 if (lineNumber > highestLine) { | |
205 highestLine = lineNumber; | |
206 } | |
207 if ((lineNumber < lowestLine) || (lowestLine == -1)) { | |
208 lowestLine = lineNumber; | |
209 } | |
210 LocationImpl loc = | |
211 new LocationImpl(virtualMachine(), this, bci); | |
212 loc.addBaseLineInfo( | |
213 new BaseLineInfo(lineNumber, declaringType)); | |
214 | |
215 // Add to the location list | |
216 lineLocations.add(loc); | |
217 | |
218 // Add to the line -> locations map | |
219 Integer key = new Integer(lineNumber); | |
220 List mappedLocs = (List)lineMapper.get(key); | |
221 if (mappedLocs == null) { | |
222 mappedLocs = new ArrayList(1); | |
223 lineMapper.put(key, mappedLocs); | |
224 } | |
225 mappedLocs.add(loc); | |
226 } | |
227 } | |
228 | |
229 info = new SoftLocationXRefs(SDE.BASE_STRATUM_NAME, | |
230 lineMapper, lineLocations, | |
231 lowestLine, highestLine); | |
232 softBaseLocationXRefsRef = new SoftReference(info); | |
233 return info; | |
234 } | |
235 | |
236 List sourceNameFilter(List list, | |
237 SDE.Stratum stratum, | |
238 String sourceName) | |
239 throws AbsentInformationException { | |
240 if (sourceName == null) { | |
241 return list; | |
242 } else { | |
243 /* needs sourceName filteration */ | |
244 List locs = new ArrayList(); | |
245 Iterator it = list.iterator(); | |
246 while (it.hasNext()) { | |
247 LocationImpl loc = (LocationImpl)it.next(); | |
248 if (loc.sourceName(stratum).equals(sourceName)) { | |
249 locs.add(loc); | |
250 } | |
251 } | |
252 return locs; | |
253 } | |
254 } | |
255 | |
256 public List allLineLocations(SDE.Stratum stratum, String sourceName) | |
257 throws AbsentInformationException { | |
258 List lineLocations = getLocations(stratum).lineLocations; | |
259 | |
260 if (lineLocations.size() == 0) { | |
261 throw new AbsentInformationException(); | |
262 } | |
263 | |
264 return Collections.unmodifiableList( | |
265 sourceNameFilter(lineLocations, stratum, sourceName)); | |
266 } | |
267 | |
268 public List locationsOfLine(SDE.Stratum stratum, String sourceName, | |
269 int lineNumber) throws AbsentInformationException { | |
270 SoftLocationXRefs info = getLocations(stratum); | |
271 | |
272 if (info.lineLocations.size() == 0) { | |
273 throw new AbsentInformationException(); | |
274 } | |
275 | |
276 /* | |
277 * Find the locations which match the line number | |
278 * passed in. | |
279 */ | |
280 List list = (List)info.lineMapper.get( | |
281 new Integer(lineNumber)); | |
282 | |
283 if (list == null) { | |
284 list = new ArrayList(0); | |
285 } | |
286 return Collections.unmodifiableList( | |
287 sourceNameFilter(list, stratum, sourceName)); | |
288 } | |
289 | |
290 LineInfo codeIndexToLineInfo(SDE.Stratum stratum, | |
291 long codeIndex) { | |
292 if (firstIndex == -1) { | |
293 getBaseLocations(); | |
294 } | |
295 | |
296 /* | |
297 * Check for invalid code index. | |
298 */ | |
299 if (codeIndex < firstIndex || codeIndex > lastIndex) { | |
300 throw new InternalError( | |
301 "Location with invalid code index"); | |
302 } | |
303 | |
304 List lineLocations = getLocations(stratum).lineLocations; | |
305 | |
306 /* | |
307 * Check for absent line numbers. | |
308 */ | |
309 if (lineLocations.size() == 0) { | |
310 return super.codeIndexToLineInfo(stratum, codeIndex); | |
311 } | |
312 | |
313 Iterator iter = lineLocations.iterator(); | |
314 /* | |
315 * Treat code before the beginning of the first line table | |
316 * entry as part of the first line. javac will generate | |
317 * code like this for some local classes. This "prolog" | |
318 * code contains assignments from locals in the enclosing | |
319 * scope to synthetic fields in the local class. Same for | |
320 * other language prolog code. | |
321 */ | |
322 LocationImpl bestMatch = (LocationImpl)iter.next(); | |
323 while (iter.hasNext()) { | |
324 LocationImpl current = (LocationImpl)iter.next(); | |
325 if (current.codeIndex() > codeIndex) { | |
326 break; | |
327 } | |
328 bestMatch = current; | |
329 } | |
330 return bestMatch.getLineInfo(stratum); | |
331 } | |
332 | |
333 public Location locationOfCodeIndex(long codeIndex) { | |
334 if (firstIndex == -1) { | |
335 getBaseLocations(); | |
336 } | |
337 | |
338 /* | |
339 * Check for invalid code index. | |
340 */ | |
341 if (codeIndex < firstIndex || codeIndex > lastIndex) { | |
342 return null; | |
343 } | |
344 | |
345 return new LocationImpl(virtualMachine(), this, codeIndex); | |
346 } | |
347 | |
348 public List variables() throws AbsentInformationException { | |
349 return getVariables(); | |
350 } | |
351 | |
352 public List variablesByName(String name) throws AbsentInformationException { | |
353 List variables = getVariables(); | |
354 | |
355 List retList = new ArrayList(2); | |
356 Iterator iter = variables.iterator(); | |
357 while(iter.hasNext()) { | |
358 LocalVariable variable = (LocalVariable)iter.next(); | |
359 if (variable.name().equals(name)) { | |
360 retList.add(variable); | |
361 } | |
362 } | |
363 return retList; | |
364 } | |
365 | |
366 public List arguments() throws AbsentInformationException { | |
367 if (argumentTypeNames().size() == 0) { | |
368 return new ArrayList(0); | |
369 } | |
370 List variables = getVariables(); | |
371 List retList = new ArrayList(variables.size()); | |
372 Iterator iter = variables.iterator(); | |
373 while(iter.hasNext()) { | |
374 LocalVariable variable = (LocalVariable)iter.next(); | |
375 if (variable.isArgument()) { | |
376 retList.add(variable); | |
377 } | |
378 } | |
379 return retList; | |
380 } | |
381 | |
382 public byte[] bytecodes() { | |
383 byte[] bytecodes = (bytecodesRef == null) ? null : | |
384 (byte[])bytecodesRef.get(); | |
385 if (bytecodes == null) { | |
386 bytecodes = saMethod.getByteCode(); | |
387 bytecodesRef = new SoftReference(bytecodes); | |
388 } | |
389 /* | |
390 * Arrays are always modifiable, so it is a little unsafe | |
391 * to return the cached bytecodes directly; instead, we | |
392 * make a clone at the cost of using more memory. | |
393 */ | |
394 return (byte[])bytecodes.clone(); | |
395 } | |
396 | |
397 public Location location() { | |
398 if (location == null) { | |
399 getBaseLocations(); | |
400 } | |
401 return location; | |
402 } | |
403 | |
404 private List getVariables() throws AbsentInformationException { | |
405 List variables = (variablesRef == null) ? null : | |
406 (List)variablesRef.get(); | |
407 if (variables != null) { | |
408 return variables; | |
409 } | |
410 | |
411 // if there are no locals, there won't be a LVT | |
412 if (saMethod.getMaxLocals() == 0) { | |
413 variables = Collections.unmodifiableList(new ArrayList(0)); | |
414 variablesRef = new SoftReference(variables); | |
415 return variables; | |
416 } | |
417 | |
418 if (! saMethod.hasLocalVariableTable()) { | |
419 throw new AbsentInformationException(); | |
420 } | |
421 //Build up the JDI view of local variable table. | |
422 LocalVariableTableElement[] locals = saMethod.getLocalVariableTable(); | |
423 int localCount = locals.length; | |
424 variables = new ArrayList(localCount); | |
425 for (int ii = 0; ii < localCount; ii++) { | |
426 String name = | |
427 saMethod.getConstants().getSymbolAt(locals[ii].getNameCPIndex()).asString(); | |
428 /* | |
429 * Skip "this$*", "this+*", "this" entries because they are never real | |
430 * variables from the JLS perspective. "this+*" is new with 1.5. | |
431 * Instead of using '+', we check for java letter or digit to avoid | |
432 * depending on javac's current choice of '+'. | |
433 */ | |
434 boolean isInternalName = name.startsWith("this") && | |
435 (name.length() == 4 || name.charAt(4)=='$' || !Character.isJavaIdentifierPart(name.charAt(4))); | |
436 if (! isInternalName) { | |
437 int slot = locals[ii].getSlot(); | |
438 long codeIndex = locals[ii].getStartBCI(); | |
439 int length = locals[ii].getLength(); | |
440 Location scopeStart = new LocationImpl(virtualMachine(), | |
441 this, codeIndex); | |
442 Location scopeEnd = | |
443 new LocationImpl(virtualMachine(), this, | |
444 codeIndex + length - 1); | |
445 String signature = | |
446 saMethod.getConstants().getSymbolAt(locals[ii].getDescriptorCPIndex()).asString(); | |
447 | |
448 int genericSigIndex = locals[ii].getSignatureCPIndex(); | |
449 String genericSignature = null; | |
450 if (genericSigIndex != 0) { | |
451 genericSignature = saMethod.getConstants().getSymbolAt(genericSigIndex).asString(); | |
452 } | |
453 | |
454 LocalVariable variable = | |
455 new LocalVariableImpl(virtualMachine(), this, | |
456 slot, scopeStart, scopeEnd, | |
457 name, signature, genericSignature); | |
458 // Add to the variable list | |
459 variables.add(variable); | |
460 } | |
461 } | |
462 | |
463 variables = Collections.unmodifiableList(variables); | |
464 variablesRef = new SoftReference(variables); | |
465 return variables; | |
466 } | |
467 } |