初めての Ruby ソースコードリーディング@ルノアール

公開日: : Ruby

記事内に広告を含む場合があります。記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。

オープンソースカンファレンスの懇親会の後に、数名とコーヒーでも、という流れになり、ルノアールへ。その席にて、とある方から「Rubyは起動時にメモリをごっそり確保して、以降、必要な時にそこから割り当てていくような方式なので嫌い」という話を聞いた。「へー、そんな実装になっているのかー」と思いつつ、その発言がキッカケで、今までやりたかった「Rubyのソースコードリーディング」をその場で開始することに。ルノアールでRubyのソースコードを読むことになるとは思わなかった。

まずはRubyのソースコードをget。


% wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz

解凍。


% tar jxf ruby-1.8.6-p111.tar.bz2

中身を見てみる。


% cd ruby-1.8.6-p111
% ls
COPYING class.c enum.c main.c range.c string.c
COPYING.ja common.mk env.h marshal.c re.c struct.c
ChangeLog compar.c error.c math.c re.h test
GPL config.guess eval.c mdoc2man.rb regex.c time.c
LEGAL config.sub ext misc regex.h util.c
LGPL configure file.c missing ruby.1 util.h
Makefile.in configure.in gc.c missing.h ruby.c variable.c
NEWS cygwin hash.c mkconfig.rb ruby.h version.c
README defines.h ia64.s node.h rubyio.h version.h
README.EXT dir.c inits.c numeric.c rubysig.h vms
README.EXT.ja distruby.rb install-sh object.c rubytest.rb win32
README.ja djgpp instruby.rb pack.c runruby.rb wince
ToDo dln.c intern.h parse.c sample x68
array.c dln.h io.c parse.y signal.c
bcc32 dmydln.c keywords prec.c sprintf.c
bignum.c dmyext.c lex.c process.c st.c
bin doc lib random.c st.h

わー、すごく分かりやすいファイル名!!ひとまず main.c を見てみる。


int
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
#ifdef _WIN32
NtInitialize(&argc, &argv);
#endif
#if defined(__MACOS__) && defined(__MWERKS__)
argc = ccommand(&argv);
#endif

{
RUBY_INIT_STACK
ruby_init();
ruby_options(argc, argv);
ruby_run();
}
return 0;
}

ruby_init() が怪しい。


% find . -maxdepth 1 -name "*.c" | xargs grep "ruby_init()"
./eval.c:ruby_init()
./eval.c: _macruby_init();
./eval.c: _vmsruby_init();
./main.c: ruby_init();

eval.c を読んでみる。


void
ruby_init()
{
static int initialized = 0;
static struct FRAME frame;
static struct iter iter;
int state;

if (initialized)
return;
initialized = 1;
#ifdef HAVE_NATIVETHREAD
ruby_thid = NATIVETHREAD_CURRENT();
#endif

ruby_frame = top_frame =
ruby_iter =

#ifdef __MACOS__
rb_origenviron = 0;
#else
rb_origenviron = environ;
#endif

Init_stack((void*)&state);
Init_heap();
PUSH_SCOPE();
ruby_scope->local_vars = 0;
ruby_scope->local_tbl = 0;
top_scope = ruby_scope;
/* default visibility is private at toplevel */
SCOPE_SET(SCOPE_PRIVATE);

Init_heap() が怪しい。


% find . -maxdepth 1 -name "*.c" | xargs grep "Init_heap()"
./eval.c: Init_heap();
./gc.c:Init_heap()

gc.c を読んでみる。


void
Init_heap()
{
if (!rb_gc_stack_start) {
Init_stack(0);
}
add_heap();
}

add_heap() がおそらく。


static void
add_heap()
{
RVALUE *p, *pend;

if (heaps_used == heaps_length) {
/* Realloc heaps */
struct heaps_slot *p;
int length;

heaps_length += HEAPS_INCREMENT;
length = heaps_length*sizeof(struct heaps_slot);
RUBY_CRITICAL(
if (heaps_used > 0) {
p = (struct heaps_slot *)realloc(heaps, length);
if (p) heaps = p;
}
else {
p = heaps = (struct heaps_slot *)malloc(length);
});
if (p == 0) rb_memerror();
}

あった。おそらくはここがそう。初回は malloc して、足らなくなったら realloc してるみたい。heap 全体は struct heaps_slot で管理してるっぽい。

言語処理系のソースを始めて読んでみたけれど、思っていたよりも楽に読めるものなのだなあ。今度 Python のソースコードでも読んでみようっと。キッカケをくれた某氏に感謝。

関連記事

サンフランシスコのピア39にあるチャウダーズでクラムチャウダーを食す!

lolipop アップルの開発者向けイベント「WWDC2014」

ミスドのカルピスドーナツとカルピスポンデリングを食べてみた!

ミスドで期間限定のカルピスコラボ商品「カルピスドーナツ」と「カルピ

十三カレー計画で牛すじカレーネギのせを食す!(大阪・十三)

「iPhoneアプリ開発キャンプ@大阪」のランチで、十三カレー計画

大阪・難波の加寿屋 法善寺でかすうどんを食す。ランチタイムはおにぎり2個まで無料!

大阪・難波の加寿屋 法善寺 (かすうどん KASUYA)で、かす

ライブドアブログで運営していた「あきお商店」を「卵は世界である」に改名しました

少し前からライブドアブログで「あきお商店」というブログをやって

→もっと見る

PAGE TOP ↑