在 Google Chrome 中调试实验性 WebAssembly externref 错误
Debugging experimental WebAssembly externref bug in Google Chrome
警告:由于引用类型提案尚未完成,此代码不会运行不切换标志或设置以启用执行实验代码。
如果您使用的是 Google Chrome 或 Chromium 浏览器,则需要启用以下标志:
chrome://flags/#enable-experimental-webassembly-features
我设置了一个简单的手写 Wasm 模块供个人使用。我本可以很容易地用 JavaScript 编写它,但使用 Wasm 更容易也更有意义,而且由于它是一个简单的个人脚本,我不在乎其他人是否不能 运行它。
我是用 wabt 的 wat2wasm 编译的。
Wasm 模块旨在提供整个 globalThis
对象以从中导入。
从那里开始,它使用了四个 TypedArray 构造函数:Uint8Array
、Uint16Array
、Uint32Array
和 BigUint64Array
.
注意:在 Wasm 之前没有执行任何代码,因此不会有任何干扰。
后来,我意识到 Wasm 根本没有按预期工作,我的数学是正确的,但变量是错误的。
我已将我的问题缩小为以下内容:
;; global -> global variable
(import "globalThis" "Uint8Array" (global $Uint8Array externref))
(import "globalThis" "Uint16Array" (global $Uint16Array externref))
(import "globalThis" "Uint32Array" (global $Uint32Array externref))
(import "globalThis" "BigUint64Array" (global $BigUint64Array externref))
;; func -> function
(import "console" "log" (func $console::log (param externref)))
(start $_start)
(func $_start
global.get $Uint8Array
call $console::log
global.get $Uint16Array
call $console::log
global.get $Uint32Array
call $console::log
global.get $BigUint64Array
call $console::log
)
这个 Wasm 是这样实例化的:
WebAssembly.instantiateStreaming(
fetch(
"test.wasm", {
mode : "same-origin",
credentials : "omit",
cache : "no-store",
redirect : "error",
referrer : "no-referrer"
}
), globalThis
).catch( console.error );
有趣的问题是日志都说了同样的话:Uint8Array
。
我傻眼了。这在字面上是不可能的。 JavaScript 文件本身未被缓存,WebAssembly 正在使用“无缓存”获取,网页本身未被缓存。
然后我想,因为我使用的是 XHTML,所以可能 HTML 文件中没有发生。它也在那里。
我尝试将 Wasm 文件转换为 TypedArray 并仅使用 WebAssembly.instantiate
,突然间,它完美无缺。
此时服务器一定是提供了错误的文件,因为我越往下看,这越是胡说八道。
我几乎想说这是 Chromium 浏览器或 V8 运行时间错误,但在我盲目尝试将其作为错误呈现之前,我需要进一步缩小范围。
我已经在 Repl.it, and on CodeSandBox.io 上设置了相同代码的两个不同版本,因此希望有人可以尝试 运行 自己尝试,以确认错误,并可能尝试调试哪里我错了。
(这可能是 Repl.it 的服务器的问题吗?)
这是 Chromium 在
https://chromium-review.googlesource.com/c/v8/v8/+/2551100.
这是我从一位开发人员那里得到的回复:
This is indeed a timing issue that has been fixed in https://chromium-review.googlesource.com/c/v8/v8/+/2551100. The problem happens when there are only imported globals, and compilation of the WebAssembly functions finishes before the stream actually finishes. In this case, the offset calculation happens after the compiler uses the offsets, and therefore produces incorrect code.
A workaround is to define one global that is not imported, as this causes the offset calculation to happen earlier.
似乎发送一个只导入全局变量而不是函数的小模块破坏了代码。
他们的代码在流和编译器之间存在线程竞争条件。
警告:由于引用类型提案尚未完成,此代码不会运行不切换标志或设置以启用执行实验代码。
如果您使用的是 Google Chrome 或 Chromium 浏览器,则需要启用以下标志:
chrome://flags/#enable-experimental-webassembly-features
我设置了一个简单的手写 Wasm 模块供个人使用。我本可以很容易地用 JavaScript 编写它,但使用 Wasm 更容易也更有意义,而且由于它是一个简单的个人脚本,我不在乎其他人是否不能 运行它。
我是用 wabt 的 wat2wasm 编译的。
Wasm 模块旨在提供整个 globalThis
对象以从中导入。
从那里开始,它使用了四个 TypedArray 构造函数:Uint8Array
、Uint16Array
、Uint32Array
和 BigUint64Array
.
注意:在 Wasm 之前没有执行任何代码,因此不会有任何干扰。
后来,我意识到 Wasm 根本没有按预期工作,我的数学是正确的,但变量是错误的。
我已将我的问题缩小为以下内容:
;; global -> global variable
(import "globalThis" "Uint8Array" (global $Uint8Array externref))
(import "globalThis" "Uint16Array" (global $Uint16Array externref))
(import "globalThis" "Uint32Array" (global $Uint32Array externref))
(import "globalThis" "BigUint64Array" (global $BigUint64Array externref))
;; func -> function
(import "console" "log" (func $console::log (param externref)))
(start $_start)
(func $_start
global.get $Uint8Array
call $console::log
global.get $Uint16Array
call $console::log
global.get $Uint32Array
call $console::log
global.get $BigUint64Array
call $console::log
)
这个 Wasm 是这样实例化的:
WebAssembly.instantiateStreaming(
fetch(
"test.wasm", {
mode : "same-origin",
credentials : "omit",
cache : "no-store",
redirect : "error",
referrer : "no-referrer"
}
), globalThis
).catch( console.error );
有趣的问题是日志都说了同样的话:Uint8Array
。
我傻眼了。这在字面上是不可能的。 JavaScript 文件本身未被缓存,WebAssembly 正在使用“无缓存”获取,网页本身未被缓存。
然后我想,因为我使用的是 XHTML,所以可能 HTML 文件中没有发生。它也在那里。
我尝试将 Wasm 文件转换为 TypedArray 并仅使用 WebAssembly.instantiate
,突然间,它完美无缺。
此时服务器一定是提供了错误的文件,因为我越往下看,这越是胡说八道。
我几乎想说这是 Chromium 浏览器或 V8 运行时间错误,但在我盲目尝试将其作为错误呈现之前,我需要进一步缩小范围。
我已经在 Repl.it, and on CodeSandBox.io 上设置了相同代码的两个不同版本,因此希望有人可以尝试 运行 自己尝试,以确认错误,并可能尝试调试哪里我错了。
(这可能是 Repl.it 的服务器的问题吗?)
这是 Chromium 在 https://chromium-review.googlesource.com/c/v8/v8/+/2551100.
这是我从一位开发人员那里得到的回复:
This is indeed a timing issue that has been fixed in https://chromium-review.googlesource.com/c/v8/v8/+/2551100. The problem happens when there are only imported globals, and compilation of the WebAssembly functions finishes before the stream actually finishes. In this case, the offset calculation happens after the compiler uses the offsets, and therefore produces incorrect code.
A workaround is to define one global that is not imported, as this causes the offset calculation to happen earlier.
似乎发送一个只导入全局变量而不是函数的小模块破坏了代码。
他们的代码在流和编译器之间存在线程竞争条件。