跳到主要内容

JEP 174:Nashorn JavaScript 引擎

概括

设计并实现一个新的轻量级、高性能的 JavaScript 实现,并将其集成到 JDK 中。新引擎将通过现有 API 供 Java 应用程序使用javax.script,更普遍的是通过新的命令行工具。

目标

  • Nashorn 将基于 ECMAScript-262 Edition 5.1 语言规范,并且必须通过 ECMAScript-262 合规性测试。

  • Nashorn 将支持javax.script(JSR 223) API。

  • 将支持从 JavaScript 调用 Java 代码以及 Java 调用 JavaScript 代码。这包括直接映射到 JavaBean。

  • Nashorn 将定义一个新的命令行工具,jjs用于评估“shebang”脚本、此处文档和编辑字符串中的 JavaScript 代码。

  • Nashorn 应用程序的性能和内存使用情况应该明显优于 Rhino。

  • Nashorn 不会暴露任何额外的安全风险。

  • 提供的库应在本地化下正常运行。

  • 错误消息和文档将国际化。

非目标

  • Nashorn 将仅支持 ECMAScript-262 Edition 5.1。它将不支持第 6 版的任何功能,或其他 JavaScript 实现提供的任何非标准功能。

  • Nashorn 将不包含浏览器插件 API。

  • Nashorn 将不包括对 DOM/CSS 或任何相关库(_例如_jQuery、Prototype 或 Dojo)的支持。

  • Nashorn 将不包括直接调试支持。

动机

Rhino 的性能已经远远落后于其他 JavaScript 引擎。为了提高性能,此时必须重写 Rhino,用旨在充分利用 JVM 的代码生成器替换其解释器。我们没有对非常旧的 Rhino 代码进行重大重写,而是选择从头开始。

将 JVM 推广为除 Java 之外的其他语言的可行平台也符合 Java 社区的利益。这推动了技术的进步并吸引了新的开发人员。

描述

Nashorn 引擎分五个阶段评估 JavaScript 源代码:Lexer -> 解析器 -> 代码生成 -> 加载 -> 运行时。

词法分析器采用 Unicode 字符数组(源)并将其转换为词汇单元或标记流;例如,数字、字符串、标识符或特殊字符。

Nashorn 使用基于 ECMAScript 262 语言规范的递归下降解析器。解析器获取词法分析器生成的标记流并收集与语言语法匹配的标记。当语法单元被识别时,解析器会构造 JavaScript 代码的中间表示(AST/IR)。

代码生成器采用 AST/IR 并生成 JVM 字节代码。执行时,该字节代码实现原始 JavaScript 源代码的语义。

代码生成分两步完成。第一步将 AST/IR 降低到更接近 JVM 指令集。此转换包括转换控件、将表达式简化为原始操作以及简化调用表达式。此步骤还负责定义用于管理数据使用、空间和类型的符号。

第二步通过 ASM 库将 AST/IR 转换为字节代码。 ASM 发出实际的字节代码以形成脚本类。该类缓存在内存中以供脚本加载器稍后使用。

生成脚本类后,需要将其安装到 JVM 中。这是通过安全的自定义类加载器使用 DefineClass 完成的。当在生成的代码中遇到时,该加载程序还用于合成特殊的 Nashorn 对象类。一旦脚本类被加载,它的 runMethod 就会被调用。

需要几个库来支持执行代码。

主运行时库包括直接支持执行代码的方法,例如toString和所需的类型转换例程toNumber,以及诸如 的分配例程allocateArray

链接器库包含帮助invokedynamic使用java.lang.invokeAPI (JSR 292) 绑定调用的方法。绑定过程非常复杂,需要搜索正确的方法,定义防护以确保调用站点始终正确,并在某些内容发生变化而需要不同的正确方法时重新链接。链接器还管理调用历史记录,以便连续重新链接时查找速度更快。

JavaScript 对象库包括对所有标准 JavaScript 对象的支持,例如ObjectFunctionNumberStringDateArrayRegExp等。它还包括字符串操作、复杂数学、应用函数等函数。

Nashorn 用于invokedynamic实现其所有调用。如果调用有 Java 对象接收器,Nashorn 会尝试将调用绑定到适当的 Java 方法而不是 JavaScript 函数。 Nashorn 对于如何解析方法有完全的自由裁量权。例如,如果它在接收器中找不到字段,它会查找等效的 Java Bean 方法。对于从 JavaScript 到 Java 的调用,结果是完全透明的。

Java 开发人员可以使用javax.script(JSR 223) API 来评估和回调 JavaScript 代码。

备择方案

Rhino 有着悠久的历史,并且源代码也与之相匹配。大多数 Rhino 代码都支持解释执行模型。为了获得显着的性能,执行模型需要利用 Hotspot 解释器/编译器。

其他 JavaScript 引擎(例如 V8 和 Nitro)提供了良好的性能,但需要第二个 VM(额外的代码和内存)和桥接 API 来与 Java 通信。

测试

杰克克

现有的 javax.script JCK 测试应该足够了。 Nashorn 只是另一个可通过javax.scriptAPI 访问的脚本引擎。 Nashorn 本身并没有公开自己的新 Java 标准 API,因此不需要额外的 JCK 测试。

功能/单元测试

现有的测试包括:

这些涵盖了大部分功能领域,但这些测试必须适应 Nashorn 基于 TestNG 的测试套件。并非所有这些测试都适用,因为 Nashorn 与 ECMAScript-262 Edition 5.1 兼容,但扩展很少。特别是,mozilla_js_tests 涵盖了 Nashorn 不支持的许多 Mozilla 特定功能。因此,需要进行一些子设置和适应工作才能在 Nashorn 的测试框架内使用这些测试。

javax.scriptAPI 和命令行工具的现有单元测试jrunscript也可以用于 Nashorn。

Nashorn 存储库中的附加单元/回归测试

这些是 Nashorn 开发人员在实现功能和修复错误的过程中开发的测试。

性能测试

为了在 Nashorn 测试框架下运行这些测试,已经做了一些调整工作。

注意:这些性能测试不包括浏览器 API 访问(DOM/CSS_等_)。诸如Dromaeo之类的性能测试套件确实提供了此类测试,但它们超出了 Nashorn 当前的范围。

安全测试

Nashorn 编译 JavaScript 源代码并生成 Java 类。这些类由特殊的类加载器加载。 Nashorn 允许从 JavaScript 进行 Java 调用。必须注意确保此类生成的类遵循 Java 安全模型。需要进行测试以确保在安全经理的领导下,Nashorn 也是安全的。对于已编译的 Java 类文件不可用的其他权限不应可供 Nashorn 生成的脚本类使用。

影响

  • 兼容性:Nashorn 不会实现当前 JDK 中 ECMAScript-262 之外的 Rhino 引擎的任何功能。
  • 安全性:需要测试
  • 性能/可扩展性:需要测试
  • I18n/L10n:是
  • 便携性:否; Nashorn 不包含任何本机代码。
  • 文档:是