JSR 292和多语言JVM

1 篇文章 0 订阅

2021年9月18日

jsr 292的功能

介绍
微软(Microsoft)通过.NET 4和DLR ,Oracle通过Da Vinci Machine项目和Java 7都在寻求改善对针对各自虚拟机的替代语言的支持。 这样,它们反映了语言开发人员和实施人员之间日益增长的趋势,他们越来越多地使用预先存在的运行时环境来托管其语言,因为从头开始开发新的运行时代表了如此重大的投资。 JVM平台的优势,例如有效的垃圾收集,强大的安全模型和JRE的广泛可用性,以及广泛选择的现有库和工具,已使JVM平台广泛用于此目的,大约有240个平台在其之上实现了不同的语言 。

但是,尽管有很多原因使JVM对语言实现者来说是有吸引力的平台,但Java字节码的设计目的是仅满足一种语言的需求,即Java本身。 因此,对于开发动态或功能语言的开发人员而言,这构成了巨大的挑战。 方法调用站点周围出现一个常见问题。 JVM对如何互连方法施加了许多限制,有利于静态引用或通过类或接口进行分派。 接收方类型必须符合呼叫站点的已解析类型,并且呼叫站点必须链接,这意味着已解析方法始终存在。 调用是静态类型的,并且需要Java类型。 这些限制非常适合Java,但其他语言则具有其他通常更宽松的调用规则。

由于Java是通用语言,因此可以使用基于对象的API来模拟其他选项或放宽方法调用的规则。 在John Rose关于InvokeDynamic的详细论文 (PDF文档)中,他将此方法称为模拟器方法 。 Java的反射API包含一个众所周知的示例-java.lang.reflect.Method.invoke,以及 还存在许多其他特定于语言的等效项,例如Clojure的clojure.lang.IFn.invoke或JRuby的DynamicMethod.call 。 使用这种方法,JRuby团队能够实现Ruby实现, 其性能大约是标准C版本的两倍 。 从本质上讲,这也是Microsoft为其.NET使用DLR所采用的方法。 但是,尽管该方法行之有效,但却带来了相当大的执行开销和复杂性,因此Sun决定走得更远。 达芬奇机器项目不是像微软那样通过库添加标准的模拟器方法,而是旨在在JVM级别进行更改。 旨在包含在Java 7中的JSR 292将成为该项目实现标准化的第一个结果。

JSR 292主要关注动态语言的需求。 它引入了两个关键的新概念-新方法调用指令,以及带有相应类型转换器工厂的方法句柄。 它还扩展了Java标识符的语法,该标识符的拼写可以是任何字符序列(称为“异国标识符”)。

InvokeDynamic和方法句柄
在Java 6中,字节码规范具有四个方法调用指令,它们直接与Java方法调用相对应:

invokestatic ,用于调用类方法
invokespecial ,用于在调用超类中的方法以及私有方法时调用实例初始化方法;
invokevirtual ,实例方法的常规方法调用
接口方法的invokeInterface
其中,虚拟调用和接口调用可能满足动态语言的目的,但是对于动态语言运行时来说,它们不够灵活,无法在运行时将调用站点绑定到目标,前提是该调用站点之前不知道目标接口绑定。 因此,JSR 292添加了第五种方法调用invokedynamic ,它充当标记,指示此时发生了动态语言运行时特定的调用。 在JVM级别,使用invokedynamic指令来调用具有非Java语言定义的链接和调度语义的方法。

像其他四个调用指令一样, invokedynamic是静态类型的,但是,在程序的控制下,使用方法句柄可以动态链接一个invokedynamic指令。 方法句柄并不是一个全新的概念,类似于SmallTalk的perform或Objective-C的performSelector 。 Rose在他的博客中简要介绍了其功能:

给定我可以调用的任何方法M,JVM为我提供了一种生成方法句柄H(M)的方法。 以后,即使忘记了M的名称,我也可以使用此句柄来按需要多次调用M。 而且,如果我将此句柄提供给其他调用者,即使他们没有按名称调用M的访问权限,他们也可以通过该句柄调用M。 如果方法是非静态的,则方法句柄始终将接收方作为其第一个参数。 如果方法是虚拟的或接口的,则方法句柄在接收方上执行分派。
方法句柄将通过类型操作以一系列Class值的方式反射性地承认其类型。

除了将方法绑定到后期调用站点之外,动态语言还会在运行时进行大量的自动类型转换,例如,将给定方法的字符串“ 12345”转换为Integer。 动态语言运行时开发人员可以使用适合通过方法句柄调用的适配器方法来创建转换类,但是为每个可能的签名和目标创建一个适配器类是行不通的。 因此,JSR 292引入了用于生成这些适配器类的工厂。 JRuby主管Charles Nutter告诉我们:

