Better tools for adjusting to strong encapsulation

Jochen Theodorou blackdrag at gmx.org
Wed Mar 22 21:07:50 UTC 2017


On 22.03.2017 12:23, Alan Bateman wrote:
[...]
> I assume your interest is Groovy where there are indeed some warnings
> that look like Groovy is to blame. For example, I get the following with
> a trivial script containing`println "Hello world!"` :
>
> $ groovy hello.groovy
> NOTE: Picked up the following options via JDK_JAVA_OPTIONS:
>    --permit-illegal-access
> WARNING: --permit-illegal-access will be removed in the next major release
> WARNING: Illegal access by org.codehaus.groovy.reflection.CachedClass
> (file:/groovy-2.4.10/lib/groovy-2.4.10.jar) to method
> java.lang.Object.finalize() (permitted by --permit-illegal-access)
> WARNING: Illegal access by org.codehaus.groovy.reflection.CachedClass
> (file:/groovy-2.4.10/lib/groovy-2.4.10.jar) to method
> java.lang.Object.clone() (permitted by --permit-illegal-access)
> WARNING: Illegal access by org.codehaus.groovy.reflection.CachedClass
> (file:/groovy-2.4.10/lib/groovy-2.4.10.jar) to method
> java.lang.Object.registerNatives() (permitted by --permit-illegal-access)
> WARNING: Illegal access by org.codehaus.groovy.vmplugin.v7.Java7$1
> (file:/groovy-2.4.10/lib/groovy-2.4.10.jar) to constructor
> java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int) (permitted by
> --permit-illegal-access)
> Hello world!
>
> The user's script is innocent but maybe you are saying that if Groovy
> spins code and that code calls back into the Groovy runtime to do its
> dirty work then Groovy will be blamed?

the warnings you are seeing are from the groovy runtime trying to 
determine - in a pre JDK9 compatible way - if it is allowed to call the 
methods on Objecz. This happens in a first step by setAccessible on all 
methods using the array version, and if that fails by using the normal 
setAccessible on each method (which will contribute to much longer 
startup times). At no point our runtime or the program you wrote are 
trying to call finalize, clone or registerNatives.

The only one we are to be blamed for is 
MethodHandles$Lookup(java.lang.Class,int), for which I haven´t 
implemented the alternative yet

If you did other programs... like for example running a gradle build... 
you would see many many more such lines

> On the question of performance then it may have an impact, it might not
> as it depends on how much illegal access is going on. We see some
> libraries doing some hacking with setAccessible(true) at startup and
> then re-using the AccessibleObject over and over, they will hardly
> notice anything.

So it will not be on a invocation base with some kind of check if that 
has been locked already? Then I misunderstood

> In the case of Groovy then running with
> JDK_JAVA_OPTIONS="-Dsun.reflect.debugModuleAccessChecks=true" reveals
> several places where  InaccessibleObjectException is being thrown and
> silently ignored, e.g:

silently and purposely ignored.

> java.lang.reflect.InaccessibleObjectException: Unable to make private
> java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int) accessible:
> module java.base does not "opens java.lang.invoke" to unnamed module
> @43bd930a
>      at
> java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)
>
>      at
> java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281)
>
>      at
> java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:192)
>
>      at
> java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:185)
>      at org.codehaus.groovy.vmplugin.v7.Java7$1.run(Java7.java:53)
>      at java.base/java.security.AccessController.doPrivileged(Native
> Method)
>      at org.codehaus.groovy.vmplugin.v7.Java7.<clinit>(Java7.java:50)
>      at
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
> Method)
>      at
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
>
>      at
> java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
>
>      at
> java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
>      at java.base/java.lang.Class.newInstance(Class.java:558)
>      at
> org.codehaus.groovy.vmplugin.VMPluginFactory.createPlugin(VMPluginFactory.java:59)
>
>      at
> org.codehaus.groovy.vmplugin.VMPluginFactory.<clinit>(VMPluginFactory.java:40)
>
>      at
> org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:102)
>
>      at
> org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:74)
>
>      at groovy.lang.GroovySystem.<clinit>(GroovySystem.java:36)
>      at
> org.codehaus.groovy.runtime.InvokerHelper.<clinit>(InvokerHelper.java:66)
>      at groovy.lang.GroovyObjectSupport.<init>(GroovyObjectSupport.java:34)
>      at groovy.lang.Binding.<init>(Binding.java:35)
>      at groovy.lang.GroovyShell.<init>(GroovyShell.java:74)
>      at groovy.ui.GroovyMain.processOnce(GroovyMain.java:651)
>      at groovy.ui.GroovyMain.run(GroovyMain.java:384)
>      at groovy.ui.GroovyMain.process(GroovyMain.java:370)
>      at groovy.ui.GroovyMain.processArgs(GroovyMain.java:129)
>      at groovy.ui.GroovyMain.main(GroovyMain.java:109)
>      at
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method)
>      at
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>
>      at
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>
>      at java.base/java.lang.reflect.Method.invoke(Method.java:563)
>      at
> org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109)
>      at
> org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131)
> Hello world!
>
> So it might be that the cost of these exceptions is already high and
> that doing illegal access (with --permit-illegal-access) will not be
> noticed while the issues are being fixed.

So you tell me that if I add an add-opens to java.base for all unnamed 
modules, I will still pay a performance penalty here? on each method 
invocation or only once?

Also... be assured that people will notice, even if that means only that 
Groovy is much slower on JDK9 compared to JDK8

bye Jochen



More information about the jigsaw-dev mailing list