内容紹介
もっと知りたい、Rubyのしくみ
VMベースのインタプリタ型言語処理系であるRubyがコードをどのように解釈し、どうやって実行するか、そのしくみを解説。Rubyについての基礎知識がなくても、図版と短いコードの実験を多用した構成により、そのしくみについて理解することができます。
実務でRubyは使えるけれど、基礎知識について自信がない人や、学びたくてもまとまった時間がとれずに悩んでいる人などもっとRubyを活用するためにRubyを知りたい人に最適。
Rubyインタプリタを題材にプログラミング言語処理系の仕組みを解説するNo Starch Press社の“Ruby Under a Microscope” の翻訳発行です。
日本語版には、Rubyの開発者であるまつもとゆきひろ氏の序文とYARVの開発者である笹田耕一氏の付録が加筆されています。
このような方におすすめ
言語処理系が動作する仕組みを学びたいと考えており、Rubyにも興味があるプログラマ
アプリケーションの動作基盤であるrubyが動く仕組みを理解したいと思うものの、コンパイラの教科書はハードルが高いと考えているRailsユーザなど
目次
主要目次
第1章 字句解析と構文解析
第2章 コンパイル
第3章 Rubyはどのようにコードを実行するか
第4章 制御構造とメソッドディスパッチ
第5章 オブジェクトとクラス
第6章 メソッド探索と定数探索
第7章 ハッシュテーブル:Ruby内部の働き者
第8章 Lispから借りてきたアイデア
第9章 メタプログラミング
第10章 JRuby:JVM上のRuby
第11章 Rubinius:Rubyで実装されたRuby
第12章 MRI・JRuby・RubiniusにおけるGC
付録A さらにそのほかのRuby仮想マシン
詳細目次
日本語版序文
序文
謝辞
はじめに
対象読者
検証にRubyを使う
どのRuby処理系なの?
本書の構成
第1章 字句解析と構文解析
字句解析:Rubyを構成する言葉
parser_yylex 関数
実験1-1:Ripperを使ってさまざまなRubyスクリプトを字句解析する
構文解析:Rubyはコードをどのように理解するか
LALR 構文解析アルゴリズムを理解する
実際のRubyの文法規則をいくつか
Bisonの文法規則を読む
実験1-2:Ripperを使ってさまざまなRubyスクリプトを構文解析する
まとめ
第2章 コンパイル
Ruby 1.8 にコンパイラはない
Ruby 1.9 以降はコンパイラを導入する
単純なスクリプトをRubyはどうコンパイルするか
ブロック呼び出しのコンパイル
RubyはAST の中をどう反復していくか
実験2-1:YARV 命令を表示する
ローカルテーブル
オプション引数のコンパイル
キーワード引数のコンパイル
実験2-2:ローカルテーブルを表示する
まとめ
第3章 Rubyはどのようにコードを実行するか
YARVの内部スタックとRubyのコールスタック
Rubyが単純なスクリプトをどう実行するかを見ていく
ブロック呼び出しの実行
YARV命令を間近に見てみる
実験3-1:Ruby 2.0/Ruby 1.9 とRuby 1.8 のベンチマーク比較
Ruby変数のローカルアクセスと動的アクセス
ローカル変数アクセス
メソッド引数はローカル変数とみなされる
動的変数アクセス
Cの世界でEPのはしごを上る
実験3-2:特殊変数を調査する
特殊変数リストの決定版
まとめ
第4章 制御構造とメソッドディスパッチ
Rubyがどうやってif 文を実行するか
あるスコープから別のスコープへジャンプする
捕捉テーブル
捕捉テーブルの別の利用方法
実験4-1:Rubyがループを内部でどう実装しているかをテストする
send 命令:Rubyで最も複雑な制御構造
メソッド探索とメソッドディスパッチ
11種類のメソッドタイプ
通常のメソッド呼び出し
通常のメソッド向け引数の準備
組み込みメソッド呼び出し
attr_readerとattr_writerの呼び出し
attr_readerとattr_writerにおけるメソッドディスパッチの最適化
実験4-2:Rubyがキーワード引数をどう実装しているかの調査
まとめ
第5章 オブジェクトとクラス
Rubyオブジェクトの内側
klassとivptrの調査
クラスの2つのインスタンスの可視化
一般的なオブジェクト
単純なRubyの値は構造体を全く必要としない
一般的なオブジェクトはインスタンス変数を持つか
RBasic構造体とRObject構造体の定義を読む
Rubyは一般的なオブジェクト用のインスタンス変数をどこに保存するか?
実験5-1:新しいインスタンス変数を保存するのにどれくらい時間がかかるか?
RClass 構造体の内側は何
継承
クラスインスタンス変数vs. クラス変数
クラス変数の取得と設定
定数
実際のRClass構造体
RClass構造体の定義を読む
実験5-2:Rubyはクラスメソッドをどこに保存する?
まとめ
第6章 メソッド探索と定数探索
Rubyがモジュールをどう実装しているか
モジュールはクラスである
クラスにモジュールをインクルードする
Rubyのメソッド探索アルゴリズム
メソッド探索の例
実際のメソッド探索アルゴリズム
Rubyにおける多重継承
グローバルメソッドキャッシュ
インラインメソッドキャッシュ
Rubyのメソッドキャッシュをクリアする
あるクラスに2つのモジュールをインクルードする
あるモジュールを別のモジュールにインクルードする
Module#prependの例
RubyがModule#prepend をどう実装しているか
実験6-1:インクルードした後でモジュールを変更する
クラスはモジュールのメソッドを後で確認する
クラスはインクルードされたサブモジュールを後では確認しない
インクルードされたクラスは元のモジュールとメソッドテーブルを共有する
Rubyがモジュールをどうコピーしているかを詳しく見る
定数探索
スーパークラス内の定数を見つける
Rubyはどうやって親の名前空間内の定数を見つけるか?
Rubyにおけるレキシカルスコープ
新しいクラスやモジュール用に定数を生成する
レキシカルスコープを使って親の名前空間内の定数を見つける
Rubyの定数探索アルゴリズム
実験6-2:Rubyはどの定数をはじめに見つけるのか?
Rubyの実際の定数探索アルゴリズム
まとめ
第7章 ハッシュテーブル:Ruby内部の働き者
Rubyにおけるハッシュテーブル
ハッシュテーブルに値を保存する
ハッシュテーブルから値を取り出す
実験7-1:さまざまなサイズのハッシュテーブルから値を取り出す
ハッシュテーブルを拡張して、より多くの値を格納する仕組み
ハッシュの衝突
エントリの再ハッシュ
Rubyはハッシュテーブル内のエントリをどう再ハッシュするか?
実験7-2:さまざまなサイズのハッシュに新しい要素を1つ追加する
マジックナンバー57と67はどこからくるのか
Rubyはハッシュ関数をどう実装しているか
実験7-3:ハッシュのキーとしてオブジェクトを使用する
Ruby 2.0におけるハッシュ最適化
まとめ
第8章 Lisp から借用したアイデア
ブロック:Rubyにおけるクロージャ
Rubyのブロック呼び出しを一歩ずつ確認する
1975 年から借用したアイデア
rb_block_tとrb_control_frame_t構造体
実験8-1:whileループとeachにブロックを渡すのとどちらが速いか
ラムダとProc:関数を第一級市民として扱う
スタックvs. ヒープメモリ
Rubyが文字列の値をどう保存するかを詳しく見る
Rubyはラムダをどう作るか
Rubyはラムダをどう呼び出すか
Proc オブジェクト
実験8-2:ラムダを呼び出した後でローカル変数を変更する
同じスコープでラムダを1回以上呼び出す
まとめ
第9章 メタプログラミング
メソッドを定義する別のやり方
通常のメソッド定義処理
オブジェクトのプレフィックスを使ってクラスメソッドを定義する
新しいレキシカルスコープを使ってクラスメソッドを定義する
特異クラスを使ってメソッドを定義する
レキシカルスコープ内の特異クラスを使ってメソッドを定義する
Refinementsを作成する
Refinementsを使用する
実験9-1:わたしは誰? レキシカルスコープを使うとselfはどう変わるか
トップレベルスコープでのself
クラススコープでのself
メタクラススコープでのself
クラスメソッドの内側でのself
メタプログラミングとクロージャ:eval、instance_eval、binding
コードを生成するコード
bindingと共にevalを呼び出す
instance_evalを使う例
Rubyのクロージャにおけるもう1つの重要な側面
instance_evalはself をレシーバに変更する
instance_evalは新しいレキシカルスコープ用に特異クラスを作成する
ブロック用のレキシカルスコープをRubyはどう監視し続けるか
実験9-2:メソッドを定義するためにクロージャを使う
define_methodを使う
メソッドはクロージャとして機能する
まとめ
第10章 JRuby:JVM上のRuby
MRIとJRubyでプログラムを実行する
JRubyはコードをどうパースし、コンパイルするか
JRubyはコードをどう実行するか
RubyクラスをJavaクラスを使って実装する
実験10-1:JRubyのJITコンパイラを観察する
実験コード
-J-XX:+PrintCompilationオプションの使用
JITはJRubyプログラムを高速化するか
JRubyとMRI における文字列
JRubyとMRI は文字列データをどう保存するか
コピー・オン・ライト
実験10-2:コピー・オン・ライトの性能を計測する
ユニークで共有されていない文字列の生成
実験コード
コピー・オン・ライトの視覚化
共有文字列を編集することは速度を落とす
まとめ
第11章 Rubinius:Rubyで実装されたRuby
Rubiniusカーネルと仮想マシン
字句解析と構文解析
Rubyを使ってRubyをコンパイルする
Rubiniusバイトコード命令列
RubyとC++とで一緒に動く
RubyのオブジェクトをC++オブジェクトで実装する
実験11-1:MRIとRubiniusのバックトレースの比較
Rubiniusのバックトレース
RubiniusとMRIの配列
MRIの配列の内側
RArray構造体の定義
Rubiniusの配列の内側
実験11-2:RubiniusのArray#shiftの実装を調査する
Array#shiftを読む
Array#shiftを変更する
まとめ
第12章 MRI・JRuby・RubiniusにおけるGC
ガベージコレクションは3つの問題を解決する
MRIにおけるガベージコレクション:マークスイープ
フリーリスト
MRIの複数のフリーリストの用途
マーク
MRIは生きているオブジェクトをどうマークするか
スイープ
遅延スイープ
RVALUE構造体
マークスイープのデメリット
実験12-1:MRIのガベージコレクションを実際に見ていく
MRIの遅延スイープの様子を見る
MRIのフルGCを見る
GCのプロファイリングレポートを翻訳する
JRubyとRubiniusにおけるGC
コピーGC
バンプ・アロケーション
半空間アルゴリズム
Edenヒープ
世代別GC
弱い世代別仮説
新世代オブジェクト用に半空間アルゴリズムを使う
オブジェクトを昇格する
旧世代オブジェクト用のガベージコレクション
世代間の参照
並行GC
オブジェクトグラフが変わっている間にもマークする
三色マーキング
JVMにおける3つのGC
実験12-2:JRubyのVerbose GCモードを使う
メジャーGCを始動する
参考文献
まとめ
付録A さらにそのほかのRuby仮想マシン
YARV:Yet Another RubyVM
YARVの設計方針
YARVの開発までの経緯
さらにそのほかのRuby仮想マシン
訳者あとがき
著者・訳者について
続きを見る