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