おまけ:LuLu (3)
- 今日の成果 → http://hzkr.kokage.cc/lulu3.zip
ちょっとソースコードが酷いですごめんなさい。CALLのコードが3カ所くらいにコピペされてます。あとでちゃんとリファクタリングする。。。
今回読んだ全命令を実装(ただし、メタテーブルの処理は除く)してあります。一応 LuLu の上で動く LuLu の上でLuaのtestディレクトリにあるfib.lua(メモ化)やfactorial.lua(Yコンビネータ)などなどは動くくらいの完成度です。現時点で、1段LuLuをかませると50倍くらい遅くなります。3段くらいするとluluのロードに時間かかりすぎて実質起動しなくなります、メタテーブルちゃんとしたらさらに遅くなりそうですね。何か最適化できるかな。
実装は基本的に読んだことそのまんまですが、いくつかポイントを。ライブラリ関数はLuaそのものの関数を使い回すことにしたので、こんな感じで
function library() return { print = print, string = string, io = io, math = math, os = os, table = table, ... } end
本体のライブラリをわりとそのままLuLu上でも使えるようになりました。対象言語と実装言語が同じだとこの辺り楽でいいですね。
Upvalueについては、GCがどうこうを考えるのは難しいと思ったので、とりあえず、全部のUpvalueを無条件に閉じています。こんな感じの実装。
-- 同じ変数に対しては同じUpvalueを返すための記憶テーブル local uvcache = {} function closeupvals(from) -- upvalueをスタックから逃がす処理 from = from or 0 for k,u in pairs(uvcache) do if from<=k and not rawequal(u.base, u) then u[1] = u.base[u.idx] u.base = u u.idx = 1 uvcache[k] = nil -- 逃がし終わったらテーブルから消す end end end
uvcacheにスタック上のインデックスとUpvalueの対応関係を保持しておいて、RETURNの時にcloseupval関数でUpvalue自身の中に値を逃がしてます。「逃がし終わったらテーブルから消す」のを忘れてるバグに長いこと気づかず苦労しました。
そんなところでしょうか。ではまた次回!