Java Bug System を見ていたら JShell 自体のデバッグを見つけたので、パッチを書こうと思いJShellについて調べてみた。
使い方や 2 つの JVM が動くぐらいは知っていたけど、具体的には知らないので調べてみました。
試しにjshellコマンドを実行してからjmcやjcmdを確認するとjdk.internal.jshell.tool.JShellToolProviderとjdk.jshell.execution.RemoteExecutionControlが起動するのが確認できます。
人間がふれ合うクラスはjdk.internal.jshell.tool.JShellToolProviderです。
jdk.internal.jshell.tool.JShellToolProviderの実行時引数を確認したところ以下のような感じでした。
java -Dapplication.home=C:\Oracle\Java\jdk-11 -Xms8m -Djdk.module.main=jdk.jshell jdk.internal.jshell.tool.JShellToolProvider
これに-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:12345を付けてデバッグできるようにします。
全部付けるとこんな感じ。
java -Dapplication.home=C:\Oracle\Java\jdk-11 -Xms8m -Djdk.module.main=jdk.jshell -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:12345jdk.internal.jshell.tool.JShellToolProvider
デバッグが出来るようになりましたが、気になるのはユーザからの入力を待つ場所あたりかと。
これは、jdk.jshellモジュールの中ではjdk.internal.jshell.tool.ConsoleIOContextクラスのpublic String readLine(String prompt, String prefix) throws IOException, InputInterruptedExceptionメソッドでユーザの入力を待ちます。
@Override public String readLine(String prompt, String prefix) throws IOException, InputInterruptedException { (略) try { return in.readLine(prompt); } catch (UserInterruptException ex) { (略) }
inのオブジェクトはjdk.internal.leモジュールのjdk.internal.jline.console.ConsoleReaderです。
jdk.internal.leモジュールでは、jdk.internal.jline.internal.InputStreamReaderクラスのpublic int read(char[] buf, int offset, int length) throws IOExceptionメソッドでユーザの入力を待ちます。
@Override public int read(char[] buf, int offset, int length) throws IOException { (略) int off = bytes.arrayOffset() + bytes.limit(); int was_red = in.read(bytes.array(), off, to_read); if (was_red == -1) { (略) }