问题描述
如题。假如不能,有哪些关于Java字节码规范的阻碍了这种实现的原因?能啊。作为图灵完备的语言,Java字节码有啥不能描述的?不能就模拟呗。
Java连x86都可以模拟(参考
JPC),区区C#不在话下。
请看Grasshopper,这是一个把MSIL编译到Java字节码,并提供.NET类库对应在Java平台上的实现,而且还做了很棒的Visual Studio整合的神奇的东西。
它由Mainsoft开发,可惜Mainsoft现在已经挂了所以官网看不到了,用另外几个链接解馋吧:
Wikipedia词条:
Grasshopper (software)The Server Side新闻稿:
Grasshopper 2.5 releasedInfoQ新闻稿:
Mainsoft: Running .NET on the JVM While Maintaining Performance当然,既然都扯到“模拟”(emulate)了,C#的需求跟JVM所提供的功能肯定还是有不直接匹配的地方。这方面话题请参考我在
SDCC 2012做的一个演讲:
JVM: A Platform For Multiple Languages话说俺以前在同样的话题里跟老赵谈笑风生的时候也提到过Grasshopper。请跳这俩传送门:
RednaxelaFX 2010-02-23 09:38:00
...
不过有没有人会愿意用一种80%样子和功能跟Java一样、但速度慢10x的JVM语言就不好说了orz
===========================================
简单的几个例子:
- C#支持无符号整数类型,JVM不直接支持。
- 在JVM上要模拟UInt32不难,只要用long来存数据就好了。但这效率方面显然不太好…IBM JVM的JIT编译器甚至有过模式匹配来识别Java代码是否在用long来模拟unsigned int,并优化为用unsigned int来实现对应的功能,以便提高速度。
- 但在JVM上要模拟UInt64就有点烦了,没有内建的比long更宽的整数类型,只好做个对象来模拟了。
- C#支持checked arithmetic(算术溢出时会抛异常),而Java…从Java 8开始也有对应的checked arithmetic API了,例如java.lang.Math.addExact(int, int),可直接对应,不需要模拟。在Java 8之前确实得模拟一下,自己实现溢出检查和抛异常的逻辑。
- C#支持用户自定义值类型,Java到Java 9为止尚未支持这种功能(Java 10或许有指望,参考Project Valhalla)。
- 其实这也好模拟:表面语义上只要值自身是不可变的,或者修改一个值的拷贝不影响其拷贝来源的值,表面上就无法区分底下的值类型是如何实现的了。想想JavaScript的String原始类型,它是值类型,但大多JavaScript引擎的实现都是把String值分配在GC堆上的,传值时传递的是指向堆上对象的指针而不是真的拷贝了String值的内容;但从JavaScript语言的表面上是看不出来这俩的区别的,因为String值不可变。
- 当然,如果这值类型是涉及与native函数做交互的地方,有原生支持跟用对象来模拟多少还是会不一样。这种边角地方得细心处理。
- C#有委托类型,而Java…从Java 7开始有了MethodHandle后这就有委托类型的直接对应物了,不需要模拟。即便在Java 7之前,自己生成类(与匿名内部类的道理一样)去模拟委托类型也不是问题。
- C#支持静态扩展方法,Java… 这功能不需要在VM里支持,而只要在编译器和运行时的binder里实现对应的resolution代码即可。
- C#支持unsafe代码,里面可以做指针运算和通过指针的裸内存访问;MSIL甚至还支持对托管堆外的数据指针的访问以及函数指针的调用。Java的话,可以通过sun.misc.Unsafe以及JNI来模拟。
- C#支持generator(带yield的方法)。其实这主要是个语法糖,在VM层面并没啥特殊处理,脏活都让C#编译器做了。所以这个在JVM上也不需要专门的VM支持。
- C#支持async/await。跟generator同理,这其实也是语法糖和运行时库的配合,并不需要在VM层面做特殊支持。
- C#支持具现化泛型(reified generics),而JVM到Java 9为止并未提供VM层面的具现化泛型的支持。嗯我知道大家都等着这个,所以放到最后说 >_<
- 其实这个也还真的好模拟。JVM没保留足够信息的话,自己在生成的类里存着需要的类型信息不就好了么。
- 例如说,对于泛型类,为每个泛型参数在类里额外带上一个ParameterizedType参数来记录这个泛型参数具体应该是什么值;对于泛型方法,同理,让它对每个泛型参数额外接受一个ParameterizedType参数。
- 当然要处理的细节有很多,例如.NET的泛型的variance与Java的规则不一样,要如何兼容,之类的。
===========================================
能直接在JVM上跑、样子长得像C#的,还有这么个语言:
Stab Language。题主有兴趣参考不?