The problem of addRead being CallerSensitive can be solve by adding a way to add a read edge from a Lookup object ?
Rémi ----- Mail original ----- > De: "Jochen Theodorou" <blackd...@gmx.org> > À: "jigsaw-dev@openjdk.java.net >> jigsaw-dev" <jigsaw-dev@openjdk.java.net> > Envoyé: Vendredi 15 Juillet 2016 15:21:01 > Objet: Re: Should setAccessible be part of Java or not? (was Re: It's not > too late for access control) > > On 14.07.2016 23:24, Alan Bateman wrote: > > > > > > On 14/07/2016 21:20, Jochen Theodorou wrote: > >> > >> What I would wish for at this moment is a document explaining the > >> runtime aspects of the module system, including limitations reflection > >> and normal method calls, as well as things like layers / runtime > >> generated modules - as well as the methods to be used to create and > >> change these. I don´t anything JLS ready here and just the behaviour > >> of the one of the latest releases is also good. I cannot give feedback > >> on a design I do not know. Because maybe some frameworks are content > >> with the compile time side of this, I am not. > >> > > Jochen - have you worked through the documents, slides and recordings > > that are linked from the main Project Jigsaw page [1]? > > > > I know in other threads we we alluded to slides on how > > Nashorn/Javascript has been updated to work with modules (and spin > > modules at runtime). I realize Groovy is different but I think we should > > do this as it may be useful to other language implementers too. > > > > [1] http://openjdk.java.net/projects/jigsaw/ > > Well, I was hoping for a document, videos do not work well for me and > slides are better, but often useless without the actual talk... depends > of course > > The problem is that this is a lot of material that barely scratches the > points I am wondering about. > > Example http://openjdk.java.net/projects/jigsaw/talks/ > > Javaone 2015 > Prepare for JDK 9 -> for me useless > Introduction to Modular Development -> for runtime aspects useless > Advanced Modular Development -> mentions addReads on slide 36 and is > done with the runtime aspect with that basically. > Project Jigsaw: Under the Hood -> is more interesting from slide 34 on, > but does not answer my questions enough. > Project Jigsaw Hack Session -> the whole thing as video > > Devoxx BE 2015 is only video > > I will give you an analysis of my situation so far: > > assuming the whole Groovy runtime is a module, and assuming I have other > modules as well, and then I want to use a Groovy script at runtime, to > access those modules. And let us assume those modules do not know of > Groovy. Let us further assume the Groovy runtime will be in a loader > that delegates to a loader knowing the classes of those modules, or is > in the same loader. > > So first problem is ... can I use the unnamed module for the scripts? > They read every (named) module, thus they can access the types. > Next are 4 types of method invocations to consider for the case of an > invocation from script in the unnamed module to named module: > reflective, indy, direct, generated bytecode for callsites (I name this > one csgen in short). The method itself is looked up by reflection > > * for indy it is only a question of the lookup object, which will be > provided by the script and can do the call > * direct calls will work > * reflection would be done from the groovy runtime, thus the runtime > need to have a read on the named module. That´s the first time I will > need Java9 special code in this scenario > * csgen is more unclear. Let us assume it is in the unnamed package as > well, in a loader that delegates to the script loader. Basically it > becomes a direct call and works. > > Next step is for my Groovy runtime having to call a method from the > script. Since everything is exported there is no problem on this side. > * indy will work after adding the read > * reflection - same > * direct call - same > * cs gen... the call to the csgen method will be done by an > interface/class of the Groovy runtime, and since the csgen class is in > the unnamed package, it has no problem calling the script methods. > > Let us look at the same scenario with a named module for scripts. I will > use that as a step in between to think about actual compile time modules > written in Groovy. So for simplicity I assume I can create such a module > at runtime and it will export everything. How to do that? I have not the > slightest idea. Anyway, that means now I have calls from named script > module to named module: > > * indy will work after the script module added a read to the target > module. This will require in the script, with a direct call to addReads, > because of caller sensitivity. Which means instead of just having JDK9 > specific code in my runtime, I will now need JDK9 specific code to my > bytecode as well. And this needs to happen before any normal method > invocation can take place, thus static initializer, first thing... which > means completely new code for the compiler, that will work only on JDK9. > This means the compiler will then have to at least know if he compiles > for JDK9 or not... > * direct call - same > * reflection - the call is effectively done from the Groovy runtime, so > the Groovy runtime will have to add the read. > * csgen in the unnamed module means.. since the call is gated by an > interface/class from the runtime I assume I do not need a read edge from > the script module to the unnamed module csgen is in. The csgen class > then will be able to read the exported class of the target module, thus > has no problem. > > Calls from the groovy runtime to the script are not different to before. > > Next step is then precompiled Groovy code in a named module. The > difference to before is that we now have to look at calls from hidden > API to hidden API of the same module and we have compile time defined > requires and exports. > > Since the Groovy runtime needs to be able to call some methods by > reflection all packages, including the hidden API, will have to be > exported to the groovy runtime and of course there will be a require for > the Groovy runtime. > > Let us briefly look at a call from the script module to an exported > class in another named module again... the script module will now > require the other named module, which means we have a reads here already. > * direct call works > * reflection - runtime has to add read > * indy works > * csgen in the unnamed module... the call is again done using > interfaces/classes from the runtime, meaning it should work. > > Then let us look at a call from hidden/public API to hidden API of the > same module of our precompiled script. > * direct call works > * indy works > * reflection works, since everything is exported to the groovy runtime.. > * csgen in the unnamed module... while the call to csgen will work > (gated by classes/interfaces of the runtime), the call from csgen to > hidden API will fail. Adding a read won´t help, end of line. A named > module would have the same problem. Solution unclear. > > As for calls from the groovy runtime to the hidden API of the script > module... Some csgen problem, everything else is fine. > > Finally calls from the script module to the hidden API of another > module... I can make this sometimes work with indy and with reflection. > csgen will have the known problem, direct calls will not work. Of course > there is now the question of if I need such a call... assume you did > write a program like this: > > Module A, export exported > package exported > class MyExportedList extends ArrayList { > def sum(init){ > def ret = init > for (it in this) ret +=it > return ret > } > } > > Module B, hidden API, require A > class HiddenX { > int value > def plus(HiddenX other) { return value+other.value } > } > > def list = [new HiddenX(value:1), new HiddenX(value:2), new > HiddenX(value:3)] as MyExportedList > assert list.sum(new HiddenX(value:0)) == 6 > > This will require the sum method in Module A to call plus on HiddenX for > the "+=". There is no interface or class for this, just the public > method. Since the class is in the hidden API of B, A will not be able to > access it. > * A direct method call is out of question for this of course, so no > static case at all. > * reflection through the groovy runtime > * indy... before I would have used the lookup object of the caller to > realize the call. Since A cannot read HiddenX, this won´t work anymore. > I would have to resort to a private "everything is allowed" constructor > in Lookup. Basically a hack, of which I won´t know if it will work in > the next JDK version. Maybe I could "steal" a lookup object from HiddenX > to avoid this, but it is very allowed to write HiddenX in another > language like Java, and then I will not be able to produce a helper > method for this. Meaning I will have to stay with the hackish > maintenance nightmare of using a private constructor. > * csgen... the sad story continues. > > And btw, how am I supposed to decide if this call is allowed or not? > > To sum things up: > * module runtime creation and handling beyond adding reads is unclear > * setAccessible failing on public classes from hidden APIs is > inconvenient, but at least we can find code for this, which is > compatible for multiple JDK versions > * csgen will probably have to fall back to reflection for most cases, > which means it will be a lot slower. A bigger change would be to give it > an indy backend. We would probably still suffer a performance penalty, > since we then have an additional layer with wrapping in between, that > cannot be removed by the JIT, as long as the JIT is unable to look > beyond the indy callsite itself. > * the indy part will have to use "forbidden" API now. > * runtime scripts will go into the unnamed module > * hidden APIs and non-public modifiers will be ignored by Groovy for as > long as the "forbidden" API works, which keeps current semantics > * most of the groovy runtime makes still heavy use of reflection and > will probably have to be reworked to use indy everywhere, if on JDK9 > (probably JDK8+). > > And I am not happy with this outcome so far. > > bye Jochen >