1 /* 2 * Copyright (c) 2004, 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.io.*; 28 import java.nio.channels.*; 29 import java.util.*; 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.memory.*; 32 import sun.jvm.hotspot.oops.*; 33 import sun.jvm.hotspot.runtime.*; 34 import sun.jvm.hotspot.classfile.*; 35 36 /* 37 * This class writes Java heap in hprof binary format. This format is 38 * used by Heap Analysis Tool (HAT). The class is heavily influenced 39 * by 'hprof_io.c' of 1.5 new hprof implementation. 40 */ 41 42 /* hprof binary format: (result either written to a file or sent over 43 * the network). 44 * 45 * WARNING: This format is still under development, and is subject to 46 * change without notice. 47 * 48 * header "JAVA PROFILE 1.0.2" (0-terminated) 49 * u4 size of identifiers. Identifiers are used to represent 50 * UTF8 strings, objects, stack traces, etc. They usually 51 * have the same size as host pointers. For example, on 52 * Solaris and Win32, the size is 4. 53 * u4 high word 54 * u4 low word number of milliseconds since 0:00 GMT, 1/1/70 55 * [record]* a sequence of records. 56 * 57 */ 58 59 /* 60 * 61 * Record format: 62 * 63 * u1 a TAG denoting the type of the record 64 * u4 number of *microseconds* since the time stamp in the 65 * header. (wraps around in a little more than an hour) 66 * u4 number of bytes *remaining* in the record. Note that 67 * this number excludes the tag and the length field itself. 68 * [u1]* BODY of the record (a sequence of bytes) 69 */ 70 71 /* 72 * The following TAGs are supported: 73 * 74 * TAG BODY notes 75 *---------------------------------------------------------- 76 * HPROF_UTF8 a UTF8-encoded name 77 * 78 * id name ID 79 * [u1]* UTF8 characters (no trailing zero) 80 * 81 * HPROF_LOAD_CLASS a newly loaded class 82 * 83 * u4 class serial number (> 0) 84 * id class object ID 85 * u4 stack trace serial number 86 * id class name ID 87 * 88 * HPROF_UNLOAD_CLASS an unloading class 89 * 90 * u4 class serial_number 91 * 92 * HPROF_FRAME a Java stack frame 93 * 94 * id stack frame ID 95 * id method name ID 96 * id method signature ID 97 * id source file name ID 98 * u4 class serial number 99 * i4 line number. >0: normal 100 * -1: unknown 101 * -2: compiled method 102 * -3: native method 103 * 104 * HPROF_TRACE a Java stack trace 105 * 106 * u4 stack trace serial number 107 * u4 thread serial number 108 * u4 number of frames 109 * [id]* stack frame IDs 110 * 111 * 112 * HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC 113 * 114 * u2 flags 0x0001: incremental vs. complete 115 * 0x0002: sorted by allocation vs. live 116 * 0x0004: whether to force a GC 117 * u4 cutoff ratio 118 * u4 total live bytes 119 * u4 total live instances 120 * u8 total bytes allocated 121 * u8 total instances allocated 122 * u4 number of sites that follow 123 * [u1 is_array: 0: normal object 124 * 2: object array 125 * 4: boolean array 126 * 5: char array 127 * 6: float array 128 * 7: double array 129 * 8: byte array 130 * 9: short array 131 * 10: int array 132 * 11: long array 133 * u4 class serial number (may be zero during startup) 134 * u4 stack trace serial number 135 * u4 number of bytes alive 136 * u4 number of instances alive 137 * u4 number of bytes allocated 138 * u4]* number of instance allocated 139 * 140 * HPROF_START_THREAD a newly started thread. 141 * 142 * u4 thread serial number (> 0) 143 * id thread object ID 144 * u4 stack trace serial number 145 * id thread name ID 146 * id thread group name ID 147 * id thread group parent name ID 148 * 149 * HPROF_END_THREAD a terminating thread. 150 * 151 * u4 thread serial number 152 * 153 * HPROF_HEAP_SUMMARY heap summary 154 * 155 * u4 total live bytes 156 * u4 total live instances 157 * u8 total bytes allocated 158 * u8 total instances allocated 159 * 160 * HPROF_HEAP_DUMP denote a heap dump 161 * 162 * [heap dump sub-records]* 163 * 164 * There are four kinds of heap dump sub-records: 165 * 166 * u1 sub-record type 167 * 168 * HPROF_GC_ROOT_UNKNOWN unknown root 169 * 170 * id object ID 171 * 172 * HPROF_GC_ROOT_THREAD_OBJ thread object 173 * 174 * id thread object ID (may be 0 for a 175 * thread newly attached through JNI) 176 * u4 thread sequence number 177 * u4 stack trace sequence number 178 * 179 * HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root 180 * 181 * id object ID 182 * id JNI global ref ID 183 * 184 * HPROF_GC_ROOT_JNI_LOCAL JNI local ref 185 * 186 * id object ID 187 * u4 thread serial number 188 * u4 frame # in stack trace (-1 for empty) 189 * 190 * HPROF_GC_ROOT_JAVA_FRAME Java stack frame 191 * 192 * id object ID 193 * u4 thread serial number 194 * u4 frame # in stack trace (-1 for empty) 195 * 196 * HPROF_GC_ROOT_NATIVE_STACK Native stack 197 * 198 * id object ID 199 * u4 thread serial number 200 * 201 * HPROF_GC_ROOT_STICKY_CLASS System class 202 * 203 * id object ID 204 * 205 * HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block 206 * 207 * id object ID 208 * u4 thread serial number 209 * 210 * HPROF_GC_ROOT_MONITOR_USED Busy monitor 211 * 212 * id object ID 213 * 214 * HPROF_GC_CLASS_DUMP dump of a class object 215 * 216 * id class object ID 217 * u4 stack trace serial number 218 * id super class object ID 219 * id class loader object ID 220 * id signers object ID 221 * id protection domain object ID 222 * id reserved 223 * id reserved 224 * 225 * u4 instance size (in bytes) 226 * 227 * u2 size of constant pool 228 * [u2, constant pool index, 229 * ty, type 230 * 2: object 231 * 4: boolean 232 * 5: char 233 * 6: float 234 * 7: double 235 * 8: byte 236 * 9: short 237 * 10: int 238 * 11: long 239 * vl]* and value 240 * 241 * u2 number of static fields 242 * [id, static field name, 243 * ty, type, 244 * vl]* and value 245 * 246 * u2 number of inst. fields (not inc. super) 247 * [id, instance field name, 248 * ty]* type 249 * 250 * HPROF_GC_INSTANCE_DUMP dump of a normal object 251 * 252 * id object ID 253 * u4 stack trace serial number 254 * id class object ID 255 * u4 number of bytes that follow 256 * [vl]* instance field values (class, followed 257 * by super, super's super ...) 258 * 259 * HPROF_GC_OBJ_ARRAY_DUMP dump of an object array 260 * 261 * id array object ID 262 * u4 stack trace serial number 263 * u4 number of elements 264 * id array class ID 265 * [id]* elements 266 * 267 * HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array 268 * 269 * id array object ID 270 * u4 stack trace serial number 271 * u4 number of elements 272 * u1 element type 273 * 4: boolean array 274 * 5: char array 275 * 6: float array 276 * 7: double array 277 * 8: byte array 278 * 9: short array 279 * 10: int array 280 * 11: long array 281 * [u1]* elements 282 * 283 * HPROF_CPU_SAMPLES a set of sample traces of running threads 284 * 285 * u4 total number of samples 286 * u4 # of traces 287 * [u4 # of samples 288 * u4]* stack trace serial number 289 * 290 * HPROF_CONTROL_SETTINGS the settings of on/off switches 291 * 292 * u4 0x00000001: alloc traces on/off 293 * 0x00000002: cpu sampling on/off 294 * u2 stack trace depth 295 * 296 * 297 * A heap dump can optionally be generated as a sequence of heap dump 298 * segments. This sequence is terminated by an end record. The additional 299 * tags allowed by format "JAVA PROFILE 1.0.2" are: 300 * 301 * HPROF_HEAP_DUMP_SEGMENT denote a heap dump segment 302 * 303 * [heap dump sub-records]* 304 * The same sub-record types allowed by HPROF_HEAP_DUMP 305 * 306 * HPROF_HEAP_DUMP_END denotes the end of a heap dump 307 * 308 */ 309 310 public class HeapHprofBinWriter extends AbstractHeapGraphWriter { 311 312 // Record which Symbol names have been dumped already. 313 private HashSet<Symbol> names; 314 315 private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000; 316 317 // The approximate size of a heap segment. Used to calculate when to create 318 // a new segment. 319 private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000; 320 321 // hprof binary file header 322 private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2"; 323 324 // constants in enum HprofTag 325 private static final int HPROF_UTF8 = 0x01; 326 private static final int HPROF_LOAD_CLASS = 0x02; 327 private static final int HPROF_UNLOAD_CLASS = 0x03; 328 private static final int HPROF_FRAME = 0x04; 329 private static final int HPROF_TRACE = 0x05; 330 private static final int HPROF_ALLOC_SITES = 0x06; 331 private static final int HPROF_HEAP_SUMMARY = 0x07; 332 private static final int HPROF_START_THREAD = 0x0A; 333 private static final int HPROF_END_THREAD = 0x0B; 334 private static final int HPROF_HEAP_DUMP = 0x0C; 335 private static final int HPROF_CPU_SAMPLES = 0x0D; 336 private static final int HPROF_CONTROL_SETTINGS = 0x0E; 337 338 // 1.0.2 record types 339 private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C; 340 private static final int HPROF_HEAP_DUMP_END = 0x2C; 341 342 // Heap dump constants 343 // constants in enum HprofGcTag 344 private static final int HPROF_GC_ROOT_UNKNOWN = 0xFF; 345 private static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01; 346 private static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02; 347 private static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03; 348 private static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04; 349 private static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05; 350 private static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06; 351 private static final int HPROF_GC_ROOT_MONITOR_USED = 0x07; 352 private static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08; 353 private static final int HPROF_GC_CLASS_DUMP = 0x20; 354 private static final int HPROF_GC_INSTANCE_DUMP = 0x21; 355 private static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22; 356 private static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23; 357 358 // constants in enum HprofType 359 private static final int HPROF_ARRAY_OBJECT = 1; 360 private static final int HPROF_NORMAL_OBJECT = 2; 361 private static final int HPROF_BOOLEAN = 4; 362 private static final int HPROF_CHAR = 5; 363 private static final int HPROF_FLOAT = 6; 364 private static final int HPROF_DOUBLE = 7; 365 private static final int HPROF_BYTE = 8; 366 private static final int HPROF_SHORT = 9; 367 private static final int HPROF_INT = 10; 368 private static final int HPROF_LONG = 11; 369 370 // Java type codes 371 private static final int JVM_SIGNATURE_BOOLEAN = 'Z'; 372 private static final int JVM_SIGNATURE_CHAR = 'C'; 373 private static final int JVM_SIGNATURE_BYTE = 'B'; 374 private static final int JVM_SIGNATURE_SHORT = 'S'; 375 private static final int JVM_SIGNATURE_INT = 'I'; 376 private static final int JVM_SIGNATURE_LONG = 'J'; 377 private static final int JVM_SIGNATURE_FLOAT = 'F'; 378 private static final int JVM_SIGNATURE_DOUBLE = 'D'; 379 private static final int JVM_SIGNATURE_ARRAY = '['; 380 private static final int JVM_SIGNATURE_CLASS = 'L'; 381 382 private static final long MAX_U4_VALUE = 0xFFFFFFFFL; 383 int serialNum = 1; 384 HeapHprofBinWriter()385 public HeapHprofBinWriter() { 386 this.KlassMap = new ArrayList<Klass>(); 387 this.names = new HashSet<Symbol>(); 388 } 389 write(String fileName)390 public synchronized void write(String fileName) throws IOException { 391 // open file stream and create buffered data output stream 392 fos = new FileOutputStream(fileName); 393 out = new DataOutputStream(new BufferedOutputStream(fos)); 394 395 VM vm = VM.getVM(); 396 dbg = vm.getDebugger(); 397 objectHeap = vm.getObjectHeap(); 398 399 OBJ_ID_SIZE = (int) vm.getOopSize(); 400 401 BOOLEAN_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BOOLEAN); 402 BYTE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_BYTE); 403 CHAR_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_CHAR); 404 SHORT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_SHORT); 405 INT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_INT); 406 LONG_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_LONG); 407 FLOAT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_FLOAT); 408 DOUBLE_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_DOUBLE); 409 OBJECT_BASE_OFFSET = TypeArray.baseOffsetInBytes(BasicType.T_OBJECT); 410 411 BOOLEAN_SIZE = objectHeap.getBooleanSize(); 412 BYTE_SIZE = objectHeap.getByteSize(); 413 CHAR_SIZE = objectHeap.getCharSize(); 414 SHORT_SIZE = objectHeap.getShortSize(); 415 INT_SIZE = objectHeap.getIntSize(); 416 LONG_SIZE = objectHeap.getLongSize(); 417 FLOAT_SIZE = objectHeap.getFloatSize(); 418 DOUBLE_SIZE = objectHeap.getDoubleSize(); 419 420 // Check weather we should dump the heap as segments 421 useSegmentedHeapDump = vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD; 422 423 // hprof bin format header 424 writeFileHeader(); 425 426 // dummy stack trace without any frames so that 427 // HAT can be run without -stack false option 428 writeDummyTrace(); 429 430 // hprof UTF-8 symbols section 431 writeSymbols(); 432 433 // HPROF_LOAD_CLASS records for all classes 434 writeClasses(); 435 436 // write HPROF_FRAME and HPROF_TRACE records 437 dumpStackTraces(); 438 439 // write CLASS_DUMP records 440 writeClassDumpRecords(); 441 442 // this will write heap data into the buffer stream 443 super.write(); 444 445 // flush buffer stream. 446 out.flush(); 447 448 // Fill in final length 449 fillInHeapRecordLength(); 450 451 if (useSegmentedHeapDump) { 452 // Write heap segment-end record 453 out.writeByte((byte) HPROF_HEAP_DUMP_END); 454 out.writeInt(0); 455 out.writeInt(0); 456 } 457 458 // flush buffer stream and throw it. 459 out.flush(); 460 out = null; 461 462 // close the file stream 463 fos.close(); 464 } 465 466 @Override writeHeapRecordPrologue()467 protected void writeHeapRecordPrologue() throws IOException { 468 if (currentSegmentStart == 0) { 469 // write heap data header, depending on heap size use segmented heap 470 // format 471 out.writeByte((byte) (useSegmentedHeapDump ? HPROF_HEAP_DUMP_SEGMENT 472 : HPROF_HEAP_DUMP)); 473 out.writeInt(0); 474 475 // remember position of dump length, we will fixup 476 // length later - hprof format requires length. 477 out.flush(); 478 currentSegmentStart = fos.getChannel().position(); 479 // write dummy length of 0 and we'll fix it later. 480 out.writeInt(0); 481 } 482 } 483 484 @Override writeHeapRecordEpilogue()485 protected void writeHeapRecordEpilogue() throws IOException { 486 if (useSegmentedHeapDump) { 487 out.flush(); 488 if ((fos.getChannel().position() - currentSegmentStart - 4L) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) { 489 fillInHeapRecordLength(); 490 currentSegmentStart = 0; 491 } 492 } 493 } 494 fillInHeapRecordLength()495 private void fillInHeapRecordLength() throws IOException { 496 497 // now get the current position to calculate length 498 long dumpEnd = fos.getChannel().position(); 499 500 // calculate the length of heap data 501 long dumpLenLong = (dumpEnd - currentSegmentStart - 4L); 502 503 // Check length boundary, overflow could happen but is _very_ unlikely 504 if (dumpLenLong >= (4L * 0x40000000)) { 505 throw new RuntimeException("Heap segment size overflow."); 506 } 507 508 // Save the current position 509 long currentPosition = fos.getChannel().position(); 510 511 // seek the position to write length 512 fos.getChannel().position(currentSegmentStart); 513 514 int dumpLen = (int) dumpLenLong; 515 516 // write length as integer 517 fos.write((dumpLen >>> 24) & 0xFF); 518 fos.write((dumpLen >>> 16) & 0xFF); 519 fos.write((dumpLen >>> 8) & 0xFF); 520 fos.write((dumpLen >>> 0) & 0xFF); 521 522 //Reset to previous current position 523 fos.getChannel().position(currentPosition); 524 } 525 526 // get the size in bytes for the requested type getSizeForType(int type)527 private long getSizeForType(int type) throws IOException { 528 switch (type) { 529 case TypeArrayKlass.T_BOOLEAN: 530 return BOOLEAN_SIZE; 531 case TypeArrayKlass.T_INT: 532 return INT_SIZE; 533 case TypeArrayKlass.T_CHAR: 534 return CHAR_SIZE; 535 case TypeArrayKlass.T_SHORT: 536 return SHORT_SIZE; 537 case TypeArrayKlass.T_BYTE: 538 return BYTE_SIZE; 539 case TypeArrayKlass.T_LONG: 540 return LONG_SIZE; 541 case TypeArrayKlass.T_FLOAT: 542 return FLOAT_SIZE; 543 case TypeArrayKlass.T_DOUBLE: 544 return DOUBLE_SIZE; 545 default: 546 throw new RuntimeException( 547 "Should not reach here: Unknown type: " + type); 548 } 549 } 550 getArrayHeaderSize(boolean isObjectAarray)551 private int getArrayHeaderSize(boolean isObjectAarray) { 552 return isObjectAarray? 553 ((int) BYTE_SIZE + 2 * (int) INT_SIZE + 2 * (int) OBJ_ID_SIZE): 554 (2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE); 555 } 556 557 // Check if we need to truncate an array calculateArrayMaxLength(long originalArrayLength, int headerSize, long typeSize, String typeName)558 private int calculateArrayMaxLength(long originalArrayLength, 559 int headerSize, 560 long typeSize, 561 String typeName) throws IOException { 562 563 long length = originalArrayLength; 564 565 // now get the current position to calculate length 566 long dumpEnd = fos.getChannel().position(); 567 long originalLengthInBytes = originalArrayLength * typeSize; 568 569 // calculate the length of heap data 570 long currentRecordLength = (dumpEnd - currentSegmentStart - 4L); 571 if (currentRecordLength > 0 && 572 (currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) { 573 fillInHeapRecordLength(); 574 currentSegmentStart = 0; 575 writeHeapRecordPrologue(); 576 currentRecordLength = 0; 577 } 578 579 // Calculate the max bytes we can use. 580 long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength)); 581 582 if (originalLengthInBytes > maxBytes) { 583 length = maxBytes/typeSize; 584 System.err.println("WARNING: Cannot dump array of type " + typeName 585 + " with length " + originalArrayLength 586 + "; truncating to length " + length); 587 } 588 return (int) length; 589 } 590 writeClassDumpRecords()591 private void writeClassDumpRecords() throws IOException { 592 ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph(); 593 try { 594 cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 595 public void visit(Klass k) { 596 try { 597 writeHeapRecordPrologue(); 598 writeClassDumpRecord(k); 599 writeHeapRecordEpilogue(); 600 } catch (IOException e) { 601 throw new RuntimeException(e); 602 } 603 } 604 }); 605 } catch (RuntimeException re) { 606 handleRuntimeException(re); 607 } 608 } 609 writeClass(Instance instance)610 protected void writeClass(Instance instance) throws IOException { 611 Klass reflectedKlass = java_lang_Class.asKlass(instance); 612 // dump instance record only for primitive type Class objects. 613 // all other Class objects are covered by writeClassDumpRecords. 614 if (reflectedKlass == null) { 615 writeInstance(instance); 616 } 617 } 618 writeClassDumpRecord(Klass k)619 private void writeClassDumpRecord(Klass k) throws IOException { 620 out.writeByte((byte)HPROF_GC_CLASS_DUMP); 621 writeObjectID(k.getJavaMirror()); 622 out.writeInt(DUMMY_STACK_TRACE_ID); 623 Klass superKlass = k.getJavaSuper(); 624 if (superKlass != null) { 625 writeObjectID(superKlass.getJavaMirror()); 626 } else { 627 writeObjectID(null); 628 } 629 630 if (k instanceof InstanceKlass) { 631 InstanceKlass ik = (InstanceKlass) k; 632 writeObjectID(ik.getClassLoader()); 633 writeObjectID(null); // ik.getJavaMirror().getSigners()); 634 writeObjectID(null); // ik.getJavaMirror().getProtectionDomain()); 635 // two reserved id fields 636 writeObjectID(null); 637 writeObjectID(null); 638 List fields = getInstanceFields(ik); 639 int instSize = getSizeForFields(fields); 640 classDataCache.put(ik, new ClassData(instSize, fields)); 641 out.writeInt(instSize); 642 643 // For now, ignore constant pool - HAT ignores too! 644 // output number of cp entries as zero. 645 out.writeShort((short) 0); 646 647 List declaredFields = ik.getImmediateFields(); 648 List staticFields = new ArrayList(); 649 List instanceFields = new ArrayList(); 650 Iterator itr = null; 651 for (itr = declaredFields.iterator(); itr.hasNext();) { 652 Field field = (Field) itr.next(); 653 if (field.isStatic()) { 654 staticFields.add(field); 655 } else { 656 instanceFields.add(field); 657 } 658 } 659 660 // dump static field descriptors 661 writeFieldDescriptors(staticFields, ik); 662 663 // dump instance field descriptors 664 writeFieldDescriptors(instanceFields, null); 665 } else { 666 if (k instanceof ObjArrayKlass) { 667 ObjArrayKlass oak = (ObjArrayKlass) k; 668 Klass bottomKlass = oak.getBottomKlass(); 669 if (bottomKlass instanceof InstanceKlass) { 670 InstanceKlass ik = (InstanceKlass) bottomKlass; 671 writeObjectID(ik.getClassLoader()); 672 writeObjectID(null); // ik.getJavaMirror().getSigners()); 673 writeObjectID(null); // ik.getJavaMirror().getProtectionDomain()); 674 } else { 675 writeObjectID(null); 676 writeObjectID(null); 677 writeObjectID(null); 678 } 679 } else { 680 writeObjectID(null); 681 writeObjectID(null); 682 writeObjectID(null); 683 } 684 // two reserved id fields 685 writeObjectID(null); 686 writeObjectID(null); 687 // write zero instance size -- as instance size 688 // is variable for arrays. 689 out.writeInt(0); 690 // no constant pool for array klasses 691 out.writeShort((short) 0); 692 // no static fields for array klasses 693 out.writeShort((short) 0); 694 // no instance fields for array klasses 695 out.writeShort((short) 0); 696 } 697 } 698 dumpStackTraces()699 private void dumpStackTraces() throws IOException { 700 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites 701 writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE ); 702 out.writeInt(DUMMY_STACK_TRACE_ID); 703 out.writeInt(0); // thread number 704 out.writeInt(0); // frame count 705 706 int frameSerialNum = 0; 707 int numThreads = 0; 708 Threads threads = VM.getVM().getThreads(); 709 710 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { 711 Oop threadObj = thread.getThreadObj(); 712 if (threadObj != null && !thread.isExiting() && !thread.isHiddenFromExternalView()) { 713 714 // dump thread stack trace 715 ThreadStackTrace st = new ThreadStackTrace(thread); 716 st.dumpStack(-1); 717 numThreads++; 718 719 // write HPROF_FRAME records for this thread's stack trace 720 int depth = st.getStackDepth(); 721 int threadFrameStart = frameSerialNum; 722 for (int j=0; j < depth; j++) { 723 StackFrameInfo frame = st.stackFrameAt(j); 724 Method m = frame.getMethod(); 725 int classSerialNum = KlassMap.indexOf(m.getMethodHolder()) + 1; 726 // the class serial number starts from 1 727 assert classSerialNum > 0:"class not found"; 728 dumpStackFrame(++frameSerialNum, classSerialNum, m, frame.getBCI()); 729 } 730 731 // write HPROF_TRACE record for one thread 732 writeHeader(HPROF_TRACE, 3 * (int)INT_SIZE + depth * (int)VM.getVM().getOopSize()); 733 int stackSerialNum = numThreads + DUMMY_STACK_TRACE_ID; 734 out.writeInt(stackSerialNum); // stack trace serial number 735 out.writeInt(numThreads); // thread serial number 736 out.writeInt(depth); // frame count 737 for (int j=1; j <= depth; j++) { 738 writeObjectID(threadFrameStart + j); 739 } 740 } 741 } 742 } 743 dumpStackFrame(int frameSN, int classSN, Method m, int bci)744 private void dumpStackFrame(int frameSN, int classSN, Method m, int bci) throws IOException { 745 int lineNumber; 746 if (m.isNative()) { 747 lineNumber = -3; // native frame 748 } else { 749 lineNumber = m.getLineNumberFromBCI(bci); 750 } 751 // First dump UTF8 if needed 752 writeSymbol(m.getName()); // method's name 753 writeSymbol(m.getSignature()); // method's signature 754 writeSymbol(m.getMethodHolder().getSourceFileName()); // source file name 755 // Then write FRAME descriptor 756 writeHeader(HPROF_FRAME, 4 * (int)VM.getVM().getOopSize() + 2 * (int)INT_SIZE); 757 writeObjectID(frameSN); // frame serial number 758 writeSymbolID(m.getName()); // method's name 759 writeSymbolID(m.getSignature()); // method's signature 760 writeSymbolID(m.getMethodHolder().getSourceFileName()); // source file name 761 out.writeInt(classSN); // class serial number 762 out.writeInt(lineNumber); // line number 763 } 764 writeJavaThread(JavaThread jt, int index)765 protected void writeJavaThread(JavaThread jt, int index) throws IOException { 766 out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ); 767 writeObjectID(jt.getThreadObj()); 768 out.writeInt(index); 769 out.writeInt(DUMMY_STACK_TRACE_ID); 770 writeLocalJNIHandles(jt, index); 771 } 772 writeLocalJNIHandles(JavaThread jt, int index)773 protected void writeLocalJNIHandles(JavaThread jt, int index) throws IOException { 774 final int threadIndex = index; 775 JNIHandleBlock blk = jt.activeHandles(); 776 if (blk != null) { 777 try { 778 blk.oopsDo(new AddressVisitor() { 779 public void visitAddress(Address handleAddr) { 780 try { 781 if (handleAddr != null) { 782 OopHandle oopHandle = handleAddr.getOopHandleAt(0); 783 Oop oop = objectHeap.newOop(oopHandle); 784 // exclude JNI handles hotspot internal objects 785 if (oop != null && isJavaVisible(oop)) { 786 out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL); 787 writeObjectID(oop); 788 out.writeInt(threadIndex); 789 out.writeInt(EMPTY_FRAME_DEPTH); 790 } 791 } 792 } catch (IOException exp) { 793 throw new RuntimeException(exp); 794 } 795 } 796 public void visitCompOopAddress(Address handleAddr) { 797 throw new RuntimeException( 798 " Should not reach here. JNIHandles are not compressed \n"); 799 } 800 }); 801 } catch (RuntimeException re) { 802 handleRuntimeException(re); 803 } 804 } 805 } 806 writeGlobalJNIHandle(Address handleAddr)807 protected void writeGlobalJNIHandle(Address handleAddr) throws IOException { 808 OopHandle oopHandle = handleAddr.getOopHandleAt(0); 809 Oop oop = objectHeap.newOop(oopHandle); 810 // exclude JNI handles of hotspot internal objects 811 if (oop != null && isJavaVisible(oop)) { 812 out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL); 813 writeObjectID(oop); 814 // use JNIHandle address as ID 815 writeObjectID(getAddressValue(handleAddr)); 816 } 817 } 818 writeObjectArray(ObjArray array)819 protected void writeObjectArray(ObjArray array) throws IOException { 820 int headerSize = getArrayHeaderSize(true); 821 final int length = calculateArrayMaxLength(array.getLength(), 822 headerSize, 823 OBJ_ID_SIZE, 824 "Object"); 825 out.writeByte((byte) HPROF_GC_OBJ_ARRAY_DUMP); 826 writeObjectID(array); 827 out.writeInt(DUMMY_STACK_TRACE_ID); 828 out.writeInt(length); 829 writeObjectID(array.getKlass().getJavaMirror()); 830 for (int index = 0; index < length; index++) { 831 OopHandle handle = array.getOopHandleAt(index); 832 writeObjectID(getAddressValue(handle)); 833 } 834 } 835 writePrimitiveArray(TypeArray array)836 protected void writePrimitiveArray(TypeArray array) throws IOException { 837 int headerSize = getArrayHeaderSize(false); 838 TypeArrayKlass tak = (TypeArrayKlass) array.getKlass(); 839 final int type = (int) tak.getElementType(); 840 final String typeName = tak.getElementTypeName(); 841 final long typeSize = getSizeForType(type); 842 final int length = calculateArrayMaxLength(array.getLength(), 843 headerSize, 844 typeSize, 845 typeName); 846 out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP); 847 writeObjectID(array); 848 out.writeInt(DUMMY_STACK_TRACE_ID); 849 out.writeInt(length); 850 out.writeByte((byte) type); 851 switch (type) { 852 case TypeArrayKlass.T_BOOLEAN: 853 writeBooleanArray(array, length); 854 break; 855 case TypeArrayKlass.T_CHAR: 856 writeCharArray(array, length); 857 break; 858 case TypeArrayKlass.T_FLOAT: 859 writeFloatArray(array, length); 860 break; 861 case TypeArrayKlass.T_DOUBLE: 862 writeDoubleArray(array, length); 863 break; 864 case TypeArrayKlass.T_BYTE: 865 writeByteArray(array, length); 866 break; 867 case TypeArrayKlass.T_SHORT: 868 writeShortArray(array, length); 869 break; 870 case TypeArrayKlass.T_INT: 871 writeIntArray(array, length); 872 break; 873 case TypeArrayKlass.T_LONG: 874 writeLongArray(array, length); 875 break; 876 default: 877 throw new RuntimeException( 878 "Should not reach here: Unknown type: " + type); 879 } 880 } 881 writeBooleanArray(TypeArray array, int length)882 private void writeBooleanArray(TypeArray array, int length) throws IOException { 883 for (int index = 0; index < length; index++) { 884 long offset = BOOLEAN_BASE_OFFSET + index * BOOLEAN_SIZE; 885 out.writeBoolean(array.getHandle().getJBooleanAt(offset)); 886 } 887 } 888 writeByteArray(TypeArray array, int length)889 private void writeByteArray(TypeArray array, int length) throws IOException { 890 for (int index = 0; index < length; index++) { 891 long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE; 892 out.writeByte(array.getHandle().getJByteAt(offset)); 893 } 894 } 895 writeShortArray(TypeArray array, int length)896 private void writeShortArray(TypeArray array, int length) throws IOException { 897 for (int index = 0; index < length; index++) { 898 long offset = SHORT_BASE_OFFSET + index * SHORT_SIZE; 899 out.writeShort(array.getHandle().getJShortAt(offset)); 900 } 901 } 902 writeIntArray(TypeArray array, int length)903 private void writeIntArray(TypeArray array, int length) throws IOException { 904 for (int index = 0; index < length; index++) { 905 long offset = INT_BASE_OFFSET + index * INT_SIZE; 906 out.writeInt(array.getHandle().getJIntAt(offset)); 907 } 908 } 909 writeLongArray(TypeArray array, int length)910 private void writeLongArray(TypeArray array, int length) throws IOException { 911 for (int index = 0; index < length; index++) { 912 long offset = LONG_BASE_OFFSET + index * LONG_SIZE; 913 out.writeLong(array.getHandle().getJLongAt(offset)); 914 } 915 } 916 writeCharArray(TypeArray array, int length)917 private void writeCharArray(TypeArray array, int length) throws IOException { 918 for (int index = 0; index < length; index++) { 919 long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE; 920 out.writeChar(array.getHandle().getJCharAt(offset)); 921 } 922 } 923 writeFloatArray(TypeArray array, int length)924 private void writeFloatArray(TypeArray array, int length) throws IOException { 925 for (int index = 0; index < length; index++) { 926 long offset = FLOAT_BASE_OFFSET + index * FLOAT_SIZE; 927 out.writeFloat(array.getHandle().getJFloatAt(offset)); 928 } 929 } 930 writeDoubleArray(TypeArray array, int length)931 private void writeDoubleArray(TypeArray array, int length) throws IOException { 932 for (int index = 0; index < length; index++) { 933 long offset = DOUBLE_BASE_OFFSET + index * DOUBLE_SIZE; 934 out.writeDouble(array.getHandle().getJDoubleAt(offset)); 935 } 936 } 937 writeInstance(Instance instance)938 protected void writeInstance(Instance instance) throws IOException { 939 out.writeByte((byte) HPROF_GC_INSTANCE_DUMP); 940 writeObjectID(instance); 941 out.writeInt(DUMMY_STACK_TRACE_ID); 942 Klass klass = instance.getKlass(); 943 writeObjectID(klass.getJavaMirror()); 944 945 ClassData cd = (ClassData) classDataCache.get(klass); 946 947 if (Assert.ASSERTS_ENABLED) { 948 Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress()); 949 } 950 List fields = cd.fields; 951 int size = cd.instSize; 952 out.writeInt(size); 953 for (Iterator itr = fields.iterator(); itr.hasNext();) { 954 writeField((Field) itr.next(), instance); 955 } 956 } 957 958 //-- Internals only below this point 959 writeFieldDescriptors(List fields, InstanceKlass ik)960 private void writeFieldDescriptors(List fields, InstanceKlass ik) 961 throws IOException { 962 // ik == null for instance fields. 963 out.writeShort((short) fields.size()); 964 for (Iterator itr = fields.iterator(); itr.hasNext();) { 965 Field field = (Field) itr.next(); 966 Symbol name = field.getName(); 967 writeSymbolID(name); 968 char typeCode = (char) field.getSignature().getByteAt(0); 969 int kind = signatureToHprofKind(typeCode); 970 out.writeByte((byte)kind); 971 if (ik != null) { 972 // static field 973 writeField(field, ik.getJavaMirror()); 974 } 975 } 976 } 977 signatureToHprofKind(char ch)978 public static int signatureToHprofKind(char ch) { 979 switch (ch) { 980 case JVM_SIGNATURE_CLASS: 981 case JVM_SIGNATURE_ARRAY: 982 return HPROF_NORMAL_OBJECT; 983 case JVM_SIGNATURE_BOOLEAN: 984 return HPROF_BOOLEAN; 985 case JVM_SIGNATURE_CHAR: 986 return HPROF_CHAR; 987 case JVM_SIGNATURE_FLOAT: 988 return HPROF_FLOAT; 989 case JVM_SIGNATURE_DOUBLE: 990 return HPROF_DOUBLE; 991 case JVM_SIGNATURE_BYTE: 992 return HPROF_BYTE; 993 case JVM_SIGNATURE_SHORT: 994 return HPROF_SHORT; 995 case JVM_SIGNATURE_INT: 996 return HPROF_INT; 997 case JVM_SIGNATURE_LONG: 998 return HPROF_LONG; 999 default: 1000 throw new RuntimeException("should not reach here"); 1001 } 1002 } 1003 writeField(Field field, Oop oop)1004 private void writeField(Field field, Oop oop) throws IOException { 1005 char typeCode = (char) field.getSignature().getByteAt(0); 1006 switch (typeCode) { 1007 case JVM_SIGNATURE_BOOLEAN: 1008 out.writeBoolean(((BooleanField)field).getValue(oop)); 1009 break; 1010 case JVM_SIGNATURE_CHAR: 1011 out.writeChar(((CharField)field).getValue(oop)); 1012 break; 1013 case JVM_SIGNATURE_BYTE: 1014 out.writeByte(((ByteField)field).getValue(oop)); 1015 break; 1016 case JVM_SIGNATURE_SHORT: 1017 out.writeShort(((ShortField)field).getValue(oop)); 1018 break; 1019 case JVM_SIGNATURE_INT: 1020 out.writeInt(((IntField)field).getValue(oop)); 1021 break; 1022 case JVM_SIGNATURE_LONG: 1023 out.writeLong(((LongField)field).getValue(oop)); 1024 break; 1025 case JVM_SIGNATURE_FLOAT: 1026 out.writeFloat(((FloatField)field).getValue(oop)); 1027 break; 1028 case JVM_SIGNATURE_DOUBLE: 1029 out.writeDouble(((DoubleField)field).getValue(oop)); 1030 break; 1031 case JVM_SIGNATURE_CLASS: 1032 case JVM_SIGNATURE_ARRAY: { 1033 if (VM.getVM().isCompressedOopsEnabled()) { 1034 OopHandle handle = ((NarrowOopField)field).getValueAsOopHandle(oop); 1035 writeObjectID(getAddressValue(handle)); 1036 } else { 1037 OopHandle handle = ((OopField)field).getValueAsOopHandle(oop); 1038 writeObjectID(getAddressValue(handle)); 1039 } 1040 break; 1041 } 1042 default: 1043 throw new RuntimeException("should not reach here"); 1044 } 1045 } 1046 writeHeader(int tag, int len)1047 private void writeHeader(int tag, int len) throws IOException { 1048 out.writeByte((byte)tag); 1049 out.writeInt(0); // current ticks 1050 out.writeInt(len); 1051 } 1052 writeDummyTrace()1053 private void writeDummyTrace() throws IOException { 1054 writeHeader(HPROF_TRACE, 3 * 4); 1055 out.writeInt(DUMMY_STACK_TRACE_ID); 1056 out.writeInt(0); 1057 out.writeInt(0); 1058 } 1059 writeClassSymbols(Klass k)1060 private void writeClassSymbols(Klass k) throws IOException { 1061 writeSymbol(k.getName()); 1062 if (k instanceof InstanceKlass) { 1063 InstanceKlass ik = (InstanceKlass) k; 1064 List declaredFields = ik.getImmediateFields(); 1065 for (Iterator itr = declaredFields.iterator(); itr.hasNext();) { 1066 Field field = (Field) itr.next(); 1067 writeSymbol(field.getName()); 1068 } 1069 } 1070 } 1071 writeSymbols()1072 private void writeSymbols() throws IOException { 1073 // Write all the symbols that are used by the classes 1074 ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph(); 1075 try { 1076 cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 1077 public void visit(Klass k) { 1078 try { 1079 writeClassSymbols(k); 1080 } catch (IOException e) { 1081 throw new RuntimeException(e); 1082 } 1083 } 1084 }); 1085 } catch (RuntimeException re) { 1086 handleRuntimeException(re); 1087 } 1088 } 1089 writeSymbol(Symbol sym)1090 private void writeSymbol(Symbol sym) throws IOException { 1091 if(sym != null) { 1092 // If name is already written don't write it again. 1093 if (names.add(sym)) { 1094 byte[] buf = sym.asString().getBytes("UTF-8"); 1095 writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE); 1096 writeSymbolID(sym); 1097 out.write(buf); 1098 } 1099 } else { 1100 writeHeader(HPROF_UTF8, 0 + OBJ_ID_SIZE); 1101 writeSymbolID(null); 1102 } 1103 } 1104 writeClasses()1105 private void writeClasses() throws IOException { 1106 // write class list (id, name) association 1107 ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph(); 1108 try { 1109 cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { 1110 public void visit(Klass k) { 1111 try { 1112 Instance clazz = k.getJavaMirror(); 1113 writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4)); 1114 out.writeInt(serialNum); 1115 writeObjectID(clazz); 1116 KlassMap.add(serialNum - 1, k); 1117 out.writeInt(DUMMY_STACK_TRACE_ID); 1118 writeSymbolID(k.getName()); 1119 serialNum++; 1120 } catch (IOException exp) { 1121 throw new RuntimeException(exp); 1122 } 1123 } 1124 }); 1125 } catch (RuntimeException re) { 1126 handleRuntimeException(re); 1127 } 1128 } 1129 1130 // writes hprof binary file header writeFileHeader()1131 private void writeFileHeader() throws IOException { 1132 // version string 1133 out.writeBytes(HPROF_HEADER_1_0_2); 1134 out.writeByte((byte)'\0'); 1135 1136 // write identifier size. we use pointers as identifiers. 1137 out.writeInt(OBJ_ID_SIZE); 1138 1139 // timestamp -- file creation time. 1140 out.writeLong(System.currentTimeMillis()); 1141 } 1142 1143 // writes unique ID for an object writeObjectID(Oop oop)1144 private void writeObjectID(Oop oop) throws IOException { 1145 OopHandle handle = (oop != null)? oop.getHandle() : null; 1146 long address = getAddressValue(handle); 1147 writeObjectID(address); 1148 } 1149 writeSymbolID(Symbol sym)1150 private void writeSymbolID(Symbol sym) throws IOException { 1151 assert (sym == null || names.contains(sym)); 1152 long address = (sym != null) ? getAddressValue(sym.getAddress()) : getAddressValue(null); 1153 writeObjectID(address); 1154 } 1155 writeObjectID(long address)1156 private void writeObjectID(long address) throws IOException { 1157 if (OBJ_ID_SIZE == 4) { 1158 out.writeInt((int) address); 1159 } else { 1160 out.writeLong(address); 1161 } 1162 } 1163 getAddressValue(Address addr)1164 private long getAddressValue(Address addr) { 1165 return (addr == null)? 0L : dbg.getAddressValue(addr); 1166 } 1167 1168 // get all declared as well as inherited (directly/indirectly) fields getInstanceFields(InstanceKlass ik)1169 private static List/*<Field>*/ getInstanceFields(InstanceKlass ik) { 1170 InstanceKlass klass = ik; 1171 List res = new ArrayList(); 1172 while (klass != null) { 1173 List curFields = klass.getImmediateFields(); 1174 for (Iterator itr = curFields.iterator(); itr.hasNext();) { 1175 Field f = (Field) itr.next(); 1176 if (! f.isStatic()) { 1177 res.add(f); 1178 } 1179 } 1180 klass = (InstanceKlass) klass.getSuper(); 1181 } 1182 return res; 1183 } 1184 1185 // get size in bytes (in stream) required for given fields. Note 1186 // that this is not the same as object size in heap. The size in 1187 // heap will include size of padding/alignment bytes as well. getSizeForFields(List fields)1188 private int getSizeForFields(List fields) { 1189 int size = 0; 1190 for (Iterator itr = fields.iterator(); itr.hasNext();) { 1191 Field field = (Field) itr.next(); 1192 char typeCode = (char) field.getSignature().getByteAt(0); 1193 switch (typeCode) { 1194 case JVM_SIGNATURE_BOOLEAN: 1195 case JVM_SIGNATURE_BYTE: 1196 size++; 1197 break; 1198 case JVM_SIGNATURE_CHAR: 1199 case JVM_SIGNATURE_SHORT: 1200 size += 2; 1201 break; 1202 case JVM_SIGNATURE_INT: 1203 case JVM_SIGNATURE_FLOAT: 1204 size += 4; 1205 break; 1206 case JVM_SIGNATURE_CLASS: 1207 case JVM_SIGNATURE_ARRAY: 1208 size += OBJ_ID_SIZE; 1209 break; 1210 case JVM_SIGNATURE_LONG: 1211 case JVM_SIGNATURE_DOUBLE: 1212 size += 8; 1213 break; 1214 default: 1215 throw new RuntimeException("should not reach here"); 1216 } 1217 } 1218 return size; 1219 } 1220 1221 // We don't have allocation site info. We write a dummy 1222 // stack trace with this id. 1223 private static final int DUMMY_STACK_TRACE_ID = 1; 1224 private static final int EMPTY_FRAME_DEPTH = -1; 1225 1226 private DataOutputStream out; 1227 private FileOutputStream fos; 1228 private Debugger dbg; 1229 private ObjectHeap objectHeap; 1230 private ArrayList<Klass> KlassMap; 1231 1232 // oopSize of the debuggee 1233 private int OBJ_ID_SIZE; 1234 1235 // Added for hprof file format 1.0.2 support 1236 private boolean useSegmentedHeapDump; 1237 private long currentSegmentStart; 1238 1239 private long BOOLEAN_BASE_OFFSET; 1240 private long BYTE_BASE_OFFSET; 1241 private long CHAR_BASE_OFFSET; 1242 private long SHORT_BASE_OFFSET; 1243 private long INT_BASE_OFFSET; 1244 private long LONG_BASE_OFFSET; 1245 private long FLOAT_BASE_OFFSET; 1246 private long DOUBLE_BASE_OFFSET; 1247 private long OBJECT_BASE_OFFSET; 1248 1249 private long BOOLEAN_SIZE; 1250 private long BYTE_SIZE; 1251 private long CHAR_SIZE; 1252 private long SHORT_SIZE; 1253 private long INT_SIZE; 1254 private long LONG_SIZE; 1255 private long FLOAT_SIZE; 1256 private long DOUBLE_SIZE; 1257 1258 private static class ClassData { 1259 int instSize; 1260 List fields; 1261 ClassData(int instSize, List fields)1262 ClassData(int instSize, List fields) { 1263 this.instSize = instSize; 1264 this.fields = fields; 1265 } 1266 } 1267 1268 private Map classDataCache = new HashMap(); // <InstanceKlass, ClassData> 1269 } 1270