<lambda>null1 package shark
2
3 import shark.HprofRecord.HeapDumpEndRecord
4 import shark.HprofRecord.HeapDumpRecord
5 import shark.HprofRecord.HeapDumpRecord.GcRootRecord
6 import shark.HprofRecord.HeapDumpRecord.HeapDumpInfoRecord
7 import shark.HprofRecord.HeapDumpRecord.ObjectRecord
8 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ClassDumpRecord
9 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.InstanceDumpRecord
10 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.ObjectArrayDumpRecord
11 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.PrimitiveArrayDumpRecord
12 import shark.HprofRecord.LoadClassRecord
13 import shark.HprofRecord.StackFrameRecord
14 import shark.HprofRecord.StackTraceRecord
15 import shark.HprofRecord.StringRecord
16 import shark.HprofRecordTag.CLASS_DUMP
17 import shark.HprofRecordTag.HEAP_DUMP_END
18 import shark.HprofRecordTag.HEAP_DUMP_INFO
19 import shark.HprofRecordTag.INSTANCE_DUMP
20 import shark.HprofRecordTag.LOAD_CLASS
21 import shark.HprofRecordTag.OBJECT_ARRAY_DUMP
22 import shark.HprofRecordTag.PRIMITIVE_ARRAY_DUMP
23 import shark.HprofRecordTag.ROOT_DEBUGGER
24 import shark.HprofRecordTag.ROOT_FINALIZING
25 import shark.HprofRecordTag.ROOT_INTERNED_STRING
26 import shark.HprofRecordTag.ROOT_JAVA_FRAME
27 import shark.HprofRecordTag.ROOT_JNI_GLOBAL
28 import shark.HprofRecordTag.ROOT_JNI_LOCAL
29 import shark.HprofRecordTag.ROOT_JNI_MONITOR
30 import shark.HprofRecordTag.ROOT_MONITOR_USED
31 import shark.HprofRecordTag.ROOT_NATIVE_STACK
32 import shark.HprofRecordTag.ROOT_REFERENCE_CLEANUP
33 import shark.HprofRecordTag.ROOT_STICKY_CLASS
34 import shark.HprofRecordTag.ROOT_THREAD_BLOCK
35 import shark.HprofRecordTag.ROOT_THREAD_OBJECT
36 import shark.HprofRecordTag.ROOT_UNKNOWN
37 import shark.HprofRecordTag.ROOT_UNREACHABLE
38 import shark.HprofRecordTag.ROOT_VM_INTERNAL
39 import shark.HprofRecordTag.STACK_FRAME
40 import shark.HprofRecordTag.STACK_TRACE
41 import shark.HprofRecordTag.STRING_IN_UTF8
42 import java.util.EnumSet
43 import kotlin.reflect.KClass
44
45 /**
46 * Wraps a [StreamingHprofReader] to provide a higher level API that streams [HprofRecord]
47 * instances.
48 */
49 class StreamingRecordReaderAdapter(private val streamingHprofReader: StreamingHprofReader) {
50
51 /**
52 * Obtains a new source to read all hprof records from and calls [listener] back for each record
53 * that matches one of the provided [recordTypes].
54 *
55 * @return the number of bytes read from the source
56 */
57 @Suppress("ComplexMethod", "LongMethod", "NestedBlockDepth")
58 fun readRecords(
59 recordTypes: Set<KClass<out HprofRecord>>,
60 listener: OnHprofRecordListener
61 ): Long {
62 val recordTags = recordTypes.asHprofTags()
63 return streamingHprofReader.readRecords(
64 recordTags
65 ) { tag, length, reader ->
66 when (tag) {
67 STRING_IN_UTF8 -> {
68 val recordPosition = reader.bytesRead
69 val record = reader.readStringRecord(length)
70 listener.onHprofRecord(recordPosition, record)
71 }
72 LOAD_CLASS -> {
73 val recordPosition = reader.bytesRead
74 val record = reader.readLoadClassRecord()
75 listener.onHprofRecord(recordPosition, record)
76 }
77 STACK_FRAME -> {
78 val recordPosition = reader.bytesRead
79 val record = reader.readStackFrameRecord()
80 listener.onHprofRecord(recordPosition, record)
81 }
82 STACK_TRACE -> {
83 val recordPosition = reader.bytesRead
84 val record = reader.readStackTraceRecord()
85 listener.onHprofRecord(recordPosition, record)
86 }
87 ROOT_UNKNOWN -> {
88 val recordPosition = reader.bytesRead
89 val record = reader.readUnknownGcRootRecord()
90 listener.onHprofRecord(recordPosition, GcRootRecord(record))
91 }
92 ROOT_JNI_GLOBAL -> {
93 val recordPosition = reader.bytesRead
94 val gcRootRecord = reader.readJniGlobalGcRootRecord()
95 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
96 }
97 ROOT_JNI_LOCAL -> {
98 val recordPosition = reader.bytesRead
99 val gcRootRecord = reader.readJniLocalGcRootRecord()
100 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
101 }
102
103 ROOT_JAVA_FRAME -> {
104 val recordPosition = reader.bytesRead
105 val gcRootRecord = reader.readJavaFrameGcRootRecord()
106 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
107 }
108
109 ROOT_NATIVE_STACK -> {
110 val recordPosition = reader.bytesRead
111 val gcRootRecord = reader.readNativeStackGcRootRecord()
112 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
113 }
114
115 ROOT_STICKY_CLASS -> {
116 val recordPosition = reader.bytesRead
117 val gcRootRecord = reader.readStickyClassGcRootRecord()
118 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
119 }
120
121 ROOT_THREAD_BLOCK -> {
122 val recordPosition = reader.bytesRead
123 val gcRootRecord = reader.readThreadBlockGcRootRecord()
124 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
125 }
126
127 ROOT_MONITOR_USED -> {
128 val recordPosition = reader.bytesRead
129 val gcRootRecord = reader.readMonitorUsedGcRootRecord()
130 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
131 }
132
133 ROOT_THREAD_OBJECT -> {
134 val recordPosition = reader.bytesRead
135 val gcRootRecord = reader.readThreadObjectGcRootRecord()
136 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
137 }
138
139 ROOT_INTERNED_STRING -> {
140 val recordPosition = reader.bytesRead
141 val gcRootRecord = reader.readInternedStringGcRootRecord()
142 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
143 }
144
145 ROOT_FINALIZING -> {
146 val recordPosition = reader.bytesRead
147 val gcRootRecord = reader.readFinalizingGcRootRecord()
148 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
149 }
150
151 ROOT_DEBUGGER -> {
152 val recordPosition = reader.bytesRead
153 val gcRootRecord = reader.readDebuggerGcRootRecord()
154 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
155 }
156
157 ROOT_REFERENCE_CLEANUP -> {
158 val recordPosition = reader.bytesRead
159 val gcRootRecord = reader.readReferenceCleanupGcRootRecord()
160 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
161 }
162
163 ROOT_VM_INTERNAL -> {
164 val recordPosition = reader.bytesRead
165 val gcRootRecord = reader.readVmInternalGcRootRecord()
166 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
167 }
168
169 ROOT_JNI_MONITOR -> {
170 val recordPosition = reader.bytesRead
171 val gcRootRecord = reader.readJniMonitorGcRootRecord()
172 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
173 }
174
175 ROOT_UNREACHABLE -> {
176 val recordPosition = reader.bytesRead
177 val gcRootRecord = reader.readUnreachableGcRootRecord()
178 listener.onHprofRecord(recordPosition, GcRootRecord(gcRootRecord))
179 }
180 CLASS_DUMP -> {
181 val recordPosition = reader.bytesRead
182 val record = reader.readClassDumpRecord()
183 listener.onHprofRecord(recordPosition, record)
184 }
185 INSTANCE_DUMP -> {
186 val recordPosition = reader.bytesRead
187 val record = reader.readInstanceDumpRecord()
188 listener.onHprofRecord(recordPosition, record)
189 }
190
191 OBJECT_ARRAY_DUMP -> {
192 val recordPosition = reader.bytesRead
193 val arrayRecord = reader.readObjectArrayDumpRecord()
194 listener.onHprofRecord(recordPosition, arrayRecord)
195 }
196
197 PRIMITIVE_ARRAY_DUMP -> {
198 val recordPosition = reader.bytesRead
199 val record = reader.readPrimitiveArrayDumpRecord()
200 listener.onHprofRecord(recordPosition, record)
201 }
202
203 HEAP_DUMP_INFO -> {
204 val recordPosition = reader.bytesRead
205 val record = reader.readHeapDumpInfoRecord()
206 listener.onHprofRecord(recordPosition, record)
207 }
208 HEAP_DUMP_END -> {
209 val recordPosition = reader.bytesRead
210 val record = HeapDumpEndRecord
211 listener.onHprofRecord(recordPosition, record)
212 }
213 else -> error("Unexpected heap dump tag $tag at position ${reader.bytesRead}")
214 }
215 }
216 }
217
218 companion object {
219 fun StreamingHprofReader.asStreamingRecordReader() = StreamingRecordReaderAdapter(this)
220
221 fun Set<KClass<out HprofRecord>>.asHprofTags(): EnumSet<HprofRecordTag> {
222 val recordTypes = this
223 return if (HprofRecord::class in recordTypes) {
224 EnumSet.allOf(HprofRecordTag::class.java)
225 } else {
226 EnumSet.noneOf(HprofRecordTag::class.java).apply {
227 if (StringRecord::class in recordTypes) {
228 add(STRING_IN_UTF8)
229 }
230 if (LoadClassRecord::class in recordTypes) {
231 add(LOAD_CLASS)
232 }
233 if (HeapDumpEndRecord::class in recordTypes) {
234 add(HEAP_DUMP_END)
235 }
236 if (StackFrameRecord::class in recordTypes) {
237 add(STACK_FRAME)
238 }
239 if (StackTraceRecord::class in recordTypes) {
240 add(STACK_TRACE)
241 }
242 if (HeapDumpInfoRecord::class in recordTypes) {
243 add(HEAP_DUMP_INFO)
244 }
245 val readAllHeapDumpRecords = HeapDumpRecord::class in recordTypes
246 if (readAllHeapDumpRecords || GcRootRecord::class in recordTypes) {
247 addAll(HprofRecordTag.rootTags)
248 }
249 val readAllObjectRecords = readAllHeapDumpRecords || ObjectRecord::class in recordTypes
250 if (readAllObjectRecords || ClassDumpRecord::class in recordTypes) {
251 add(CLASS_DUMP)
252 }
253 if (readAllObjectRecords || InstanceDumpRecord::class in recordTypes) {
254 add(INSTANCE_DUMP)
255 }
256 if (readAllObjectRecords || ObjectArrayDumpRecord::class in recordTypes) {
257 add(OBJECT_ARRAY_DUMP)
258 }
259 if (readAllObjectRecords || PrimitiveArrayDumpRecord::class in recordTypes) {
260 add(PRIMITIVE_ARRAY_DUMP)
261 }
262 }
263 }
264 }
265 }
266 }
267