본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
WebAssembly, Wasm; 웹어셈블리
웹 브라우저와 그 밖의 환경에서 안전하고 빠르게 실행되도록 설계된 이식 가능한 바이너리 명령어 형식

WebAssembly(웹어셈블리, 줄여서 Wasm)는 스택 기반 가상 기계를 위한 이식 가능한 바이너리 명령어 형식이다. C, C++, Rust, Go 같은 언어로 짠 프로그램을 컴파일해 .wasm 파일로 만들면 브라우저가 이를 검증한 뒤 기계어로 번역해 네이티브에 가까운 속도로 실행한다. 사람이 읽을 수 있는 텍스트 형식(.wat)도 함께 정의되어 있다.

WebAssembly는 프로그래밍 언어가 아니라 컴파일 대상(target)이다. 이름에 "어셈블리"가 붙은 것은 웹에 어셈블리 수준의 저수준 코드를 들여온다는 뜻이지만, 실제 CPU 명령어가 아니라 특정 하드웨어에 매이지 않은 바이트코드다. 자바스크립트를 대체하려는 것이 아니라 계산이 무거운 부분(영상·이미지 처리, 게임 엔진, 물리 시뮬레이션, 암호, 압축, CAD, 머신러닝 추론)을 맡아 자바스크립트와 함께 쓰도록 설계되었다.

2019년 12월 5일 W3C 권고안이 되었고, W3C는 HTML, CSS, 자바스크립트에 이은 "웹의 네 번째 언어"라고 소개했다.[1] 설계는 처음부터 웹 밖에서도 쓸 수 있게 했기 때문에, 지금은 서버리스 플랫폼, 엣지 컴퓨팅, 플러그인 시스템, 블록체인 스마트 계약 실행기 등에서도 쓰인다.

전신: asm.js와 Native Client

편집 원본 편집

웹에서 네이티브 코드를 빠르게 돌리려는 시도는 두 갈래였다.

기술 만든 곳 방식 결말
Native Client(NaCl), PNaCl Google x86·ARM 네이티브 코드(NaCl) 또는 LLVM 비트코드(PNaCl)를 소프트웨어 결함 격리 샌드박스에서 실행 Chrome만 지원. WebAssembly 등장 뒤 폐기
asm.js Mozilla(2013) 자바스크립트의 엄격한 부분 집합. x | 0(정수), +x(실수) 같은 표기로 타입을 드러내 엔진이 미리 컴파일(AOT)할 수 있게 함. Emscripten이 C/C++를 asm.js로 변환 모든 브라우저에서 돌지만 파일이 크고 파싱이 느림. WebAssembly의 직접적인 출발점

asm.js는 "자바스크립트로도 C++에 가까운 속도가 난다"는 것을 보였지만, 텍스트라서 크고 파싱이 오래 걸렸다. 64비트 정수도 없었다. 같은 의미를 압축된 바이너리로 표현하자는 것이 WebAssembly의 출발이었고, 초기 기능은 asm.js와 표현력이 같게 맞추었다.

  • 2015년 4월: Mozilla의 Luke Wagner가 WebAssembly/design 저장소에 첫 설계 문서를 올렸다.[2]
  • 2015년 6월 17일: Mozilla, Google(Chromium), Microsoft(Edge), Apple(WebKit) 엔지니어들이 함께 WebAssembly를 발표했다. 네 브라우저 팀이 같은 날 서로 연결된 블로그 글을 올렸다.[3][4] W3C 커뮤니티 그룹에서 설계가 진행되었다.
  • 2016년: Unity의 게임 데모 Angry Bots를 Firefox, Chrome, Edge에서 WebAssembly로 돌리는 시연이 있었다.
  • 2017년 3월: 첫 버전(MVP, 최소 기능 제품)의 바이너리 형식, 자바스크립트 API, 참조 인터프리터에 합의하고 미리 보기 단계를 끝냈다. Firefox 52가 가장 먼저, 몇 주 뒤 Chrome 57이 기본 활성화했다.
  • 2017년 9~11월: Safari 11, Edge 16이 지원하면서 11월 Mozilla가 "모든 주요 브라우저에서 지원"을 선언했다.[5]
  • 2018년 2월: W3C WebAssembly 작업 그룹이 핵심 명세, 자바스크립트 인터페이스, 웹 API 세 문서의 첫 공개 초안을 냈다.
  • 2019년 3월: Mozilla가 브라우저 밖 실행을 위한 시스템 인터페이스 WASI를 발표했다.
  • 2019년 11월 12일: Mozilla, Fastly, Intel, Red Hat이 Bytecode Alliance를 세웠다. 첫 프로젝트는 Wasmtime, Lucet, WAMR, Cranelift 등이다.[6]
  • 2019년 12월 5일: WebAssembly 핵심 명세 1.0이 W3C 권고안이 되었다.[1]
  • 2022년: 벡터(SIMD) 명령, 대량 메모리 연산, 다중 반환값, 참조 타입을 담은 2.0 명세의 첫 공개 초안이 W3C에 올라왔다.
  • 2025년 3월 20일: WebAssembly 2.0이 완료되었다고 발표되었다. 작업 그룹은 2.0부터 최종 권고안(REC)으로 올리지 않고 후보 권고안(CR)을 계속 고쳐 가는 상시 갱신(evergreen) 방식을 택했다.[7]
  • 2024년 1월 25일: 컴포넌트 모델을 바탕으로 다시 설계한 WASI 0.2(Preview 2)가 나왔다.[2]
  • 2025년 9월 17일: WebAssembly 3.0이 발표되었다. 64비트 주소 공간, 가비지 컬렉션, 예외 처리 등 대형 기능이 한꺼번에 표준에 들어갔다.[8]

