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