WebAssembly是一種新的二進制格式,它可以方便地將C/C++等靜態語言的代碼快速地“運行”在瀏覽器中,這一特性為前端密集計算場景提供了無限可能。不僅如此,通過WebAssembly技術,我們還可以將基于Unity等游戲引擎開發的大型游戲快速地移植到Web端。WebAssembly技術現在已經被計劃設計成W3C的標準,眾多瀏覽器廠商已經提供了對其MVP版本標準的支持。在Google I/O 2017大會上,Google首次針對WebAssembly技術進行了公開演講和推廣,其Post-MVP版本標準更是對諸如DOM操作、多線程和GC等特性提供了支持。WebAssembly所帶來的Web技術變革勢不可擋。本書力求從一些簡單的實踐入手,深入理論,到復雜的具有實際業務價值的綜合實踐,深入淺出地介紹Wasm技術發展至今,其背后所涉及的各種底層設計原理與實現、相關工具鏈以及未來發展方向等多方面內容。本書內容包括:WebAssembly技術的發展歷程,從PNaCl到ASM.js再到WebAssembly,以及這些技術的基本應用方法與性能對比;WebAssembly的標準上層API、底層堆棧機的設計原理,以及對MVP標準理論的深入解讀;與WebAssembly標準相關的進階內容,如單指令多數據流(SIMD)、動態鏈接(DL)等;LLVM工具鏈與WAT可讀文本格式的相關內容;基于Emscripten工具鏈開發WebAssembly應用的基本流程,以及工具鏈的一些基本常用功能和特性;基于Emscripten工具鏈實現C/C++語言動態關系綁定技術;Emscripten工具鏈所提供的一些如WebGL支持、虛擬文件系統、應用優化以及HTML 5事件系統等高級應用特性;構建一個具有實際業務價值的WebAssembly應用,現階段Wasm生態的發展情況,以及在Post-MVP標準中制訂的一些WebAssembly未來發展規劃。本書的目標讀者為Web前端開發人員、C/C++開發人員和對WebAssembly技術感興趣的人員。
于航,現就職于阿里巴巴 / 餓了么事業部(BU),資深前端工程師,FreeCodeCamp(FCC) China 上海社區負責人,QCon(2017)上海前端專場講師。2016 年開始研究 WebAssembly 技術,2017 年加入 WebAssembly 中國社區,同年加入官方WCG(W3C Community Group),定期參與 WCG組織的各種線上視頻研討會議,在跟進 WebAssembly 最新發展的同時,也為 WebAssembly 的標準化提出自己的建議和意見。生活中喜歡彈鋼琴、演講與分享。主要技術研究方向為Web前端與基礎設施架構、WebAssembly、LLVM以及編譯器等相關領域。
目 錄
第1 章 漫談WebAssembly 發展史 1
1.1 JavaScript 的發展和弊端 1
1.1.1 快速發展與基準測試 1
1.1.2 Web 新時代與不斷挑戰 8
1.1.3 無法跨越的“阻礙” 11
1.1.4 Chrome V8 引擎鏈路 17
1.2 曾經嘗試——ASM.js 與PNaCl 28
1.2.1 失落的ASM.js 28
1.2.2 古老的NaCl 與PNaCl 42
1.3 新的可能——WebAssembly 57
1.3.1 改變與顛覆 57
1.3.2 一路向前,WCG 與WWG 85
第2 章 WebAssembly 核心原理(基于MVP 標準) 90
2.1 應用與標準Web 接口 90
2.1.1 編譯與初始化 90
2.1.2 驗證模塊 106
2.1.3 遇到錯誤 106
2.1.4 內存分配 108
2.1.5 表 112
2.2 深入設計模型——堆棧機 118
2.2.1 堆棧式虛擬機 119
2.2.2 逆波蘭表達式 125
2.2.3 Shunting-yard 算法 126
2.2.4 標簽與跳轉 130
2.2.5 條件語句 135
2.2.6 子程序調用 137
2.2.7 變量 138
2.2.8 棧幀 139
2.2.9 堆 140
2.3 類型檢查 141
2.3.1 數據指令類型 142
2.3.2 基本流程控制 144
2.3.3 基于表達式的控制流 149
2.3.4 類型堆棧的一致性 151
2.3.5 不可達代碼 155
2.4 二進制編碼 156
2.4.1 字節序——大端模式與小端模式 157
2.4.2 基于LEB-128 的整數編碼 161
2.4.3 基于IEEE-754—2008 的浮點數編碼 163
2.4.4 基于UTF-8 的字符串編碼 167
2.4.5 模塊數據類型 168
2.4.6 虛擬指令與編碼 169
2.4.7 類型構造符 174
2.5 模塊 175
2.5.1 段 175
2.5.2 索引空間 185
2.5.3 二進制原型結構 186
2.6 內存結構 196
2.6.1 操作運算符 197
2.6.2 尋址 197
2.6.3 對齊 198
2.6.4 溢出與調整 203
第3 章 動態鏈接與SIMD(基于MVP 標準) 204
3.1 動態鏈接(Dynamic Linking) 204
3.1.1 ELF 206
3.1.2 符號重定向(Symbol Relocation) 212
3.1.3 GOT(Global Offset Table,全局偏移表) 225
3.1.4 PLT(Procedure Lookup Table,過程查詢表) 229
3.1.5 基于表的Wasm 模塊動態鏈接 233
3.2 單指令多數據流(SIMD) 237
3.2.1 SIMD 應用 239
3.2.2 并行與并發 243
3.2.3 費林分類法 244
3.2.4 SIMD.js & TC39 246
3.2.5 WebAssembly 上的SIMD 擴展 248
第4 章 深入LLVM 與WAT 250
4.1 LLVM——底層虛擬機 250
4.1.1 傳統的編譯器架構 251
4.1.2 LLVM 中間表示層 252
4.1.3 基于LLVM 的編譯器架構 254
4.1.4 LLVM 優化策略 256
4.1.5 LLVM 命令行工具 261
4.1.6 WebAssembly 與LLVM 268
4.2 基于LLVM 定義新的編程語言 272
4.2.1 圖靈完備與DSL 276
4.2.2 簡易詞法分析器 280
4.2.3 RDP 與OPP 算法 287
4.2.4 AST(抽象語法樹) 295
4.2.5 簡易語法分析器 296
4.2.6 生成LLVM-IR 代碼 303
4.2.7 鏈接優化器 307
4.2.8 編譯到目標代碼 308
4.2.9 整合I/O 交互層 312
4.3 WAT 315
4.3.1 S-表達式 316
4.3.2 WAT/Wasm 與Binary-AST 318
4.3.3 其他與設計原則 320
第5 章 Emscripten 基礎應用 321
5.1 利器——Emscripten 工具鏈 321
5.1.1 Emscripten 發展歷史 321
5.1.2 Emscripten 組成結構 323
5.1.3 Emscripten 下載、安裝與配置 325
5.1.4 運行測試套件 329
5.1.5 編譯到ASM.js 330
5.2 連接C/C++與WebAssembly 332
5.2.1 構建類型 333
5.2.2 Emscripten 運行時環境 341
5.2.3 在JavaScript 代碼中調用C/C++函數 350
5.2.4 在C/C++代碼中調用JavaScript 函數 362
第6 章 基于Emscripten 的語言關系綁定 381
6.1 基于Embind 實現關系綁定 383
6.1.1 簡單類 388
6.1.2 數組與對象類型 390
6.1.3 高級類元素 392
6.1.4 重載函數 406
6.1.5 枚舉類型 407
6.1.6 基本類型 408
6.1.7 容器類型 410
6.1.8 轉譯JavaScript 代碼 412
6.1.9 內存視圖 415
6.2 基于WebIDL 實現關系綁定 416
6.2.1 指針、引用和值類型 419
6.2.2 類成員變量 421
6.2.3 常量“const”關鍵字 422
6.2.4 命名空間 423
6.2.5 運算符重載 424
6.2.6 枚舉類型 425
6.2.7 接口類 428
6.2.8 原始指針、空指針與void 指針 430
6.2.9 默認類型轉換 433
第7 章 探索Emscripten 高級特性 436
7.1 加入優化流程 436
7.1.1 使用編譯器代碼優化策略 441
7.1.2 使用GCC 壓縮代碼 443
7.1.3 使用IndexedDB 緩存模塊對象 445
7.1.4 其他優化參數 452
7.2 使用標準庫與文件系統 453
7.2.1 使用基于musl 和libc++的標準庫 454
7.2.2 虛擬文件系統結構 457
7.2.3 打包初始化文件 459
7.2.4 基本文件系統操作 460
7.2.5 懶加載 469
7.2.6 Fetch API 473
7.3 處理瀏覽器事件 478
7.3.1 事件注冊函數 479
7.3.2 事件回調函數 480
7.3.3 通用類型與返回值類型 481
7.3.4 常用事件 483
7.4 基于EGL、OpenGL、SDL 和OpenAL 的多媒體處理. 486
7.4.1 使用EGL 與OpenGL 處理圖形 487
7.4.2 使用SDL 處理圖形 493
7.4.3 使用OpenAL 處理音頻 496
7.5 調試WebAssembly 應用 499
7.5.1 編譯器的調試信息 499
7.5.2 使用調試模式 501
7.5.3 手動跟蹤 502
7.5.4 其他常用編譯器調試選項 504
第8 章 WebAssembly 綜合實踐、發展與未來 505
8.1 DIP 綜合實踐應用 505
8.1.1 應用描述 505
8.1.2 濾鏡與卷積 506
8.1.3 基本組件類型與架構 510
8.1.4 編寫基本頁面骨架(HTML 與CSS) 511
8.1.5 編寫核心卷積函數(C++) 512
8.1.6 編寫主渲染循環與“膠水”代碼(JavaScript) 514
8.1.7 使用Emscripten 編譯并運行應用 519
8.1.8 性能對比 520
8.2 WebAssembly 常用工具集 521
8.2.1 Cheerp 521
8.2.2 Webpack 4 523
8.2.3 Go 和Rust 的WebAssembly 實踐 525
8.2.4 Binaryen 528
8.2.5 WasmFiddle 529
8.2.6 Wabt 530
8.2.7 AssemblyScript 530
8.3 WebAssembly 未來草案 530
8.3.1 GC(垃圾回收) 531
8.3.2 Multi-Thread(多線程)與原子操作 531
8.3.3 異常處理 531
8.3.4 多返回值擴展 531
8.3.5 ES 模塊 531
8.3.6 尾遞歸 532
8.3.7 BigInts 的雙向支持 532
8.3.8 自定義注釋語法 532