WebAssembly 명령은 값 스택 위에서 동작한다. i32.add는 스택에서 두 값을 꺼내 더한 결과를 다시 넣는다. 스택 기계를 고른 이유는 레지스터 기계보다 코드 밀도가 높아 파일이 작기 때문이다. 스택의 모양은 컴파일 시점에 정해지도록 제한되어 있어서(분기마다 넣고 빼는 값의 개수가 맞아야 함), 엔진은 스택을 실제로 흉내 내지 않고 곧바로 레지스터 할당된 기계어로 바꿀 수 있다.

기본 값 타입은 정수 i32, i64와 부동소수점 f32, f64 네 가지다. 여기에 128비트 벡터 v128(2.0), 불투명 참조 funcref, externref(2.0), GC 구조체·배열 참조(3.0)가 더해졌다. 정수에는 부호가 없고, 부호 있는·없는 해석은 명령(i32.div_s, i32.div_u)이 정한다.

구조적 제어 흐름

편집 원본 편집

일반 어셈블리와 달리 임의 주소로 뛰는 점프 명령이 없다. block, loop, if/else로 중첩 블록을 만들고, br n은 n단계 바깥 블록으로 빠져나간다(loop이면 처음으로 돌아간다). br_table은 C의 switch에 해당한다. 이 제약 덕분에 엔진이 코드를 한 번 훑는 것(single pass)만으로 검증하고 컴파일할 수 있고, 제어 흐름을 하이재킹하는 공격이 어려워진다. C의 goto 같은 비구조적 흐름은 컴파일러가 Emscripten의 Relooper 같은 알고리즘으로 구조화한다.

WebAssembly에서는 .wasm 파일 하나가 모듈 하나다. 모듈은 섹션들로 이루어진다.

섹션 내용
type 함수 시그니처 목록
import / export 바깥(자바스크립트나 호스트)에서 받는 함수·메모리·테이블·전역 변수, 바깥에 내보내는 것
function / code 함수 선언과 본문(선언을 본문보다 먼저 두어 병렬 컴파일이 쉽다)
table 함수 참조 배열. 함수 포인터와 간접 호출(call_indirect)에 쓴다
memory 선형 메모리의 초기·최대 크기
global 전역 변수
data / elem 메모리·테이블 초기화 데이터
start 인스턴스화할 때 자동 실행할 함수
custom 디버그 정보(DWARF), 이름, 소스 맵 등 실행과 무관한 부가 정보

모듈은 상태가 없는 코드이고, 여기에 import 값을 채워 인스턴스(instance)를 만들어야 실행된다. 한 모듈로 여러 인스턴스를 만들 수 있다.

