おおざっぱに、現在構想中のvmまわりについてメモ。楽しい話題なのかどうかは知らない。


今のVMがこんな感じ

struct vm_state GTY(())
{
  VEC(tree) *stack; // tree スタック
  VEC(tree) *consts; // 定数テーブル
  VEC(tree) *functions; // 関数テーブル

  tree cur_func;
  ilog_mod cur_mod;
  tree env;
  unsigned int pc;
  unsigned int fp_i;

  VEC(char) *code;
  VEC(int) *i_stack; // 整数スタック

  tree *GTY((skip))fp;
};

スタックがtree用とint用の二本あってもったいないんだけど、GCCGC(garbage collecterね)の構造上仕方がない。ポインタと整数を混ぜられない。
VECでスタック参照すると、毎回ポインタを参照しないといけなくなるので、VECまわりはもうちょっとなんとかしたほうがいい。でも、ひょっとしたらそんなにオーバーヘッドではないかもしれない。VECは、GCCの可変長配列ライブラリなのだけど、変態マクロでテンプレートしてるので、そういうのが好きな人は読んでみると良いかと。(gcc/vec.h)
GCCはver. 3系列までは配列の先とか、ポインタの先とか、構造体の先とかの解析が弱い。ような気がする。

// arr[0]にスタックが割り当てられる
int func()
{
  int arr[4];
  arr[0] = 3;

  call();

  return arr[0];
}

// return 40になる。
int func2()
{
  int x = 40;
  call();
  return x;
}

だから、アレ。VECだとアレかもしんない。別にいいけど。そのうち考える。


継続も例外も考えてないのでフレーム構造は簡単。のはず。例外は…どうするか。よくわからん。そのうち考える。
callでスタックに詰むのは、PC、FP、CUR_FUNC…だけ、か。少ないな。いや、そんなもんか。現在呼び出してる関数があるので、それを辿っていけば、どうにでもなる。はず。RET命令のアレはいらないよ>自分。あー、FPを積まないと。いやFPは積んでるんだけど、FPが。


前のループ問題は

function func() {

	for ( var i=0; i<20; i++ ) {
		var x;
		return function () { return x; }
	}
}

こういうのがあったら、

	LOAD_CONST 0
	SET_LOCAL 0  ; i = 0 
label:
	BIND	1
	CLOSURE1 <anon func>
	LOAD_CONST 20
	LOAD_LOCAL 0
	JLT labale

こんな感じにする、BINDすると、フレーム作る。anon funcが

	LOAD_OUTER 1,0  ; 一個外側のloacal0
	RET

こんな感じ。
けど、これ、ループで作ったフレームがこの関数以外で使われることが無いんだから、このループのフレームと関数呼び出された時のフレームを一緒にしてしまえば、LOAD_LOCALになるんじゃないの?あー。無理無理。再帰してると無理。気付いてよかった。