comparison agent/src/share/classes/sun/jvm/hotspot/utilities/ObjectReader.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 2002-2007 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.utilities;
26
27 import java.lang.reflect.Modifier;
28 import java.util.*;
29 import sun.jvm.hotspot.debugger.*;
30 import sun.jvm.hotspot.oops.*;
31 import sun.jvm.hotspot.runtime.*;
32 import sun.jvm.hotspot.utilities.*;
33
34 /**
35 * ObjectReader can "deserialize" objects from debuggee.
36 *
37 * Class Loading:
38 *
39 * ObjectReader loads classes using the given class loader. If no
40 * class loader is supplied, it uses a ProcImageClassLoader, which
41 * loads classes from debuggee core or process.
42
43 * Object creation:
44 *
45 * This class uses no-arg constructor to construct objects. But if
46 * there is no no-arg constructor in a given class, then it tries to
47 * use other constructors with 'default' values - null for object
48 * types, 0, 0.0, false etc. for primitives. If this process fails to
49 * construct an instance (because of null checking by constructor or 0
50 * being invalid for an int arg etc.), then null is returned. While
51 * constructing complete object graph 'null' is inserted silently on
52 * failure and the deserialization continues to construct best-effort
53 * object graph.
54 *
55 * Debug messages:
56 *
57 * The flag sun.jvm.hotspot.utilities.ObjectReader.DEBUG may be set to
58 * non-null to get debug error messages and stack traces.
59 *
60 * JDK version:
61 *
62 * JDK classes are loaded by bootstrap class loader and not by the
63 * supplied class loader or ProcImageClassLoader. This may create
64 * problems if a JDK class evolves. i.e., if SA runs a JDK version
65 * different from that of the debuggee, there is a possibility of
66 * schema change. It is recommended that the matching JDK version be
67 * used to run SA for proper object deserialization.
68 *
69 */
70
71 public class ObjectReader {
72
73 private static final boolean DEBUG;
74 static {
75 DEBUG = System.getProperty("sun.jvm.hotspot.utilities.ObjectReader.DEBUG") != null;
76 }
77
78 public ObjectReader(ClassLoader cl) {
79 this.cl = cl;
80 this.oopToObjMap = new HashMap();
81 this.fieldMap = new HashMap();
82 }
83
84 public ObjectReader() {
85 this(new ProcImageClassLoader());
86 }
87
88 public Object readObject(Oop oop) throws ClassNotFoundException {
89 if (oop instanceof Instance) {
90 return readInstance((Instance) oop);
91 } else if (oop instanceof TypeArray){
92 return readPrimitiveArray((TypeArray)oop);
93 } else if (oop instanceof ObjArray){
94 return readObjectArray((ObjArray)oop);
95 } else {
96 return null;
97 }
98 }
99
100 protected final Object getDefaultPrimitiveValue(Class clz) {
101 if (clz == Boolean.TYPE) {
102 return Boolean.FALSE;
103 } else if (clz == Character.TYPE) {
104 return new Character(' ');
105 } else if (clz == Byte.TYPE) {
106 return new Byte((byte) 0);
107 } else if (clz == Short.TYPE) {
108 return new Short((short) 0);
109 } else if (clz == Integer.TYPE) {
110 return new Integer(0);
111 } else if (clz == Long.TYPE) {
112 return new Long(0L);
113 } else if (clz == Float.TYPE) {
114 return new Float(0.0f);
115 } else if (clz == Double.TYPE) {
116 return new Double(0.0);
117 } else {
118 throw new RuntimeException("should not reach here!");
119 }
120 }
121
122 protected Symbol javaLangString;
123 protected Symbol javaLangString() {
124 if (javaLangString == null) {
125 javaLangString = VM.getVM().getSymbolTable().probe("java/lang/String");
126 }
127 return javaLangString;
128 }
129
130 public Object readInstance(Instance oop) throws ClassNotFoundException {
131 Object result = getFromObjTable(oop);
132 if (result == null) {
133 InstanceKlass kls = (InstanceKlass) oop.getKlass();
134 // Handle java.lang.String instances differently. As part of JSR-133, fields of immutable
135 // classes have been made final. The algorithm below will not be able to read Strings from
136 // debuggee (can't use reflection to set final fields). But, need to read Strings is very
137 // important. FIXME: need a framework to handle many other special cases.
138 if (kls.getName().equals(javaLangString())) {
139 return OopUtilities.stringOopToString(oop);
140 }
141
142 Class clz = readClass(kls);
143 try {
144 result = clz.newInstance();
145 } catch (Exception ex) {
146 // no-arg constructor failed to create object. Let us try
147 // to call constructors one-by-one with default arguments
148 // (null for objects, 0/0.0 etc. for primitives) till we
149 // succeed or fail on all constructors.
150
151 java.lang.reflect.Constructor[] ctrs = clz.getDeclaredConstructors();
152 for (int n = 0; n < ctrs.length; n++) {
153 java.lang.reflect.Constructor c = ctrs[n];
154 Class[] paramTypes = c.getParameterTypes();
155 Object[] params = new Object[paramTypes.length];
156 for (int i = 0; i < params.length; i++) {
157 if (paramTypes[i].isPrimitive()) {
158 params[i] = getDefaultPrimitiveValue(paramTypes[i]);
159 }
160 }
161 try {
162 c.setAccessible(true);
163 result = c.newInstance(params);
164 break;
165 } catch (Exception exp) {
166 if (DEBUG) {
167 System.err.println("Can't create object using " + c);
168 exp.printStackTrace();
169 }
170 }
171 }
172 }
173
174 if (result != null) {
175 putIntoObjTable(oop, result);
176 oop.iterate(new FieldSetter(result), false);
177 }
178 }
179 return result;
180 }
181
182 public Object readPrimitiveArray(final TypeArray array) {
183
184 Object result = getFromObjTable(array);
185 if (result == null) {
186 int length = (int) array.getLength();
187 TypeArrayKlass klass = (TypeArrayKlass) array.getKlass();
188 int type = (int) klass.getElementType();
189 switch (type) {
190 case TypeArrayKlass.T_BOOLEAN: {
191 final boolean[] arrayObj = new boolean[length];
192 array.iterate(new DefaultOopVisitor() {
193 public void doBoolean(BooleanField field, boolean isVMField) {
194 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
195 arrayObj[ifd.getIndex()] = field.getValue(array);
196 }
197 }, false);
198 result = arrayObj;
199 }
200 break;
201
202 case TypeArrayKlass.T_CHAR: {
203 final char[] arrayObj = new char[length];
204 array.iterate(new DefaultOopVisitor() {
205 public void doChar(CharField field, boolean isVMField) {
206 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
207 arrayObj[ifd.getIndex()] = field.getValue(array);
208 }
209 }, false);
210 result = arrayObj;
211 }
212 break;
213
214 case TypeArrayKlass.T_FLOAT: {
215 final float[] arrayObj = new float[length];
216 array.iterate(new DefaultOopVisitor() {
217 public void doFloat(FloatField field, boolean isVMField) {
218 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
219 arrayObj[ifd.getIndex()] = field.getValue(array);
220 }
221 }, false);
222 result = arrayObj;
223 }
224 break;
225
226 case TypeArrayKlass.T_DOUBLE: {
227 final double[] arrayObj = new double[length];
228 array.iterate(new DefaultOopVisitor() {
229 public void doDouble(DoubleField field, boolean isVMField) {
230 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
231 arrayObj[ifd.getIndex()] = field.getValue(array);
232 }
233 }, false);
234 result = arrayObj;
235 }
236 break;
237
238 case TypeArrayKlass.T_BYTE: {
239 final byte[] arrayObj = new byte[length];
240 array.iterate(new DefaultOopVisitor() {
241 public void doByte(ByteField field, boolean isVMField) {
242 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
243 arrayObj[ifd.getIndex()] = field.getValue(array);
244 }
245 }, false);
246 result = arrayObj;
247 }
248 break;
249
250 case TypeArrayKlass.T_SHORT: {
251 final short[] arrayObj = new short[length];
252 array.iterate(new DefaultOopVisitor() {
253 public void doShort(ShortField field, boolean isVMField) {
254 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
255 arrayObj[ifd.getIndex()] = field.getValue(array);
256 }
257 }, false);
258 result = arrayObj;
259 }
260 break;
261
262 case TypeArrayKlass.T_INT: {
263 final int[] arrayObj = new int[length];
264 array.iterate(new DefaultOopVisitor() {
265 public void doInt(IntField field, boolean isVMField) {
266 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
267 arrayObj[ifd.getIndex()] = field.getValue(array);
268 }
269 }, false);
270 result = arrayObj;
271 }
272 break;
273
274 case TypeArrayKlass.T_LONG: {
275 final long[] arrayObj = new long[length];
276 array.iterate(new DefaultOopVisitor() {
277 public void doLong(LongField field, boolean isVMField) {
278 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
279 arrayObj[ifd.getIndex()] = field.getValue(array);
280 }
281 }, false);
282 result = arrayObj;
283 }
284 break;
285
286 default:
287 throw new RuntimeException("should not reach here!");
288 }
289
290 putIntoObjTable(array, result);
291 }
292 return result;
293 }
294
295 protected final boolean isRobust(OopHandle handle) {
296 return RobustOopDeterminator.oopLooksValid(handle);
297 }
298
299 public Object readObjectArray(final ObjArray array) throws ClassNotFoundException {
300 Object result = getFromObjTable(array);
301 if (result == null) {
302 int length = (int) array.getLength();
303 ObjArrayKlass klass = (ObjArrayKlass) array.getKlass();
304 Klass bottomKls = klass.getBottomKlass();
305 Class bottomCls = null;
306 final int dimension = (int) klass.getDimension();
307 int[] dimArray = null;
308 if (bottomKls instanceof InstanceKlass) {
309 bottomCls = readClass((InstanceKlass) bottomKls);
310 dimArray = new int[dimension];
311 } else { // instanceof TypeArrayKlass
312 TypeArrayKlass botKls = (TypeArrayKlass) bottomKls;
313 dimArray = new int[dimension -1];
314 }
315 // initialize the length
316 dimArray[0] = length;
317 final Object[] arrayObj = (Object[]) java.lang.reflect.Array.newInstance(bottomCls, dimArray);
318 putIntoObjTable(array, arrayObj);
319 result = arrayObj;
320 array.iterate(new DefaultOopVisitor() {
321 public void doOop(OopField field, boolean isVMField) {
322 OopHandle handle = field.getValueAsOopHandle(getObj());
323 if (! isRobust(handle)) {
324 return;
325 }
326
327 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
328 try {
329 arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
330 } catch (Exception e) {
331 if (DEBUG) {
332 System.err.println("Array element set failed for " + ifd);
333 e.printStackTrace();
334 }
335 }
336 }
337 }, false);
338 }
339 return result;
340 }
341
342 protected class FieldSetter extends DefaultOopVisitor {
343 protected Object obj;
344
345 public FieldSetter(Object obj) {
346 this.obj = obj;
347 }
348
349 private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
350 if (DEBUG) {
351 if (f != null) System.err.println("Field set failed for " + f);
352 ex.printStackTrace();
353 }
354 }
355
356 // Callback methods for each field type in an object
357 public void doOop(OopField field, boolean isVMField) {
358 OopHandle handle = field.getValueAsOopHandle(getObj());
359 if (! isRobust(handle) ) {
360 return;
361 }
362
363 java.lang.reflect.Field f = null;
364 try {
365 f = readField(field);
366 if (Modifier.isFinal(f.getModifiers())) return;
367 f.setAccessible(true);
368 f.set(obj, readObject(field.getValue(getObj())));
369 } catch (Exception ex) {
370 printFieldSetError(f, ex);
371 }
372 }
373
374 public void doByte(ByteField field, boolean isVMField) {
375 java.lang.reflect.Field f = null;
376 try {
377 f = readField(field);
378 if (Modifier.isFinal(f.getModifiers())) return;
379 f.setAccessible(true);
380 f.setByte(obj, field.getValue(getObj()));
381 } catch (Exception ex) {
382 printFieldSetError(f, ex);
383 }
384 }
385
386 public void doChar(CharField field, boolean isVMField) {
387 java.lang.reflect.Field f = null;
388 try {
389 f = readField(field);
390 if (Modifier.isFinal(f.getModifiers())) return;
391 f.setAccessible(true);
392 f.setChar(obj, field.getValue(getObj()));
393 } catch (Exception ex) {
394 printFieldSetError(f, ex);
395 }
396 }
397
398 public void doBoolean(BooleanField field, boolean isVMField) {
399 java.lang.reflect.Field f = null;
400 try {
401 f = readField(field);
402 if (Modifier.isFinal(f.getModifiers())) return;
403 f.setAccessible(true);
404 f.setBoolean(obj, field.getValue(getObj()));
405 } catch (Exception ex) {
406 printFieldSetError(f, ex);
407 }
408 }
409
410 public void doShort(ShortField field, boolean isVMField) {
411 java.lang.reflect.Field f = null;
412 try {
413 f = readField(field);
414 if (Modifier.isFinal(f.getModifiers())) return;
415 f.setAccessible(true);
416 f.setShort(obj, field.getValue(getObj()));
417 } catch (Exception ex) {
418 printFieldSetError(f, ex);
419 }
420 }
421
422 public void doInt(IntField field, boolean isVMField) {
423 java.lang.reflect.Field f = null;
424 try {
425 f = readField(field);
426 if (Modifier.isFinal(f.getModifiers())) return;
427 f.setAccessible(true);
428 f.setInt(obj, field.getValue(getObj()));
429 } catch (Exception ex) {
430 printFieldSetError(f, ex);
431 }
432 }
433
434 public void doLong(LongField field, boolean isVMField) {
435 java.lang.reflect.Field f = null;
436 try {
437 f = readField(field);
438 if (Modifier.isFinal(f.getModifiers())) return;
439 f.setAccessible(true);
440 f.setLong(obj, field.getValue(getObj()));
441 } catch (Exception ex) {
442 printFieldSetError(f, ex);
443 }
444 }
445
446 public void doFloat(FloatField field, boolean isVMField) {
447 java.lang.reflect.Field f = null;
448 try {
449 f = readField(field);
450 if (Modifier.isFinal(f.getModifiers())) return;
451 f.setAccessible(true);
452 f.setFloat(obj, field.getValue(getObj()));
453 } catch (Exception ex) {
454 printFieldSetError(f, ex);
455 }
456 }
457
458 public void doDouble(DoubleField field, boolean isVMField) {
459 java.lang.reflect.Field f = null;
460 try {
461 f = readField(field);
462 if (Modifier.isFinal(f.getModifiers())) return;
463 f.setAccessible(true);
464 f.setDouble(obj, field.getValue(getObj()));
465 } catch (Exception ex) {
466 printFieldSetError(f, ex);
467 }
468 }
469
470 public void doCInt(CIntField field, boolean isVMField) {
471 throw new RuntimeException("should not reach here!");
472 }
473 }
474
475 public Class readClass(InstanceKlass kls) throws ClassNotFoundException {
476 Class cls = (Class) getFromObjTable(kls);
477 if (cls == null) {
478 cls = Class.forName(kls.getName().asString().replace('/', '.'), true, cl);
479 putIntoObjTable(kls, cls);
480 }
481 return cls;
482 }
483
484 public Object readMethodOrConstructor(sun.jvm.hotspot.oops.Method m)
485 throws NoSuchMethodException, ClassNotFoundException {
486 String name = m.getName().asString();
487 if (name.equals("<init>")) {
488 return readConstructor(m);
489 } else {
490 return readMethod(m);
491 }
492 }
493
494 public java.lang.reflect.Method readMethod(sun.jvm.hotspot.oops.Method m)
495 throws NoSuchMethodException, ClassNotFoundException {
496 java.lang.reflect.Method result = (java.lang.reflect.Method) getFromObjTable(m);
497 if (result == null) {
498 Class clz = readClass((InstanceKlass)m.getMethodHolder());
499 String name = m.getName().asString();
500 Class[] paramTypes = getParamTypes(m.getSignature());
501 result = clz.getMethod(name, paramTypes);
502 putIntoObjTable(m, result);
503 }
504 return result;
505 }
506
507 public java.lang.reflect.Constructor readConstructor(sun.jvm.hotspot.oops.Method m)
508 throws NoSuchMethodException, ClassNotFoundException {
509 java.lang.reflect.Constructor result = (java.lang.reflect.Constructor) getFromObjTable(m);
510 if (result == null) {
511 Class clz = readClass((InstanceKlass)m.getMethodHolder());
512 String name = m.getName().asString();
513 Class[] paramTypes = getParamTypes(m.getSignature());
514 result = clz.getDeclaredConstructor(paramTypes);
515 putIntoObjTable(m, result);
516 }
517 return result;
518 }
519
520 public java.lang.reflect.Field readField(sun.jvm.hotspot.oops.Field f)
521 throws NoSuchFieldException, ClassNotFoundException {
522 java.lang.reflect.Field result = (java.lang.reflect.Field) fieldMap.get(f);
523 if (result == null) {
524 FieldIdentifier fieldId = f.getID();
525 Class clz = readClass((InstanceKlass) f.getFieldHolder());
526 String name = fieldId.getName();
527 try {
528 result = clz.getField(name);
529 } catch (NoSuchFieldException nsfe) {
530 result = clz.getDeclaredField(name);
531 }
532 fieldMap.put(f, result);
533 }
534 return result;
535 }
536
537 protected final ClassLoader cl;
538 protected Map oopToObjMap; // Map<Oop, Object>
539 protected Map fieldMap; // Map<sun.jvm.hotspot.oops.Field, java.lang.reflect.Field>
540
541 protected void putIntoObjTable(Oop oop, Object obj) {
542 oopToObjMap.put(oop, obj);
543 }
544
545 protected Object getFromObjTable(Oop oop) {
546 return oopToObjMap.get(oop);
547 }
548
549 protected class SignatureParser extends SignatureIterator {
550 protected Vector tmp = new Vector(); // Vector<Class>
551
552 public SignatureParser(Symbol s) {
553 super(s);
554 }
555
556 public void doBool () { tmp.add(Boolean.TYPE); }
557 public void doChar () { tmp.add(Character.TYPE); }
558 public void doFloat () { tmp.add(Float.TYPE); }
559 public void doDouble() { tmp.add(Double.TYPE); }
560 public void doByte () { tmp.add(Byte.TYPE); }
561 public void doShort () { tmp.add(Short.TYPE); }
562 public void doInt () { tmp.add(Integer.TYPE); }
563 public void doLong () { tmp.add(Long.TYPE); }
564 public void doVoid () {
565 if(isReturnType()) {
566 tmp.add(Void.TYPE);
567 } else {
568 throw new RuntimeException("should not reach here");
569 }
570 }
571
572 public void doObject(int begin, int end) {
573 tmp.add(getClass(begin, end));
574 }
575
576 public void doArray (int begin, int end) {
577 int inner = arrayInnerBegin(begin);
578 Class elemCls = null;
579 switch (_signature.getByteAt(inner)) {
580 case 'B': elemCls = Boolean.TYPE; break;
581 case 'C': elemCls = Character.TYPE; break;
582 case 'D': elemCls = Double.TYPE; break;
583 case 'F': elemCls = Float.TYPE; break;
584 case 'I': elemCls = Integer.TYPE; break;
585 case 'J': elemCls = Long.TYPE; break;
586 case 'S': elemCls = Short.TYPE; break;
587 case 'Z': elemCls = Boolean.TYPE; break;
588 case 'L': elemCls = getClass(inner + 1, end); break;
589 default: break;
590 }
591
592 int dimension = inner - begin;
593 // create 0 x 0 ... array and get class from that
594 int[] dimArray = new int[dimension];
595 tmp.add(java.lang.reflect.Array.newInstance(elemCls, dimArray).getClass());
596 }
597
598 protected Class getClass(int begin, int end) {
599 String className = getClassName(begin, end);
600 try {
601 return Class.forName(className, true, cl);
602 } catch (Exception e) {
603 if (DEBUG) {
604 System.err.println("Can't load class " + className);
605 }
606 throw new RuntimeException(e);
607 }
608 }
609
610 protected String getClassName(int begin, int end) {
611 StringBuffer buf = new StringBuffer();
612 for (int i = begin; i < end; i++) {
613 char c = (char) (_signature.getByteAt(i) & 0xFF);
614 if (c == '/') {
615 buf.append('.');
616 } else {
617 buf.append(c);
618 }
619 }
620 return buf.toString();
621 }
622
623 protected int arrayInnerBegin(int begin) {
624 while (_signature.getByteAt(begin) == '[') {
625 ++begin;
626 }
627 return begin;
628 }
629
630 public int getNumParams() {
631 return tmp.size();
632 }
633
634 public Enumeration getParamTypes() {
635 return tmp.elements();
636 }
637 }
638
639 protected Class[] getParamTypes(Symbol signature) {
640 SignatureParser sp = new SignatureParser(signature);
641 sp.iterateParameters();
642 Class result[] = new Class[sp.getNumParams()];
643 Enumeration e = sp.getParamTypes();
644 int i = 0;
645 while (e.hasMoreElements()) {
646 result[i] = (Class) e.nextElement();
647 i++;
648 }
649 return result;
650 }
651 }