선형 메모리(linear memory)는 모듈이 쓰는 하나의 연속된 바이트 배열이다. 64KiB 단위 페이지로 크기를 정하고 memory.grow로 늘릴 수 있지만 줄일 수는 없다. 주소는 이 배열 안의 오프셋일 뿐이라 모듈은 배열 밖, 즉 엔진이나 브라우저, 다른 모듈의 메모리를 가리킬 방법이 없다. 모든 메모리 접근은 범위 검사를 받고, 64비트 엔진은 보통 가상 메모리 예약과 가드 페이지로 검사 비용을 거의 없앤다.

선형 메모리 밖에 따로 있는 것이 값 스택, 호출 스택, 함수 코드, 테이블이다. 호출 스택이 선형 메모리에 없으므로 버퍼 오버플로로 반환 주소를 덮어쓰는 고전적 공격이 통하지 않는다. 다만 C 컴파일러가 선형 메모리 안에 따로 만드는 "그림자 스택"의 지역 배열끼리는 서로 덮어쓸 수 있다.

샌드박스 보안 모델

편집 원본 편집
  • 로드할 때 타입 검사를 거친다. 검증을 통과하지 못한 모듈은 실행되지 않는다.
  • 모듈은 import로 받은 것 말고는 바깥 세계(파일, 네트워크, DOM, 시스템 호출)에 접근할 수 없다. 권한은 호스트가 명시적으로 넘겨준 함수로만 생긴다. 이것이 능력 기반 보안(capability-based security) 구조다.
  • 브라우저에서는 자바스크립트와 같은 샌드박스, 같은 출처 정책과 CSP를 따른다. CSP 3는 eval을 허용하지 않고 Wasm 컴파일만 허용하는 'wasm-unsafe-eval' 키워드를 정의한다.

바이너리와 텍스트 형식

편집 원본 편집

바이너리 형식은 매직 넘버 00 61 73 6D(\0asm)와 버전 01 00 00 00으로 시작하고, 정수는 가변 길이 LEB128로 저장해 크기를 줄인다. 내려받는 도중에 컴파일을 시작하는 스트리밍 컴파일과 함수별 병렬 컴파일을 고려해 설계되었다. 텍스트 형식(WAT)은 S-표현식 문법을 쓴다.

C 함수와 이를 컴파일한 결과를 비교하면 다음과 같다.

long long factorial(long long n) {
    return n == 0 ? 1 : n * factorial(n - 1);
}
(module
  (func $factorial (export "factorial") (param $n i64) (result i64)
    (if (result i64) (i64.eqz (local.get $n))
      (then (i64.const 1))
      (else
        (i64.mul
          (local.get $n)
          (call $factorial (i64.sub (local.get $n) (i64.const 1))))))))

같은 함수 본문을 접지 않은(linear) 명령 나열과 바이너리로 쓰면 다음과 같다.

명령 바이트
local.get 0 20 00
i64.eqz 50
if (result i64) 04 7E
i64.const 1 42 01
else 05
local.get 0, local.get 0 20 00 20 00
i64.const 1, i64.sub 42 01 7D
call 0, i64.mul 10 00 7E
end, (함수 끝) end 0B 0B

텍스트와 바이너리 변환은 WABT 도구 모음의 wat2wasm, wasm2wat, 최적화는 Binaryen의 wasm-opt로 한다. 텍스트 형식으로 직접 코드를 쓸 수도 있지만 대개는 디버깅과 학습용이다.

자바스크립트와 연동

편집 원본 편집

브라우저에서는 자바스크립트 API로 모듈을 불러오고, import 객체로 함수를 넘기고, export된 함수를 호출한다.

const imports = {
  env: { log: (x) => console.log('from wasm:', x) }
};
// 서버가 Content-Type: application/wasm 으로 보내야 스트리밍 컴파일이 된다
const { instance } = await WebAssembly.instantiateStreaming(fetch('/math.wasm'), imports);

console.log(instance.exports.factorial(10n));   // i64는 JS BigInt로 주고받는다

