cast_off 0.2.3 → 0.3.1

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.
data/README CHANGED
@@ -22,8 +22,8 @@ $gem install cast_off
22
22
  CastOff は Ruby 処理系に一切手をくわえることなく、Ruby 処理系の拡張ライブラリとして実装しています。
23
23
  このため、gem コマンド経由で容易にインストールすることができます。
24
24
  ただし、脱最適化などの処理が処理系の実装依存になっているため、Ruby 1.9.3 のみの対応となっています。
25
- 一応 Ruby 1.9.2 でも動作はしますが、Ruby 1.9.3 よりも不安定かもしれません。
26
- Ruby1.9.2 と Ruby1.9.3 以外のバージョンの Ruby 処理系では、動作しないため、ご注意ください。
25
+ 一応 Ruby 1.9.2 でも動作しますが、Ruby 1.9.3 よりも不安定かもしれません。
26
+ Ruby1.9.2 と Ruby1.9.3 以外のバージョンの Ruby 処理系では動作しないため、ご注意ください。
27
27
 
28
28
 
29
29
 
@@ -133,13 +133,13 @@ CastOff の利用方法には、コマンドラインからの利用とスクリ
133
133
  ** コマンドラインからの利用
134
134
 
135
135
  *** コマンドラインからの利用の流れ
136
- コマンドラインツール CastOff では、引数に高速化したいプログラムを指定することで、
137
- 容易にコンパイルを行うことができます。
136
+ CastOff が提供するコマンドラインツール cast_off では、
137
+ 引数に高速化したいプログラムを指定することで、容易にコンパイルを行うことができます。
138
138
  詳しくは下で解説しますが、コマンドラインからの CastOff の利用は、
139
139
  次のようなコマンドを繰り返し実行することで行います。
140
140
 
141
141
  -----------------------------------------------------
142
- $CastOff コンパイル対象のスクリプト コンパイル対象に与える引数の例
142
+ $cast_off コンパイル対象のスクリプト コンパイル対象に与える引数の例
143
143
  -----------------------------------------------------
144
144
 
145
145
  例えば、次のようなスクリプトの実行を高速化したい場合、
@@ -149,35 +149,19 @@ $ruby foo.rb bar
149
149
  次のように実行することで、foo.rb と、使用するライブラリをコンパイルすることができます。
150
150
  (この例での bar は、foo.rb に対する引数です)
151
151
 
152
- $CastOff foo.rb bar
152
+ $cast_off foo.rb bar
153
153
 
154
- コマンドラインツール CastOff によるコンパイルは、次の2つの手順で行います。
154
+ コマンドラインからのコンパイルは、次の2つの手順で行います。
155
155
  1:コンパイル対象のメソッドを決定
156
156
  2:コンパイル対象のプロファイル情報を収集し、コンパイル
157
157
  この2つのステップそれぞれで対象プログラムを実行します。
158
158
  このため、上の例の場合、foo.rb を、コンパイルのために2度実行します。
159
159
  実行の回数は、今後、1-2の手順をまとめることで、削減する予定です。
160
160
 
161
- コンパイルした後は、コンパイルしたプログラムに対し、数行追加することで、
162
- コンパイルしたコードを読み込んで動作させることができます。
163
- 上の例の場合、次のようなソースコードを貼り付けることで、
164
- foo.rb の実行の際にコンパイル済みコードを使用することができます。
165
- コマンドラインからのコンパイルが済んだ後は、コンパイルにかかる時間を気にする必要はありません。
166
- -----------------------------------------------------
167
- require 'cast_off'
168
- CastOff.program_name = "foo.rb"
169
- CastOff.skip_configuration_check(true)
170
- CastOff.deoptimize(false)
171
- CastOff.use_default_configuration()
172
- CastOff.autoload()
173
- -----------------------------------------------------
174
-
175
- CastOff.autoload は、Ruby 処理系が提供するトレース API を用いて動作します。
176
- この API は実行時のオーバヘッドが大きいため、CastOff.autoload を呼び出してから、
177
- コンパイル済みコードの読み込みが終了するまで、対象プログラムの実行速度が大きく低下します。
161
+ コンパイルした後は、--run オプションを用いることで、コンパイルしたコードを読み込んで動作させることができます。
162
+ 上の例の場合、次のようなコマンドを実行することで、コンパイル済みコードを用いて foo.rb を実行することができます。
178
163
 
