JS::Object.awaitが返らないときがある? - @ledsun blog にて次のような疑問を持ちました。
this.vm.evalAsync(script.ScriptBody)の中でthis.vm.evalAsync(script.ScriptBody)するのがよくないのでしょうか?
素朴にevalAsync
の中でevalAsync
を呼ぶとどうなるのか試してみます。
<html> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.script.iife.js"></script> <script> function main() { window.rubyVM.evalAsync(` require 'js' JS.global[:rubyVM].evalAsync("puts 'a'") `) } // RubyVMの初期化を待ってから、mainを実行します。 const id = setInterval(() => { if (window.rubyVM) { clearInterval(id) main() } }, 300) </script> </html>
実行すると
vm_call_cfunc: cfp consistency error
はRubyのエラーのようです。
Bug #11903: [BUG] vm_call_cfunc - cfp consistency error - Ruby master - Ruby Issue Tracking System に同じエラー文面に関するバグ報告があります。
報告内容は関係ないだろうと思って読んでいません。
Uncaught (in promise) RuntimeError: unreachable
はAsyncifyに関わるエラーのようです。
[Asyncify] RuntimeError: unreachable · Issue #15488 · emscripten-core/emscripten · GitHub に同じエラー文面に関するバグ報告があります。
まあ、よくわかりません。
ちなみにどちらかのevalAsyncをevalに返ると動きます。
window.rubyVM.eval(` require 'js' JS.global[:rubyVM].evalAsync("puts 'a'") `)
または
window.rubyVM.evalAsync(` require 'js' JS.global[:rubyVM].eval("puts 'a'") `)
です。
JS::Object.awaitが返らないときがある? - @ledsun blog のときはこのエラーは起きていません。 evalAsync内でfetchして取得したRubyスクリプトをevalAsyncしてるはずなので、同じ現象がおきるはずだと思っていました。 何かが違うようです。・・・。 RubyとJavaScriptを行ったり来たりしているところが、いまいち追いかけられなくて、頭の中でワープさせているんですが・・・正しく想像出来ていなさそうです。
evalAsyncの中はFiberで実装されている*1のですが・・・また、これがコードがどこにどう飛ぶのがかわかりません。
追記
Bug with passing Procs around: "RuntimeError: unreachable" · Issue #34 · ruby/ruby.wasm · GitHub を眺めていたらもう少し短い再現コードが書けることに気がつきました。
<script type="module"> import { DefaultRubyVM } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.esm.js' const main = async () => { // Fetch and instantiate WebAssembly binary const response = await fetch( "https://cdn.jsdelivr.net/npm/[email protected]/dist/ruby+stdlib.wasm" ); const buffer = await response.arrayBuffer(); const module = await WebAssembly.compile(buffer); const { vm } = await DefaultRubyVM(module); window.rubyVM = vm; vm.evalAsync(`JS.global[:rubyVM].evalAsync("puts 'a'")`) }; main(); </script>