openjdk.ruOpenJDK на русском

JEP 174: Nashorn JavaScript Engine

движок JavaScript Nashorn

ОтветственныйJim Laskey
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск8
Компонентcore-libs / jdk.nashorn
Обсуждениеnashorn dash dev at openjdk dot java dot net
ТрудоёмкостьXL
ДлительностьXL
РецензентыSundararajan Athijegannathan
ОдобренBrian Goetz
Создан2012/11/21 20:00
Обновлён2015/02/13 19:38
Задача8046164

Аннотация

Спроектировать и реализовать новую легковесную высокопроизводительную реализацию JavaScript и интегрировать её в JDK. Новый движок будет доступен Java-приложениям через существующий API javax.script, а в более общем случае — через новый инструмент командной строки.

Цели

  • Nashorn будет основан на спецификации языка ECMAScript-262 Edition 5.1 и должен проходить тесты на соответствие ECMAScript-262.

  • Nashorn будет поддерживать API javax.script (JSR 223).

  • Будет обеспечена поддержка вызова Java-кода из JavaScript и вызова JavaScript-кода из Java. Это включает прямое отображение на JavaBeans.

  • Nashorn определит новый инструмент командной строки jjs для выполнения JavaScript-кода в скриптах с «shebang», here-документах и строках редактирования.

  • Производительность и потребление памяти приложений на Nashorn должны быть значительно лучше, чем у Rhino.

  • Nashorn не будет создавать никаких дополнительных рисков безопасности.

  • Поставляемые библиотеки должны корректно работать при локализации.

  • Сообщения об ошибках и документация будут интернационализированы.

Что не является целью

  • Nashorn будет поддерживать только ECMAScript-262 Edition 5.1. Он не будет поддерживать ни возможности Edition 6, ни какие-либо нестандартные возможности, предоставляемые другими реализациями JavaScript.

  • Nashorn не будет включать API для плагинов браузера.

  • Nashorn не будет включать поддержку DOM/CSS или каких-либо связанных библиотек (например, jQuery, Prototype или Dojo).

  • Nashorn не будет включать непосредственную поддержку отладки.

Мотивация

Производительность Rhino сильно отстала от производительности других движков JavaScript. Чтобы улучшить производительность, на данном этапе Rhino пришлось бы переписать, заменив его интерпретатор генератором кода, спроектированным для полного использования возможностей JVM. Вместо того чтобы браться за масштабную переработку очень старого кода Rhino, мы решили начать с нуля.

Кроме того, в интересах Java-сообщества продвигать JVM как жизнеспособную платформу для языков, отличных от Java. Это развивает технологию и привлекает новых разработчиков.

Описание

Движок Nashorn обрабатывает исходный код JavaScript в пять этапов: лексический анализатор -> синтаксический анализатор -> генерация кода -> загрузка -> выполнение.

Лексический анализатор принимает массив символов Unicode (исходный код) и преобразует его в поток лексических единиц, или токенов; например, чисел, строк, идентификаторов или специальных символов.

Nashorn использует синтаксический анализатор рекурсивного спуска, основанный на спецификации языка ECMAScript 262. Синтаксический анализатор принимает поток токенов, созданный лексическим анализатором, и собирает токены, соответствующие синтаксису языка. По мере распознавания синтаксических единиц синтаксический анализатор строит промежуточное представление (AST/IR) JavaScript-кода.

Генератор кода принимает AST/IR и генерирует байт-код JVM. При выполнении этот байт-код реализует семантику исходного кода JavaScript.

Генерация кода выполняется в два шага. Первый шаг понижает AST/IR до представления, более близкого к набору инструкций JVM. Это преобразование включает трансформацию управляющих конструкций, сведение выражений к примитивным операциям и упрощение выражений вызова. Этот шаг также отвечает за определение символов, используемых для управления использованием данных, пространством и типами.

Второй шаг транслирует AST/IR в байт-код с помощью библиотеки ASM. ASM выдаёт собственно байт-коды, из которых формируется класс скрипта. Этот класс кэшируется в памяти для последующего использования загрузчиком скриптов.

После того как класс скрипта сгенерирован, его нужно установить в JVM. Это делается с помощью defineClass через защищённый пользовательский загрузчик классов. Этот загрузчик также используется для синтеза специальных классов объектов Nashorn, когда они встречаются в сгенерированном коде. После загрузки класса скрипта вызывается его runMethod.

