Fixed baaad bug in INVOKE? handling when method does not exist
...due to incompatible change in .class file. When a method that
does not exist is about to be invoked, then
`java.lang.NoSuchMethodError` must be thrown. If the instruction is
INVOKEINTERFACE, `java.lang.AbstractMethodError` should be thrown
instead.
The VM does not check nor throw these exceptions by itself. Instead
it relies on Smalltalk #doesNotUnderstand: mechanism. There it checks
whether the sending context is a a JavaContext and if so, throw Java
error as specified in JVM spec.
Interesting how far we went without noticing...
--- a/JavaClass.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaClass.st Mon Mar 21 09:21:48 2016 +0000
@@ -1772,7 +1772,7 @@
directedTo: class
for: receiver
withArguments: args
- from: thisContext sender
+ from: sender
ilc: nil.
^ method isNil ifTrue:[
@@ -1783,7 +1783,7 @@
"Created: / 19-09-2011 / 23:33:06 / Jan Kurs <kursjan@fit.cvut.cz>"
"Modified: / 10-04-2012 / 16:47:31 / kursjan"
- "Modified: / 07-01-2014 / 13:41:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 01:05:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!JavaClass methodsFor:'java initialization'!
@@ -2167,7 +2167,13 @@
doesNotUnderstand:aMessage
| sender |
- sender := thisContext sender.
+
+ "/ When we arrive here, the stack is:
+ "/ 1 - JavaObject>>doesNotUnderstand: (i.e., this method)
+ "/ 2 - context for not understood method (created by VM to hold arguments)
+ "/ 3 - context of method that sent the not understood message
+ "/ Hence the `thisContext sender sender below.
+ sender := thisContext sender sender.
^self
perform: aMessage
onReceiver: self
@@ -2177,7 +2183,7 @@
"Modified: / 16-11-1998 / 16:50:56 / cg"
"Modified: / 19-09-2011 / 23:43:56 / Jan Kurs <kursjan@fit.cvut.cz>"
"Modified (comment): / 01-01-2012 / 19:36:41 / kursjan <kursjan@fit.cvut.cz>"
- "Modified: / 03-01-2012 / 21:02:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 00:59:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
lookupFieldFor:fname static: searchStatic onlyPublic: publicOnly
--- a/JavaClassRefTests.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaClassRefTests.st Mon Mar 21 09:21:48 2016 +0000
@@ -84,24 +84,21 @@
testAccessingNonPublicFromInside
| javaClassRef initString throwedException |
- self enableMockedExceptionThrowing.
-
[ initString := 'Lstx/libjava/tests/mocks/NonPublicClass;'.
javaClassRef := self getClassRefNamed: initString.
javaClassRef owner: (Java classForName: 'stx.libjava.tests.mocks.Crate').
javaClassRef resolve. ] on: Error
do: [:e | throwedException := e ].
self assertTrue: (throwedException isNil).
- self disableMockedExceptionThrowing.
"Created: / 13-04-2011 / 13:42:47 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 17:58:19 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+ "Modified: / 21-03-2016 / 08:59:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
testAccessingNonPublicFromOutside
| javaClassRef initString throwedException |
- self enableMockedExceptionThrowing.
[
initString := 'Lstx/libjava/tests/mocks/NonPublicClass;'.
javaClassRef := self getClassRefNamed:initString.
@@ -110,61 +107,54 @@
] on:Error do:[:e | throwedException := e ].
self assertTrue:(throwedException notNil
and:[ throwedException messageText = 'IllegalAccessError' ]).
- self disableMockedExceptionThrowing.
"Created: / 13-04-2011 / 13:37:41 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 17:58:22 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
- "Modified: / 10-12-2013 / 18:36:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 08:59:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
testAccessingPublic
| javaClassRef initString |
- self enableMockedExceptionThrowing.
self shouldnt:
[ initString := 'Lstx/libjava/tests/mocks/PublicClass;'.
javaClassRef := self getClassRefNamed: initString.
javaClassRef owner: self someJavaClass.
javaClassRef resolve. ]
raise: Error.
- self disableMockedExceptionThrowing.
"Created: / 13-04-2011 / 13:36:33 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 17:58:24 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
- "Modified: / 10-12-2013 / 18:38:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 09:00:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
testNonPublicClassPresent
| javaClassRef initString |
- self enableMockedExceptionThrowing.
initString := 'Lstx/libjava/tests/mocks/NonPublicClass;'.
javaClassRef := self getClassRefNamed: initString.
javaClassRef owner: (Java
classForName: 'stx.libjava.tests.mocks.SubclassOfNonPublicClass').
javaClassRef resolve.
self assertTrue: (javaClassRef resolvedValue notNil).
- self disableMockedExceptionThrowing.
"Created: / 13-04-2011 / 13:38:49 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 17:58:27 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
- "Modified: / 31-01-2014 / 09:12:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 09:00:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
testPublicClassPresent
| javaClassRef initString |
- self enableMockedExceptionThrowing.
initString := 'Lstx/libjava/tests/mocks/PublicClass;'.
javaClassRef := self getClassRefNamed: initString.
javaClassRef owner: self someJavaClass.
javaClassRef resolve.
self assertTrue: (javaClassRef resolvedValue notNil).
- self disableMockedExceptionThrowing.
"Created: / 13-04-2011 / 13:39:00 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 17:58:29 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
- "Modified: / 31-01-2014 / 09:13:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 09:00:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!JavaClassRefTests methodsFor:'primitives'!
--- a/JavaExceptionTests.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaExceptionTests.st Mon Mar 21 09:21:48 2016 +0000
@@ -67,6 +67,7 @@
"Created: / 30-03-2012 / 13:38:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
+
!JavaExceptionTests methodsFor:'callbacks'!
call: trhower with: aBoolean
--- a/JavaObject.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaObject.st Mon Mar 21 09:21:48 2016 +0000
@@ -20,6 +20,8 @@
"
"{ Package: 'stx:libjava' }"
+"{ NameSpace: Smalltalk }"
+
Object subclass:#JavaObject
instanceVariableNames:'_lockWord_'
classVariableNames:''
@@ -325,7 +327,29 @@
<resource: #skipInDebuggersWalkBack>
| sender retval didNotUnderstood |
- sender := thisContext sender.
+ "/ When we arrive here, the stack is:
+ "/ 1 - JavaObject>>doesNotUnderstand: (i.e., this method)
+ "/ 2 - context for not understood method (created by VM to hold arguments)
+ "/ 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:[
@@ -337,7 +361,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: / 28-10-2013 / 10:33:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 01:24:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!JavaObject methodsFor:'printing & storing'!
--- a/JavaRefsAndConstantPoolTestCase.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaRefsAndConstantPoolTestCase.st Mon Mar 21 09:21:48 2016 +0000
@@ -172,19 +172,6 @@
!JavaRefsAndConstantPoolTestCase methodsFor:'helpers'!
-disableMockedExceptionThrowing
- JavaResolver uniqueInstance exceptionThrower: exceptionThrowerBackup.
-
- "Created: / 13-04-2011 / 14:11:34 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
-!
-
-enableMockedExceptionThrowing
- exceptionThrowerBackup := JavaResolver uniqueInstance exceptionThrower.
- JavaResolver uniqueInstance exceptionThrower: JavaExceptionThrowerMock new.
-
- "Created: / 13-04-2011 / 14:11:01 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
-!
-
getCrateClassReadStream
^ ((stx_libjava packageDirectory / 'tests' )
/ 'java' / 'bin'
@@ -319,18 +306,21 @@
!JavaRefsAndConstantPoolTestCase methodsFor:'running'!
setUp
- self enableMockedExceptionThrowing.
+ super setUp.
+ exceptionThrowerBackup := JavaResolver uniqueInstance exceptionThrower.
+ JavaResolver uniqueInstance exceptionThrower: JavaExceptionThrowerMock new.
"Created: / 12-05-2011 / 17:30:41 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
"Modified: / 23-05-2011 / 18:02:18 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+ "Modified: / 21-03-2016 / 08:59:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
tearDown
-
- self disableMockedExceptionThrowing.
+ JavaResolver uniqueInstance exceptionThrower: exceptionThrowerBackup.
+ super tearDown.
"Created: / 12-05-2011 / 17:30:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
- "Modified: / 08-08-2011 / 17:24:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+ "Modified: / 21-03-2016 / 08:59:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!JavaRefsAndConstantPoolTestCase::JavaExceptionThrowerMock class methodsFor:'documentation'!
--- a/JavaRuntimeConstantPoolTests.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaRuntimeConstantPoolTests.st Mon Mar 21 09:21:48 2016 +0000
@@ -74,10 +74,11 @@
!
tearDown
-super tearDown.
+ super tearDown.
JavaConstantPool allConstantPools: constantPoolCacheBackup.
"Created: / 13-05-2011 / 09:33:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
+ "Modified (format): / 21-03-2016 / 08:52:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!JavaRuntimeConstantPoolTests methodsFor:'tests'!
--- a/JavaVM.st Sun Mar 20 23:55:04 2016 +0000
+++ b/JavaVM.st Mon Mar 21 09:21:48 2016 +0000
@@ -3889,10 +3889,17 @@
!
throwNoSuchMethodError
- ^ self throwExceptionClassName: 'java.lang.NoSuchMethodError'
- withMessage: 'looking up a method failed'.
+ ^ 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
--- a/ProxyMethod.st Sun Mar 20 23:55:04 2016 +0000
+++ b/ProxyMethod.st Mon Mar 21 09:21:48 2016 +0000
@@ -26,6 +26,8 @@
"
"{ Package: 'stx:libjava' }"
+"{ NameSpace: Smalltalk }"
+
Method variableSubclass:#ProxyMethod
instanceVariableNames:'body'
classVariableNames:'InstallProxies'
@@ -148,6 +150,20 @@
"
"Created: / 06-12-2011 / 21:18:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+uninstallAllProxies
+ ProxyMethod allInstances do:[:m |
+ m mclass notNil ifTrue:[
+ m mclass basicRemoveSelector: m selector
+ ]
+ ]
+.
+ "
+ ProxyMethod uninstallAllProxies
+ "
+
+ "Created: / 21-03-2016 / 01:02:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!ProxyMethod methodsFor:'accessing'!