WebGL-Native: 初期化時にスタックオーバーフローする問題
prev: https://zenn.dev/okuoku/scraps/5777ef80737f27
next: https://zenn.dev/okuoku/scraps/1128673fdb2a15
ちょっと複雑になると起動しなくなる
一難去ってまた一難だな。。
複雑な代入は一旦演算の途中結果をスタックにspillすることになるが、これが最適化を切っていることにより全てが別々のインスタンスになり、1エントリあたり数ワード(wasm2c
的な定義のtableぶん)のスタック消費になってしまうように見える。
生成された関数の冒頭部分の逆アセンブルは:
static void init_table(void) {
00007FFB1D66E970 push r15
00007FFB1D66E972 push r14
00007FFB1D66E974 push r13
00007FFB1D66E976 push r12
00007FFB1D66E978 push rsi
00007FFB1D66E979 push rdi
00007FFB1D66E97A push rbp
00007FFB1D66E97B push rbx
00007FFB1D66E97C mov eax,143528h ★ スタック要求サイズ
00007FFB1D66E981 call __chkstk (07FFB1D601055h)
00007FFB1D66E986 sub rsp,rax
00007FFB1D66E989 lea rax,[w2c___ZL26RegisterInterfaceSplitImplyyP15IUnityInterface (07FFB20BE04F0h)]
00007FFB1D66E990 lea rcx,[w2c_b289 (07FFB20BE0490h)]
00007FFB1D66E997 lea rdx,[w2c__ManagedStreamHelpers_ManagedStreamSeek_mD7B16AF1079F3F11EE782A32F851ABD761BD2E9E (07FFB20BE0240h)]
00007FFB1D66E99E lea r8,[w2c_b288 (07FFB20BE01D0h)]
00007FFB1D66E9A5 lea r9,[w2c__InputDevices_InvokeConnectionEvent_m19E87BB6671D4B4CE3EB322EEE3621B0146A7077 (07FFB20BDF9F0h)]
00007FFB1D66E9AC lea r10,[w2c_b287 (07FFB20BDF990h)]
00007FFB1D66E9B3 lea r11,[w2c_b286 (07FFB20BDE7C0h)]
00007FFB1D66E9BA lea rsi,[w2c__UmAlQuraCalendar_CheckTicksRange_mF5B461A483849D8CB9A2B87B47FA5218E68FEFF7 (07FFB20BDF130h)]
00007FFB1D66E9C1 lea rdi,[w2c__HijriCalendar_CheckTicksRange_m2D1B18699664C2C21AC0F985BD6731A8B3DEC395 (07FFB20BDE820h)]
00007FFB1D66E9C8 lea rbx,[w2c__PlayerConnection_MessageCallbackInternal_m223C558BDA58E11AE597D73CEC359718A336FD74 (07FFB20BDE20
Win32におけるデフォルトスタックサイズは1MiBとかなのでちょっと足りない結果になる。
とりあえず最適化を有効に
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index d44a802..7ef9967 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -1,6 +1,6 @@
@@ -32,6 +32,7 @@ function(translate_wasm proj wasmpath)
# .c => .bc
add_custom_command(OUTPUT ${bcpath}
COMMAND clang -g3 -c -emit-llvm -O0
+ -Xclang -disable-O0-optnone
-DWASM_RT_MEMCHECK_SIGNAL_HANDLER=1
-I${WASMSTUB}
-o ${bcpath} ${wasmcpath}
@@ -40,7 +41,7 @@ function(translate_wasm proj wasmpath)
# .bc => .o
add_custom_command(OUTPUT ${outpath}
- COMMAND clang -g3 -O0 -c
+ COMMAND clang -g3 -O1 -c
-o ${outpath} ${bcpath}
DEPENDS ${bcpath}
COMMENT "WASM: Generating machine code LLVM => bin (${proj})")
-Xclang -disable-O0-optnone
がミソで、LLVM-IRレベルでの最適化を抑制しつつ、後段のclangによるamd64コード生成で最適化をしたければこのオプションが必要になる。LLVM-IRの生成時に -O0
を付けた場合、後段(特にLTO時)での最適化を避けるために optnone
属性が付いてしまう 。
... これで一応起動はするようになったが、ビルドには30分以上掛かるように。。まぁ滅多に再ビルドしないから良いけど。。
なんか遅い
せっかく最適化を有効にしたんでDOSboxを起動してみたけど何か遅い。
Import関数(= JavaScript側に実装された関数) e
は getTempRet0
らしく、64bit値用のヘルパー関数らしい。これが実行時間の 10% 程度を占めている。
"e": getTempRet0,
Node.jsの WebAssembly
を使う場合は、WASMとJavaScriptの界面のコストはほぼ無視できる(本当?)と考えられるが、今回のようにWASM実行環境とJavaScript環境を分離しようとすると、どうしてもそれなりのコストになってしまう。
これはちょっとどうしようも無いかな。。Dosbox-xがfastcompを捨ててくれれば改善できるかもしれないが。。
ついでにスタック破壊問題を修正
デバッグビルドだとこんな警告出るんだ。。破壊されている alloca
のアロケーションが足りなかった。
diff --git a/node-nccc/node-nccc.c b/node-nccc/node-nccc.c
index 2c9d939..65c697f 100644
--- a/node-nccc/node-nccc.c
+++ b/node-nccc/node-nccc.c
@@ -128,7 +128,7 @@ nccc_call_trampoline(napi_env env, napi_callback_info info){
abort();
}
if(dispatch){
- inbuf = alloca(sizeof(uint64_t)*ctx->incount+1);
+ inbuf = alloca(sizeof(uint64_t)*(ctx->incount+1));
}else{
inbuf = alloca(sizeof(uint64_t)*ctx->incount);
}
寝不足では。
dispatch
モードの場合、引数は実際に呼ばれるC関数ポインタが追加される関係上1つ増える。このため、1つ増えた変数を格納するぶんだけ余計に alloca
する必要がある(前のコードだと演算子の優先順位上1バイトしか増えない)。