JavaLookup: make Java-to-Java lookup returning a trampoline when method is not found.
authorJan Vrany <jan.vrany@fit.cvut.cz>
Wed, 23 Mar 2016 10:07:43 +0000
changeset 3551 f8304e321df7
parent 3550 81ee3d2cc629
child 3552 9c3f3089d912
JavaLookup: make Java-to-Java lookup returning a trampoline when method is not found. The trampoline in turn throws `NoSuchMethodError` or `AbstractMethodError`. This way, there's no need to detect Java-to-Java send in JavaObject>>doesNotUnderstand: to correctly handle these (rare) cases (as done in commit e546e1df7a01)
JavaLookup.st
JavaObject.st
JavaVM.st
--- a/JavaLookup.st	Tue Mar 22 23:42:40 2016 +0000
+++ b/JavaLookup.st	Wed Mar 23 10:07:43 2016 +0000
@@ -37,7 +37,7 @@
 
 Lookup subclass:#J2J
 	instanceVariableNames:''
-	classVariableNames:''
+	classVariableNames:'NoSuchMethodErrorSelector AbstractMethodErrorSelectors'
 	poolDictionaries:''
 	privateIn:JavaLookup
 !
@@ -256,6 +256,54 @@
     "Modified: / 22-03-2016 / 22:44:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!JavaLookup::J2J class methodsFor:'initialization'!
+
+initialize
+    "Invoked at system start or when the class is dynamically loaded."
+
+    "/ please change as required (and remove this comment)
+
+    NoSuchMethodErrorSelector := #(
+            " 0" #'throwNoSuchMethodError'
+            " 1" #'throwNoSuchMethodError_:'
+            " 2" #'throwNoSuchMethodError_:_:'
+            " 3" #'throwNoSuchMethodError_:_:_:'
+            " 4" #'throwNoSuchMethodError_:_:_:_:'
+            " 5" #'throwNoSuchMethodError_:_:_:_:_:'
+            " 6" #'throwNoSuchMethodError_:_:_:_:_:_:'
+            " 7" #'throwNoSuchMethodError_:_:_:_:_:_:_:'
+            " 8" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:'
+            " 9" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:'
+            "10" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:'
+            "11" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:_:'
+            "12" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:_:_:'
+            "13" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:'
+            "14" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:_:'
+            "15" #'throwNoSuchMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:'
+    ).
+
+    AbstractMethodErrorSelectors := #(
+            " 0" #'throwAbstractMethodError'
+            " 1" #'throwAbstractMethodError_:'
+            " 2" #'throwAbstractMethodError_:_:'
+            " 3" #'throwAbstractMethodError_:_:_:'
+            " 4" #'throwAbstractMethodError_:_:_:_:'
+            " 5" #'throwAbstractMethodError_:_:_:_:_:'
+            " 6" #'throwAbstractMethodError_:_:_:_:_:_:'
+            " 7" #'throwAbstractMethodError_:_:_:_:_:_:_:'
+            " 8" #'throwAbstractMethodError_:_:_:_:_:_:_:_:'
+            " 9" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:'
+            "10" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:'
+            "11" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:_:'
+            "12" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:_:_:'
+            "13" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:'
+            "14" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:_:'
+            "15" #'throwAbstractMethodError_:_:_:_:_:_:_:_:_:_:_:_:_:_:_:'
+    ).
+
+    "Modified: / 23-03-2016 / 09:41:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !JavaLookup::J2J methodsFor:'lookup'!
 
 lookupMethodForSelector: selector directedTo: initialSearchClass
@@ -268,30 +316,41 @@
     | method superMethod |
 
     method := super lookupMethodForSelector: selector directedTo: initialSearchClass.
