GraalVM - это платформа времени выполнения, которая обеспечивает поддержку Java и других языков на основе байт-кода Java, а также дополнительных языков, таких как JavaScript, Ruby, Python или LLVM. И мы твердо верим, что это будущее виртуальных машин для языков, которые мы знаем сейчас.

Однако мы понимаем, что переход с установленной Oracle JVM или OpenJDK на GraalVM - смелый шаг, который вы, возможно, пока не захотите делать полностью. Но вы можете попробовать некоторые интересные возможности проекта GraalVM на стандартной JVM.

В этом сообщении блога мы покажем, как использовать движок JavaScript GraalVM из примера приложения Maven. Мы также покажем, как использовать движок JavaScript GraalVM на стандартном OpenJDK 11, включая Graal в качестве JIT-компилятора (точно в срок) для повышения максимальной производительности. Таким образом, движок JavaScript GraalVM можно использовать в качестве замены устаревшего движка Nashorn JavaScript. Мы продемонстрируем это на приложении Maven, так как все необходимые артефакты доступны в Maven central.

JavaScript GraalVM и компилятор Graal

Может возникнуть один вопрос: как связаны JavaScript-движок GraalVM с Graal; Могу ли я использовать только движок JavaScript и опустить Graal?

Если вы это сделаете, все будет полностью работать. Затем вы можете проанализировать и выполнить любой (действительный) код JavaScript. Механизм JavaScript GraalVM - это приложение Java, которое работает с любой реализацией Java 8+. Выполнение JavaScript построено на интерпретаторе абстрактного синтаксического дерева (AST), который может выполняться как любое другое приложение Java. Каждая виртуальная машина Java будет в некоторой степени оптимизировать ее, но выполнение JavaScript останется интерпретируемым, поэтому будет медленным.

Однако у компилятора Graal есть несколько специальных приемов для преобразования этого интерпретатора AST в высоко оптимизированный машинный код. Он адаптируется к исполняемому приложению JavaScript и скомпилирует приложение вместе с интерпретатором в машинный код, тем самым эффективно превратив его в компилятор JavaScript во время выполнения. После короткой фазы разогрева приложение JavaScript, таким образом, достигнет производительности, близкой к нативной, если движок JavaScript GraalVM выполняется на JVM с включенным компилятором Graal.

Пример приложения

Мы подготовили образец приложения, показывающий соответствующую настройку. Этот пример на основе Maven может служить отправной точкой для передачи, например приложения JavaScript на основе Nashorn для JavaScript GraalVM с поддержкой Graal.

Пример сосредоточен на вычислении простых чисел в JavaScript, которые потребляются из кода Java. В нем показано, как получить доступ к JavaScript GraalVM с предпочтительным интерфейсом org.graalvm.polyglot, а также с интерфейсом javax.script (JSR 223 ScriptEngine). Кроме того, пример кода выполняется через ScriptEngine на движке Nashorn (если есть). Идентичное количество итераций прогрева и измерения выполняется и печатается в виде простого теста, показывающего время выполнения, необходимое для соответствующего движка (чем ниже значения, тем лучше).

Пример доступен на GitHub:

Https://github.com/graalvm/graal-js-jdk11-maven-demo

Обратите внимание, что конкретные достоинства кода не являются интересной частью обсуждения, обычно исходные коды Java и JavaScript можно разделить на отдельные файлы и так далее. Этот пример ориентирован на инфраструктуру для выполнения многоязычного кода Java и JavaScript. Приложение должно запускаться из коробки, если вы скомпилируете и выполните его с помощью следующих команд; убедитесь, что вы используете JDK11, указав на него JAVA_HOME.

export JAVA_HOME=/path/to/JDK11
mvn clean && mvn package && mvn exec:exec@graal

Это гарантирует, что вы используете Graal для JIT-компиляции кода JavaScript GraalVM. По нашим измерениям, в этом приложении JavaScript GraalVM был примерно в два раза быстрее, чем Nashorn (попробуйте на своей машине, YMMV). Если вас интересует более подробное сравнение производительности, обратитесь к предыдущему посту о Nashorn и GraalVM JavaScript.

Для сравнения вы можете выполнить тот же тест без включенной компиляции Graal:

mvn clean && mvn package && mvn exec:exec@nograal

В этом режиме при выполнении без включения Graal в качестве JIT-компилятора производительность GraalVM / JavaScript значительно падает.

Некоторые технические идеи

Что происходит за кулисами? В файле pom.xml объявлено несколько зависимостей для соответствующих пакетов, включая org.graalvm.compiler и org.graalvm.js. Они доступны в Maven Central и загружаются оттуда.

В JVM передаются три аргумента, как объявлено в разделе конфигурации плагина, которые включают компиляцию Graal на JVM:

  • -XX:+UnlockExperimentalVMOptions
    Этот флаг включает следующую опцию
  • -XX:+EnableJVMCI
    Включает компиляцию кода Java через JVMCI (интерфейс компилятора виртуальной машины Java).
  • --upgrade-module-path
    P Добавляет правильную версию Graal в путь к модулю, чтобы ее можно было использовать в качестве компилятора для GraalVM / JavaScript.

Заключение

В этом посте мы рассмотрели, как можно использовать артефакты движка JavaScript GraalVM из Maven Central и запустить их на стандартном JDK. Без доступа к компилятору Graal производительность кода JavaScript в этой настройке может быть не оптимальной - к счастью, вы можете включить компилятор Graal с кучей параметров командной строки и получить гораздо более быстрое выполнение JavaScript. При наличии компилятора Graal JavaScript GraalVM значительно быстрее, чем Nashorn. В качестве ориентира вот некоторые результаты тестов, которые мы получили ранее при тестировании Octane:

В будущем, возможно, появится возможность предоставить больше артефактов GraalVM на Maven Central и позволить еще большему количеству языков выполняться таким образом на других JVM без необходимости установки самих двоичных файлов GraalVM.

Сообщите нам, будет ли вам полезен такой подход или что бы вы хотели увидеть в будущем. Мы рады получать комментарии здесь или в виде запросов функций в наших репозиториях GitHub для Graal или GraalVM / JavaScript.