Loading deck

Emscripten

Runtimeと

デバッグ

junji hashimoto

目次

  • はじめに
  • 動機
  • 長い闘い
  • Runtimeの構造
  • DLLの仕組み
  • デバッグ方法
    • ソースとの対応
    • printfデバッグ
  • 終わりに

はじめに

  • この発表を行うにあたり、某企業や団体とは無関係です。
  • 実際の業務に使用しているわけではないので、内容についてはご了承ください。
  • Emscriptenのランタイムに関する資料がありましたら共有お願いします。

Emscriptenを始めた動機

  • 食指が動く
  • 各種妄想
    • AWSのLambdaでHaskellを動かしたい。
    • ブラウザ上で自作のHaskell製プログラムを動かしたい
  • ​HaskellのインタプリタhugsをEmscriptenでビルドし始める。

戦いの幕開け(よくある問題)

  • Emscriptenは環境
    • OSと独立したファイルシステムと環境変数
  • JSのイベントモデルから来る問題
    • CLIのプログラムをWebに移植するには、stdinのあたりの処理の書き直しが必要
    • window.promptの置き換え
    • JSの闇
      • promise、awaitに期待?
  • 一旦できたかに思われたが。

長い闘い

  • その後
    • インタプリタとCとJSの連携(DLL関連)
  • 未知の領域へ(問題だらけ)
    • realpathでEINVAL(musl起因)
    • LD_LIBRARY_PATHが動かない
    • dlopenでセグフォ(RTLD_GLOBALのバグ)
    • chdirで例外

たどり着いた結論

  • ランタイムのアーキテクチャがわからないとデバッグできない。
    • どこにprintfをおけばいいのか
    • スタックトレースが意味不明
      • ftCallとかでて落ちる。
    • straceがない。(ブラウザなので)

             ということで

  • Emscriptenのランタイムの紹介をします。

x86とのアーキテクチャの違い

x86 Emscripten
レジスタ(PCも) ある ない
スタックの向き 上位アドレスから
下位アドレス
下位アドレスから
​上位アドレス
ヒープの場所 コードの後 スタックの後
コードの場所 メモリ上 jsの関数
関数ポインタ メモリ上のアドレス 関数テーブルの
インデックス

Runtimeの構造

JSのオブジェクト全体

スタック

ヒープ

関数テーブル

FUNCTION_TABLE_<sig>

FS:File System

関数('_'で始まる)

関数ポインタ用:

<sig>は関数型情報

'_'で始まる関数への

参照が入っている

通常呼び出し用

DLL(SIDE_MODULE)の構造

MAIN_MODULE(本体)からevalで呼ばれる

スタック

ヒープ

関数テーブル

FUNCTION_TABLE_<sig>

関数('_'で始まる)

関数ポインタ用:

MAIN_MODULEの

ポインタと

SIDE_MODULE

両方がマージ

 

関数:

DLLの関数のみ

MAIN_MODULE

と共有

関数の呼ばれ方

  • モジュール内の場合
    • '_'付きの関数が直接呼ばれる
  • ​モジュール外や関数ポインタの場合
    • ​関数テーブルのポインタをftCallに渡して実行
    • ftCallには型がある。(signatureとよぶらしい)
      • v:void
      • i:int
      • i:pointer
      • d:double

ソースとの対応

  • ランタイム
    • emscripten/src
  • ftCallなどの関数生成
    • ​emscripten/emscripten.py
  • ​libc(musl)とかcのライブラリ
    • ​emscripten/system

デバッグ方法

  • printfデバッグ
    • 自分のソースにprintf
    • ランタイムのライブラリにconsole.log
    • 最適化しないで動く場合は生成されたJSにconsole.log
    • 最適化しないと動かない場合は生成されたJSをjs-beautifyで整形してconsole.log
      • elseifや小数点で間違ったJSを吐くので手で直す。

他の方法はないのか

  • デバッグオプションは?
    • EMCC_DEBUGはコード生成のデバッグ用でランタイムのエラーには無力
    • 代わりにLIBRARY_DEBUGというのがあるらしい
  • デバッガは?
    • node inspectとかコードが大きすぎて動かない
    • 最適化を外すとブラウザで動かない。
      • サイズが10Mbyteごえなので

終わりに