<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>JIT</title><link>https://blog.ast.moe/tags/jit/</link><description>Recent posts from 五里霧中</description><generator>Hugo</generator><item><title>Omoikaneのbaseline JITでAcid3がメモリ異常終了する原因を追った</title><link>https://blog.ast.moe/blog/2026-09-13/</link><pubDate>Sun, 13 Sep 2026 20:20:51 +0900</pubDate><guid>https://blog.ast.moe/blog/2026-09-13/</guid><description>&lt;p&gt;自作ブラウザの&lt;a href="https://github.com/ieee0824/omoikane"&gt;Omoikane&lt;/a&gt;でCSSの実装を進めていたところ、Acid3がメモリ異常で落ちるようになりました。&lt;/p&gt;
&lt;p&gt;問題が出たのはbaseline JITを有効にした場合だけです。interpreterでは通ります。&lt;/p&gt;
&lt;p&gt;さらに、OmoikaneのAcid3 runnerにはFaithfulとDirectDriveという2つの実行方法がありますが、Faithfulは100点まで完了し、そのあとのDirectDriveで落ちていました。&lt;/p&gt;
&lt;p&gt;環境によって壊れ方も違います。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;環境&lt;/th&gt;
&lt;th&gt;発生した異常&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;x86_64 Linux&lt;/td&gt;
&lt;td&gt;SIGSEGV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64 Linux&lt;/td&gt;
&lt;td&gt;SIGABRT、約60 GBのallocation、再実行ではSIGSEGV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64 macOS&lt;/td&gt;
&lt;td&gt;SIGSEGV、再実行ではSIGBUS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;同じテストなのにsignalが揃っていません。&lt;/p&gt;
&lt;p&gt;CSSの変更で見つかった問題ですが、結果的にはCSSではなく、Boaのshared shapeが持つ弱参照キャッシュの寿命が原因でした。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ieee0824/omoikane/issues/755"&gt;Issue #755&lt;/a&gt;と&lt;a href="https://github.com/ieee0824/omoikane/pull/757"&gt;PR #757&lt;/a&gt;の話です。&lt;/p&gt;
&lt;h2 id="faithfulとdirectdrive"&gt;FaithfulとDirectDrive&lt;/h2&gt;
&lt;p&gt;先に、OmoikaneのAcid3 runnerにある2つの実行方法について説明します。&lt;/p&gt;
&lt;p&gt;どちらも同じAcid3のページを読み込み、同じ100個のsubtestを実行します。違うのは、Acid3のテストループをどう進めるかです。&lt;/p&gt;
&lt;p&gt;Faithfulでは、ページ内のinline event handlerを接続して実際の&lt;code&gt;load&lt;/code&gt;イベントを発火します。&lt;/p&gt;
&lt;p&gt;Acid3の&lt;code&gt;&amp;lt;body onload=&amp;quot;update()&amp;quot;&amp;gt;&lt;/code&gt;がOmoikaneのevent処理を通って実行され、その後は仮想時計を進めながら、&lt;code&gt;setTimeout(update, 10)&lt;/code&gt;で予約された処理を順番に動かします。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;load event
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; &amp;lt;body onload=&amp;#34;update()&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; setTimeout(update, 10)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 仮想時計を進める
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 次のupdate()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;実際のブラウザでページを開いたときに近い経路です。event handlerの接続、timer、callback、event loopのどこかが壊れていれば、途中で進まなくなります。&lt;/p&gt;
&lt;p&gt;DirectDriveでは、この&lt;code&gt;setTimeout&lt;/code&gt;の連鎖を使いません。&lt;/p&gt;
&lt;p&gt;runner側から&lt;code&gt;update()&lt;/code&gt;を直接呼び、subtestを一つずつ進めます。iframeやobjectの読み込みに必要な0msのtaskだけは処理しますが、Acid3自身が予約する10ms timerは迂回します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;runner
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; update()を直接呼ぶ
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 必要な0ms taskを処理
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 次のupdate()を直接呼ぶ
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これは、timerやload eventの実装が未完成でも、JavaScript engineやDOMが個々のsubtestをどこまで処理できるかを見るための基準です。&lt;/p&gt;</description></item></channel></rss>