1 /*
2 * Copyright (c) 2002, 2022, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 package sun.jvm.hotspot.utilities;
26
27 import java.lang.reflect.Modifier;
28 import java.util.*;
29 import java.util.stream.*;
30 import sun.jvm.hotspot.debugger.*;
31 import sun.jvm.hotspot.oops.*;
32 import sun.jvm.hotspot.runtime.*;
33 import sun.jvm.hotspot.utilities.*;
34
35 /**
36 * ObjectReader can "deserialize" objects from debuggee.
37 *
38 * Class Loading:
39 *
40 * ObjectReader loads classes using the given class loader. If no
41 * class loader is supplied, it uses a ProcImageClassLoader, which
42 * loads classes from debuggee core or process.
43
44 * Object creation:
45 *
46 * This class uses no-arg constructor to construct objects. But if
47 * there is no no-arg constructor in a given class, then it tries to
48 * use other constructors with 'default' values - null for object
49 * types, 0, 0.0, false etc. for primitives. If this process fails to
50 * construct an instance (because of null checking by constructor or 0
51 * being invalid for an int arg etc.), then null is returned. While
52 * constructing complete object graph 'null' is inserted silently on
53 * failure and the deserialization continues to construct best-effort
54 * object graph.
55 *
56 * Debug messages:
57 *
58 * The flag sun.jvm.hotspot.utilities.ObjectReader.DEBUG may be set to
59 * non-null to get debug error messages and stack traces.
60 *
61 * JDK version:
62 *
63 * JDK classes are loaded by bootstrap class loader and not by the
64 * supplied class loader or ProcImageClassLoader. This may create
65 * problems if a JDK class evolves. i.e., if SA runs a JDK version
66 * different from that of the debuggee, there is a possibility of
67 * schema change. It is recommended that the matching JDK version be
68 * used to run SA for proper object deserialization.
69 *
70 */
71
72 public class ObjectReader {
73
74 private static final boolean DEBUG;
75 static {
76 DEBUG = System.getProperty("sun.jvm.hotspot.utilities.ObjectReader.DEBUG") != null;
77 }
78
79 public ObjectReader(ClassLoader cl) {
80 this.cl = cl;
81 this.oopToObjMap = new HashMap<>();
82 this.fieldMap = new HashMap<>();
83 }
84
85 public ObjectReader() {
86 this(new ProcImageClassLoader());
87 }
88
89 static void debugPrintln(String msg) {
90 if (DEBUG) {
91 System.err.println("DEBUG>" + msg);
92 }
93 }
94
95 static void debugPrintStackTrace(Exception exp) {
96 if (DEBUG) {
97 StackTraceElement[] els = exp.getStackTrace();
98 for (int i = 0; i < els.length; i++) {
99 System.err.println("DEBUG>" + els[i].toString());
100 }
101 }
102 }
103
104 public Object readObject(Oop oop) throws ClassNotFoundException {
105 if (oop instanceof Instance) {
106 return readInstance((Instance) oop);
107 } else if (oop instanceof TypeArray){
108 return readPrimitiveArray((TypeArray)oop);
109 } else if (oop instanceof ObjArray){
110 return readObjectArray((ObjArray)oop);
111 } else {
112 return null;
113 }
114 }
115
116 protected final Object getDefaultPrimitiveValue(Class clz) {
117 if (clz == Boolean.TYPE) {
118 return Boolean.FALSE;
119 } else if (clz == Character.TYPE) {
120 return ' ';
121 } else if (clz == Byte.TYPE) {
122 return (byte) 0;
123 } else if (clz == Short.TYPE) {
124 return (short) 0;
125 } else if (clz == Integer.TYPE) {
126 return 0;
127 } else if (clz == Long.TYPE) {
128 return 0L;
129 } else if (clz == Float.TYPE) {
130 return 0.0f;
131 } else if (clz == Double.TYPE) {
132 return 0.0;
133 } else {
134 throw new RuntimeException("should not reach here!");
135 }
136 }
137
138 protected String javaLangString;
139 protected String javaUtilHashtableEntry;
140 protected String javaUtilHashtable;
141 protected String javaUtilProperties;
142
143 protected String javaLangString() {
144 if (javaLangString == null) {
145 javaLangString = "java/lang/String";
146 }
147 return javaLangString;
148 }
149
150 protected String javaUtilHashtableEntry() {
151 if (javaUtilHashtableEntry == null) {
152 javaUtilHashtableEntry = "java/util/Hashtable$Entry";
153 }
154 return javaUtilHashtableEntry;
155 }
156
157 protected String javaUtilHashtable() {
158 if (javaUtilHashtable == null) {
159 javaUtilHashtable = "java/util/Hashtable";
160 }
161 return javaUtilHashtable;
162 }
163
164 protected String javaUtilProperties() {
165 if (javaUtilProperties == null) {
166 javaUtilProperties = "java/util/Properties";
167 }
168 return javaUtilProperties;
169 }
170
171 private void setHashtableEntry(java.util.Hashtable<Object, Object> p, Oop oop) {
172 InstanceKlass ik = (InstanceKlass)oop.getKlass();
173 OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;");
174 OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;");
175 OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;");
176 if (DEBUG) {
177 if (Assert.ASSERTS_ENABLED) {
178 Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?");
179 Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!");
180 }
181 }
182
183 Object key = null;
184 Object value = null;
185 Oop next = null;
186 try {
187 key = readObject(keyField.getValue(oop));
188 value = readObject(valueField.getValue(oop));
189 next = nextField.getValue(oop);
190 // For Properties, should use setProperty(k, v). Since it only runs in SA
191 // using put(k, v) should be OK.
192 p.put(key, value);
193 if (next != null) {
194 setHashtableEntry(p, next);
195 }
196 } catch (ClassNotFoundException ce) {
197 if( DEBUG) {
198 debugPrintln("Class not found " + ce);
199 debugPrintStackTrace(ce);
200 }
201 }
202 }
203
204 private void setPropertiesEntry(java.util.Properties p, Oop oop) {
205 InstanceKlass ik = (InstanceKlass)oop.getKlass();
206 OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;");
207 OopField valueField = (OopField)ik.findField("val", "Ljava/lang/Object;");
208 OopField nextField = (OopField)ik.findField("next", "Ljava/util/concurrent/ConcurrentHashMap$Node;");
209
210 try {
211 p.setProperty((String)readObject(keyField.getValue(oop)),
212 (String)readObject(valueField.getValue(oop)));
213 } catch (ClassNotFoundException ce) {
214 if (DEBUG) {
215 debugPrintStackTrace(ce);
216 }
217 }
218 // If this hashmap table Node is chained, then follow the chain to the next Node.
219 Oop chainedOop = nextField.getValue(oop);
220 if (chainedOop != null) {
221 setPropertiesEntry(p, chainedOop);
222 }
223 }
224
225 protected Object getHashtable(Instance oop) {
226 InstanceKlass k = (InstanceKlass)oop.getKlass();
227 OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;");
228 if (tableField == null) {
229 debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;");
230 return null;
231 }
232 java.util.Hashtable<Object, Object> table = new java.util.Hashtable<>();
233 ObjArray kvs = (ObjArray)tableField.getValue(oop);
234 long size = kvs.getLength();
235 debugPrintln("Hashtable$Entry Size = " + size);
236 for (long i=0; i<size; i++) {
237 Oop entry = kvs.getObjAt(i);
238 if (entry != null && entry.isInstance()) {
239 setHashtableEntry(table, entry);
240 }
241 }
242 return table;
243 }
244
245 private Properties getProperties(Instance oop) {
246 InstanceKlass k = (InstanceKlass)oop.getKlass();
247 OopField mapField = (OopField)k.findField("map", "Ljava/util/concurrent/ConcurrentHashMap;");
248 if (mapField == null) {
249 debugPrintln("Could not find field of Ljava/util/concurrent/ConcurrentHashMap");
250 return null;
251 }
252
253 Instance mapObj = (Instance)mapField.getValue(oop);
254 if (mapObj == null) {
255 debugPrintln("Could not get map field from java.util.Properties");
256 return null;
257 }
258
259 InstanceKlass mk = (InstanceKlass)mapObj.getKlass();
260 OopField tableField = (OopField)mk.findField("table", "[Ljava/util/concurrent/ConcurrentHashMap$Node;");
261 if (tableField == null) {
262 debugPrintln("Could not find field of [Ljava/util/concurrent/ConcurrentHashMap$Node");
263 return null;
264 }
265
266 java.util.Properties props = new java.util.Properties();
267 ObjArray kvs = (ObjArray)tableField.getValue(mapObj);
268 long size = kvs.getLength();
269 debugPrintln("ConcurrentHashMap$Node Size = " + size);
270 LongStream.range(0, size)
271 .mapToObj(kvs::getObjAt)
272 .filter(o -> o != null)
273 .forEach(o -> setPropertiesEntry(props, o));
274
275 return props;
276 }
277
278 public Object readInstance(Instance oop) throws ClassNotFoundException {
279 Object result = getFromObjTable(oop);
280 if (result == null) {
281 InstanceKlass kls = (InstanceKlass) oop.getKlass();
282 // Handle java.lang.String instances differently. As part of JSR-133, fields of immutable
283 // classes have been made final. The algorithm below will not be able to read Strings from
284 // debuggee (can't use reflection to set final fields). But, need to read Strings is very
285 // important.
286 // Same for Hashtable, key and hash are final, could not be set in the algorithm too.
287 // FIXME: need a framework to handle many other special cases.
288 if (kls.getName().equals(javaLangString())) {
289 return OopUtilities.stringOopToString(oop);
290 }
291
292 if (kls.getName().equals(javaUtilHashtable())) {
293 return getHashtable(oop);
294 }
295
296 if (kls.getName().equals(javaUtilProperties())) {
297 return getProperties(oop);
298 }
299
300 Class<?> clz = readClass(kls);
301 try {
302 result = clz.getDeclaredConstructor().newInstance();
303 } catch (Exception ex) {
304 // no-arg constructor failed to create object. Let us try
305 // to call constructors one-by-one with default arguments
306 // (null for objects, 0/0.0 etc. for primitives) till we
307 // succeed or fail on all constructors.
308
309 java.lang.reflect.Constructor[] ctrs = clz.getDeclaredConstructors();
310 for (int n = 0; n < ctrs.length; n++) {
311 java.lang.reflect.Constructor c = ctrs[n];
312 Class[] paramTypes = c.getParameterTypes();
313 Object[] params = new Object[paramTypes.length];
314 for (int i = 0; i < params.length; i++) {
315 if (paramTypes[i].isPrimitive()) {
316 params[i] = getDefaultPrimitiveValue(paramTypes[i]);
317 }
318 }
319 try {
320 c.setAccessible(true);
321 result = c.newInstance(params);
322 break;
323 } catch (Exception exp) {
324 if (DEBUG) {
325 debugPrintln("Can't create object using " + c);
326 debugPrintStackTrace(exp);
327 }
328 }
329 }
330 }
331
332 if (result != null) {
333 putIntoObjTable(oop, result);
334 oop.iterate(new FieldSetter(result), false);
335 }
336 }
337 return result;
338 }
339
340 public Object readPrimitiveArray(final TypeArray array) {
341
342 Object result = getFromObjTable(array);
343 if (result == null) {
344 int length = (int) array.getLength();
345 TypeArrayKlass klass = (TypeArrayKlass) array.getKlass();
346 int type = klass.getElementType();
347 switch (type) {
348 case TypeArrayKlass.T_BOOLEAN: {
349 final boolean[] arrayObj = new boolean[length];
350 array.iterate(new DefaultOopVisitor() {
351 public void doBoolean(BooleanField field, boolean isVMField) {
352 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
353 arrayObj[ifd.getIndex()] = field.getValue(array);
354 }
355 }, false);
356 result = arrayObj;
357 }
358 break;
359
360 case TypeArrayKlass.T_CHAR: {
361 final char[] arrayObj = new char[length];
362 array.iterate(new DefaultOopVisitor() {
363 public void doChar(CharField field, boolean isVMField) {
364 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
365 arrayObj[ifd.getIndex()] = field.getValue(array);
366 }
367 }, false);
368 result = arrayObj;
369 }
370 break;
371
372 case TypeArrayKlass.T_FLOAT: {
373 final float[] arrayObj = new float[length];
374 array.iterate(new DefaultOopVisitor() {
375 public void doFloat(FloatField field, boolean isVMField) {
376 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
377 arrayObj[ifd.getIndex()] = field.getValue(array);
378 }
379 }, false);
380 result = arrayObj;
381 }
382 break;
383
384 case TypeArrayKlass.T_DOUBLE: {
385 final double[] arrayObj = new double[length];
386 array.iterate(new DefaultOopVisitor() {
387 public void doDouble(DoubleField field, boolean isVMField) {
388 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
389 arrayObj[ifd.getIndex()] = field.getValue(array);
390 }
391 }, false);
392 result = arrayObj;
393 }
394 break;
395
396 case TypeArrayKlass.T_BYTE: {
397 final byte[] arrayObj = new byte[length];
398 array.iterate(new DefaultOopVisitor() {
399 public void doByte(ByteField field, boolean isVMField) {
400 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
401 arrayObj[ifd.getIndex()] = field.getValue(array);
402 }
403 }, false);
404 result = arrayObj;
405 }
406 break;
407
408 case TypeArrayKlass.T_SHORT: {
409 final short[] arrayObj = new short[length];
410 array.iterate(new DefaultOopVisitor() {
411 public void doShort(ShortField field, boolean isVMField) {
412 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
413 arrayObj[ifd.getIndex()] = field.getValue(array);
414 }
415 }, false);
416 result = arrayObj;
417 }
418 break;
419
420 case TypeArrayKlass.T_INT: {
421 final int[] arrayObj = new int[length];
422 array.iterate(new DefaultOopVisitor() {
423 public void doInt(IntField field, boolean isVMField) {
424 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
425 arrayObj[ifd.getIndex()] = field.getValue(array);
426 }
427 }, false);
428 result = arrayObj;
429 }
430 break;
431
432 case TypeArrayKlass.T_LONG: {
433 final long[] arrayObj = new long[length];
434 array.iterate(new DefaultOopVisitor() {
435 public void doLong(LongField field, boolean isVMField) {
436 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
437 arrayObj[ifd.getIndex()] = field.getValue(array);
438 }
439 }, false);
440 result = arrayObj;
441 }
442 break;
443
444 default:
445 throw new RuntimeException("should not reach here!");
446 }
447
448 putIntoObjTable(array, result);
449 }
450 return result;
451 }
452
453 protected final boolean isRobust(OopHandle handle) {
454 return RobustOopDeterminator.oopLooksValid(handle);
455 }
456
457 public Object readObjectArray(final ObjArray array) throws ClassNotFoundException {
458 Object result = getFromObjTable(array);
459 if (result == null) {
460 int length = (int) array.getLength();
461 ObjArrayKlass klass = (ObjArrayKlass) array.getKlass();
462 Klass bottomKls = klass.getBottomKlass();
463 Class bottomCls = null;
464 final int dimension = (int) klass.getDimension();
465 int[] dimArray = null;
466 if (bottomKls instanceof InstanceKlass) {
467 bottomCls = readClass((InstanceKlass) bottomKls);
468 dimArray = new int[dimension];
469 } else { // instanceof TypeArrayKlass
470 TypeArrayKlass botKls = (TypeArrayKlass) bottomKls;
471 dimArray = new int[dimension -1];
472 }
473 // initialize the length
474 dimArray[0] = length;
475 final Object[] arrayObj = (Object[]) java.lang.reflect.Array.newInstance(bottomCls, dimArray);
476 putIntoObjTable(array, arrayObj);
477 result = arrayObj;
478 array.iterate(new DefaultOopVisitor() {
479 public void doOop(OopField field, boolean isVMField) {
480 OopHandle handle = field.getValueAsOopHandle(getObj());
481 if (! isRobust(handle)) {
482 return;
483 }
484
485 IndexableFieldIdentifier ifd = (IndexableFieldIdentifier) field.getID();
486 try {
487 arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
488 } catch (Exception e) {
489 if (DEBUG) {
490 debugPrintln("Array element set failed for " + ifd);
491 debugPrintStackTrace(e);
492 }
493 }
494 }
495 }, false);
496 }
497 return result;
498 }
499
500 protected class FieldSetter extends DefaultOopVisitor {
501 protected Object obj;
502
503 public FieldSetter(Object obj) {
504 this.obj = obj;
505 }
506
507 private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
508 if (DEBUG) {
509 if (f != null) debugPrintln("Field set failed for " + f);
510 debugPrintStackTrace(ex);
511 }
512 }
513
514 // Callback methods for each field type in an object
515 public void doOop(OopField field, boolean isVMField) {
516 OopHandle handle = field.getValueAsOopHandle(getObj());
517 if (! isRobust(handle) ) {
518 return;
519 }
520
521 java.lang.reflect.Field f = null;
522 try {
523 f = readField(field);
524 if (Modifier.isFinal(f.getModifiers())) return;
525 f.setAccessible(true);
526 f.set(obj, readObject(field.getValue(getObj())));
527 } catch (Exception ex) {
528 printFieldSetError(f, ex);
529 }
530 }
531
532 public void doByte(ByteField field, boolean isVMField) {
533 java.lang.reflect.Field f = null;
534 try {
535 f = readField(field);
536 if (Modifier.isFinal(f.getModifiers())) return;
537 f.setAccessible(true);
538 f.setByte(obj, field.getValue(getObj()));
539 } catch (Exception ex) {
540 printFieldSetError(f, ex);
541 }
542 }
543
544 public void doChar(CharField field, boolean isVMField) {
545 java.lang.reflect.Field f = null;
546 try {
547 f = readField(field);
548 if (Modifier.isFinal(f.getModifiers())) return;
549 f.setAccessible(true);
550 f.setChar(obj, field.getValue(getObj()));
551 } catch (Exception ex) {
552 printFieldSetError(f, ex);
553 }
554 }
555
556 public void doBoolean(BooleanField field, boolean isVMField) {
557 java.lang.reflect.Field f = null;
558 try {
559 f = readField(field);
560 if (Modifier.isFinal(f.getModifiers())) return;
561 f.setAccessible(true);
562 f.setBoolean(obj, field.getValue(getObj()));
563 } catch (Exception ex) {
564 printFieldSetError(f, ex);
565 }
566 }
567
568 public void doShort(ShortField field, boolean isVMField) {
569 java.lang.reflect.Field f = null;
570 try {
571 f = readField(field);
572 if (Modifier.isFinal(f.getModifiers())) return;
573 f.setAccessible(true);
574 f.setShort(obj, field.getValue(getObj()));
575 } catch (Exception ex) {
576 printFieldSetError(f, ex);
577 }
578 }
579
580 public void doInt(IntField field, boolean isVMField) {
581 java.lang.reflect.Field f = null;
582 try {
583 f = readField(field);
584 if (Modifier.isFinal(f.getModifiers())) return;
585 f.setAccessible(true);
586 f.setInt(obj, field.getValue(getObj()));
587 } catch (Exception ex) {
588 printFieldSetError(f, ex);
589 }
590 }
591
592 public void doLong(LongField field, boolean isVMField) {
593 java.lang.reflect.Field f = null;
594 try {
595 f = readField(field);
596 if (Modifier.isFinal(f.getModifiers())) return;
597 f.setAccessible(true);
598 f.setLong(obj, field.getValue(getObj()));
599 } catch (Exception ex) {
600 printFieldSetError(f, ex);
601 }
602 }
603
604 public void doFloat(FloatField field, boolean isVMField) {
605 java.lang.reflect.Field f = null;
606 try {
607 f = readField(field);
608 if (Modifier.isFinal(f.getModifiers())) return;
609 f.setAccessible(true);
610 f.setFloat(obj, field.getValue(getObj()));
611 } catch (Exception ex) {
612 printFieldSetError(f, ex);
613 }
614 }
615
616 public void doDouble(DoubleField field, boolean isVMField) {
617 java.lang.reflect.Field f = null;
618 try {
619 f = readField(field);
620 if (Modifier.isFinal(f.getModifiers())) return;
621 f.setAccessible(true);
622 f.setDouble(obj, field.getValue(getObj()));
623 } catch (Exception ex) {
624 printFieldSetError(f, ex);
625 }
626 }
627
628 public void doCInt(CIntField field, boolean isVMField) {
629 throw new RuntimeException("should not reach here!");
630 }
631 }
632
633 public Class readClass(InstanceKlass kls) throws ClassNotFoundException {
634 Class cls = (Class) getFromObjTable(kls);
635 if (cls == null) {
636 cls = Class.forName(kls.getName().asString().replace('/', '.'), true, cl);
637 putIntoObjTable(kls, cls);
638 }
639 return cls;
640 }
641
642 public Object readMethodOrConstructor(sun.jvm.hotspot.oops.Method m)
643 throws NoSuchMethodException, ClassNotFoundException {
644 String name = m.getName().asString();
645 if (name.equals("<init>") || name.equals("<vnew>")) {
646 return readConstructor(m);
647 } else {
648 return readMethod(m);
649 }
650 }
651
652 public java.lang.reflect.Method readMethod(sun.jvm.hotspot.oops.Method m)
653 throws NoSuchMethodException, ClassNotFoundException {
654 java.lang.reflect.Method result = (java.lang.reflect.Method) getFromObjTable(m);
655 if (result == null) {
656 Class<?> clz = readClass(m.getMethodHolder());
657 String name = m.getName().asString();
658 Class[] paramTypes = getParamTypes(m.getSignature());
659 result = clz.getMethod(name, paramTypes);
660 putIntoObjTable(m, result);
661 }
662 return result;
663 }
664
665 public java.lang.reflect.Constructor readConstructor(sun.jvm.hotspot.oops.Method m)
666 throws NoSuchMethodException, ClassNotFoundException {
667 java.lang.reflect.Constructor result = (java.lang.reflect.Constructor) getFromObjTable(m);
668 if (result == null) {
669 Class<?> clz = readClass(m.getMethodHolder());
670 String name = m.getName().asString();
671 Class[] paramTypes = getParamTypes(m.getSignature());
672 result = clz.getDeclaredConstructor(paramTypes);
673 putIntoObjTable(m, result);
674 }
675 return result;
676 }
677
678 public java.lang.reflect.Field readField(sun.jvm.hotspot.oops.Field f)
679 throws NoSuchFieldException, ClassNotFoundException {
680 java.lang.reflect.Field result = fieldMap.get(f);
681 if (result == null) {
682 FieldIdentifier fieldId = f.getID();
683 Class clz = readClass(f.getFieldHolder());
684 String name = fieldId.getName();
685 try {
686 result = clz.getField(name);
687 } catch (NoSuchFieldException nsfe) {
688 result = clz.getDeclaredField(name);
689 }
690 fieldMap.put(f, result);
691 }
692 return result;
693 }
694
695 protected final ClassLoader cl;
696 protected Map<Object, Object> oopToObjMap;
697 protected Map<sun.jvm.hotspot.oops.Field, java.lang.reflect.Field> fieldMap;
698
699 protected void putIntoObjTable(Oop oop, Object obj) {
700 oopToObjMap.put(oop, obj);
701 }
702
703 protected Object getFromObjTable(Oop oop) {
704 return oopToObjMap.get(oop);
705 }
706
707 protected void putIntoObjTable(Metadata oop, Object obj) {
708 oopToObjMap.put(oop, obj);
709 }
710
711 protected Object getFromObjTable(Metadata oop) {
712 return oopToObjMap.get(oop);
713 }
714
715 protected class SignatureParser extends SignatureIterator {
716 protected Vector<Class<?>> tmp = new Vector<>();
717
718 public SignatureParser(Symbol s) {
719 super(s);
720 }
721
722 public void doBool () { tmp.add(Boolean.TYPE); }
723 public void doChar () { tmp.add(Character.TYPE); }
724 public void doFloat () { tmp.add(Float.TYPE); }
725 public void doDouble() { tmp.add(Double.TYPE); }
726 public void doByte () { tmp.add(Byte.TYPE); }
727 public void doShort () { tmp.add(Short.TYPE); }
728 public void doInt () { tmp.add(Integer.TYPE); }
729 public void doLong () { tmp.add(Long.TYPE); }
730 public void doVoid () {
731 if(isReturnType()) {
732 tmp.add(Void.TYPE);
733 } else {
734 throw new RuntimeException("should not reach here");
735 }
736 }
737
738 public void doObject(int begin, int end) {
739 tmp.add(getClass(begin, end));
740 }
741
742 public void doArray (int begin, int end) {
743 int inner = arrayInnerBegin(begin);
744 Class elemCls = null;
745 switch (_signature.getByteAt(inner)) {
746 case 'B': elemCls = Boolean.TYPE; break;
747 case 'C': elemCls = Character.TYPE; break;
748 case 'D': elemCls = Double.TYPE; break;
749 case 'F': elemCls = Float.TYPE; break;
750 case 'I': elemCls = Integer.TYPE; break;
751 case 'J': elemCls = Long.TYPE; break;
752 case 'S': elemCls = Short.TYPE; break;
753 case 'Z': elemCls = Boolean.TYPE; break;
754 case 'L': elemCls = getClass(inner + 1, end); break;
755 default: break;
756 }
757
758 int dimension = inner - begin;
759 // create 0 x 0 ... array and get class from that
760 int[] dimArray = new int[dimension];
761 tmp.add(java.lang.reflect.Array.newInstance(elemCls, dimArray).getClass());
762 }
763
764 protected Class getClass(int begin, int end) {
765 String className = getClassName(begin, end);
766 try {
767 return Class.forName(className, true, cl);
768 } catch (Exception e) {
769 if (DEBUG) {
770 debugPrintln("Can't load class " + className);
771 }
772 throw new RuntimeException(e);
773 }
774 }
775
776 protected String getClassName(int begin, int end) {
777 StringBuilder buf = new StringBuilder();
778 for (int i = begin; i < end; i++) {
779 char c = (char) (_signature.getByteAt(i) & 0xFF);
780 if (c == '/') {
781 buf.append('.');
782 } else {
783 buf.append(c);
784 }
785 }
786 return buf.toString();
787 }
788
789 protected int arrayInnerBegin(int begin) {
790 while (_signature.getByteAt(begin) == '[') {
791 ++begin;
792 }
793 return begin;
794 }
795
796 public int getNumParams() {
797 return tmp.size();
798 }
799
800 public Enumeration getParamTypes() {
801 return tmp.elements();
802 }
803 }
804
805 protected Class[] getParamTypes(Symbol signature) {
806 SignatureParser sp = new SignatureParser(signature);
807 sp.iterateParameters();
808 Class result[] = new Class[sp.getNumParams()];
809 Enumeration e = sp.getParamTypes();
810 int i = 0;
811 while (e.hasMoreElements()) {
812 result[i] = (Class) e.nextElement();
813 i++;
814 }
815 return result;
816 }
817 }
--- EOF ---