GE Energy利用InvokeDynamic指令将Magik移向JVM

今年7月,GE能源管理业务(GE Energy Management)从GE能源集团分离出来。同月,其数字能源部门(Digital Energy)透露,他们正在将Magik(一种受Smalltalk启发而设计的编程语言)从其专有的虚拟机MagikSF移植向JVM。

Magik是一种动态类型的面向对象语言,支持多重继承和多态。它最初出现于1990年,比Java还要早。Magik已用于GE能源集团的Smallworld技术平台,而且该语言就是为实现面向企业设施(如配电)和电信的复杂应用而设计的。比如在电信领域,GE能源管理业务有一款名为Physical Network Inventory的产品,支持电信公司规划和管理其铜线、光纤和电缆的电信网络。在企业设施方面,其产品Electric Office为配电公司提供了类似功能。

Magik看起来非常像Ruby。下面是一个简单的“hello world”例子程序:

 Magik> _for i _over 1.upto(3)
                _loop
                write("Hello world ", i)
                _endloop

在Ruby中写法如下:

1.  upto(3) do |i|
  puts("Hello world #{i}")
end

这两段代码的输出相同,如下:

Hello world 1
Hello world 2
Hello world 3

虽然移植工作今年7月份才向外界透露,但GE能源集团的团队在一年之前——也就是2011年7月——就开始了概念验证工作,有一个小团队在工作中使用了Java 7的早期发布版本。 团队主管、架构师George Marrows向InfoQ说到,

这非常成功,从那时起我们就为产品发布版本而努力了。我们编写了Magik语言的解析器、编译器和运行时,集成了我们的大多数C库,并且使用Java2D编写了一个全新的图形子系统,所有新设计的组件都与现有系统高度兼容。

移植尚不彻底,不过移植版本已经能够运行完整的应用程序。最关键的是,考虑到GE能源集团的合作伙伴与客户所编写的数百万行Magik代码,移植版本的目标是完全兼容MagikSF版本,开发者只需要简单地在JVM移植版本上重新编译Magik源代码。Marrows对我们说,“我们确信,我们的语言实现与MagikSF 非常非常接近,我们的库支持也做得非常好,而且随着运行的Magik代码越来越多以及不断修复不兼容的地方,改进也在持续进行。”

正如你所预料的那样,考虑到Magik的动态类型系统,移植版本大量使用了Java 7的 invokedynamic字节码指令。Marrows说到,

我们大量使用了invokedynamic,不仅是在明显的方法分派(method dispatch)中,在将复杂字面量绑定到其使用位置以及解析全局变量时也有所应用。Duncan MacGregor在团队中负责这项工作——使用invokedynamic,他一度发现几乎每周都有性能改进。

invokeDynamic和java.lang.invoke的使用体验非常好。我们可以将其看做JVM JIT编译器方法内联功能的一个API,就这一点而言,它非常出色。我们惊喜地看到,自从去年Java 7的第一个版本发布以来,几乎每次更新都能带来一些性能改进;而且看起来我们还可以从Java 8的“lambda form”工作中继续获得改进。

从技术角度看,JVM的很多功能MagikSF是不支持的,比如

  • MagikSF是解释型的,而JVM支持JIT编译。
  • MagikSF使用的是绿色线程,而JVM使用原生线程。
  • MagikSF只支持32位,而JVM也支持64位。
  • MagikSF有自己的垃圾收集器,其垃圾收集器是分代的,但并非并发垃圾收集器;而在Hotspot虚拟机中,Java支持多种垃圾收集器,大多是并发收集器。

当然,像Oracle和IBM等大型软件厂商所贡献的大量资源和专家经验也让JVM获益良多。

Marrows的团队看到的性能改进结果令人印象深刻:在他们运行的大多数基准测试中,Java移植版本的速度已经有所超越,有些情况下性能改进高达30倍。就像Marrows所指出的那样,随着时间的推移,invokeDynamic和JVM的性能不断改进,他们的项目也相应获益,诸如在Java 7 update 9上要比在Java 7 update 2上执行得更好。更重要的是,作为Java 8 Lambda 项目的一部分,Oracle重新设计了invokeDynamic;而且这一版本正在被向后移植到Java 7中(按照计划,该特性将包含在即将发布的update 12中)。尽管Marrows告诉我们,有些代码实例表明,相对于update 9,在update 12上运行当前测试构建时性能有些劣化,但是在很多情况下新版本会快得多;这点他们会与Oracle的团队讨论。到目前为止,Marrows的团队从Oracle,特别是JSR 292专家组的Rémi Forax那里得到了极大的支持,Rémi Forax “帮助我们开始使用JSR 292,而且在MLVM(multi-language virtual machine)邮件列表中,他是一位不知疲倦的贡献者”。

虽然最初没有相应计划,但团队现在还是通过混用JNI和Java 2D的方式移植了图形系统——“将JNI与C库继承,可以访问我们的数据库并执行优化的几何与其他计算。Java 2D渲染贴图和UI。”

该团队最终实现的从Java到Magik的内置的互操作还相当不错,Java 2D所支持的图形系统中大量使用了这一特性。比如:

def_slotted_exemplar(
  :line_style,
    { { :colour, colour } },
    { :simple_style_mixin},
 {:|com.gesmallworld.magik.commons.drawingsurface.LineStyle|})
 $ 
_private _method line_style.|getColour|()
   >> .colour
_endmethod

|getColour|中的竖线用于保留Java代码里的大小写,因为Magik是不区分大小写的。

而从Magik到Java的互操作就不是那么方便了,需要开发者编写包装代码。

public class Char16Vector {
    @MagikInitialiser
    public static void exposeThisClass() {
        //Expose an instance of this class to Magik
    }
    @MagikMethod(name="nth()")
    public Char16Vector nth( Integer index ) {
        return new Char16Vector(value.substring(index-1, index));
    }
}

Nashorn是Oracle的新JavaScript实现。利用Dynalink库,它能够更清晰地实现该功能。Jim Laskey在其博客上提供了一个很好的例子,通过Twitter4J 库,使用Nashorn与Twitter交互,可以很好地实现上述功能。Marrows告诉我们,Dynalink就是他和团队想要看到的东西。

除了能够使用Java虚拟机之外,该团队发现跑在Java平台上还有其他的优点。Marrows在JavaOne Brazil大会上提到,能够接近Java开发者并使用Java类库,这也是优势。此外他告诉我们,

...我们非常欣赏JVM带来的力量和灵活性,这能够支持我们未来所要进行的任何改进。

更一般的意义是,我们趁此机会简化并替换了我们迄今为止所开发的MagikSF环境的某些部分,如图形支持和文件I/O等。我们认为这种事情以后做的话,工作量只会多不会少。

JVM上的语言越来越多,Magik就是其中之一,其他还包括Groovy、Jruby和Nashorn等,这些语言都用到了invokeDynamic指令。JSR 292真正帮助JVM成为一种通用的编程语言环境。

参考英文原文:GE Energy Uses InvokeDynamic to Bring Magik to the JVM

你可能感兴趣的:(GE Energy利用InvokeDynamic指令将Magik移向JVM)