Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

詳説GraalVM(3) Polyglot

今回は他言語実行環境としてのGraalVM、Polyglotに着目します。現時点での最新版、1.0.0-rc5を使います。

http://www.graalvm.org/downloads/

なお、rc5からCommunity EditionがmacOSに対応しました(今まではEnterprise Editionだけでした)。こちらを使います。

$ java -version
openjdk version "1.8.0_172"
OpenJDK Runtime Environment (build 1.8.0_172-20180626105433.graaluser.jdk8u-src-tar-g-b11)
GraalVM 1.0.0-rc5 (build 25.71-b01-internal-jvmci-0.46, mixed mode)

Polyglot Shell

$ $JAVA_HOME/bin/polyglot --shell
GraalVM MultiLanguage Shell 1.0.0-rc5
Copyright (c) 2013-2018, Oracle and/or its affiliates
  JavaScript version 1.0
Usage: 
  Use Ctrl+L to switch language and Ctrl+D to exit.
  Enter -usage to get a list of available commands.
js> 

polyglotコマンドにshellオプションを付けると、REPLが立ち上がります。Ctrl+Lで言語が切り替えられるのですが、押しても切り替わらず何も起こらないでしょう。

これは、GraalVMにデフォルトで入っているのはJavaScriptだけだからです。他の言語は自分でインストールします。

このままでも、JavaScriptとJavaの相互運用はできます。相互運用する場合、--jvmオプションが必要です。

$ $JAVA_HOME/bin/polyglot --shell --jvm
js> var BigInteger = Java.type('java.math.BigInteger');
js> BigInteger.valueOf(2).pow(100).toString(16)
10000000000000000000000000

guコマンドでの言語インストール

GraalVMにはgu (Graal updater) コマンドがあり、guコマンドで言語をコンポーネントとしてインストールできます。提供されている言語を見ます。

$ $JAVA_HOME/bin/gu available
Downloading: Component catalog
ComponentId              Version             Component name
----------------------------------------------------------------
python                   1.0.0-rc5           Graal.Python
R                        1.0.0-rc5           FastR
ruby                     1.0.0-rc5           TruffleRuby

python、R、rubyがあります。rubyをインストールします。

$ $JAVA_HOME/bin/gu install ruby
Downloading: Component catalog
Processing component archive: Component ruby
Downloading: Component ruby
Installing new component: TruffleRuby (org.graalvm.ruby, version 1.0.0-rc5)
...

$ $JAVA_HOME/bin/gu list
ComponentId              Version             Component name
----------------------------------------------------------------
ruby                     1.0.0-rc5           TruffleRuby

rubyがあります。

RubyとJava、JavaScriptとの相互運用

polyglotシェルを起動し、Ctrl+Lするとrubyに切り替わります。

$ $JAVA_HOME/bin/polyglot --shell --jvm
ruby>

JavaScriptと同様、rubyとJavaで相互運用できます。

ruby> BigInteger = Java.type('java.math.BigInteger')
ruby> BigInteger.valueOf(2).pow(100).toString(16)
"10000000000000000000000000"

JavaScriptからRubyを呼び出してみます。

js> var array = Polyglot.eval("ruby", "[1,2,42,4]")
js> array[2]
42

RubyからJavaScript。

ruby> array = Polyglot.eval('js', '[1,2,42,4]')
<foreign>
ruby> array[2]
undefined local variable or method `array' for main:Object

polyglotシェルでは他言語の戻り値をうまく扱えないようです。こう書くと動きます。

ruby> array = Polyglot.eval('js', '[1,2,42,4]'); array[2]
42

rbファイルに書く場合はきちんと動作します。

不明点

呼び出し側の変数をeval内で参照する方法。

js> var s = "100";
js> Polyglot.eval('ruby', 's.to_i')
undefined local variable or method `s' for main:Object (NameError)

たとえばここでは、JavaScriptの変数sをRubyのeval内で参照したい。Javadocを見たけれど、うまく見つからなかった。

ソースファイルから実行する

test.rbとして保存します。

array = Polyglot.eval('js', '[1,2,42,4]'); 
puts array[2]

rubyコマンドはgraalvm-ce-1.0.0-rc5/Contents/Home/jre/languages/ruby/bin/rubyにあります。

$ graalvm-ce-1.0.0-rc5/Contents/Home/jre/languages/ruby/bin/ruby -v
truffleruby 1.0.0-rc5, like ruby 2.4.4, GraalVM CE Native [x86_64-darwin]

実行します。他言語と相互運用する場合、--jvmオプションが必要です。

$ graalvm-ce-1.0.0-rc5/Contents/Home/jre/languages/ruby/bin/ruby --jvm test.rb
42

デバッガ

GraalVMには多言語環境に対応したデバッガがあります。なんとChromeのDevToolsを利用しています。--inspectオプションをつけます。

$ graalvm-ce-1.0.0-rc5/Contents/Home/jre/languages/ruby/bin/ruby --jvm --inspect test.rb
Debugger listening on port 9229.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/4cc77c2e-56cbc17f25aee

Chromeにchrome-devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/4cc77c2e-56cbc17f25aeeをそのまま入力します。

f:id:jyukutyo:20180808142835p:plain

ブレークポイントも設定できます。

f:id:jyukutyo:20180808142935p:plain

その他変数の中身を見るなど、デバッガ機能が利用できます。

f:id:jyukutyo:20180808143025p:plain