'WebAssembly初探以及在Tengine中的應用'

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

WebAssembly初探以及在Tengine中的應用

另一個針對嵌入式環境的開源庫Intel WAMR,它不包含Back End,直接人肉解析WebAssembly二進制的代碼段中的指令,然後實現這些指令對應的功能,這種運行方式和解釋型語言沒多大區別,或許是因為嵌入式環境資源限制導致的無法加載通常體積較大的Back End。

0x06 WASI

從上面的介紹可以看到,所有的概念和例子的語境都沒有離開瀏覽器,正在將WebAssembly技術帶離瀏覽器奔向更大應用場景的是WASI規範,它定義了一系列底層(特別是和系統資源相關)的操作。

上文提及,WebAssembly是沙盒的,這對於瀏覽器而言很關鍵,但是當它脫離瀏覽器後,作為獨立VM,和Native環境打交道就不可避免。讓這些個接口規範化程度直接決定了其跨平臺性。

先貼一張WASI的終極目標示意圖

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

WebAssembly初探以及在Tengine中的應用

另一個針對嵌入式環境的開源庫Intel WAMR,它不包含Back End,直接人肉解析WebAssembly二進制的代碼段中的指令,然後實現這些指令對應的功能,這種運行方式和解釋型語言沒多大區別,或許是因為嵌入式環境資源限制導致的無法加載通常體積較大的Back End。

0x06 WASI

從上面的介紹可以看到,所有的概念和例子的語境都沒有離開瀏覽器,正在將WebAssembly技術帶離瀏覽器奔向更大應用場景的是WASI規範,它定義了一系列底層(特別是和系統資源相關)的操作。

上文提及,WebAssembly是沙盒的,這對於瀏覽器而言很關鍵,但是當它脫離瀏覽器後,作為獨立VM,和Native環境打交道就不可避免。讓這些個接口規範化程度直接決定了其跨平臺性。

先貼一張WASI的終極目標示意圖

WebAssembly初探以及在Tengine中的應用

用大家都熟悉的話總結就是 "Write One,Run Everywhere",同一個編譯目標能在不同平臺、機器上運行。

和Emscripten的區別

上文提到的emcc就是Emscripten項目的一員,從本文開頭的例子中,貌似emcc也能執行open read等操作,那為何還需要定義WASI呢?一個新的規範的出現必定是為了解決當前的某些問題,首先來看下Emscripten的問題。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

WebAssembly初探以及在Tengine中的應用

另一個針對嵌入式環境的開源庫Intel WAMR,它不包含Back End,直接人肉解析WebAssembly二進制的代碼段中的指令,然後實現這些指令對應的功能,這種運行方式和解釋型語言沒多大區別,或許是因為嵌入式環境資源限制導致的無法加載通常體積較大的Back End。

0x06 WASI

從上面的介紹可以看到,所有的概念和例子的語境都沒有離開瀏覽器,正在將WebAssembly技術帶離瀏覽器奔向更大應用場景的是WASI規範,它定義了一系列底層(特別是和系統資源相關)的操作。

上文提及,WebAssembly是沙盒的,這對於瀏覽器而言很關鍵,但是當它脫離瀏覽器後,作為獨立VM,和Native環境打交道就不可避免。讓這些個接口規範化程度直接決定了其跨平臺性。

先貼一張WASI的終極目標示意圖

WebAssembly初探以及在Tengine中的應用

用大家都熟悉的話總結就是 "Write One,Run Everywhere",同一個編譯目標能在不同平臺、機器上運行。

和Emscripten的區別

上文提到的emcc就是Emscripten項目的一員,從本文開頭的例子中,貌似emcc也能執行open read等操作,那為何還需要定義WASI呢?一個新的規範的出現必定是為了解決當前的某些問題,首先來看下Emscripten的問題。

WebAssembly初探以及在Tengine中的應用

read函數被emcc翻譯成了__syscall3(3, args),即VM/Engine需要實現一個名字叫__syscall3的函數,且函數read的多個參數將被保存在WebAssembly線性空間中,集成在參數 args 中,這被認為type unsafe

WASI將這些POSIX函數重新定義,如下圖所示,無論哪個平臺的VM/Engine,只需要實現和自身平臺相關的__wasi_fd_read函數給WebAssembly用即可,這樣在編寫WebAssembly調用read函數時就無需關心自身將會運行在哪個平臺。

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

WebAssembly初探以及在Tengine中的應用

另一個針對嵌入式環境的開源庫Intel WAMR,它不包含Back End,直接人肉解析WebAssembly二進制的代碼段中的指令,然後實現這些指令對應的功能,這種運行方式和解釋型語言沒多大區別,或許是因為嵌入式環境資源限制導致的無法加載通常體積較大的Back End。

