成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

WebAssembly 系列(四)WebAssembly 工作原理

stormzhang / 3374人閱讀

摘要:但是它們其實(shí)并不是二選一的關(guān)系并不是只能用或者。正因?yàn)槿绱耍噶钣袝r(shí)也被稱為虛擬指令。這是因?yàn)槭遣捎没跅5奶摂M機(jī)的機(jī)制。聲明模塊的全局變量。。下文預(yù)告現(xiàn)在你已經(jīng)了解了模塊的工作原理,下面將會(huì)介紹為什么運(yùn)行的更快。

作者:Lin Clark

編譯:胡子大哈

翻譯原文:http://huziketang.com/blog/posts/detail?postId=58c77641a6d8a07e449fdd24

英文原文:Creating and working with WebAssembly modules

轉(zhuǎn)載請(qǐng)注明出處,保留原文鏈接以及作者信息

本文是關(guān)于 WebAssembly 系列的第四篇文章(本系列共六篇文章)。如果你沒(méi)有讀先前文章的話,建議先讀這里。如果對(duì) WebAssembly 沒(méi)概念,建議先讀這里(中文文章)。

WebAssembly 是除了 JavaScript 以外,另一種可以在網(wǎng)頁(yè)中運(yùn)行的編程語(yǔ)言。過(guò)去如果你想在瀏覽器中運(yùn)行代碼來(lái)對(duì)網(wǎng)頁(yè)中各種元素進(jìn)行控制,只有 JavaScript 這一種選擇。

所以當(dāng)人們談?wù)?WebAssembly 的時(shí)候,往往會(huì)拿 JavaScript 來(lái)進(jìn)行比較。但是它們其實(shí)并不是“二選一”的關(guān)系——并不是只能用 WebAssembly 或者 JavaScript。

實(shí)際上,我們鼓勵(lì)開發(fā)者將這兩種語(yǔ)言一起使用,即使你不親自實(shí)現(xiàn) WebAssembly 模塊,你也可以學(xué)習(xí)它現(xiàn)有的模塊,并它的優(yōu)勢(shì)來(lái)實(shí)現(xiàn)你的功能。

WebAssembly 模塊定義的一些功能可以通過(guò) JavaScript 來(lái)調(diào)用。所以就像你通過(guò) npm 下載 lodash 模塊并通過(guò) API 使用它一樣,未來(lái)你也可以下載 WebAssembly 模塊并且使用其提供的功能。

那么就讓我們來(lái)看一下如何開發(fā) WebAssembly 模塊,以及如何通過(guò) JavaScript 使用他們。

WebAssembly 處于哪個(gè)環(huán)節(jié)?

在上一篇關(guān)于匯編的文章中,我介紹了編譯器是如何從高級(jí)語(yǔ)言翻譯到機(jī)器碼的。

那么在上圖中,WebAssembly 在什么位置呢?實(shí)際上,你可以把它看成另一種“目標(biāo)匯編語(yǔ)言”。

每一種目標(biāo)匯編語(yǔ)言(x86、ARM)都依賴于特定的機(jī)器結(jié)構(gòu)。當(dāng)你想要把你的代碼放到用戶的機(jī)器上執(zhí)行的時(shí)候,你并不知道目標(biāo)機(jī)器結(jié)構(gòu)是什么樣的。

而 WebAssembly 與其他的匯編語(yǔ)言不一樣,它不依賴于具體的物理機(jī)器??梢猿橄蟮乩斫獬伤?strong>概念機(jī)器的機(jī)器語(yǔ)言,而不是實(shí)際的物理機(jī)器的機(jī)器語(yǔ)言。

正因?yàn)槿绱?,WebAssembly 指令有時(shí)也被稱為虛擬指令。它比 JavaScript 代碼更直接地映射到機(jī)器碼,它也代表了“如何能在通用的硬件上更有效地執(zhí)行代碼”的一種理念。所以它并不直接映射成特定硬件的機(jī)器碼。

瀏覽器把 WebAssembly 下載下來(lái),然后先經(jīng)過(guò) WebAssembly 模塊,再到目標(biāo)機(jī)器的匯編代碼。

