Skip to content

Commit 5969484

Browse files
nya3jpgeorgewfraser
authored andcommitted
Avoid scanning all classes on attach
Clients try to enable all breakpoints on attach, but currently it ends up with querying all classes loaded in the VM today. This is very slow; it takes ~5ms per class on my environment. This patch workarounds the problem by skipping classes that are clearly irrelevant.
1 parent aa72af3 commit 5969484

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

src/main/java/org/javacs/debug/JavaDebugServer.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ private boolean matchesLine(BreakpointRequest b, int line) {
182182
private List<ReferenceType> loadedTypesMatching(String absolutePath) {
183183
var matches = new ArrayList<ReferenceType>();
184184
for (var type : vm.allClasses()) {
185+
// ReferenceType#relativePath is slow. Avoid them when possible.
186+
if (!mayProvideType(absolutePath, type)) {
187+
continue;
188+
}
185189
var path = relativePath(type);
186190
if (!path.isEmpty() && absolutePath.endsWith(path)) {
187191
matches.add(type);
@@ -362,6 +366,18 @@ private void enablePendingBreakpointsInLoadedClasses() {
362366
}
363367

364368
private void enablePendingBreakpointsIn(ReferenceType type) {
369+
// ReferenceType#relativePath is slow. Avoid them when possible.
370+
boolean found = false;
371+
for (var b : pendingBreakpoints) {
372+
if (mayProvideType(b.source.path, type)) {
373+
found = true;
374+
break;
375+
}
376+
}
377+
if (!found) {
378+
return;
379+
}
380+
365381
// Check that class has source information
366382
var path = relativePath(type);
367383
if (path.isEmpty()) return;
@@ -715,5 +731,26 @@ public EvaluateResponseBody evaluate(EvaluateArguments req) {
715731
throw new UnsupportedOperationException();
716732
}
717733

734+
/** Determines if a given type might be provided by a source file. */
735+
private static boolean mayProvideType(String absolutePath, ReferenceType type) {
736+
var lastSlashPos = absolutePath.lastIndexOf('/');
737+
if (lastSlashPos < 0) {
738+
return true;
739+
}
740+
var absoluteDir = absolutePath.substring(0, lastSlashPos);
741+
742+
var fullName = type.name();
743+
var lastDotPos = fullName.lastIndexOf('.');
744+
if (lastDotPos < 0) {
745+
return true;
746+
}
747+
var packageName = fullName.substring(0, lastDotPos);
748+
749+
// If a type belongs to the package "x.y.z", its source directory should end with "x/y/z".
750+
// Unfortunately it's difficult to consider class names because of anonymous classes and
751+
// non-public classes.
752+
return absoluteDir.endsWith(packageName.replace('.', '/'));
753+
}
754+
718755
private static final Logger LOG = Logger.getLogger("debug");
719756
}

0 commit comments

Comments
 (0)