0x06 WASI

從上面的介紹可以看到,所有的概念和例子的語境都沒有離開瀏覽器,正在將WebAssembly技術帶離瀏覽器奔向更大應用場景的是WASI規範,它定義了一系列底層(特別是和系統資源相關)的操作。

上文提及,WebAssembly是沙盒的,這對於瀏覽器而言很關鍵,但是當它脫離瀏覽器後,作為獨立VM,和Native環境打交道就不可避免。讓這些個接口規範化程度直接決定了其跨平臺性。

先貼一張WASI的終極目標示意圖

WebAssembly初探以及在Tengine中的應用

用大家都熟悉的話總結就是 "Write One,Run Everywhere",同一個編譯目標能在不同平臺、機器上運行。

和Emscripten的區別

上文提到的emcc就是Emscripten項目的一員,從本文開頭的例子中,貌似emcc也能執行open read等操作,那為何還需要定義WASI呢?一個新的規範的出現必定是為了解決當前的某些問題,首先來看下Emscripten的問題。

WebAssembly初探以及在Tengine中的應用

read函數被emcc翻譯成了__syscall3(3, args),即VM/Engine需要實現一個名字叫__syscall3的函數,且函數read的多個參數將被保存在WebAssembly線性空間中,集成在參數 args 中,這被認為type unsafe

WASI將這些POSIX函數重新定義,如下圖所示,無論哪個平臺的VM/Engine,只需要實現和自身平臺相關的__wasi_fd_read函數給WebAssembly用即可,這樣在編寫WebAssembly調用read函數時就無需關心自身將會運行在哪個平臺。

WebAssembly初探以及在Tengine中的應用

WASI例子

這裡使用的不再使用上文例子中的emcc,而是使用高版本Clang,為了避免系統環境無法支持高版本Clang的情況,這裡使用官方推薦的wasi-sdk-6來編譯生成WASI。

下載工具鏈

下載好wasi-sdk-6後解壓,例如我的解壓路徑是./code/wasi-sdk-6.0,可以使用如下命令編譯C源碼

編寫C文件

$cat 1.c 
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
char buf[1024];
int main()
{
int fd = open("1.c", O_RDONLY);
if (fd < 0) {
printf("can't load file 1.c\\n");
return -1;
}
read(fd, buf, sizeof(buf));
printf("Read file:\\n%s",buf);
return 0;
}

編譯

./code/wasi-sdk-6.0/opt/wasi-sdk/bin/clang --target=wasm32-wasi --sysroot=./code/wasi-sdk-6.0/opt/wasi-sdk/share/sysroot 1.c -o 1.wasm

運行WASI

這裡我們使用Wasmer的CLI來運行WASI

wasmer run 1.wasm --mapdir ./:./

如果順利的話,他將打印出當前目錄下1.c文件的內容。

0x07 Tengine+WebAssembly

Tengine作為基於Nginx的Web服務器,開源至今已有8年,在集團內幾乎所有應用前都部署了Tengine作為反向代理,同時Tengine本身作為集團統一接入產品,每天處理著集團大多數入口流量。

Tengine在WebAssembly領域也做了些嘗試,目前使用了Wasmer/Wavm 作為自己底層的runtime(編譯Tengine時選擇具體runtime)

下圖是Tengine使用WebAssembly的框架(藍色是為了支持WebAssembly而新增加的功能)

"

0x01 前言

WebAssembly本質是一種二進制指令格式(Binary Instruction Format),即是一種編譯目標,該技術成功地使得瀏覽器有辦法將沉重且耗時的JS代碼變成了擁有Native性能的二進制,毋庸置疑,它是成功的。

WebAssembly初探以及在Tengine中的應用

當WebAssembly脫離於瀏覽器後,其沙盒、高效、規範化、可移植性 等特性使其成為獨立VM變得可能,本文也將討論起WebAssembly技術作為獨立VM的優勢以及其在Tengine中的應用。

0x02 簡介

WebAssembly標準目前由Mozilla領導,Google、Microsoft、Apple等眾多大公司參與制定,但是是何緣故能讓這4大巨頭站在一塊、他們最原始的動機又是什麼,或許我們已經不得而知,Brendan Eich(JS的發明者、WebAssembly的主要推動者)也承認了最開始使用了私有github來協調各大巨頭共同確定目標並且推動他們為這項技術買單。

