Issue #93 [3/3]: Avoid (expensive) registry scan to find all erroneous classes
authorJan Vrany <jan.vrany@fit.cvut.cz>
Tue, 20 Sep 2016 22:56:52 +0100
changeset 3627 5d22435da54d
parent 3626 7be362f041a8
child 3653 12e952deff1f
child 3767 13867af21c6a
Issue #93 [3/3]: Avoid (expensive) registry scan to find all erroneous classes Instead remember such classes in a separate set when the class is registered. The set is NOT weak and does not need to. Registry holds classes strongly anyway. There's no point to recompile an obsolete class (I believe, we'll see). This yields in another ~25% speedup for Groovy classloading benchmark. https://swing.fit.cvut.cz/projects/stx-libjava/ticket/93
JavaClassRegistry.st
JavaClassReloader.st
tools/JavaCompiler.st
--- a/JavaClassRegistry.st	Wed Sep 21 09:18:20 2016 +0100
+++ b/JavaClassRegistry.st	Tue Sep 20 22:56:52 2016 +0100
@@ -23,7 +23,7 @@
 "{ NameSpace: Smalltalk }"
 
 JavaClassEnvironment subclass:#JavaClassRegistry
-	instanceVariableNames:'vm loaders notifier lock'
+	instanceVariableNames:'vm loaders notifier lock erroneous'
 	classVariableNames:''
 	poolDictionaries:'JavaVMData'
 	category:'Languages-Java-Support'
@@ -168,6 +168,25 @@
     "Modified: / 09-04-2014 / 18:43:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+erroneous
+    "Return a list of classes that contain compilation errors"
+
+    | classes |
+
+    erroneous isNil ifTrue:[ ^ #() ].
+    lock critical:[
+        classes := erroneous copy.
+    ].
+    ^ classes.
+
+    "
+    JavaVM registry erroneous
+    "
+
+    "Created: / 20-09-2016 / 23:00:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-09-2016 / 10:34:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 systemPackage: syspkg
     "Return name (as string) of system package named syspkg or nil if no such package is loaded"
 
@@ -298,8 +317,9 @@
                     on:[:typeAndClass|Smalltalk changed: typeAndClass first with: typeAndClass second].
     notifier priority: Processor userBackgroundPriority - 1.
     lock := RecursionLock new.
+    erroneous := nil.
 
-    "Modified (format): / 22-11-2013 / 11:08:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-09-2016 / 10:28:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 setVM: aJavaVM
@@ -335,6 +355,11 @@
                     | reloadedClass |
 
                     self registerClassRedefined: oldClass.  
+                    "/ ...if old class contained errors, unregister it from list of erroneous 
+                    "/ classes...
+                    oldClass hasErrors ifTrue:[ 
+                        self unregisterErroneous: oldClass.  
+                    ]. 
                     reloadedClass := JavaClassReloader reload: oldClass with: newClass.
                     "/OK, full reload, not just method dictionary update"
                     reloadedClass ~~ oldClass ifTrue:[
@@ -351,6 +376,12 @@
                         self registerClassInClassLoader: reloadedClass.  
                         self registerClassInSmalltalk: reloadedClass notify: false.
                     ].
+                    "/ ...if old class contained errors, unregister it from erroneous as now
+                    "/ it is obsolete...
+                    reloadedClass hasErrors ifTrue:[ 
+                        self registerErroneous: reloadedClass.  
+                    ].
+                    "/ ...likewise, if new class contains errors,
                     Smalltalk changed: #classDefinition with: reloadedClass.
                     ^self.
                 ].
@@ -366,14 +397,19 @@
     newClass isJavaClass ifTrue:[
         self registerClassInClassLoader: newClass.
         "/ Register class in system dictionary so it can be browsed
-        "/ by system browser
+        "/ by system browser...
         self registerClassInSmalltalk: newClass notify: true.
 
-        "/ Also register builtin classes in JavaVMData
+        "/ ...register builtin classes in JavaVMData...
         newClass isBuiltInClass ifTrue:[
             self assert: newClass classLoader isNil. "/must be loaded by primordial CL...
             self registerBuiltIn: newClass.
         ].
+
+        "/ ...and finally, if class contains compilation errors, register it as such...
+        newClass hasErrors ifTrue:[ 
+            self registerErroneous: newClass.
+        ].
     ].
     "/ There may be classes already loaded with compile errors.
     "/ Try to recompile all erroneous classes that depends on this one...
