/** * 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); } } }