// 선형 메모리는 ArrayBuffer로 보인다. 문자열·배열은 이 메모리에 복사해 넘긴다.
const mem = new Uint8Array(instance.exports.memory.buffer);
  • 숫자는 그대로 오가고(i64는 BigInt), 문자열·배열·객체는 한쪽이 선형 메모리에 복사하고 포인터와 길이를 넘기는 식으로 전달한다. 이 연결 코드(glue code)는 Emscripten, Rust의 wasm-bindgen 같은 도구가 생성한다.
  • Wasm은 DOM이나 웹 API를 직접 호출하지 못하고 자바스크립트를 거쳐야 한다. externref로 자바스크립트 객체 참조를 들고 있을 수는 있다.
  • 3.0의 JS 문자열 내장 함수(JS String Builtins)는 자바스크립트 문자열을 복사 없이 다룰 수 있게 해 GC 언어의 연동 비용을 줄인다.
  • 비동기 자바스크립트 API를 동기 코드처럼 부르게 해 주는 JSPI(JavaScript Promise Integration)도 표준화가 진행되었다.
  • Node.js, Deno, Bun 같은 서버 자바스크립트 런타임도 같은 WebAssembly API를 제공한다.
언어 도구 비고
C, C++ Emscripten, Clang(8 이상, --target=wasm32), WASI SDK Emscripten은 Clang/LLVM 앞단, Binaryen 최적화기, POSIX·OpenGL·SDL을 흉내 내는 자바스크립트 런타임을 묶은 도구다. 기존 C/C++ 코드베이스를 다시 짜지 않고 웹으로 옮기는 주 경로
Rust rustc(wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2), wasm-bindgen, wasm-pack GC가 없고 런타임이 작아 결과물이 작다. 가장 활발한 생태계
Go 표준 컴파일러(GOOS=js GOARCH=wasm, Go 1.11부터), TinyGo 표준 컴파일러는 런타임·GC를 포함해 결과물이 큰 편이고, TinyGo가 작게 만든다. Go 1.21부터 GOOS=wasip1
C#, F#(.NET) Blazor WebAssembly .NET 런타임을 Wasm으로 컴파일해 브라우저에서 돌린다
Kotlin Kotlin/Wasm WasmGC 사용
Dart Flutter 웹의 Wasm 빌드 WasmGC 사용
Java 등 JVM 언어 TeaVM, CheerpJ, J2CL CheerpJ는 기존 JAR를 그대로 브라우저에서 실행
Python Pyodide(CPython을 Emscripten으로 컴파일), PyScript NumPy 등 과학 계산 패키지까지 브라우저에서 실행
AssemblyScript 전용 컴파일러 TypeScript와 비슷한 문법으로 Wasm을 직접 출력
Swift, Zig, Haskell(GHC), OCaml, Scheme(Guile Hoot), Ruby(ruby.wasm) 각 언어 도구 공식 또는 커뮤니티 지원

2021년 기준 40개 안팎의 언어가 WebAssembly를 컴파일 대상으로 지원한다고 집계되었다. 가비지 컬렉션이 필요한 언어는 예전에는 자기 GC를 선형 메모리 안에 통째로 넣어야 해서 크고 느렸다. 3.0의 WasmGC는 엔진(브라우저의 자바스크립트 GC)이 관리하는 구조체·배열 타입을 제공해 이 문제를 줄인다. 다만 .NET 런타임은 내부 포인터 등 WasmGC에 없는 기능이 필요해 여전히 자체 GC를 쓴다. 자바스크립트 자체를 Wasm으로 컴파일하는 시도(Javy, Porffor 등)도 있다.

버전 들어간 기능
1.0(MVP, 2017년 구현, 2019년 W3C 권고) 4가지 숫자 타입, 선형 메모리 1개, 테이블 1개, 구조적 제어 흐름, import/export
2.0(2025년 3월 완료) 128비트 고정 폭 SIMD(v128, 명령 200여 개 추가), 대량 메모리 연산(memory.copy, memory.fill), 다중 반환값, 참조 타입(externref, 여러 테이블), 트랩 없는 실수→정수 변환, 부호 확장 명령
3.0(2025년 9월) 64비트 주소 공간(memory64, 4GiB 초과 메모리), 여러 개의 메모리, 가비지 컬렉션(WasmGC 구조체·배열), 타입 있는 함수 참조, 꼬리 호출(tail call), 예외 처리(try_table, exnref), 완화된 SIMD(relaxed SIMD), 결정적 실행 프로필, 사용자 정의 주석 문법, JS 문자열 내장 함수[8]
별도 제안 스레드와 원자적 연산(SharedArrayBuffer 기반 공유 메모리, 브라우저 대부분 지원), JSPI, 스택 전환(stack switching), 컴포넌트 모델(브라우저는 미지원)

