Java程序员狂喜!Endive项目让WebAssembly性能起飞,这个项目让Java跑WebAssembly比C++还快,而且不用装任何本地库!
扔掉JNI!Endive让Java直接跑Rust/C/Go代码,速度还不慢,Wasm模块现在能当Java对象调了!
Chicory改名Endive并加入Bytecode Alliance,通过Redline编译器实现Java原生调用Wasm且无本地依赖,性能对标Wasmtime,未来支持组件模型。
这个项目换了个新名字继续干大事
先给你一个大白话总结:以前有个项目叫Chicory,能让Java程序直接跑WebAssembly模块,不用装任何本地代码。现在这个项目改名叫Endive,搬到了一个中立的基金会底下,而且以后跑得更快、支持更多功能。Java程序员以后想用Wasm就跟用普通Java库一样简单。
为什么我要先说这个总结呢?因为后面我要讲的是这个项目怎么来的、为什么换名字、技术上有啥突破。你只要记住一句话就行:以后Java里用Wasm会变成家常便饭,而且跑起来跟C++写的那些运行时一样快。
有人闲着问了个问题然后就造出了东西
2023年9月,有一小撮开发者聚在一起问了个看起来很无聊的问题:能不能在JVM上跑WebAssembly,而且完全不依赖任何本地代码?说白了就是,我写了个Java程序,能不能直接运行一个Wasm文件,就像读个普通文件一样简单,不用调用什么C库、不用装什么动态链接库。
这帮人就开始撸代码。他们搞出来的东西叫Chicory。两年时间不到,这个东西就跑去给一堆大项目当发动机了。比如说JRuby用它来解析Ruby代码,有人写了个纯Java的SQLite驱动跑在它上面,还有人搞了个嵌入式PostgreSQL,甚至有个纯Java的QuickJs运行时也靠它。TrinoDB这个大数据查询引擎,用它来跑Python写的UDF函数。
你看出来没?这帮人本来只是做着玩,结果做着做着就变成了基础设施。就像你家楼下那个卖煎饼的大爷,本来只想混口饭吃,结果成了整个科技园的早餐供应中心。
换个新名字和新家能让项目活得更久
好,前面说了这个项目已经很有用了,那它现在遇到了什么问题呢?问题就是它需要一个更稳定的家。以前Chicory就是几个公司的人凑在一起搞的开源项目,虽然也跨公司合作,但总觉得缺个官方身份。
现在好了,这个项目改名叫Endive,正式加入了Bytecode Alliance。这是个啥组织呢?专门搞WebAssembly生态的,里面有大公司也有独立开发者,目标就是让Wasm变得更安全、更通用、更容易在不同平台上跑。这个组织是中立的,不偏向任何一家公司。
为啥要加入这个组织?因为Java不是个小众平台,它是全世界几百万程序员吃饭的家伙。如果WebAssembly将来要成为跨语言的通用组件格式,Java必须在这个故事里有一席之地。Endive给了这个社区的开发者一个官方地盘,大家可以光明正大地一起干活。
你可以这么理解:以前Chicory就像是个摆地摊的,东西虽然好,但终究是野路子。现在Endive拿到了营业执照,还入驻了万达广场,后面就能招更多人手、干更大的事。
换个编译器就能跑出飞一样的性能
前面说了项目有了新名字和新家,但这只是第一步。接下来最实在的一个技术改进是:换编译器。以前Chicory跑Wasm代码,用的是解释执行的方式,说白了就是一行一行读代码然后模拟执行,速度肯定比不上直接跑机器码。
Endive现在要合并一个叫Redline的实验性编译器进来。这个编译器用的是Cranelift,这玩意儿跟Wasmtime运行时用的是同一个编译后端。Wasmtime是目前最快的Wasm运行时之一,用Rust写的。Endive用了这套编译技术之后,性能就能跟Wasmtime掰手腕了。
最关键的是什么呢?你作为Java程序员,不需要为了这点性能去装任何额外的依赖。在Java 25及以上版本,因为Foreign Function & Memory API(就是那个Panama项目)已经变成标准功能了,Redline编译器可以直接用这个API生成机器码,完全不依赖本地库。
以前你要在Java里跑Wasm,要么图方便用解释器跑得慢,要么图性能去调用本地代码搞得部署很麻烦。现在Endive告诉你:两个都要。既像Java库一样好用,又跑出本地代码的速度。这就好比你想吃火锅又想吃烧烤,以前得跑两家店,现在有一家店给你搞了个火锅烧烤一体桌。
以后Java程序能直接调用别的语言写的组件
前面说了性能问题怎么解决,那下一个问题就是:怎么让Java程序更方便地调用各种语言写的Wasm组件。现在的Wasm模块,你要调用它,得自己手动处理参数怎么传、内存怎么共享,挺麻烦的。
Wasm社区正在搞一个东西叫Component Model,直译就是组件模型。这个东西定义了组件之间怎么通过类型明确的接口互相调用,不管你组件是用Rust写的还是Go写的还是C写的。接口是明确的、带类型的,不像以前那样就是一堆字节流。
Endive要把这个组件模型完整实现在JVM上。这意味着啥呢?你是一个Java程序员,想用别人写好的一个Rust组件,你不用去学Rust,也不用写JNI那种恶心人的胶水代码。你只需要拿到这个组件的接口定义文件,Endive帮你生成Java的绑定代码,你在Java代码里就像调用普通Java对象一样调用它。
更重要的是安全和控制。Java服务加载一个组件的时候,可以精确控制这个组件能访问什么资源,比如能不能读文件、能不能发网络请求。这些控制都是通过类型接口明确声明的,不是靠猜的。而且你还能用JVM自带的那些监控工具去观察这个组件在干啥,比如用jstack看线程、用jmap看内存。
这套东西一旦搞成了,Java会成为第一个深度集成组件模型的主流托管运行时。什么叫托管运行时?就是像JVM、.NET CLR这种有垃圾回收、有安全管理的运行环境,跟C++那种直接跑在硬件上的不一样。我们希望在Java上学到的经验,以后能帮其他托管运行时做类似的事情。
接下来要干的三件大事
前面我讲了Endive这个项目的来历、为什么换名字、性能怎么提升、组件模型是啥。现在给你捋一下接下来具体要干什么。
第一件事,把Redline编译器正式合并到主分支,让默认的运行时就用这套新编译器,性能直接拉满。这事已经有人在干了,不会让大家等太久。
第二件事,把Wasm标准的兼容性做到位。Wasm标准本身一直在加新功能,比如WasmGC(让Wasm模块也能用垃圾回收)这种提案。Endive要跟上这些标准,确保你写的Wasm模块不管在哪个运行时跑,行为都一样。
第三件事,加深对WASI和组件模型的支持。WASI就是WebAssembly的系统接口,相当于让Wasm模块能访问文件、网络这些操作系统功能。Endive要让Java程序通过WASI去加载和管理组件,做到跟本地程序一样的体验。
小结一下这个项目到底牛逼在哪
Endive这个项目,说白了就是在做一件事:让Java和WebAssembly这两个大家伙能够无缝地一起工作。以前你要在Java里用Wasm,要么慢要么麻烦。现在Endive给你一个方案:不加本地依赖、跑得快、支持组件化调用、有中立基金会在背后撑腰。
这个项目会继续用Apache 2.0开源协议,谁都可以拿去用,谁都可以来改。如果你是搞Java的、搞Wasm的、搞插件系统的、搞跨语言组件的,或者你就是单纯觉得这玩意儿有意思,都可以来一起搞。
代码已经放在那了,第一个正式版本会尽量保持跟Chicory的兼容性,老用户迁移不会有太大痛苦。接下来就是一路狂飙,让Java生态彻底拥抱WebAssembly。
极客辣评
像这样的项目在 JDK 25+(严格来说是 24+)中开发会更有趣也更容易,因为有了新的 Java 类文件/字节码 API。Endive 似乎使用了 OW2 汇编,可能是因为它支持 JDK 11。新的 JDK API 的最低目标版本是 JDK 17。不过,恕我直言,OW2 汇编的难度要高得多。
我之所以会关注这个项目,是因为我刚刚完成了 Petrify( https://github.com/exabrial/petrify )的一个主要版本发布,它可以将机器学习模型编译成 JVM 字节码。编译过程需要 JDK 25,但编译后的模型可以在 JDK 17 及更高版本上运行。
如果它能成为第二个同时支持垃圾回收和 WASI 组件模型的流行运行时,那就太好了。目前只有 Wasmtime 具备这种组合,这有点令人担忧。
终于可以在桌面上运行 Kotlin/WASM 了!
我们解决了相反的问题,通过 WebAssembly 在浏览器中运行任何 Java 应用程序:https://labs.leaningtech.com/blog/cheerpj-4.3
是的,它也能运行 Minecraft :-) https://browsercraft.cheerpj.com/