まあそれはいい。今日、あれから一時間くらい考えて大体決まった。
1パス目で構文解析。このときに、ループと関数に大きめのフレーム情報をのっけとく。んで、ネストした関数からそのフレームの変数の中の変数から参照があったら、そのフレームに印をつけとく。

// 大きめのフレーム情報をframe_baseという名前にしておく。
function nanika()  // 関数にframe_baseいっこ
{
	var x;

	while ( 1 ) { // ループにframe_baseいっこ
		var y;
		for ( ;; ) { // このループにもframe_baseいっこ
			var z;

			function nestfunc() {
				return () { z+x; } 
			}
		}
	}
}

この場合だと、xとzを参照するので、

function nanika()  // この関数はクロージャ。
{
	var x;

	while ( 1 ) { // これはただのループ
		var y;
		for ( ;; ) { // このループは毎回フレーム生成
			var z;

			function nestfunc() {
				return () { z+x; } 
			}
		}
	}
}

ここまで1パス。
次のパスでローカル変数番号付けとコード生成。2パスでいける。後埋めするのはジャンプアドレスだけ。


変数の番号付けで注意しないといけないのは、

function nanika() {
	{
		var x;
	}
	{
		var y;
	}
}

この場合は、xとyは同じ変数にしてもいいけど、

function nanika() {
	{
		var x;
		function () { return x; }
	}
	{
		var y;
	}
}

この場合は、xとyは同じにしてはいけない。これは、適当にビットマップ持たせといて、必要になったらマークしていけば大丈夫。多分。


さらにやるとしたら、ローカル変数の生存期間ぐらい調べるとか

{
	var x,y;

	x = ...;
	... ;
	// ここより下ではx使わない
	y = ...;
	...
}

こうなってたら、xとyは同じにしてもいい。これをパス増やさずにそれなりに簡単に実現することって可能?できるならやってもいいと思うが。あとはネスト関数入りループの中からネスト関数で使われない変数を外に出してコピーする量減らすとか。うにゃうにゃとか、うにゃうにゃとか。(書くのが面倒になってきたらしい)


そこらへんは、まあいい。多分、今考えてる分でメモリ割り当て量はともかく、割り当て回数は大体削れるはずだ。他のスクリプト言語と比較しても負けることは無い、と思う。