@Override
  @Nullable
  public DebuggerSession attachVirtualMachine(@NotNull DebugEnvironment environment) throws ExecutionException {
    DebugProcessEvents debugProcess = new DebugProcessEvents(myProject);
    DebuggerSession session = DebuggerSession.create(debugProcess, environment);
    ExecutionResult executionResult = session.getProcess().getExecutionResult();
    if (executionResult == null) {
      return null;
    }
    session.getContextManager().addListener(mySessionListener);

    // the whole method may still be called from EDT, we need to update the state immediately in this case
    UIUtil.invokeLaterIfNeeded(() -> {
      getContextManager()
        .setState(DebuggerContextUtil.createDebuggerContext(session, session.getContextManager().getContext().getSuspendContext()),
                  session.getState(), DebuggerSession.Event.CONTEXT, null);
    });

    final ProcessHandler processHandler = executionResult.getProcessHandler();

    synchronized (mySessions) {
      mySessions.put(processHandler, session);
    }

    if (!(processHandler instanceof RemoteDebugProcessHandler)) {
      // add listener only to non-remote process handler:
      // on Unix systems destroying process does not cause VMDeathEvent to be generated,
      // so we need to call debugProcess.stop() explicitly for graceful termination.
      // RemoteProcessHandler on the other hand will call debugProcess.stop() as a part of destroyProcess() and detachProcess() implementation,
      // so we shouldn't add the listener to avoid calling stop() twice
      processHandler.addProcessListener(new ProcessAdapter() {
        @Override
        public void processWillTerminate(@NotNull ProcessEvent event, boolean willBeDestroyed) {
          ProcessHandler processHandler = event.getProcessHandler();
          final DebugProcessImpl debugProcess = getDebugProcess(processHandler);
          if (debugProcess != null) {
            // if current thread is a "debugger manager thread", stop will execute synchronously
            // it is KillableColoredProcessHandler responsibility to terminate VM
            debugProcess.stop(willBeDestroyed &&
                              !(processHandler instanceof KillableColoredProcessHandler &&
                                ((KillableColoredProcessHandler)processHandler).shouldKillProcessSoftly()));

            // wait at most 10 seconds: the problem is that debugProcess.stop() can hang if there are troubles in the debuggee
            // if processWillTerminate() is called from AWT thread debugProcess.waitFor() will block it and the whole app will hang
            if (!DebuggerManagerThreadImpl.isManagerThread()) {
              if (SwingUtilities.isEventDispatchThread()) {
                ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
                  ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
                  indicator.setIndeterminate(false);
                  int wait = 0;
                  while (wait < WAIT_KILL_TIMEOUT && !indicator.isCanceled()) {
                    indicator.setFraction((double)wait / WAIT_KILL_TIMEOUT);
                    debugProcess.waitFor(200);
                    wait += 200;
                  }
                }, JavaDebuggerBundle.message("waiting.for.debugger.response"), true, debugProcess.getProject());
              }
              else {
                debugProcess.waitFor(WAIT_KILL_TIMEOUT);
              }
            }
          }
        }
      });
    }
    getEventPublisher().sessionCreated(session);

    if (debugProcess.isDetached() || debugProcess.isDetaching()) {
      session.dispose();
      return null;
    }
    if (environment.isRemote()) {
      // optimization: that way BatchEvaluator will not try to lookup the class file in remote VM
      // which is an expensive operation when executed first time
      debugProcess.putUserData(BatchEvaluator.REMOTE_SESSION_KEY, Boolean.TRUE);
    }

    return session;
  }
@Override
  @Nullable
  public DebuggerSession attachVirtualMachine(@NotNull DebugEnvironment environment)