編譯到 .wasm 文件

目前對(duì)于 WebAssembly 支持情況最好的編譯器工具鏈?zhǔn)?LLVM。有很多不同的前端和后端插件可以用在 LLVM 上。

提示:很多 WebAssembly 開發(fā)者用 C 語(yǔ)言或者 Rust 開發(fā),再編譯成 WebAssembly。其實(shí)還有其他的方式來(lái)開發(fā) WebAssembly 模塊。例如利用 TypeScript 開發(fā) WebAssembly 模塊,或者直接用 WebAssembly 文本也可以。

假設(shè)想從 C 語(yǔ)言到 WebAssembly,我們就需要 clang 前端來(lái)把 C 代碼變成 LLVM 中間代碼。當(dāng)變換成了 LLVM IR 時(shí),說(shuō)明 LLVM 已經(jīng)理解了代碼,它會(huì)對(duì)代碼自動(dòng)地做一些優(yōu)化。

為了從 LLVM IR 生成 WebAssembly,還需要后端編譯器。在 LLVM 的工程中有正在開發(fā)中的后端,而且應(yīng)該很快就開發(fā)完成了,現(xiàn)在這個(gè)時(shí)間節(jié)點(diǎn),暫時(shí)還看不到它是如何起作用的。

還有一個(gè)易用的工具,叫做 Emscripten。它通過(guò)自己的后端先把代碼轉(zhuǎn)換成自己的中間代碼(叫做 asm.js),然后再轉(zhuǎn)化成 WebAssembly。實(shí)際上它背后也是使用的 LLVM。

Emscripten 還包含了許多額外的工具和庫(kù)來(lái)包容整個(gè) C/C++ 代碼庫(kù),所以它更像是一個(gè)軟件開發(fā)者工具包(SDK)而不是編譯器。例如系統(tǒng)開發(fā)者需要文件系統(tǒng)以對(duì)文件進(jìn)行讀寫,Emscripten 就有一個(gè) IndexedDB 來(lái)模擬文件系統(tǒng)。

不考慮太多的這些工具鏈,只要知道最終生成了 .wasm 文件就可以了。后面我會(huì)介紹 .wasm 文件的結(jié)構(gòu),在這之前先一起了解一下在 JS 中如何使用它。

加載一個(gè) .wasm 模塊到 JavaScript

.wasm 文件是 WebAssembly 模塊,它可以加載到 JavaScript 中使用,現(xiàn)階段加載的過(guò)程稍微有點(diǎn)復(fù)雜。

function fetchAndInstantiate(url, importObject) {
  return fetch(url).then(response =>
    response.arrayBuffer()
  ).then(bytes =>
    WebAssembly.instantiate(bytes, importObject)
  ).then(results =>
    results.instance
  );
}

如果想深入了解,可以在 MDN 文檔中了解更多。

我們一直在致力于把這一過(guò)程變得簡(jiǎn)單,對(duì)工具鏈進(jìn)行優(yōu)化。希望能夠把它整合到現(xiàn)有的模塊打包工具中,比如 webpack 中,或者整合到加載器中,比如 SystemJS 中。我們相信加載 WebAssembly 模塊也可以像加載 JavaScript 一樣簡(jiǎn)單。

這里介紹 WebAssembly 模塊和 JavaScript 模塊的主要區(qū)別。當(dāng)前的 WebAssembly 只能使用數(shù)字(整型或者浮點(diǎn)型)作為參數(shù)或者返回值。

對(duì)于任何其他的復(fù)雜類型,比如 string,就必須得用 WebAssembly 模塊的內(nèi)存操作了。如果是經(jīng)常使用 JavaScript,對(duì)直接操作內(nèi)存不是很熟悉的話,可以回想一下 C、C++ 和 Rust 這些語(yǔ)言,它們都是手動(dòng)操作內(nèi)存。WebAssembly 的內(nèi)存操作和這些語(yǔ)言的內(nèi)存操作很像。

為了實(shí)現(xiàn)這個(gè)功能,它使用了 JavaScript 中稱為 ArrayBuffer 的數(shù)據(jù)結(jié)構(gòu)。ArrayBuffer 是一個(gè)字節(jié)數(shù)組,所以它的索引(index)就相當(dāng)于內(nèi)存地址了。

