1 package shark.internal 2 3 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord.FieldRecord 4 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord.StaticFieldRecord 5 import shark.PrimitiveType 6 import shark.PrimitiveType.BOOLEAN 7 import shark.PrimitiveType.BYTE 8 import shark.PrimitiveType.CHAR 9 import shark.PrimitiveType.DOUBLE 10 import shark.PrimitiveType.FLOAT 11 import shark.PrimitiveType.INT 12 import shark.PrimitiveType.LONG 13 import shark.PrimitiveType.SHORT 14 import shark.ValueHolder 15 import shark.ValueHolder.BooleanHolder 16 import shark.ValueHolder.ByteHolder 17 import shark.ValueHolder.CharHolder 18 import shark.ValueHolder.DoubleHolder 19 import shark.ValueHolder.FloatHolder 20 import shark.ValueHolder.IntHolder 21 import shark.ValueHolder.LongHolder 22 import shark.ValueHolder.ReferenceHolder 23 import shark.ValueHolder.ShortHolder 24 import shark.internal.IndexedObject.IndexedClass 25 26 internal class ClassFieldsReader( 27 private val identifierByteSize: Int, 28 private val classFieldBytes: ByteArray 29 ) { 30 classDumpStaticFieldsnull31 fun classDumpStaticFields(indexedClass: IndexedClass): List<StaticFieldRecord> { 32 return read(initialPosition = indexedClass.fieldsIndex) { 33 val staticFieldCount = readUnsignedShort() 34 val staticFields = ArrayList<StaticFieldRecord>(staticFieldCount) 35 for (i in 0 until staticFieldCount) { 36 val nameStringId = readId() 37 val type = readUnsignedByte() 38 val value = readValue(type) 39 staticFields.add( 40 StaticFieldRecord( 41 nameStringId = nameStringId, 42 type = type, 43 value = value 44 ) 45 ) 46 } 47 staticFields 48 } 49 } 50 classDumpFieldsnull51 fun classDumpFields(indexedClass: IndexedClass): List<FieldRecord> { 52 return read(initialPosition = indexedClass.fieldsIndex) { 53 skipStaticFields() 54 55 val fieldCount = readUnsignedShort() 56 val fields = ArrayList<FieldRecord>(fieldCount) 57 for (i in 0 until fieldCount) { 58 fields.add(FieldRecord(nameStringId = readId(), type = readUnsignedByte())) 59 } 60 fields 61 } 62 } 63 classDumpHasReferenceFieldsnull64 fun classDumpHasReferenceFields(indexedClass: IndexedClass): Boolean { 65 return read(initialPosition = indexedClass.fieldsIndex) { 66 skipStaticFields() 67 val fieldCount = readUnsignedShort() 68 for (i in 0 until fieldCount) { 69 position += identifierByteSize 70 val type = readUnsignedByte() 71 if (type == PrimitiveType.REFERENCE_HPROF_TYPE) { 72 return@read true 73 } 74 } 75 return@read false 76 } 77 } 78 readnull79 private fun <R> read( 80 initialPosition: Int, 81 block: ReadInFlight.() -> R 82 ): R { 83 val readInFlight = ReadInFlight() 84 readInFlight.position = initialPosition 85 return readInFlight.run(block) 86 } 87 88 private inner class ReadInFlight { 89 var position = 0 90 skipStaticFieldsnull91 fun skipStaticFields() { 92 val staticFieldCount = readUnsignedShort() 93 for (i in 0 until staticFieldCount) { 94 position += identifierByteSize 95 val type = readUnsignedByte() 96 position += if (type == PrimitiveType.REFERENCE_HPROF_TYPE) { 97 identifierByteSize 98 } else { 99 PrimitiveType.byteSizeByHprofType.getValue(type) 100 } 101 } 102 } 103 readValuenull104 fun readValue(type: Int): ValueHolder { 105 return when (type) { 106 PrimitiveType.REFERENCE_HPROF_TYPE -> ReferenceHolder(readId()) 107 BOOLEAN_TYPE -> BooleanHolder(readBoolean()) 108 CHAR_TYPE -> CharHolder(readChar()) 109 FLOAT_TYPE -> FloatHolder(readFloat()) 110 DOUBLE_TYPE -> DoubleHolder(readDouble()) 111 BYTE_TYPE -> ByteHolder(readByte()) 112 SHORT_TYPE -> ShortHolder(readShort()) 113 INT_TYPE -> IntHolder(readInt()) 114 LONG_TYPE -> LongHolder(readLong()) 115 else -> throw IllegalStateException("Unknown type $type") 116 } 117 } 118 readBytenull119 fun readByte(): Byte { 120 return classFieldBytes[position++] 121 } 122 readIntnull123 fun readInt(): Int { 124 return (classFieldBytes[position++].toInt() and 0xff shl 24) or 125 (classFieldBytes[position++].toInt() and 0xff shl 16) or 126 (classFieldBytes[position++].toInt() and 0xff shl 8) or 127 (classFieldBytes[position++].toInt() and 0xff) 128 } 129 readLongnull130 fun readLong(): Long { 131 return (classFieldBytes[position++].toLong() and 0xff shl 56) or 132 (classFieldBytes[position++].toLong() and 0xff shl 48) or 133 (classFieldBytes[position++].toLong() and 0xff shl 40) or 134 (classFieldBytes[position++].toLong() and 0xff shl 32) or 135 (classFieldBytes[position++].toLong() and 0xff shl 24) or 136 (classFieldBytes[position++].toLong() and 0xff shl 16) or 137 (classFieldBytes[position++].toLong() and 0xff shl 8) or 138 (classFieldBytes[position++].toLong() and 0xff) 139 } 140 readShortnull141 fun readShort(): Short { 142 return ((classFieldBytes[position++].toInt() and 0xff shl 8) or 143 (classFieldBytes[position++].toInt() and 0xff)).toShort() 144 } 145 readUnsignedShortnull146 fun readUnsignedShort(): Int { 147 return readShort().toInt() and 0xFFFF 148 } 149 readUnsignedBytenull150 fun readUnsignedByte(): Int { 151 return readByte().toInt() and 0xFF 152 } 153 readIdnull154 fun readId(): Long { 155 // As long as we don't interpret IDs, reading signed values here is fine. 156 return when (identifierByteSize) { 157 1 -> readByte().toLong() 158 2 -> readShort().toLong() 159 4 -> readInt().toLong() 160 8 -> readLong() 161 else -> throw IllegalArgumentException("ID Length must be 1, 2, 4, or 8") 162 } 163 } 164 readBooleannull165 fun readBoolean(): Boolean { 166 return readByte() 167 .toInt() != 0 168 } 169 readCharnull170 fun readChar(): Char { 171 return readShort().toChar() 172 } 173 readFloatnull174 fun readFloat(): Float { 175 return Float.fromBits(readInt()) 176 } 177 readDoublenull178 fun readDouble(): Double { 179 return Double.fromBits(readLong()) 180 } 181 } 182 183 companion object { 184 private val BOOLEAN_TYPE = BOOLEAN.hprofType 185 private val CHAR_TYPE = CHAR.hprofType 186 private val FLOAT_TYPE = FLOAT.hprofType 187 private val DOUBLE_TYPE = DOUBLE.hprofType 188 private val BYTE_TYPE = BYTE.hprofType 189 private val SHORT_TYPE = SHORT.hprofType 190 private val INT_TYPE = INT.hprofType 191 private val LONG_TYPE = LONG.hprofType 192 } 193 } 194