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>")) { 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 }