wasm도 돌려준다

메모리 회수의 Wasm backend 이식은 드문 출발점을 갖고 있었다: git의 역사가 「몇 Phase 전에 한 번 시도되어, unsound로서 철거되었다」를 보여 주고 있었던 것이다 —— escape하는 값이 망가지기에, backend는 리크하는 쪽을 골랐다. 부활은 옛 아이디어를 지키고, 빠져 있던 세 부품을 더했다: 결과를 copy-out한다, escape하는 store를 컴파일 시에 거부한다, escape하는 closure를 결과 타입으로 거부한다. 수용 테스트는 이미 쓰여 있었다 —— 그 2048 probe가, 이번엔 평평한 선을 기대하며. 선은 나왔다: bump pointer는 3만 수 동안 4,544 bytes로 동결됐다.

merewasmmemory-modelregionslanguage-design

앞 회의 forcing number —— 64메가바이트의 수명, 한 수 ~8.4킬로바이트 —— 는 그것이 사기로 되어 있던 구현 세션을 샀다. 하지만 세션은 고고학 강의로 시작했다. Wasm backend의 region 블록 emission에는, 한때 자명한 것 그 자체 —— 블록 입구에서 bump pointer를 저장하고 출구에서 복원한다 —— 를 하고 있었고, 그것이 unsound로서 철거되었다고 설명하는 코멘트가 남아 있었다: 블록 안에서 할당된 값이 escape하면(기록에 남은 예에서는, 블록에서 반환된 container), 다음 할당이 말없이 덮어쓸 메모리를 가리킨다. 망가뜨릴 바에야, 당시의 정직한 선택은 리크였다. 그러니 이 이식은 「Wasm에 회수를 더한다」가 아니라 더 흥미로운 것이었다: 알려진 unsound 설계를, 그것을 unsound로 만들던 결락 부품을 공급해 부활시킨다.

세 부품과, 더 단순한 기계

부품은 C backend의 회수가 요했던 것과 같은 셋의 번역이었다. 첫째, 결과는 copy-out한다: 블록의 값은 타입별 copy 기구로 deep copy된다 —— 실은 두 번: 먼저 블록의 쓰레기 위 staging copy로, 다음에 bump pointer 복원 후, 바깥 할당 범위로. 두 카피는 겹칠 수 없다. staging copy는 body가 할당한 모든 것보다 위에 앉기 때문이다 —— 미묘한 버그 하나를 논증 하나로 바꾸는 작은 증명. 둘째, escape하는 store는 컴파일 에러: Wasm에는 per-container 저장소가 없으므로, C가 store된 값을 container 자신의 region에 copy하는 장면에서, Wasm은 단적으로 거부한다 —— 블록 밖에서 만들어진 container로의 heap 값 push, channel로의 송신, spawn, extern으로의 callback 건네기는 docs 안내와 함께 컴파일에 실패한다. 블록 에서 만들어진 container는 자유롭게 만질 수 있다. 블록과 함께 죽기 때문이다. 셋째, escape하는 closure는 결과 타입으로 거부. 이 이식이 원래 C 작업보다 가벼웠던 이유는, Wasm의 단일 스레드 세계에는 C의 장치가 아무것도 필요 없기 때문이다 —— thread-local도 heap block chain도 없음: mark는 Wasm의 값 스택에 타고, scratch global 하나가 카피를 부린다. 같은 설계, 가동 부품은 넷이 아니라 하나.

평평한 선

2048의 키 핸들러는 body 둘레에 region R { ... }을 하나 얻었다 —— 스냅숏, 렌더 문자열, 온갖 중간값이 수마다 죽는다. 한편 보드 그 자체(기동 시에 만들어진 날 정수의 vector)는 이 모든 것에 닿지 않은 채 제자리에서 mutate되기를 계속한다. probe를 재주행: 3만 수, trap 제로, 그리고 bump pointer는 첫 수에서 4,544 bytes, 1만 5천 수에서 4,544 bytes, 3만 수에서 4,544 bytes를 읽었다. 거의 평평, 이 아니다 —— 동결이다. 7,700 수에서 죽던 게임에서, 한 수당 순 할당 제로. suite는 역사의 줄기를 하나 바로잡았다: 리크를 주장하던 옛 테스트(리크가 건전한 선택이던 시대에 의도적으로 고정된 Phase 16.4의 거동)는, 새 형태를 주장하는 테스트들로 교체되었다 —— 「블록에서 container를 반환하는 것은, 망가지는 게 아니라 컴파일 에러가 된다」를 포함해서.

아크가 닫히는 곳

이로써 세 Part에 걸쳐 열려 있던 루프가 닫혔다. 장수 프로그램 편은 C backend의 회수와 「Wasm에는 아직 없다」는 정직한 주기로 끝났다. probe 회는 「없다」를 숫자로 바꿨다. 이 회는 숫자를 평평한 선으로 바꿨다. 각 backend는 이제 자신의 정직한 이야기를 가진다: interpreter는 GC. C는 copy-on-store 딸린 회수로, store는 무제한. Wasm은 copy-on-store 대신 escape를 에러로 하는 회수 —— 더 엄격하고, 더 단순하고, 그것이 섬기는 브라우저 프로그램에는 충분. C와 Wasm 이야기의 남은 차이는 다른 차이들과 같은 곳에 적혀, 그것을 요하는 프로그램을 기다리고 있다. 다음 회는 다른 종류의 발견에 대해 —— 찾으러 간 기능이 이미 세워져 있던 probe의 이야기다.

← Back to Mere: 언어를 만들다