普遍認為,這4大廠代表了4大瀏覽器平臺,在面對日益增加的前端業務邏輯對計算機計算資源的消耗,迫切需要一種新的技術,該技術首先需要解決JS性能問題,即它是高效的;其次需要安全性,即它是沙盒的;接著是需要可移植性,即能被所有瀏覽器接受。

0x03 例子

首先我們先來通過一個例子來直觀感受下WebAssembly

機器環境準備

  • 升級工具鏈(僅集團的機器需要,因為他們的版本較低,使用OSX可以不需要這步)
  • emcc編譯器

準備源文件

#include <stdio.h>
int main()
{
printf("in wasm world\\n");
return 1;
}

編譯

chenjiayuadeMacBook-Pro:emsdk mrpre$ emcc targt.c -o target.html
chenjiayuadeMacBook-Pro:emsdk mrpre$
chenjiayuadeMacBook-Pro:emsdk mrpre$ ls -l target*
-rw-r--r-- 1 mrpre staff 80 8 13 10:21 target.c
-rw-r--r-- 1 mrpre staff 102676 8 13 10:22 target.html
-rw-r--r-- 1 mrpre staff 102935 8 13 10:22 target.js
-rw-r--r-- 1 mrpre staff 42765 8 13 10:22 target.wasm

我們看到,生成了3個文件,target.js 是膠水文件,用來調用target.wasm,其被本身用來被JSEngine加載。

使用node運行

chenjiayuadeMacBook-Pro:emsdk mrpre$ node target.js
in wasm world
chenjiayuadeMacBook-Pro:emsdk mrpre$

貌似還不直觀,那就使用瀏覽器運行

先在當前目錄中啟動一個簡單的httpserver用以瀏覽器訪問

python -m SimpleHTTPServer 9000

瀏覽器訪問http://127.0.0.1:9000/target.html

WebAssembly初探以及在Tengine中的應用

展示頁面的其他元素是emcc幫助生成的我們並不關心,這裡我們關心瀏覽器控制檯console輸出的結果,console裡面輸出的正是我們C代碼printf打印的數據,可以推測,printf的功能由console.log實現。

0x04 安全性

WebAssembly的安全性歸根結底,是其沙盒的特性。

文件安全

你可以在 上面例子中 嘗試 open一個xxx文件,你會發現,你沒辦法打開,除非編譯時顯示的加上"--embed-file xxx",該編譯選項將文件內容全部放在target.js中,target.wasm在被執行時,所有的文件操作也均在內存上執行,在WebAssembly所有讀寫操作均在內存上進行。

內存安全

先來看下WebAssembly是如何管理內存的。

通常,WebAssembly的內存需要Native環境申請且提供給.wasm,即Native在實例化.wasm文件時需要顯示將一塊屬於Native環境的內存給.wasm使用,這帶來2個好處。

(1)Native和WebAssembly內存共享

(2)防止內存洩露

(1)內存共享

先來看如何共享字符串。

1、首先,有一塊內存10字節的內存,由Native環境申請,且給WebAssembly使用,並且告訴WebAssembly地址是14~23,WebAssembly會將其映射為0~10。

WebAssembly初探以及在Tengine中的應用

2、WebAssembly將字符串"Hello"寫入0~4

WebAssembly初探以及在Tengine中的應用

3、WebAssembly告訴Native"Hello"的起始地址,當前例子是0。

WebAssembly初探以及在Tengine中的應用

4、Native獲得0,知道其映射在Native環境的地址是14,所有從14開始讀取字符串

乍一聽,反倒覺得這不安全,該特性豈不會讓WebAssembly內存的錯誤操作汙染到Native的環境?

實際上,當執行WebAssembly的VM/Engine嘗試操作內存的時候,都會判斷內存的邊界,當Vm/Engine發現地址越界時會拋出異常:

WebAssembly初探以及在Tengine中的應用

(2)防止內存洩露

這個也很容易理解,對於Native環境,其傳給WebAssembly的內存對於Native而言就是一個pool,當調用玩且釋放WebAssembly時也可以隨即釋放該pool;對於有GC的語言,這個pool在Native環境被創建時就已被GC跟蹤,會自動釋放內存。

0x05 性能

WebAssembly通常被認為是高性能的,我們來看看究竟如何。

WebAssembly VS JS

JS執行流程

WebAssembly初探以及在Tengine中的應用

WebAssembly執行流程(附帶和上圖的對比)

WebAssembly初探以及在Tengine中的應用

總結WebAssembly比JS更快的原因

(1)WebAssembly的變量類型不是JS的動態類型,所以編譯器無需在運行時才編譯。

(3)因為WebAssembly變量是靜態的,編譯器無需生成多份代碼。

(4)LLVM已經在編譯C文件時進行了優化。

