
Wasm에 대해서 알아보고, Wasm의 등장 배경에 대해서 다루는 글입니다.
the Web has become the most ubiquitous application platform ever, and yet by historical accident the only natively supported programming language for that platform is javascript.
by Web Assembly 개발자 팀
웹 어셈블리(이하 Wasm) 개발팀은 자바스크립트가 웹에서 동작하는 유일한 프로그래밍 언어가 된 이유는 우연일 뿐이라고 지적한다. 브라우저가 자바스크립트만 해석해야할 이유도 필요도 없다는 사실에 주목하자.
Wasm은 웹 브라우저에서 실행할 수 있는 새로운 형식의 파일을 의미한다. C, C++, RUST 등의 컴파일 언어만이 아니라 Python과 같은 스크립트 언어를 포함하여 약 30개의 언어를 Wasm 형식으로 바꿔 사용할 수 있다. Wasm은 바이너리 포멧으로 변형되기 때문에 웹에서도 네이티브에 가까운 속도로 실행될 수 있어, 웹 플랫폼 기반한 새로운 유형의 서비스를 제공할 수 있다는 큰 장점이 있다.
💡 Wasm의 앞머리가 Web이라 웹에서만 돌아간다고 생각하지 말자!
Wasm은 여러 플랫폼 위에서 네이티브에 가까운 속도로 실행되는 것을 목표한다.
Wasm은 2017년에 등장했고, 현재는 웹 표준이다.

C 언어
int add(int x, int y){
return x + y;
}
WAT 형식으로 변환
(module
(table 0 anyfunc)
(memory $0 1)
(export "memory" (memory $0))
(export "add" (func $add))
(func $add (; 0 ;) (param $0 i32)
(param $1 i32) (result i32)
(i32.add
(get_local $1)
(get_local $0)
)
)
)
Wasm 형식으로 변환
wasm-function[0]:
sup rsp, 8
mov ecx, esi
mov eax, ecx
add eax, edi
nop
add rsp, 8
ret
Wasm이 브라우저에서 해석 가능한 네 번째 언어가 된 이유는 다음과 같다.
사진 출처
스크립트 언어가 가진 한계
자바스크립트(JIT 컴파일러 도입 이전)는 3 가지 단계로 코드를 해석했다. 먼저 코드를 parsing하고 execute한 뒤에 garbage collection순으로 코드를 실행했다. 위 그림을 보면 execute가 대부분의 시간을 차지하는 것을 알 수 있는데, 스크립트 언어가 가진 한계이다.
최근 스크립트 언어들은 실행 시간을 줄이기 위에 JIT(Just-In-Time) 컴파일 기술을 도입해 실행 성능을 향상 시켰으며, 자바스크립트도 마찬가지이다.
사진 출처
JIT 컴파일러 도입 후 성능 개선
JIT 컴파일러가 도입되며 3 단계로 이루어 지던 자바스크립트 실행이 5 가지 단계로 변경됐다. execute 전에 최적화(optimize)하는 과정을 둬서 실행 시간을 획기적으로 줄일 수 있었고, 이를 토대로 웹 플랫폼 외의 곳에서도 자바스크립트 언어가 활용되는 계기가 됐다.
최적화 단계에 대해서 생각해보자
스크립트 언어의 경우 loop에 해당하는 작업도 매번 다시 translate하는 단점이 있다. JIT은 컴파일이 필요하다고 판단이 들 때 컴파일 하는 방식을 의미한다. 컴파일도 비용이 들기 때문에 컴파일이 필요하다는 확률적인 결정을 아주 잘 내려야 한다는 것이다.
그렇지 않다면 JIT을 도입해도 성능 개선을 기대할 수 없다. 컴파일 비용, 컴파일이 필요한 지 아닌지 모니터링 하는 비용, 잘못된 최적화를 다시 조정하는 비용 등이 필요하게 되니 주의해야 한다.
운 좋게도 브라우저나 Node.js가 사용하는 자바스크립트 엔진은 매우 성능이 좋으니 믿고 사용해도 된다.
사진 출처
parse
JavaScript 엔진은 문자열을 의미 있는 토큰들로 변환한 뒤에 구문을 분석해 AST라는 추상 구문 트리를 생성한다. JIT 컴파일러를 사용하는 엔진의 경우 AST를 기계가 바로 해석할 수 있는 바이트코드(Bytecode)로 변환하는 과정을 가치게 된다.
Wasm은 이미 바이너리 코드이기 때문에 디코딩하고 오류 검사만 진행한다.
compile + optimize
둘 다 같은 과정을 거치지만 WASM이 더 빠르다. Wasm이 기계어에 훨씬 가깝고, 모니터링과 같은 과정이 필요없기 때문이다.
re-optimize
JavaScript를 실행하는 과정에만 존재하며, 비슷한 환경에서 재실행되길 기대했던 컴파일 대상이 그렇지 않을 때 일어난다.
execute
해당 단계는 Wasm이 JavaScript에 비해 항상 빠른것은 아니라는 사실에 주목하자. JavaScript도 최적화를 잘 한 상태라면 Wasm과 같은 execute 속도를 기대할 수 있다. 그렇다고 JavaScript가 더 빠른 것은 아니다. WASM에 비해 같거나 느리다.
garbage collection
Wasm는 GC를 지원하지 않아 수동으로 메모리를 관리해야 한다.메모리 관리를 개발자가 직접 해야한다는 것은 단점이지만, 메모리 성능에 대해 신뢰할 수 있다는 장점이 있다.
Wasm은 Figma, AutoCAD Web, Google Earth와 같이 3D 그래픽 처리, 웹 플랫폼 기반 게임 등과 같은 특정 서비스에 사용된다.
Wasm은 CPU 집약적인 작업이 필요한 경우에 높은 성능을 기대할 수 있고 CPU 집약적인 서비스에만 사용해야 한다고 생각한다. 일반적인 웹 어플리케이션의 경우에는 Wasm을 사용할 이유가 없다.
💡 특정한 언어로 된 라이브러리나 애플리케이션을 웹에서 사용하고 싶다면 말리진 않겠지만, 아마도 비슷한 기능을 제공하는 라이브러리가 자바스크립트에도 있을테니 그것을 사용하자.
이렇게 생각하는 이유는 다음과 같다.