이 글의 원본은 여기에서 보실 수 있습니다.

혹시 더 나은 번역을 제안해주신다면 감사하게 수용하겠습니다.


웹어셈블리는 웹에서 코드를 실행시킬 수 있는 새로운 방법입니다. 웹어셈블리와 함께라면 C나 C++ 같은 언어로 쓰여진 모듈을 브라우저에서 실행시키는 것이 가능하죠.

현재는 모듈만으로는 동작하는 것이 아직은 불가능합니다. 이러한 현재 동작 상황은 브라우저에 ES 모듈 지원이 활성화된다면 바뀔 것으로 기대하고 있습니다. 브라우저에 ES 모듈 지원이 정상적으로 동작한다면, 웹어셈블리의 모듈들은 다른 ES 모듈들이 로딩되는 것과 같은 방식으로 로딩될 것입니다. 예를 들면 <script type="module" src="my-wasm-module.wasm"> 과 같이 말이에요.

역자 주: 현재 ES6 에서 새롭게 추가된 import / export 등의 ES Module 시스템 지원은 아직 최신 브라우저에 추가되지 않았습니다. Babel에 의해서 CommonJS / AMD 로더 방식으로 트랜스파일 됩니다. 이에 대한 브라우저 지원은 이 곳에서 확인할 수 있습니다. 현재 최신 Safari와 Chrome Canary 61 버전부터 활성화 되어 있네요.

하지만 아직은 웹어셈블리 모듈을 정상적으로 실행시키기 위하여 자바스크립트를 사용해야만 합니다. 자바스크립트를 사용하여 웹어셈블리 모듈의 ‘인스턴스’ 를 만들어냅니다. 그러면 자바스크립트 코드 내에서 웹어셈블리 모듈 인스턴스 내부에 존재하는 함수를 호출할 수 있게 되지요.

예를 들어, React 가 어떻게 웹어셈블리 모듈을 초기화하는지 살펴봅시다. (이 영상을 보면 React에서 어떻게 웹어셈블리를 사용하는지 배울 수 있을 것입니다.)

사용자가 페이지를 로딩하면, 아마 동일한 방식으로 시작할 것입니다.

브라우저는 JS 파일을 다운로드 받겠지요. 이후에 .wasm 파일을 가져올 것입니다. 이 .wasm 파일에는 바이너리 형태의 웹어셈블리 코드가 포함되어 있겠지요.

.js 파일과 .wasm 파일을 다운로드 받는 브라우저

이 파일들을 실행시키기 위해서는 먼저 파일들을 브라우저에 로딩 시켜야겠지요. 먼저 .js 파일을 로딩하면, React 의 자바스크립트 부분이 로딩될 것입니다. 그리고 해당 자바스크립트는 웹어셈블리 모듈의 인스턴스를 생성할 것입니다.

이를 위해서는, WebAssembly.instantiate 메서드를 호출합니다.

WebAssembly.instantiate을 호출하고 있는 React.js 로봇

이 부분을 좀 더 자세히 봅시다.

우리가 제일 먼저 WebAssembly.instantiate 로 넘겨주는 것은 .wasm 파일로부터 얻은 바이너리 코드 일 것입니다. 모듈의 코드이지요.

그래서 바이너리를 버퍼로 추출한 이후, WebAssembly.instantiate 메서드를 호출합니다.

WebAssembly.instantiate 메서드의 파라미터로 넘겨진 바이너리 코드

자바스크립트 엔진은 웹어셈블리 모듈의 코드를 코드가 실행될 기계에 특정한 바이트 코드로 컴파일 합니다.

하지만 이 작업이 메인 스레드에서 일어나는 것은 좋지 않죠. 자바스크립트 개발자라면 아시겠지만 메인 스레드는 DOM, 브라우저 내의 레이아웃 등을 건드립니다. 메인 스레드가 멈추면 모든 화면이 멈춰버리기 때문에, 이러한 일이 일어난다면 굉장히 불행하겠지요. 그래서 WebAssembly.instantiate 메서드는 프라미스를 반환합니다.

모듈 컴파일의 결과로 반환된 프라미스

이는 메인 스레드가 다른 작업을 수행할 수 있도록 해줍니다. 웹어셈블리 모듈의 컴파일이 끝난다면 프라미스를 통하여 이를 메인 스레드에게 알려주기 때문에, 메인 스레드는 언제 컴파일이 끝났는지를 알 수 있습니다. 프라미스는 웸어셈블리 모듈의 인스턴스 값을 반환하죠.

하지만 컴파일 된 모듈이 인스턴스를 생성하는데에 필요한 유일한 것은 아닙니다.

전 모듈을 설명서 같은 것이라고 생각합니다. 인스턴스는 설명서를 읽고 무언가를 만들어내고자 하는 사람과 같다고 할 수 있습니다. 어떠한 것을 만들기 위해서는, 설명서 뿐 아니라 어떠한 것을 만들기 위한 재료 또한 필요하지요. 실제로 동작할 무언가가 있어야 합니다.

