Asm.js

**asm.js** 是一個中間語言，設計目的是使採用 C 等程式語言編寫的電腦軟體可執行為網路應用程式，同時效能特徵明顯優於標準 JavaScript。

asm.js 包括一個 JavaScript 的嚴格子集，其中的代碼採用具有手動記憶體管理的靜態型別語言（就像 C 語言）編寫，代碼使用一個原始碼至原始碼編譯器（例如基於 LLVM 的 Emscripten）翻譯。通過將語言特性限制在適合提前最佳化和其他效能改進的範圍內，效能得到了提高。

Mozilla Firefox 是第一個實現針對 asm.js 最佳化的瀏覽器，從 Firefox 22 開始使用。

## 設計

asm.js 由 JavaScript 語言的一個嚴格子集組成。它可以顯著提高採用具有手動記憶體管理（例如 C）的靜態型別語言編寫的網路應用程式在使用原始碼至原始碼編譯器轉換為 JavaScript 後的效能。Asm.js 的目標並不是提高手寫 JavaScript 代碼的效能，也不實現增強效能以外的其他目的。

通過將語言特性限制在適合提前最佳化和其他效能改進的範圍內，其旨在具有比標準 JavaScript 更接近於本地（原生）代碼的效能特徵。通過使用 JavaScript 的一個子集，asm.js 很大程度上支援所有主要的網頁瀏覽器，這不同於 WebAssembly 或 Google Native Client 等途徑。

## 代碼生成

asm.js 通常不直接編寫，而是作為一種通過編譯器生成的中間語言，該編譯器取得 C++ 或其他語言的原始碼，然後輸出 asm.js。

例如，提供下列 C 語言代碼：

Emscripten 將輸出下列 JavaScript 代碼：

注意新增的 `|0` 和去除的類型說明符。在 JavaScript 中，按位元運算子會將運算元轉換為 32 位元有符號整數並給出整數結果。這意味著使用 0 的按位元 OR 為一個無作用的操作，只是將值轉換為整數。通過對每個參數這樣做，確保了從外部代碼呼叫該函式時，該值被轉換為正確的類型。這也用於返回值，在該情況下確保添加 1 到 i 的結果將是一個整數（否則可能變得太大），並標記函式的返回類型。這些轉換為 asm.js 所必需，這樣最佳化編譯器才可以提前生成高效的本地代碼。在此類最佳化編譯器中，當 asm.js 代碼呼叫其他 asm.js 代碼時，轉換不執行，因為必需的類型說明符意味著已保證值具有正確的類型。此外，不同於執行浮點加法和轉換為整數，它可以簡單地執行本機整數運算。這樣一來，它可以得到顯著的效能增益。
下面是另一個計算字串長度的例子：

它對應以下 asm.js 代碼：

在生成的代碼中，變數 MEM8 實際上是一個類型緩衝區的逐位元組「視圖」，它充當 asm.js 代碼的堆（heap）。

## 效能

因為 asm.js 在瀏覽器中執行，所以效能很大程度上取決於瀏覽器和硬體。編譯為 asm.js 的 C 程式的初步基準通常比使用 Clang 的本地編譯慢一倍以上。

這種超過普通 JavaScript 的效能增益主要是由於 100％的類型一致性以及幾乎沒有垃圾回收（記憶體是手動管理的大型類型陣列）。這個更簡單的模型沒有動態行為，沒有記憶體分配或釋放，只有一組簡單、定義明確的整數和浮點操作，從而可實現更好的效能和最佳化潛力。

Mozilla 在 2013 年 12 月的基準測試顯示：「使用 float32 最佳化的 Firefox 可以執行所有基準，只比原生速度慢不到 1.5 倍。 Mozilla 指出本地編譯代碼的效能不是單個度量，而是一個範圍，使用不同的本地編譯器（此例中為 Clang 與 GCC）將提供不同效能的代碼。「事實上，在一些基準測試比如 Box2D、FASTA 和 copy 中，asm.js 與 Clang 比較接近，或者比 Clang 到 GCC 還接近 Clang。在一種情況下，asm.js 甚至在 Box2D 上略微擊敗 Clang。」

