class HeapDumpInstanceObject implements InstanceObject {

  @VisibleForTesting
  @NotNull
  public List<ReferenceObject> extractReferences() {
    // Sort hard referrers to appear first.
    List<Instance> sortedReferences = new ArrayList<>(myInstance.getHardReverseReferences());
    sortedReferences.sort(DEPTH_COMPARATOR);

    // Sort soft referrers to appear second.
    if (myInstance.getSoftReverseReferences() != null) {
      List<Instance> sortedSoftReferences = new ArrayList<>(myInstance.getSoftReverseReferences());
      sortedSoftReferences.sort(DEPTH_COMPARATOR);
      sortedReferences.addAll(sortedSoftReferences);
    }

    List<ReferenceObject> referrers = new ArrayList<>(sortedReferences.size());

    // Determine the variable names of references.
    for (Instance reference : sortedReferences) {
      // Note that each instance can have multiple references to the same object.
      List<String> referencingFieldNames = new ArrayList<>(3);
      if (reference instanceof ClassInstance) {
        ClassInstance classInstance = (ClassInstance)reference;
        for (ClassInstance.FieldValue entry : classInstance.getValues()) {
          // This instance is referenced by a field of the referrer class
          if (entry.getField().getType() == Type.OBJECT && entry.getValue() == myInstance) {
            referencingFieldNames.add(entry.getField().getName());
          }
        }
      }
      else if (reference instanceof ArrayInstance) {
        ArrayInstance arrayInstance = (ArrayInstance)reference;
        assert arrayInstance.getArrayType() == Type.OBJECT;
        Object[] values = arrayInstance.getValues();
        for (int i = 0; i < values.length; ++i) {
          // This instance is referenced by an array
          if (values[i] == myInstance) {
            referencingFieldNames.add(String.valueOf(i));
          }
        }
      }
      else if (reference instanceof ClassObj) {
        ClassObj classObj = (ClassObj)reference;
        Map<Field, Object> staticValues = classObj.getStaticFieldValues();
        for (Map.Entry<Field, Object> entry : staticValues.entrySet()) {
          // This instance is referenced by a static field of a Class object.
          if (entry.getKey().getType() == Type.OBJECT && entry.getValue() == myInstance) {
            referencingFieldNames.add(entry.getKey().getName());
          }
        }
      }

      InstanceObject referencingInstance = myCaptureObject.findInstanceObject(reference);
      assert referencingInstance != null;
      referrers.add(new ReferenceObject(referencingFieldNames, referencingInstance));
    }

    return referrers;
  }

    HeapDumpInstanceObject(@NotNull HeapDumpCaptureObject captureObject,
                         @NotNull Instance instance,
                         @NotNull ClassDb.ClassEntry classEntry,
                         @Nullable ValueType precomputedValueType);

}