GLOBAL_REF と GLOC とか Scm_FindBindind() とか

GLOBAL_REF マクロを見ていく中で、オペランドが指すオブジェクトが Global LOCation オブジェクトかどうかを確認する処理がある。
とりあえず、この Global LOCation というナニを色々確認してみる事に。
# イケれば module における変数束縛の管理方法云々についてもナニ
ちなみに ScmGloc 型に関する readingGauche のエントリは以下

上記コンテンツの概要説明によれば

Gauche では、グローバル変数束縛は module によって管理される仕組みになっているらしい

との事。これは_Gauche:グローバル変数参照の最適化_にもその記述がありますな。ただ、このドキュメントには

グローバル変数参照は、Scm_FindBinding(module.c) によって解決される。これは指定モジュールおよびそこから可視のモジュール中から、指定された名前に束縛されている GLOC (global location) オブジェクトを探して返すもの。

という記述もある。最初は Scm_FindBinding() 手続きが GLOC なオブジェクトを作って戻すのかな? と思ってたのでちょっとハズしてしまったカンジ。
上記ドキュメントにて Scm_FindBinding() 手続きでは以下の順で束縛を探索、とある。

  1. 指定モジュール (base)
  2. import しているモジュールとその親モジュール
  3. 親モジュール

これらそれぞれについて Scm_HashTableRef() で symbol を探索。この手続きの掘削でハマッた記憶がナニ。掘削の痕跡が微妙、と言いつつ自分ブログを検索してみたら以下なソレが出てきました。

むむ、と言いつつ確認。あまり参考にならないな。きちんと理解できていないのが敗因と思われます。もう少し自分の参考になる記録を残すべく頑張ってみます。

整理しつつ続行

GLOBAL_REF マクロの定義によれば

        FETCH_OPERAND(v);                                               \
        if (!SCM_GLOCP(v)) {                                            \
            VM_ASSERT(SCM_IDENTIFIERP(v));                              \

な記述にてオペランド

  • GLOC なオブジェクト
  • ScmIdentifire なオブジェクト

限定になる模様。これって_グローバル変数参照の最適化_の_前提となる仕組み_の項に記述あり。ここの記述によれば、コンパイル時にマクロや定数として展開されなかった場合、GREF インストラクションのオペランドとして、該当変数が identifier として埋め込まれる、とある。このあたりの前提となる仕組みが理解できてない、というか掘り下げれてないあたりが微妙。
う、でも Scm_FindBinding() 手続きの以下のナニで

    v = Scm_HashTableRef(m->table, SCM_OBJ(symbol), SCM_FALSE);
    if (SCM_GLOCP(v)) {
        gloc = SCM_GLOC(v);
        if (!SCM_UNBOUNDP(gloc->value)) goto found;
    }

戻ってきた v が GLOC オブジェクトで value 属性が SCM_UNBOUNDP なケイスがあるのか。てーか module の table 属性を探索するナニが具体的に見えてないのが気持ちが悪い原因なのか。

module.c 見てみる

先頭あたりに以下なコメント。

/*
 * Modules
 *
 *  A module maps symbols to global locations.
 *  The mapping is resolved at the compile time.
 *  Scheme's current-module is therefore a syntax, instead of
 *  a procedure, to capture compile-time information.
 *

最後らへんが若干微妙。module.c を table 属性で search してみたら以下な手続きに hit

static void init_module(ScmModule *m, ScmSymbol *name)
{
    m->name = name;
    m->imported = m->exported = m->depended = SCM_NIL;
    m->exportAll = FALSE;
    m->parents = defaultParents;
    m->mpl = Scm_Cons(SCM_OBJ(m), defaultMpl);
    m->table = SCM_HASH_TABLE(Scm_MakeHashTableSimple(SCM_HASH_EQ, 0));
}

最後のソレがアレ。SCM_HASH_EQ な hash table が生成されて云々ですか。このあたりは何度か見てますね。

  • Scm_MakeHashTableSimple で領域作って Scm_HashCoreInitSimple に渡す
  • type は上記の通り SCM_HASH_EQ で、hash_core_predef_procs から手続きげと
    • accessfn は address_access
    • hashfn は address_hash
    • cmpfn は address_cmp
  • 最後に hash_core_init で属性に設定

どうやら init_module という関数はノーチェックだった模様。それにしてもこのあたりボトルネックらしく色々と工夫やら調査やらをされているみたい。

むむ

未だに微妙なのが Global LOCation なオブジェクトなのか。あ、それ以外にもあるな。このあたりの解が compile.scm なあたり (と類推してるんですが) なのが微妙。