void removeChildNodesRecursively(@NotNull List<? super Disposable> disposables,
                                   @NotNull ObjectTree tree,
                                   @Nullable Throwable trace,
                                   @Nullable Predicate<? super Disposable> predicate) {
    myChildren.removeChildren(predicate, childNode -> {
      // predicate is used only for direct children
      childNode.removeChildNodesRecursively(disposables, tree, trace, null);
      // already disposed. may happen when someone does `register(obj, ()->Disposer.dispose(t));` abomination
      Disposable object = childNode.getObject();
      boolean alreadyDisposed = tree.rememberDisposedTrace(object, trace) != null;
      if (!alreadyDisposed) {
        disposables.add(object);
      }
    });
  }
void removeChildNodesRecursively(@NotNull List<? super Disposable> disposables,
                                   @NotNull ObjectTree tree,
                                   @Nullable Throwable trace,
                                   @Nullable Predicate<? super Disposable> predicate)