トップ

Konoha memo

内容について

konoha のソースコードを読んでみてのメモです。内容の正確さは保証しません

コメント等ありましたらプロファイルにあるメイルアドレスのほうまでお願いします

konoha_t 型

include/konoha/konoha_t.h の中で定義

 853 #define KONOHA_MAGIC        314159
 854 
 855 typedef struct konoha_t {
 856         knh_uintptr_t  magic;
 857         Ctx *ctx;
 858 } konoha_t ;

konoha_t を引数にとる関数はいくつかある

Linux LKM 用のソース( obsolete/lkm.c )の中で struct konohadev_t のメンバになっている

 31 struct konohadev_t {
 32     dev_t id;
 33     struct cdev cdev;
 34     konoha_t  konoha;
 35     char* buffer;
 36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
 37     struct semaphore sem;
 38 #endif
 39 };

通常のインタプリタでは、main( src/konoha.c )が konoha_open(4096) ( src/main/runtime.c )を呼んで、konoha_t が作られる( konoha_t を返す関数は konoha_open のみ)。konoha_open は konoha_t を構造体の値返しで返す。main 内では konoha という変数名で、値渡しで、呼び出す関数に渡している

konoha_t を引数にとる関数は全体から見るとわずかで、その中身の Ctx * を引数にとる関数が多い

konoha_t を引数にとる関数は konoha_* 、Ctx * を引数にとる関数は knh_* という命名規則があるようだ

