Discussion:
module readability and exceptions in api
Michał Zegan
2018-10-10 16:43:30 UTC
Permalink
Hello,
I have following 2 questions:
1. Reflection and MethodHandles throw exceptions deriving from
java.lang.ReflectiveOperationException, that are checked exceptions.
However, the whole module related api throws unchecked exceptions. What
is the actual reason/motivation for using unchecked exceptions? Are
checked exceptions being discouraged, or what?
2. What is the use for Module.addReads and
ModuleLayer.Controller.addReads methods? Module a can access module b
only if a reads b, however:
- in normal cases, the module graph is statically determined, and when
code in module a calls code in module b, then module b probably should
not be optional with a readability edge added at runtime, because we
risk things like IllegalAccessError or NoClassDefFoundError... or
whatever else when code in a calls code in b when b either does not
exist or we have no readability edge. Also such dynamic addition of
readability edges would require special support from module class
loaders to update their... package to class loader mappings to cover the
new module
- in case of such an optional dependency, I believe module a would
access b either through some public api defined in another module, but
reachable from both (and that would not require adding readability
edge), or through reflection (but in this case readability edge is
implied), or both
Alan Bateman
2018-10-10 18:36:00 UTC
Permalink
Post by Michał Zegan
2. What is the use for Module.addReads and
ModuleLayer.Controller.addReads methods?
Module addReads is important when generating bytecode in your own module
with references to classes in modules that you don't read. Another
example  is where you create method handles for a method in a class that
is a member of a module that you don't read.

The equivalent ModuleLayer.Controller addReads is the container case.
There was a recent thread here with Alex Svirivov where he's prototyping
creating a container creating a module layer for a web application. The
container may need to use addExports to export the web application entry
point to the container and (depending on how the container invokes the
web application entry point) it may need to read the module in the child
layer too.

-Alan
Michał Zegan
2018-10-10 20:09:47 UTC
Permalink
Post by Alan Bateman
Post by Michał Zegan
2. What is the use for Module.addReads and
ModuleLayer.Controller.addReads methods?
Module addReads is important when generating bytecode in your own module
with references to classes in modules that you don't read. Another
example  is where you create method handles for a method in a class that
is a member of a module that you don't read.
The equivalent ModuleLayer.Controller addReads is the container case.
There was a recent thread here with Alex Svirivov where he's prototyping
creating a container creating a module layer for a web application. The
container may need to use addExports to export the web application entry
point to the container and (depending on how the container invokes the
web application entry point) it may need to read the module in the child
layer too.
-Alan
Oh when we are at it, a bit offtopic, can bytecode generation be
replaced with method handle usage, or method handles are still not fast
enough... or whatever?
Jochen Theodorou
2018-10-11 17:03:24 UTC
Permalink
On 10.10.2018 22:09, Michał Zegan wrote:
[...]
Post by Michał Zegan
Oh when we are at it, a bit offtopic, can bytecode generation be
replaced with method handle usage, or method handles are still not fast
enough... or whatever?
In my experience they are fast enough in many, if not most cases. But if
you cannot do with constant handles and have to create them at runtime,
then the creation cost is killing your performance.

bye Jochen
Michał Zegan
2018-10-11 17:57:38 UTC
Permalink
Post by Jochen Theodorou
[...]
Post by Michał Zegan
Oh when we are at it, a bit offtopic, can bytecode generation be
replaced with method handle usage, or method handles are still not fast
enough... or whatever?
In my experience they are fast enough in many, if not most cases. But if
you cannot do with constant handles and have to create them at runtime,
then the creation cost is killing your performance.
But they are made mostly for that, fast method calls where you don't
constantly have to create new handles? What about caching? Like
performance of putting such a handle in, say, a map or ... well whatever
more complicated than purely static usage of them...
Post by Jochen Theodorou
bye Jochen
Jochen Theodorou
2018-10-11 23:44:57 UTC
Permalink
Post by Michał Zegan
Post by Jochen Theodorou
[...]
Post by Michał Zegan
Oh when we are at it, a bit offtopic, can bytecode generation be
replaced with method handle usage, or method handles are still not fast
enough... or whatever?
In my experience they are fast enough in many, if not most cases. But if
you cannot do with constant handles and have to create them at runtime,
then the creation cost is killing your performance.
But they are made mostly for that, fast method calls where you don't
constantly have to create new handles? What about caching? Like
performance of putting such a handle in, say, a map or ... well whatever
more complicated than purely static usage of them...
Not sure I get your question. They are made for fast method calls, yes.
Does not mean they are cheap to create in the first place. You can even
build a PIC of definable length by combining multiple handles together
in a guardWithTest - manner and get pretty good peak performance.

