GraalVM JavaScriptの実装

GraalVMは、JavaScriptおよびNode.jsアプリケーションを実行するためのECMAScript準拠のランタイムです。完全に標準に準拠しており、アプリケーションを高いパフォーマンスで実行できます。また、言語の相互運用性や共通ツールなど、GraalVMスタックのすべての利点を享受できます。このリファレンス・ドキュメントでは、使用可能なJavaScriptエンジン構成、Node.jsランタイム、javax.script.ScriptEngine実装、マルチスレッド・サポートの詳細、考えられる埋込みシナリオなどについて説明します。これまでNashornエンジンまたはRhinoエンジンにターゲット指定していたコードを移行できるように、移行ガイドが用意されています。

JavaScriptの実行

GraalVM 22.2以降、JavaScriptサポートは別個のGraalVMコンポーネント内にパッケージ化されています。これはGraalVMアップデータを使用してインストールできます:

$GRAALVM/bin/gu install js

または、次のように、JavaScriptランタイム・コンポーネントをダウンロードし、ファイルからインストールすることもできます:

$GRAALVM/bin/gu install --file ~/Downloads/js-...-.jar

これにより、js$GRAALVM_HOME/binディレクトリにインストールされます。JavaScriptコンポーネントがインストールされている場合、GraalVMでは、プレーンJavaScript (ECMAScript)コードを実行できます:

$GRAALVM/bin/js [options] [filename...] -- [args]

GraalVM JavaScriptと既存の標準およびエンジンとの互換性の詳細は、「JavaScriptの互換性」を参照してください。

Node.jsの実行

GraalVMは、変更されていないNode.jsアプリケーションを実行できます。アプリケーションでは、npmモジュール(ネイティブ・モジュールを含む)をインポートできます。GraalVM 21.1以降、Node.jsサポートは別個のGraalVMコンポーネント内にパッケージ化されています。これはGraalVMアップデータを使用してインストールできます:

$GRAALVM/bin/gu install nodejs

または、次のように、Node.jsランタイム・コンポーネントをダウンロードし、ファイルからインストールすることもできます:

$GRAALVM/bin/gu install --file ~/Downloads/nodejs-installable-...-.jar

これにより、nodeおよびnpmランチャが$GRAALVM_HOME/binディレクトリにインストールされます。nodeユーティリティを使用して、Node.jsアプリケーションを実行します:

node [options] [filename] [args]

Node.jsパッケージをインストールするには、$GRAALVM_HOME/binnpmランチャを使用します。npmコマンドは、デフォルトのNode.jsコマンドと同等で、すべてのNode.js APIをサポートします。

  1. 次のように、npm installを使用してcolorsおよびansispanパッケージをインストールします:
     npm install colors ansispan
    

    インストールしたパッケージは、アプリケーションから使用できます。

  2. 次のコード・スニペットをapp.jsという名前のファイルに追加し、Node.jsパッケージをインストールしたディレクトリに保存します:
     const http = require("http");
     const span = require("ansispan");
     require("colors");
    
     http.createServer(function (request, response) {
         response.writeHead(200, {"Content-Type": "text/html"});
         response.end(span("Hello Graal.js!".green));
     }).listen(8000, function() { console.log("Graal.js server running at http://127.0.0.1:8000/".red); });
    
     setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000);
    
  3. 次のように、GraalVMでnodeコマンドを使用して実行します:
     node app.js
    

Node.jsの実行の詳細は、「Node.jsランタイム」を参照してください。Node.js機能は、アプリケーションがnodeバイナリ・ランチャから起動されたときに使用できます。Node.jsアプリケーションの起動時またはJavaコンテキストからのnpmパッケージへのアクセス時には、特定の制限が適用されます。Node.jsとJavaスクリプト・コンテキストの違いを参照してください。

相互運用性

GraalVMは、Ruby、R、Python、LLVMなどの他のいくつかのプログラミング言語をサポートしています。GraalVMはNode.jsおよびJavaScriptアプリケーションを実行するように設計されていますが、これらの言語間の相互運用性にも対応し、GraalVMポリグロットAPIを使用すればこれらのうち任意の言語でコードを実行したり、メソッドをコールできます。

Node.jsまたはJavaScriptと他の言語との相互運用性を有効にするには、--jvmおよび--polyglotオプションを渡します。たとえば:

node --jvm --polyglot
Welcome to Node.js v16.14.2.
Type ".help" for more information.
> var array = Polyglot.eval("python", "[1,2,42,4]")
> console.log(array[2]);
42
> console.log(Polyglot.eval('R', 'runif(100)')[0]);
0.8198353068437427

他のプログラミング言語との相互運用性の詳細は、「ポリグロット・プログラミング」を参照してください。

Javaとの相互運用性

JavaScriptからJavaにアクセスするには、次の例のようにJava.typeを使用します:

node --jvm
> var BigInteger = Java.type('java.math.BigInteger');
> console.log(BigInteger.valueOf(2).pow(100).toString(16));
10000000000000000000000000

その逆に、JavaからJavaScriptを実行するには、JavaScriptコンテキストをJavaプログラムに埋め込みます:

import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;

public class HelloPolyglot {

    static String JS_CODE = "(function myFun(param){console.log('hello '+param);})";

    public static void main(String[] args) {
        System.out.println("Hello Java!");
        try (Context context = Context.create()) {
            Value value = context.eval("js", JS_CODE);
            value.execute(args[0]);
        }
    }
}

関数定義をラップすると(())、関数がすぐに返されます。ソース・コード単位は、例に示すように文字列で表したり、ファイル、URLからの読取りおよびその他の方法を通じて表すことができます。

前述のJavaプログラムを実行します:

javac HelloPolyglot.java
java HelloPolyglot JavaScript

これにより、Javaに埋め込まれたJavaScriptコンテキストを評価できますが、Javaコードから直接関数をコールしたり、関数のパラメータを設定することはできません。Node.jsランタイムはJVMに埋め込むことはできず、別のプロセスとして起動する必要があります。

たとえば、次のコードをapp.jsという名前で保存します:

var HelloPolyglot = Java.type("HelloPolyglot");

HelloPolyglot.main(["from node.js"]);

console.log("done");

次に、--jvmオプションを指定してnodeを起動し、Javaとの相互運用性を有効にします:

node --jvm --vm.cp=. app.js
Hello Java!
hello from node.js
done

クラスパスを設定することで、JVMが適切に起動するようにnodeに指示します。Node.jsとJVMの両方が同じプロセスで実行され、相互運用性は前述と同じValueクラスを使用して機能します。

言語の相互運用性の詳細は、「Javaの相互運用性」ガイドを参照してください。

その他のドキュメント

詳細は、GraalVM JavaScriptに関する特定のトピックのドキュメント・ページを参照してください:

GraalVM JavaScriptの使用:

レガシー環境:

Node.jsサポート: