cast_off 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/README +578 -0
  2. data/README.en +256 -0
  3. data/bin/CastOff +145 -0
  4. data/cast_off.gemspec +25 -0
  5. data/ext/cast_off/cast_off.c.rb +1386 -0
  6. data/ext/cast_off/cast_off.h +24 -0
  7. data/ext/cast_off/depend +70 -0
  8. data/ext/cast_off/extconf.rb +19 -0
  9. data/ext/cast_off/generated_c_include/inline_api.h +507 -0
  10. data/ext/cast_off/generated_c_include/iter_api.h +595 -0
  11. data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
  12. data/ext/cast_off/generated_c_include/vm_api.h +751 -0
  13. data/ext/cast_off/ruby_source/atomic.h +56 -0
  14. data/ext/cast_off/ruby_source/constant.h +34 -0
  15. data/ext/cast_off/ruby_source/debug.h +41 -0
  16. data/ext/cast_off/ruby_source/eval_intern.h +234 -0
  17. data/ext/cast_off/ruby_source/gc.h +98 -0
  18. data/ext/cast_off/ruby_source/id.h +175 -0
  19. data/ext/cast_off/ruby_source/insns.inc +179 -0
  20. data/ext/cast_off/ruby_source/insns_info.inc +695 -0
  21. data/ext/cast_off/ruby_source/internal.h +227 -0
  22. data/ext/cast_off/ruby_source/iseq.h +125 -0
  23. data/ext/cast_off/ruby_source/manual_update.h +135 -0
  24. data/ext/cast_off/ruby_source/method.h +105 -0
  25. data/ext/cast_off/ruby_source/node.h +503 -0
  26. data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
  27. data/ext/cast_off/ruby_source/thread_win32.h +40 -0
  28. data/ext/cast_off/ruby_source/vm_core.h +756 -0
  29. data/ext/cast_off/ruby_source/vm_exec.h +184 -0
  30. data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
  31. data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
  32. data/ext/cast_off/ruby_source/vm_opts.h +51 -0
  33. data/lib/cast_off.rb +15 -0
  34. data/lib/cast_off/compile.rb +629 -0
  35. data/lib/cast_off/compile/basicblock.rb +144 -0
  36. data/lib/cast_off/compile/cfg.rb +391 -0
  37. data/lib/cast_off/compile/code_manager.rb +284 -0
  38. data/lib/cast_off/compile/configuration.rb +2368 -0
  39. data/lib/cast_off/compile/dependency.rb +240 -0
  40. data/lib/cast_off/compile/information.rb +775 -0
  41. data/lib/cast_off/compile/instruction.rb +446 -0
  42. data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
  43. data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
  44. data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
  45. data/lib/cast_off/compile/ir/operand.rb +934 -0
  46. data/lib/cast_off/compile/ir/param_ir.rb +98 -0
  47. data/lib/cast_off/compile/ir/return_ir.rb +92 -0
  48. data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
  49. data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
  50. data/lib/cast_off/compile/iseq.rb +454 -0
  51. data/lib/cast_off/compile/method_information.rb +1384 -0
  52. data/lib/cast_off/compile/namespace/namespace.rb +556 -0
  53. data/lib/cast_off/compile/namespace/uuid.rb +323 -0
  54. data/lib/cast_off/compile/stack.rb +65 -0
  55. data/lib/cast_off/compile/translator.rb +1562 -0
  56. data/lib/cast_off/suggestion.rb +98 -0
  57. data/lib/cast_off/util.rb +58 -0
  58. metadata +107 -0
data/README ADDED
@@ -0,0 +1,578 @@
1
+ * はじめに
2
+ 本ツール CastOff は Ruby の高速化を支援するツールです。
3
+ 一言で説明すると、Ruby1.9.3 用のコンパイラです。
4
+ CastOff は、ユーザが与えた変数のクラス情報などを解釈し、
5
+ 指定した Ruby のメソッドを C 拡張形式のメソッドへと変換します。
6
+ C 拡張に変換することで、Ruby の仮想マシンのオーバヘッドを削減し、
7
+ 対象となるメソッドを高速化することができます。
8
+ 本 README では、CastOff の基本機能について紹介します。
9
+ ご質問、ご要望等があれば、shiba@rvm.jp もしくは
10
+ http://github.com/soba1104/CastOff/issues まで、ご連絡ください。
11
+
12
+
13
+
14
+ * ライセンス
15
+ Ruby 処理系のライセンスに従います。
16
+
17
+
18
+
19
+ * インストール方法
20
+ ソースコードは RubyForge にアップロードしているので、
21
+
22
+ $gem install cast_off
23
+
24
+ としてください。
25
+
26
+ 現時点での実装は Ruby1.9.3 の VM の実装に強く依存しているため、Ruby1.9.3 のみ対応しています。
27
+ 他のバージョンの Ruby 処理系では、動作しないため、ご注意ください。
28
+ 尚、Ruby1.9.4 などの今後リリースされるバージョンには、その都度対応していく予定です。
29
+
30
+
31
+
32
+ * CastOff の利用における注意点
33
+
34
+ ** 利用すると非互換になる機能
35
+ 現状、CastOff を用いた場合、Ruby 処理系との非互換性が生じる可能性があります。
36
+ ここでは、現時点で把握できている、Ruby 処理系との非互換が生じる機能、
37
+ 特にコンパイルエラーを出すことが出来ない機能について列挙します。
38
+ ここで列挙した機能を使用するプログラムやメソッドに対しては、CastOff を利用するべきではありません。
39
+ ここに列挙した機能以外で非互換になる点を発見された方は、
40
+ お手数ですが、shiba@rvm.jp もしくは http://github.com/soba1104/CastOff/issues まで、ご報告をお願い申し上げます。
41
+
42
+ -継続(Continuation)
43
+ Ruby の継続(Continuation) を用いた場合、実行コンテキストの保存に失敗することが確認できています。
44
+ 継続を使用するプログラムでは、CastOff を利用しないでください。
45
+
46
+ -定数の再定義
47
+ CastOff は、コンパイルしたコードの読み込み時、もしくは最初に実行したときに定数解決を行います。
48
+ 性能上の理由により、CastOff は定数解決後は常に同じ値を使いまわすため、定数の再定義に対応することができません。
49
+ 定数の上書きを行うようなプログラムでは、CastOff を利用しないでください。
50
+ 定数の上書きのフック、もしくは RubyVM が管理する世代番号のチェックが高速にできるようになった場合、
51
+ この非互換性は解消する予定です。
52
+
53
+ -メソッドや Proc のパラメータ取得
54
+ コンパイル済みメソッドや Proc に対する情報を取得しようとした場合、
55
+ コンパイル前と異なる挙動を示すメソッドがいくつかあります。
56
+ 例えば、Method#arity や Proc#arity などの、メソッドや Proc の引数に
57
+ 関する情報を取得しようとした場合、コンパイル前とコンパイル後では異なる値になります。
58
+
59
+
60
+ ** 起動時間
61
+ CastOff は Ruby で実装しているので、CastOff を用いると、CastOff の読み込みというオーバヘッドが発生します。
62
+ このため、実行時間が短いプログラムに対してCastOff を利用すると、逆に遅くなる可能性があります。
63
+
64
+ また、CastOff を用いた場合、通常の require などの処理に加えて、CastOff がコンパイルしたメソッドの数だけ、コンパイル済みコードの読み込み、
65
+ および、メソッド上書きのフックなどの処理(以降、初期化処理と呼ぶ)が走ります。
66
+ コマンドラインから CastOff を利用した場合、閾値の設定次第では数多くのメソッドがコンパイルされるため、初期化処理に時間がかかります。
67
+ このため、ボトルネックとなるメソッドが分かっている場合は、スクリプトから CastOff を利用し、
68
+ コンパイル対象のメソッドを直接指定して利用した方が高速に動作します。
69
+
70
+
71
+ ** コンパイル時間
72
+ CastOff は Ruby で実装しており、実装コストの兼ね合いから、コンパイル時間には配慮していません。
73
+ このため、CastOff によるコンパイルは非常に時間がかかります。
74
+ 起動時間に関する注意でも述べたように、コマンドラインから CastOff を利用した場合、
75
+ 閾値の設定次第では数多くのメソッドがコンパイルされます。
76
+ 閾値を低く設定しすぎると、コンパイルに非常に時間がかかるという点に、ご注意ください。
77
+
78
+ また、コマンドラインから CastOff を利用する場合、対象プログラムを実行し、プロファイル情報を取得する必要があります。
79
+ このため、コンパイル対象の実行に数時間かかるようなプログラムに対しては、コマンドライン経由で CastOff を利用するべきではありません。
80
+ このようなプログラムに対しては、実行に時間がかからないような入力を与えるか、スクリプトから CastOff を利用してください。
81
+
82
+
83
+ ** コンパイル済みコードの読み込み
84
+ CastOff がコンパイル済みコードを読み込むためには、コンパイルしたメソッドが定義されている必要があります。
85
+ メソッドを定義し終わるまでは、コンパイル済みコードを読み込むことはできません。
86
+
87
+ CastOff をコマンドラインから利用した場合、CastOff は、クラス定義文をフックし、
88
+ コンパイルしたメソッドが定義済みかどうかを確認します。
89
+ そして、コンパイルしたメソッドが定義済みだった場合、コンパイル済みコードを読み込みます。
90
+ このため、次の bar メソッドのように、定義後にクラス定義文が無いようなメソッドは、
91
+ 明示的に指定しない限りコンパイル済みコードは読み込まれません。
92
+ このような場合には、メソッドの定義後に、明示的に CastOff.autoload もしくは CastOff.load を呼び出してください。
93
+
94
+ -----------------------------------------------------
95
+ class Foo # クラス定義文終了時に、Foo#foo のコンパイル済みコードが読み込まれる
96
+ def foo
97
+ ...
98
+ end
99
+ end
100
+
101
+ def bar() # 以降、クラス定義文が無いので、bar のコンパイル済みコードは読み込まれない
102
+ ...
103
+ end
104
+
105
+ # 以下、クラス定義文は無し
106
+ -----------------------------------------------------
107
+
108
+
109
+
110
+ * CastOff の利用方法
111
+ CastOff は Ruby のメソッドを C に変換し、高速化を実現するためのツールです。
112
+ CastOff の利用方法には、コマンドラインからの利用とスクリプトからの利用の2種類があります。
113
+ ここでは、これら2種類の利用方法について簡単に説明します。
114
+
115
+
116
+ ** コマンドラインからの利用
117
+
118
+ *** コマンドラインからの利用の流れ
119
+ コマンドラインツール CastOff では、引数に高速化したいプログラムを指定することで、
120
+ 容易にコンパイルを行うことができます。
121
+ 詳しくは下で解説しますが、コマンドラインからの CastOff の利用は、
122
+ 次のようなコマンドを繰り返し実行することで行います。
123
+
124
+ -----------------------------------------------------
125
+ $CastOff コンパイル対象のスクリプト コンパイル対象に与える引数の例
126
+ -----------------------------------------------------
127
+
128
+ 例えば、次のようなスクリプトの実行を高速化したい場合、
129
+
130
+ $ruby foo.rb bar
131
+
132
+ 次のように実行することで、foo.rb と、使用するライブラリをコンパイルすることができます。
133
+ (この例での bar は、foo.rb に対する引数です)
134
+
135
+ $CastOff foo.rb bar
136
+
137
+ コマンドラインツール CastOff によるコンパイルは、次の2つの手順で行います。
138
+ 1:コンパイル対象のメソッドを決定
139
+ 2:コンパイル対象のプロファイル情報を収集し、コンパイル
140
+ この2つのステップそれぞれで対象プログラムを実行します。
141
+ このため、上の例の場合、foo.rb を、コンパイルのために2度実行します。
142
+ 実行の回数は、今後、1-2の手順をまとめることで、削減する予定です。
143
+
144
+ コンパイルした後は、コンパイルしたプログラムに対し、数行追加することで、
145
+ コンパイルしたコードを読み込んで動作させることができます。
146
+ 上の例の場合、次のようなソースコードを貼り付けることで、
147
+ foo.rb の実行の際にコンパイル済みコードを使用することができます。
148
+ コマンドラインからのコンパイルが済んだ後は、コンパイルにかかる時間を気にする必要はありません。
149
+ -----------------------------------------------------
150
+ require 'cast_off'
151
+ CastOff.program_name = "foo.rb"
152
+ CastOff.skip_configuration_check(true)
153
+ CastOff.deoptimize(false)
154
+ CastOff.use_default_configuration()
155
+ CastOff.autoload()
156
+ -----------------------------------------------------
157
+
158
+ CastOff.autoload は、Ruby 処理系が提供するトレース API を用いて動作します。
159
+ この API は実行時のオーバヘッドが大きいため、CastOff.autoload を呼び出してから、
160
+ コンパイル済みコードの読み込みが終了するまで、対象プログラムの実行速度が大きく低下します。
161
+
162
+ CastOff がコンパイル済みコードを読み込むには、コンパイルした全てのメソッドが定義済みである必要があります。
163
+ このため、CastOff.autoload の呼び出しは、require 文などを一通り呼び終えた後に行うのが、もっとも効率が良いです。
164
+
165
+ また、コマンドラインからの利用で注意する必要があるのは、コンパイル時とは異なる引数を用いて実行する場合の挙動です。
166
+ 上の例では、コンパイル時に bar という引数を与えています。
167
+ CastOff は、bar を引数として foo.rb を実行したときのプロファイル情報を基にコンパイルを行うため、
168
+ 異なる引数を与えた場合、クラス情報の不整合を起こし、例外、もしくは脱最適化を発生させる可能性があります。
169
+
170
+ 例えば、foo.rb が下の例のようなプログラムだった場合、bar という引数がわたってきた場合は String オブジェクトが、
171
+ baz という引数がわたってきた場合は Symbol オブジェクトが、sample メソッドに渡されます。
172
+
173
+ -----------------------------------------------------
174
+ # 例) foo.rb
175
+ def sample(o)
176
+ puts o.inspect
177
+ end
178
+ case ARGV.shift
179
+ when 'bar'
180
+ sample('bar')
181
+ when 'baz'
182
+ sample(:baz)
183
+ end
184
+ -----------------------------------------------------
185
+
186
+ ここで、CastOff foo.rb bar として foo.rb をコンパイルすると、CastOff は、プロファイル情報から、
187
+ sample メソッドに渡されるオブジェクトは String オブジェクトのみであるという判断を下します。
188
+ そして、sample メソッドに渡されるオブジェクトが String オブジェクトであるという前提に基づいたコードを生成します。
189
+ このため、foo.rb に baz という引数を渡した場合、sample メソッドに対し、想定していなかった Symbol オブジェクトが
190
+ 渡ってきてしまい、コンパイルの前提条件が崩れてしまいます。
191
+ CastOff は、コンパイルの前提条件が崩れたことを検出したときに、例外の発生、もしくは脱最適化を行います。
192
+ 例外を発生させた場合は実行を継続させることができず、脱最適化を行った場合はパフォーマンスに対するペナルティが発生してしまいます。
193
+
194
+ このような場合には、
195
+
196
+ $CastOff foo.rb bar
197
+
198
+ とした次に、
199
+
200
+ $CastOff foo.rb baz
201
+
202
+ としてください。
203
+ このようにすることで、引数を bar とした場合、引数を baz とした場合の両方のプロファイル情報を用いてコンパイルを行うことができます。
204
+ プロファイル情報やコンパイル結果を削除したい場合は、--clear という引数を CastOff に与えて実行してください。
205
+
206
+
207
+ ***コマンドライン引数
208
+ CastOff [options] [programfile] [arguments]
209
+
210
+
211
+ ***オプション一覧
212
+ --verbose
213
+ コンパイルの進捗とコンパイル結果に関する内部情報を表示します。
214
+
215
+ --deoptimize
216
+ 脱最適化を有効にします。
217
+ 現在、ブロックを用いたメソッドの脱最適化には対応していないので、ご注意ください。
218
+
219
+ --clear
220
+ プロファイル結果やコンパイル結果を削除します。
221
+ name オプションによって foo と名づけたコンパイル結果を削除する場合、次のコマンドを使用してください。
222
+ $CastOff --clear --name=foo
223
+
224
+ --threshold=COUNT
225
+ COUNT 回以上実行されたメソッドをコンパイルするよう、閾値を設定します。
226
+ COUNT のデフォルト値は100です。
227
+
228
+ --name=NAME
229
+ コンパイル結果に NAME という名前をつけます。
230
+ ここでつけた名前は、コンパイル済みコードが既に存在するかどうかの確認に使用します。
231
+ コンパイル済みコードが見つかり、コンパイル対象やコンパイルオプション(スクリプトからの利用を参照)
232
+ に変更が無かった場合、CastOff はコンパイル済みコードを再利用します。
233
+ name オプションを使用しなかった場合、CastOff は File.basename([programfile]) の結果を名前として使用します。
234
+
235
+ -h, --help
236
+ コマンドラインツール CastOff のヘルプメッセージを表示します。
237
+
238
+ --version
239
+ CastOff のバージョンを表示します。
240
+
241
+ --step-1
242
+ コンパイルの最初のステップを実行します。
243
+ このステップでは、コンパイル対象のメソッドを決定します。
244
+
245
+ --step-2
246
+ コンパイルの2番目のステップを実行します。
247
+ このステップでは、コンパイル対象のプロファイル情報を収集します。
248
+ そして、コンパイル対象のメソッドをコンパイルします。
249
+
250
+ --run
251
+ コンパイル済みコードを用いて、対象プログラム[programfile]を実行します。
252
+
253
+
254
+
255
+ ** スクリプトからの利用
256
+
257
+ *** スクリプトからの利用の流れ
258
+ CastOff をスクリプトから用いる場合、コンパイルのタイミングやコンパイル対象のメソッド、コンパイルオプションを、
259
+ CastOff に対して直接指定することができます。
260
+ 詳しくは下で解説しますが、スクリプトからの CastOff の利用は、次のようなメソッドを用いて行います。
261
+
262
+ -----------------------------------------------------
263
+ CastOff.compile(クラス,メソッド名,binding,クラス情報)
264
+ -----------------------------------------------------
265
+
266
+ 例えば、次のようなメソッドの実行を高速化したい場合、
267
+
268
+ -----------------------------------------------------
269
+ class Tarai
270
+ def tarai( x, y, z )
271
+ if x <= y
272
+ then y
273
+ else tarai(tarai(x-1, y, z),
274
+ tarai(y-1, z, x),
275
+ tarai(z-1, x, y))
276
+ end
277
+ end
278
+ end
279
+ -----------------------------------------------------
280
+
281
+ tarai メソッドを定義した後に、次のように記述することで、
282
+ tarai メソッドを Ruby の C 拡張にコンパイルし、
283
+ コンパイル済みの C 拡張に tarai メソッドを置き換えることができます。
284
+
285
+ -----------------------------------------------------
286
+ CastOff.compile(Tarai, :tarai, [:x, :y, :z] => Fixnum, Fixnum => {:- => Fixnum})
287
+ -----------------------------------------------------
288
+
289
+ ここでの CastOff.compile に対する引数はそれぞれ次のような意味をもっています。
290
+ 第一引数: コンパイルしたいメソッドが Tarai クラスに定義されていることを指定しています。
291
+ 第二引数: コンパイルしたいメソッドの名前が tarai であることを指定しています。
292
+ 第三引数: コンパイル対象である Tarai#tarai メソッド内のクラス情報を指定しています。
293
+ [:x, :y, :z] => Fixnum は、ローカル変数 x, y, z が、常に Fixnum オブジェクトであることを指定しています。
294
+ Fixnum => {:- => Fixnum} は、Fixnum#- が、常に Fixnum オブジェクトを返すことを指定しています。
295
+ ローカル変数 x, y, z や Fixnum#- の返り値は Bignum オブジェクトであることも想定できますが、
296
+ たらい回し関数にそのような入力をあたえることはまず無いと判断し、常に Fixnum であることを指定しています。
297
+ このように、第三引数では、想定する用途において渡ってくるオブジェクトのみを指定します。
298
+
299
+ このように、CastOff.compile などの、CastOff へのコンパイル指定を行うメソッドを用いることで、
300
+ ボトルネックとなっているメソッドをコンパイルしていくことができます。
301
+ コマンドラインからの利用よりも、コンパイル対象やコンパイルの条件をより細かく指定できるのが、スクリプトからの利用の利点です。
302
+
303
+ コンパイルして得た C 拡張のコードは、コンパイルのための条件や、
304
+ コンパイル対象のメソッドを定義したファイルに変更が加えられていなかった場合に、自動的に再利用されます。
305
+ このため、1度コンパイルが済んだ後では、コンパイルにかかる時間を気にする必要はありません。
306
+
307
+ CastOff をスクリプトから利用するうえで強くおすすめするのは、CastOff.compile の呼び出しを、高速化したいプログラムとは別ファイルに記述するという点です。
308
+ このようにした方が、CastOff への依存を簡単に無くすことができ、CastOff によってトラブルが発生した場合の対処が容易になります。
309
+ また、コンパイル済みの C 拡張コードを再利用するためには、コンパイル対象のファイルに変更が加えられていない必要があるため、
310
+ コンパイル済みコードの再利用が容易になります。
311
+ 例えば、高速化したいプログラムに対しては、次のように、patch.rb の require 文のみを追記してください。
312
+
313
+ -----------------------------------------------------
314
+ # 高速化したいプログラム
315
+
316
+ # 一通りのメソッド定義
317
+ class Foo
318
+ def foo
319
+ ...
320
+ end
321
+ end
322
+
323
+ class Bar
324
+ def bar
325
+ ...
326
+ end
327
+ end
328
+ ...
329
+
330
+ require 'patch' # この行だけ追記
331
+ -----------------------------------------------------
332
+
333
+ そして、patch.rb の中から、CastOff.compile を呼び出してください。
334
+
335
+ -----------------------------------------------------
336
+ # patch.rb
337
+
338
+ require 'cast_off'
339
+
340
+ class Foo
341
+ CastOff.compile(self, :foo, binding, クラス情報)
342
+ end
343
+
344
+ class Bar
345
+ CastOff.compile(self, :bar, binding, クラス情報)
346
+ end
347
+ -----------------------------------------------------
348
+
349
+ このようにすることで、require 'patch' の1行を削除するだけで、容易に CastOff への依存を解消することができます。
350
+ また、Foo#foo のコンパイルに用いるクラス情報を更新しても、Bar#bar の再コンパイルが走ることが無くなります。
351
+
352
+
353
+ ***クラス情報の指定
354
+ CastOff に対するクラス情報の指定は、次のように行います。
355
+
356
+ -変数のクラス情報の指定:
357
+ --ローカル変数、引数
358
+ :ローカル変数名 => クラス
359
+ :ローカル変数名 => [クラス1, クラス2, ...]
360
+ [:ローカル変数名1, :ローカル変数名2, ...] => クラス
361
+ [:ローカル変数名1, :ローカル変数名2, ...] => [クラス1, クラス2, ...]
362
+
363
+ --インスタンス変数
364
+ :@インスタンス変数名 => クラス
365
+ :@インスタンス変数名 => [クラス1, クラス2, ...]
366
+ [:@インスタンス変数名1, :@インスタンス変数名2, ...] => クラス
367
+ [:@インスタンス変数名1, :@インスタンス変数名2, ...] => [クラス1, クラス2, ...]
368
+
369
+ --クラス変数
370
+ :@@クラス変数名 => クラス
371
+ :@@クラス変数名 => [クラス1, クラス2, ...]
372
+ [:@@クラス変数名1, :@@クラス変数名2, ...] => クラス
373
+ [:@@クラス変数名1, :@@クラス変数名2, ...] => [クラス1, クラス2, ...]
374
+
375
+ --グローバル変数
376
+ :$グローバル変数名 => クラス
377
+ :$グローバル変数名 => [クラス1, クラス2, ...]
378
+ [:$グローバル変数名1, :$グローバル変数名2, ...] => クラス
379
+ [:$グローバル変数名1, :$グローバル変数名2, ...] => [クラス1, クラス2, ...]
380
+
381
+
382
+ -メソッドの返り値のクラス情報の指定:
383
+ クラス => {:メソッド名1 => 返り値のクラス, :メソッド名2 => [返り値のクラス1, 返り値のクラス2, ...], ...}
384
+
385
+
386
+ -定数のクラス情報の指定:
387
+ 定数のクラス情報の指定は、変数やメソッドの返り値とは異なります。
388
+ 定数のクラス情報の指定は、定数解決に使用できる Binding オブジェクトを渡すことで行います。
389
+
390
+ 例えば、次のような Sample#sample メソッドをコンパイルする場合、
391
+
392
+ -----------------------------------------------------
393
+ COUNT = 1000000
394
+ class Sample
395
+ def sample()
396
+ COUNT.times do
397
+ ...
398
+ end
399
+ end
400
+ end
401
+ -----------------------------------------------------
402
+
403
+ 次のように指定することで、COUNT という定数が Fixnum オブジェクトであることを指定することができます。
404
+
405
+ -----------------------------------------------------
406
+ class Sample
407
+ CastOff.compile(self, :sample, binding, クラス情報)
408
+ end
409
+ -----------------------------------------------------
410
+
411
+ 上のように、CastOff.compile の引数に Binding オブジェクトを渡すと、CastOff はコンパイル時に、
412
+ 与えられた Binding オブジェクトを用いて定数を参照し、定数のクラス情報を解決します。
413
+ ここで与える Binding オブジェクトは定数解決にのみ使用するため、
414
+ 定数の解決に使用できる Binding オブジェクトならば、どのようなものを渡してもかまいません。
415
+ 上の例では、CastOff.compile の呼び出しを、Sample クラスのクラス定義文の中で行うことで、
416
+ Sample#sample メソッドと同様の定数スコープを構築し、CastOff に渡しています。
417
+
418
+ Ruby では、クラス定義文を好きな場所で呼び出し、既存のクラスの定数スコープを得ることができます。
419
+ このため、Sample#sample メソッドを定義した箇所と、CastOff.compile を呼び出す箇所は、別ファイルでもかまいません。
420
+ CastOff への依存を簡単に無くすためにも、CastOff.compile の呼び出しは、高速化したいプログラムとは別ファイルに
421
+ まとめて記述したほうが使いやすいと思います。これについては、「スクリプトからの利用の流れ」を参照してください。
422
+
423
+
424
+ *** コンパイルの指定
425
+ ここでは、CastOff にコンパイルを指定するための方法を簡単に解説します。
426
+ クラス情報の指定方法については、上記のスクリプトからの利用の流れを参照してください。
427
+
428
+ -Ruby のインスタンスメソッドのコンパイル指定
429
+ --指定方法
430
+ CastOff.compile(クラス or モジュール, メソッド名, binding)
431
+ CastOff.compile(クラス or モジュール, メソッド名, binding, クラス情報)
432
+ CastOff.compile(クラス or モジュール, メソッド名, クラス情報)
433
+ --備考
434
+ Ruby のメソッドをコンパイルし、C 拡張に変換、対象のメソッドを上書きします。
435
+ メソッド名は Symbol オブジェクトで指定してください。
436
+ 第三引数で与える Binding オブジェクトは、定数の解決に使用します。
437
+
438
+ -Ruby の特異メソッドのコンパイル指定
439
+ --指定方法
440
+ CastOff.compile_singleton_method(オブジェクト, メソッド名, binding)
441
+ CastOff.compile_singleton_method(オブジェクト, メソッド名, binding, クラス情報)
442
+ CastOff.compile_singleton_method(オブジェクト, メソッド名, クラス情報)
443
+ --備考
444
+ 特異メソッドのコンパイルは、CastOff.compile ではなくこちらを使用してください。
445
+ CastOff.compile と同様に、対象のメソッドを上書きします。
446
+ メソッド名は Symbol オブジェクトで指定してください。
447
+ 第三引数で与える Binding オブジェクトは、定数の解決に使用します。
448
+
449
+ -Ruby プログラムの一部をコンパイルし、実行させる指定
450
+ --指定方法
451
+ CastOff.execute(クラス情報) { ブロック }
452
+ --備考
453
+ 与えられたブロックをコンパイルし、実行します。
454
+
455
+
456
+ *** コンパイルオプションに関する指定
457
+ CastOff をスクリプトから用いる場合、コンパイルの条件(コンパイルオプション)について様々な指定を行うことができます。
458
+ ここでは、CastOff に対して指定できるコンパイルオプションについて簡単に解説します。
459
+
460
+ -実行時にクラス情報のチェックを行うガードの有無
461
+ --指定方法
462
+ CastOff.inject_guard(true or false)
463
+ ---デフォルト値
464
+ true
465
+ ---備考
466
+ クラス情報に関するガードを挿入する(true)かしない(false)かを設定します。
467
+ クラス情報に関するガードとは、プログラマが手動で与えたクラス情報や、
468
+ プロファイルによって得たクラス情報が正しいかどうかを、実行時に検査するためのものです。
469
+ ガードでの検査に失敗した場合のデフォルトの挙動は例外ですが、
470
+ CastOff.deoptimize(true) とすることで、脱最適化を有効にすることができます。
471
+
472
+
473
+ --脱最適化
474
+ ---指定方法
475
+ CastOff.deoptimize(true or false)
476
+ ---デフォルト値
477
+ false
478
+ ---備考
479
+ ガードでの検査に失敗した場合に、脱最適化を行う(true)か、例外を発生させる(false)かを設定します。
480
+ 脱最適化を有効にすることで、ガードでの検査失敗時にも実行を継続させることができます。
481
+ しかし、脱最適化に必要な情報を保持する必要があり、CastOff による高速化の度合いが低下します。
482
+
483
+
484
+ --コンパイル条件のチェックのスキップ
485
+ ---指定方法
486
+ CastOff.skip_configuration_check(true or false)
487
+ ---デフォルト値
488
+ false
489
+ ---備考
490
+ コンパイル済みコードを再利用していいかどうかを判定するときに、
491
+ コンパイル条件(コンパイルオプションや CastOff に与えるクラス情報など)
492
+ のチェックをスキップする(true)かスキップしない(false)かを設定します。
493
+
494
+ CastOff は、デフォルトでは、コンパイル済みコードを再利用していいかどうかを判定するときに、
495
+ 指定されたコンパイル条件が、コンパイル済みのものと現在与えられているもので同一かどうかの判定を行います。
496
+ このとき、コンパイル条件が異なっていた場合は再度コンパイルを行います。
497
+ CastOff.skip_configuration_check(true) とすると、このコンパイル条件のチェックをスキップします。
498
+
499
+ コンパイル条件のチェックには Marshal.load などの実行コストの高い処理を複数回呼び出すため、時間がかかります。
500
+ CastOff に与えるコンパイル条件が決定した場合は、このオプションを使用して、
501
+ コンパイル条件のチェックをスキップし、ロード時間を短縮することをおすすめします。
502
+
503
+
504
+ --コンパイル済みコードの再利用
505
+ ---指定方法
506
+ CastOff.reuse_compiled_binary(true or false)
507
+ ---デフォルト値
508
+ true
509
+ ---備考
510
+ コンパイル済みコードの再利用をする(true)かしない(false)かを設定します。
511
+ 再コンパイルを強制したい場合は、false に設定してください。
512
+
513
+
514
+ --定数の先読み
515
+ ---指定方法
516
+ CastOff.prefetch_constant()
517
+ ---デフォルト値
518
+ true
519
+ ---備考
520
+ 定数の先読みを行う(true)か行わない(false)かを設定します。
521
+ 定数の先読みを行わせるためには、Binding オブジェクトを、コンパイル時に与える必要があります。
522
+ 定数の先読みを指定した場合、CastOff は、定数の解決をロード時、もしくは最初に実行されたときに行います。
523
+ そして、先読みを行った定数を常に使用します。
524
+ このため、先読みを行った場合、定数を上書きした場合も、上書き前の値を使用してしまいます。
525
+ 定数の上書きを使用するプログラムをコンパイルする場合、定数の先読みをオフにしてください。
526
+ ただし、定数の先読みをオフにした場合、定数の参照に rb_const_get を複数回使用するため、
527
+ 定数参照がボトルネックになる可能性があります。
528
+
529
+
530
+ --コンパイル経過や CastOff の内部情報表示の指定
531
+ ---指定方法
532
+ CastOff.verbose(true or false)
533
+ ---デフォルト値
534
+ false
535
+ ---備考
536
+ コンパイルの経過や CastOff の内部情報を表示する(true)かしない(false)かを設定します。
537
+ ここでの CastOff の内部情報とは、次のようなものです。
538
+ 1:クラス情報を解決できなかった変数やメソッドの返り値
539
+ 2:複製を削減できなかった文字列リテラル
540
+
541
+
542
+ --組み込み変数に対する非互換性の許容
543
+ ---指定方法
544
+ CastOff.allow_builtin_variable_incompatibility(true or false)
545
+ ---デフォルト値
546
+ false
547
+ ---備考
548
+ $1 などの、正規表現に関する組み込み変数の非互換性を許容する(true)か、許容しない(false)かを設定します。
549
+ $1 などの、正規表現に関する組み込み変数は、メソッド呼び出し毎に個別のスコープを持ちます。
550
+ 例えば、次のような foo と bar では、これらの組み込み変数に対し、それぞれ異なるスコープを持っています。
551
+ このため、foo 内で $1 の値が "foo" となるにも拘らず、bar 内の puts $1 で表示されるのは、"bar" となります。
552
+
553
+ -----------------------------------------------------
554
+ def foo()
555
+ "this is foo" =~ /(foo)/ # $1 = "foo" となる
556
+ end
557
+
558
+ def bar()
559
+ "this is bar" =~ /(bar)/ # $1 = "bar" となる
560
+ foo()
561
+ puts $1 # bar と表示
562
+ end
563
+
564
+ def baz()
565
+ "this is baz" =~ /(baz)/ # $1 = "baz" となる
566
+ puts $1 # baz と表示
567
+ end
568
+ -----------------------------------------------------
569
+
570
+ これに対し、CastOff を用いた場合、foo と bar のこれらの組み込み変数に対するスコープが共有されてしまいます。
571
+ つまり、CastOff を使用すると、foo によって $1 の値が "foo" に上書きされ、bar 内の puts $1 で表示されるのが、"foo" となってしまいます。
572
+ 以上の理由により、CastOff では、コンパイル対象のメソッドが $1 などの組み込み変数を使用していた場合、コンパイルエラーを発生させます。
573
+
574
+ しかし、上の例の baz のように、$1 が上書きされないようなメソッドでは、このような非互換性は問題とはなりません。
575
+ baz メソッドのように、組み込み変数のスコープに対する非互換性が崩れていても問題ない場合は、このオプションを使用してください。
576
+ CastOff.allow_builtin_variable_incompatibility(true) とすると、
577
+ $1 などの組み込み変数を使用していても、コンパイルを行うことができます。
578
+