Fixes for class unloadfing: unload inner classes first.
authorJan Vrany <jan.vrany@fit.cvut.cz>
Mon, 11 Aug 2014 09:46:49 +0100
changeset 3217 261bad2a9657
parent 3216 1d977d2d3abb
child 3220 dac830f75266
Fixes for class unloadfing: unload inner classes first.
JavaClassRegistry.st
JavaClassReloader.st
experiments/JavaClassReloaderTests.st
experiments/experiments.rc
libjava.rc
tools/tools.rc
--- a/JavaClassRegistry.st	Mon Aug 11 01:55:40 2014 +0100
+++ b/JavaClassRegistry.st	Mon Aug 11 09:46:49 2014 +0100
@@ -402,23 +402,26 @@
 unregisterClass: oldClass
     | classes |
 
-    "/ First. remove the class from system dictionary
-    "/ and from registry so nobody could resolve it.
-    self unregisterClassInSmalltalk: oldClass notify: true.
     classes := loaders at: oldClass classLoader ifAbsent: nil.
     classes notNil ifTrue:[
         "/ Check if the class is there, it could be removed meanwhile...
         (classes includesKey: oldClass binaryName) ifTrue:[
-            classes removeKey: oldClass binaryName.
             "/ Now, invalidate references and unload all dependent clases
             "/ (JavaClassReloader will unload them by recursively call #unregisterClass:
             JavaClassReloader unload: oldClass.
+            "/ Now remove it from class registry...
+            classes removeKey: oldClass binaryName.
+            "/ ...from class loader...
+            self unregisterClassInClassLoader: oldClass.  
+            "/ ...from reflection cache....
+            JavaVM reflection removeJavaClassObjectForClass: oldClass.
+            "/ ...and from Smalltalk dictionary
+            self unregisterClassInSmalltalk: oldClass notify: true.
         ]
     ].
 
     "Created: / 04-04-2012 / 02:43:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 14-09-2013 / 23:41:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified (comment): / 17-10-2013 / 02:25:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 11-08-2014 / 01:57:47 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 unregisterClassLoader: aJavaClassLoader
--- a/JavaClassReloader.st	Mon Aug 11 01:55:40 2014 +0100
+++ b/JavaClassReloader.st	Mon Aug 11 09:46:49 2014 +0100
@@ -181,8 +181,11 @@
 
 unload: oldClass
 