-    method isNil ifTrue:[ ^ nil ].
-
-    superMethod := super lookupMethodForSelector: selector directedTo: method mclass superclass.
-    [ superMethod notNil ] whileTrue:[
-        (method overrides: superMethod) ifFalse:[
-            method := superMethod
+    method notNil ifTrue:[
+        superMethod := super lookupMethodForSelector: selector directedTo: method mclass superclass.
+        [ superMethod notNil ] whileTrue:[
+            (method overrides: superMethod) ifFalse:[
+                method := superMethod
+            ].
+            superMethod := super lookupMethodForSelector: selector directedTo: superMethod mclass superclass.
         ].
-        superMethod := super lookupMethodForSelector: selector directedTo: superMethod mclass superclass.
     ].
-
-    ^method
+    ^ method
 
     "Created: / 05-07-2012 / 11:06:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 23-03-2016 / 09:44:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 lookupMethodForSelector:selector directedTo:initialSearchClass for:aReceiver withArguments:argArrayOrNil from:sendingContext ilc: ilcCache
     | method |
     method := self lookupMethodForSelector: selector directedTo: initialSearchClass.
+    "/ No method found. Return a trampoline that will throw NoSuchMethodError or AbstractMethodError
+    "/ (for INVOKEINTERFACE)
+    method isNil ifTrue:[ 
+        "/ This is a hacky check whether the failing instruction is INVOKEINTERFACE or not
+        (sendingContext method byteCode at: sendingContext pc - 1) == 185 ifTrue:[ 
+            method := JavaVM class >> (AbstractMethodErrorSelectors at: argArrayOrNil size + 1)
+        ] ifFalse:[ 
+            method := JavaVM class >> (NoSuchMethodErrorSelector at: argArrayOrNil size + 1)
+        ].
+    ].
     ilcCache notNil ifTrue:[
         ilcCache bindTo: method forClass: initialSearchClass.
     ].
     ^ method.
 
     "Created: / 22-03-2016 / 22:43:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 23-03-2016 / 09:57:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaLookup::J2S methodsFor:'lookup'!
@@ -1131,3 +1190,4 @@
 
 
 JavaLookup initialize!
+JavaLookup::J2J initialize!
--- a/JavaObject.st	Tue Mar 22 23:42:40 2016 +0000
+++ b/JavaObject.st	Wed Mar 23 10:07:43 2016 +0000
@@ -333,23 +333,6 @@
     "/   3 - context of method that sent the not understood message
     "/ Hence the `thisContext sender sender below.
     sender := thisContext sender sender.
-    "/ When a sending context is a JavaContext, then throw NoSuchMethodError/AbstractMethodError
-    "/ This may happen if classfile was changes meanwhile so it's now 
-    "/ incompatible
-    sender class == JavaContext ifTrue:[ 
-        "/ Sigh, must check whether the instruction was INVOKEINTERFACE which
-        "/ throws AbstractMethodError rather than NoSuchMethodError. Arghh...
-
-        | error |
-
-        (sender method byteCode at: sender pc - 1) == 185 ifTrue:[ 
-            error := 'java.lang.AbstractMethodError'
-        ] ifFalse:[ 
-            error := 'java.lang.NoSuchMethodError'
-        ].
-        JavaVM throwExceptionClassName: error withMessage: ('No method %1 in class %2' bindWith: aMessage selector with: self class javaName).
-        ^ nil
-    ].
     didNotUnderstood := false.
     retval := self class perform: aMessage onReceiver: self from: sender ifNotFound: [ didNotUnderstood :=  true ].
     ^ didNotUnderstood ifTrue:[
@@ -361,7 +344,7 @@
     "Modified: / 16-11-1998 / 16:50:56 / cg"
     "Modified: / 19-09-2011 / 23:43:56 / Jan Kurs <kursjan@fit.cvut.cz>"
     "Modified: / 01-01-2012 / 19:49:35 / kursjan <kursjan@fit.cvut.cz>"
-    "Modified: / 21-03-2016 / 01:24:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 23-03-2016 / 10:01:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaObject methodsFor:'printing & storing'!
--- a/JavaVM.st	Tue Mar 22 23:42:40 2016 +0000
+++ b/JavaVM.st	Wed Mar 23 10:07:43 2016 +0000
@@ -3437,13 +3437,6 @@
 
 !JavaVM class methodsFor:'helpers - exceptions'!
 
-throwAbstractMethodError
-    ^ self throwExceptionClassName: 'java.lang.AbstractMethodError'
-        withMessage: 'resolving a method ref failed'.
-
-    "Created: / 11-04-2011 / 20:32:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
-!
-
 throwArrayIndexOutOfBoundsException: badIndex
     | exClass  ex |
 
@@ -3888,20 +3881,6 @@
     "Created: / 13-04-2011 / 12:16:36 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
 !
 
-throwNoSuchMethodError
-      ^ self throwNoSuchMethodError: 'looking up a method failed'.
-
-    "Created: / 11-04-2011 / 20:33:19 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
-    "Modified: / 21-03-2016 / 01:11:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-!
-
-throwNoSuchMethodError: message
-      ^ self throwExceptionClassName: 'java.lang.NoSuchMethodError'
-              withMessage: message
-
-    "Created: / 21-03-2016 / 01:11:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-!
-
 throwNullPointerException
     self throwNullPointerException:'null pointer'
 
@@ -3988,6 +3967,203 @@
     "Created: / 20-07-2012 / 19:15:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!JavaVM class methodsFor:'helpers - exceptions - trampolines'!
+
+throwAbstractMethodError
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 11-04-2011 / 20:32:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+    "Modified: / 23-03-2016 / 09:59:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:32:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:33:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:34:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:34:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13 _: a14
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:34:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwAbstractMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13 _: a14 _: a15
+    ^ JavaVM throwExceptionClassName: 'java.lang.AbstractMethodError' withMessage: 'trying to execute abstract method or (missing) interface method'.
+
+    "Created: / 23-03-2016 / 09:34:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 11-04-2011 / 20:33:19 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+    "Modified: / 23-03-2016 / 09:58:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 21-03-2016 / 01:11:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 23-03-2016 / 09:58:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:35:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13 _: a14
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+throwNoSuchMethodError: a1 _: a2 _: a3 _: a4 _: a5 _: a6 _: a7 _: a8 _: a9 _: a10 _: a11 _: a12 _: a13 _: a14 _: a15
+      ^ JavaVM throwExceptionClassName: 'java.lang.NoSuchMethodError' withMessage: 'method not found'
+
+    "Created: / 23-03-2016 / 09:36:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !JavaVM class methodsFor:'helpers - io'!
 
 commonOpenStreamUsing: aBlock