ひとり勉強会

ひとり楽しく勉強会

おまけ:LuLu (3)

ちょっとソースコードが酷いですごめんなさい。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自身の中に値を逃がしてます。「逃がし終わったらテーブルから消す」のを忘れてるバグに長いこと気づかず苦労しました。
そんなところでしょうか。ではまた次回!