其實說到底,核心問題就是JS是動態類型語言。

WebAssembly為什麼快

首先需要了解的是,編譯器通常分為Front End 和 Back End,Front End 用於語法分析,然後生成IR(Intermediate representation),Front End用於生成IR對應的機器碼。下圖是WebAssembly從源文件到可執行機器碼的整個流程。

WebAssembly初探以及在Tengine中的應用

將其分為2部分,前半部分在Server端完成,編譯成wasm二進制。後半部分由VM/Engine完成,將wasm二進制編譯成對應機器的字節碼。

WebAssembly初探以及在Tengine中的應用

所以當一個瀏覽器或者VM/Engine獲得WebAssembly二進制文件時,並非解析格式後直接執行,而是需要使用Back End將其編譯成機器碼。

當有人都在說WebAssembly代碼有Native運行速度時,往往都忽略了使用Back End編譯成機器碼的耗時。

開源項目Wasmer項目使用了3個Back End,通常需要在編譯耗時以及對應生成的機器碼執行效率間進行取捨。

WebAssembly初探以及在Tengine中的應用

另一個針對嵌入式環境的開源庫Intel WAMR,它不包含Back End,直接人肉解析WebAssembly二進制的代碼段中的指令,然後實現這些指令對應的功能,這種運行方式和解釋型語言沒多大區別,或許是因為嵌入式環境資源限制導致的無法加載通常體積較大的Back End。

0x06 WASI

從上面的介紹可以看到,所有的概念和例子的語境都沒有離開瀏覽器,正在將WebAssembly技術帶離瀏覽器奔向更大應用場景的是WASI規範,它定義了一系列底層(特別是和系統資源相關)的操作。

上文提及,WebAssembly是沙盒的,這對於瀏覽器而言很關鍵,但是當它脫離瀏覽器後,作為獨立VM,和Native環境打交道就不可避免。讓這些個接口規範化程度直接決定了其跨平臺性。

先貼一張WASI的終極目標示意圖

WebAssembly初探以及在Tengine中的應用

用大家都熟悉的話總結就是 "Write One,Run Everywhere",同一個編譯目標能在不同平臺、機器上運行。

和Emscripten的區別

上文提到的emcc就是Emscripten項目的一員,從本文開頭的例子中,貌似emcc也能執行open read等操作,那為何還需要定義WASI呢?一個新的規範的出現必定是為了解決當前的某些問題,首先來看下Emscripten的問題。

WebAssembly初探以及在Tengine中的應用

read函數被emcc翻譯成了__syscall3(3, args),即VM/Engine需要實現一個名字叫__syscall3的函數,且函數read的多個參數將被保存在WebAssembly線性空間中,集成在參數 args 中,這被認為type unsafe

WASI將這些POSIX函數重新定義,如下圖所示,無論哪個平臺的VM/Engine,只需要實現和自身平臺相關的__wasi_fd_read函數給WebAssembly用即可,這樣在編寫WebAssembly調用read函數時就無需關心自身將會運行在哪個平臺。

WebAssembly初探以及在Tengine中的應用

WASI例子

這裡使用的不再使用上文例子中的emcc,而是使用高版本Clang,為了避免系統環境無法支持高版本Clang的情況,這裡使用官方推薦的wasi-sdk-6來編譯生成WASI。

下載工具鏈

下載好wasi-sdk-6後解壓,例如我的解壓路徑是./code/wasi-sdk-6.0,可以使用如下命令編譯C源碼

編寫C文件

$cat 1.c 
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
char buf[1024];
int main()
{
int fd = open("1.c", O_RDONLY);
if (fd < 0) {
printf("can't load file 1.c\\n");
return -1;
}
read(fd, buf, sizeof(buf));
printf("Read file:\\n%s",buf);
return 0;
}

編譯

./code/wasi-sdk-6.0/opt/wasi-sdk/bin/clang --target=wasm32-wasi --sysroot=./code/wasi-sdk-6.0/opt/wasi-sdk/share/sysroot 1.c -o 1.wasm

運行WASI

這裡我們使用Wasmer的CLI來運行WASI

wasmer run 1.wasm --mapdir ./:./

如果順利的話,他將打印出當前目錄下1.c文件的內容。

0x07 Tengine+WebAssembly

Tengine作為基於Nginx的Web服務器,開源至今已有8年,在集團內幾乎所有應用前都部署了Tengine作為反向代理,同時Tengine本身作為集團統一接入產品,每天處理著集團大多數入口流量。

Tengine在WebAssembly領域也做了些嘗試,目前使用了Wasmer/Wavm 作為自己底層的runtime(編譯Tengine時選擇具體runtime)

