573120: Exception handling in GarbageCleaner.java

Handle DTFJ references not found in heap scan

Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=573120
Change-Id: Ib96f547e1d933c76fef62b3ac7221b2c3470bcf5
diff --git a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/DTFJIndexBuilder.java b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/DTFJIndexBuilder.java
index f98ae89..e55a61a 100644
--- a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/DTFJIndexBuilder.java
+++ b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/DTFJIndexBuilder.java
@@ -748,6 +748,7 @@
     private int msgNnoSuperClassForArray = errorCount;

     private int msgNproblemReadingJavaStackFrame = errorCount;

     private int msgNskipHeapObject = errorCount;

+    private int msgNthreadBlocking = errorCount;

 

     /*

      * (non-Javadoc)

@@ -1266,7 +1267,7 @@
                 continue;

             JavaThread th = (JavaThread) next;

             long threadAddress = findMissingObjectsFromJavaThread(th, missingObjects, listener);

-            if (getExtraInfo)

+            if (getExtraInfo || useDTFJRoots)

             {

                 // Scan stack frames for pseudo-classes

                 int frameId = 0;

@@ -1279,84 +1280,100 @@
                         continue;

                     JavaStackFrame jf = (JavaStackFrame) next2;

                     if (listener.isCanceled()) { throw new IProgressListener.OperationCanceledException(); }

-                    JavaLocation jl = null;

-                    try

+                    if (useDTFJRoots)

                     {

-                        jl = jf.getLocation();

-                        JavaMethod jm = jl.getMethod();

-                        long frameAddress = getFrameAddress(jf, prevFrameAddress, pointerSize);

-                        prevFrameAddress = frameAddress;

-                        if (frameAddress != 0)

+                        Iterator<?> it = null;

+                        try

                         {

-                            if (indexToAddress0.reverse(frameAddress) < 0)

+                            it = jf.getHeapRoots();

+                        }

+                        catch (LinkageError e)

+                        {

+                        }

+                        if (it != null)

+                            findMissingReferences(missingObjects, it, listener);

+                    }

+                    if (getExtraInfo)

+                    {

+                        JavaLocation jl = null;

+                        try

+                        {

+                            jl = jf.getLocation();

+                            JavaMethod jm = jl.getMethod();

+                            long frameAddress = getFrameAddress(jf, prevFrameAddress, pointerSize);

+                            prevFrameAddress = frameAddress;

+                            if (frameAddress != 0)

                             {

-                                long methodAddress = getMethodAddress(jm, listener);

-                                if (!allFrames.containsKey(frameAddress))

+                                if (indexToAddress0.reverse(frameAddress) < 0)

                                 {

-                                    if (!getExtraInfo3)

-                                        allMethods.add(jm);

-                                    allFrames.put(frameAddress, methodAddress);

+                                    long methodAddress = getMethodAddress(jm, listener);

+                                    if (!allFrames.containsKey(frameAddress))

+                                    {

+                                        if (!getExtraInfo3)

+                                            allMethods.add(jm);

+                                        allFrames.put(frameAddress, methodAddress);

+                                    }

+                                    else

+                                    {

+                                        String newMethodName;

+                                        try

+                                        {

+                                            newMethodName = getMethodName(jm, listener);

+                                        }

+                                        catch (CorruptDataException e)

+                                        {

+                                            newMethodName = format(methodAddress);

+                                        }

+                                        String oldMethodName;

+                                        long oldMethodAddress = allFrames.get(frameAddress);

+                                        try

+                                        {

+                                            JavaMethod oldJm = methodAddresses.get(allFrames.get(frameAddress));

+                                            if (oldJm != null)

+                                            {

+                                                oldMethodName = getMethodName(oldJm, listener);

+                                            }

+                                            else

+                                            {

+                                                oldMethodName = format(oldMethodAddress);

+                                            }

+                                        }

+                                        catch (CorruptDataException e)

+                                        {

+                                            oldMethodName = format(allFrames.get(oldMethodAddress));

+                                        }

+                                        listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

+                                                        Messages.DTFJIndexBuilder_DuplicateJavaStackFrame, frameId,

+                                                        format(frameAddress), oldMethodName, newMethodName,

+                                                        format(threadAddress)), null);

+                                    }

                                 }

                                 else

                                 {

-                                    String newMethodName;

-                                    try

-                                    {

-                                        newMethodName = getMethodName(jm, listener);

-                                    }

-                                    catch (CorruptDataException e)

-                                    {

-                                        newMethodName = format(methodAddress);

-                                    }

-                                    String oldMethodName;

-                                    long oldMethodAddress = allFrames.get(frameAddress);

-                                    try

-                                    {

-                                        JavaMethod oldJm = methodAddresses.get(allFrames.get(frameAddress));

-                                        if (oldJm != null)

-                                        {

-                                            oldMethodName = getMethodName(oldJm, listener);

-                                        }

-                                        else

-                                        {

-                                            oldMethodName = format(oldMethodAddress);

-                                        }

-                                    }

-                                    catch (CorruptDataException e)

-                                    {

-                                        oldMethodName = format(allFrames.get(oldMethodAddress));

-                                    }

                                     listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

-                                                    Messages.DTFJIndexBuilder_DuplicateJavaStackFrame, frameId,

-                                                    format(frameAddress), oldMethodName, newMethodName,

-                                                    format(threadAddress)), null);

+                                                    Messages.DTFJIndexBuilder_IgnoringJavaStackFrame, frameId,

+                                                    format(frameAddress), format(threadAddress)), null);

                                 }

                             }

+                        }

+                        catch (CorruptDataException e)

+                        {

+                            if (jl != null)

+                            {

+                                if (msgNproblemReadingJavaStackFrame-- > 0)

+                                    listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

+                                                    Messages.DTFJIndexBuilder_ProblemReadingJavaStackFrameLocation, frameId,

+                                                    jl, format(threadAddress)), e);

+                            }

                             else

                             {

-                                listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

-                                                Messages.DTFJIndexBuilder_IgnoringJavaStackFrame, frameId,

-                                                format(frameAddress), format(threadAddress)), null);

+                                if (msgNproblemReadingJavaStackFrame-- > 0)

+                                    listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

+                                                    Messages.DTFJIndexBuilder_ProblemReadingJavaStackFrame, frameId,

+                                                    format(threadAddress)), e);

                             }

                         }

                     }

-                    catch (CorruptDataException e)

-                    {

-                        if (jl != null)

-                        {

-                            if (msgNproblemReadingJavaStackFrame-- > 0)

-                                listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

-                                                Messages.DTFJIndexBuilder_ProblemReadingJavaStackFrameLocation, frameId,

-                                                jl, format(threadAddress)), e);

-                        }

-                        else

-                        {

-                            if (msgNproblemReadingJavaStackFrame-- > 0)

-                                listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

-                                                Messages.DTFJIndexBuilder_ProblemReadingJavaStackFrame, frameId,

-                                                format(threadAddress)), e);

-                        }

-                    }

                 }

             }

         }

@@ -1428,6 +1445,22 @@
         }

         listener.worked(1);

         workCountSoFar += 1;

+        listener.subTask(Messages.DTFJIndexBuilder_FindingMissingHeapRoots);

+        if (useDTFJRoots)

+        {

+            Iterator<?> it = null;

+            try

+            {

+                it = dtfjInfo.getJavaRuntime().getHeapRoots();

+            }

+            catch (LinkageError e)

+            {

+            }

+            if (it != null)

+                findMissingReferences(missingObjects, it, listener);

+        }

+        listener.worked(1);

+        workCountSoFar += 1;

         listener.subTask(Messages.DTFJIndexBuilder_AddingMissingObjects);

         for (Iterator<HashMapLongObject.Entry<JavaObject>> it = missingObjects.entries(); it.hasNext(); )

         {

@@ -2462,6 +2495,8 @@
         skippedMessages += Math.max(0, -msgNoutboundReferences);

         skippedMessages += Math.max(0, -msgNnoSuperClassForArray);

         skippedMessages += Math.max(0, -msgNproblemReadingJavaStackFrame);

+        skippedMessages += Math.max(0, -msgNskipHeapObject);

+        skippedMessages += Math.max(0, -msgNthreadBlocking);

         if (skippedMessages > 0)

         {

             listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

@@ -2483,6 +2518,46 @@
         listener.done();

     }

 

+    private void findMissingReferences(HashMapLongObject<JavaObject> missingObjects, Iterator<?> it,

+                    IProgressListener listener)

+    {

+        for (; it.hasNext();)

+        {

+            Object next1 = it.next();

+            if (isCorruptData(next1, listener, Messages.DTFJIndexBuilder_CorruptDataReadingRoots, dtfjInfo.getJavaRuntime()))

+                continue;

+            JavaReference r = (JavaReference) next1;

+            try

+            {

+                Object o = r.getTarget();

+                JavaObject jo = null;

+                if (o instanceof JavaObject)

+                {

+                    jo = (JavaObject) o;

+                }

+                else if (o instanceof JavaClass)

+                {

+                    JavaClass jc = (JavaClass)o;

+                    jo = jc.getObject();

+                }

+                if (jo != null)

+                {

+                    long objaddr = jo.getID().getAddress();

+                    if (indexToAddress0.reverse(objaddr) < 0)

+                    {

+                        missingObjects.put(objaddr, jo);

+                    }

+                }

+            }

+            catch (DataUnavailable e)

+            {

+            }

+            catch (CorruptDataException e)

+            {

+            }

+        }

+    }

+

     /**

      * Add outbound references for method types and pseudo types

      * @param methodTypeAddr

@@ -4140,7 +4215,8 @@
         }

         catch (DTFJException e)

         {

-            listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

+            if (msgNthreadBlocking-- > 0)

+                listener.sendUserMessage(Severity.WARNING, MessageFormat.format(

                             Messages.DTFJIndexBuilder_ProblemReadingJavaThreadInformationFor, th), e);

         }

     }

@@ -7136,18 +7212,24 @@
     private void addRoot(HashMapIntObject<List<XGCRootInfo>> gc, long obj, long ctx, int type)

     {

         XGCRootInfo rri = new XGCRootInfo(obj, ctx, newRootType(type));

+        int objectId = indexToAddress.reverse(rri.getObjectAddress());

+        if (objectId < 0)

+        {

+            // If the object isn't known, can't add it to the mapping

+            if (debugInfo) debugPrint("addRoot with unrecognised object address " + format(obj)); //$NON-NLS-1$

+            return;

+        }

         int contextId = indexToAddress.reverse(rri.getContextAddress());

         if (contextId < 0)

         {

             rri = new XGCRootInfo(obj, obj, newRootType(type));

-            rri.setContextId(indexToAddress.reverse(rri.getObjectAddress()));

+            rri.setContextId(objectId);

         }

         else

         {

             rri.setContextId(contextId);

         }

-        rri.setObjectId(indexToAddress.reverse(rri.getObjectAddress()));

-        int objectId = rri.getObjectId();

+        rri.setObjectId(objectId);

         List<XGCRootInfo> rootsForID = gc.get(objectId);

         if (rootsForID == null)

         {

diff --git a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/Messages.java b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/Messages.java
index da669b9..2b4242b 100644
--- a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/Messages.java
+++ b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/Messages.java
@@ -1,10 +1,10 @@
 /*******************************************************************************

- * Copyright (c) 2009,2020 IBM Corporation.

+ * Copyright (c) 2009,2021 IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

- * https://www.eclipse.org/legal/epl-2.0/
- *
+ * https://www.eclipse.org/legal/epl-2.0/

+ *

  * SPDX-License-Identifier: EPL-2.0

  *

  * Contributors:

@@ -89,6 +89,7 @@
     public static String DTFJIndexBuilder_FindingClassLoaderObjects;

     public static String DTFJIndexBuilder_FindingClassLoaders;

     public static String DTFJIndexBuilder_FindingJVM;

+    public static String DTFJIndexBuilder_FindingMissingHeapRoots;

     public static String DTFJIndexBuilder_FindingMonitorObjects;

     public static String DTFJIndexBuilder_FindingObjects;

     public static String DTFJIndexBuilder_FindingOutboundReferencesForClasses;

diff --git a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/messages.properties b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/messages.properties
index db38ab5..b9152b5 100644
--- a/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/messages.properties
+++ b/plugins/org.eclipse.mat.dtfj/src/org/eclipse/mat/dtfj/messages.properties
@@ -30,6 +30,7 @@
 DTFJIndexBuilder_CorruptDataReadingHeaps=Corrupt data reading heaps at {0} : {1} from Java runtime at {2}

 DTFJIndexBuilder_DuplicateJavaStackFrame=Ignoring Java stack frame {0} at duplicate address {1} old type {2} new type {3} for thread object at {4}

 DTFJIndexBuilder_IgnoringJavaStackFrame=Ignoring Java stack frame {0} at {1} for thread object at {2} as it has same address as an object

+DTFJIndexBuilder_FindingMissingHeapRoots=Finding heap root objects missing from heap

 DTFJIndexBuilder_FindingMonitorObjects=Finding monitor objects missing from heap

 DTFJIndexBuilder_NullPurgedMapping=Null purged mapping

 DTFJIndexBuilder_PurgedIdentifiers=Purged {0} identifiers using {1} bytes