如果你想在 JavaScript 和 WebAssembly 之間傳遞字符串,可以利用 ArrayBuffer 將其寫入內(nèi)存中,這時(shí)候 ArrayBuffer 的索引就是整型了,可以把它傳遞給 WebAssembly 函數(shù)。此時(shí),第一個(gè)字符的索引就可以當(dāng)做指針來(lái)使用。

這就好像一個(gè) web 開發(fā)者在開發(fā) WebAssembly 模塊時(shí),把這個(gè)模塊包裝了一層外衣。這樣其他使用者在使用這個(gè)模塊的時(shí)候,就不用關(guān)心內(nèi)存管理的細(xì)節(jié)。

如果你想了解更多的內(nèi)存管理,看一下我們寫的 WebAssembly 的內(nèi)存操作。

.wasm 文件結(jié)構(gòu)

如果你是寫高級(jí)語(yǔ)言的開發(fā)者,并且通過(guò)編譯器編譯成 WebAssembly,那你不用關(guān)心 WebAssembly 模塊的結(jié)構(gòu)。但是了解它的結(jié)構(gòu)有助于你理解一些基本問(wèn)題。

如果你對(duì)編譯器還不了解,建議先讀一下“WebAssembly 系列(三)編譯器如何生成匯編”這篇文章。

這段代碼是即將生成 WebAssembly 的 C 代碼:

int add42(int num) {
    return num + 42;
}

你可以使用 WASM Explorer 來(lái)編譯這個(gè)函數(shù)。

打開 .wasm 文件(假設(shè)你的編輯器支持的話),可以看到下面代碼:

00 61 73 6D 0D 00 00 00 01 86 80 80 80 00 01 60
01 7F 01 7F 03 82 80 80 80 00 01 00 04 84 80 80
80 00 01 70 00 00 05 83 80 80 80 00 01 00 01 06
81 80 80 80 00 00 07 96 80 80 80 00 02 06 6D 65
6D 6F 72 79 02 00 09 5F 5A 35 61 64 64 34 32 69
00 00 0A 8D 80 80 80 00 01 87 80 80 80 00 00 20
00 41 2A 6A 0B

這是模塊的“二進(jìn)制”表示。之所以用引號(hào)把“二進(jìn)制”引起來(lái),是因?yàn)樯厦嫫鋵?shí)是用十六進(jìn)制表示的,不過(guò)把它變成二進(jìn)制或者人們能看懂的十進(jìn)制表示也很容易。

例如,下面是 num + 42 的各種表示方法。

代碼是如何工作的:基于棧的虛擬機(jī)

如果你對(duì)具體的操作過(guò)程很好奇,那么這幅圖可以告訴你指令都做了什么。

從圖中我們可以注意到 操作并沒(méi)有指定哪兩個(gè)數(shù)字進(jìn)行加。這是因?yàn)?WebAssembly 是采用“基于棧的虛擬機(jī)”的機(jī)制。即一個(gè)操作符所需要的所有值,在操作進(jìn)行之前都已經(jīng)存放在堆棧中。

所有的操作符,比如加法,都知道自己需要多少個(gè)值。 需要兩個(gè)值,所以它從堆棧頂部取兩個(gè)值就可以了。那么指令就可以變的更短(單字節(jié)),因?yàn)橹噶畈恍枰付ㄔ醇拇嫫骱湍康募拇嫫鳌_@也使得 .wasm 文件變得更小,進(jìn)而使得加載 .wasm 文件更快。

盡管 WebAssembly 使用基于棧的虛擬機(jī),但是并不是說(shuō)在實(shí)際的物理機(jī)器上它就是這么生效的。當(dāng)瀏覽器翻譯 WebAssembly 到機(jī)器碼時(shí),瀏覽器會(huì)使用寄存器,而 WebAssembly 代碼并不指定用哪些寄存器,這樣做的好處是給瀏覽器最大的自由度,讓其自己來(lái)進(jìn)行寄存器的最佳分配。