179
- CastOff がコンパイル済みコードを読み込むには、コンパイルした全てのメソッドが定義済みである必要があります。
180
- このため、CastOff.autoload の呼び出しは、require 文などを一通り呼び終えた後に行うのが、もっとも効率が良いです。
164
+ $cast_off --run foo.rb bar
181
165
 
182
166
  また、コマンドラインからの利用で注意する必要があるのは、コンパイル時とは異なる引数を用いて実行する場合の挙動です。
183
167
  上の例では、コンパイル時に bar という引数を与えています。
@@ -200,7 +184,7 @@ when 'baz'
200
184
  end
201
185
  -----------------------------------------------------
202
186
 
203
- ここで、CastOff foo.rb bar として foo.rb をコンパイルすると、CastOff は、プロファイル情報から、
187
+ ここで、cast_off foo.rb bar として foo.rb をコンパイルすると、CastOff は、プロファイル情報から、
204
188
  sample メソッドに渡されるオブジェクトは String オブジェクトのみであるという判断を下します。
205
189
  そして、sample メソッドに渡されるオブジェクトが String オブジェクトであるという前提に基づいたコードを生成します。
206
190
  このため、foo.rb に baz という引数を渡した場合、sample メソッドに対し、想定していなかった Symbol オブジェクトが
@@ -210,24 +194,24 @@ CastOff は、コンパイルの前提条件が崩れたことを検出したと
210
194
 
211
195
  このような場合には、
212
196
 
213
- $CastOff foo.rb bar
197
+ $cast_off foo.rb bar
214
198
 
215
199
  とした次に、
216
200
 
217
- $CastOff foo.rb baz
201
+ $cast_off foo.rb baz
218
202
 
219
203
  としてください。
220
204
  このようにすることで、引数を bar とした場合、引数を baz とした場合の両方のプロファイル情報を用いてコンパイルを行うことができます。
221
- プロファイル情報やコンパイル結果を削除したい場合は、--clear という引数を CastOff に与えて実行してください。
205
+ プロファイル情報やコンパイル結果を削除したい場合は、--clear という引数を与えて実行してください。
222
206
 
223
207
 
224
208
  ***コマンドライン引数
225
- CastOff [options] [programfile] [arguments]
209
+ cast_off [options] [programfile] [arguments]
226
210
 
227
211
 
228
212
  ***オプション一覧
229
- --verbose
230
- コンパイルの進捗とコンパイル結果に関する内部情報を表示します。
213
+ --run
214
+ コンパイル済みコードを用いて、対象プログラム[programfile]を実行します。
231
215
 
232
216
  --deoptimize
233
217
  脱最適化を有効にします。
@@ -235,7 +219,7 @@ CastOff [options] [programfile] [arguments]
235
219
  --clear
236
220
  プロファイル結果やコンパイル結果を削除します。
237
221
  name オプションによって foo と名づけたコンパイル結果を削除する場合、次のコマンドを使用してください。
238
- $CastOff --clear --name=foo
222
+ $cast_off --clear --name=foo
239
223
 
240
224
  --threshold=COUNT
241
225
  COUNT 回以上実行されたメソッドをコンパイルするよう、閾値を設定します。
@@ -248,24 +232,15 @@ COUNT のデフォルト値は100です。
248
232
  に変更が無かった場合、CastOff はコンパイル済みコードを再利用します。
249
233
  name オプションを使用しなかった場合、CastOff は File.basename([programfile]) の結果を名前として使用します。
250
234
 
235
+ --verbose
236
+ コンパイルの進捗とコンパイル結果に関する内部情報を表示します。
237
+
251
238
  -h, --help
252
- コマンドラインツール CastOff のヘルプメッセージを表示します。
239
+ ヘルプメッセージを表示します。
253
240
 
254
241
  --version
255
242
  CastOff のバージョンを表示します。
256
243
 
257
- --step-1
258
- コンパイルの最初のステップを実行します。
259
- このステップでは、コンパイル対象のメソッドを決定します。
260
-
261
- --step-2
262
- コンパイルの2番目のステップを実行します。
263
- このステップでは、コンパイル対象のプロファイル情報を収集します。
264
- そして、コンパイル対象のメソッドをコンパイルします。
265
-
266
- --run
267
- コンパイル済みコードを用いて、対象プログラム[programfile]を実行します。
268
-
269
244
 
270
245
 
271
246
  ** スクリプトからの利用
data/README.en CHANGED
@@ -89,19 +89,19 @@ end
89
89
  * Usage
90
90
 
91
91
  ** Use CastOff from command line
92
- By use of command line tool CastOff, you can improve performance of your Ruby program easily.
92
+ By use of command line tool cast_off, you can improve performance of your Ruby program easily.
93
93
  If you want to improve performance of your Ruby program, you should execute following command repeatedly.
94
94
 
95
95
  -----------------------------------------------------
96
- $CastOff PathOfTargetProgram ArgumentsOfTargetProgram
96
+ $cast_off PathOfTargetProgram ArgumentsOfTargetProgram
97
97
  -----------------------------------------------------
98
98
 
99
99
  For example, when you want to improve performance of Ruby program "foo.rb"
100
100
  (in this example, "foo.rb" recieves one argument "bar" or "baz"), you should execute following commands.
101
101
 
102
102
  -----------------------------------------------------
103
- $CastOff foo.rb bar
104
- $CastOff foo.rb baz
103
+ $cast_off foo.rb bar
104
+ $cast_off foo.rb baz
105
105
  -----------------------------------------------------
106
106
 
107
107
  When you execute these commands, CastOff does followings to compile foo.rb and related libraries.
@@ -111,34 +111,20 @@ When you execute these commands, CastOff does followings to compile foo.rb and r
111
111
  3: Executes "foo.rb" with argument "baz" to get and update profile information.
112
112
  4: Compiles "foo.rb" and related libraries.
113
113
 
114
- When CastOff finishes compilation, CastOff outputs some codes.
115
- You can load compiled methods by pasting these codes.
116
- In above example, CastOff outputs following codes.
114
+ After CastOff finishes compilation, you can run target program with --run option.
115
+ In above example, you can run target program with compiled codes by use of following command.
117
116
 
118
- -----------------------------------------------------
119
- require 'cast_off'
120
- CastOff.program_name = "foo.rb"
121
- CastOff.skip_configuration_check(true)
122
- CastOff.deoptimize(false)
123
- CastOff.use_default_configuration()
124
- CastOff.autoload()
125
- -----------------------------------------------------
126
-
127
- "CastOff.autoload" uses trace api provided from Ruby runtime.
128
- But this api slows down Ruby program execution significantly.
129
- If you want to avoid this overhead, call "CastOff.autoload" after all method definitions.
130
- CastOff uses trace api to check method definition,
131
- so if you call "CastOff.autoload" after all method definitions, CastOff can cancel tracing immediately.
117
+ $cast_off --run foo.rb bar
132
118
 
133
119
 
134
120
  *** Command line arguments
135
121
 
136
- CastOff [options] PathOfTargetProgram ArgumentsOfTargetProgram
122
+ cast_off [options] PathOfTargetProgram ArgumentsOfTargetProgram
137
123
 
138
124
 
139
125
  *** Command line options
140
- --verbose
141
- Show compilation progress and internal information.
126
+ --run
127
+ Execute target program with compiled methods.
142
128
 
143
129
  --deoptimize
144
130
  Enable deoptimization.
@@ -147,7 +133,7 @@ Enable deoptimization.
147
133
  Clear profile information and delete compiled methods.
148
134
  If you want to clear profile information and compiled methods of target name "foo",
149
135
  you should execute following command.
150
- $CastOff --clear --name=foo
136
+ $cast_off --clear --name=foo
151
137
 
152
138
  --threshold=COUNT
153
139
  Compile method which is executed more than COUNT.
@@ -158,23 +144,15 @@ Name compiled methods NAME.
158
144
  This name is used for search of compiled methods.
159
145
  If you don't use this option, CastOff uses File.basename([programfile]) as name.
160
146
 
147
+ --verbose
148
+ Show compilation progress and internal information.
149
+
161
150
  -h, --help
162
151
  Show help.
163
152
 
164
153
  --version
165
154
  Show version number of CastOff.
166
155
 
167
- --step-1
168
- Execute first step of compilation.
169
- On this step, CastOff decides compilation target methods.
170
-
171
- --step-2
172
- Execute second step of compilation.
173
- On this step, CastOff collects profile information and compiles methods.
174
-
175
- --run
176
- Execute target program with compiled methods.
177
-
178
156
 
179
157
 
180
158
  ** Use CastOff from script
@@ -16,11 +16,11 @@ opt = OptionParser.new(<<-EOS, 32, ' ')
16
16
  CastOff is a performance improvement tool for Ruby1.9.3.
17
17
 
18
18
  Usage:
19
- CastOff [options] [programfile] [arguments]
19
+ cast_off [options] [programfile] [arguments]
20
20
  EOS
21
21
  opt.separator("\n Options:")
22
- opt.on('--verbose', <<-EOS.strip) {|v| verbose = true }
23
- Show compilation progress and internal information.
22
+ opt.on('--run', <<-EOS.strip) {|v| step = 'run' }
23
+ Execute [programfile] with compiled codes.
24
24
  EOS
25
25
  opt.on('--deoptimize', <<-EOS.strip) {|v| deoptimize = true }
26
26
  Enable deoptimization.
@@ -30,29 +30,43 @@ opt.on('--threshold=COUNT', <<-EOS.strip, Integer) {|v| threshold = v }
30
30
  Default value is 100.
31
31
  EOS
32
32
  opt.on('--name=NAME', <<-EOS.strip, String) {|v| name = v }
33
- Name compiled methods NAME.
34
- This name is used for search of compiled methods.
33
+ Name compiled codes NAME.
34
+ This name is used for search of compiled codes.
35
35
  If you don't use this option, CastOff uses File.basename([programfile]) as name.
36
36
  EOS
37
37
  opt.on('--clear', <<-EOS.strip) {|v| clear = true }
38
- Clear profile information and delete compiled methods.
39
- If you want to clear profile information and compiled methods of target name "foo",
38
+ Clear profile information and delete compiled codes.
39
+ If you want to clear profile information and compiled codes of target name "foo",
40
40
  you should execute following command.
41
- $CastOff --clear --name=foo
42
- EOS
43
- opt.on('--run', <<-EOS.strip) {|v| step = 'run' }
44
- Execute [programfile] with compiled methods.
41
+ $cast_off --clear --name=foo
45
42
  EOS
46
- opt.on('--step-1', <<-EOS.strip) {|v| step = '1' }
47
- First step of compilation.
48
- On this step, CastOff decides compilation target methods.
49
- EOS
50
- opt.on('--step-2', <<-EOS.strip) {|v| step = '2' }
51
- Second step of compilation.
52
- On this step, CastOff collects profile information and compiles methods.
43
+ opt.on('--step-1') {|v| step = '1' }
44
+ opt.on('--step-2') {|v| step = '2' }
45
+ opt.on('--verbose', <<-EOS.strip) {|v| verbose = true }
46
+ Show compilation progress and internal information.
53
47
  EOS
54
48
  opt.on_tail('-h', "--help", "Show this help.") do
55
- puts opt
49
+ message = opt.to_s.gsub(/\n[ ]*--step-[0-9]+[ ]*/, '')
50
+ message.concat(<<-EOS)
51
+
52
+ Example:
53
+ ------------------------------------------
54
+ # fib.rb
55
+ def fib n
56
+ (n < 3) ? 1 : (fib(n-1) + fib(n-2))
57
+ end
58
+ fib(ARGV.shift.to_i)
59
+ ------------------------------------------
60
+
61
+ 1 Profile and compile fib.rb:
62
+ $cast_off fib.rb 30 # 30 is a argument of fib.rb
63
+
64
+ 2 Run fib.rb with compiled codes:
65
+ $cast_off --run fib.rb 30 # 30 is a argument of fib.rb
66
+
67
+ Report bugs to <http://github.com/soba1104/CastOff/issues>.
68
+ EOS
69
+ puts message
56
70
  exit
57
71
  end
58
72
  opt.on_tail("--version", "Show version number.") do
@@ -70,9 +84,9 @@ if clear
70
84
  if name.empty?
71
85
  STDERR.puts(<<-EOS)
72
86
  Invalid arguments. You should pass target name to CastOff.
73
- If you want to clear profile information and compiled methods of target name "foo",
87
+ If you want to clear profile information and compiled codes of target name "foo",
74
88
  you should execute following command.
75
- $CastOff --clear --name=foo
89
+ $cast_off --clear --name=foo
76
90
  EOS
77
91
  exit(1)
78
92
  end
@@ -104,7 +118,13 @@ CastOff.verbose(verbose)
104
118
  case step
105
119
  when nil
106
120
  STDERR.puts("-------------------------------- compilation start: threshold = #{threshold}, name = #{name}, profiling = ruby #{args} --------------------------------")
107
- 2.times{|i| system("#{this} --step-#{i + 1} --threshold=#{threshold} --name=#{name} #{deoptimize ? '--deoptimize' : ''} #{verbose ? '--verbose' : ''} #{args}")}
121
+ 2.times do |i|
122
+ system("#{this} --step-#{i + 1} --threshold=#{threshold} --name=#{name} #{deoptimize ? '--deoptimize' : ''} #{verbose ? '--verbose' : ''} #{args}")
123
+ unless $? == 0
124
+ STDERR.puts("Failed to execute 'ruby #{args}'")
125
+ exit
126
+ end
127
+ end
108
128
  when '1'
109
129
  STDERR.puts("-------------------------------- step 1 --------------------------------") if verbose
110
130
  CastOff.development(true)
@@ -123,6 +143,7 @@ when '2'
123
143
  }
124
144
  fin = Object.new
125
145
  ObjectSpace.define_finalizer(fin){
146
+ =begin
126
147
  msg = <<-EOS
127
148
 
128
149
  ----------------------------------------------------------------------------------------
@@ -132,6 +153,15 @@ Please add following lines to top of #{script}.
132
153
  require 'cast_off'
133
154
  #{configuration.chomp}
134
155
  CastOff.autoload()
156
+ ----------------------------------------------------------------------------------------
157
+ EOS
158
+ =end
159
+ msg = <<-EOS
160
+ ----------------------------------------------------------------------------------------
161
+ Compilation finished successfully.
162
+ You can execute #{script} with compiled codes by use of following command.
163
+
164
+ $cast_off --run --name=#{name}#{deoptimize ? ' --deoptimize ' : ' '}#{args}
135
165
  ----------------------------------------------------------------------------------------
136
166
  EOS
137
167
  STDERR.puts(msg)
@@ -142,5 +172,6 @@ else
142
172
  raise("should not be reached")
143
173
  end
144
174
 
175
+ $0 = script
145
176
  load script if step
146
177
 
data/cast_off.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "cast_off"
3
- spec.version = "0.2.3"
3
+ spec.version = "0.3.1"
4
4
  spec.platform = Gem::Platform::RUBY
5
5
  spec.summary = "Performance improvement tool for Ruby1.9.3"
6
6
  spec.description = <<-EOS
@@ -10,7 +10,7 @@ CastOff is a performance improvement tool for Ruby1.9.3
10
10
  cast_off.gemspec
11
11
  ]
12
12
  spec.bindir = 'bin'
13
- spec.executables << 'CastOff'
13
+ spec.executables << 'cast_off'
14
14
  spec.require_path = 'lib'
15
15
  spec.extensions = 'ext/cast_off/extconf.rb'
16
16
  spec.has_rdoc = false
@@ -23,6 +23,18 @@ module CastOff::Compiler
23
23
  bug() if @insns.find{|i| i.iseq != @iseq}
24
24
  end
25
25
 
26
+ def source
27
+ return '' unless @irs
28
+ line = nil
29
+ @irs.inject(''){|src, ir|
30
+ insn = ir.insn
31
+ next src if insn.line == line
32
+ next src if insn.source.empty?
33
+ line = insn.line
34
+ src.concat(insn.source).concat("\n")
35
+ }.chomp
36
+ end
37
+
26
38
  def entry_point?
27
39
  @entry_point
28
40
  end
@@ -302,7 +302,7 @@ module CastOff::Compiler
302
302
  bug() unless ir.src.unboxed? == ir.dst.unboxed?
303
303
  end
304
304
  ir.variables_without_result.each do |v|
305
- ds = defs.variable_definition.select {|d| v == d.result_variable }
305
+ ds = defs.definition.select {|d| v == d.result_variable }
306
306
  if v.unboxed?
307
307
  bug() if ds.find{|d| not d.result_variable.unboxed? }
308
308
  elsif v.boxed?
@@ -252,6 +252,7 @@ module CastOff
252
252
  def load_base_configuration()
253
253
  return nil unless File.exist?(@base_configuration_path)
254
254
  conf_str = File.open(@base_configuration_path, 'rb:us-ascii').read()
255
+ conf_str.untaint # FIXME
255
256
  Configuration.load(conf_str)
256
257
  end
257
258
 
@@ -260,7 +261,7 @@ module CastOff
260
261
  exist_conf_str = File.open("#{@dstdir}/#{@conffile}", 'rb:us-ascii').read()
261
262
  # exist_conf_str が tainted であるため、Marshal.load で読み込んだ class も tainted になってしまう
262
263
  # RDoc だと、それのせいで Insecure: can't modify array となる
263
- #exist_conf_str.untaint
264
+ exist_conf_str.untaint # FIXME
264
265
  Configuration.load(exist_conf_str)
265
266
  end
266
267
 
@@ -274,7 +275,7 @@ module CastOff
274
275
  def load_annotation()
275
276
  return nil unless File.exist?(@annotation_path)
276
277
  ann_str = File.open(@annotation_path, 'rb:us-ascii').read()
277
- ann_str.untaint
278
+ ann_str.untaint # FIXME
278
279
  Marshal.load(ann_str)
279
280
  end
280
281
 
@@ -244,8 +244,7 @@ o = Object
244
244
  dst = (@variable_configuration[sym] ||= [])
245
245
  (src + dst).each do |cw|
246
246
  bug() unless cw.instance_of?(ClassWrapper)
247
- bug() if cw.singleton?
248
- bug() if cw.contain_class == SingletonClass
247
+ bug() if !cw.singleton? && cw.contain_class == SingletonClass
249
248
  end
250
249
  @variable_configuration[sym] = (dst | src)
251
250
  end
@@ -253,16 +252,14 @@ o = Object
253
252
  conf.return_value_configuration.each do |(cw0, src0)|
254
253
  bug() unless src0.instance_of?(Hash)
255
254
  bug() unless cw0.instance_of?(ClassWrapper)
256
- bug() if cw0.singleton?
257
- bug() if cw0.contain_class == SingletonClass
255
+ bug() if !cw0.singleton? && cw0.contain_class == SingletonClass
258
256
  dst0 = (@return_value_configuration[cw0] ||= {})
259
257
  src0.each do |(sym, src1)|
260
258
  bug() unless src1.instance_of?(Array)
261
259
  dst1 = (dst0[sym] ||= [])