JSR-292中的MethodHandles API提供了用于在调用方和目标方法之间编写简单的“胶水”的基本构件。 InvokeDynamic通过在进行动态调用时联系您的语言或库来工作,您可以通过提供适当地连接调用者和被调用者的方法句柄(或方法句柄链)来对此进行响应。 例如,如果在进行动态调用的过程中需要重新排序参数,则可以在链中插入“置换参数”句柄。 如果您需要使用异常处理包装最终目标,则可以插入“捕获异常”句柄。 这里有用于访问字段,调用其他Java方法,扩展/扩展参数(与“可变参数”数组之间的参数),在条件上分支的句柄等等。
如果可用的句柄不能满足您的所有需求,您还可以扩展JavaMethodHandle并自己在Java中实现逻辑。 这使您可以提供更复杂的逻辑,而无需将所有内容分解成小块。

您可以将MethodHandles视为“ JVM的函数指针”,并具有以JVM直接理解的形式表示更复杂的调用序列的额外好处。 我认为它们是JSR-292最酷的部分。

查尔斯·纳特(Charles Nutter)在博客中写道,详细描述了他使用InvokeDynamic的早期经验。 使用早期的InvokeDynamic实现,Nutter及其团队能够大大简化其实现,而不会降低性能。 我们问他InvokeDynamic是否能够击败原始的JRuby实现。

首先,我需要解释说,在调用动态技术之前,我们(JRuby)已经做了很多工作,以尽可能提高性能。 这涉及许多技巧,旨在诱使JVM像优化Java代码一样优化Ruby代码,而且我相信JVM上的任何其他动态语言都无法像我们所做的那样多。 因此,要使invokedynamic击败我们,它必须做很多工作。
就是说,在OpenJDK 7的最新版本中,invokedynamic已经开始击败股票JRuby的动态调用性能。 这并不是100%的时间更快,您必须稍微调整一下JVM的内置优化阈值,但是绝对可以达到目标。 也没有我们在整个JRuby中充分利用invokedynamic和方法句柄。 只有某些类型的调用才能使用invokedynamic,并且通过连接其余的JRuby,我们肯定会看到类似的好处。 这可能会在整个夏天发生,因为invokedynamic参考实现的API会逐渐降低。

Java语法
JSR292的这三个主要JVM功能– InvokeDynamic,方法句柄和奇异标识符,将具有通过Project Coin提案实现的相应源代码语法。 这项更改将为Java提供一种与依赖于InvokeDynamic字节码指令的新JVM语言进行互操作的机制,并且在使用javac和JVM作为开发新的编程语言和语言的平台时,还有望减少对字节码操作技术的依赖。运行时。

仅静态类java.dyn.InvokeDynamic支持动态调用:
Object x = InvokeDynamic.getMeSomething();

使用类java.dyn.MethodHandle可以检索虚拟调用的方法句柄:
MethodHandle mh = …;
mh.invoke();

应该注意的是,InvokeDynamic和MethodHandle都暴露了检查异常的潜在漏洞,尽管InvokeDynamic或虚拟调用可能会生成检查异常,但是无法静态推断在编译时可能从给定调用站点抛出哪些异常时间。 尽管这进一步削弱了Java语言中的检查异常模型,但提案Wiki认为这并不代表一个新问题。

由于已经构造Java程序来处理未检查的异常和错误,因此,错过捕获被检查的异常的可能性不认为是危险。 实际上,如果不放松静态异常检查,就无法支持动态语言。
外来标识符
Coin提案还提供了对奇异标识符的直接支持,使用哈希符号将其引入并放在引号中:
int #“strange variable name” = 42;
System.out.println(#“strange variable name”); // prints 42

奇异标识符不能为空,因此int#“”; 将是非法的。 某些“危险”字符,特别是/。 ; <> []在外来标识符中是非法的,除非它们前面带有反斜杠字符,即使对于字符串或字符文字而言这不是真的。 如果在危险字符前加反斜杠,则会删除反斜杠并收集字符。 如果转义的字符会参与JVM规范禁止的字节码名称,则编译器将拒绝包含奇异标识符的程序。

结论
JSR 292允许JVM组合字节码(仍然是静态计算的最有效表示形式)和方法句柄图,这是一种将计算进行实时组合的更有效方法。 这样,JSR 292的新功能使JVM上的动态和静态语言的混合和匹配方法更加容易,从而使开发人员更容易选择适合工作的语言。

可以合理地假设JVM的未来版本会更进一步。 JSR 292本身专注于动态语言的功能,而达芬奇机器项目则探索了功能语言更需要的功能,例如尾部调用, 延续和接口注入 。 其中一些将来可能会标准化。

翻译自: https://www.infoq.com/articles/invokedynamic/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

jsr 292的功能

相关资源:JSR286(Portlet2)中文参考手册_JSR286-Web开发文档类资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值