웹어셈블리 로봇 옆에 있는 설명서

이러한 재료의 역할을 하는 부분이 WebAssembly.instantiate 메서드의 두 번째 파라미터에 넘겨집니다. 이것이 imports 객체이지요.

WebAssembly.instantiate 메서드의 파라미터인 imports 객체

전 imports 객체를 어떠한 것의 재료를 담은 박스와 같다고 생각합니다. 마치 당신이 이케아에서 재료를 사오는 것 처럼 말이에요. 인스턴스는 이러한 재료들(imports)를 이용하여, 설명서가 지시한 대로 어떠한 것을 만들어냅니다. 각각의 설명서가 각각의 특정한 재료를 요구하듯, 각각의 모듈은 특정한 종류의 imports 를 기대합니다.

웹어셈블리 로봇 옆에 있는 Imports 박스

그래서 당신이 모듈을 초기화시킬 때에(WebAssembly.instantiate), 각각의 모듈에 필요한 imports 를 포함하고 있는 imports 객체를 파라미터로 넘겨줍니다. 각각의 import는 다음의 네 종류의 imports 중 하나일 것입니다.

  • values (값)
  • function closures (클로저 함수)
  • memory (메모리)
  • tables (테이블)

Values (값)

imports 로 값을 제공할 수 있습니다. 값을 제공하는 경우, 이 값은 기본적으로 전역 변수입니다. 현재 웹어셈블리가 지원하는 유일한 데이터 타입은 정수(integer)와 실수(float) 뿐이므로, 두 타입 중 하나의 값을 가져야만 합니다. 향후에는 더 많은 타입이 웹어셈블리 스펙에 추가될 것입니다.

Function closures (클로저 함수)

imports 로 클로저 함수를 제공할 수도 있습니다. 즉 웹어셈블리 내에서 호출할 수 있는 자바스크립트 함수를 넘길 수 있다는 말입니다.

이것은 현재의 웹어셈블리 버전에서는 DOM 메서드를 직접 호출할 수 없기 때문에 특히나 유용합니다. DOM에 직접 접근하는 것은 현재 웹어셈블리 로드맵에는 존재하지만, 웹어셈블리 스펙에는 존재하지 않습니다.

현재 할 수 있는 방법은 당신이 필요한 대로 DOM에 접근하는 자바스크립트 함수를 만든 후, 이 함수를 웹어셈블리로 클로저 함수 형태로 imports 를 통해 넘기는 것입니다. 그러면 웹어셈블리는 당신이 만든 자바스크립트 함수를 호출하여 DOM 에 접근할 수 있겠지요.

Memory (메모리)

다른 import의 한 종류로는 메모리 객체가 있습니다. 이 객체는 웹어셈블리 코드로 하여금 수동으로 메모리를 관리하는 것을 에뮬레이션 할 수 있도록 해줍니다. 메모리 객체의 개념이 약간 헷갈리므로, 다음 글에서 이에 대해 조금 더 깊게 다뤄보도록 하겠습니다.

Tables (테이블)

import의 마지막 종류에는 보안과도 관련이 있습니다. 이는 ‘테이블’ 이라 불립니다. 이를 활용하면 함수 포인터 같은 것을 사용 가능하도록 해줍니다. 이 역시 개념이 꽤나 복잡하므로, 다다음 글에서 이에 대해 더 깊게 다뤄보도록 하겠습니다.


이것들이 당신의 인스턴스에 장착할 수 있는 4가지 종류의 imports 입니다.

imports 박스에 포함된 각기 다른 종류의 imports

인스턴스를 반환하기 위해서는, WebAssembly.instantitate 메서드로부터 반환된 프라미스가 리졸브 되어야 합니다. 두 가지를 포함하고 있지요. 인스턴스와, 컴파일 된 모듈을 각각 반환합니다.

역자 주: WebAssembly.instantiate(URI_OF_WASM, importObj).then((instance, compiled_module) => {}) 형태로 반환한다는 의미입니다.

컴파일 된 모듈을 가지고 있으면 좋은 점은, 필요한 경우 동일한 모듈의 다른 인스턴스를 빠르게 만들어낼 수 있습니다. WebAssembly.instantiate 메서드의 첫 번째 파라미터로 컴파일 된 모듈이 포함된 변수를 넘겨주면 되죠. 모듈 그 자체에는 아무런 상태 값을 가지고 있지 않습니다. 따라서 인스턴스들은 컴파일 된 모듈의 코드를 공유할 수 있습니다.

당신의 인스턴스는 이제 완전히 무장되었고 출전할 준비가 되었습니다. 컴파일 된 코드인 설명서도 가지고 있고, 각각의 재료 역할을 하는 imports 들 또한 가지고 있죠. 이제 웹어셈블리로 만든 바이너리 코드 내부에 존재하는 메서드를 호출할 수 있습니다.

웸어셈블리 로봇이 부팅 완료되다

다음의 두 개의 글에서는 메모리와 테이블의 import 에 대해서 더욱 깊게 다뤄볼 것입니다.