262
260
  (src1 + dst1).each do |cw1|
263
261
  bug() unless cw1.instance_of?(ClassWrapper)
264
- bug() if cw1.singleton?
265
- bug() if cw1.contain_class == SingletonClass
262
+ bug() if !cw1.singleton? && cw1.contain_class == SingletonClass
266
263
  end
267
264
  dst0[sym] = (dst1 | src1)
268
265
  end
@@ -278,13 +275,19 @@ o = Object
278
275
  update_hash.each do |(k, v)|
279
276
  bug() unless k.instance_of?(Symbol)
280
277
  bug() unless v.instance_of?(Array)
281
- next if v.include?(SingletonClass)
278
+ next if v.map{|a| a.first }.include?(SingletonClass)
282
279
  # variable annotation
283
280
  a0 = v
284
- a0 = a0.map{|c|
281
+ a0 = a0.map{|(c, singleton_p)|
285
282
  bug(c) unless c.is_a?(Class)
286
283
  bug() unless c != SingletonClass
287
- ClassWrapper.new(c, true)
284
+ if singleton_p
285
+ wrapper = ClassWrapper.new(c, false)
286
+ bug() unless wrapper.singleton?
287
+ else
288
+ wrapper = ClassWrapper.new(c, true)
289
+ end
290
+ wrapper
288
291
  }
289
292
  a1 = @variable_configuration[k] || []
290
293
  update_p = true unless (a0 - a1).empty?
@@ -296,27 +299,38 @@ o = Object
296
299
 
297
300
  def update_return_value_configuration(update_hash)
298
301
  update_p = false
299
- update_hash.each do |(k, v)|
300
- bug() unless k.instance_of?(Class)
301
- bug() unless v.instance_of?(Hash)
302
- next if k == SingletonClass
303
- # return value annotation
304
- h0 = v
305
- k = ClassWrapper.new(k, true)
306
- h1 = @return_value_configuration[k] || {}
307
- h0.each do |(mid, klasses0)|
308
- next if klasses0.include?(SingletonClass)
309
- klasses0 = klasses0.map{|c|
310
- bug(c) unless c.is_a?(Class)
311
- bug() unless c != SingletonClass
312
- ClassWrapper.new(c, true)
313
- }
314
- klasses1 = h1[mid] || []
315
- update_p = true unless (klasses0 - klasses1).empty?
316
- klasses1 |= klasses0
317
- h1[mid] = klasses1
302
+ bug() unless update_hash.size == 2
303
+ update_hash.each do |(sym, mtbl)|
304
+ bug() unless sym == :singleton_methods || sym == :instance_methods
305
+ bug() unless mtbl.is_a?(Hash)
306
+ mtbl.each do |(k, v)|
307
+ bug() unless k.instance_of?(Class)
308
+ bug() unless v.instance_of?(Hash)
309
+ next if k == SingletonClass
310
+ # return value annotation
311
+ h0 = v
312
+ k = ClassWrapper.new(k, sym == :instance_methods)
313
+ h1 = @return_value_configuration[k] || {}
314
+ h0.each do |(mid, klasses0)|
315
+ next if klasses0.include?(SingletonClass)
316
+ klasses0 = klasses0.map{|(c, singleton_p)|
317
+ bug(c) unless c.is_a?(Class)
318
+ bug() unless c != SingletonClass
319
+ if singleton_p
320
+ wrapper = ClassWrapper.new(c, false)
321
+ bug() unless wrapper.singleton?
322
+ else
323
+ wrapper = ClassWrapper.new(c, true)
324
+ end
325
+ wrapper
326
+ }
327
+ klasses1 = h1[mid] || []
328
+ update_p = true unless (klasses0 - klasses1).empty?
329
+ klasses1 |= klasses0
330
+ h1[mid] = klasses1
331
+ end
332
+ @return_value_configuration[k] = h1
318
333
  end
319
- @return_value_configuration[k] = h1
320
334
  end
321
335
  update_p
322
336
  end