public CompletableFuture<StackFrame> getStackFrameAsync() {
    DebuggerManagerThreadImpl.assertIsManagerThread();

    checkValid();

    if (myStackFrame == null) {
      ThreadReference threadRef = myThreadProxy.getThreadReference();
      return getFrameIndexAsync().thenCompose(index -> {
          // batch get frames from 1 to FRAMES_BATCH_MAX
          // making this number very high does not help much because renderers invocation usually flush all caches
          if (index > 0 && index < FRAMES_BATCH_MAX) {
            try {
              return DebuggerUtilsAsync.frames(threadRef, 0, Math.min(myThreadProxy.frameCount(), FRAMES_BATCH_MAX))
                .thenApply(frames -> myStackFrame = frames.get(index));
            }
            catch (EvaluateException e) {
              return CompletableFuture.failedFuture(e);
            }
          }
          else {
            return DebuggerUtilsAsync.frame(threadRef, index).thenApply(f -> myStackFrame = f);
          }
        })
        .exceptionally(throwable -> {
          if (DebuggerUtilsAsync.unwrap(throwable) instanceof ObjectCollectedException) {
            throw new CompletionException(EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message("evaluation.error.thread.collected")));
          }
          throw (RuntimeException)throwable;
        });
    }

    return CompletableFuture.completedFuture(myStackFrame);
  }
public CompletableFuture<StackFrame> getStackFrameAsync()