61

我已阅读问题如何使用 asm.js 进行测试和开发?,并且接受的答案提供了指向http://kripken.github.com/mloc_emscripten_talk/#/的链接。

该幻灯片的结论是“静态类型的语言,尤其是 C/C++ 可以有效地编译为 JavaScript ”,因此我们可以“期望编译的 C/C++ 的速度仅比本地代码慢 2 倍,或者更好,今年晚些时候”。

但是非静态类型的语言,比如常规的 JavaScript 本身呢?可以编译成asm.js吗?

4

7 回答 7

34

JavaScript 本身可以编译成 asm.js 吗?

不是真的,因为它的动态特性。这与尝试将其编译为 C甚至本机代码时的问题相同——您实际上需要随它一起发布一个 VM 以处理这些非静态方面。至少,这样的虚拟机是可能的:

js.js是 JavaScript 中的 JavaScript 解释器。SpiderMonkey没有尝试从头开始创建解释器,而是将其编译为LLVM,然后emscripten将输出转换为 JavaScript。

但是如果 asmjs 代码比普通 JS 运行得更快,那么将 JS 编译为 asmjs 是有意义的,不是吗?

不, asm.js是一个非常受限的 JS 子集,可以很容易地转换为字节码。然而,您首先需要将 JS 的所有高级功能分解为该子集才能获得此优势 - imo 是一项相当复杂的任务。但是 JavaScript 引擎经过设计和优化,可以将所有这些高级功能直接转换为字节码——那么为什么还要费心像 asm.js 这样的中间步骤呢?Js.js 声称比“原生”JS 慢 200 倍左右。

那么一般的非静态类型语言呢?

幻灯片讨论了……只是 C/C++?向前。具体来说:

动态语言

可以编译整个 C/C++ 运行时并以适当的语义解释原始语言,但这不是轻量级的

从这些语言到 JavaScript 的源到源编译器会忽略语义差异(例如,数字类型)

实际上,这些语言依赖于特殊的虚拟机来提高效率

他们的源到源编译器失去了在这些 VM 中所做的优化

于 2013-03-26T08:31:43.603 回答
12

回答一般问题“有可能吗?” 那么答案是肯定的,JavaScript 和 asm.js 子集都是图灵完备的,因此存在翻译。

是否应该这样做并期望性能收益是另一个问题。简短的回答是“不,你不应该”。我把这比作试图压缩一个压缩文件;是的,可以运行压缩算法,但通常您不应期望生成的文件更小。

简短的回答:动态类型语言的性能成本来自代码的含义;具有相同含义的静态类型程序将承担相同的成本。

要理解这一点,重要的是要理解为什么asm.js 提供了性能优势。或者,更一般地说,为什么静态类型的语言比动态类型的语言表现更好。简短的回答是“运行时类型检查需要时间”,更长的回答将包括优化静态类型代码的改进可行性。例如:

function a(x) { return x + 1; }
function b(x) { return x - 1; }
function c(x, y) { return a(x) + b(y); }

如果xy都已知是整数,我可以将函数优化c为几个机器代码指令。如果它们可以是整数或字符串,优化问题就会变得更加困难;在某些情况下,我必须将它们视为字符串附加,而在其他情况下则将其视为附加。特别是,发生在 中的加法运算有四种可能的解释c;它可以是加法,或字符串追加,或强制到字符串和追加的两种不同变体。随着您添加更多可能的类型,可能的排列数量会增加;在最坏的情况下,对于动态类型语言,您有k^n 个可能的表达式解释,其中涉及n 个项,每个项可能有任意数量的k类型。在静态类型语言中,k=1,因此任何给定表达式总是有 1 种解释。正因为如此,优化器在优化静态类型代码方面从根本上比动态类型代码更有效:在寻找优化机会时需要考虑的排列更少。

这里的重点是,当从动态类型代码转换为静态类型代码时(就像从 JavaScript 转换为 asm.js 时所做的那样),您必须考虑原始代码的语义。这意味着类型检查仍然会发生(它刚刚被拼写为静态类型代码)并且所有这些排列仍然存在以扼杀编译器。

