package shark.internal import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord.FieldRecord import shark.HprofRecord.HeapDumpRecord.ObjectRecord.InstanceDumpRecord import shark.PrimitiveType import shark.PrimitiveType.BOOLEAN import shark.PrimitiveType.BYTE import shark.PrimitiveType.CHAR import shark.PrimitiveType.DOUBLE import shark.PrimitiveType.FLOAT import shark.PrimitiveType.INT import shark.PrimitiveType.LONG import shark.PrimitiveType.SHORT import shark.ValueHolder import shark.ValueHolder.BooleanHolder import shark.ValueHolder.ByteHolder import shark.ValueHolder.CharHolder import shark.ValueHolder.DoubleHolder import shark.ValueHolder.FloatHolder import shark.ValueHolder.IntHolder import shark.ValueHolder.LongHolder import shark.ValueHolder.ReferenceHolder import shark.ValueHolder.ShortHolder internal class FieldValuesReader( private val record: InstanceDumpRecord, private val identifierByteSize: Int ) { private var position = 0 fun readValue(field: FieldRecord): ValueHolder { return when (field.type) { PrimitiveType.REFERENCE_HPROF_TYPE -> ReferenceHolder(readId()) BOOLEAN_TYPE -> BooleanHolder(readBoolean()) CHAR_TYPE -> CharHolder(readChar()) FLOAT_TYPE -> FloatHolder(readFloat()) DOUBLE_TYPE -> DoubleHolder(readDouble()) BYTE_TYPE -> ByteHolder(readByte()) SHORT_TYPE -> ShortHolder(readShort()) INT_TYPE -> IntHolder(readInt()) LONG_TYPE -> LongHolder(readLong()) else -> throw IllegalStateException("Unknown type ${field.type}") } } private fun readId(): Long { // As long as we don't interpret IDs, reading signed values here is fine. return when (identifierByteSize) { 1 -> readByte().toLong() 2 -> readShort().toLong() 4 -> readInt().toLong() 8 -> readLong() else -> throw IllegalArgumentException("ID Length must be 1, 2, 4, or 8") } } private fun readBoolean(): Boolean { val value = record.fieldValues[position] position++ return value != 0.toByte() } private fun readByte(): Byte { val value = record.fieldValues[position] position++ return value } private fun readInt(): Int { val value = record.fieldValues.readInt(position) position += 4 return value } private fun readShort(): Short { val value = record.fieldValues.readShort(position) position += 2 return value } private fun readLong(): Long { val value = record.fieldValues.readLong(position) position += 8 return value } private fun readFloat(): Float { return Float.fromBits(readInt()) } private fun readDouble(): Double { return Double.fromBits(readLong()) } private fun readChar(): Char { val string = String(record.fieldValues, position, 2, Charsets.UTF_16BE) position += 2 return string[0] } companion object { private val BOOLEAN_TYPE = BOOLEAN.hprofType private val CHAR_TYPE = CHAR.hprofType private val FLOAT_TYPE = FLOAT.hprofType private val DOUBLE_TYPE = DOUBLE.hprofType private val BYTE_TYPE = BYTE.hprofType private val SHORT_TYPE = SHORT.hprofType private val INT_TYPE = INT.hprofType private val LONG_TYPE = LONG.hprofType } }