
Binaryen是用C ++編寫的WebAssembly的編譯器和工具鏈基礎架構庫。它的目的是使websembly變得容易,快速和有效:
Easy :二進制中的二進制標頭中具有簡單的C API,也可以從JavaScript中使用。它接受類似WebAssembly形式的輸入,但也接受了更喜歡的編譯器的一般控制流程圖。
快速:Binaryen的內部紅外線使用緊湊的數據結構,並使用所有可用的CPU內核設計用於完全並行的代碼和優化。 Binaryen的IR還非常容易,很快地將其編譯為WebSembly,因為它本質上是WebAssembly的子集。
有效:Binaryen的優化器具有許多通行證(稍後請參見概述),可以提高代碼大小和速度。這些優化旨在使二進制功能強大,以便將其用作編譯器後端。一個特定的重點是特定於WebAssembly的優化(通用編譯器可能不會做的),您可以將其視為WASM縮小,類似於JavaScript,CSS等的Minification,所有這些都是語言特定於語言的。
使用二進製作為組件(通常運行的wasm-opt )的工具鏈包括:
Emscripten (C/C ++)wasm-pack (生鏽)J2CL (Java; J2Wasm )Kotlin (Kotlin/Wasm)Dart (顫音)wasm_of_ocaml (OCAML)有關其中一些工作方式的更多信息,請參閱V8 WASMGC移植Blogpost的工具鏈體系結構部分。
使用二進製作為庫的編譯器包括:
AssemblyScript將打字稿變體到WebAssembly的彙編wasm2js將WebAssembly編譯到JSAsterius將Haskell編譯為WebAssemblyGrain二進制還提供了一組工具鏈實用程序
如果您有興趣參加,請諮詢貢獻說明。
Binaryen的內部IR被設計為
二進制IR和WebAssembly語言之間存在一些差異:
catch塊中支持)表示為pop子表達。--generate-stack-ir --print-stack-ir (打印堆棧ir),保證這對WASM Parsers有效。ref.func的地址的函數必須在表中或通過(elem declare func $..)聲明。 Binaryen會在必要時發出該數據,但在IR中並不表示該數據。也就是說,可以在無需考慮聲明功能參考的情況下進行IR。local.get必須在結構上由local.set統治。儘管與WASM規範保持一致,但您可能會注意到一些較小的細節:Block不會干擾驗證。無名塊永遠不會散發到二進制格式中(我們只是發出了它們的內容),因此我們忽略了它們,目的是出於不可阻斷的當地人的目的。結果,如果您閱讀了二進製文件發出的WASM文本,那麼您可能會看到似乎不應根據規範驗證的代碼(並且可能無法在WASM文本解析器中驗證),但是這種差異將不存在二進制格式(Binaryen發出的二進製文件在任何地方都可以隨時使用,但對於目的的錯誤,它將始終使用)。pass.h和LocalStructuralDominance類中的requiresNonNullableLocalFixups()掛鉤。ref.func的IR類型始終是特定的功能類型,而不是普通的funcref 。它也是不可破壞的。try_table在分支上發送的類型(如果我們分支,永遠不會發送null),也就是說,它發送(ref exn)而不是(ref null exn)。在這兩種情況下,如果未啟用GC,我們都會在二進制中排放較少的類型。閱讀二進製文件時,將在我們構建IR時應用更精緻的類型。br_if輸出類型在二進制IR中更精緻:當值流入時,它們具有值的類型。在WASM規格中,類型是分支目標的類型,可能不太精煉。在此處使用更精緻的類型確保我們使用所有類型信息以最佳方式優化,但這確實意味著某些圓形操作可能看起來有些不同。特別是,當我們發出一個br_if時,其類型在二進制IR中更精緻,然後在其後立即發射鑄件,以便輸出在WASM規格中具有正確的類型。在極少數情況下,這可能會導致一些額外大小的字節(在br_if值未使用的常見情況下,我們避免了此開銷)。ref.cast鑄造字符串視圖( stringview_wtf16等)。這簡化了紅外線,因為它允許ref.cast始終在所有位置使用(並且在優化器中可能會降低參考為ref.as_non_null )。 StringRef Spec似乎不允許這樣做,並且要解決二進制編寫者將替換將字符串視圖施放為不可加藏的類型的ref.as_non_null ref.cast完全跳過的no-op的字符串視圖的ref.cast 。結果,您可能會注意到,在某些角落情況下,往返轉換(WASM => binaryen ir => wasm)會稍微更改代碼。
src/wasm-stack.h )。堆棧IR允許針對WebAssembly的二進制二進制格式量身定制的一堆優化(但是,堆棧IR比主要二元IR效率較低)。如果您有一個特別優化的WASM文件,則簡單的往返轉換(只需讀寫,而無需優化)可能會引起更明顯的差異,因為二進制將其擬合到Binaryen ir更結構化的格式中。如果您在往返轉換期間還進行了優化,則將運行堆棧IR選擇,並且最終的WASM將得到更好的優化。與二元IR合作時的注意:
二進制固有函數看起來像是對導入的調用,例如,
( import " binaryen-intrinsics " " foo " ( func $foo ))以這種方式實施它們,可以通過其他工具讀取和編寫它們,並且避免瞭如果我們具有自定義的二進制格式擴展名,可能會在這些工具中發生的二進制格式錯誤混淆。
優化器可以優化一種固有的方法。如果不是這樣,則必須在運送WASM之前降低它,否則,它看起來像是對不存在的導入的調用(VMS將在沒有適當值的導入值時顯示出錯誤)。最終降低不是自動完成的。 Intersics的用戶必須明確地為此進行通行,因為這些工具不知道用戶何時打算完成優化,因為用戶可能具有多個優化步驟的管道,或者可能正在進行本地實驗,或者進行本地實驗,或者進行模糊/減少等等。只有用戶知道最終優化何時在Wastm是“最終”之前進行“最終”和“最終”進行。請注意,通常,最終降低後可能會進行一些其他優化,因此有用的模式是正常使用內在物質優化一次,然後將它們降低,然後優化之後,例如:
wasm-opt input.wasm -o output.wasm -O --intrinsic-lowering -O每個內在的語義都定義了其語義,其中包括允許優化器對其進行的操作以及最終降低將變為什麼。有關詳細的定義,請參見Intrinsics.h。快速摘要在這裡顯示:
call.without.effects :類似於call_ref ,它接收參數,以及對呼叫的函數的引用,並使用這些參數函數,除了優化器可以假定呼叫沒有副作用,並且可能能夠將其優化為(如果沒有使用結果),通常通常使用)。 該存儲庫包含在bin/中構建以下工具的代碼(請參閱“構建說明”):
wasm-opt :加載WebAssembly並在其上運行Binaryen IR。wasm-as :以文本格式(當前S-表達格式)組裝WebAssembly為二進制格式(通過二進制IR)。wasm-dis :以二進制格式為文本格式的未組裝WebAssembly(通過二進制IR)。wasm2js :WebAssembly-to-JS編譯器。 Emscripten用來生成JavaScript作為WebAssembly的替代方法。wasm-reduce :用於WebAssembly文件的測試櫃還原器。給定一個出於某種原因很有趣的WASM文件(例如,它崩潰了特定的VM),Wasm-reduce可以找到具有相同屬性的較小的WASM文件,通常更容易調試。有關更多詳細信息,請參見文檔。wasm-shell :可以加載和解釋WebAssembly代碼的外殼。它還可以運行規格測試套件。wasm-emscripten-finalize :採用LLVM+LLD產生的WASM二進制,並對它進行特定於Emscripten的通行證。wasm-ctor-eval :可以在編譯時執行功能(或功能部分)的工具。wasm-merge :將多個WASM文件合併到一個文件中,將相應的導入連接到出口。就像bundler的JS一樣,但為WASM。wasm-metadce :一種以靈活的方式刪除WASM文件部分的工具,取決於模塊的使用方式。binaryen.js :獨立的JavaScript庫,它揭示了用於創建和優化WASM模塊的二進制方法。有關構建,請參見NPM上的binaryen.js(或直接從Github或Unpkg下載)。最小要求:Node.js V15.8或Chrome V75或Firefox V78。所有二元工具都是確定性的,也就是說,給定相同的輸入,您應該始終獲得相同的輸出。 (如果您看到其他行為的案例,請提交問題。)
每個使用說明在下面。
Binaryen包含大量優化通行證,以使WebAssembly更小,更快。您可以使用wasm-opt運行二元優化器,但也可以在使用其他工具(例如wasm2js和wasm-metadce時運行它們。
addDefaultFunctionOptimizationPasses等功能設置。wasm-opt --help 。有關其所做的詳細信息,請參閱每個優化通過,但這是一些相關的概述:
if武器在其末尾有一些共享指令,則避免代碼。block ,減少其數量。local.set存在的值。 (與塞膠合的重疊;這實現了僅提及的特定操作,而沒有所有其他工作cocelocals的作用,因此在優化管道的其他地方很有用。)br或br_table各種變換(例如, if可能的話,將一個帶有br的block轉動到中間的塊)。local.get/set/tee ”優化通過,執行諸如更換集合的事情以及將設置的值移至get(並創建T卹)的事情。還創建block/if/loop返回值,而不是使用本地來傳遞該值。if手臂,一滴恆定值,沒有副作用,一個帶單個孩子的block ,等等。上面的“ LTO”意味著優化是鏈接時間優化,因為它跨多個函數起作用,但是從某種意義上說,二進制始終是“ LTO”,因為它通常在最終的鏈接WASM上運行。
二進制優化器中的高級優化技術包括SSAIFIENT,FLAT IR和堆棧/罌粟IR。
有關如何有效使用優化器的更多信息,請參見“優化器食譜Wiki”頁面。
Binaryen還包含除優化以外的其他事情的各種通行證,例如JavaScript的合法化,異步等。
Binaryen使用git subpoules(僅針對GTEST編寫時),因此在構建之前,您必須初始化subsodules:
git submodule init
git submodule update之後,您可以使用Cmake構建:
cmake . && make需要C ++ 17編譯器。在MacOS上,您需要通過brew install cmake cmake請注意,您還可以將ninja用作生成器: cmake -G Ninja . && ninja 。
為了避免GTEST依賴性,您可以將-DBUILD_TESTS=OFF傳遞給cmake。
可以使用emscripten構建binaryen.js,可以通過SDK安裝。
emcmake cmake . && emmake make binaryen_jsemcmake cmake -DBUILD_FOR_BROWSER=ON . && emmake make使用Microsoft Visual Studio安裝程序,安裝“用於CMAKE的Visual C ++工具”組件。
生成項目:
mkdir build
cd build
" %VISUAL_STUDIO_ROOT%Common7IDECommonExtensionsMicrosoftCMakeCMakebincmake.exe " ..用Visual_studio_root替換了通往Visual Studio安裝的路徑。如果您使用的是Visual Studio構建工具,則該路徑將為“ C: Program Files(X86) Microsoft Visual Studio 2017 buildTools”。
從開發人員命令提示符中,構建所需的項目:
msbuild binaryen.vcxprojCmake生成了一個名為“ All_build.vcxproj”的項目,以方便地構建所有項目。
構建由使用二進制的各種工具鏈(如emscripten, wasm-pack等)分發。
https://github.com/webassembly/binaryen/releases
目前包括以下平台的構建:
Linux-x86_64Linux-arm64MacOS-x86_64MacOS-arm64Windows-x86_64Node.js (實驗): wasm-opt端口到JavaScript+WebAssembly。運行node wasm-opt.js作為在Node.js運行的任何平台上的本wasm-opt建的置換替換。需要Node.js 18+(對於WASM EH和WASM線程)。 (請注意,此構建也可以在DENO,BUN或其他JavaScript+WebAssembly環境中運行,但僅在Node.js上進行測試) 跑步
bin/wasm-opt [.wasm or .wat file] [options] [passes, see --help] [--help]WASM Optimizer接收WebAssembly作為輸入,並且可以在其上運行轉換並打印(在轉換之前和/或轉換之後)。例如,嘗試
bin/wasm-opt test/lit/passes/name-types.wast -all -S -o -這將在測試套件中輸出一個測試用例。要運行轉換通行證,請嘗試
bin/wasm-opt test/lit/passes/name-types.wast --name-types -all -S -o - name-types通行證可確保每種類型都有一個名稱,並且重命名了異常長的類型名稱。您可以通過比較兩個命令的輸出來查看變換原因。
將自己的轉換通行證添加到外殼上很容易,只需將.cpp文件添加到src/passes中,然後重建外殼即可。示例代碼,查看name-types通過。
還有更多註釋:
bin/wasm-opt --help 。--debug將發出一些調試信息。可以通過將它們作為逗號分隔字符串列表傳遞給單個調試通道(通過#define DEBUG_TYPE xxx )。例如: bin/wasm-opt --debug=binary 。這些調試通道也可以通過BINARYEN_DEBUG環境變量啟用。跑步
bin/wasm2js [input.wasm file]這將在控制台上打印出JavaScript。
例如,嘗試
bin/wasm2js test/hello_world.wat該輸出包含
function add ( x , y ) {
x = x | 0 ;
y = y | 0 ;
return x + y | 0 | 0 ;
}作為翻譯
( func $add (; 0 ;) ( type $0 ) ( param $x i32 ) ( param $y i32 ) ( result i32 )
( i32.add
( local.get $x )
( local.get $y )
)
)WASM2JS的輸出為ES6模塊格式 - 基本上,它將WASM模塊轉換為ES6模塊(在較舊的瀏覽器和Node.js版本上運行您可以使用Babel等將其轉換為ES5)。讓我們看一個稱呼“ Hello World Wat”的完整示例;首先,創建主JS文件:
// main.mjs
import { add } from "./hello_world.mjs" ;
console . log ( 'the sum of 1 and 2 is:' , add ( 1 , 2 ) ) ;運行此操作(請注意,您需要一個帶有ES6模塊支持的足夠新的Node.js):
$ bin/wasm2js test/hello_world.wat -o hello_world.mjs
$ node --experimental-modules main.mjs
the sum of 1 and 2 is: 3WASM2JS的輸出始終牢記:
-O或其他優化級別運行具有優化版本的WASM2J。這將沿整個管道(WASM和JS)進行優化。不過,它不會像Minify Whitepsace那樣做JS Minifer所能完成的一切,因此您之後仍應運行普通的JS minifer。 wasm-ctor-eval在編譯時執行功能或部分功能。這樣做之後,它將運行時狀態序列到WASM中,就像採用“快照”一樣。當WASM後來加載並以VM運行時,它將從那時開始執行,而無需重新完成已經執行的工作。
例如,考慮這個小程序:
( module
;; A global variable that begins at 0.
( global $global ( mut i32 ) ( i32.const 0 ))
( import " import " " import " ( func $import ))
( func " main "
;; Set the global to 1.
( global.set $global
( i32.const 1 ))
;; Call the imported function. This *cannot* be executed at
;; compile time.
( call $import )
;; We will never get to this point, since we stop at the
;; import.
( global.set $global
( i32.const 2 ))
)
)我們可以在這樣的編譯時評估其中的一部分:
wasm-ctor-eval input.wat --ctors=main -S -o -這告訴它,我們要執行一個單個函數(“ ctor”是“全局構造函數”的縮寫,“ global構造函數”是來自在程序的輸入點之前執行的代碼的名稱),然後將其作為文本打印到stdout 。結果是:
trying to eval main
...partial evalling successful, but stopping since could not eval: call import: import.import
...stopping
(module
(type $none_ = > _none (func))
(import " import " " import " (func $import ))
(global $global (mut i32) (i32.const 1))
(export " main " (func $0 _0))
(func $0 _0
(call $import )
(global.set $global
(i32.const 2)
)
)
)登錄表明我們設法評估了main()的一部分,但並非全部,但正如預期的那樣:我們可以評估第一個global.get 。請注意,在輸出WASM中,全局的值已從0更新到1,並且第一個global.get已刪除:WASM現在處於一種狀態,即當我們以VM運行時,將從wasm-ctor-eval停止的地點繼續無縫地運行。
在這個小例子中,我們剛剛保存了少量工作。可以節省多少工作取決於您的程序。 (它可以幫助您進行純計算,並將導入的呼叫盡可能遲到。)
請注意,如前所述, wasm-ctor-eval的名稱與全局構造函數有關,但是您可以在此處執行什麼都沒有限制。如果其內容合適,則可以執行WASM的任何導出。例如,在Emscripten中, wasm-ctor-eval甚至在可能的情況下都在main()上運行。
wasm-merge將WASM文件結合在一起。例如,想像一下您有一個項目,該項目使用來自多個工具鏈的WASM文件。然後,將它們全部合併到運輸前的單個WASM文件中可能會有所幫助,因為在單個WASM中,模塊之間的呼叫成為模塊中的正常調用,這使它們可以夾住,消除了死亡代碼,等等,依此類推,可能會提高速度和尺寸。
wasm-merge在普通的WASM文件上運行。與wasm-ld在WASM對象文件上運行一樣,它與WASM wasm-ld LD不同。 wasm-merge可以在多工鏈情況下有助於,其中至少一個工具鏈不使用WASM對象文件。
例如,想像一下我們有這兩個WASM文件:
;; a.wasm
( module
( import " second " " bar " ( func $second.bar ))
( export " main " ( func $func ))
( func $func
( call $second.bar )
)
) ;; b.wasm
( module
( import " outside " " log " ( func $log ( param i32 )))
( export " bar " ( func $func ))
( func $func
( call $log
( i32.const 42 )
)
)
)您本地驅動器上的文件名是a.wasm和b.wasm ,但為了合併 /捆綁目的,可以說第一個被稱為"first" ,第二個稱為"second" 。也就是說,我們希望第一個模塊的"second.bar"導入在第二個模塊中調用函數$func 。這是wasm-merge命令:
wasm-merge a.wasm first b.wasm second -o output.wasm我們將其提供給第一個WASM文件,然後是其名稱,然後將其命名為第二個WASM文件,然後是其名稱。合併的輸出是:
( module
( import " outside " " log " ( func $log ( param i32 )))
( export " main " ( func $func ))
( export " bar " ( func $func_2 ))
( func $func
( call $func_2 )
)
( func $func_2
( call $log
( i32.const 42 )
)
)
) wasm-merge將兩個文件組合到一個文件中,合併了它們的功能,導入等,同時修復了名稱衝突並將相應的導入連接到導出。特別是,請注意$func如何調用$func_2 ,這正是我們想要的: $func_2是第二個模塊的功能(重命名以避免名稱碰撞)。
請注意,此示例中的WASM輸出可能受益於其他優化。首先,對$func_2呼叫現在可以輕鬆地夾住,因此我們可以運行wasm-opt -O3為我們做到這一點。另外,我們可能不需要所有可以運行WASM-METADCE的進出口。一個良好的工作流程可能是運行wasm-merge ,然後是wasm-metadce ,然後使用wasm-opt結束。
從“ JS Bundler”的意義上講, wasm-merge有點像WASM文件的捆綁器。也就是說,在上面的WASM文件中,想像我們有此JS代碼可以在運行時實例化並將其連接到:
// Compile the first module.
var first = await fetch ( "a.wasm" ) ;
first = new WebAssembly . Module ( first ) ;
// Compile the first module.
var second = await fetch ( "b.wasm" ) ;
second = new WebAssembly . Module ( second ) ;
// Instantiate the second, with a JS import.
second = new WebAssembly . Instance ( second , {
outside : {
log : ( value ) => {
console . log ( 'value:' , value ) ;
}
}
} ) ;
// Instantiate the first, importing from the second.
first = new WebAssembly . Instance ( first , {
second : second . exports
} ) ;
// Call the main function.
first . exports . main ( ) ; wasm-merge作用基本上是JS所做的:它可以將導入到導出,使用您提供的模塊名稱解決名稱。也就是說,通過運行wasm-merge我們正在將連接模塊連接的工作從運行時到編譯時間。結果,在運行wasm-merge後,我們需要少得多的Js才能獲得相同的結果:
// Compile the single module.
var merged = await fetch ( "merged.wasm" ) ;
merged = new WebAssembly . Module ( merged ) ;
// Instantiate it with a JS import.
merged = new WebAssembly . Instance ( merged , {
outside : {
log : ( value ) => {
console . log ( 'value:' , value ) ;
}
}
} ) ;
// Call the main function.
merged . exports . main ( ) ;我們仍然需要獲取和編譯合併的WASM,並提供JS導入,但是不再需要連接兩個WASM模塊的工作。
默認情況下,如果存在重疊的導出名稱, wasm-merge錯誤。也就是說, wasm-merge將自動處理重疊函數名稱,依此類推,因為這些功能名稱不可見(代碼仍然行為相同),但是如果我們重命名的導出,則需要修改外部以期望新的導出名稱,因此我們在此名稱衝突上誤以為是錯誤的。
如果您確實希望出口重命名,請與--rename-export-conflicts一起運行wasm-merge 。後來的出口將附加給他們的後綴,以確保它們不會與以前的出口重疊。後綴是確定性的,因此,一旦看到它們是什麼,您可以從外面稱呼它們。
另一個選擇是使用--skip-export-conflicts它將簡單地跳過以後的名稱相互矛盾的出口。例如,在第一個模塊是唯一與外部交互的模塊和後來的模塊僅與第一個模塊交互的情況下,這可能很有用。
wasm-merge使用多內存和多桌功能。也就是說,如果多個輸入模塊每個都有一個內存,則輸出WASM將具有多個內存,並且取決於多記憶功能,這意味著較舊的WASM VMS可能無法運行WASM。 (作為如此舊的VM的解決方法,您可以運行wasm-opt --multi-memory-lowering -Multi-Multi降低了一個記憶。)
./check.py (或python check.py )將在test/測試容器上運行wasm-shell , wasm-opt等,並驗證其輸出。
check.py腳本支持一些選項:
./check.py [--interpreter = /path/to/interpreter] [TEST1] [TEST2].../check.py --list-suites 。emcc或nodejs 。如果找不到該工具,它們將不會運行,您會看到警告。tests/spec上游的測試。運行./check.py應該更新這些。請注意,我們正在嘗試在修改它們時逐漸將舊版WASM-OPT測試移植以使用lit和filecheck 。對於輸出浪費的passes測試,可以使用scripts/port_passes_tests_to_lit.py自動完成此操作,對於輸出浪費的非passes測試,請參見#4779,以獲取如何進行簡單的手動端口。
對於LIT測試,隨著對二進制的更改,通常可以自動更新測試期望(檢查線)。請參閱scripts/update_lit_checks.py 。
在大多數情況下,也可以自動更新非光線測試。請參閱scripts/auto_update_tests.py 。
./third_party/setup.py [mozjs | v8 | wabt | all] (或python third_party/setup.py )安裝所需的依賴項,例如spidermonkey js shell,v8 js shell和wabt in third_party/ 。安裝時其他腳本會自動拾取它們。
運行pip3 install -r requirements-dev.txt以獲取lit測試的要求。請注意,您需要在$PATH (在Linux, ~/.local/bin上)安裝位置pip安裝。
./scripts/fuzz_opt.py [--binaryen-bin = build/bin] (或python scripts/fuzz_opt.py )將在隨機傳遞的隨機輸入上運行各種模糊模式,直到找到可能的錯誤為止。有關所有詳細信息,請參見Wiki頁面。
Binaryen可以讀取和寫入源地圖(請參閱wasm-opt -ism和-osm標誌)。它還可以以文本格式讀取和讀取源地圖註釋,也就是說
;; @ src.cpp:100:33
( i32.const 42 )該42常數被註釋為出現在100行和第33列的名為src.cpp的文件中。源地圖和文本格式註釋是可以互換的,也就是說,它們都導致相同的IR表示形式,因此您可以從註釋的WAT開始,並讓Binaryen將其寫入二進制 +源地圖文件,或者讀取包含這些註釋的二進制 +源地圖文件和打印文本。
源地圖信息的IR表示很簡單:在每個功能中,我們都有表達式的地點圖。優化通過應將地圖更新為相關。通常,這種“僅作用”是因為優化器會在可能的情況下嘗試重複使用節點,因此它們保留相同的調試信息。
文本格式註釋支持速記,其中無需重複註釋。例如,如果孩子沒有自己的註釋,則將孩子的調試信息標記為:
;; @ src.cpp:100:33
( i32.add
( i32.const 41 ) ;; This receives an annotation of src.cpp:100:33
;; @ src.cpp:111:44
( i32.const 1 )
)第一個const將具有與父級相同的調試信息,因為它沒有指定,並且通常嵌套表示所有實現相同源代碼的指令的“捆綁”。
請注意,文本打印不會發出這種重複的註釋,這可能會令人困惑。要打印所有註釋,請在環境中設置BINARYEN_PRINT_FULL=1 。這將為上述add打印:
[i32] ;; @ src.cpp:100:33
( i32.add
[i32] ;; @ src.cpp:100:33
( i32.const 41 )
[i32] ;; @ src.cpp:111:44
( i32.const 1 )
) (在調試位置之前,完整的打印模式還為每個表達式添加了一個[type] )。
調試信息也從表達式傳播到其下一個同胞:
;; @ src.cpp:100:33
( local.set $x
( i32.const 0 )
)
( local.set $y ;; This receives an annotation of src.cpp:100:33
( i32.const 0 )
)您可以通過明確提到表達式沒有使用註釋來驗證信息來防止調試信息的傳播;;@ nothens nothens:@
;; @ src.cpp:100:33
( local.set $x
;; @
( i32.const 0 ) ;; This does not receive any annotation
)
;; @
( local.set $y ;; This does not receive any annotation
( i32.const 7 )
)這也阻止了兒童和兄弟姐妹的傳播。因此,表達式(i32.const 7)也沒有任何調試信息。
二進制格式沒有速記。也就是說,通過二進制 +源地圖往返(寫作和閱讀)不應更改哪些表達式在它們或該信息的內容上具有調試信息。
源地圖格式使用片段定義了映射,也就是說,如果一個段開始在二進制偏移10處開始,則適用於該偏移量的所有指令,直到另一個段開始(或到達輸入的末端)。如上所述,Binaryen的IR表示從表達式到位置的映射,因此我們需要在編寫和讀取源地圖時映射基於細分的格式。
這主要是直接的,但是我們需要做的一件事是處理擁有的事物之間缺乏調試信息。如果我們擁有B缺乏調試信息的ABC ,那麼僅散發A和C的一個段就會導致A段也覆蓋B ,因為在源地圖中,在源地圖段中沒有大小 - 而是在新的段開始時結束。為了避免以這種方式塗抹B ,我們將源地圖輸入到尺寸1的B上,這僅標記其具有的二進制偏移,沒有源文件,行號和列的後面3個字段。 (這似乎是源地圖規範的目的,並且在瀏覽器和工具中起作用。)
Binaryen還為矮人提供了可選的支持。這主要僅跟踪表達式的位置,並相應地重寫矮人的位置。它無法處理當地人重新索引之類的事情,因此默認情況下可能會破壞矮人的通行證。結果,此模式不適合完全優化的發布構建,但對於本地調試可能很有用。
Binaryen的名稱的靈感來自Emscripten :Emscripten的名稱,這表明它將某些內容轉換為腳本- 特別是JavaScript- ,Binaryen建議它將某些內容轉換為二進製文件- 特別是WebAssembly 。 Binaryen始於Emscripten的WebAssembly生成和優化工具,因此該名稱從發射基於文本的格式JavaScript(從早期開始)轉移到二進制格式WebAssembly(自WebAssemply啟動以來就完成了)的名稱。
“二進制”以與“ targaryen”相同的方式發音。
是的,確實如此。這是一個分步教程,講述瞭如何在Windows 10 x64下與CMAKE和Visual Studio 2015編譯。但是,現在可能需要Visual Studio 2017。在Windows和OS X上的幫助將不勝感激,因為大多數Core Dev都在Linux上。