于 2015-05-11T00:12:15.757 回答
11

关于asm.js的一些事实,希望可以使概念清晰:

  1. 是的,您可以手动编写asm.js方言。

    如果您确实查看了asm.js的示例,那么它们远非用户友好。显然,Javascript 不是创建此代码的前端语言。

  2. 将 vanilla Javascript 翻译成asm.js方言是不可能的。

    想一想——如果你已经可以以完全静态的方式翻译标准 Javascript,为什么还需要asm.js呢?asm.js的唯一存在意味着 Javascript JIT 人员在一些人中放弃了他们的承诺,即 Javascript 将在没有开发人员任何努力的情况下变得更快。

    这有几个原因,但我们只能说JIT很难像理解静态编译器一样理解动态语言。然后可能让开发人员充分了解 JIT。

最后归结为使用正确的工具来完成任务。如果您想要静态的、高性能的代码,请使用C / C++ ( / Java ) - 如果您想要动态语言,请使用JavascriptPython ......

于 2013-03-27T16:30:31.783 回答
3

asm.js 的创建是为了有一小部分可以轻松优化的 javascript 子集。如果您有办法将 javascript 转换为 javascript/asm.js,则不再需要 asm.js - 该方法可以直接插入到 js 解释器中。

于 2014-05-09T22:37:06.907 回答
2

理论上,如果可以使用 asm.js 中存在的语言的有限子集来表达,则可以将任何 JavaScript 操作转换/编译/转译为 asm.js。然而,在实践中,目前没有工具能够将普通的 JavaScript 转换为 asm.js(2017 年 6 月)。

无论哪种方式,将具有静态类型的语言转换为 asm.js 会更有意义,因为静态类型是 asm.js 的要求,而缺少静态类型是普通 JavaScript 的特性之一,这使得编译成 asm 变得异常困难.js。

早在 2013 年 asm.js 大热的时候,就有尝试编译类似 JavaScript 的静态类型语言,但无论是语言还是编译器,似乎都被抛弃了。

今天,在 2017 年,JavaScipt 子集TypeScriptFlow将是转换为 asm.js 的合适候选者,但两种语言的核心开发团队都对这种转换不感兴趣。LLJS有一个可以编译为 asm.js 的 fork,但那个项目几乎已经死了。ThinScript是最近的一次尝试,它基于 TypeScript,但它似乎也没有被激活。

因此,生成 asm.js 代码的最佳和最简单的方法仍然是用 C/C++ 编写代码并对其进行转换/编译/转译。然而,在可预见的未来,我们是否愿意这样做还有待观察。Web Assembly可能很快会完全取代 asm.js,并且已经出现了类似 TypeScript 的语言,例如TurboScriptAssemblyScript,它们可以转换为 Web Assembly。事实上,TurboScript 最初是基于 ThinScript 并用于编译成 asm.js,但他们似乎已经放弃了这个功能。

于 2017-06-22T14:11:40.933 回答
2

可以通过首先将常规 JavaScript编译为 C或 C++,然后使用Emscripten将生成的代码编译为 asm.js 来将常规 JavaScript 转换为asm.js。我不确定这是否实用,但它仍然是一个有趣的概念。

还有一个名为NectarJS的编译器将 JavaScript 编译为 WebAssembly 和 ASM.js。

于 2016-10-30T15:44:40.183 回答
1

检查这个http://badassjs.com/post/43420901994/asm-js-a-low-level-highly-optimizable-subset-of

基本上你需要检查你的代码是否与asm.js兼容(没有强制或类型转换,你需要管理内存等)。这背后的想法是用 javascript 编写代码,检测瓶颈并更改代码以使用 asm.js 和 aot 编译而不是 jit 和动态编译......有点 PITA 但你仍然可以使用 javascript 或其他像 c++ 或更好的语言......在不久的将来,lljs......

于 2013-03-25T23:48:21.220 回答