/**
   * Associates breakpoint with class. Create requests for loaded class and registers callback for
   * loading classes
   *
   * @param debugProcess the requesting process
   */
  protected void createOrWaitPrepare(DebugProcessImpl debugProcess, String classToBeLoaded) {
    debugProcess.getRequestsManager().callbackOnPrepareClasses(this, classToBeLoaded);

    List list = debugProcess.getVirtualMachineProxy().classesByName(classToBeLoaded);
    for (final Object aList : list) {
      ReferenceType refType = (ReferenceType) aList;
      if (refType.isPrepared()) {
        processClassPrepare(debugProcess, refType);
      }
    }
  }
  @Nullable
  private static List<Value> copyToBuffer(
      EvaluationContextImpl evaluationContext, ObjectReference bitmap, Dimension size)
      throws EvaluateException {
    DebugProcessImpl debugProcess = evaluationContext.getDebugProcess();
    VirtualMachineProxyImpl virtualMachineProxy = debugProcess.getVirtualMachineProxy();

    List<ReferenceType> classes = virtualMachineProxy.classesByName("byte[]");
    if (classes.size() != 1 || !(classes.get(0) instanceof ArrayType)) {
      return null;
    }
    ArrayType byteArrayType = (ArrayType) classes.get(0);

    classes = virtualMachineProxy.classesByName("java.nio.ByteBuffer");
    if (classes.size() != 1 || !(classes.get(0) instanceof ClassType)) {
      return null;
    }
    ClassType byteBufferType = (ClassType) classes.get(0);
    Method wrapMethod =
        DebuggerUtils.findMethod(byteBufferType, "wrap", "([B)Ljava/nio/ByteBuffer;");
    if (wrapMethod == null) {
      return null;
    }

    ArrayReference byteArray = byteArrayType.newInstance(size.width * size.height * 4);
    Value byteBufferRef =
        debugProcess.invokeMethod(
            evaluationContext, byteBufferType, wrapMethod, ImmutableList.of(byteArray));

    Method copyToBufferMethod =
        DebuggerUtils.findMethod(
            bitmap.referenceType(), "copyPixelsToBuffer", "(Ljava/nio/Buffer;)V");
    if (copyToBufferMethod == null) {
      return null;
    }

    debugProcess.invokeMethod(
        evaluationContext, bitmap, copyToBufferMethod, ImmutableList.of(byteBufferRef));
    return byteArray.getValues();
  }
 @Override
 protected void createRequestForPreparedClass(
     final DebugProcessImpl debugProcess, final ReferenceType classType) {
   if (!isInScopeOf(debugProcess, classType.name())) {
     if (LOG.isDebugEnabled()) {
       LOG.debug(
           classType.name()
               + " is out of debug-process scope, breakpoint request won't be created for line "
               + getLineIndex());
     }
     return;
   }
   try {
     List<Location> locations =
         debugProcess.getPositionManager().locationsOfLine(classType, getSourcePosition());
     if (!locations.isEmpty()) {
       for (Location loc : locations) {
         if (LOG.isDebugEnabled()) {
           LOG.debug(
               "Found location [codeIndex="
                   + loc.codeIndex()
                   + "] for reference type "
                   + classType.name()
                   + " at line "
                   + getLineIndex()
                   + "; isObsolete: "
                   + (debugProcess.getVirtualMachineProxy().versionHigher("1.4")
                       && loc.method().isObsolete()));
         }
         if (!acceptLocation(debugProcess, classType, loc)) {
           continue;
         }
         final BreakpointRequest request =
             debugProcess.getRequestsManager().createBreakpointRequest(this, loc);
         debugProcess.getRequestsManager().enableRequest(request);
         if (LOG.isDebugEnabled()) {
           LOG.debug(
               "Created breakpoint request for reference type "
                   + classType.name()
                   + " at line "
                   + getLineIndex()
                   + "; codeIndex="
                   + loc.codeIndex());
         }
       }
     } else {
       // there's no executable code in this class
       debugProcess
           .getRequestsManager()
           .setInvalid(
               this,
               DebuggerBundle.message(
                   "error.invalid.breakpoint.no.executable.code",
                   (getLineIndex() + 1),
                   classType.name()));
       if (LOG.isDebugEnabled()) {
         LOG.debug(
             "No locations of type " + classType.name() + " found at line " + getLineIndex());
       }
     }
   } catch (ClassNotPreparedException ex) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("ClassNotPreparedException: " + ex.getMessage());
     }
     // there's a chance to add a breakpoint when the class is prepared
   } catch (ObjectCollectedException ex) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("ObjectCollectedException: " + ex.getMessage());
     }
     // there's a chance to add a breakpoint when the class is prepared
   } catch (InvalidLineNumberException ex) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("InvalidLineNumberException: " + ex.getMessage());
     }
     debugProcess
         .getRequestsManager()
         .setInvalid(this, DebuggerBundle.message("error.invalid.breakpoint.bad.line.number"));
   } catch (InternalException ex) {
     LOG.info(ex);
   } catch (Exception ex) {
     LOG.info(ex);
   }
   updateUI();
 }
  public void reloadClasses(final Map<String, HotSwapFile> modifiedClasses) {
    DebuggerManagerThreadImpl.assertIsManagerThread();

    if (modifiedClasses == null || modifiedClasses.size() == 0) {
      myProgress.addMessage(
          myDebuggerSession,
          MessageCategory.INFORMATION,
          DebuggerBundle.message("status.hotswap.loaded.classes.up.to.date"));
      return;
    }

    final DebugProcessImpl debugProcess = getDebugProcess();
    final VirtualMachineProxyImpl virtualMachineProxy = debugProcess.getVirtualMachineProxy();

    final Project project = debugProcess.getProject();
    final BreakpointManager breakpointManager =
        (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager();
    breakpointManager.disableBreakpoints(debugProcess);

    // virtualMachineProxy.suspend();

    try {
      RedefineProcessor redefineProcessor = new RedefineProcessor(virtualMachineProxy);

      int processedEntriesCount = 0;
      for (final Map.Entry<String, HotSwapFile> entry : modifiedClasses.entrySet()) {
        // stop if process is finished already
        if (debugProcess.isDetached() || debugProcess.isDetaching()) {
          break;
        }
        if (redefineProcessor.getProcessedClassesCount() == 0 && myProgress.isCancelled()) {
          // once at least one class has been actually reloaded, do not interrupt the whole process
          break;
        }
        processedEntriesCount++;
        final String qualifiedName = entry.getKey();
        if (qualifiedName != null) {
          myProgress.setText(qualifiedName);
          myProgress.setFraction(processedEntriesCount / (double) modifiedClasses.size());
        }
        try {
          redefineProcessor.processClass(qualifiedName, entry.getValue().file);
        } catch (IOException e) {
          reportProblem(qualifiedName, e);
        }
      }

      if (redefineProcessor.getProcessedClassesCount() == 0 && myProgress.isCancelled()) {
        // once at least one class has been actually reloaded, do not interrupt the whole process
        return;
      }

      redefineProcessor.processPending();
      myProgress.setFraction(1);

      final int partiallyRedefinedClassesCount =
          redefineProcessor.getPartiallyRedefinedClassesCount();
      if (partiallyRedefinedClassesCount == 0) {
        myProgress.addMessage(
            myDebuggerSession,
            MessageCategory.INFORMATION,
            DebuggerBundle.message(
                "status.classes.reloaded", redefineProcessor.getProcessedClassesCount()));
      } else {
        final String message =
            DebuggerBundle.message(
                "status.classes.not.all.versions.reloaded",
                partiallyRedefinedClassesCount,
                redefineProcessor.getProcessedClassesCount());
        myProgress.addMessage(myDebuggerSession, MessageCategory.WARNING, message);
      }

      LOG.debug("classes reloaded");
    } catch (Throwable e) {
      processException(e);
    }

    debugProcess.getPositionManager().clearCache();

    DebuggerContextImpl context = myDebuggerSession.getContextManager().getContext();
    SuspendContextImpl suspendContext = context.getSuspendContext();
    if (suspendContext != null) {
      XExecutionStack stack = suspendContext.getActiveExecutionStack();
      if (stack != null) {
        ((JavaExecutionStack) stack).initTopFrame();
      }
    }

    final Semaphore waitSemaphore = new Semaphore();
    waitSemaphore.down();
    //noinspection SSBasedInspection
    SwingUtilities.invokeLater(
        () -> {
          try {
            if (!project.isDisposed()) {
              breakpointManager.reloadBreakpoints();
              debugProcess.getRequestsManager().clearWarnings();
              if (LOG.isDebugEnabled()) {
                LOG.debug("requests updated");
                LOG.debug("time stamp set");
              }
              myDebuggerSession.refresh(false);

              XDebugSession session = myDebuggerSession.getXDebugSession();
              if (session != null) {
                session.rebuildViews();
              }
            }
          } catch (Throwable e) {
            LOG.error(e);
          } finally {
            waitSemaphore.up();
          }
        });

    waitSemaphore.waitFor();

    if (!project.isDisposed()) {
      try {
        breakpointManager.enableBreakpoints(debugProcess);
      } catch (Exception e) {
        processException(e);
      }
    }
  }