main

square/leakcanary

Last updated at: 29/12/2023 09:39

ObjectArrayReferenceReader.kt

TLDR

This file is a part of the Shark library and contains the ObjectArrayReferenceReader class. The class implements the ReferenceReader interface and defines a single read method. The ObjectArrayReferenceReader class is responsible for reading references from object arrays.

Methods

read

The read method takes a HeapObjectArray as a parameter and returns a sequence of Reference objects. This method iterates over each element in the array and filters out any that are null or do not exist in the object graph. It then maps each element to a Reference object, with the value object ID, index, and details about the reference location. The resulting sequence of Reference objects is returned.

Classes

ObjectArrayReferenceReader

This class implements the ReferenceReader interface and is responsible for reading references from object arrays. It provides a single method, read, which takes a HeapObjectArray and returns a sequence of Reference objects. Additionally, it contains a companion object with a utility method, isSkippablePrimitiveWrapperArray, to determine if a given array is a skippable primitive wrapper array.

package shark

import shark.HeapObject.HeapObjectArray
import shark.Reference.LazyDetails
import shark.ReferenceLocationType.ARRAY_ENTRY

internal class ObjectArrayReferenceReader : ReferenceReader<HeapObjectArray> {
  override fun read(source: HeapObjectArray): Sequence<Reference> {
    if (source.isSkippablePrimitiveWrapperArray) {
      // primitive wrapper arrays aren't interesting.
      // That also means the wrapped size isn't added to the dominator tree, so we need to
      // add that back when computing shallow size in ShallowSizeCalculator.
      // Another side effect is that if the wrapped primitive is referenced elsewhere, we might
      // double count its size.
      return emptySequence()
    }

    val graph = source.graph
    val record = source.readRecord()
    val arrayClassId = source.arrayClassId
    return record.elementIds.asSequence().filter { objectId ->
      objectId != ValueHolder.NULL_REFERENCE && graph.objectExists(objectId)
    }.mapIndexed { index, elementObjectId ->
      Reference(
        valueObjectId = elementObjectId,
        isLowPriority = false,
        lazyDetailsResolver = {
          LazyDetails(
            name = index.toString(),
            locationClassObjectId = arrayClassId,
            locationType = ARRAY_ENTRY,
            isVirtual = false,
            matchedLibraryLeak = null
          )
        }
      )
    }
  }
  internal companion object {
    private val skippablePrimitiveWrapperArrayTypes = setOf(
      Boolean::class,
      Char::class,
      Float::class,
      Double::class,
      Byte::class,
      Short::class,
      Int::class,
      Long::class
    ).map { it.javaObjectType.name + "[]" }

    internal val HeapObjectArray.isSkippablePrimitiveWrapperArray: Boolean
      get() = arrayClassName in skippablePrimitiveWrapperArrayTypes
  }
}