스레드는 공유 메모리를 쓰므로 브라우저에서 스펙터 대책 때문에 교차 출처 격리가 필요하다. 페이지가 Cross-Origin-Opener-Policy: same-origin과 Cross-Origin-Embedder-Policy: require-corp 헤더를 보내야 SharedArrayBuffer를 쓸 수 있다(교차 출처 리소스 공유 참고). 2018년 스펙터 공개 직후 브라우저들이 SharedArrayBuffer를 일시적으로 껐고, Wasm 스레드 제안도 이 때문에 한동안 보류되었다.

브라우저 밖의 WebAssembly

편집 원본 편집

WASI(WebAssembly System Interface)는 브라우저 밖에서 Wasm 모듈이 파일, 시계, 난수, 환경 변수, 소켓 같은 시스템 기능을 쓰게 하는 표준 인터페이스다. POSIX와 비슷한 기능을 주되, 모듈은 런타임이 넘겨준 디렉터리나 소켓 핸들만 쓸 수 있다(능력 기반 보안). CloudABI와 Capsicum의 영향을 받았다.

  • WASI 0.1(Preview 1): POSIX 비슷한 함수 모음. 네트워크 지원이 빈약했다.
  • WASI 0.2(Preview 2, 2024년 1월): 컴포넌트 모델 위에서 다시 정의되었다. CLI 월드, HTTP 프록시 월드, TCP/UDP 소켓을 포함한다.
  • WASI 0.3: 비동기 함수를 기본 지원하는 버전으로 2026년 출시를 목표로 하고, 이후 1.0이 계획되어 있다.[2]

2019년 Docker 공동 창업자 Solomon Hykes는 "2008년에 WASM과 WASI가 있었다면 Docker를 만들 필요가 없었을 것"이라고 말했다.[2]

컴포넌트 모델

편집 원본 편집

핵심 Wasm은 정수와 실수만 주고받을 수 있어, 서로 다른 언어로 만든 모듈을 연결하려면 문자열·목록·구조체를 어떻게 메모리에 펼칠지 매번 약속해야 했다. 컴포넌트 모델은 인터페이스 정의 언어 WIT(Wasm Interface Type)로 문자열, 리스트, 레코드, variant, 리소스 같은 고수준 타입을 정의하고, 표준 ABI(Canonical ABI)로 변환 규칙을 정한다. 컴포넌트는 서로의 메모리를 공유하지 않고 import/export 함수로만 통신하며, 한 컴포넌트의 export가 다른 컴포넌트의 import와 맞으면 둘을 하나로 합성할 수 있다. 인터페이스 묶음을 "월드(world)"라고 한다. Rust로 만든 컴포넌트를 Python 호스트에서 부르는 식의 언어 간 재사용이 목표다.

런타임 개발 특징
Wasmtime Bytecode Alliance Cranelift 코드 생성기 기반. WASI와 컴포넌트 모델의 기준 구현
Wasmer Wasmer사 여러 컴파일러 백엔드(Cranelift, LLVM, Singlepass), 패키지 레지스트리 WAPM
WasmEdge CNCF 샌드박스 프로젝트(Second State 시작) 클라우드 네이티브, 엣지, AI 추론 확장
WAMR(WebAssembly Micro Runtime) Bytecode Alliance(Intel 시작) 수백 KB 메모리의 임베디드·IoT 장치용. 인터프리터·AOT·JIT
wasm3 커뮤니티 빠른 인터프리터, 마이크로컨트롤러에서도 동작
V8, SpiderMonkey, JavaScriptCore Google, Mozilla, Apple 브라우저 엔진. V8은 Node.js·Deno·Cloudflare Workers의 기반이기도 하다

