
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-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 can read and write source maps (see the -ism and -osm flags to wasm-opt ). It can also read and read source map annotations in the text format, that is,
;; @ src.cpp:100:33
( i32.const 42 ) That 42 constant is annotated as appearing in a file called src.cpp at line 100 and column 33 . Source maps and text format annotations are interchangeable, that is, they both lead to the same IR representation, so you can start with an annotated wat and have Binaryen write that to a binary + a source map file, or read a binary + source map file and print text which will contain those annotations.
The IR representation of source map info is simple: in each function we have a map of expressions to their locations. Optimization passes should update the map as relevant. Often this "just works" because the optimizer tries to reuse nodes when possible, so they keep the same debug info.
The text format annotations support a shorthand in which repeated annotations are not necessary. For example, children are tagged with the debug info of the parent, if they have no annotation of their own:
;; @ 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 )
)The first const will have debug info identical to the parent, because it has none specified, and generally such nesting indicates a "bundle" of instructions that all implement the same source code.
Note that text printing will not emit such repeated annotations, which can be confusing. To print out all the annotations, set BINARYEN_PRINT_FULL=1 in the environment. That will print this for the above add :
[i32] ;; @ src.cpp:100:33
( i32.add
[i32] ;; @ src.cpp:100:33
( i32.const 41 )
[i32] ;; @ src.cpp:111:44
( i32.const 1 )
) (full print mode also adds a [type] for each expression, right before the debug location).
The debug information is also propagated from an expression to its next sibling:
;; @ 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 )
) You can prevent the propagation of debug info by explicitly mentioning that an expression has not debug info using the annotation ;;@ with nothing else:
;; @ 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 )
) This stops the propagatation to children and siblings as well. So, expression (i32.const 7) does not have any debug info either.
There is no shorthand in the binary format. That is, roundtripping (writing and reading) through a binary + source map should not change which expressions have debug info on them or the contents of that info.
The source maps format defines a mapping using segments , that is, if a segment starts at binary offset 10 then it applies to all instructions at that offset and until another segment begins (or the end of the input is reached). Binaryen's IR represents a mapping from expressions to locations, as mentioned, so we need to map to and from the segment-based format when writing and reading source maps.
That is mostly straightforward, but one thing we need to do is to handle the lack of debug info in between things that have it. If we have ABC where B lacks debug info, then just emitting a segment for A and C would lead A 's segment to also cover B , since in source maps segments do not have a size - rather they end when a new segment begins. To avoid B getting smeared in this manner, we emit a source maps entry to B of size 1, which just marks the binary offset it has, and without the later 3 fields of the source file, line number, and column. (This appears to be the intent of the source maps spec, and works in browsers and tools.)
Binaryen also has optional support for DWARF. This primarily just tracks the locations of expressions and rewrites the DWARF's locations accordingly; it does not handle things like re-indexing of locals, and so passes that might break DWARF are disabled by default. As a result, this mode is not suitable for a fully optimized release build, but it can be useful for local debugging.
Binaryen's name was inspired by Emscripten 's: Emscripten's name suggests it converts something into a script - specifically JavaScript - and Binaryen's suggests it converts something into a binary - specifically WebAssembly . Binaryen began as Emscripten's WebAssembly generation and optimization tool, so the name fit as it moved Emscripten from something that emitted the text-based format JavaScript (as it did from its early days) to the binary format WebAssembly (which it has done since WebAssembly launched).
"Binaryen" is pronounced in the same manner as "Targaryen".
是的,确实如此。 Here's a step-by-step tutorial on how to compile it under Windows 10 x64 with with CMake and Visual Studio 2015 . However, Visual Studio 2017 may now be required. Help would be appreciated on Windows and OS X as most of the core devs are on Linux.