This is an automated email from the ASF dual-hosted git repository.

entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 8a328a3  Performance optimizations to speed up remote debugging.
8a328a3 is described below

commit 8a328a371bed55f5f488bb3d0d89ae8a8c5b84bc
Author: Martin Entlicher <[email protected]>
AuthorDate: Tue Sep 7 12:13:34 2021 +0200

    Performance optimizations to speed up remote debugging.
---
 .../debugger/jpda/DeadlockDetectorImpl.java        |  44 ++--
 .../debugger/jpda/JDIExceptionReporter.java        |  16 +-
 .../modules/debugger/jpda/JPDADebuggerImpl.java    | 223 ++++++++++++---------
 .../modules/debugger/jpda/SingleThreadWatcher.java |   5 +-
 .../debugger/jpda/actions/StepActionProvider.java  |   3 +
 .../debugger/jpda/models/JPDAThreadGroupImpl.java  |  11 +-
 .../debugger/jpda/models/JPDAThreadImpl.java       | 122 ++++++-----
 .../debugger/jpda/models/ObjectTranslation.java    | 115 +++++++++--
 .../modules/debugger/jpda/models/ThreadsCache.java |  17 --
 java/java.lsp.server/manifest.mf                   |   1 +
 .../modules/debugger/jpda/Bundle.properties        |  18 ++
 .../lsp/server/debugging/NbProtocolServer.java     | 154 +++++++-------
 .../variables/NbVariablesRequestHandler.java       | 104 +++++-----
 .../org/netbeans/modules/java/lsp/server/layer.xml |  30 +++
 14 files changed, 529 insertions(+), 334 deletions(-)

diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/DeadlockDetectorImpl.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/DeadlockDetectorImpl.java
index 8018fe8..9f1a938 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/DeadlockDetectorImpl.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/DeadlockDetectorImpl.java
@@ -34,15 +34,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import org.netbeans.api.debugger.jpda.CallStackFrame;
 import org.netbeans.api.debugger.jpda.DeadlockDetector;
 import org.netbeans.api.debugger.jpda.JPDADebugger;
 import org.netbeans.api.debugger.jpda.JPDAThread;
 import org.netbeans.api.debugger.jpda.ObjectVariable;
-import org.netbeans.api.debugger.jpda.This;
 import org.netbeans.modules.debugger.jpda.expr.JDIVariable;
 import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
-import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
 import org.openide.util.RequestProcessor;
 import org.openide.util.RequestProcessor.Task;
 import org.openide.util.WeakListeners;
@@ -52,6 +52,9 @@ import org.openide.util.WeakSet;
  *
  * @author martin
  */
[email protected]({
+    "USE_JPDA_DEADLOCK_DETECTOR=true"
+})
 public class DeadlockDetectorImpl extends DeadlockDetector implements 
