changeset 14054:2e69293d5e12

Interpreter: Repair and simplify method selection logic. Handle native and abstract methods more gracefully. Add test for default method selection. Failing tests: 1 (testEnum).
author jrose
date Fri, 10 Jun 2016 00:32:55 -0700
parents f9072be260c9
children 5d236453e343
files interpreter/src/valhalla/interpreter/InternalHelpers.java interpreter/src/valhalla/interpreter/Interpreter.java interpreter/test-helpers/test/valhalla/interpreter/InterpreterTestHelper1.java interpreter/test/valhalla/interpreter/InterpreterTest.java
diffstat 4 files changed, 22 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/interpreter/src/valhalla/interpreter/InternalHelpers.java	Thu Jun 09 22:20:10 2016 -0400
+++ b/interpreter/src/valhalla/interpreter/InternalHelpers.java	Fri Jun 10 00:32:55 2016 -0700
@@ -89,9 +89,7 @@
     // FIXME: put this as a privileged Lookup method
     static MethodHandle convertVirtualToSpecial(MethodHandleInfo mhi, Class dynamicReceiver) {
         try {
-            Object o = MH_Lookup_resolveOrFail.invoke(LOOKUP, (byte) mhi.getReferenceKind(), dynamicReceiver, mhi.getName(), mhi.getMethodType());
-            Class<?> clazz = (Class) MH_MemberName_getDeclaringClass.invoke(o);
-            return LOOKUP.findSpecial(clazz, mhi.getName(), mhi.getMethodType(), clazz);
+            return LOOKUP.findSpecial(dynamicReceiver, mhi.getName(), mhi.getMethodType(), dynamicReceiver);
         }
         catch (Throwable ex) {
             throw new InterpreterError(ex);
--- a/interpreter/src/valhalla/interpreter/Interpreter.java	Thu Jun 09 22:20:10 2016 -0400
+++ b/interpreter/src/valhalla/interpreter/Interpreter.java	Fri Jun 10 00:32:55 2016 -0700
@@ -235,6 +235,11 @@
                 case H_INVOKEINTERFACE:
                     // do a dispatch to find out where the bytecodes really are
                     selected = doMethodSelection(mhi, args[0].getClass());
+                    if (selected != null) {
+                        mhi = InternalHelpers.crackMethodHandle(selected);
+                        // method selection should not select an abstract method
+                        assert((mhi.getModifiers() & Opcodes.ACC_ABSTRACT) == 0);
+                    }
                     if (args[0].getClass().getName().contains("/"))
                         altOwner = args[0].getClass().getName();
                     interpretable = true;
@@ -283,6 +288,7 @@
         Frame f = cm.methods()
                     .filter(m -> m.getName().equals(methodName)
                                  && m.getDesc().equals(methodDesc)
+                                 && ((m.getAccess() & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) == 0)
                                  && ((isStatic && (m.getAccess() & Opcodes.ACC_STATIC) != 0)
                                      || (!isStatic && (m.getAccess() & Opcodes.ACC_STATIC) == 0)))
                     .findFirst()
--- a/interpreter/test-helpers/test/valhalla/interpreter/InterpreterTestHelper1.java	Thu Jun 09 22:20:10 2016 -0400
+++ b/interpreter/test-helpers/test/valhalla/interpreter/InterpreterTestHelper1.java	Fri Jun 10 00:32:55 2016 -0700
@@ -157,4 +157,17 @@
             return 3;
         }
     }
+
+    public static int testInterfaceCall2() {
+        AnInterface2 f = new AnImplementingClass2();
+        return f.four();
+    }
+
+    interface AnInterface2 {
+        default int four() { return 4; }
+    }
+
+    static class AnImplementingClass2 implements AnInterface2{
+        // keep the default four() = 4
+    }
 }
--- a/interpreter/test/valhalla/interpreter/InterpreterTest.java	Thu Jun 09 22:20:10 2016 -0400
+++ b/interpreter/test/valhalla/interpreter/InterpreterTest.java	Fri Jun 10 00:32:55 2016 -0700
@@ -142,6 +142,8 @@
     public void testInterface() throws Throwable {
         Integer i = (Integer) interpreter.invokestatic(HELPER_1, "testInterfaceCall", "()I");
         assertEquals((int) i, 3);
+        Integer i2 = (Integer) interpreter.invokestatic(HELPER_1, "testInterfaceCall2", "()I");
+        assertEquals((int) i2, 4);
     }
 
     public void testEnum() throws Throwable {