559247: OQL method call improvements

Performance improvements

Change-Id: Ie0677e8a74c24f9033c356846a277ac5a20fcd89
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=559247
diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
index fc7c0c9..01d5a65 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/MethodCallExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.

+ * Copyright (c) 2008, 2020 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License v1.0

  * which accompanies this distribution, and is available at

@@ -16,7 +16,6 @@
 import java.lang.reflect.Method;

 import java.lang.reflect.Modifier;

 import java.security.AccessControlException;

-import java.text.MessageFormat;

 import java.util.ArrayList;

 import java.util.Arrays;

 import java.util.Iterator;

@@ -212,7 +211,7 @@
             argTypes.append(arg != null ? unboxedType(arg.getClass()).getName() : null);

         }

         throw new SnapshotException(MessageUtil.format(Messages.MethodCallExpression_Error_MethodNotFound,

-                        new Object[] { this.name, argTypes, subject, subject != null ? subject.getClass().getName() : null }));

+                        this.name, argTypes, subject, subjectClass.getName()));

     }

 

     /**

@@ -238,21 +237,35 @@
                 unbox = true;

             i++;

         }

+        extracted(extraMethods, subjectClass, argumentTypes1);

+        if (unbox)

+            extracted(extraMethods, subjectClass, argumentTypes2);

+    }

+

+    private void extracted(List<Method> extraMethods, final Class<? extends Object> subjectClass,

+                    Class<?>[] argumentTypes1)

+    {

         try

         {

-            Method m1 = subjectClass.getMethod(name, argumentTypes1);

-            extraMethods.add(m1);

-        }

-        catch (SecurityException e1)

-        {

-        }

-        catch (NoSuchMethodException e1)

-        {

-        }

-        if (unbox) try

-        {

-            Method m1 = subjectClass.getMethod(name, argumentTypes2);

-            extraMethods.add(m1);

+            // Avoid some NoSuchMethodExceptions by checking the name and number of parms first

+            nextMethod: for (Method m2 : subjectClass.getMethods())

+            {

+                if (!m2.getName().equals(name))

+                    continue;

+                int parameterCount = m2.getParameterCount();

+                if (parameterCount != argumentTypes1.length)

+                    continue;

+                Class<?>[] parameterTypes = m2.getParameterTypes();

+                for (int j = 0; j < parameterCount; ++j)

+                {

+                    Class<?>pt = parameterTypes[j];

+                    if (!pt.isAssignableFrom(argumentTypes1[j]))

+                        continue nextMethod;

+                }

+                Method m1 = subjectClass.getMethod(name, argumentTypes1);

+                extraMethods.add(m1);

+                break;

+            }

         }

         catch (SecurityException e1)

         {

@@ -370,8 +383,9 @@
          * Default allows a few safe methods.

          */

         String match = System.getProperty("mat.oql.methodFilter", //$NON-NLS-1$

-                        "!java.lang.ClassLoader#*;!java.lang.Compiler#*;!java.lang.Module*;!java.lang.Process*;!java.lang.Runtime#*;!java.lang.SecurityManager#*;!java.lang.System#*;!java.lang.Thread*;java.lang.*" //$NON-NLS-1$

-                        + ";java.util.*;!org.eclipse.mat.snapshot.ISnapshot#dispose;org.eclipse.mat.snapshot.*;org.eclipse.mat.snapshot.model.*;!*"); //$NON-NLS-1$

+                        "org.eclipse.mat.snapshot.model.*;!org.eclipse.mat.snapshot.ISnapshot#dispose;org.eclipse.mat.snapshot.*;java.util.*;" //$NON-NLS-1$

+                        + "!java.lang.ClassLoader#*;!java.lang.Compiler#*;!java.lang.Module*;!java.lang.Process*;!java.lang.Runtime#*;!java.lang.SecurityManager#*;!java.lang.System#*;!java.lang.Thread*;java.lang.*" //$NON-NLS-1$

+                        + ";!*"); //$NON-NLS-1$

         String nm = method.getDeclaringClass().getName()+"#"+method.getName(); //$NON-NLS-1$

         for (String pt : match.split(";")) //$NON-NLS-1$

         {

@@ -394,7 +408,7 @@
             else

                 m = nm.equals(pt);

             if (not && m)

-                throw new AccessControlException(MessageFormat.format(Messages.MethodCallExpression_Error_MethodProhibited, nm, "!" + pt, match)); //$NON-NLS-1$

+                throw new AccessControlException(MessageUtil.format(Messages.MethodCallExpression_Error_MethodProhibited, nm, "!" + pt, match)); //$NON-NLS-1$

             if (m)

                 break;

         }

diff --git a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/PathExpression.java b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/PathExpression.java
index 7668ee2..0e3803b 100644
--- a/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/PathExpression.java
+++ b/plugins/org.eclipse.mat.parser/src/org/eclipse/mat/parser/internal/oql/compiler/PathExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2019 SAP AG and IBM Corporation.

+ * Copyright (c) 2008, 2020 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License v1.0

  * which accompanies this distribution, and is available at

@@ -140,34 +140,45 @@
                                     if (attribute.getName().equals(descriptor.getName()))

                                     {

                                         Method method = descriptor.getReadMethod();

-                                        try

+                                        // Perhaps the method should be accessible via an interface, so try that first

+                                        boolean useInterface = false;

+                                        for (Class<?> intf : method.getDeclaringClass().getInterfaces())

                                         {

-                                            // Check whether access to this method should be allowed

-                                            MethodCallExpression.checkMethodAccess(method);

-                                        }

-                                        catch (SecurityException e)

-                                        {

-                                            // Perhaps the method should be accessible via an interface

-                                            for (Class<?> intf : method.getDeclaringClass().getInterfaces())

+                                            try

                                             {

-                                                try

+                                                // Avoid some NoSuchMethodExceptions by checking the name and number of parms first

+                                                for (Method m3 : intf.getMethods())

                                                 {

+                                                    if (!m3.getName().equals(method.getName()))

+                                                        continue;

+                                                    if (m3.getParameterCount() != method.getParameterTypes().length)

+                                                        continue;

                                                     Method m2 = intf.getMethod(method.getName(), method.getParameterTypes());

                                                     MethodCallExpression.checkMethodAccess(m2);

                                                     // Switching to the interface method

                                                     method = m2;

-                                                    // Clear the exception indicator

-                                                    e = null;

+                                                    // Indicate found

+                                                    useInterface = true;

                                                     break;

                                                 }

-                                                catch (NoSuchMethodException e1)

-                                                {

-                                                }

-                                                catch (SecurityException e1)

-                                                {

-                                                }

                                             }

-                                            if (e != null)

+                                            catch (NoSuchMethodException e1)

+                                            {

+                                            }

+                                            catch (SecurityException e1)

+                                            {

+                                            }

+                                            if (useInterface)

+                                                break;

+                                        }

+                                        if (!useInterface)

+                                        {

+                                            try

+                                            {

+                                                // Check whether access to this method should be allowed

+                                                MethodCallExpression.checkMethodAccess(method);

+                                            }

+                                            catch (SecurityException e)

                                             {

                                                 // Fail for the original reason

                                                 throw new SnapshotException(MessageUtil.format(

@@ -176,7 +187,6 @@
                                                                                 attribute.name }),

                                                                 e);

                                             }

-                                            // Continue with equivalent interface method

                                         }

                                         current = method.invoke(current, (Object[]) null);

                                         didFindProperty = true;