PropertyChangeListener {
     
     private final Set<JPDAThread> suspendedThreads = new WeakSet<JPDAThread>();
@@ -61,6 +64,9 @@ public class DeadlockDetectorImpl extends DeadlockDetector 
implements PropertyCh
     private Map<Long, Node> monitorToNode;
 
     DeadlockDetectorImpl(JPDADebugger debugger) {
+        if (!Boolean.valueOf(Bundle.USE_JPDA_DEADLOCK_DETECTOR())) {
+            return;
+        }
         debugger.addPropertyChangeListener(this);
         List<JPDAThread> threads = 
debugger.getThreadsCollector().getAllThreads();
         for (JPDAThread thread : threads) {
@@ -85,24 +91,26 @@ public class DeadlockDetectorImpl extends DeadlockDetector 
implements PropertyCh
                 final Set<JPDAThread> tempSuspThreads;
                 synchronized(suspendedThreads) {
                     suspendedThreads.add(thread);
-                    tempSuspThreads = new 
HashSet<JPDAThread>(suspendedThreads);
+                    tempSuspThreads = suspendedThreads.size() > 1 ? new 
HashSet<JPDAThread>(suspendedThreads) : null;
                 }
-                final Task[] taskPtr = new Task[] { null };
-                synchronized (unfinishedTasks) {
-                    Task task = rp.post(new Runnable() {
-                        public void run() {
-                            Set<Deadlock> deadlocks;
-                            deadlocks = findDeadlockedThreads(tempSuspThreads);
-                            if (deadlocks != null) {
-                                setDeadlocks(deadlocks);
-                            }
-                            synchronized (unfinishedTasks) {
-                                unfinishedTasks.remove(taskPtr[0]);
+                if (tempSuspThreads != null) {
+                    final Task[] taskPtr = new Task[] { null };
+                    synchronized (unfinishedTasks) {
+                        Task task = rp.post(new Runnable() {
+                            public void run() {
+                                Set<Deadlock> deadlocks;
+                                deadlocks = 
findDeadlockedThreads(tempSuspThreads);
+                                if (deadlocks != null) {
+                                    setDeadlocks(deadlocks);
+                                }
+                                synchronized (unfinishedTasks) {
+                                    unfinishedTasks.remove(taskPtr[0]);
+                                }
                             }
-                        }
-                    });
-                    unfinishedTasks.add(task);
-                    taskPtr[0] = task;
+                        });
+                        unfinishedTasks.add(task);
+                        taskPtr[0] = task;
+                    }
                 }
             } else {
                 synchronized (suspendedThreads) {
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JDIExceptionReporter.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JDIExceptionReporter.java
index a5c75ab..947f3a5 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JDIExceptionReporter.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JDIExceptionReporter.java
@@ -31,7 +31,8 @@ import org.openide.util.Exceptions;
  */
 public final class JDIExceptionReporter {
 
-    private static final Logger logger = 
Logger.getLogger("org.netbeans.modules.debugger.jpda.jdi");    // NOI18N
+    private static final Logger LOGGER = 
Logger.getLogger("org.netbeans.modules.debugger.jpda.jdi");    // NOI18N
+    private static final Level LOGLEVEL = Level.FINER;
 
     public static final Object RET_VOID = new Object();
 
@@ -46,14 +47,14 @@ public final class JDIExceptionReporter {
     }
 
     public static boolean isLoggable() {
-        return logger.isLoggable(java.util.logging.Level.FINER);
+        return LOGGER.isLoggable(java.util.logging.Level.SEVERE);
     }
 
     public static void logCallStart(String className, String methodName, 
String msg, Object[] args) {
         try {
-            logger.log(java.util.logging.Level.FINER, msg, args);
+            LOGGER.log(LOGLEVEL, msg, args);
         } catch (Exception exc) {
-            logger.log(java.util.logging.Level.FINER, "Logging of 
"+className+"."+methodName+"() threw exception:", exc);
+            LOGGER.log(LOGLEVEL, "Logging of "+className+"."+methodName+"() 
threw exception:", exc);
         }
         callStartTime.set(System.nanoTime());
     }
@@ -62,10 +63,13 @@ public final class JDIExceptionReporter {
         long t2 = System.nanoTime();
         long t1 = callStartTime.get();
         callStartTime.remove();
-        logger.log(java.util.logging.Level.FINER, "          {0}.{1}() 
returned after {2} ns, return value = {3}",
+        LOGGER.log(LOGLEVEL, "          {0}.{1}() returned after {2} ns, 
return value = {3}",
                    new Object[] {className, methodName, (t2 - t1), (RET_VOID 
== ret) ? "void" : ret});
         if (ret instanceof Throwable) {
-            logger.log(Level.FINER, "", (Throwable) ret);
+            LOGGER.log(LOGLEVEL, "", (Throwable) ret);
+        }
+        if ((t2 - t1) > 100_000_000) {
+            LOGGER.log(LOGLEVEL, "", new RuntimeException("TooLongCall"));
         }
     }
 
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
index c84c44d..1085334 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
@@ -60,8 +60,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.security.auth.Refreshable;
@@ -107,10 +110,12 @@ import 
org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper
 import org.netbeans.modules.debugger.jpda.jdi.IntegerValueWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
 import 
org.netbeans.modules.debugger.jpda.jdi.InvalidStackFrameExceptionWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.LocalVariableWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.MirrorWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.StackFrameWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.ThreadReferenceWrapper;
+import org.netbeans.modules.debugger.jpda.jdi.TypeComponentWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.ValueWrapper;
 import org.netbeans.modules.debugger.jpda.jdi.VirtualMachineWrapper;
@@ -184,6 +189,8 @@ public class JPDADebuggerImpl extends JPDADebugger {
     private final Map<Long, String>     markedObjects = new 
LinkedHashMap<Long, String>();
     private final Map<String, ObjectVariable> markedObjectLabels = new 
LinkedHashMap<String, ObjectVariable>();
     private final Map<ClassType, List>  allInterfacesMap = new 
WeakHashMap<ClassType, List>();
+    private static final int            RP_THROUGHPUT = 10;
+    private final RequestProcessor      rpCreateThreads = new 
RequestProcessor(JPDADebuggerImpl.class.getName()+"_newJPDAThreads", 
RP_THROUGHPUT); // NOI18N
 
     private StackFrame      altCSF = null;  //PATCH 48174
 
@@ -1163,11 +1170,21 @@ public class JPDADebuggerImpl extends JPDADebugger {
         }
     }
 
+    private Method stringLengthMethod;
+    private Method stringSubstringMethod;
+    private final Object stringMethodsLock = new Object();
+
     private Value cutLength(StringReference sr, int maxLength, ThreadReference 
tr) throws InvalidExpressionException {
         try {
             Method stringLengthMethod;
-                stringLengthMethod = ClassTypeWrapper.concreteMethodByName(
-                        (ClassType) ValueWrapper.type (sr), "length", "()I"); 
// NOI18N
+            synchronized (stringMethodsLock) {
+                stringLengthMethod = this.stringLengthMethod;
+                if (stringLengthMethod == null) {
+                    stringLengthMethod = ClassTypeWrapper.concreteMethodByName(
+                            (ClassType) ValueWrapper.type (sr), "length", 
"()I"); // NOI18N
+                    this.stringLengthMethod = stringLengthMethod;
+                }
+            }
             List<Value> emptyArgs = Collections.emptyList();
             IntegerValue lengthValue = (IntegerValue) 
org.netbeans.modules.debugger.jpda.expr.TreeEvaluator.
                 invokeVirtual (
@@ -1178,8 +1195,15 @@ public class JPDADebuggerImpl extends JPDADebugger {
                     this
                 );
                 if (IntegerValueWrapper.value(lengthValue) > maxLength) {
-                    Method subStringMethod = 
ClassTypeWrapper.concreteMethodByName(
-                            (ClassType) ValueWrapper.type (sr), "substring", 
"(II)Ljava/lang/String;");  // NOI18N
+                    Method subStringMethod;
+                    synchronized (stringMethodsLock) {
+                        subStringMethod = this.stringSubstringMethod;
+                        if (subStringMethod == null) {
+                            subStringMethod = 
ClassTypeWrapper.concreteMethodByName(
+                                (ClassType) ValueWrapper.type (sr), 
"substring", "(II)Ljava/lang/String;");  // NOI18N
+                            this.stringSubstringMethod = subStringMethod;
+                        }
+                    }
                     if (subStringMethod != null) {
                         sr = (StringReference) 
org.netbeans.modules.debugger.jpda.expr.TreeEvaluator.
                             invokeVirtual (
@@ -1201,34 +1225,25 @@ public class JPDADebuggerImpl extends JPDADebugger {
     }
 
     public static String getGenericSignature (TypeComponent component) {
-        if (tcGenericSignatureMethod == null) {
-            return null;
-        }
         try {
-            return (String) tcGenericSignatureMethod.invoke
-                (component, new Object[0]);
-        } catch (IllegalAccessException e) {
-            Exceptions.printStackTrace(e);
-            return null;    // should not happen
-        } catch (InvocationTargetException e) {
-            Exceptions.printStackTrace(e);
-            return null;    // should not happen
+            return TypeComponentWrapper.genericSignature(component);
+        } catch (InternalExceptionWrapper ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (VMDisconnectedExceptionWrapper ex) {
+            // Disconnected
         }
+        return null;
     }
 
     public static String getGenericSignature (LocalVariable component) {
-        if (lvGenericSignatureMethod == null) {
-            return null;
-        }
         try {
-            return (String) lvGenericSignatureMethod.invoke(component, new 
Object[0]);
-        } catch (IllegalAccessException e) {
-            Exceptions.printStackTrace(e);
-            return null;    // should not happen
-        } catch (InvocationTargetException e) {
-            Exceptions.printStackTrace(e);
-            return null;    // should not happen
+            return LocalVariableWrapper.genericSignature(component);
+        } catch (InternalExceptionWrapper ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (VMDisconnectedExceptionWrapper ex) {
+            // Disconnected
         }
+        return null;
     }
 
     public VirtualMachine getVirtualMachine () {
@@ -1270,7 +1285,6 @@ public class JPDADebuggerImpl extends JPDADebugger {
             canBeModified = null; // Reset the can be modified flag
         }
 
-        initGenericsSupport ();
         EditorContextBridge.getContext().createTimeStamp(this);
 
 
@@ -1854,20 +1868,21 @@ public class JPDADebuggerImpl extends JPDADebugger {
     }
 
     public void notifyToBeResumedAll() {
-        Collection threads = threadsTranslation.getTranslated();
-        for (Iterator it = threads.iterator(); it.hasNext(); ) {
-            Object threadOrGroup = it.next();
-            if (threadOrGroup instanceof JPDAThreadImpl) {
-                int status = ((JPDAThreadImpl) threadOrGroup).getState();
+        List<? extends JPDAThreadImpl> threads = 
threadsTranslation.getTranslated((o) -> (o instanceof JPDAThreadImpl) ? 
(JPDAThreadImpl) o : null);
+        int n = threads.size();
+        if (n > 0) {
+            processInParallel(n, (i) -> {
+                JPDAThreadImpl thread = threads.get(i);
+                int status = thread.getState();
                 boolean invalid = (status == JPDAThread.STATE_NOT_STARTED ||
                                    status == JPDAThread.STATE_UNKNOWN ||
                                    status == JPDAThread.STATE_ZOMBIE);
                 if (!invalid) {
-                    ((JPDAThreadImpl) threadOrGroup).notifyToBeResumed();
+                    thread.notifyToBeResumed();
                 } else if (status == JPDAThread.STATE_UNKNOWN || status == 
JPDAThread.STATE_ZOMBIE) {
-                    threadsTranslation.remove(((JPDAThreadImpl) 
threadOrGroup).getThreadReference());
+                    threadsTranslation.remove(thread.getThreadReference());
                 }
-            }
+            });
         }
     }
 
@@ -1876,21 +1891,22 @@ public class JPDADebuggerImpl extends JPDADebugger {
     }
     
     public void notifyToBeResumedAllNoFire(Set<ThreadReference> 
ignoredThreads) {
-        Collection threads = threadsTranslation.getTranslated();
-        for (Iterator it = threads.iterator(); it.hasNext(); ) {
-            Object threadOrGroup = it.next();
-            if (threadOrGroup instanceof JPDAThreadImpl &&
-                    (ignoredThreads == null || 
!ignoredThreads.contains(threadOrGroup))) {
-                int status = ((JPDAThreadImpl) threadOrGroup).getState();
+        List<? extends JPDAThreadImpl> threads = 
threadsTranslation.getTranslated((o) ->
+                (o instanceof JPDAThreadImpl && (ignoredThreads == null || 
!ignoredThreads.contains(o))) ? (JPDAThreadImpl) o : null);
+        int n = threads.size();
+        if (n > 0) {
+            processInParallel(n, (i) -> {
+                JPDAThreadImpl thread = threads.get(i);
+                int status = thread.getState();
                 boolean invalid = (status == JPDAThread.STATE_NOT_STARTED ||
                                    status == JPDAThread.STATE_UNKNOWN ||
                                    status == JPDAThread.STATE_ZOMBIE);
                 if (!invalid) {
-                    ((JPDAThreadImpl) threadOrGroup).notifyToBeResumedNoFire();
+                    thread.notifyToBeResumedNoFire();
                 } else if (status == JPDAThread.STATE_UNKNOWN || status == 
JPDAThread.STATE_ZOMBIE) {
-                    threadsTranslation.remove(((JPDAThreadImpl) 
threadOrGroup).getThreadReference());
+                    threadsTranslation.remove(thread.getThreadReference());
                 }
-            }
+            });
         }
     }
     
@@ -1916,16 +1932,24 @@ public class JPDADebuggerImpl extends JPDADebugger {
                     //  Re-fire the changes
                     @Override
                     public void propertyChange(PropertyChangeEvent evt) {
-                        String propertyName = evt.getPropertyName();
-                        if 
(ThreadsCache.PROP_THREAD_STARTED.equals(propertyName)) {
-                            firePropertyChange(PROP_THREAD_STARTED, null, 
getThread((ThreadReference) evt.getNewValue()));
-                        }
-                        if 
(ThreadsCache.PROP_THREAD_DIED.equals(propertyName)) {
-                            firePropertyChange(PROP_THREAD_DIED, 
getThread((ThreadReference) evt.getOldValue()), null);
-                        }
-                        if 
(ThreadsCache.PROP_GROUP_ADDED.equals(propertyName)) {
-                            firePropertyChange(PROP_THREAD_GROUP_ADDED, null, 
getThreadGroup((ThreadGroupReference) evt.getNewValue()));
-                        }
+                        rpCreateThreads.post(() -> {
+                            String propertyName = evt.getPropertyName();
+                            if 
(ThreadsCache.PROP_THREAD_STARTED.equals(propertyName)) {
+                                JPDAThreadImpl thread = 
getThread((ThreadReference) evt.getNewValue());
+                                if 
(!thread.getName().contains(ThreadsCache.THREAD_NAME_FILTER_PATTERN)) {
+                                    firePropertyChange(PROP_THREAD_STARTED, 
null, thread);
+                                }
+                            }
+                            if 
(ThreadsCache.PROP_THREAD_DIED.equals(propertyName)) {
+                                JPDAThreadImpl thread = 
getThread((ThreadReference) evt.getOldValue());
+                                if 
(!thread.getName().contains(ThreadsCache.THREAD_NAME_FILTER_PATTERN)) {
+                                    firePropertyChange(PROP_THREAD_DIED, 
thread, null);
+                                }
+                            }
+                            if 
(ThreadsCache.PROP_GROUP_ADDED.equals(propertyName)) {
+                                firePropertyChange(PROP_THREAD_GROUP_ADDED, 
null, getThreadGroup((ThreadGroupReference) evt.getNewValue()));
+                            }
+                        });
                     }
                 });
             }
@@ -1961,13 +1985,63 @@ public class JPDADebuggerImpl extends JPDADebugger {
             }
         }
         int n = threadList.size();
-        List<JPDAThread> threads = new ArrayList<JPDAThread>(n);
-        for (int i = 0; i < n; i++) {
-            threads.add(getThread(threadList.get(i)));
+        final List<ThreadReference> tl = threadList;
+
+        // Create threads in parallel.
+        // Constructor of JPDAThreadImpl calls getName() and getStatus(), 
which take time on slow connection during remote debugging.
+        List<JPDAThread> threads = new ArrayList<>(n);
+        if (n > 0) {
+            AtomicBoolean filteredThreads = new AtomicBoolean(false);
+            processInParallel(n, (i) -> {
+                JPDAThreadImpl thread = getThread(tl.get(i));
+                if 
(!thread.getName().contains(ThreadsCache.THREAD_NAME_FILTER_PATTERN)) {
+                    threads.set(i, thread);
+                } else {
+                    threads.set(i, null);
+                    filteredThreads.set(true);
+                }
+            });
+            if (filteredThreads.get()) {
+                Iterator<JPDAThread> it = threads.iterator();
+                while (it.hasNext()) {
+                    if (it.next() == null) {
+                        it.remove();
+                    }
+                }
+            }
         }
         return Collections.unmodifiableList(threads);
     }
 
+    private void processInParallel(int n, Consumer<Integer> task) {
+        // Run by chunks:
+        int chunks = Math.min(RP_THROUGHPUT, n);
+        int chn = n / chunks + ((n % chunks) > 0 ? 1 : 0);
+        class TranslateThreads implements Runnable {
+
+            private final int ch;
+
+            private TranslateThreads(int ch) {
+                this.ch = ch;
+            }
+
+            @Override
+            public void run() {
+                int i0 = ch*chn;
+                for (int i = i0; i < i0 + chn && i < n; i++) {
+                    task.accept(i);
+                }
+            }
+        }
+        RequestProcessor.Task[] tasks = new RequestProcessor.Task[chunks];
+        for (int ch = 0; ch < chunks; ch++) {
+            tasks[ch] = rpCreateThreads.post(new TranslateThreads(ch));
+        }
+        for (int ch = 0; ch < chunks; ch++) {
+            tasks[ch].waitFinished();
+        }
+    }
+
     public JPDAThreadGroup[] getTopLevelThreadGroups() {
         ThreadsCache tc = getThreadsCache();
         if (tc == null) {
@@ -2135,43 +2209,6 @@ public class JPDADebuggerImpl extends JPDADebugger {
 
     // private helper methods 
..................................................
 
-    private static final java.util.regex.Pattern jvmVersionPattern =
-            java.util.regex.Pattern.compile 
("(\\d+)\\.(\\d+)\\.(\\d+)(_\\d+)?(-\\w+)?");
-    private static java.lang.reflect.Method  tcGenericSignatureMethod;
-    private static java.lang.reflect.Method  lvGenericSignatureMethod;
-
-
-    private void initGenericsSupport () {
-        tcGenericSignatureMethod = null;
-        if (Bootstrap.virtualMachineManager ().minorInterfaceVersion () >= 5) {
-            VirtualMachine vm;
-            synchronized (virtualMachineLock) {
-                vm = virtualMachine;
-            }
-            if (vm == null) {
-                return ;
-            }
-            try {
-                java.util.regex.Matcher m = 
jvmVersionPattern.matcher(VirtualMachineWrapper.version(vm));
-                if (m.matches ()) {
-                    int minor = Integer.parseInt (m.group (2));
-                    if (minor >= 5) {
-                        try {
-                            tcGenericSignatureMethod = TypeComponent.class.
-                                getMethod ("genericSignature", new Class [0]);
-                            lvGenericSignatureMethod = LocalVariable.class.
-                                getMethod ("genericSignature", new Class [0]);
-                        } catch (NoSuchMethodException e) {
-                            // the method is not available, ignore generics
-                        }
-                    }
-                }
-            } catch (InternalExceptionWrapper e) {
-            } catch (VMDisconnectedExceptionWrapper e) {
-            }
-        }
-    }
-
     private PropertyChangeEvent setStateNoFire (int state) {
         int o;
         synchronized (stateLock) {
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/SingleThreadWatcher.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/SingleThreadWatcher.java
index f5d6bcf..df2dee2 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/SingleThreadWatcher.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/SingleThreadWatcher.java
@@ -32,11 +32,14 @@ public class SingleThreadWatcher implements Runnable {
 
     private static final int DELAY = 3000;
 
-    private JPDAThreadImpl t;
+    private final JPDAThreadImpl t;
     private Task watchTask;
 
     public SingleThreadWatcher(JPDAThreadImpl t) {
         this.t = t;
+        if (!Boolean.valueOf(Bundle.USE_JPDA_DEADLOCK_DETECTOR())) {
+            return;
+        }
         //System.err.println("\nnew SingleThreadWatcher("+t+")");
         watchTask = t.getDebugger().getRequestProcessor().post(this, DELAY);
     }
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
index 44bcdf0..a770ea5 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java
@@ -605,6 +605,9 @@ implements Executor {
             return 0;
         } catch (InternalExceptionWrapper iex) {
             return 0;
+        } catch (IndexOutOfBoundsException iobe) {
+            // no frames on stack
+            return 0;
         } catch (InvalidStackFrameExceptionWrapper iex) {
             return 0;
         } catch (ObjectCollectedExceptionWrapper iex) {
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadGroupImpl.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadGroupImpl.java
index c42257f..1a05a1a 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadGroupImpl.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadGroupImpl.java
@@ -24,6 +24,7 @@ import com.sun.jdi.ThreadGroupReference;
 import com.sun.jdi.ThreadReference;
 
 import com.sun.jdi.VMDisconnectedException;
+import java.util.Arrays;
 import java.util.List;
 
 import org.netbeans.api.debugger.jpda.JPDAThread;
@@ -84,8 +85,14 @@ public class JPDAThreadGroupImpl implements JPDAThreadGroup {
         List<ThreadReference> l = tc.getThreads(tgr);
         int i, k = l.size ();
         JPDAThreadImpl[] ts = new JPDAThreadImpl[k];
-        for (i = 0; i < k; i++) {
-            ts [i] = debugger.getThread(l.get (i));
+        i = 0;
+        for (ThreadReference t : l) {
+            JPDAThreadImpl thread = debugger.getThread(t);
+            if 
(thread.getName().contains(ThreadsCache.THREAD_NAME_FILTER_PATTERN)) {
+                ts = Arrays.copyOf(ts, k - 1);
+            } else {
+                ts[i++] = thread;
+            }
         }
         return ts;
     }
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java
index 0e4b4f0..c430d9b 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java
@@ -626,35 +626,31 @@ public final class JPDAThreadImpl implements JPDAThread, 
Customizer, BeanContext
             }
             List l;
             CallStackFrame[] theCachedFrames = null;
-                int max;
-                synchronized (cachedFramesLock) {
-                    if (stackDepth < 0) {
-                        stackDepth = 
ThreadReferenceWrapper.frameCount(threadReference);
-                    }
-                    max = stackDepth;
+            CallStackFrame[] frames;
+            // synchronize the whole retrieval of frames to prevent from 
concurrent retrieval of the same frames.
+            synchronized (cachedFramesLock) {
+                if (stackDepth < 0) {
+                    stackDepth = 
ThreadReferenceWrapper.frameCount(threadReference);
                 }
+                int max = stackDepth;
                 if (to < 0) to = max; // Fight strange negative frame counts 
from http://www.netbeans.org/issues/show_bug.cgi?id=162448
                 from = Math.min(from, max);
                 to = Math.min(to, max);
-                if (to - from > 1) {  /*TODO: Frame caching cause problems 
with invalid frames. Some fix is necessary...
-                 *  as a workaround, frames caching is disabled.*/
-                    synchronized (cachedFramesLock) {
-                        if (from == cachedFramesFrom && to == cachedFramesTo) {
-                            return cachedFrames;
-                        }
-                        if (from >= cachedFramesFrom && to <= cachedFramesTo) {
-                            // TODO: Arrays.copyOfRange(cachedFrames, from - 
cachedFramesFrom, to);
-                            return copyOfRange(cachedFrames, from - 
cachedFramesFrom, to - cachedFramesFrom);
-                        }
-                        if (cachedFramesFrom >= 0 && cachedFramesTo > 
cachedFramesFrom) {
-                            int length = to - from;
-                            theCachedFrames = new CallStackFrame[length];
-                            for (int i = 0; i < length; i++) {
-                                if (i >= cachedFramesFrom && i < 
cachedFramesTo) {
-                                    theCachedFrames[i] = cachedFrames[i - 
cachedFramesFrom];
-                                } else {
-                                    theCachedFrames[i] = null;
-                                }
+                if (to - from > 1) {
+                    if (from == cachedFramesFrom && to == cachedFramesTo) {
+                        return cachedFrames;
+                    }
+                    if (from >= cachedFramesFrom && to <= cachedFramesTo) {
+                        return Arrays.copyOfRange(cachedFrames, from - 
cachedFramesFrom, to - cachedFramesFrom);
+                    }
+                    if (cachedFramesFrom >= 0 && cachedFramesTo > 
cachedFramesFrom) {
+                        int length = to - from;
+                        theCachedFrames = new CallStackFrame[length];
+                        for (int i = 0; i < length; i++) {
+                            if (i >= cachedFramesFrom && i < cachedFramesTo) {
+                                theCachedFrames[i] = cachedFrames[i - 
cachedFramesFrom];
+                            } else {
+                                theCachedFrames[i] = null;
                             }
                         }
                     }
@@ -694,25 +690,22 @@ public final class JPDAThreadImpl implements JPDAThread, 
Customizer, BeanContext
                 if (l == null) {
                     l = java.util.Collections.emptyList();
                 }
-            int n = l.size();
-            CallStackFrame[] frames = new CallStackFrame[n];
-            for (int i = 0; i < n; i++) {
-                if (theCachedFrames != null && theCachedFrames[i] != null) {
-                    frames[i] = theCachedFrames[i];
-                } else {
-                    frames[i] = new CallStackFrameImpl(this, (StackFrame) 
l.get(i), from + i, debugger);
-                }
-                if (from == 0 && i == 0 && currentOperation != null) {
-                    ((CallStackFrameImpl) 
frames[i]).setCurrentOperation(currentOperation);
+                int n = l.size();
+                frames = new CallStackFrame[n];
+                for (int i = 0; i < n; i++) {
+                    if (theCachedFrames != null && theCachedFrames[i] != null) 
{
+                        frames[i] = theCachedFrames[i];
+                    } else {
+                        frames[i] = new CallStackFrameImpl(this, (StackFrame) 
l.get(i), from + i, debugger);
+                    }
+                    if (from == 0 && i == 0 && currentOperation != null) {
+                        ((CallStackFrameImpl) 
frames[i]).setCurrentOperation(currentOperation);
+                    }
                 }
+                cachedFrames = frames;
+                cachedFramesFrom = from;
+                cachedFramesTo = to;
             }
-            //if (to - from > 1) {
-                synchronized (cachedFramesLock) {
-                    cachedFrames = frames;
-                    cachedFramesFrom = from;
-                    cachedFramesTo = to;
-                }
-            //}
             return frames;
         } catch (IncompatibleThreadStateException ex) {
             String msg = ex.getLocalizedMessage() + " " + getThreadStateLog();
@@ -745,17 +738,6 @@ public final class JPDAThreadImpl implements JPDAThread, 
Customizer, BeanContext
         }
     }
     
-    private static CallStackFrame[] copyOfRange(CallStackFrame[] original, int 
from, int to) {
-        // TODO: Use Arrays.copyOfRange(cachedFrames, from, to);
-        int newLength = to - from;
-        if (newLength < 0)
-            throw new IllegalArgumentException(from + " > " + to);
-        CallStackFrame[] copy = new CallStackFrame[newLength];
-        System.arraycopy(original, from, copy, 0,
-                         Math.min(original.length - from, newLength));
-        return copy;
-    }
-
     private void cleanCachedFrames() {
         synchronized (cachedFramesLock) {
             stackDepth = -1;
@@ -1229,6 +1211,10 @@ public final class JPDAThreadImpl implements JPDAThread, 
Customizer, BeanContext
     }
 
     public PropertyChangeEvent notifySuspended(boolean doFire, boolean 
explicitelyPaused) {
+        return notifySuspended(doFire, explicitelyPaused, true);
+    }
+
+    private PropertyChangeEvent notifySuspended(boolean doFire, boolean 
explicitelyPaused, boolean verifyStatusAndName) {
         if (loggerS.isLoggable(Level.FINE)) {
             loggerS.fine("["+threadName+"]: "+"notifySuspended(doFire = 
"+doFire+", explicitelyPaused = "+explicitelyPaused+")");
         }
@@ -1246,22 +1232,26 @@ public final class JPDAThreadImpl implements 
JPDAThread, Customizer, BeanContext
                 }
                 return null;
             }
-            try {
-                suspendCount = 
ThreadReferenceWrapper.suspendCount(threadReference);
-                threadName = ThreadReferenceWrapper.name(threadReference);
-            } catch (IllegalThreadStateExceptionWrapper ex) {
-                return null; // Thrown when thread has exited
-            } catch (ObjectCollectedExceptionWrapper ocex) {
-                return null; // The thread is gone
-            } catch (VMDisconnectedExceptionWrapper ex) {
-                return null; // The VM is gone
-            } catch (InternalExceptionWrapper ex) {
-                return null; // Something is gone
+            if (verifyStatusAndName) {
+                try {
+                    suspendCount = 
ThreadReferenceWrapper.suspendCount(threadReference);
+                    threadName = ThreadReferenceWrapper.name(threadReference);
+                } catch (IllegalThreadStateExceptionWrapper ex) {
+                    return null; // Thrown when thread has exited
+                } catch (ObjectCollectedExceptionWrapper ocex) {
+                    return null; // The thread is gone
+                } catch (VMDisconnectedExceptionWrapper ex) {
+                    return null; // The VM is gone
+                } catch (InternalExceptionWrapper ex) {
+                    return null; // Something is gone
+                }
+            } else {
+                suspendCount = 1;
             }
             //System.err.println("notifySuspended("+getName()+") suspendCount 
= "+suspendCount+", var suspended = "+suspended);
             suspendedNoFire = false;
             debugger.setCurrentSuspendedNoFireThread(null);
-            if ((!suspended || suspendedNoFire && doFire) && 
isThreadSuspended()) {
+            if ((!suspended || suspendedNoFire && doFire) && 
(!verifyStatusAndName || isThreadSuspended())) {
                 //System.err.println("  setting suspended = true");
                 suspended = true;
                 suspendedToFire = Boolean.TRUE;
@@ -1479,7 +1469,7 @@ public final class JPDAThreadImpl implements JPDAThread, 
Customizer, BeanContext
         }
         // Do not notify suspended state when was already unsuspended when 
started invoking.
         if (!wasUnsuspendedStateWhenInvoking) {
-            PropertyChangeEvent evt = notifySuspended(false, false);
+            PropertyChangeEvent evt = notifySuspended(false, false, false);
             if (evt != null) {
                 evt.setPropagationId("methodInvoke"); // NOI18N
                 pch.firePropertyChange(evt);
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ObjectTranslation.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ObjectTranslation.java
index cd96fa7..9d05e6c 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ObjectTranslation.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ObjectTranslation.java
@@ -30,14 +30,20 @@ import com.sun.jdi.ThreadReference;
 import com.sun.jdi.Value;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
 import org.netbeans.api.debugger.jpda.JPDAThread;
 
 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
+import org.openide.util.Exceptions;
 
 /**
  * Helps to translate one tree to another.
@@ -140,7 +146,8 @@ public final class ObjectTranslation {
     }
     
     /**
-     * Translates a debuggee Mirror to a wrapper object.
+     * Translates a debuggee Mirror to a wrapper object. It allows thread safe
+     * concurrent translation.
      *
      * @param o the Mirror object in the debuggee
      * @return translated object or <code>null</code> when the argument
@@ -148,13 +155,28 @@ public final class ObjectTranslation {
      */
     public Object translate (Mirror o) {
         Object r = null;
+        boolean create = false;
         synchronized (cache) {
-            WeakReference wr = cache.get (o);
-            if (wr != null)
-                r = wr.get ();
+            WeakReference wr = cache.get(o);
+            if (wr != null) {
+                r = wr.get();
+            }
             if (r == null) {
-                r = createTranslation (o);
-                cache.put (o, new WeakReference<Object>(r));
+                r = new TranslationFuture();
+                create = true;
+                cache.put (o, new WeakReference<>(r));
+            }
+        }
+        if (r instanceof TranslationFuture) {
+            TranslationFuture tf = (TranslationFuture) r;
+            if (create) {
+                r = createTranslation(o);
+                tf.complete(r);
+                synchronized (cache) {
+                    cache.put(o, new WeakReference<>(r));
+                }
+            } else {
+                r = tf.get();
             }
         }
         return r;
@@ -170,9 +192,13 @@ public final class ObjectTranslation {
     public Object translateExisting(Mirror o) {
         Object r = null;
         synchronized (cache) {
-            WeakReference wr = cache.get (o);
-            if (wr != null)
-                r = wr.get ();
+            WeakReference wr = cache.get(o);
+            if (wr != null) {
+                r = wr.get();
+                if (r instanceof TranslationFuture) {
+                    r = ((TranslationFuture) r).get();
+                }
+            }
         }
         return r;
     }
@@ -187,6 +213,9 @@ public final class ObjectTranslation {
             for (Iterator it = references.iterator(); it.hasNext(); ) {
                 WeakReference wr = (WeakReference) it.next();
                 Object r = wr.get();
+                if (r instanceof TranslationFuture) {
+                    r = ((TranslationFuture) r).get();
+                }
                 if (r != null) {
                     translated.add(r);
                 }
@@ -196,7 +225,35 @@ public final class ObjectTranslation {
     }
     
     /**
-     * Translates a debuggee Mirror to a wrapper object.
+     * Get existing translated objects.
+     *
+     * @param <T> the type of translated objects we're looking for
+     * @param test a test function that returns non-null objects of type
+     *             <code>T</code> that we're looking for
+     * @return a list of translated objects selected by the test function.
+     */
+    public <T> List<? extends T> getTranslated(Function<Object, T> test) {
+        List<T> translated = new ArrayList<>();
+        synchronized (cache) {
+            Collection references = cache.values();
+            for (Iterator it = references.iterator(); it.hasNext(); ) {
+                WeakReference wr = (WeakReference) it.next();
+                Object r = wr.get();
+                if (r instanceof TranslationFuture) {
+                    r = ((TranslationFuture) r).get();
+                }
+                T t;
+                if (r != null && (t = test.apply(r)) != null) {
+                    translated.add(t);
+                }
+            }
+        }
+        return translated;
+    }
+    
+    /**
+     * Translates a debuggee Mirror to a wrapper object. It allows thread safe
+     * concurrent translation.
      *
      * @param o the Mirror object in the debuggee
      * @param v an additional argument used for the translation
@@ -206,17 +263,32 @@ public final class ObjectTranslation {
     public Object translate (Mirror o, Object v) {
         Object r = null;
         boolean verify = false;
+        boolean create = false;
         synchronized (cache) {
-            WeakReference wr = cache.get (o);
-            if (wr != null)
-                r = wr.get ();
+            WeakReference wr = cache.get(o);
+            if (wr != null) {
+                r = wr.get();
+            }
             if (r == null) {
-                r = createTranslation (o, v);
-                cache.put (o, new WeakReference<Object>(r));
+                r = new TranslationFuture();
+                create = true;
+                cache.put(o, new WeakReference<>(r));
             } else {
                 verify = true;
             }
         }
+        if (r instanceof TranslationFuture) {
+            TranslationFuture tf = (TranslationFuture) r;
+            if (create) {
+                r = createTranslation(o, v);
+                tf.complete(r);
+                synchronized (cache) {
+                    cache.put(o, new WeakReference<>(r));
+                }
+            } else {
+                r = tf.get();
+            }
+        }
         if (verify) {
             verifyTranslation(r, o, v);
         }
@@ -273,5 +345,16 @@ public final class ObjectTranslation {
     public static ObjectTranslation createLocalsTranslation(JPDADebuggerImpl 
debugger) {
         return new ObjectTranslation(debugger, LOCALS_ID);
     }
-    
+
+    private static final class TranslationFuture extends 
CompletableFuture<Object> {
+
+        @Override
+        public Object get() {
+            try {
+                return super.get();
+            } catch (ExecutionException | InterruptedException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
 }
diff --git 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ThreadsCache.java
 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ThreadsCache.java
index f6c428a..d2fb2f9 100644
--- 
a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ThreadsCache.java
+++ 
b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/ThreadsCache.java
@@ -149,28 +149,12 @@ public class ThreadsCache implements Executor {
     
     private synchronized void init() throws VMDisconnectedExceptionWrapper, 
InternalExceptionWrapper {
         allThreads = new 
ArrayList<ThreadReference>(VirtualMachineWrapper.allThreads(vm));
-        filterThreads(allThreads);
     }
     
-    private void filterThreads(List<ThreadReference> threads) {
-        for (int i = 0; i < threads.size(); i++) {
-            ThreadReference tr = threads.get(i);
-            try {
-                if 
(ThreadReferenceWrapper.name(tr).contains(THREAD_NAME_FILTER_PATTERN)) {
-                    threads.remove(i);
-                    i--;
-                }
-            } catch (Exception ex) {
-                // continue
-            }
-        }
-    }
-
     private void initGroups(ThreadGroupReference group) {
         try {
             List<ThreadGroupReference> groups = new 
ArrayList<>(ThreadGroupReferenceWrapper.threadGroups0(group));
             List<ThreadReference> threads = new 
ArrayList<>(ThreadGroupReferenceWrapper.threads0(group));
-            filterThreads(threads);
             groupMap.put(group, groups);
             threadMap.put(group, threads);
             for (ThreadGroupReference g : groups) {
@@ -562,7 +546,6 @@ public class ThreadsCache implements Executor {
             } catch (VMDisconnectedExceptionWrapper vmdex) {
                 return ;
             }
-            filterThreads(allThreadsNew);
 
             newThreads = new ArrayList<ThreadReference>(allThreadsNew);
             newThreads.removeAll(allThreads);
diff --git a/java/java.lsp.server/manifest.mf b/java/java.lsp.server/manifest.mf
index 32384b0..78c39b3 100644
--- a/java/java.lsp.server/manifest.mf
+++ b/java/java.lsp.server/manifest.mf
@@ -3,4 +3,5 @@ AutoUpdate-Show-In-Client: true
 OpenIDE-Module: org.netbeans.modules.java.lsp.server
 OpenIDE-Module-Implementation-Version: 1
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/java/lsp/server/Bundle.properties
+OpenIDE-Module-Layer: org/netbeans/modules/java/lsp/server/layer.xml
 
diff --git 
a/java/java.lsp.server/nbcode/branding/modules/org-netbeans-modules-debugger-jpda.jar/org/netbeans/modules/debugger/jpda/Bundle.properties
 
b/java/java.lsp.server/nbcode/branding/modules/org-netbeans-modules-debugger-jpda.jar/org/netbeans/modules/debugger/jpda/Bundle.properties
new file mode 100644
index 0000000..98e59d7
--- /dev/null
+++ 
b/java/java.lsp.server/nbcode/branding/modules/org-netbeans-modules-debugger-jpda.jar/org/netbeans/modules/debugger/jpda/Bundle.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+USE_JPDA_DEADLOCK_DETECTOR=false
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
index d22b718..08b133b 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
@@ -31,6 +31,8 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.lsp4j.debug.Capabilities;
@@ -100,6 +102,9 @@ import org.openide.util.RequestProcessor;
  */
 public final class NbProtocolServer implements IDebugProtocolServer, 
LspSession.ScheduledServer {
 
+    private static final Logger LOGGER = 
Logger.getLogger(NbProtocolServer.class.getName());
+    private static final Level LOGLEVEL = Level.FINE;
+
     private final DebugAdapterContext context;
     private final NbLaunchRequestHandler launchRequestHandler = new 
NbLaunchRequestHandler();
     private final NbAttachRequestHandler attachRequestHandler = new 
NbAttachRequestHandler();
@@ -107,6 +112,7 @@ public final class NbProtocolServer implements 
IDebugProtocolServer, LspSession.
     private final NbBreakpointsRequestHandler breakpointsRequestHandler = new 
NbBreakpointsRequestHandler();
     private final NbVariablesRequestHandler variablesRequestHandler = new 
NbVariablesRequestHandler();
     private final RequestProcessor evaluationRP = new 
RequestProcessor(NbProtocolServer.class.getName(), 3);
+    private final RequestProcessor threadsRP = new 
RequestProcessor(NbProtocolServer.class.getName(), 1);
     private boolean initialized = false;
     private Future<Void> runningServer;
 
@@ -284,72 +290,78 @@ public final class NbProtocolServer implements 
IDebugProtocolServer, LspSession.
 
     @Override
     public CompletableFuture<StackTraceResponse> 
stackTrace(StackTraceArguments args) {
-        CompletableFuture<StackTraceResponse> future = new 
CompletableFuture<>();
         if (context.getDebugSession() == null) {
+            CompletableFuture<StackTraceResponse> future = new 
CompletableFuture<>();
             ErrorUtilities.completeExceptionally(future, "Debug Session 
doesn't exist.", ResponseErrorCode.InvalidParams);
+            return future;
         } else {
-            List<StackFrame> result = new ArrayList<>();
-            int cnt = 0;
-            DVThread dvThread = 
context.getThreadsProvider().getThread(args.getThreadId());
-            if (dvThread != null) {
-                cnt = dvThread.getFrameCount();
-                int from = args.getStartFrame() != null ? args.getStartFrame() 
: 0;
-                int to = args.getLevels() != null ? from + args.getLevels() : 
Integer.MAX_VALUE;
-                List<DVFrame> stackFrames = dvThread.getFrames(from, to);
-                for (DVFrame frame : stackFrames) {
-                    int frameId = 
context.getThreadsProvider().getThreadObjects().addObject(args.getThreadId(), 
new NbFrame(args.getThreadId(), frame));
-                    int line = frame.getLine();
-                    if (line < 0) { // unknown
-                        line = 0;
-                    }
-                    int column = frame.getColumn();
-                    if (column < 0) { // unknown
-                        column = 0;
-                    }
-                    StackFrame stackFrame = new StackFrame();
-                    stackFrame.setId(frameId);
-                    stackFrame.setName(frame.getName());
-                    URI sourceURI = frame.getSourceURI();
-                    if (sourceURI != null) {
-                        Source source = new Source();
-                        String scheme = sourceURI.getScheme();
-                        if (null == scheme || scheme.isEmpty() || 
"file".equalsIgnoreCase(scheme)) {
-                            
source.setName(Paths.get(sourceURI).getFileName().toString());
-                            source.setPath(sourceURI.getPath());
-                            source.setSourceReference(0);
-                        } else {
-                            int ref = context.createSourceReference(sourceURI, 
frame.getSourceMimeType());
-                            String path = sourceURI.getPath();
-                            if (path == null) {
-                                path = sourceURI.getSchemeSpecificPart();
-                            }
-                            if (path != null) {
-                                int sepIndex = Math.max(path.lastIndexOf('/'), 
path.lastIndexOf(File.separatorChar));
-                                source.setName(path.substring(sepIndex + 1));
-                                if ("jar".equalsIgnoreCase(scheme)) {
-                                    try {
-                                        path = new URI(path).getPath();
-                                    } catch (URISyntaxException ex) {
-                                        // ignore, we just tried
+            return CompletableFuture.supplyAsync(() -> {
+                LOGGER.log(LOGLEVEL, "stackTrace() START");
+                long t1 = System.nanoTime();
+                List<StackFrame> result = new ArrayList<>();
+                int cnt = 0;
+                DVThread dvThread = 
context.getThreadsProvider().getThread(args.getThreadId());
+                if (dvThread != null) {
+                    cnt = dvThread.getFrameCount();
+                    int from = args.getStartFrame() != null ? 
args.getStartFrame() : 0;
+                    int to = args.getLevels() != null ? from + 
args.getLevels() : Integer.MAX_VALUE;
+                    List<DVFrame> stackFrames = dvThread.getFrames(from, to);
+                    for (DVFrame frame : stackFrames) {
+                        int frameId = 
context.getThreadsProvider().getThreadObjects().addObject(args.getThreadId(), 
new NbFrame(args.getThreadId(), frame));
+                        int line = frame.getLine();
+                        if (line < 0) { // unknown
+                            line = 0;
+                        }
+                        int column = frame.getColumn();
+                        if (column < 0) { // unknown
+                            column = 0;
+                        }
+                        StackFrame stackFrame = new StackFrame();
+                        stackFrame.setId(frameId);
+                        stackFrame.setName(frame.getName());
+                        URI sourceURI = frame.getSourceURI();
+                        if (sourceURI != null) {
+                            Source source = new Source();
+                            String scheme = sourceURI.getScheme();
+                            if (null == scheme || scheme.isEmpty() || 
"file".equalsIgnoreCase(scheme)) {
+                                
source.setName(Paths.get(sourceURI).getFileName().toString());
+                                source.setPath(sourceURI.getPath());
+                                source.setSourceReference(0);
+                            } else {
+                                int ref = 
context.createSourceReference(sourceURI, frame.getSourceMimeType());
+                                String path = sourceURI.getPath();
+                                if (path == null) {
+                                    path = sourceURI.getSchemeSpecificPart();
+                                }
+                                if (path != null) {
+                                    int sepIndex = 
Math.max(path.lastIndexOf('/'), path.lastIndexOf(File.separatorChar));
+                                    source.setName(path.substring(sepIndex + 
1));
+                                    if ("jar".equalsIgnoreCase(scheme)) {
+                                        try {
+                                            path = new URI(path).getPath();
+                                        } catch (URISyntaxException ex) {
+                                            // ignore, we just tried
+                                        }
                                     }
+                                    source.setPath(path);
                                 }
-                                source.setPath(path);
+                                source.setSourceReference(ref);
                             }
-                            source.setSourceReference(ref);
+                            stackFrame.setSource(source);
                         }
-                        stackFrame.setSource(source);
+                        stackFrame.setLine(line);
+                        stackFrame.setColumn(column);
+                        result.add(stackFrame);
                     }
-                    stackFrame.setLine(line);
-                    stackFrame.setColumn(column);
-                    result.add(stackFrame);
                 }
-            }
-            StackTraceResponse response = new StackTraceResponse();
-            response.setStackFrames(result.toArray(new 
StackFrame[result.size()]));
-            response.setTotalFrames(cnt);
-            future.complete(response);
+                StackTraceResponse response = new StackTraceResponse();
+                response.setStackFrames(result.toArray(new 
StackFrame[result.size()]));
+                response.setTotalFrames(cnt);
+                long t2 = System.nanoTime();
+                LOGGER.log(LOGLEVEL, "stackTrace() END after {0} ns", (t2 - 
t1));
+                return response;
+            }, threadsRP);
         }
-        return future;
     }
 
     @Override
@@ -427,22 +439,28 @@ public final class NbProtocolServer implements 
IDebugProtocolServer, LspSession.
 
     @Override
     public CompletableFuture<ThreadsResponse> threads() {
-        CompletableFuture<ThreadsResponse> future = new CompletableFuture<>();
         if (context.getDebugSession() == null) {
+            CompletableFuture<ThreadsResponse> future = new 
CompletableFuture<>();
             ErrorUtilities.completeExceptionally(future, "Debug Session 
doesn't exist.", ResponseErrorCode.InvalidParams);
+            return future;
         } else {
-            List<org.eclipse.lsp4j.debug.Thread> result = new ArrayList<>();
-            context.getThreadsProvider().visitThreads((id, dvThread) -> {
-                org.eclipse.lsp4j.debug.Thread thread = new 
org.eclipse.lsp4j.debug.Thread();
-                thread.setId(id);
-                thread.setName(dvThread.getName());
-                result.add(thread);
-            });
-            ThreadsResponse response = new ThreadsResponse();
-            response.setThreads(result.toArray(new 
org.eclipse.lsp4j.debug.Thread[result.size()]));
-            future.complete(response);
+            return CompletableFuture.supplyAsync(() -> {
+                LOGGER.log(LOGLEVEL, "threads() START");
+                long t1 = System.nanoTime();
+                List<org.eclipse.lsp4j.debug.Thread> result = new 
ArrayList<>();
+                context.getThreadsProvider().visitThreads((id, dvThread) -> {
+                    org.eclipse.lsp4j.debug.Thread thread = new 
org.eclipse.lsp4j.debug.Thread();
+                    thread.setId(id);
+                    thread.setName(dvThread.getName());
+                    result.add(thread);
+                });
+                ThreadsResponse response = new ThreadsResponse();
+                response.setThreads(result.toArray(new 
org.eclipse.lsp4j.debug.Thread[result.size()]));
+                long t2 = System.nanoTime();
+                LOGGER.log(LOGLEVEL, "threads() END after {0} ns", (t2 - t1));
+                return response;
+            }, threadsRP);
         }
-        return future;
     }
     
     private EvaluateResponse passToApplication(String args) {
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
index b1627d2..7da7ca5 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
@@ -21,6 +21,8 @@ package 
org.netbeans.modules.java.lsp.server.debugging.variables;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.lsp4j.debug.SetVariableArguments;
 import org.eclipse.lsp4j.debug.SetVariableResponse;
@@ -31,11 +33,13 @@ import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
 import org.netbeans.api.debugger.Session;
 
 import org.netbeans.modules.java.lsp.server.debugging.DebugAdapterContext;
+import org.netbeans.modules.java.lsp.server.debugging.NbProtocolServer;
 import org.netbeans.modules.java.lsp.server.debugging.NbScope;
 import org.netbeans.modules.java.lsp.server.debugging.launch.NbDebugSession;
 import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
 import org.netbeans.spi.viewmodel.Models;
 import org.netbeans.spi.viewmodel.UnknownTypeException;
+import org.openide.util.RequestProcessor;
 
 /**
  *
@@ -43,72 +47,78 @@ import org.netbeans.spi.viewmodel.UnknownTypeException;
  */
 public final class NbVariablesRequestHandler {
 
+    private static final Logger LOGGER = 
Logger.getLogger(NbProtocolServer.class.getName());
+    private static final Level LOGLEVEL = Level.FINE;
+
     private static final String LOCALS_VIEW_NAME = "LocalsView";
     private static final String LOCALS_VALUE_COLUMN_ID = "LocalsValue";
     private static final String LOCALS_TO_STRING_COLUMN_ID = "LocalsToString";
     private static final String LOCALS_TYPE_COLUMN_ID = "LocalsType";
 
     private final ViewModel.Provider localsModelProvider;
+    private final RequestProcessor variablesRP = new 
RequestProcessor(NbVariablesRequestHandler.class.getName(), 2);
 
     public NbVariablesRequestHandler() {
         this.localsModelProvider = new ViewModel.Provider(LOCALS_VIEW_NAME);
     }
 
     public CompletableFuture<VariablesResponse> variables(VariablesArguments 
arguments, DebugAdapterContext context) {
-        CompletableFuture<VariablesResponse> future = new 
CompletableFuture<>();
-
-        VariablesResponse response = new VariablesResponse();
-        Object container = 
context.getThreadsProvider().getThreadObjects().getObject(arguments.getVariablesReference());
-        if (container == null) {
-            // Nothing, or an old container
-            response.setVariables(new Variable[0]);
-        } else {
-            Session session = context.getDebugSession().getSession();
-            Models.CompoundModel localsModel = 
localsModelProvider.getModel(session);
-            int threadId;
-            if (container instanceof NbScope) {
-                threadId = ((NbScope) container).getFrame().getThreadId();
-                container = localsModel.getRoot();
+        return CompletableFuture.supplyAsync(() -> {
+            LOGGER.log(LOGLEVEL, "variables() START");
+            long t1 = System.nanoTime();
+            VariablesResponse response = new VariablesResponse();
+            Object container = 
context.getThreadsProvider().getThreadObjects().getObject(arguments.getVariablesReference());
+            if (container == null) {
+                // Nothing, or an old container
+                response.setVariables(new Variable[0]);
             } else {
-                threadId = 
context.getThreadsProvider().getThreadObjects().findObjectThread(arguments.getVariablesReference());
-            }
-            List<Variable> list = new ArrayList<>();
-            try {
-                Object[] children;
-                int count = arguments.getCount() != null ? 
arguments.getCount() : 0;
-                if (count > 0) {
-                    int start = arguments.getStart() != null ? 
arguments.getStart() : 0;
-                    children = localsModel.getChildren(container, start, start 
+ count);
+                Session session = context.getDebugSession().getSession();
+                Models.CompoundModel localsModel = 
localsModelProvider.getModel(session);
+                int threadId;
+                if (container instanceof NbScope) {
+                    threadId = ((NbScope) container).getFrame().getThreadId();
+                    container = localsModel.getRoot();
                 } else {
-                    children = localsModel.getChildren(container, 0, 
Integer.MAX_VALUE);
+                    threadId = 
context.getThreadsProvider().getThreadObjects().findObjectThread(arguments.getVariablesReference());
                 }
-                for (Object child : children) {
-                    String name = localsModel.getDisplayName(child);
-                    String value;
-                    try {
-                        value = String.valueOf(localsModel.getValueAt(child, 
LOCALS_TO_STRING_COLUMN_ID));
-                    } catch (UnknownTypeException ex) {
-                        value = String.valueOf(localsModel.getValueAt(child, 
LOCALS_VALUE_COLUMN_ID));
+                List<Variable> list = new ArrayList<>();
+                try {
+                    Object[] children;
+                    int count = arguments.getCount() != null ? 
arguments.getCount() : 0;
+                    if (count > 0) {
+                        int start = arguments.getStart() != null ? 
arguments.getStart() : 0;
+                        children = localsModel.getChildren(container, start, 
start + count);
+                    } else {
+                        children = localsModel.getChildren(container, 0, 
Integer.MAX_VALUE);
                     }
-                    String type = String.valueOf(localsModel.getValueAt(child, 
LOCALS_TYPE_COLUMN_ID));
-                    Variable variable = new Variable();
-                    variable.setName(name);
-                    variable.setValue(value);
-                    variable.setType(type);
-                    if (!localsModel.isLeaf(child)) {
-                        int id = 
context.getThreadsProvider().getThreadObjects().addObject(threadId, child);
-                        variable.setVariablesReference(id);
+                    for (Object child : children) {
+                        String name = localsModel.getDisplayName(child);
+                        String value;
+                        try {
+                            value = 
String.valueOf(localsModel.getValueAt(child, LOCALS_TO_STRING_COLUMN_ID));
+                        } catch (UnknownTypeException ex) {
+                            value = 
String.valueOf(localsModel.getValueAt(child, LOCALS_VALUE_COLUMN_ID));
+                        }
+                        String type = 
String.valueOf(localsModel.getValueAt(child, LOCALS_TYPE_COLUMN_ID));
+                        Variable variable = new Variable();
+                        variable.setName(name);
+                        variable.setValue(value);
+                        variable.setType(type);
+                        if (!localsModel.isLeaf(child)) {
+                            int id = 
context.getThreadsProvider().getThreadObjects().addObject(threadId, child);
+                            variable.setVariablesReference(id);
+                        }
+                        list.add(variable);
                     }
-                    list.add(variable);
+                } catch (UnknownTypeException e) {
+                    throw 
ErrorUtilities.createResponseErrorException(e.getMessage(), 
ResponseErrorCode.InternalError);
                 }
-            } catch (UnknownTypeException e) {
-                ErrorUtilities.completeExceptionally(future, e.getMessage(), 
ResponseErrorCode.InternalError);
-                return future;
+                response.setVariables(list.toArray(new Variable[list.size()]));
             }
-            response.setVariables(list.toArray(new Variable[list.size()]));
-        }
-        future.complete(response);
-        return future;
+            long t2 = System.nanoTime();
+            LOGGER.log(LOGLEVEL, "variables() END after {0} ns", (t2 - t1));
+            return response;
+        }, variablesRP);
     }
 
     public CompletableFuture<SetVariableResponse> 
setVariable(SetVariableArguments args, DebugAdapterContext context) {
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/layer.xml 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/layer.xml
new file mode 100644
index 0000000..311b57a
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/layer.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" 
"http://www.netbeans.org/dtds/filesystem-1_2.dtd";>
+<filesystem>
+    <folder name="Debugger">
+        <file 
name="org-netbeans-modules-debugger-jpda-ui-CurrentThreadAnnotationListener.instance_hidden"/>
+        <folder name="netbeans-JPDASession">
+            <!--file 
name="org-netbeans-modules-debugger-jpda-ui-focus-FocusSuspendController.instance_hidden"/-->
+        </folder>
+    </folder>
+</filesystem>
\ No newline at end of file

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to