## 實現

Emscripten 專案提供了可以編譯 C 和 C++（或其他任何可轉換為 LLVM IR 的語言）代碼為 asm.js 的工具。

所有支援 JavaScript 較新版本的瀏覽器都應該能支援執行 asm.js 代碼，因為它是該規範的子集。

部分瀏覽器的實現針對 asm.js 進行了特別最佳化：

* Mozilla Firefox 是第一個實現針對 asm.js 最佳化的網頁瀏覽器，自 Firefox 22 開始使用。 OdinMonkey 是 Mozilla 在 Firefox 中使用的 asm.js 提前編譯器，它是 IonMonkey（SpiderMonkey 的 JIT 編譯器）的一個組件。
* 微軟在 Microsoft Edge 使用的 JavaScript 引擎 Chakra 中實現了 asm.js 支援，執行驗證以產生高度最佳化的 JIT 代碼。
* Google Chrome 的 V8 JavaScript 引擎在 Chrome 28 中對 asm.js 基準測試的效能是以前 Chrome 版本的兩倍以上，儘管 Chrome 的 V8 沒有使用提前編譯。

## 採用

目前幾乎所有基於 asm.js 的應用程式都是使用 Emscripten 或 Mandreel 編譯為 asm.js 的 C/C++ 應用程式。

到目前為止，已有不少程式語言、應用程式框架、程式、函式庫、遊戲、遊戲引擎及其他軟體已被移植。部分名單見下：

### 程式語言

* C/C++：Clang 和 LLVM
* Lua VM：Lua 虛擬機器
* Perl：(micro) perl-5.16.3 的移植
* Python – CPython 移植
* Ruby – Ruby 移植

### 應用程式框架

* pepper.js：許多 PNaCl 應用的移植
* Qt：various Qt demos 及 KDE 應用（如 Kate）的移植

### 程式和庫

* OpenGL、SDL 和 SDL2
* Vim（Vi IMproved）
* FreeType：在 JavaScript 中使用 FreeType 的 TrueType 字型光柵化
* SQLite
* GNU Privacy Guard
* ctags
* gnuplot
* Graphviz
* zlib

### 遊戲引擎

* 虛幻引擎 3: 在 4 天內移植
* Unreal Engine 4
* Unity
* ScummVM，它支援許多經典的冒險遊戲
* Godot

### 遊戲

* _Doom_：執行在 PrBoom 上的開源 Freedoom 遊戲 assets，基於開源的 Doom 代碼
* _SuperTux_
* _Dune II_ via OpenDune
* _BananaBread_ based on Cube 2
* Humble Mozilla Bundle 中的每個遊戲（Super Hexagon、輕率漠視重力、Osmos、Zen Bound 2、Dustforce DX、Voxatron、FTL: Advanced Edition 和 Democracy 3）

### 仿真器

* EM-DOSBox：一個 DOSBox 模擬器的移植
* Start9.io：面向多個遊戲架構的網路仿真平台
* JSMESS：一個 MESS 模擬器的移植，面向許多遊戲機和電腦系統

### 數學計算

* HTML5 Fractal Playground – 繪製迭代函式生成的分形，例如 Mandelbrot fractal。

## 參見

* WebAssembly – 一個開發中的用於瀏覽器的位元組碼，旨在比 asm.js 更快地解析 
RPython
* CrossBridge
* Google Native Client（NaCl）

## 參考資料

## 外部連結

* 官方網站
* GitHub 上的 asm.js 頁面
* Asm.js: The JavaScript Compile Target（頁面存檔備份，存於網際網路檔案館）
* RPerl（頁面存檔備份，存於網際網路檔案館）
* Asm.js usage per Google Chrome statistics（頁面存檔備份，存於網際網路檔案館）