Для поддержки выполняемого кода нужно несколько библиотек.

Основная библиотека времени выполнения включает методы, непосредственно поддерживающие выполнение кода, например, процедуры преобразования типов, необходимые для toString и toNumber, и процедуры выделения памяти, такие как allocateArray.

Библиотека компоновщика включает методы, помогающие связывать вызовы invokedynamic с помощью API java.lang.invoke (JSR 292). Процесс связывания довольно сложен: он включает поиск правильного метода, определение защитных условий, гарантирующих, что места вызова продолжают быть корректными, и повторное связывание, если что-то изменилось и требуется другой правильный метод. Компоновщик также ведёт историю вызовов, чтобы при последующих повторных связываниях поиск выполнялся быстрее.

Библиотека объектов JavaScript включает поддержку всех стандартных объектов JavaScript, например, Object, Function, Number, String, Date, Array, RegExp и так далее. Она также включает функции для работы со строками, сложных математических вычислений, применения функций и т. д.

Nashorn использует invokedynamic для реализации всех своих вызовов. Если у вызова получателем является Java-объект, Nashorn пытается связать вызов с подходящим Java-методом, а не с функцией JavaScript. Nashorn полностью свободен в том, как он разрешает методы. Например, если он не может найти поле в получателе, он ищет эквивалентный метод Java Bean. Для вызовов из JavaScript в Java результат полностью прозрачен.

Java-разработчики могут использовать API javax.script (JSR 223) для выполнения JavaScript-кода и обратных вызовов в него.

Альтернативы

У Rhino долгая история и соответствующий ей исходный код. Большая часть кода Rhino поддерживает интерпретируемую модель выполнения. Чтобы получить значительный прирост производительности, модель выполнения должна использовать преимущества интерпретатора и компилятора Hotspot.

Другие движки JavaScript, такие как V8 и Nitro, обеспечивают хорошую производительность, но потребовали бы второй виртуальной машины (дополнительный код и память) и связующего API для взаимодействия с Java.

Тестирование

JCK

Существующих JCK-тестов javax.script должно быть достаточно. Nashorn — просто ещё один движок скриптов, доступный через API javax.script. Сам Nashorn не предоставляет собственного нового стандартного Java API, поэтому дополнительные JCK-тесты не нужны.

Функциональные и модульные тесты

Существующие тесты включают:

Они охватывают большую часть функциональных областей, но эти тесты нужно адаптировать к набору тестов Nashorn на основе TestNG. Не все эти тесты могут быть применимы, поскольку Nashorn соответствует ECMAScript-262 Edition 5.1 с небольшим числом расширений. В частности, mozilla_js_tests охватывают многие специфичные для Mozilla возможности, которые Nashorn поддерживать не будет. Поэтому для использования этих тестов в тестовом фреймворке Nashorn требуется работа по выделению подмножества и адаптации.

Существующие модульные тесты для API javax.script и инструмента командной строки jrunscript также можно использовать для Nashorn.

Дополнительные модульные и регрессионные тесты в репозитории Nashorn

Это тесты, разработанные разработчиками Nashorn в ходе реализации возможностей и исправления ошибок.

Тесты производительности

Была проведена некоторая работа по адаптации для запуска этих тестов в тестовом фреймворке Nashorn.

Примечание: эти тесты производительности не включают доступ к API браузера (DOM/CSS и т. п.). Такие тесты есть в наборах тестов производительности, например в Dromaeo, но они выходят за рамки текущего охвата Nashorn.

Тесты безопасности

Nashorn компилирует исходный код JavaScript и генерирует классы Java. Эти классы загружаются специальным загрузчиком классов. Nashorn позволяет выполнять вызовы Java из JavaScript. Необходимо следить за тем, чтобы такие сгенерированные классы соответствовали модели безопасности Java. Нужны тесты, гарантирующие, что при наличии менеджера безопасности Nashorn также безопасен. Классам скриптов, сгенерированным Nashorn, не должны быть доступны никакие дополнительные разрешения, которые недоступны скомпилированным файлам классов Java.

Влияние

  • Совместимость: Nashorn не будет реализовывать ни одной возможности движка Rhino, имеющегося сейчас в JDK, которая выходит за рамки ECMAScript-262.
  • Безопасность: требуется тестирование
  • Производительность и масштабируемость: требуется тестирование
  • I18n/L10n: да
  • Переносимость: нет; Nashorn не содержит нативного кода.
  • Документация: да