WebAssembly 模塊的組成部分

除了上面介紹的,.wasm 文件還有其他部分,通常把它們叫做部件。一些部件對(duì)于模塊來(lái)講是必須的,一些是可選的。

必須部分

Type。在模塊中定義的函數(shù)的函數(shù)聲明和所有引入函數(shù)的函數(shù)聲明。

Function。給出模塊中每個(gè)函數(shù)一個(gè)索引。

Code。模塊中每個(gè)函數(shù)的實(shí)際函數(shù)體。

可選部分

Export。使函數(shù)、內(nèi)存、表單(table)、全局變量等對(duì)其他 WebAssembly 或 JavaScript 可見(jiàn),允許動(dòng)態(tài)鏈接一些分開編譯的組件,即 .dll 的WebAssembly 版本。

Import。允許從其他 WebAssembly 或者 JavaScript 中引入指定的函數(shù)、內(nèi)存、表單或者全局變量。

Start。當(dāng) WebAssembly 模塊加載進(jìn)來(lái)的時(shí)候,可以自動(dòng)運(yùn)行的函數(shù)(類似于 main 函數(shù))。

Global。聲明模塊的全局變量。

Memory。定義模塊用到的內(nèi)存。

Table。使得可以映射到 WebAssembly 模塊以外的值,如映射到 JavaScript 對(duì)象中。這在間接函數(shù)調(diào)用時(shí)很有用。

Data。初始化內(nèi)存。

Element。初始化表單(table)。

如果想要了解更多的部件,可以在“如何使用部件”中深入了解。

下文預(yù)告

現(xiàn)在你已經(jīng)了解了 WebAssembly 模塊的工作原理,下面將會(huì)介紹為什么 WebAssembly 運(yùn)行的更快。

我最近正在寫一本《React.js 小書》,對(duì) React.js 感興趣的童鞋,歡迎指點(diǎn)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81987.html

相關(guān)文章

  • WebAssembly 系列(一)生動(dòng)形象地介紹 WebAssembly

    摘要:但是為什么執(zhí)行的更快呢在這個(gè)系列文章中,我會(huì)為你解釋這一點(diǎn)。所以當(dāng)人們說(shuō)更快的時(shí)候,一般來(lái)講是與相比而言的。被人們廣為傳播的性能大戰(zhàn)在年打響。性能的提升使得的應(yīng)用范圍得到很大的擴(kuò)展?,F(xiàn)在通過(guò),我們很有可能正處于第二個(gè)拐點(diǎn)。 作者:Lin Clark 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58ce8036...

    wangbjun 評(píng)論0 收藏0
  • WebAssembly 為什么比 asm.js 快?

    摘要:并且于年月日,四個(gè)主要的瀏覽器一致同意宣布的版本已經(jīng)完成,即將推出一個(gè)瀏覽器可以搭載的穩(wěn)定版本。因此本文著重介紹為什么比更快。本文主要表達(dá)的是為什么應(yīng)該是更快的。則不同,它是由幾大主要的瀏覽器廠商共同設(shè)計(jì)的。 作者:Alon Zakai 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58ce80d2a6d8a0...

    Binguner 評(píng)論0 收藏0
  • JavaScript 工作原理之六-WebAssembly 對(duì)比 JavaScript 及其使用場(chǎng)景

    摘要:現(xiàn)在,我們將會(huì)剖析的工作原理,而最重要的是它和在性能方面的比對(duì)加載時(shí)間,執(zhí)行速度,垃圾回收,內(nèi)存使用,平臺(tái)訪問(wèn),調(diào)試,多線程以及可移植性。目前,是專門圍繞和的使用場(chǎng)景設(shè)計(jì)的。目前不支持多線程。 原文請(qǐng)查閱這里,略有改動(dòng),本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第六章...

    jay_tian 評(píng)論0 收藏0
  • 前端每周清單半年盤點(diǎn)之 WebAssembly

    摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。利用降低三倍加載速度自推出之后,很多開發(fā)者都開始嘗試在小型項(xiàng)目中實(shí)踐,不過(guò)尚缺大型真實(shí)案例比較。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目...

    Alan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<