-
Enhancement
-
Resolution: Fixed
-
P4
-
9
-
b102
-
Verified
One thing that I thought of recently as I was using it is more aggressive use of class redefinition. Let's say I have a project in my IDE, and my build compiles my classes to ./build/classes. So in the REPL I've done:
repl> /classpath build/classes
to add the classes to my class path. I would like it if, when I edit/rebuild in my IDE, there is some way to refresh those classes. Maybe something like
repl> /refresh
which would cause it to walk the class path, find classfiles that have been changed since their last load, and redefine-class them? (Or even doing this automatically without asking.) This would let both views stay in sync.
-Brian
+1000 on being able to refresh when the classpath changes. That is very important for an IDE integration I think. I think it would be better (on the API level), to have an explicit refresh. IDEs are likely to know better when the refresh is in order (e.g. at the end of a build, not during a built, etc.) The tool might listen on the filesystem, but I'd be afraid of potential problems with one process writing to the build/classes and other process listening and getting partial data. So, and explicit /refresh command would seem totally fine to me.
-Jan
I completely agree. In my own real-world use of the jshell tool, I have frequently needed this.
The proposed implementation approach was JPDA class redefinition:
JDI redefineClasses
JVM TI - RedefineClasses
The Hotspot VM (using JDI naming) supports the capabilities canRedefineClasses, but not canAddMethod or canUnrestrictedlyRedefineClasses.
(See jdk9 hotspot: hg.openjdk.java.net/jdk9/jdk9/hotspot/file/de592ea5f7ba/src/share/vm/prims/jvmtiManageCapabilities.cpp).
As a result, the listed changes result in a failure with an exception:
adding a method (changing parameter types counts as deleting/adding)
deleting a method
changing the schema (the adding or removing a field, changing the type, or modifier of a field)
changing the hierarchy (changing a superclass or interface)
changing class modifiers
changing method modifiers
While there are, of course, external changes that do not run afoul of these restrictions (basically, method body only changes), this is not a general mechanism that can be used for update -- either in JShell or elsewhere. This could potentially be an optimization in the cases where it might work. Note there are also delicate issues around stack frames in active (background) threads and class loaders -- as debugger writers know.
What is needed is a general mechanism that works in almost all cases. I believe that approach is decidedly less whizzy, namely, restart and replay the history. Like start-up, output would probably be hidden by-default. The failure point of this approach is JShell code that queries non-reusable input. The most likely case might be user terminal input, but user terminal input doesn't currently work in JShell and this is not planned for JDK 9 -- note: no one seems to have noticed this yet. It should be possible to somewhat trim the history, but note that an external change could cause previously invalid code to become valid -- this could, quite plausibly, be the users motivation for restart -- realization of missing functionality in the system they are exercising.
This approach has a couple of nice side-effects:
* In the event of a crash (e.g. the user calls a method that calls System.exit()), rather than losing all input, the user can be offered a restore option
* The user can restore previous state of an exited session.
-Robert
repl> /classpath build/classes
to add the classes to my class path. I would like it if, when I edit/rebuild in my IDE, there is some way to refresh those classes. Maybe something like
repl> /refresh
which would cause it to walk the class path, find classfiles that have been changed since their last load, and redefine-class them? (Or even doing this automatically without asking.) This would let both views stay in sync.
-Brian
+1000 on being able to refresh when the classpath changes. That is very important for an IDE integration I think. I think it would be better (on the API level), to have an explicit refresh. IDEs are likely to know better when the refresh is in order (e.g. at the end of a build, not during a built, etc.) The tool might listen on the filesystem, but I'd be afraid of potential problems with one process writing to the build/classes and other process listening and getting partial data. So, and explicit /refresh command would seem totally fine to me.
-Jan
I completely agree. In my own real-world use of the jshell tool, I have frequently needed this.
The proposed implementation approach was JPDA class redefinition:
JDI redefineClasses
JVM TI - RedefineClasses
The Hotspot VM (using JDI naming) supports the capabilities canRedefineClasses, but not canAddMethod or canUnrestrictedlyRedefineClasses.
(See jdk9 hotspot: hg.openjdk.java.net/jdk9/jdk9/hotspot/file/de592ea5f7ba/src/share/vm/prims/jvmtiManageCapabilities.cpp).
As a result, the listed changes result in a failure with an exception:
adding a method (changing parameter types counts as deleting/adding)
deleting a method
changing the schema (the adding or removing a field, changing the type, or modifier of a field)
changing the hierarchy (changing a superclass or interface)
changing class modifiers
changing method modifiers
While there are, of course, external changes that do not run afoul of these restrictions (basically, method body only changes), this is not a general mechanism that can be used for update -- either in JShell or elsewhere. This could potentially be an optimization in the cases where it might work. Note there are also delicate issues around stack frames in active (background) threads and class loaders -- as debugger writers know.
What is needed is a general mechanism that works in almost all cases. I believe that approach is decidedly less whizzy, namely, restart and replay the history. Like start-up, output would probably be hidden by-default. The failure point of this approach is JShell code that queries non-reusable input. The most likely case might be user terminal input, but user terminal input doesn't currently work in JShell and this is not planned for JDK 9 -- note: no one seems to have noticed this yet. It should be possible to somewhat trim the history, but note that an external change could cause previously invalid code to become valid -- this could, quite plausibly, be the users motivation for restart -- realization of missing functionality in the system they are exercising.
This approach has a couple of nice side-effects:
* In the event of a crash (e.g. the user calls a method that calls System.exit()), rather than losing all input, the user can be offered a restore option
* The user can restore previous state of an exited session.
-Robert