xref: /aosp_15_r20/external/leakcanary2/shark-graph/src/main/java/shark/internal/FieldValuesReader.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)
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 }