@@ -383,7 +419,7 @@
 
     "Created: / 23-10-2011 / 11:53:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 02-11-2011 / 18:40:52 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
-    "Modified: / 19-09-2016 / 16:54:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-09-2016 / 23:25:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 registerClasses: classes
@@ -584,6 +620,16 @@
     "Created: / 15-08-2014 / 15:09:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+registerErroneous: aJavaClass
+    lock critical:[    
+        erroneous isNil ifTrue:[ erroneous := Set new ].
+        erroneous add: aJavaClass
+    ].
+
+    "Created: / 20-09-2016 / 23:17:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-09-2016 / 10:31:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 unregisterClassInClassLoader: class
     "Unregisters class from it's classloader"
 
@@ -631,6 +677,16 @@
 
     "Created: / 04-04-2012 / 10:01:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 17-10-2013 / 10:50:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+unregisterErroneous: aJavaClass
+    lock critical:[
+        erroneous remove: aJavaClass.
+        erroneous := erroneous asNilIfEmpty.
+    ]
+
+    "Created: / 20-09-2016 / 23:18:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-09-2016 / 10:32:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaClassRegistry class methodsFor:'documentation'!
--- a/JavaClassReloader.st	Wed Sep 21 09:18:20 2016 +0100
+++ b/JavaClassReloader.st	Tue Sep 20 22:56:52 2016 +0100
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
 "
  COPYRIGHT (c) 1996-2015 by Claus Gittinger
 
@@ -476,13 +474,14 @@
     oldClass isInitialized ifTrue:[ newClass classInit ].
 
     newMethods do:[:m|m setJavaClass: oldClass].
+    oldClass setAccessFlags: newClass accessFlags.    
     oldClass setAttributes: newClass attributes.
     oldClass annotations: newClass annotations.
     oldClass setMethodDictionary: newMethods constantPool: newClass constantPool.
     oldClass setSource: newClass sourceString.
     oldClass setFields: newClass fields.
     oldClass setStaticFields: newClass staticFields.
-    "Flush all proxies, they mau refer to old static methods"
+    "Flush all proxies, they may refer to old static methods"
     oldClass class setMethodDictionary: MethodDictionary new.
 
     oldMethodsRemoved do:[:oldMRemoved |
@@ -511,7 +510,7 @@
 
     "Created: / 16-12-2012 / 17:36:52 / Marcel Hlopko <marcel.hlopko@fit.cvut.cz>"
     "Modified: / 12-10-2013 / 19:20:03 / Marcel Hlopko <marcel.hlopko@fit.cvut.cz>"
-    "Modified: / 02-04-2015 / 08:46:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-09-2016 / 09:40:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaClassReloader::SingleClassReloader methodsFor:'private-helpers'!
--- a/tools/JavaCompiler.st	Wed Sep 21 09:18:20 2016 +0100
+++ b/tools/JavaCompiler.st	Tue Sep 20 22:56:52 2016 +0100
@@ -238,8 +238,8 @@
      Classes with no source are silently ignored"
 
     JavaVM booted ifFalse:[ ^ self ].
-    JavaVM registry classes do:[:each |
-        (each ~~ classToIgnore and:[each hasErrors]) ifTrue:[
+    JavaVM registry erroneous do:[:each |
+        each ~~ classToIgnore ifTrue:[
             | source |
 
             source := each source.
@@ -250,7 +250,7 @@
     ].
 
     "Created: / 17-10-2013 / 09:51:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-    "Modified: / 20-11-2013 / 16:08:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 20-09-2016 / 22:58:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !JavaCompiler methodsFor:'accessing'!