下圖是Tengine使用WebAssembly的框架(藍色是為了支持WebAssembly而新增加的功能)

WebAssembly初探以及在Tengine中的應用

由於語言的限制,Wasmer c-api和Wavm c-api是分別針對兩種不同的VM提供的C的api接口,雖然兩個VM都自帶c-api,但是其功能都無法滿足Tengine需求,所以重新使用C++和Rust編寫了各自的庫對應的c-api。

Tengine C-API 實現了 加載WebAssembly、實例化WebAssembly、調用WebAssembly函數等操作,對於熟悉編寫Nginx C模塊的人來說,可以在任意地方調用這些函數來加載和運行WebAssembly。

同時在WebAssembly代碼裡可以調用諸如ngx_wasm_callhost_get_headers、ngx_wasm_callhost_get_var等函數獲取當前HTTP請求的相關信息來給WebAssembly處理。

Wasm util實際上是 類似 一些 Lua的指令,這裡Tengine暫時實現了類似content_by_lua_file的content_by_wasm_file指令用於調試功能。

體驗

雖王婆賣瓜,但童叟無欺。這裡提供了一個HTTP接口(運氣好的話當你看到這篇文章的時候這個接口還在),你可以POST一個WebAssembly文件上來,Tengine幫你運行且將結果作為HTTP response body反吐給你!

(手下留情別傳太大的,日常機器資源有限)

準備C源碼

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <malloc.h>
#include <time.h>
#ifdef __EMSCRIPTEN__
#define __IMPORT(name)
#else
#define __IMPORT(name) __attribute__((__import_module__("env"), __import_name__(#name)))
#endif
int ngx_wasm_callhost_say(char *str, int len) __IMPORT(_ngx_wasm_callhost_say);
int main(void) {
int max, len;
char time[65], *p;
struct timespec tp;
max = 100 + sizeof(time);
p = malloc(max);
if (!p) {
ngx_wasm_callhost_say("malloc fail", sizeof("malloc fail") - 1);
return 0;
}
clock_gettime(CLOCK_REALTIME, &tp);
len = snprintf(p ,max, "in host time %ld", tp.tv_sec);
ngx_wasm_callhost_say(p, len);

free(p);
return 0;
}

編譯

emcc 1.c -o 1.wasm -s ERROR_ON_UNDEFINED_SYMBOLS=0

或者

./code/wasi-sdk-6.0/opt/wasi-sdk/bin/clang --target=wasm32-wasi --sysroot=./code/wasi-sdk-6.0/opt/wasi-sdk/share/sysroot 1.c -o 1.wasm -Wl,--allow-undefined

發送至Tengine

curl http://11.164.24.251:8088/runwasm -H "Transfer-Encoding: chunked" --data-binary "@./1.wasm"

正常情況下返回的內容是WebAssembly代碼中ngx_wasm_callhost_say傳入的內容。

這是我自己測試的結果

[[email protected] /home/shangxu.cjy/code/wasmtengine/alibaba-tengine]
$curl http://11.164.24.251:8088/runwasm -H "Transfer-Encoding: chunked" --data-binary "@./1.wasm"
in host time 1565876453

展望

社區

WebAssembly技術還處於初中期階段,特別是脫離於瀏覽器環境後作為獨立VM/Engine,相關的定義和規範缺失,各開源實現都未能跟上。

在Tengine嘗試加載這兩個WebAssembly VM時,碰到了各種VM自身的問題,包括 當 WebAssembly異常(空指針等),整個VM也就crash了,同時 也出現過更新emcc編譯器後,編譯出來的wasm文件無法被VM運行的情況。 期望 WebAssembly 儘早被完善。

Tengine + 多語言

WebAssembly 是二進制的格式的規範,理論上只要能被編譯成LLVM IR的語言都能被轉換成WebAssembly ,這意味著理論上,Tengine可以使用WebAssembly 作為多語言的容器,無論哪種語言都能作為Tengine模塊開發且運行速度接近Native。或許在不久得將來,Tengine能夠作為底層的網絡容器發揮其特有的異步優勢,而上層業務代碼可以使用Go/Rust/C/C++甚至是JAVA,發揮不同語言的特性。

Tengine + 安全

WebAssembly 是沙盒的,這意味著如果WebAssembly 文件內容出現異常不會連累宿主環境(Native),特別適合運行一些危險的邏輯。

Reference

所有參考資料都以超鏈接方式展示在原文中。

作者:shangxu.cjy

本文為雲棲社區內容,未經允許不得轉載。

"

相關推薦

推薦中...