Mysaifu JVM は Windows Mobile 上で動作するJava仮想マシンです。クラスライブラリとしてGNU Classpathを使用しています。
<!------------------>
<b><code>java.awt</code></b>
<!------------------>
<ul>
<li>
<code>Component.setForeground(), setBackground()</code>でコンポーネントの色を変更した場合、すぐに画面に反映されるようにした。
</li>
<li>
<code>Component</code>が最初に表示された時点で、無条件に以下の2つのイベントを<code>EventQueue</code>にpostするように変更した。<br>
<ul>
<li><code>ComponentEvent.COMPONENT_MOVED</code></li>
<li><code>ComponentEvent.COMPONENT_RESIZED</code></li>
</ul>
GNU Classpathでは、<code>Component.isShown()</code>が<code>false</code>を返す間は、位置やサイズが変更されても上記2つのイベントはpostされない。しかし、最初に表示された時点で上記2つのイベントがpostされることを前提にしているアプリケーションがあるため、初期表示時に限って2つのイベントをpostするようにした。(GNU Classpathの実装は変更せず、Windows CEのpeer実装側を変更した)
</li>
<li>
<code>Checkbox.setState()</code>を呼び出した際に、<code>ItemEvent</code>をpostしていたが、この動作は誤りだった。ユーザの操作によってのみ発生させるように修正した。
</li>
<li>
<code>Checkbox</code>をタップした際にpostされる<code>ItemEvent</code>の<code>getItem()</code>メソッドの戻り値が<code>String</code>ではなく<code>Checkbox</code>になっていた。
</li>
<li>
<code>Label</code>の初期サイズを無視していた点を修正した。
</li>
<li>
<code>ContainerPeer</code>実装クラスの<code>getInsets()</code>が正しい値を返すように修正した。
</li>
<li>
<code>ScrollPanePeer</code>実装クラスの<code>getInsets(), getNativeInsets()</code>メソッドを削除した。(<code>ContainerPeer</code>実装クラスの<code>getInsets()</code>を使用するように修正した)
</li>
<li>
<code>GraphicsEnvironment.getMaximumWindowBounds()</code>は、"Today"ウインドウのサイズを返すようにした。<br>
これにより、画面上部のNavBarと画面下部のコマンドバーのサイズが考慮された値が返されるようになった。
</li>
<li>
以下のシステムプロパティを設定した場合、<code>Frame</code>および<code>Dialog</code>派生クラスを
「フローティング」表示可能とした。<br>
フローティング表示された場合はタイトルバーが表示され、サイズ変更も可能になる。<br>
<p>
<code>gnu.java.awt.peer.wce.floating=[frame,dialog]</code><br>
例1)<code>Dialog</code>派生クラスをフローティング表示する場合<br>
<b><code>gnu.java.awt.peer.wce.floating=dialog</code></b><br>
例2)<code>Frame,Dialog</code>派生クラスの両方をフローティング表示する場合<br>
<b><code>gnu.java.awt.peer.wce.floating=frame,dialog</code></b></br>
</p>
</li>
<li>
<code>Frame</code>クラスの以下のメソッドを実装した。<br>
<ul>
<li><code>setUndecorated(boolean)</code></li>
<li><code>setBounds(int,int,int,int)</code></li>
<li><code>setResizable(boolean)</code></li>
</ul>
</li>
<li>
<code>Dialog</code>クラスの以下のメソッドを実装した。<br>
<ul>
<li><code>setUndecorated(boolean)</code></li>
<li><code>setBounds(int,int,int,int)</code></li>
<li><code>setResizable(boolean)</code></li>
</ul>
</li>
<li>
<code>Component.getImage(ImageProducer)</code>を実装した。
</li>
<li>
<code>WM_ERASEBKGND</code>メッセージを無視していたが、Java側で必ず背景を塗りつぶすとは限らないため、<code>WM_ERASEBKGND</code>メッセージ受信時には<code>Component</code>の背景色を利用して塗りつぶすようにした。<br>
ただし、<code>ScrollPane</code>のスクロール時にちらつくように
なったため、暫定的な対策として<code>ScrollPane</code>がスクロール処理を行っている間は
<code>WM_ERASEBKGND</code>メッセージを無視するようにした。
</li>
<li>
<code>Component</code>および<code>Toolkit</code>の以下のメソッドを用いて<code>Image</code>を生成する際に、
バックグラウンドスレッドで<code>ImageProducer.startProduction(ImageConsumer)</code>を呼び出して、非同期に<code>Image</code>を生成していた。<br>
<ul>
<li><code>public Image createImage(ImageProducer)</code></li>
</ul>
しかし、上記メソッドからリターンした時点で<code>Image</code>が完成していることを前提に
しているアプリケーションが存在しているため、呼び出し元のスレッド内で<code>startProduction()</code>を呼び出すように修正した。
(GNU ClasspathのGTK+実装もそのようになっていた)
</li>
<li>
<code>Grphics.drawImage(Image, int, int, ImageObserver)</code>の第1引数に<code>null</code>を指定すると、<code>NullPointerException</code>が<code>throw</code>されていた。何もせずにリターンするように修正した。
</li>
<li>
ファイルやネットワーク上から<code>Image</code>をロードした際、データのロードが完了していない状態で<code>ImageObserver.ALLBITS</code>を通知していた。<code>SOMEBITS</code>を通知するように修正した。
</li>
<li>
<code>ScrollPane</code>でスクロールが発生した際に<code>AdjustmentEvent</code>を
通知するようにした。(GNU Classpath 0.18の<code>ScrollPaneAdjustable</code>には
バグがあるため、Bug report済み)
</li>
<li>
<code>ScrollPane</code>が<code>SCROLLBARS_AS_NEEDED</code>を指定して作成された場合、
子<code>Component</code>のサイズに応じてスクロールバーを非表示にする必要がある。
この判断基準が誤っていたため修正した。<br>
<code>Adjustable</code>の<code>getVisibleAmount()</code>が<code>getMaximum()</code>以上
の値を返した場合、スクロールバーを非表示にするようにした。
</li>
</ul>
<!---------------->
<b><code>java.lang</code></b>
<!---------------->
<ul>
<li>
<code>Class.isInsatance(Object)</code>に<code>null</code>を渡すと、JVMがクラッシュしていた。<br>
<code>false</code>を返すように修正した。
</li>
</ul>
<!---------------->
<b>JVM本体</b>
<!---------------->
<ul>
<li>
システムプロパティ<code>java.ext.dirs</code>をJVMが設定するようにした。<br>
jarファイルを<code>\Program Files\Mysaifu JVM\jre\lib\ext</code>に配置しておくと、
実行時にjarファイル内のクラスがロードされるようになった。
</li>
<li>
クラスロード時に、constant_pool 配列の最後の要素についてUTF-8文字列の解決が行われていなかった。<br>
たとえば、<code>constant_pool</code>配列末尾に<code>CONSTANT_Methodref_info</code>が入っていた場合、この要素を参照するメソッド呼び出しを行うとJVMがクラッシュしていた。
</li>
<li>
jsr命令の後続16ビットを「符号なし」として扱っていたため、不正なアドレスにジャンプしていた。<br>
符号付16ビットして扱うように修正した。
</li>
<li>
1つバイトコードを実行するたびに「例外が発生しているか」をチェックしていたが、仕様上例外が発生することがない命令は
この処理を省略するようにした。
</li>
<li>
<code>iastore</code>命令実行時の関数呼び出し回数を削減した。
</li>
<li>
<code>iadd, ladd, fadd, dadd, isub, lsub, fsub, dsub, imul, lmul, fmul, dmul</code>命令実行時の
オペランドスタック処理を高速化した。(オペランドスタックに対してPOP, PUSHする回数を減らした)
</li>
<li>
ヒストリファイル(recent\ディレクトリ配下に作成されるファイル)の名前に '\' が含まれることがあった。<br>
'\'を'_' に置換するように修正した。<br>
(\My Documents\test.jar 等を実行した場合、ヒストリファイルの作成に失敗していた)
</li>
<li>
バイトコード実行ループ処理内で「次に実行する命令位置」を決める処理(pcを更新する処理)を高速化した。<br>
(ループ末尾で「命令長配列」を参照して更新していたが、各バイトコードの実行完了時点で即値を加算するようにした)
</li>
<li>
<code>new</code>命令実行時に、対象クラスのアクセスフラグを無視していた。
フラグをチェックし、アクセスできない場合には<code>IllegalAccessError</code>を<code>throw</code>するようにした。
</li>
<li>
<code>getfield, putfield</code>命令実行時に、「対象フィールドのオブジェクト内におけるオフセット値」を<code>CONSTANT_Field_ref</code>構造体キャッシュしておき、
2回目以降のアクセスではフィールド位置を再計算しないようにした。
</li>
</ul>