1 package shark.internal 2 3 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord.FieldRecord 4 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.InstanceDumpRecord 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 25 internal class FieldValuesReader( 26 private val record: InstanceDumpRecord, 27 private val identifierByteSize: Int 28 ) { 29 30 private var position = 0 31 readValuenull32 fun readValue(field: FieldRecord): ValueHolder { 33 return when (field.type) { 34 PrimitiveType.REFERENCE_HPROF_TYPE -> ReferenceHolder(readId()) 35 BOOLEAN_TYPE -> BooleanHolder(readBoolean()) 36 CHAR_TYPE -> CharHolder(readChar()) 37 FLOAT_TYPE -> FloatHolder(readFloat()) 38 DOUBLE_TYPE -> DoubleHolder(readDouble()) 39 BYTE_TYPE -> ByteHolder(readByte()) 40 SHORT_TYPE -> ShortHolder(readShort()) 41 INT_TYPE -> IntHolder(readInt()) 42 LONG_TYPE -> LongHolder(readLong()) 43 else -> throw IllegalStateException("Unknown type ${field.type}") 44 } 45 } 46 readIdnull47 private fun readId(): Long { 48 // As long as we don't interpret IDs, reading signed values here is fine. 49 return when (identifierByteSize) { 50 1 -> readByte().toLong() 51 2 -> readShort().toLong() 52 4 -> readInt().toLong() 53 8 -> readLong() 54 else -> throw IllegalArgumentException("ID Length must be 1, 2, 4, or 8") 55 } 56 } 57 readBooleannull58 private fun readBoolean(): Boolean { 59 val value = record.fieldValues[position] 60 position++ 61 return value != 0.toByte() 62 } 63 readBytenull64 private fun readByte(): Byte { 65 val value = record.fieldValues[position] 66 position++ 67 return value 68 } 69 readIntnull70 private fun readInt(): Int { 71 val value = record.fieldValues.readInt(position) 72 position += 4 73 return value 74 } 75 readShortnull76 private fun readShort(): Short { 77 val value = record.fieldValues.readShort(position) 78 position += 2 79 return value 80 } 81 readLongnull82 private fun readLong(): Long { 83 val value = record.fieldValues.readLong(position) 84 position += 8 85 return value 86 } 87 readFloatnull88 private fun readFloat(): Float { 89 return Float.fromBits(readInt()) 90 } 91 readDoublenull92 private fun readDouble(): Double { 93 return Double.fromBits(readLong()) 94 } 95 readCharnull96 private fun readChar(): Char { 97 val string = String(record.fieldValues, position, 2, Charsets.UTF_16BE) 98 position += 2 99 return string[0] 100 } 101 102 companion object { 103 private val BOOLEAN_TYPE = BOOLEAN.hprofType 104 private val CHAR_TYPE = CHAR.hprofType 105 private val FLOAT_TYPE = FLOAT.hprofType 106 private val DOUBLE_TYPE = DOUBLE.hprofType 107 private val BYTE_TYPE = BYTE.hprofType 108 private val SHORT_TYPE = SHORT.hprofType 109 private val INT_TYPE = INT.hprofType 110 private val LONG_TYPE = LONG.hprofType 111 } 112 }