2017-07-24 103 views
1

我正在尝试一个简单的hello world WebAssembly示例,并且我无法理解在Chrome 59中看到的错误:如果缓冲区大小大于4KB,WebAssembly.Compile将不被允许使用

RangeError: WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.compile, or compile on a worker thread.

src/wasm/counter.wasm:13 
    10 | let wa; 
    11 | const make = source => { 
    12 | // buffer should already be set 
> 13 | return wa = new Module(buffer); 
    14 | }; 
    15 | 
    16 | const WebAssemblyModule = function(deps = { 

我跟着步骤this tutorial,并没有错误,我可以创造一切条件。我正在使用create-react-apprewired with wasm-loader

如果我使用本地生成的计数器模块,我会在开始时提到我提到的错误。如果我尝试使用预建版本(例如in this project),它可以正常工作。

当我构建我的模块时,我使用的是与教程中指定的相同的命令。具有工作模块的项目与README中列出的命令相同:

emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1 

任何想法可能会导致错误?

回答

2

一些浏览器限制了可以同步编译的模块的大小,因为这会阻塞主线程。正如错误信息所示,他们宁愿让您使用WebAssembly.compile,它会返回promise。我建议你进一步去使用WebAssembly.instantiate这将会异步编译和实例化,并在某些情况下生成更高性能的代码。见its documentation,签名是:

Promise<WebAssemblyInstantiatedSource> 
    instantiate(BufferSource bytes [, importObject]) 

bytes是你传递给Module上述相同的缓冲区,importObject是你必须传递给Instance同样的事情。


另一种方法是使您的.wasm文件变小。这很脆弱,因为主线程的大小限制是任意的,而且你并不真正控制你生成的代码的大小。您可以尝试使用-O2-Os进行编译,您可以运行binaryen的优化程序来尝试缩小大小。您也可以将您的代码拆分为多个较小的模块,分别进行编译,然后将它们动态链接在一起(共享导入/导出,并为所有这些模块使用相同的内存)。

但是,这不是你应该依赖的东西,而且你仍然阻止主线程。


还有一种选择是将您的所有代码移动到WebWorker。您可以尽可能多地屏蔽它们,不需要Promise s。

+1

感谢您的回复!这很有道理 - 问题似乎来自'wasm-loader',因为它是进行模块加载的人。我在那里提交了一个问题:https://github.com/ballercat/wasm-loader/issues/4 –

+0

当sync模块编译创建更慢的代码时,您能否提供更多详细信息? – Vitaly

+1

@Vitaly主要区别在于编译器是否知道分配的内存:如果〜4GiB虚拟预留是可能的并且安装了信号处理程序,则不需要显式边界检查。这在编译时不一定是已知的,但在实例化时肯定已知。 –