GeekNews를 보던 중 Javy라는 물건을 발견했다.
Javy?
JS 코드를 웹 어셈블리(이하 WASM)에서 돌릴 수 있도록 만들어 주는 툴 체인이다. JS 코드를 가져온 뒤, WASM에 임베드 된 JS 런타임으로 실행을 하며, dynamic linking을 사용하면 아주 작은 크기의 웹어셈 모듈을 만들 수 있다고 한다. 즉, JS 코드를 가져와서 WASM 위에 올리고, 그걸 다시 node로 돌릴 수 있다는 뜻이다!
....??
대체 왜 이런 짓을 하는가?
처음 보면 이해가 잘 안 되는 광경일 수 있다. 사실 나도 그랬다. 기껏 JS로 코드를 짜놓고 WASM 모듈로 올린다니? 그냥 JS로 쓰면 되잖아? 그 이유를 알기 위해 Javy의 역사를 잠시 훑어 볼 필요가 있다.
Javy는 원래 Shopify에서 만든 오픈소스 프로젝트였다. 그 뒤, 현재는 Bytecode Alliance에서 관리하고 있다. Shopify는 온라인 이커머스 플랫폼으로, 쇼핑몰을 간단하게 만들 수 있도록 도와주는 일을 주로 하고 있다.
그러면 더욱 더 이해가 안 가기 시작한다. 쇼핑몰 플랫폼에서 왜 이런 걸 내놓았을까?
Shopify에서 내놓은 기능인 Shopify Functions 때문이다. 이게 무엇인고 하니, 유저가 운영하는 쇼핑몰의 백엔드 로직을 커스터마이징 할 수 있는 기능이다.
스토어 파이프라인을 자기 입맛대로 바꿀 수 있도록 해 주는 굉장히 신기한 서비스인데, 이걸 구현하기 위해 WASM이 쓰였다고 한다. WASM의 특징 중 하나인 샌드박스가 유용하게 쓰인 모양. 물론 브라우저 밖에서 사용하는 것이니 WASI를 활용했다. 따라서 WASM과 잘 맞는 rust를 기본 언어로 사용하는 Shopify Functions를 출시하게 된다.
하지만 문제가 하나 있는데, 대부분의 웹 개발자들은 rust를 쓸 줄 모른다는 사실! 다들 JS를 주로 쓰는데 이것 때문에 rust를 입문하기엔 rust의 진입장벽이 너무 높다. 따라서 Shopify는 WASM에 JS를 올린다는 발상을 실천으로 옮기게 되는데...
However, at the time of writing, WebAssembly’s architecture makes JIT-ing impossible. There’s no way for Wasm to generate and then execute code, as the memory storing the instructions is completely inaccessible to the module itself. This is by design: By preventing any code that wasn’t present during module instantiation from being executed, almost all remote code execution vulnerabilities become impossible.
아뿔사, 그냥 기존의 JS 엔진을 가져오려 했지만 WASM에선 JIT가 불가능하다는 문제에 직면했다. 보안 이슈로 막아놓은 것. 따라서 다른 대안을 찾아야 했다.
그렇게 찾은 대안은 바로 QuickJS. C로 구현한 JS 엔진이다. ES2020 까지 지원한다. C이기 때문에 WASM 위에 올라간다!
따라서 JS 스크립트를 받은 뒤, QuickJS를 통해 QuickJS 바이트코드로 변환하고, 그걸 WASM 위에 올린 뒤 실행하는 엄청난 마개조가 완성되었다.
결론
처음 봤을 땐 이런 물건이 나온 이유를 짐작하기 힘들었는데, 역시 다 이유가 있었다. 나름 합리적인 이유로 재미있는 결과가 나왔다는 게 굉장히 흥미로웠다. 적정기술의 훌륭한 예를 볼 수 있었던 흔치 않은 기회였다.