이 밖에 WAVM, InNative 같은 AOT 런타임도 있다. 인터프리터·런타임은 x86, ARM, RISC-V, MIPS 등 여러 CPU와 리눅스, BSD, 윈도우, macOS 등에서 동작한다.

  • 서버리스·엣지 컴퓨팅: Cloudflare Workers, Fastly Compute, Fermyon Spin 등. 컨테이너보다 시작이 빨라(마이크로초~밀리초) 요청마다 격리된 인스턴스를 띄울 수 있다.
  • 프록시·서비스 메시 확장: Envoy와 Istio의 Proxy-Wasm ABI, Red Hat OpenShift Service Mesh의 확장.
  • 컨테이너 생태계: Docker의 Wasm 워크로드 지원, 쿠버네티스에서 Wasm을 돌리는 Krustlet, SpinKube, containerd의 runwasi, Microsoft AKS의 WASI 노드 풀 미리 보기.
  • 플러그인: 신뢰할 수 없는 사용자 코드를 격리해 돌리는 확장 시스템. Redpanda의 데이터 변환, 데이터베이스 사용자 정의 함수, 편집기와 게임의 모드가 예다.
  • 블록체인: 여러 스마트 계약 플랫폼이 실행기로 Wasm을 쓴다. 이더리움은 EVM을 eWASM으로 바꾸는 계획을 논의했지만 채택하지 않았다(이더리움 가상머신 참고).