If your performance characteristics are that you run large amounts of
calls only once and you do not know the handles in advance, then you
have a problem, depending on what you compare with.

But can runtime bytecode generation still work in times of jigsaw modules?

bye Jochen
Michał Zegan
2018-10-12 23:40:40 UTC
Permalink
Post by Alan Bateman
Post by Michał Zegan
2. What is the use for Module.addReads and
ModuleLayer.Controller.addReads methods?
Module addReads is important when generating bytecode in your own module
with references to classes in modules that you don't read. Another
example  is where you create method handles for a method in a class that
is a member of a module that you don't read.
Oh actually one question I forgot about: if I generate bytecode
accessing classes in modules that I don't read, and I call
Module.addReads on myself, I can then read the module with classes I
want to access, however my module's class loader probably will not
delegate to the other module's class loader for class loading, so how to
solve this situation? Creating my own class loader that loads the
bytecode would require to have separate module for the bytecode.
Post by Alan Bateman
The equivalent ModuleLayer.Controller addReads is the container case.
There was a recent thread here with Alex Svirivov where he's prototyping
creating a container creating a module layer for a web application. The
container may need to use addExports to export the web application entry
point to the container and (depending on how the container invokes the
web application entry point) it may need to read the module in the child
layer too.
-Alan
Alan Bateman
2018-10-13 07:24:48 UTC
Permalink
Post by Michał Zegan
Oh actually one question I forgot about: if I generate bytecode
accessing classes in modules that I don't read, and I call
Module.addReads on myself, I can then read the module with classes I
want to access, however my module's class loader probably will not
delegate to the other module's class loader for class loading, so how to
solve this situation? Creating my own class loader that loads the
bytecode would require to have separate module for the bytecode.
Right, the class loader delegation must respect the readability graph.
There aren't any APIs for dynamically augmenting the delegation graph so
it would require that bring your own class loaders (and specify a
mapping function to defineModules) if you want to do that.

-Alan
Michał Zegan
2018-10-13 14:12:30 UTC
Permalink
Post by Alan Bateman
Post by Michał Zegan
Oh actually one question I forgot about: if I generate bytecode
accessing classes in modules that I don't read, and I call
Module.addReads on myself, I can then read the module with classes I
want to access, however my module's class loader probably will not
delegate to the other module's class loader for class loading, so how to
solve this situation? Creating my own class loader that loads the
bytecode would require to have separate module for the bytecode.
Right, the class loader delegation must respect the readability graph.
There aren't any APIs for dynamically augmenting the delegation graph so
it would require that bring your own class loaders (and specify a
mapping function to defineModules) if you want to do that.
hmm so it is not a good idea to, say, generate a bytecode/class to be
defined as part of currently loaded module X by means of
MethodHandles.Lookup.defineClass or something like that if this bytecode
would have to access module Y that is currently not readable by X,
because I have no control over class loader of X and cannot augment it's
delegation? So may be better to make my own module Z that reads Y and X
and that contains my class, and open some packages to it or export them
to it or do whatever? Then I probably have no use for Module.addReads
either, just addExports/maybe addOpens...
Post by Alan Bateman
-Alan
Alan Bateman
2018-10-14 07:27:42 UTC
Permalink
Post by Michał Zegan
hmm so it is not a good idea to, say, generate a bytecode/class to be
defined as part of currently loaded module X by means of
MethodHandles.Lookup.defineClass or something like that if this bytecode
would have to access module Y that is currently not readable by X,
because I have no control over class loader of X and cannot augment it's
delegation?
This isn't really a module issue. When spinning code at run-time then
you have to take visibility into account. I'm sure there are custom
class loaders around that do have some support for dynamically updating
how they delegate but it's not something that the ClassLoader API has
any support for.

-Alan
Michał Zegan
2018-10-14 11:33:05 UTC
Permalink
Post by Alan Bateman
Post by Michał Zegan
hmm so it is not a good idea to, say, generate a bytecode/class to be
defined as part of currently loaded module X by means of
MethodHandles.Lookup.defineClass or something like that if this bytecode
would have to access module Y that is currently not readable by X,
because I have no control over class loader of X and cannot augment it's
delegation?
This isn't really a module issue. When spinning code at run-time then
you have to take visibility into account. I'm sure there are custom
class loaders around that do have some support for dynamically updating
how they delegate but it's not something that the ClassLoader API has
any support for.
It is not a module issue directly, however if I generate bytecode at
runtime and define it to an existing package of an existing module, then
either I have the ultimate control of this module and know which class
loader is used there, or I have no control over it because it is
application module, then it is a bigger problem.
Post by Alan Bateman
-Alan
Loading...