void (@NotNull MethodBreakpointBase breakpoint, @NotNull DebugProcessImpl debugProcess, @NotNull ReferenceType classType, @NotNull ClassesByNameProvider classesByName, boolean base) { if (breakpoint.isWatchExit() && !MethodBreakpointBase.canBeWatchExitEmulated(debugProcess)) { breakpoint.disableEmulation(); return; } if (!base && !shouldCreateRequest(breakpoint, breakpoint.getXBreakpoint(), debugProcess, true)) { return; } Method lambdaMethod = MethodBytecodeUtil.getLambdaMethod(classType, classesByName); if (lambdaMethod != null && breakpoint .matchingMethods(StreamEx.of(((ClassType)classType).interfaces()).flatCollection(ReferenceType::allMethods), debugProcess) .findFirst().isEmpty()) { return; } StreamEx<Method> methods = lambdaMethod != null ? StreamEx.of(lambdaMethod) : breakpoint.matchingMethods(StreamEx.of(classType.methods()).filter(m -> base || !m.isAbstract()), debugProcess); boolean found = false; for (Method method : methods) { found = true; if (method.isNative()) { LOG.info("Breakpoint emulation was disabled because " + method + " is native"); breakpoint.disableEmulation(); return; } else if (method.isAbstract()) { continue; } Method target = MethodBytecodeUtil.getBridgeTargetMethod(method, classesByName); if (target != null) { method = target; } if (breakpoint.isWatchEntry()) { // We assume that all VMs start code indexes from zero. Location location = new LocationCodeIndexOnly(method, 0); createLocationBreakpointRequest(breakpoint, location, debugProcess, true); } if (breakpoint.isWatchExit()) { final Method finalMethod = method; class BytecodeVisitor extends MethodVisitor implements MethodBytecodeUtil.InstructionOffsetReader { private int bytecodeOffset = -1; BytecodeVisitor() { super(Opcodes.API_VERSION); } @Override public void readBytecodeInstructionOffset(int offset) { bytecodeOffset = offset; } @Override public void visitInsn(int opcode) { if (Opcodes.IRETURN <= opcode && opcode <= Opcodes.RETURN) { assert bytecodeOffset >= 0; Location location = new LocationCodeIndexOnly(finalMethod, bytecodeOffset); createLocationBreakpointRequest(breakpoint, location, debugProcess, false); } } } MethodBytecodeUtil.visit(method, new BytecodeVisitor(), false); } } if (base && found) { // desired class found - now also track all new classes createRequestForSubClasses(breakpoint, debugProcess, classType); } }