- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > web開(kāi)發(fā) >
- Javascript編譯目標Asm.js的介紹
這篇文章主要介紹“Javascript編譯目標Asm.js的介紹”,在日常操作中,相信很多人在Javascript編譯目標Asm.js的介紹問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對大家解答”Javascript編譯目標Asm.js的介紹”的疑惑有所幫助!接下來(lái),請跟著(zhù)小編一起來(lái)學(xué)習吧!
正如許多開(kāi)發(fā)者一樣,我也為Asm.js的前景而感到興奮不已。最近的新聞——Asm.js正 在被Firefox支持——引起了我的興趣。同樣感興趣的還有Mozilla和Epic聲明(mirror)他們已經(jīng)為Asm.js而支持Unreal Engine 3——并且運行十分良好。
獲得一個(gè)C++游戲引擎運行Javascript,并使用WebGL來(lái)渲染,這是一個(gè)重大的突破,這個(gè)突破很大程度上歸功于Mozilla開(kāi)發(fā)的工具鏈,才使得這一切變得可能。
由于Unreal Engine 3開(kāi)始支持Asm.js,我瀏覽了來(lái)自Twitter,blogs和其他地方的回應,當一部分開(kāi)發(fā)者表現出對這項制造奇跡的技術(shù)躍躍欲試時(shí),我也看到許多 疑惑:Asm.js是一個(gè)插件嗎?Asm.js能讓我平時(shí)使用的Javascript運行的更快嗎?它兼容所有瀏覽器嗎?從這些回應中,我認為 Asm.js及其相關(guān)技術(shù)很重要,我將解釋這些技術(shù),好讓開(kāi)發(fā)者明白發(fā)生了什么以及他們將會(huì )如何從這些技術(shù)中獲益。另外,為了寫(xiě)出這篇我對這項技術(shù)的概 覽,我也請教了David Herman(Mozilla研究院的高級研究員)一大堆關(guān)于A(yíng)sm.js和如何梳理這些知識的問(wèn)題。
什么是 Asm.js?
為了理解 Asm.js 及其適用與瀏覽器的所在,你需要知道它的由來(lái)以及它存在的意義。
Asm.js 來(lái)自于 JavaScript 應用的一個(gè)新領(lǐng)域: 編譯成JavaScript的C/C++應用. 它是 JavaScript 應用的一個(gè)全新流派,由 Mozilla 的 Emscripten項目催生而來(lái)。
Emscripten 將 C/C++ 代碼傳入 LLVM, 并將 LLVM生成的字節碼轉換成 JavaScript (具體的, Asm.js, 是 JavaScript 的一個(gè)子集).
如果被編譯成的 Asm.js 的代碼做了一些渲染工作,那么它幾乎總是由WebGL來(lái)處理的 (并且由 OpenGL 來(lái)渲染). 這樣技術(shù)上就利用了JavaScript 和瀏覽器的好處,但幾乎完全避開(kāi)了頁(yè)面中Javascript使用的實(shí)際的、常規的代碼執行和渲染路徑.
Asm.js是Javascript的一個(gè)子集,它深度的限制了其所能做的范圍和所能操作的對象。這樣做才能使得Asm.js的代碼能夠盡可能運行的快, 從而盡可能減少各種假定情況的出現,從而能夠把Asmjs代碼直接轉變成為匯編代碼。有一個(gè)特別值得注意的是 - Asmjs還只是Javascript - 不需要瀏覽器的插件或者是別的特性去運行它(雖然一個(gè)能夠檢測出并且優(yōu)化Asmjs代碼的瀏覽器當然是要快一些)。它是Javascript的一個(gè)特定的 子集,為性能優(yōu)化而生,特別是為那些需要編譯成為Javascript的應用程序來(lái)做優(yōu)化。
***的理解Asmjs工作的方式,就是看看一些Asmjs-編譯化的代碼。讓我們看看這個(gè)函數,這是從真實(shí)的Asmjs編譯模塊里面提取出來(lái)的函數(來(lái)自BananaBread demo)。我對代碼格式做了調整,所以看起來(lái)更加合乎代碼片段的閱讀,原本它是一個(gè)高度壓縮的JavaScript代碼中的一個(gè)很大的計算機二進(jìn)制對象。
function Vb(d) { d = d | 0; var e = 0, f = 0, h = 0, j = 0, k = 0, l = 0, m = 0, n = 0, o = 0, p = 0, q = 0, r = 0, s = 0; e = i; i = i + 12 | 0; f = e | 0; h = d + 12 | 0; j = c[h >> 2] | 0; if ((j | 0) > 0) { c[h >> 2] = 0; k = 0 } else { k = j } j = d + 24 | 0; if ((c[j >> 2] | 0) > 0) { c[j >> 2] = 0 } l = d + 28 | 0; c[l >> 2] = 0; c[l + 4 >> 2] = 0; l = (c[1384465] | 0) + 3 | 0; do { if (l >>> 0 < 26) { if ((4980736 >>> (l >>> 0) & 1 | 0) == 0) { break } if ((c[1356579] | 0) > 0) { m = d + 4 | 0; n = 0; while (1) { o = c[(c[1356577] | 0) + (n << 2) >> 2] | 0; do { if (a[o + 22 | 0] << 24 >> 24 == 24) { if (!(Vp(d, o | 0) | 0)) { break } p = (c[m >> 2] | 0) + (((c[h >> 2] | 0) - 1 | 0) * 40 & -1) + 12 | 0; q = o + 28 | 0; c[p >> 2] = c[q >> 2] | 0; c[p + 4 >> 2] = c[q + 4 >> 2] | 0; c[p + 8 >> 2] = c[q + 8 >> 2] | 0; c[p + 12 >> 2] = c[q + 12 >> 2] | 0; c[p + 16 >> 2] = c[q + 16 >> 2] | 0; c[p + 20 >> 2] = c[q + 20 >> 2] | 0; c[p + 24 >> 2] = c[q + 24 >> 2] | 0 } } while (0); o = n + 1 | 0; if ((o | 0) < (c[1356579] | 0)) { n = o } else { break } } r = c[h >> 2] | 0 } else { r = k } if ((r | 0) == 0) { i = e; return } n = c[j >> 2] | 0; if ((n | 0) >= 1) { i = e; return } m = f | 0; o = f + 4 | 0; q = f + 8 | 0; p = n; while (1) { g[m >> 2] = 0.0; g[o >> 2] = 0.0; g[q >> 2] = 0.0; Vq(d, p, f, 0, -1e3); n = c[j >> 2] | 0; if ((n | 0) < 1) { p = n } else { break } } i = e; return } } while (0); if ((c[1356579] | 0) <= 0) { i = e; return } f = d + 16 | 0; r = 0; while (1) { k = c[(c[1356577] | 0) + (r << 2) >> 2] | 0; do { if (a[k + 22 | 0] << 24 >> 24 == 30) { h = b[k + 14 >> 1] | 0; if ((h - 1 & 65535) > 1) { break } l = c[j >> 2] | 0; p = (c[1384465] | 0) + 3 | 0; if (p >>> 0 < 26) { s = (2293760 >>> (p >>> 0) & 1 | 0) != 0 ? 0 : -1e3 } else { s = -1e3 } if (!(Vq(d, l, k | 0, h << 16 >> 16, s) | 0)) { break } g[(c[f >> 2] | 0) + (l * 112 & -1) + 56 >> 2] = +(b[k + 12 >> 1] << 16 >> 16 | 0); h = (c[f >> 2] | 0) + (l * 112 & -1) + 60 | 0; l = k + 28 | 0; c[h >> 2] = c[l >> 2] | 0; c[h + 4 >> 2] = c[l + 4 >> 2] | 0; c[h + 8 >> 2] = c[l + 8 >> 2] | 0; c[h + 12 >> 2] = c[l + 12 >> 2] | 0; c[h + 16 >> 2] = c[l + 16 >> 2] | 0; c[h + 20 >> 2] = c[l + 20 >> 2] | 0; c[h + 24 >> 2] = c[l + 24 >> 2] | 0 } } while (0); k = r + 1 | 0; if ((k | 0) < (c[1356579] | 0)) { r = k } else { break } } i = e; return }
從技術(shù)上說(shuō),這是Javascript代碼,但是我們已經(jīng)看到這段代碼一點(diǎn)都不像大多我們正??吹降牟僮鱀OM的Javascript。通過(guò)看這段代碼,我們可以發(fā)現幾件事:
這段特定的代碼只能處理數值。事實(shí)上這是所有Asm.js代碼的情形。Asm.js只能處理被挑出的幾種不同的數值類(lèi)型,而沒(méi)有提供其他的數據類(lèi)型(包括字符串,布爾型和對象)。
所有外部數據在一個(gè)稱(chēng)為堆的對象中存儲并被引用。堆在本質(zhì)上是一個(gè)大數組(應當是一個(gè)在性能上高度優(yōu)化的類(lèi)型化數組)。所有的數據在這個(gè)數組中存儲——有效的替代了全局變量,結構體,閉包和其他形式的數據存儲。
當訪(fǎng)問(wèn)和賦值變量時(shí),結果被統一的強制轉換成一種特定類(lèi)型。例如f = e | 0;給變量f賦值e,但它也確保了結果的類(lèi)型是一個(gè)整數(|0把值轉換成整數,確保了這點(diǎn))。這也發(fā)生在浮點(diǎn)型上——注意0.0和g[...] = +(...)的使用.
看看從數據結構中寫(xiě)入讀出的值,用c表示的數據結構好像是一個(gè)Int32Array(存儲32位整數,因為這些值總是通過(guò)|0被轉換成或者轉換自一個(gè)整數),g好像是一個(gè)Float32Array(存儲32位浮點(diǎn)數,因為這些值總是通過(guò)包裹上+(...)轉換成浮點(diǎn)數)。
這么做以后,結果就是高度優(yōu)化,并且可以直接從Asm.js語(yǔ)法轉換成匯編,而不必像常常要對Javascript做的那樣解釋它。它有效地削減了使像Javascript之類(lèi)的的動(dòng)態(tài)語(yǔ)言緩慢的東西:例如需要垃圾收集器和動(dòng)態(tài)類(lèi)型。
作為一個(gè)更容易理解的Asm.js代碼示例,我們來(lái)看看一個(gè)Asm.js規范上的例子:
function DiagModule(stdlib, foreign, heap) { "use asm"; // Variable Declarations var sqrt = stdlib.Math.sqrt; // Function Declarations function square(x) { x = +x; return +(x*x); } function diag(x, y) { x = +x; y = +y; return +sqrt(square(x) + square(y)); } return { diag: diag }; }
看看這個(gè)模塊,它完全能讓人理解!閱讀這些代碼,我們能更好的理解Asm.js模塊的結構。一個(gè)模塊包含在一個(gè)函數中,它以頂部的"use asm";指令開(kāi)始。它提示解釋器這個(gè)函數里所有的東西可以被當成Asm.js處理,并可以直接被編譯成匯編代碼。
注意在函數頂部的三個(gè)參數:stdlib,foreigh和heap。stdlib對象包含了很多內建數學(xué)函數的引用。foreign提供了自定義用戶(hù)功能(例如在WebGL中繪制圖形)的訪(fǎng)問(wèn)。***,heap給了你一個(gè)ArrayBuffer,它可以通過(guò)很多透鏡(例如Int32Array和Float32Array)來(lái)觀(guān)察。
該模塊剩下的被分成了三部分:變量聲明,函數聲明,還有***把函數導出暴露給用戶(hù)的一個(gè)對象。
導出是尤其要去理解的一個(gè)重點(diǎn),因為它既讓所有模塊中的代碼被當成Asm.js處理,又使得代碼可以被其他普通的Javascript代碼使用。因此,在理論上你可以通過(guò)使用上面的DiagModule代碼,寫(xiě)下如下代碼:
document.body.onclick = function() { function DiagModule(stdlib){"use asm"; ... return { ... };} var diag = DiagModule({ Math: Math }).diag; alert(diag(10, 100)); };
這帶來(lái)了一個(gè)Asm.js模塊DiagModule,它被Javascript解釋器特殊處理,但仍然能夠被其他Javascript代碼使用(我們仍能訪(fǎng)問(wèn)并使用它,比如一個(gè)單擊事件處理程序)。
性能如何?
現在A(yíng)sm.js唯一的實(shí)現就是nightly versions of Firefox(而且也只是針對特定的幾個(gè)平臺)。原來(lái)的數字告訴我們Ams.js的性能是非常非常不錯的。對于復雜的應用(比如上面的游戲)性能僅僅比普通C++編譯的慢兩倍(可以和Java或者C#相媲美)。實(shí)際上,這已經(jīng)比目前瀏覽器的運行時(shí)環(huán)境要快很多了,幾乎是***版的Firefox或者Chrome執行速度的4~10倍。
基于目前***測試,可以看出Asm.js在性能上有很大的提升??紤]到現在僅僅是Asm.js的最初開(kāi)發(fā)階段,相信在不久的將來(lái)就會(huì )有更大的性能提升。
看到Asm.js和當前的Firefox和Chrome引擎的性能差距是很有意思的。一個(gè)4~10倍的性能差異是非常巨大的(就好像拿這些瀏覽器和IE6 做性能對比一樣)。有趣的是雖然有這么大的性能差異,但是許多的Asm.js演示例子仍然是可以在Chrome和Firefox——這些代表著(zhù)當前 Javascript先進(jìn)技術(shù)的引擎——上使用的。這也就是說(shuō)他們的性能明顯不如一個(gè)運行著(zhù)優(yōu)化過(guò)的Asm.js代碼的瀏覽器相提并論。
使用情況
需要說(shuō)明的是現在幾乎所有基于A(yíng)sm.js的應用都是C/C++應用使用Emscripten編譯的??梢钥隙ǖ恼f(shuō),在不久的將來(lái),這類(lèi)即將運行在 Asm.js的應用,將會(huì )從可以在瀏覽器中運行這一可移植性中獲益,但是在支持javascript方面有一定復雜度的應用將不可行。
到目前為止,大部分的使用情況下,代碼性能是至關(guān)重要的:比如運行游戲,圖像,處理語(yǔ)言翻譯和庫。從一個(gè)關(guān)于Emscripten項目列表的概覽可以看到許多即將被廣大開(kāi)發(fā)者使用的技術(shù)。
許多游戲引擎已經(jīng)被支持。一個(gè)好的演示也許就是BananaBread FPS游戲(源代碼),它可以直接在瀏覽器中運行,支持多玩家和機器人。
支持javascript的LaTeX,即textlive.js,使用Emscripten,允許你完全在你的瀏覽器中編輯PDF文檔。
支持javascript的SQLite,能夠在Node.js中運行。
NaCL:一個(gè)網(wǎng)絡(luò )加密解密的庫。
Asm.js支持
就像之前提到的那樣,現在只有nightly版本的Firefox支持Asm.js的優(yōu)化。
但是,要注意Asm.js格式的Javascript代碼仍然是Javascript,雖然其存在一些限制。這樣,其他的瀏覽器即使不支持Asm.js仍可以將其作為普通的Javascript代碼運行。
有關(guān)代碼性能重要而令人不解的一點(diǎn)是:如果瀏覽器不支持typed array或者不能對Asm.js代碼進(jìn)行特殊的編譯,Asm.js的性能會(huì )變的很差。當然,這并不止針對Asm.js,如果沒(méi)有這些特性,瀏覽器的性能在其他方面也會(huì )收到影響。
Asm.js與Web開(kāi)發(fā)
你可能已經(jīng)看出來(lái)了,上面的Asm.js代碼不是手工輸入的的。Asm.js需要一些特殊的工具來(lái)編寫(xiě),而且其開(kāi)發(fā)和編寫(xiě)普通的 Javascript代碼有很大區別。目前一般的Asm.js應用都是從C/C++編譯到Javascript的,很顯然它們都不會(huì )與DOM進(jìn)行任何交 互,而是直接與WebGL打交道。
為了能讓一般的開(kāi)發(fā)者使用,需要一些更能讓人接受的中間語(yǔ)言。目前LLJS已經(jīng)逐漸實(shí)現向Asm.js編譯了。需要注意的是,LLJS這樣的語(yǔ)言同樣與常規的Javascript有很大區別,會(huì )讓許多Javascript開(kāi)發(fā)者感到困擾。即使是用LLJS這樣更加友好的語(yǔ)言,編寫(xiě)Asm.js必須要對復雜的代碼進(jìn)行優(yōu)化,這恐怕只有資深開(kāi)發(fā)者能夠勝任了。
就算有了LLJS或者別的語(yǔ)言來(lái)幫助我們編寫(xiě)Asm.js,我們也沒(méi)有同樣性能優(yōu)異的DOM可以使用。理想的環(huán)境應該是將LLJS與DOM一起編譯產(chǎn)生單一的可執行二進(jìn)制文件。我還想不出這樣做性能會(huì )有多好,但是我想這么做!
與David Herman的問(wèn)答
我寫(xiě)信給David Herman(Mozilla Research的高級研究員),向他詢(xún)問(wèn)了一些問(wèn)題。他們是如何將Asm.js的各部分結合在一起的?他們又希望用戶(hù)從中得到什么呢?他親切地深入回答了這些問(wèn)題,有些回復很有趣。我希望你們也同樣能從中獲得啟發(fā)。
Asm.js的目標是什么?你們這個(gè)計劃的目標人群是哪些?
創(chuàng )建一個(gè)利于用戶(hù)訪(fǎng)問(wèn)版本的Asm.js是否合理呢,比如一個(gè)更新版本的LLJS?或者是擴展目前項目的范圍,而不僅僅是一個(gè)編譯器的目標語(yǔ)言?
有一個(gè)討論是關(guān)于,在目前支持Asm.js的瀏覽器和不支持的瀏覽器之間,會(huì )出現一種因此更新而形成的性能的分界,類(lèi)似與 2008/2009年中所發(fā)生的JavaScript性能競爭。雖然技術(shù)上來(lái)看,Asm.js的代碼在現實(shí)中,可以運行于任意兩者之上,而性能的不同,對 于大多數的場(chǎng)合而言將會(huì )有有明顯的不同(譯者注:原詞是too crippling,意思大致是嚴重的傷害)。那么對于這種分界,以及高度限制Javascript,為什么你選擇了Javascript作為編譯的目標?為什么不是另一種取代javascript的語(yǔ)言或者是一種插件?(譯者注:作者似乎是想說(shuō)明,Javascript的限制對于所有瀏覽器都會(huì )有影響,那么對于不支持Asm.js的瀏覽器會(huì )有所傷害,所以為什么不選擇別的語(yǔ)言或者是插件,這樣就會(huì )只影響自己的產(chǎn)品)
拿Asm.js和Google的Native Client做比較,你覺(jué)得如何?他們似乎都有這類(lèi)似的目標,同時(shí)Asmjs有著(zhù)可以運行在任何支持javascript的地方的優(yōu)勢。有過(guò)對于兩者之間的任何性能比較么?
Emscripten是另一個(gè)Mozilla項目,也是Asm.js的主要兼容代碼的貢獻者。有多少Asm.js的開(kāi)發(fā)被Emscripten的項目需求所支配?Emscripten又從引擎的提升上獲得了什么益處?
Asm.js的功能還會(huì )變動(dòng)么?隨著(zhù)越來(lái)越多編譯器開(kāi)發(fā)者的加入,你贊不贊同加入更多的附加功能(比如更高級的數據結構)?
可以做出JavaScript-to-Asm.js轉譯器么,它會(huì )被做出來(lái)么?
現在A(yíng)sm.js還不能進(jìn)行與有關(guān)DOM和瀏覽器的操作。創(chuàng )建一個(gè)Emscripten到Ams.js版本的DOM(就像DOM.js)如何?
編寫(xiě)Asm.js代碼與編寫(xiě)一般的Javascript代碼相比確實(shí)十分困難,你有什么工具可以提供給開(kāi)發(fā)者和編譯器作者呢?
我覺(jué)得你們很樂(lè )于和其他瀏覽器廠(chǎng)商一起工作,你們的合作和討論進(jìn)展如何?
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系站長(cháng)郵箱:ts@56dr.com進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2 建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站