-    oldClass subclassesDo:[:cls | 
-        JavaVM registry unregisterClass: cls 
+    oldClass subclassesDo:[:subclass |
+        JavaVM registry unregisterClass: subclass.
+    ].
+    oldClass innerClassesIgnoreUnloaded do:[:innerclass | 
+        JavaVM registry unregisterClass: innerclass.
     ].
     JavaVM registry allClassesDo:[:cls|        
         "/ JV: Q: Should we remove all users of the interface? Let's do it, but not
@@ -191,14 +194,7 @@
 
         ifaces := cls getInterfaces.
         ifaces notNil ifTrue:[
-            (ifaces  anySatisfy:[:ref|
-                    ref isJavaClass ifTrue:[
-                        ref == oldClass
-                    ] ifFalse:[
-                        ref name =  oldClass binaryName
-                    ]
-            ]) ifTrue:[
-
+            (ifaces  anySatisfy:[:ref| ref isJavaClass ifTrue:[ ref == oldClass]  ifFalse:[ ref name =  oldClass binaryName ] ]) ifTrue:[
                 JavaVM registry unregisterClass: cls
             ].
         ].
@@ -206,7 +202,7 @@
     ]
 
     "Created: / 14-09-2013 / 15:53:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 09-04-2014 / 18:43:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 08-08-2014 / 22:38:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaClassReloader methodsFor:'reloading-requests'!
--- a/experiments/JavaClassReloaderTests.st	Mon Aug 11 01:55:40 2014 +0100
+++ b/experiments/JavaClassReloaderTests.st	Mon Aug 11 09:46:49 2014 +0100
@@ -2172,6 +2172,137 @@
 
     "Created: / 14-09-2013 / 19:04:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 15-09-2013 / 00:40:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+test_unloading_03a
+    "
+    1) compile class A with inner class InnerA
+    2) remove class A
+    3) check that InnerA has been removed too.
+    "
+
+    | jclassA jclassInnerA |
+
+    self compileAndRegister:'
+public class test_unloading_03a_A { 
+    public static class InnerA {
+    }
+}'.
+
+    jclassA := JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader.
+    jclassInnerA := JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA).
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA).
+
+    jclassA removeFromSystem.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA) not.
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA) not.
+
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader) isNil.    
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader) isNil.
+
+    "Created: / 08-08-2014 / 22:00:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 08-08-2014 / 23:02:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+test_unloading_03b
+    "
+    1) compile class A with inner class InnerA
+    2) remove class A
+    3) check that both classes are gone
+    "
+
+    | jclassA jclassInnerA |
+
+    self compileAndRegister:'
+public class test_unloading_03a_A { 
+    public static class InnerA {
+    }
+}'.
+
+    jclassA := JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader.
+    jclassInnerA := JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA).
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA).
+
+    jclassInnerA removeFromSystem.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA) .
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA) not.
+
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader) notNil.    
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader) isNil.
+
+    "Created: / 11-08-2014 / 09:25:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+test_unloading_03c
+    "
+    1) compile class A with inner class InnerA
+    2) remove class A
+    3) check that both classes are gone
+    "
+
+    | jclassA jclassInnerA |
+
+    self compileAndRegister:'
+public class test_unloading_03a_A { 
+    public static class InnerA {
+    }
+}'.
+
+    jclassA := JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader.
+    jclassInnerA := JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA).
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA).
+
+    jclassA removeFromSystem.
+    jclassInnerA removeFromSystem.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA) not.
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA) not.
+
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader) isNil.    
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader) isNil.
+
+    "Created: / 11-08-2014 / 09:25:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+test_unloading_03d
+    "
+    1) compile class A with inner class InnerA
+    2) remove class A
+    3) check that both classes are gone
+    "
+
+    | jclassA jclassInnerA |
+
+    self compileAndRegister:'
+public class test_unloading_03a_A { 
+    public static class InnerA {
+    }
+}'.
+
+    jclassA := JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader.
+    jclassInnerA := JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA).
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA).
+
+    jclassInnerA removeFromSystem.
+    jclassA removeFromSystem.
+
+    self assert: (Smalltalk allClasses includesIdentical: jclassA) not.
+    self assert: (Smalltalk allClasses includesIdentical: jclassInnerA) not.
+
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A' definedBy: testClassLoader) isNil.    
+    self assert: (JavaVM classNamed: #'test_unloading_03a_A$InnerA' definedBy: testClassLoader) isNil.
+
+    "Created: / 11-08-2014 / 09:26:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaClassReloaderTests class methodsFor:'documentation'!
--- a/experiments/experiments.rc	Mon Aug 11 01:55:40 2014 +0100
+++ b/experiments/experiments.rc	Mon Aug 11 09:46:49 2014 +0100
@@ -25,7 +25,7 @@
       VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0"
       VALUE "ProductName", "Smalltalk/X\0"
       VALUE "ProductVersion", "6.2.4.0\0"
-      VALUE "ProductDate", "Mon, 11 Aug 2014 00:51:54 GMT\0"
+      VALUE "ProductDate", "Mon, 11 Aug 2014 08:34:44 GMT\0"
     END
 
   END
--- a/libjava.rc	Mon Aug 11 01:55:40 2014 +0100
+++ b/libjava.rc	Mon Aug 11 09:46:49 2014 +0100
@@ -25,7 +25,7 @@
       VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2011\nCopyright eXept Software AG 1998-2011\nCopyright Jan Vrany, Jan Kurs and Marcel Hlopko\n          SWING Research Group, Czech Technical University In Prague\0"
       VALUE "ProductName", "Smalltalk/X\0"
       VALUE "ProductVersion", "6.2.4.0\0"
-      VALUE "ProductDate", "Mon, 11 Aug 2014 00:51:52 GMT\0"
+      VALUE "ProductDate", "Mon, 11 Aug 2014 08:34:41 GMT\0"
     END
 
   END
--- a/tools/tools.rc	Mon Aug 11 01:55:40 2014 +0100
+++ b/tools/tools.rc	Mon Aug 11 09:46:49 2014 +0100
@@ -25,7 +25,7 @@
       VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2011\nCopyright eXept Software AG 1998-2011\0"
       VALUE "ProductName", "Smalltalk/X\0"
       VALUE "ProductVersion", "6.2.4.0\0"
-      VALUE "ProductDate", "Mon, 11 Aug 2014 00:51:57 GMT\0"
+      VALUE "ProductDate", "Mon, 11 Aug 2014 08:34:47 GMT\0"
     END
 
   END