제품 내용
Figma C++로 짠 문서 처리 엔진을 asm.js에서 WebAssembly로 바꾸어 2017년 로딩 시간을 3배 줄였다고 발표했다. 파싱이 약 20배 빨라지고 번역된 코드를 캐시할 수 있었던 효과다[9]
Adobe Photoshop 웹판 C++ 코드베이스를 Emscripten으로 옮겼다. Wasm 스레드와 SIMD(평균 3~4배, 일부 80~160배 속도 향상), OPFS, Display P3 캔버스, Lit 기반 Spectrum Web Components, Workbox 서비스 워커를 쓴다[10]
Google Earth, AutoCAD 웹판 기존 네이티브 C++ 코드를 웹으로 옮긴 대표 사례
Unity, Unreal Engine 웹 빌드가 C++(Unity는 IL2CPP로 변환한 C#) 엔진을 Wasm으로 컴파일한다. Unreal Engine의 HTML5 출력은 4.2x 버전대 이후 공식 지원이 끝나고 커뮤니티 플러그인으로 넘어간 것으로 알려져 있다
wllama(llama.cpp) llama.cpp의 Wasm 바인딩. GPU 없이 Wasm SIMD와 멀티스레드로 브라우저에서 대형 언어 모델을 추론한다. 멀티스레드를 쓰려면 COOP/COEP 헤더가 필요하다[11]
SQLite, FFmpeg SQLite 공식 Wasm 빌드, ffmpeg.wasm으로 브라우저 안 데이터베이스와 동영상 변환
Blazor, Avalonia UI, Uno Platform, Qt C#·C++ UI 프레임워크의 웹 대상
Flutter 웹에서 Skia 렌더러를 쓰기 위한 CanvasKit(Skia의 Wasm 빌드)과 Dart의 WasmGC 빌드
PyScript 브라우저 안 Python 실행(Pyodide 기반)
a-Shell iOS 터미널 앱. iOS가 앱 안에서 네이티브 코드 생성을 막기 때문에, 사용자가 컴파일한 C 프로그램을 Wasm으로 만들어 실행한다
rhwp Rust와 WebAssembly로 만든 오픈 소스 한글(HWP/HWPX) 문서 뷰어·편집기
아르테미스 엔진 비주얼 노벨 제작 도구의 웹 출력

초기 발표에서는 네이티브 대비 약 10% 느린 수준이라고 했지만, 실제 프로그램에서는 차이가 더 크다.

  • 2019년 USENIX ATC에 발표된 연구("Not So Fast")는 SPEC CPU 벤치마크를 브라우저에서 수정 없이 돌려, 네이티브 대비 평균 Firefox 45%, Chrome 55% 느리고, 최악의 경우 2.08배(Firefox), 2.5배(Chrome) 걸린다고 보고했다. 원인으로 레지스터 수 부족, 추가 분기·범위 검사, 컴파일러 최적화 부족을 들었다.[12]
  • libsodium 개발자 Frank Denis의 암호 연산 벤치마크에서는 2023년 가장 빠른 런타임이 중앙값 기준 네이티브보다 약 2.32배 느렸고, AES처럼 네이티브가 CPU 전용 명령을 쓰는 항목은 80배 가까이 차이가 났다.[13] 2026년 같은 벤치마크에서는 새 wide-arithmetic 명령을 쓴 Wasmer가 1.33배, Wasmtime이 1.46배까지 줄었다.[14]
  • 자바스크립트와 비교하면 결과가 상황에 따라 다르다. 현대 자바스크립트 엔진은 JIT 컴파일로 크게 최적화되어 있어, 짧거나 자바스크립트와 자주 오가는 작업에서는 Wasm이 오히려 느릴 수 있다. 계산 집약적이고 메모리 배치를 직접 통제할 수 있는 코드에서 이득이 크다. Rust/Wasm으로 웹 앱을 빠르게 하려던 스타트업 Zaplib은 고객의 시뮬레이터를 옮겼더니 5% 빨라지는 데 그쳤다며 2022년 사업을 접었다.
  • 강점은 최고 속도보다 예측 가능성에 있다. 타입이 정해져 있어 JIT의 가정이 깨지며 느려지는(deoptimization) 일이 없고, 미리 컴파일되어 시작 성능이 안정적이며, 기존 C/C++ 라이브러리를 그대로 가져올 수 있다.
  • 모바일 브라우저에서는 큰 메모리 할당(수백 MB 이상)이 불안정하다는 보고가 있다.
  • 크립토재킹: 방문자의 CPU로 몰래 암호화폐를 채굴하는 스크립트가 WebAssembly를 적극 활용했다. 2017~2019년 운영된 Coinhive가 대표적이다. 2019년 DIMVA에 발표된 독일 브라운슈바이크 공대 등의 연구는 Alexa 상위 100만 사이트를 조사해 약 600개 중 1개 사이트가 Wasm을 실행하며, 그중 절반 이상이 채굴이나 난독화 같은 악의적 용도라고 보고했다.[15] Coinhive 폐쇄 뒤인 2021년 슈투트가르트 대학 연구에서는 수집한 Wasm 바이너리 가운데 채굴 목적이 1% 미만으로 줄었다.[16]
  • 난독화와 탐지 회피: 바이너리 형식이라 악성 코드 분석이 자바스크립트보다 어렵고, 기존 스크립트 탐지 도구가 놓치기 쉽다.
  • 모듈 내부 메모리 안전성: 샌드박스는 모듈 바깥을 보호할 뿐, C/C++ 코드의 버퍼 오버플로와 해제 후 사용(use-after-free)은 선형 메모리 안에서 그대로 일어난다. 스택 카나리아, ASLR 같은 네이티브 방어 기법이 없어 모듈 내부 데이터 변조는 오히려 쉬울 수 있다.
  • 사이드 채널: 공유 메모리와 고해상도 타이머는 스펙터 류 공격의 재료가 되므로 교차 출처 격리 아래에서만 허용된다.
  • 구조적 제어 흐름은 제어 흐름 하이재킹을 어렵게 하고, 기호 실행 같은 정적 검증 기법을 적용하기 쉽게 한다.

자바스크립트와의 관계

편집 원본 편집

WebAssembly가 자바스크립트를 대체할 것이라는 전망도 있지만, 설계 목표는 보완이다. Wasm은 DOM을 직접 다룰 수 없어 웹 페이지 조작은 여전히 자바스크립트가 맡는다. 같은 기능이라도 런타임과 라이브러리를 포함한 Wasm 배포 파일이 자바스크립트보다 큰 경우가 많아, 로딩 시간이 중요한 콘텐츠 중심 사이트(뉴스, 쇼핑)에는 불리하고 실행 성능이 중요한 게임, 사진·동영상 편집, 온라인 IDE, CAD에 유리하다. 실무에서는 앱의 대부분을 자바스크립트나 TypeScript로 쓰고 성능이 중요한 핵심만 Wasm 모듈로 불러 쓰는 구성이 일반적이다.

한국의 연구 동향

편집 원본 편집
  • 국내 연구팀 어셈넥스트(AsmNEXT)가 2022년 1월 Bytecode Alliance 회원으로 합류해 런타임 개선에 참여하고 국내 WebAssembly 콘퍼런스를 열었다(공식 임기는 2023년 4월 종료).[17]
  • KAIST 전산학부 류석영 교수 연구팀은 자바스크립트 명세 기법에 이어 WebAssembly 명세를 엄밀하게 기술하는 SpecTec 작업에 참여했고(2025년 공식 채택), "명세 기반 WebAssembly 자동 테스트 생성" 주제로 2025년 Google V8 연구 지원금에 선정되었다.[18]