001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Tim Tromey - update method signature syntax (bug 31507)
011: *******************************************************************************/package org.eclipse.jdi.internal;
012:
013: import java.io.ByteArrayOutputStream;
014: import java.io.DataInputStream;
015: import java.io.DataOutputStream;
016: import java.io.IOException;
017: import java.lang.reflect.Field;
018: import java.lang.reflect.Modifier;
019: import java.util.ArrayList;
020: import java.util.Arrays;
021: import java.util.Collections;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.TreeSet;
028:
029: import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket;
030: import org.eclipse.jdi.internal.jdwp.JdwpMethodID;
031: import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
032:
033: import com.ibm.icu.text.MessageFormat;
034: import com.sun.jdi.AbsentInformationException;
035: import com.sun.jdi.ClassLoaderReference;
036: import com.sun.jdi.ClassNotLoadedException;
037: import com.sun.jdi.Locatable;
038: import com.sun.jdi.Location;
039: import com.sun.jdi.Method;
040: import com.sun.jdi.Type;
041:
042: /**
043: * Implementation of com.sun.jdi.Method.
044: */
045: public class MethodImpl extends TypeComponentImpl implements Method,
046: Locatable {
047: /** InvokeOptions Constants. */
048: public static final int INVOKE_SINGLE_THREADED_JDWP = 0x01;
049: public static final int INVOKE_NONVIRTUAL_JDWP = 0x02;
050:
051: /** Map with Strings for flag bits. */
052: private static String[] fgInvokeOptions = null;
053:
054: /** MethodTypeID that corresponds to this reference. */
055: private JdwpMethodID fMethodID;
056:
057: /** The following are the stored results of JDWP calls. */
058: private List fVariables = null;
059: private long fLowestValidCodeIndex = -1;
060: private long fHighestValidCodeIndex = -1;
061: private Map fCodeIndexToLine = null;
062: private Map fLineToCodeIndexes = null;
063: private Map fStratumAllLineLocations = null;
064: private int fArgumentSlotsCount = -1;
065: private List fArguments = null;
066: private List fArgumentTypes = null;
067: private List fArgumentTypeNames = null;
068: private List fArgumentTypeSignatures = null;
069: private byte[] fByteCodes = null;
070: private long[] fCodeIndexTable;
071: private int[] fJavaStratumLineNumberTable;
072:
073: private String fReturnTypeName = null;
074:
075: /**
076: * Creates new MethodImpl.
077: */
078: public MethodImpl(VirtualMachineImpl vmImpl,
079: ReferenceTypeImpl declaringType, JdwpMethodID methodID,
080: String name, String signature, String genericSignature,
081: int modifierBits) {
082: super (
083: "Method", vmImpl, declaringType, name, signature, genericSignature, modifierBits); //$NON-NLS-1$
084: fMethodID = methodID;
085: }
086:
087: /**
088: * Flushes all stored Jdwp results.
089: */
090: protected void flushStoredJdwpResults() {
091: fVariables = null;
092: fLowestValidCodeIndex = -1;
093: fHighestValidCodeIndex = -1;
094: fCodeIndexToLine = null;
095: fLineToCodeIndexes = null;
096: fStratumAllLineLocations = null;
097: fCodeIndexTable = null;
098: fJavaStratumLineNumberTable = null;
099: fArgumentSlotsCount = -1;
100: fArguments = null;
101: fArgumentTypes = null;
102: fArgumentTypeNames = null;
103: fArgumentTypeSignatures = null;
104: fByteCodes = null;
105: }
106:
107: /**
108: * @return Returns methodID of method.
109: */
110: protected JdwpMethodID getMethodID() {
111: return fMethodID;
112: }
113:
114: /**
115: * @return Returns map of location to line number.
116: */
117: protected Map javaStratumCodeIndexToLine()
118: throws AbsentInformationException {
119: if (isAbstract()) {
120: return Collections.EMPTY_MAP;
121: }
122: getLineTable();
123: return fCodeIndexToLine;
124: }
125:
126: /**
127: * @return Returns map of line number to locations.
128: */
129: protected List javaStratumLineToCodeIndexes(int line)
130: throws AbsentInformationException {
131: if (isAbstract() || isNative()) {
132: return null;
133: }
134: getLineTable();
135:
136: return (List) fLineToCodeIndexes.get(new Integer(line));
137: }
138:
139: /**
140: * Gets line table from VM.
141: */
142: private void getLineTable() throws AbsentInformationException {
143: if (isObsolete()) {
144: return;
145: }
146: if (fCodeIndexToLine != null) {
147: if (fCodeIndexToLine.isEmpty()) {
148: throw new AbsentInformationException(
149: JDIMessages.MethodImpl_Got_empty_line_number_table_for_this _method_1);
150: }
151: return;
152: }
153:
154: initJdwpRequest();
155: try {
156: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
157: DataOutputStream outData = new DataOutputStream(outBytes);
158: writeWithReferenceType(this , outData);
159:
160: JdwpReplyPacket replyPacket = requestVM(
161: JdwpCommandPacket.M_LINE_TABLE, outBytes);
162: switch (replyPacket.errorCode()) {
163: case JdwpReplyPacket.ABSENT_INFORMATION:
164: throw new AbsentInformationException(
165: JDIMessages.MethodImpl_No_line_number_information_available_2);
166: case JdwpReplyPacket.NATIVE_METHOD:
167: throw new AbsentInformationException(
168: JDIMessages.MethodImpl_No_line_number_information_available_2);
169: }
170: defaultReplyErrorHandler(replyPacket.errorCode());
171:
172: DataInputStream replyData = replyPacket.dataInStream();
173: fLowestValidCodeIndex = readLong("lowest index", replyData); //$NON-NLS-1$
174: fHighestValidCodeIndex = readLong(
175: "highest index", replyData); //$NON-NLS-1$
176: int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$
177: fCodeIndexToLine = new HashMap();
178: fLineToCodeIndexes = new HashMap();
179: if (nrOfElements == 0) {
180: throw new AbsentInformationException(
181: JDIMessages.MethodImpl_Got_empty_line_number_table_for_this _method_3);
182: }
183: fCodeIndexTable = new long[nrOfElements];
184: fJavaStratumLineNumberTable = new int[nrOfElements];
185: for (int i = 0; i < nrOfElements; i++) {
186: long lineCodeIndex = readLong("code index", replyData); //$NON-NLS-1$
187: Long lineCodeIndexLong = new Long(lineCodeIndex);
188: int lineNr = readInt("line nr", replyData); //$NON-NLS-1$
189: Integer lineNrInt = new Integer(lineNr);
190:
191: // Add entry to code-index to line mapping.
192: fCodeIndexToLine.put(lineCodeIndexLong, lineNrInt);
193:
194: fCodeIndexTable[i] = lineCodeIndex;
195: fJavaStratumLineNumberTable[i] = lineNr;
196:
197: List lineNrEntry = (List) fLineToCodeIndexes
198: .get(lineNrInt);
199: if (lineNrEntry == null) {
200: lineNrEntry = new ArrayList();
201: fLineToCodeIndexes.put(lineNrInt, lineNrEntry);
202: }
203: lineNrEntry.add(lineCodeIndexLong);
204: }
205: } catch (IOException e) {
206: fCodeIndexToLine = null;
207: fLineToCodeIndexes = null;
208: defaultIOExceptionHandler(e);
209: } finally {
210: handledJdwpRequest();
211: }
212: }
213:
214: /**
215: * @return Returns the line number that corresponds to the given lineCodeIndex.
216: */
217: protected int javaStratumLineNumber(long lineCodeIndex)
218: throws AbsentInformationException {
219: if (isAbstract() || isNative() || isObsolete()) {
220: return -1;
221: }
222: getLineTable();
223: if (lineCodeIndex > fHighestValidCodeIndex) {
224: throw new AbsentInformationException(
225: JDIMessages.MethodImpl_Invalid_code_index_of_a_location_given_4);
226: }
227:
228: Long lineCodeIndexObj;
229: Integer lineNrObj;
230: long index = lineCodeIndex;
231: // Search for the line where this code index is located.
232: do {
233: lineCodeIndexObj = new Long(index);
234: lineNrObj = (Integer) javaStratumCodeIndexToLine().get(
235: lineCodeIndexObj);
236: } while (lineNrObj == null && --index >= fLowestValidCodeIndex);
237: if (lineNrObj == null) {
238: if (lineCodeIndex >= fLowestValidCodeIndex) {
239: index = lineCodeIndex;
240: do {
241: lineCodeIndexObj = new Long(index);
242: lineNrObj = (Integer) javaStratumCodeIndexToLine()
243: .get(lineCodeIndexObj);
244: } while (lineNrObj == null
245: && ++index <= fHighestValidCodeIndex);
246: if (lineNrObj != null) {
247: return lineNrObj.intValue();
248: }
249: }
250: throw new AbsentInformationException(
251: JDIMessages.MethodImpl_Invalid_code_index_of_a_location_given_4);
252: }
253: return lineNrObj.intValue();
254: }
255:
256: /**
257: * @see com.sun.jdi.Method#allLineLocations()
258: */
259: public List allLineLocations() throws AbsentInformationException {
260: return allLineLocations(virtualMachine().getDefaultStratum(),
261: null);
262: }
263:
264: /**
265: * @see com.sun.jdi.Method#arguments()
266: */
267: public List arguments() throws AbsentInformationException {
268: if (isNative() || isAbstract()) {
269: throw new AbsentInformationException(
270: JDIMessages.MethodImpl_No_local_variable_information_available_9);
271: }
272: if (fArguments != null) {
273: return fArguments;
274: }
275:
276: List result = new ArrayList();
277: Iterator iter = variables().iterator();
278: while (iter.hasNext()) {
279: LocalVariableImpl var = (LocalVariableImpl) iter.next();
280: if (var.isArgument())
281: result.add(var);
282: }
283: fArguments = result;
284: return fArguments;
285: }
286:
287: /**
288: * @return Returns a text representation of all declared argument types of this method.
289: */
290: public List argumentTypeNames() {
291: if (fArgumentTypeNames != null) {
292: return fArgumentTypeNames;
293: }
294: List argumentTypeSignatures = argumentTypeSignatures();
295: List result = new ArrayList();
296: for (Iterator iter = argumentTypeSignatures.iterator(); iter
297: .hasNext();) {
298: result.add(TypeImpl.signatureToName((String) iter.next()));
299: }
300:
301: fArgumentTypeNames = result;
302: return fArgumentTypeNames;
303: }
304:
305: /**
306: * @return Returns a signatures of all declared argument types of this method.
307: */
308: private List argumentTypeSignatures() {
309: if (fArgumentTypeSignatures != null) {
310: return fArgumentTypeSignatures;
311: }
312:
313: fArgumentTypeSignatures = GenericSignature
314: .getParameterTypes(signature());
315: return fArgumentTypeSignatures;
316: }
317:
318: /**
319: * @return Returns the list containing the type of each argument.
320: */
321: public List argumentTypes() throws ClassNotLoadedException {
322: if (fArgumentTypes != null) {
323: return fArgumentTypes;
324: }
325:
326: List result = new ArrayList();
327: Iterator iter = argumentTypeSignatures().iterator();
328: ClassLoaderReference classLoaderRef = declaringType()
329: .classLoader();
330: VirtualMachineImpl vm = virtualMachineImpl();
331: while (iter.hasNext()) {
332: String argumentTypeSignature = (String) iter.next();
333: result.add(TypeImpl.create(vm, argumentTypeSignature,
334: classLoaderRef));
335: }
336: fArgumentTypes = result;
337: return fArgumentTypes;
338: }
339:
340: /**
341: * @return Returns an array containing the bytecodes for this method.
342: */
343: public byte[] bytecodes() {
344: if (fByteCodes != null) {
345: return fByteCodes;
346: }
347:
348: initJdwpRequest();
349: try {
350: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
351: DataOutputStream outData = new DataOutputStream(outBytes);
352: writeWithReferenceType(this , outData);
353:
354: JdwpReplyPacket replyPacket = requestVM(
355: JdwpCommandPacket.M_BYTECODES, outBytes);
356: defaultReplyErrorHandler(replyPacket.errorCode());
357:
358: DataInputStream replyData = replyPacket.dataInStream();
359: int length = readInt("length", replyData); //$NON-NLS-1$
360: fByteCodes = readByteArray(length, "bytecodes", replyData); //$NON-NLS-1$
361: return fByteCodes;
362: } catch (IOException e) {
363: fByteCodes = null;
364: defaultIOExceptionHandler(e);
365: return null;
366: } finally {
367: handledJdwpRequest();
368: }
369: }
370:
371: /**
372: * @return Returns the hash code value.
373: */
374: public int hashCode() {
375: return fMethodID.hashCode();
376: }
377:
378: /**
379: * @return Returns true if two mirrors refer to the same entity in the target VM.
380: * @see java.lang.Object#equals(Object)
381: */
382: public boolean equals(Object object) {
383: return object != null
384: && object.getClass().equals(this .getClass())
385: && fMethodID.equals(((MethodImpl) object).fMethodID)
386: && referenceTypeImpl().equals(
387: ((MethodImpl) object).referenceTypeImpl());
388: }
389:
390: /**
391: * @return Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
392: */
393: public int compareTo(Object object) {
394: if (object == null
395: || !object.getClass().equals(this .getClass()))
396: throw new ClassCastException(
397: JDIMessages.MethodImpl_Can__t_compare_method_to_given_object_6);
398:
399: // See if declaring types are the same, if not return comparison between declaring types.
400: Method type2 = (Method) object;
401: if (!declaringType().equals(type2.declaringType()))
402: return declaringType().compareTo(type2.declaringType());
403:
404: // Return comparison of position within declaring type.
405: int index1 = declaringType().methods().indexOf(this );
406: int index2 = type2.declaringType().methods().indexOf(type2);
407: if (index1 < index2) {
408: return -1;
409: } else if (index1 > index2) {
410: return 1;
411: } else {
412: return 0;
413: }
414: }
415:
416: /**
417: * @see com.sun.jdi.Method#isAbstract()
418: */
419: public boolean isAbstract() {
420: return (fModifierBits & MODIFIER_ACC_ABSTRACT) != 0;
421: }
422:
423: /**
424: * @see com.sun.jdi.Method#isConstructor()
425: */
426: public boolean isConstructor() {
427: return name().equals("<init>"); //$NON-NLS-1$
428: }
429:
430: /**
431: * @see com.sun.jdi.Method#isNative()
432: */
433: public boolean isNative() {
434: return (fModifierBits & MODIFIER_ACC_NATIVE) != 0;
435: }
436:
437: /**
438: * @see com.sun.jdi.Method#isStaticInitializer()
439: */
440: public boolean isStaticInitializer() {
441: return name().equals("<clinit>"); //$NON-NLS-1$
442: }
443:
444: /**
445: * @see com.sun.jdi.Method#isSynchronized()
446: */
447: public boolean isSynchronized() {
448: return (fModifierBits & MODIFIER_ACC_SYNCHRONIZED) != 0;
449: }
450:
451: /**
452: * @see com.sun.jdi.Method#locationOfCodeIndex(long)
453: */
454: public Location locationOfCodeIndex(long index) {
455: if (isAbstract() || isNative()) {
456: return null;
457: }
458: try {
459: Integer lineNrInt = (Integer) javaStratumCodeIndexToLine()
460: .get(new Long(index));
461: if (lineNrInt == null) {
462: throw new AbsentInformationException(
463: MessageFormat
464: .format(
465: JDIMessages.MethodImpl_No_valid_location_at_the_specified_code_index__0__2,
466: new Object[] { Long
467: .toString(index) }));
468: }
469: } catch (AbsentInformationException e) {
470: }
471: return new LocationImpl(virtualMachineImpl(), this , index);
472: }
473:
474: /**
475: * @see com.sun.jdi.Method#locationsOfLine(int)
476: */
477: public List locationsOfLine(int line)
478: throws AbsentInformationException {
479: return locationsOfLine(virtualMachine().getDefaultStratum(),
480: null, line);
481: }
482:
483: /**
484: * @see com.sun.jdi.Method#returnType()
485: */
486: public Type returnType() throws ClassNotLoadedException {
487: int startIndex = signature().lastIndexOf(')') + 1; // Signature position is just after ending brace.
488: return TypeImpl.create(virtualMachineImpl(), signature()
489: .substring(startIndex), declaringType().classLoader());
490: }
491:
492: /**
493: * @see com.sun.jdi.Method#returnTypeName()
494: */
495: public String returnTypeName() {
496: if (fReturnTypeName != null) {
497: return fReturnTypeName;
498: }
499: int startIndex = signature().lastIndexOf(')') + 1; // Signature position is just after ending brace.
500: fReturnTypeName = TypeImpl.signatureToName(signature()
501: .substring(startIndex));
502: return fReturnTypeName;
503: }
504:
505: /**
506: * @see com.sun.jdi.Method#variables()
507: */
508: public List variables() throws AbsentInformationException {
509: if (isNative() || isAbstract()) {
510: throw new AbsentInformationException(
511: JDIMessages.MethodImpl_No_local_variable_information_available_9);
512: }
513:
514: if (fVariables != null) {
515: return fVariables;
516: }
517:
518: initJdwpRequest();
519: try {
520: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
521: DataOutputStream outData = new DataOutputStream(outBytes);
522: writeWithReferenceType(this , outData);
523:
524: boolean withGenericSignature = virtualMachineImpl()
525: .isJdwpVersionGreaterOrEqual(1, 5);
526: int jdwpCommand = withGenericSignature ? JdwpCommandPacket.M_VARIABLE_TABLE_WITH_GENERIC
527: : JdwpCommandPacket.M_VARIABLE_TABLE;
528: JdwpReplyPacket replyPacket = requestVM(jdwpCommand,
529: outBytes);
530: switch (replyPacket.errorCode()) {
531: case JdwpReplyPacket.ABSENT_INFORMATION:
532: return inferArguments();
533: }
534:
535: defaultReplyErrorHandler(replyPacket.errorCode());
536:
537: DataInputStream replyData = replyPacket.dataInStream();
538: fArgumentSlotsCount = readInt("arg count", replyData); //$NON-NLS-1$
539: int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$
540: List variables = new ArrayList(nrOfElements);
541: for (int i = 0; i < nrOfElements; i++) {
542: long codeIndex = readLong("code index", replyData); //$NON-NLS-1$
543: String name = readString("name", replyData); //$NON-NLS-1$
544: String signature = readString("signature", replyData); //$NON-NLS-1$
545: String genericSignature = null;
546: if (withGenericSignature) {
547: genericSignature = readString(
548: "generic signature", replyData); //$NON-NLS-1$
549: if ("".equals(genericSignature)) { //$NON-NLS-1$
550: genericSignature = null;
551: }
552: }
553: int length = readInt("length", replyData); //$NON-NLS-1$
554: int slot = readInt("slot", replyData); //$NON-NLS-1$
555: boolean isArgument = slot < fArgumentSlotsCount;
556:
557: // Note that for instance methods, the first slot contains the this reference.
558: if (isStatic() || slot > 0) {
559: LocalVariableImpl localVar = new LocalVariableImpl(
560: virtualMachineImpl(), this , codeIndex,
561: name, signature, genericSignature, length,
562: slot, isArgument);
563: variables.add(localVar);
564: }
565: }
566: fVariables = variables;
567: return fVariables;
568: } catch (IOException e) {
569: fArgumentSlotsCount = -1;
570: fVariables = null;
571: defaultIOExceptionHandler(e);
572: return null;
573: } finally {
574: handledJdwpRequest();
575: }
576: }
577:
578: /**
579: * @throws AbsentInformationException
580: */
581: private List inferArguments() throws AbsentInformationException {
582: // infer arguments, if possible
583:
584: // try to generate the right generic signature for each argument
585: String genericSignature = genericSignature();
586: String[] signatures = (String[]) argumentTypeSignatures()
587: .toArray(new String[0]);
588: String[] genericSignatures;
589: if (genericSignature == null) {
590: genericSignatures = new String[signatures.length];
591: } else {
592: genericSignatures = (String[]) GenericSignature
593: .getParameterTypes(genericSignature).toArray(
594: new String[0]);
595: for (int i = 0; i < genericSignatures.length; i++) {
596: if (genericSignatures[i].equals(signatures[i])) {
597: genericSignatures[i] = null;
598: }
599: }
600: }
601:
602: int slot = 0;
603: if (!isStatic()) {
604: slot++;
605: }
606: if (signatures.length > 0) {
607: fArgumentSlotsCount = signatures.length;
608: fVariables = new ArrayList(fArgumentSlotsCount);
609: for (int i = 0; i < signatures.length; i++) {
610: String name = "arg" + i; //$NON-NLS-1$
611: LocalVariableImpl localVar = new LocalVariableImpl(
612: virtualMachineImpl(), this , 0, name,
613: signatures[i], genericSignatures[i], -1, slot,
614: true);
615: fVariables.add(localVar);
616: slot++;
617: }
618: return fVariables;
619: }
620: throw new AbsentInformationException(
621: JDIMessages.MethodImpl_No_local_variable_information_available_9);
622:
623: }
624:
625: /**
626: * @see com.sun.jdi.Method#variablesByName(String)
627: */
628: public List variablesByName(String name)
629: throws AbsentInformationException {
630: Iterator iter = variables().iterator();
631: List result = new ArrayList();
632: while (iter.hasNext()) {
633: LocalVariableImpl var = (LocalVariableImpl) iter.next();
634: if (var.name().equals(name)) {
635: result.add(var);
636: }
637: }
638: return result;
639: }
640:
641: /**
642: * @see com.sun.jdi.Locatable#location()
643: */
644: public Location location() {
645: if (isAbstract()) {
646: return null;
647: }
648: if (isNative()) {
649: return new LocationImpl(virtualMachineImpl(), this , -1);
650: }
651: // First retrieve line code table.
652: try {
653: getLineTable();
654: } catch (AbsentInformationException e) {
655: return new LocationImpl(virtualMachineImpl(), this , -1);
656: }
657:
658: // Return location with Lowest Valid Code Index.
659: return new LocationImpl(virtualMachineImpl(), this ,
660: fLowestValidCodeIndex);
661: }
662:
663: /**
664: * Writes JDWP representation.
665: */
666: public void write(MirrorImpl target, DataOutputStream out)
667: throws IOException {
668: fMethodID.write(out);
669: if (target.fVerboseWriter != null) {
670: target.fVerboseWriter.println("method", fMethodID.value()); //$NON-NLS-1$
671: }
672: }
673:
674: /**
675: * Writes JDWP representation, including ReferenceType.
676: */
677: protected void writeWithReferenceType(MirrorImpl target,
678: DataOutputStream out) throws IOException {
679: referenceTypeImpl().write(target, out);
680: write(target, out);
681: }
682:
683: /**
684: * Writes JDWP representation, including ReferenceType with Tag.
685: */
686: protected void writeWithReferenceTypeWithTag(MirrorImpl target,
687: DataOutputStream out) throws IOException {
688: referenceTypeImpl().writeWithTag(target, out);
689: write(target, out);
690: }
691:
692: /**
693: * @return Reads JDWP representation and returns new instance.
694: */
695: protected static MethodImpl readWithReferenceTypeWithTag(
696: MirrorImpl target, DataInputStream in) throws IOException {
697: VirtualMachineImpl vmImpl = target.virtualMachineImpl();
698: // See Location.
699: ReferenceTypeImpl referenceType = ReferenceTypeImpl
700: .readWithTypeTag(target, in);
701: if (referenceType == null)
702: return null;
703:
704: JdwpMethodID ID = new JdwpMethodID(vmImpl);
705: if (target.fVerboseWriter != null) {
706: target.fVerboseWriter.println("method", ID.value()); //$NON-NLS-1$
707: }
708:
709: ID.read(in);
710: if (ID.isNull()) {
711: return null;
712: }
713:
714: // The method must be part of a known reference type.
715: MethodImpl method = referenceType.findMethod(ID);
716: if (method == null) {
717: throw new InternalError(
718: JDIMessages.MethodImpl_Got_MethodID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_10);
719: }
720: return method;
721: }
722:
723: /**
724: * @return Reads JDWP representation and returns new instance.
725: */
726: protected static MethodImpl readWithNameSignatureModifiers(
727: ReferenceTypeImpl target, ReferenceTypeImpl referenceType,
728: boolean withGenericSignature, DataInputStream in)
729: throws IOException {
730: VirtualMachineImpl vmImpl = target.virtualMachineImpl();
731: JdwpMethodID ID = new JdwpMethodID(vmImpl);
732: ID.read(in);
733: if (target.fVerboseWriter != null) {
734: target.fVerboseWriter.println("method", ID.value()); //$NON-NLS-1$
735: }
736:
737: if (ID.isNull()) {
738: return null;
739: }
740: String name = target.readString("name", in); //$NON-NLS-1$
741: String signature = target.readString("signature", in); //$NON-NLS-1$
742: String genericSignature = null;
743: if (withGenericSignature) {
744: genericSignature = target.readString(
745: "generic signature", in); //$NON-NLS-1$
746: if ("".equals(genericSignature)) { //$NON-NLS-1$
747: genericSignature = null;
748: }
749: }
750: int modifierBits = target.readInt(
751: "modifiers", AccessibleImpl.getModifierStrings(), in); //$NON-NLS-1$
752:
753: MethodImpl mirror = new MethodImpl(vmImpl, referenceType, ID,
754: name, signature, genericSignature, modifierBits);
755: return mirror;
756: }
757:
758: /**
759: * Retrieves constant mappings.
760: */
761: public static void getConstantMaps() {
762: if (fgInvokeOptions != null) {
763: return;
764: }
765:
766: Field[] fields = MethodImpl.class.getDeclaredFields();
767: fgInvokeOptions = new String[32];
768:
769: for (int i = 0; i < fields.length; i++) {
770: Field field = fields[i];
771: if ((field.getModifiers() & Modifier.PUBLIC) == 0
772: || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0
773: || (field.getModifiers() & Modifier.FINAL) == 0) {
774: continue;
775: }
776:
777: try {
778: String name = field.getName();
779:
780: if (name.startsWith("INVOKE_")) { //$NON-NLS-1$
781: int value = field.getInt(null);
782: for (int j = 0; j < fgInvokeOptions.length; j++) {
783: if ((1 << j & value) != 0) {
784: fgInvokeOptions[j] = name;
785: break;
786: }
787: }
788: }
789: } catch (IllegalAccessException e) {
790: // Will not occur for own class.
791: } catch (IllegalArgumentException e) {
792: // Should not occur.
793: // We should take care that all public static final constants
794: // in this class are numbers that are convertible to int.
795: }
796: }
797: }
798:
799: /**
800: * @return Returns a map with string representations of tags.
801: */
802: protected static String[] getInvokeOptions() {
803: getConstantMaps();
804: return fgInvokeOptions;
805: }
806:
807: /**
808: * @see Method#isObsolete()
809: *
810: * The JDK 1.4.0 specification states that obsolete methods
811: * are given an ID of zero. It also states that when a method
812: * is redefined, the new method gets the ID of the old method.
813: * Thus, the JDWP query for isObsolete on JDK 1.4 will never return true
814: * for a non-zero method ID. The query is therefore not needed
815: */
816: public boolean isObsolete() {
817: if (virtualMachineImpl().isJdwpVersionGreaterOrEqual(1, 4)) {
818: return fMethodID.value() == 0;
819: }
820: return false;
821: }
822:
823: /**
824: * @see Method#allLineLocations(String, String)
825: */
826: public List allLineLocations(String stratum, String sourceName)
827: throws AbsentInformationException {
828: if (isAbstract() || isNative()) {
829: return Collections.EMPTY_LIST;
830: }
831: if (stratum == null) { // if stratum not defined use the default stratum for the declaring type
832: stratum = declaringType().defaultStratum();
833: }
834: List allLineLocations = null;
835: Map sourceNameAllLineLocations = null;
836: if (fStratumAllLineLocations == null) { // the stratum map doesn't exist, create it
837: fStratumAllLineLocations = new HashMap();
838: } else {
839: // get the source name map
840: sourceNameAllLineLocations = (Map) fStratumAllLineLocations
841: .get(stratum);
842: }
843: if (sourceNameAllLineLocations == null) { // the source name map doesn't exist, create it
844: sourceNameAllLineLocations = new HashMap();
845: fStratumAllLineLocations.put(stratum,
846: sourceNameAllLineLocations);
847: } else {
848: // get the line locations
849: allLineLocations = (List) sourceNameAllLineLocations
850: .get(sourceName);
851: }
852: if (allLineLocations == null) { // the line locations are not know, compute and store them
853: getLineTable();
854: allLineLocations = referenceTypeImpl().allLineLocations(
855: stratum, sourceName, this , fCodeIndexTable,
856: fJavaStratumLineNumberTable);
857: sourceNameAllLineLocations
858: .put(sourceName, allLineLocations);
859: }
860: return allLineLocations;
861: }
862:
863: /**
864: * @see Method#locationsOfLine(String, String, int)
865: */
866: public List locationsOfLine(String stratum, String sourceName,
867: int lineNumber) throws AbsentInformationException {
868: if (isAbstract() || isNative()) {
869: return Collections.EMPTY_LIST;
870: }
871: return referenceTypeImpl().locationsOfLine(stratum, sourceName,
872: lineNumber, this );
873: }
874:
875: /**
876: * Return a list which contains a location for the each disjoin range of code indice
877: * that have bean assigned to the given lines (by the compiler or/and the VM).
878: * Return an empty list if there is not executable code at the specified lines.
879: */
880: protected List javaStratumLocationsOfLines(List javaLines)
881: throws AbsentInformationException {
882: Set tmpLocations = new TreeSet();
883: for (Iterator iter = javaLines.iterator(); iter.hasNext();) {
884: Integer key = (Integer) iter.next();
885: List indexes = javaStratumLineToCodeIndexes(key.intValue());
886: if (indexes != null) {
887: tmpLocations.addAll(indexes);
888: }
889: }
890: List locations = new ArrayList();
891: for (Iterator iter = tmpLocations.iterator(); iter.hasNext();) {
892: long index = ((Long) iter.next()).longValue();
893: int position = Arrays.binarySearch(fCodeIndexTable, index);
894: if (position == 0
895: || !tmpLocations.contains(new Long(
896: fCodeIndexTable[position - 1]))) {
897: locations.add(new LocationImpl(virtualMachineImpl(),
898: this , index));
899: }
900: }
901: return locations;
902: }
903:
904: public boolean isBridge() {
905: return (fModifierBits & MODIFIER_ACC_BRIDGE) != 0;
906: }
907:
908: public boolean isVarArgs() {
909: // TODO: remove this test when j9 solve its problem
910: // it returns invalid 1.5 flags for 1.4 classes.
911: // see bug 53870
912: return !virtualMachine().name().equals("j9") && (fModifierBits & MODIFIER_ACC_VARARGS) != 0; //$NON-NLS-1$
913: }
914: }
|