- khabaはOSASKを強く意識しており(GBAで動くOSASKを作ることが最初の動機だったので当然)、khabaでもタスクセーブできなければいけない。しかもセーブしたものを他のCPUで再開できたら、しかもエミュレーションなしでできたら、とてもいいだろう。
- 68000とかで実行したタスクをセーブしx86でロードすると、メモリイメージ上のエンディアンが合わないので、16bitメモリアクセス前後に XCHG(AL, AH); みたいなコードを挿入しなければいけないことになる。これはコードが肥大化するし、遅い。それならば、メモリ上のintやshortをすべて反転させてしまえばいいではないか。
- これをやるにはメモリのイメージに対して、どこがintでどこがcharでどこがポインタか、みたいなことを完全に把握しなければならない。だから把握する。この情報があるので、メモリダンプの可読性は非常に高い。構造体も認識するので、デバッグはかなり楽になる。
- IA-16でセーブしたものをIA-32でロードする場合、メモリに余裕があるならintの幅を16bit→32bitにしてしまうほうが、動作が速い。しかしこれをやるとメモリのポインタがずれる恐れがある。でもやる。khabaではメモリ上にストアされたポインタは実際のアドレスではなく、ファイルのパスのような抽象的なもので格納する。実際にはパスそのものを保存するわけではないが、 &stack.func_abc.table.i[12] のような形式へたどれるような情報をもつ。
struct STACK {
struct MAIN {
int i, j, k; /* 関数main()のスタック変数 */
};
struct FUNC_AAA { /* main()がfunc_aaa()を呼んだのでスタックに積まれた */
struct CODEPOINTER ret; /* ここは &code.main.label126 とかが入っているのだろう */
int i, j;
float x, y;
};
struct FUNC_ABC { /* func_aaa()がfunc_abcを呼んだらしい */
struct CODEPOINTER ret;
struct TABLE {
int i[100];
};
};
};
- 当然ながらこのSTACK構造体は動的に変わることになる。関数呼び出しのオーバヘッドはやや大きい。
- この例ではstackの伸びる方向とは逆に書いたが、実際はスタックの伸びる方向にあわせて書くべきだ。・・・が、khabaのスタックがESPのように伸びていくとは決まっていない。
- もしメモリ使用状況マネージャに書き足すのがつらいのなら、スタックはスタック上にとるのではなく、mallocみたいにしたらいいかもしれない。この場合、旧スタックポインタをスタック内に記憶しておくことになるだろう。
struct FUNC_ABC {
struct CODEPOINTER ret;
struct DATAPOINTER oldstack;
struct TABLE {
int i[100];
};
};
};
- つまり呼び出し元を探るにはoldstackをたどっていけばいい。チェイン構造である。この場合、この構造体はもはやスタック上にはないので、先の例はこうなるだろうか。 &heap.func_abc.table.i[12] 。
- 再帰などで同じ関数が何度も呼ばれたら、 &heap.func_abc~37.table.i[12] とかになるのだろう。
- このmalloc型スタックは、GBAみたいなマシンでは有利かもしれない。GBAは速いRAMが少ないので、大きなスタックをキャッシュに保持するのは大変である。でもmalloc方式にすれば、小さなオブジェクトがたくさんできるだけなので、今使っているものくらいなら問題なくキャッシュに収まる可能性が大きい。
- このような形式でタスクセーブされるため、タスクセーブ後にプログラムを少々書き換えたとしても、再開できないことはない(khabaバイナリを最適化して、ローカル変数名情報などを適当なIDなどに交換してしまったあとだと、改造しても動くというのはやりにくいかもしれないが)。
- khabaでは「unionを使って、floatで書いたものをintで読む」なんてことは絶対に禁止である。しかしunionが使えないわけではない。書いた型と違う型で読んだ場合に例外が起きるというだけのことである。同じ理由で強引にキャストして値を読むこともできない。
- OSASKではメモリレスアーキテクチャをとっており、これはGBAでも引き継がせる予定だが、ということはつまり、メモリイメージというのは、ただのバイナリファイルである。バイナリファイルにこのような型情報がつくわけだ。これは非常に便利である。バイナリファイルに型情報があるのだから、それなりのエディタを作れば、データの任意の部分を人間にわかりやすい形式で表示したり編集したりできるわけだ。
{
view {
color = white; /* enumであればこのように表示できるはず(ただしこのコメントは実在しない) */
fontsize = 15;
};
history[5] = {
"abc.txt", "def.txt", "ghi.h", "", ""
};
};
- これはテキストエディタの設定ファイル(兼環境保存ファイル)の例である。もちろんこれくらいの読みやすい設定ファイルを持つテキストエディタは既にごまんとありkhabaのアドバンテージとはいえないが、しかしこのようなファイルが、実際はただの100バイト前後のバイナリであって、解読ルーチンなしに読めるのである(バイナリなので当然)。これはかなりいけていると思う。しかもただのテキストファイルではないので、viewとかの部分は編集できないだろうし(無理に編集することもできるだろうけど、その場合違う構造体になってしまうのでもはやこのアプリには読み込めない)、colorのところはwhiteのほかにblueやredなどを選択すればいいだけにもできる。汎用・バイナリ・バリュー・エディタ?
- これが現在実行中のアプリのスタックやヒープに対してもできるのだから、デバッガなんてもういらないかも。