src/konoha.c

 34 int main(int argc, char **argv)
 35 {
 36 #if defined(K_USING_BTRON)
 37         char **args = knh_tcstoeucs(argc, argv);
 38 #else
 39         char** args = (char**) argv;
 40 #endif
 41         konoha_t konoha = konoha_open(4096);

src/main/runtime.c

576 KNHAPI(konoha_t) konoha_open(size_t stacksize)
577 {
578         konoha_t k = {KONOHA_MAGIC};
579         konoha_init();
580         if(stacksize < K_STACKSIZE) stacksize = K_STACKSIZE;
581         {
582                 Ctx *ctx = new_RootContext();
583                 k.ctx = ctx;
584         }
585         return k;
586 }

konoha_open の引数はスタックサイズとなっているが、参照しているバージョンでは使われていない

Ctx についてはここでは深追いしない

KONOHA_MAGIC はなんのためにあるのか

include/konoha/konoha_t.h に以下のようなマクロがある

 862 #define KONOHA_CHECK_(konoha) \
 863         if(konoha.magic != KONOHA_MAGIC) { \
 864                 KNH_SYSLOG(NULL, LOG_ERR, "this is not a Konoha Scripting Engine"); \
 865                 return; \
 866         }\
 867 
 868 #define KONOHA_CHECK(konoha, value) \
 869         if(konoha.magic != KONOHA_MAGIC) { \
 870                 KNH_SYSLOG(NULL, LOG_ERR, "this is not a Konoha Scripting Engine"); \
 871                 return value; \
 872         }\

konoha_t を引数にとって、マジックが一致するかを見て、一致しなければ関数を終了させるマクロである

konoha_close( src/main/runtime.c )、konoha_load, konoha_eval(コメントアウトされている)( src/langc/script.c )、その他 src/main/konoha_api.c にあるいくつかの、konoha_t を引数にとる関数の先頭で、引数として渡された konoha_t のチェックに利用している

Konoha の初期化

src/konoha.c にある main の頭から追ってみる

 36 #if defined(K_USING_BTRON)
 37         char **args = knh_tcstoeucs(argc, argv);
 38 #else
 39         char** args = (char**) argv;
 40 #endif

BTRON (T-Shell) だったら引数をTRONコードからEUCに変換している。knh_tcstoeucs は T-Shell の? tstring.h にある tcstoeucs のラッパ。obsolete/tb.c にある

 41         konoha_t konoha = konoha_open(4096);

konoha_open を読んでいく

src/main/runtime.c

576 KNHAPI(konoha_t) konoha_open(size_t stacksize)
577 {
578         konoha_t k = {KONOHA_MAGIC};
579         konoha_init();
580         if(stacksize < K_STACKSIZE) stacksize = K_STACKSIZE;
581         {
582                 Ctx *ctx = new_RootContext();
583                 k.ctx = ctx;
584         }
585         return k;
586 }

konoha_init( src/main/konoha_api.c )は konoha_open からしか呼ばれない

  50 #ifdef K_USING_THREAD
  51 static volatile knh_thread_key_t ctxkey;
  59 void konoha_init(void)
  60 {
  61         static int isInit = 0;
  62 #ifdef K_USING_THREAD
  63         if(isInit == 0) {
  64                 knh_thread_key_create((knh_thread_key_t*)&ctxkey);
  65         }
  66 #endif
  67         knh_srand(0);
  68         isInit = 1;
  69 }

knh_thread_key_create は pthread_key_create のラッパ(現状。src/main/thread.c )。

ctxkey は src/main/konoha_api.c の中の knh_*Context という名前の関数から参照されている。Konoha は、スレッドを利用する場合、コンテキストへのポインタ( Ctx * )に Thread local storage 経由でアクセスするのだが、そのアクセスのためのキーを作成している。キーの初期化は 1 回でいいのでそのように書かれている。マルチスレッドで呼ばれない前提のコード

knh_srand は、ここと、src/main/apidata/numberapi.c の System_setRandomSeed 関数が呼んでいる。定義は src/main/number.c にある

 61 void knh_srand(knh_uint_t seed)
 62 {
 63         if(seed == 0) {
 64 #ifdef K_USING_POSIX
 65                 seed = (knh_uint_t)time(NULL) + getpid();
 66 #else
 67                 seed = (knh_uint_t)time(NULL);
 68 #endif
 69         }
 70 #ifndef KONOHA_ON_LKM
 71 #ifdef K_USING_INT32
 72         init_genrand((unsigned long)seed);
 73 #else
 74         init_genrand64((unsigned long long int)seed);
 75 #endif
 76 #endif /* KONOHA_ON_LKM */
 77 }

seed が 0 なら time と getpid を元に seed を設定して、init_genrand を呼んでいる。init_genrand(64)? はこのモジュール内にはなく、src/ext/mt19937(ar|-64).c の中にある

konoha_open に戻って

580         if(stacksize < K_STACKSIZE) stacksize = K_STACKSIZE;

設定されたスタックが小さい( include/konoha/konoha_config.h で #define K_STACKSIZE 1024 と設定されている)ようなら大きくしている。が、結局使われていない

582                 Ctx *ctx = new_RootContext();

new_RootContext を見る。これは src/main/runtime.c のローカル関数で、konoha_open からしか呼ばれていない

304 static Ctx* new_RootContext(void)
305 {
306         knh_Context_t *ctx = (knh_Context_t*)new_hContext(NULL);

new_hContext もローカル関数で、new_RootContext からしか呼ばれていない。しかし、コードを見ると、id=0 のコンテキストを引数に取って呼ぶような場合もあるように書かれている

 67 volatile static size_t ctxid_counter = 1;
 68 
 69 static knh_Context_t* new_hContext(Ctx *ctx0)
 70 {
 71         knh_Context_t *ctx;
 72         if(ctx0 == NULL) {
 73                 ctx = (knh_Context_t*)malloc(sizeof(knh_Context_t));
 74                 ctx0 = ctx;
 75                 ctx->ctxid = 0;
 76         }
 77         else {
 78                 KNH_ASSERT_CTX0(ctx0);
 79                 ctx = (knh_Context_t*)KNH_MALLOC(ctx0, sizeof(knh_Context_t));
 80                 ctx->ctxid = ctxid_counter;
 81                 ctxid_counter++;
 82         }
 83         knh_bzero(ctx, sizeof(knh_Context_t));
 84         ctx->h.magic = K_OBJECT_MAGIC;
 85 #ifdef KNH_HOBJECT_REFC
 86         ctx->h.refc = K_RCGC_INIT;
 87 #endif
 88         ctx->h.flag = FLAG_CTX(FLAG_Context);
 89         ctx->h.bcid = CLASS_Context;
 90         ctx->h.cid  = CLASS_Context;
 91         ctx->h.ctxid = 0;
 92         ctx->h.lock  = LOCK_NOP;
 93         ctx->unusedObject = NULL;
 94         ctx->unusedObjectSize = 0;
 95         ctx->parent = ctx0;
 96         ctx->fsweep = knh_getDefaultSweepFunc();
 97         ctx->unusedContext = NULL;
 98         return ctx;
 99 }

ここで main に戻ってみると、konoha_open のあとは konoha_parseopt → konoha_shell か konoha_load konoha_runMain → konoha_close となっている

コンテキストについて読むのは次の節として、konoha_close( src/main/runtime.c )をざっと見る

597 KNHAPI(void) konoha_close(konoha_t konoha)
598 {
599         knh_Context_t *ctx;
600         KONOHA_CHECK_(konoha);
601         ctx = (knh_Context_t*)konoha.ctx;
602         if(ctx->share->threadCounter > 1) {
603                 fprintf(stderr, "Many threads are still running... Found %d threads", (int)ctx->share->threadCounter);
604                 return;
605         }
606         knh_Context_traverse(konoha.ctx, ctx, ctx->fsweep);
607 }

引数チェック(マジックナンバーの確認)をして、threadCounter が 1 より大きいようならメッセージを表示してそのまま戻る...が、この版を grep した限りでは threadCounter は 1 に初期化するだけで他からアクセスしてない。konoha 5 のコードでは src/main/systemtable.c の new_ThreadContext と knh_ThreadContext_dispose でインクリメント・デクリメントしている

knh_Context_traverse は、Konoha の GC 処理のルーチンで、マークフェーズ・スイープフェーズの両方でコンテキストのオブジェクトツリーを辿るのに使うルーチンである。ここでは ctx->fsweep を引数に指定しているのでスイープフェイズの呼び出しと同じ処理をおこなっている

コンテキストも Konoha のオブジェクトとして扱われている。ただし、マークルーチン中に IS_Context(o) というマクロでオブジェクトがコンテキストの場合だけ特別扱いして knh_Context_traverse を呼んでいたり、IS_SWEEP(ftr) というマクロ( include/konoha/konoha_t.h )で

 691 #define knh_Object_sweep       (ctx)->fsweep
 692 #define IS_SWEEP(f)            (f == knh_Object_sweep)

マクロが現れる位置で ctx を参照して、トラバース関数が ctx->fsweep と同じかどうかをチェックしていたり(どういうことなのか追い切れていない)、コンテキストはちょっと特殊な扱いをするようになっている

konoha_close から戻ったら、return 0 で main は終わる

コンテキスト

Konoha 処理系の状態が全部入っている(らしい)オブジェクト

定義は include/konoha/konoha_t.h にある

 266 typedef const struct knh_Context_t    Ctx;

const 修飾子を付けて Ctx という別名が定義されている。構造体の定義で同時に typedef して型名 knh_Context_t も定義しているが、Ctx の定義の時点では本体の定義がまだなので struct を付ける必要がある

本体の定義は以下

 804 typedef struct knh_Context_t {
 805         knh_hObject_t h;
 806         knh_Object_t        *unusedObject;
 807         size_t               unusedObjectSize;
 808 
 809         /* stack */
 810         knh_sfp_t*                   stack;
 811         knh_sfp_t*                   esp;
 812         size_t                       stacksize;
 813         knh_sfp_t*                   stacktop;
 814         knh_Ftraverse                fsweep;
 815 
 816         /* cache (stacksize * 2 + 1) */
 817         size_t                        cachesize;
 818         struct knh_Method_t         **mtdCache;
 819         struct knh_Method_t         **fmtCache;
 820         struct knh_Mapper_t         **mprCache;
 821 
 822         /* shared table */
 823         const knh_share_t           *share;
 824         knh_stat_t                  *stat;
 825 
 826         knh_flag_t                   flag;
 827         knh_ushort_t                 ctxid;
 828         const struct knh_Context_t   *parent;
 829         knh_mutex_t                  *ctxlock;
 830         const struct knh_Context_t   *unusedContext;
 831 
 832         struct knh_System_t*         sys;
 833         struct knh_Script_t*         script;
 834         struct knh_String_t*         enc;
 835         struct knh_InputStream_t*    in;
 836         struct knh_OutputStream_t*   out;
 837         struct knh_OutputStream_t*   err;
 838         struct knh_Bytes_t*          bufa;
 839         struct knh_OutputStream_t*   bufw;
 840         struct knh_Bytes_t*          bconvbuf;
 841         struct knh_DictMap_t*        props;
 842         struct knh_Gamma_t            *gma;
 843         struct knh_Array_t          *lines;
 844 
 845         knh_case_t                   caseid;
 846 //      int    hasError;
 847 //      struct knh_String_t *msgError;
 848 
 849 } knh_Context_t ;

マクロが使用される文脈で ctx という名前でコンテキストへのポインタを参照できることを前提に書かれているマクロが多数ある

頭からみてゆく

 805         knh_hObject_t h;

オブジェクトヘッダ。Konoha の全オブジェクトに共通のヘッダ

 384 typedef struct knh_hObject_t {
 385         knh_ushort_t magic; knh_flag_t  flag;
 386         knh_class_t  bcid;  knh_class_t cid;
 387         knh_ushort_t ctxid; knh_lock_t  lock;
 388 //#ifdef KNH_HOBJECT_REFC
 389         KNH_MT_VOLATILE knh_uintptr_t refc;
 390 //#endif
 391         void *meta;
 392 } knh_hObject_t ;

magic はマジックナンバー。オブジェクトの識別に使う。DBG_ASSERT_ISOBJECT というマクロがあり

 379         #define DBG_ASSERT_ISOBJECT(o)        DBG_ASSERT((o)->h.magic == K_OBJECT_MAGIC)

ガベージコレクションなどで使われている

flag はオブジェクトがイミュータブルかどうか、などをセットするフラグ

knh_flag_t は他のフラグでも共通に使われている型( knh_ClassTable_t の cflag など)なので、コードの追跡にはあまり使えない

フラグの意味については、マクロが include/konoha/konoha_name.h の 503 行から 595 行にあり、名前でだいたいどういう意味のフラグがあるのかわかる

コンテキストの場合は FLAG_CTX(FLAG_Context) で初期化している。FLAG_CTX は

 59 #ifdef KNH_DBGMODE
 60 #define FLAG_CTX(f)      (f|FLAG_Context_Verbose|FLAG_Context_Strict)
 61 #else
 62 #define FLAG_CTX(f)      (f|FLAG_Context_Strict)
 63 #endif

FLAG_Context は include/konoha/konoha_name.h で

 367 #define CFLAG_Context           ((knh_flag_t)0)
 368 #define FLAG_Context            FLAG_oflag(CFLAG_Context)

FLAG_oflag は include/konoha/konoha_class.h で #define FLAG_oflag(f) (f)

FLAG_Context_Verbose と FLAG_Context_Strict は include/konoha/konoha_name.h で

#define FLAG_Context_Verbose (knh_flag_t)(1<<2) と #define FLAG_Context_Strict (knh_flag_t)(1<<0) のように定義されている

knh_class_t 型の bcid と cid は、どちらもオブジェクトのクラスを示す id(実体は ClassTable の index )が入っていて、普通は bcid と cid は同じで bcid のほうを使う、ようである

ただし、オブジェクトが配列かイテレータの場合、bcid にコンテナ(配列かイテレータ)の id が、cid に要素の id が入るようである。src/main/class.c の knh_setClassName に以下のようなコードがある

122         if(t->bcid == cid) {
123                 KNH_INITv(t->sname, new_T(t->cspi->name));
124         }
125         else if(t->bcid == CLASS_Array || t->bcid == CLASS_IArray || t->bcid == CLASS_FArray) {
126                 knh_cwb_t cwbbuf, *cwb = knh_cwb_open(ctx, &cwbbuf);
127                 knh_write_sname(ctx, cwb->w, knh_class_p1(cid));
128                 knh_write(ctx, cwb->w, STEXT("[]"));
129                 KNH_INITv(t->sname, knh_cwb_newString(ctx, cwb));
130         }
131         else if(t->bcid == CLASS_Iterator) {
132                 knh_cwb_t cwbbuf, *cwb = knh_cwb_open(ctx, &cwbbuf);
133                 knh_write_sname(ctx, cwb->w, knh_class_p1(cid));
134                 knh_write(ctx, cwb->w, STEXT(".."));
135                 KNH_INITv(t->sname, knh_cwb_newString(ctx, cwb));
136         }

(総称型でもこのようなことをしている?)

コンテキストの場合は bcid == cid == CLASS_Context である。CLASS_Context は include/konoha/konoha_name.h の中で #define CLASS_Context ((knh_class_t)39)

ヘッダの ctxid は、そのオブジェクトが作られたコンテキストの id で、コンテキストオブジェクトの場合は 0 である(id == 0 のコンテキストの場合は自分自身の id、その他のコンテキストは id == 0 のコンテキストから作る

コンテキスト以外のオブジェクトの初期化は src/main/memory.c の new_hObject, new_Object_bcid, new_Object_init, new_Object_boxing にて

ヘッダの lock は LOCK_NOP への初期化以外は何もしてないようである LOCK_NOP の定義は include/konoha/konoha_t.h で #define LOCK_NOP ((knh_lock_t)0)

KNH_HOBJECT_REFC はリファレンスカウントガベージコレクションが有効になっていると 1 に #define される

include/konoha/konoha_t.h

 372 #ifdef K_USING_RCGC
 373 #define KNH_HOBJECT_REFC      1
 374 #endif

K_USING_RCGC は configure 時に --enable-rcgc=yes にすると定義される。デフォルトでは no

(追記) だが、konoha_config.h の中に #define K_USING_RCGC 1 とあって、強制的に設定されている

refc の修飾子 KNH_MT_VOLATILE は include/konoha/konoha_t.h で

  55 #ifdef K_USING_THREAD
  56 #define KNH_MT_VOLATILE    volatile
  57 #else
  58 #define KNH_MT_VOLATILE
  59 #endif

のように定義されている。refc はリファレンスカウントガベージコレクションのリファレンスカウント

コンテキストでは K_RCGC_INIT に直接初期化している。他のオブジェクトではマクロを使っている

meta は src/langc/term.c knh_InputStream_parseToken で何かに使っている他は使ってないようだ

以上でヘッダ終わり。コンテキストの場合、ヘッダの初期化は src/main/runtime.c の new_hContext でおこなっている

 84         ctx->h.magic = K_OBJECT_MAGIC;
 85 #ifdef KNH_HOBJECT_REFC
 86         ctx->h.refc = K_RCGC_INIT;
 87 #endif
 88         ctx->h.flag = FLAG_CTX(FLAG_Context);
 89         ctx->h.bcid = CLASS_Context;
 90         ctx->h.cid  = CLASS_Context;
 91         ctx->h.ctxid = 0;
 92         ctx->h.lock  = LOCK_NOP;

knh_Context_t の本体に戻って続きを見てゆくわけだが

 806         knh_Object_t        *unusedObject;
 807         size_t               unusedObjectSize;

初期化が runtime.c の new_hContext でおこなわれる

 93         ctx->unusedObject = NULL;
 94         ctx->unusedObjectSize = 0;

他は全て memory.c の中で操作されている

これは konoha のメモリフレームワークで以下のように使われている

マクロ KNH_CHECK_UNUSED_OBJECT

115 #define KNH_CHECK_UNUSED_OBJECT(ctx) { \
116                 if(unlikely(ctx->unusedObject == NULL)) { \
117                         KNH_ASSERT(ctx->unusedObjectSize == 0); \
118                         ((knh_Context_t*)ctx)->unusedObject = new_UnusedObject(ctx); \
119                 } \
120                 DBG_checkOPage(ctx, ctx->unusedObject TRACEDATA);\
121         } \
122 

unusedObject が NULL なら unusedObjectSize をチェックして、new_UnusedObject で新しく unusedObject を作り? 設定している(unusedObjectSize はここで設定しなくていいのか? ← 問題ない。new_UnusedObject の中で設定している。というか ctx->unusedObject も new_UnusedObject の中で副作用で設定していて、return ctx->unusedObject されたものをまたマクロで ctx->unusedObject に設定している(冗長な代入?))

new_UnusedObject は 50 行ぐらいみっちりとコードがあるので詳しくはあとまわし

DBG_checkOPage を見る

133 static void DBG_checkOPage(Ctx *ctx, void *used TRACEARG)
134 {
135         size_t pageindex, size = ctx->share->OPageTableSize;
136         for(pageindex = 0; pageindex < size; pageindex++) {
137                 void *ptr = ctx->share->OPageTable[pageindex].opage;
138                 if(ptr < used && used < ptr + SIZEOF_OPage) return;
139         }
140         TRACE_SYSLOG(ctx, LOG_ERR, "not paged object %p", used);
141 }

ctx->share の(share の意味は今のところ不明)OPageTable のテーブルの中にあるかどうかをチェックしている( OPageTable は new_UnusedObject の中などで操作している)。LOG_ERR なので必ず見つかるはず、というロジックのようだ

TRACEDATA と TRACEARG というあやしいトークン(コンマがない!)は konoha_debug.h の中で次のように定義されている

 11 #define TRACEARG          ,char *_file, int _line, char *_func
 12 #define TRACEDATA         ,(char*)__FILE__, (int)__LINE__, (char*)__FUNCTION__

KNH_OBJECT_REUSE を見る

123 #define KNH_OBJECT_REUSE(ctx, used) { \
124                 DBG_checkOPage(ctx, used TRACEDATA);\
125                 used->ref = ctx->unusedObject;\
126                 ((knh_Context_t*)ctx)->unusedObject = used;\
127                 ((knh_Context_t*)ctx)->unusedObjectSize += 1;\
128         }\
129 

OPageTable にあるかどうかをチェックして、used で指定されたオブジェクトを ctx->unusedObject につないで unusedObjectSize をインクリメント

ref は knh_Object_t 型で定義されている void * 型の要素で

 394 typedef struct knh_Object_t {
 395         knh_hObject_t h;
 396         void *ref;
 397         void *ref2_unused;
 398         void *ref3_unused;
 399 } knh_Object_t ;

状況によってあれこれに使われるもののようである。ここでは unusedObject がフリーリストになっていて、その next ポインタとして使われている

スタック

 809         /* stack */
 810         knh_sfp_t*                   stack;
 811         knh_sfp_t*                   esp;
 812         size_t                       stacksize;
 813         knh_sfp_t*                   stacktop;
 814         knh_Ftraverse                fsweep;

fsweep 以外は src/main/stack.c にほとんどの操作するコードがある

knh_sfp_t 型は include/konoha/konoha_t.h で

 485 typedef struct knh_sfp_t {
 486         union {
 487                 void   *ref;
 488                 Object *o;
 489                 struct knh_Int_t    *i;
 490                 struct knh_Float_t  *f;
 491                 struct knh_Class_t  *c;
 492                 struct knh_String_t *s;
 493                 struct knh_Bytes_t  *ba;
 494                 struct knh_Pair_t   *pair;
 495                 struct knh_Tuple_t  *tuple;
 496                 struct knh_Range_t  *range;
 497                 struct knh_Array_t  *a;
 498                 struct knh_IArray_t  *ia;
 499                 struct knh_FArray_t  *fa;
 500                 struct knh_Iterator_t *it;
 501                 struct knh_DictMap_t  *dmap;
 502                 struct knh_DictSet_t  *dset;
 503                 struct knh_HashMap_t  *hmap;
 504                 struct knh_HashSet_t *hset;
 505                 struct knh_Closure_t *cc;
 506                 struct knh_InputStream_t  *in;
 507                 struct knh_OutputStream_t *w;
 508                 struct knh_Method_t *mtd;
 509                 struct knh_Mapper_t *mpr;
 510                 struct knh_Exception_t *e;
 511                 struct knh_ExceptionHandler_t *hdr;
 512                 struct knh_NameSpace_t *ns;
 513                 struct knh_Glue_t   *glue;
 514                 struct knh_ObjectField_t *ox;
 515         };
 516         union {
 517                 knh_boolean_t bvalue;
 518                 knh_int_t     ivalue;
 519                 knh_uint_t    uvalue;
 520                 knh_float_t   fvalue;
 521                 knh_uint64_t  data;
 522                 knh_code_t    *pc;
 523                 knh_callinfo_t ci;
 524         };
 525 } knh_sfp_t;

と定義されている。スタックの中身はこれらのどれかと決まっている?

stack.c の knh_stack_initexpand を見るとよくわからないがキャッシュの初期化などもやっている

fsweep は knh_Ftraverse 型で、

538 typedef void (*knh_Ftraverse)(Ctx *ctx, Object *);

という定義になっている

691 #define knh_Object_sweep       (ctx)->fsweep

というマクロが参照しており、src/main/runtime.c と src/main/memory.c に fsweep を参照するコードがある

src/main/runtime.c では new_hContext という関数で knh_getDefaultSweepFunc() が返す関数ポインタに初期化している。knh_traverseSharedContext という関数の中に、ctx->fsweep を knh_Object_finalSweep (なにもしない関数)に書き換えているコードがある。konoha_close という関数で、knh_Context_traverse(konoha.ctx, ctx, ctx->fsweep); のように参照している

knh_getDefaultSweepFunc は src/main/memory.c の中にあり knh_Object_RCsweep を返している

src/main/memory.c のほうは knh_System_gc という関数の中で、いったん ctx->fsweep を退避して knh_Object_finalSweep を設定し、あとで元に戻す、ということをやっている

fsweep を直接参照してる箇所は以上である