typeprof 0.9.2 → 0.14.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/Gemfile.lock +6 -5
- data/doc/demo.md +2 -2
- data/doc/todo.md +133 -0
- data/lib/typeprof/analyzer.rb +201 -104
- data/lib/typeprof/block.rb +39 -4
- data/lib/typeprof/builtin.rb +217 -70
- data/lib/typeprof/cli.rb +7 -0
- data/lib/typeprof/config.rb +30 -14
- data/lib/typeprof/container-type.rb +24 -0
- data/lib/typeprof/export.rb +134 -74
- data/lib/typeprof/import.rb +87 -39
- data/lib/typeprof/iseq.rb +116 -41
- data/lib/typeprof/method.rb +29 -7
- data/lib/typeprof/type.rb +75 -13
- data/lib/typeprof/version.rb +1 -1
- data/smoke/alias.rb +4 -4
- data/smoke/alias2.rb +3 -1
- data/smoke/arguments.rb +2 -2
- data/smoke/arguments2.rb +5 -5
- data/smoke/array-each.rb +1 -1
- data/smoke/array-each3.rb +1 -1
- data/smoke/array-map.rb +1 -1
- data/smoke/array-map2.rb +1 -1
- data/smoke/array-map3.rb +3 -3
- data/smoke/array-mul.rb +2 -2
- data/smoke/array-plus1.rb +1 -1
- data/smoke/array-plus2.rb +1 -0
- data/smoke/array-range-aref.rb +11 -11
- data/smoke/array-replace.rb +1 -1
- data/smoke/array1.rb +5 -5
- data/smoke/array10.rb +1 -1
- data/smoke/array11.rb +1 -1
- data/smoke/array12.rb +1 -1
- data/smoke/array14.rb +1 -1
- data/smoke/array15.rb +1 -1
- data/smoke/array2.rb +2 -2
- data/smoke/array3.rb +1 -0
- data/smoke/array6.rb +2 -1
- data/smoke/array8.rb +1 -1
- data/smoke/array9.rb +1 -1
- data/smoke/attr-module.rb +1 -0
- data/smoke/attr-vis.rb +43 -0
- data/smoke/attr-vis.rbs +4 -0
- data/smoke/attr.rb +2 -2
- data/smoke/block-ambiguous.rb +4 -4
- data/smoke/block-args1-rest.rb +6 -5
- data/smoke/block-args1.rb +5 -5
- data/smoke/block-args2-rest.rb +6 -5
- data/smoke/block-args2.rb +5 -5
- data/smoke/block-args3-rest.rb +7 -6
- data/smoke/block-args3.rb +6 -6
- data/smoke/block-blockarg.rb +3 -3
- data/smoke/block-kwarg.rb +4 -4
- data/smoke/block1.rb +1 -1
- data/smoke/block10.rb +1 -1
- data/smoke/block11.rb +2 -2
- data/smoke/block2.rb +1 -1
- data/smoke/block3.rb +1 -1
- data/smoke/block5.rb +1 -0
- data/smoke/block_given.rb +37 -0
- data/smoke/break4.rb +17 -0
- data/smoke/class_eval.rb +22 -0
- data/smoke/class_method.rb +2 -2
- data/smoke/class_method2.rb +2 -2
- data/smoke/constant2.rb +3 -2
- data/smoke/context-sensitive1.rb +1 -1
- data/smoke/cvar.rb +3 -2
- data/smoke/define_method.rb +2 -2
- data/smoke/define_method3.rb +1 -0
- data/smoke/define_method4.rb +1 -1
- data/smoke/define_method6.rb +19 -0
- data/smoke/define_method7.rb +18 -0
- data/smoke/demo.rb +6 -6
- data/smoke/demo1.rb +1 -1
- data/smoke/demo11.rb +1 -1
- data/smoke/demo2.rb +1 -1
- data/smoke/demo3.rb +1 -1
- data/smoke/demo4.rb +3 -3
- data/smoke/demo5.rb +1 -1
- data/smoke/demo6.rb +2 -1
- data/smoke/demo7.rb +1 -1
- data/smoke/demo9.rb +1 -0
- data/smoke/dummy-execution1.rb +1 -1
- data/smoke/dummy-execution2.rb +1 -1
- data/smoke/dummy_element.rb +1 -1
- data/smoke/ensure1.rb +1 -1
- data/smoke/enum_for.rb +15 -0
- data/smoke/enum_for2.rb +17 -0
- data/smoke/extended.rb +38 -0
- data/smoke/fib.rb +2 -2
- data/smoke/flow1.rb +1 -1
- data/smoke/flow10.rb +17 -0
- data/smoke/flow11.rb +17 -0
- data/smoke/flow2.rb +1 -1
- data/smoke/flow3.rb +1 -1
- data/smoke/flow5.rb +1 -1
- data/smoke/flow6.rb +1 -1
- data/smoke/flow7.rb +1 -1
- data/smoke/flow8.rb +1 -1
- data/smoke/flow9.rb +1 -1
- data/smoke/function.rb +1 -1
- data/smoke/gvar.rb +1 -1
- data/smoke/gvar2.rb +1 -1
- data/smoke/hash-fetch.rb +3 -3
- data/smoke/included.rb +38 -0
- data/smoke/inheritance.rb +4 -4
- data/smoke/inherited.rb +26 -0
- data/smoke/initialize.rb +3 -2
- data/smoke/instance_eval.rb +2 -2
- data/smoke/instance_eval4.rb +12 -0
- data/smoke/int_times.rb +1 -1
- data/smoke/integer.rb +1 -1
- data/smoke/ivar.rb +3 -2
- data/smoke/ivar2.rb +2 -2
- data/smoke/ivar3.rb +2 -1
- data/smoke/ivar4.rb +1 -0
- data/smoke/kernel-class.rb +1 -1
- data/smoke/keyword4.rb +1 -1
- data/smoke/kwrest.rb +1 -0
- data/smoke/kwsplat1.rb +2 -2
- data/smoke/kwsplat2.rb +1 -1
- data/smoke/manual-rbs.rb +1 -0
- data/smoke/manual-rbs3.rb +1 -0
- data/smoke/method_missing.rb +4 -3
- data/smoke/module3.rb +1 -1
- data/smoke/module4.rb +1 -0
- data/smoke/module5.rb +1 -1
- data/smoke/module_function1.rb +3 -2
- data/smoke/module_function2.rb +3 -2
- data/smoke/multiple-include.rb +1 -0
- data/smoke/next1.rb +1 -1
- data/smoke/object-send1.rb +3 -3
- data/smoke/optional1.rb +1 -1
- data/smoke/optional2.rb +1 -1
- data/smoke/optional3.rb +1 -1
- data/smoke/parameterizedd-self.rb +2 -1
- data/smoke/prepend1.rb +33 -0
- data/smoke/prepend2.rb +10 -0
- data/smoke/prepend2.rbs +9 -0
- data/smoke/primitive_method.rb +19 -0
- data/smoke/proc4.rb +1 -1
- data/smoke/public.rb +4 -0
- data/smoke/range.rb +1 -1
- data/smoke/rbs-attr.rb +2 -2
- data/smoke/rbs-proc2.rb +1 -1
- data/smoke/rbs-proc3.rb +1 -1
- data/smoke/rbs-tyvar4.rb +3 -2
- data/smoke/rbs-tyvar6.rb +3 -3
- data/smoke/redo1.rb +1 -1
- data/smoke/redo2.rb +1 -1
- data/smoke/rescue1.rb +1 -1
- data/smoke/rescue2.rb +1 -1
- data/smoke/rescue3.rb +1 -0
- data/smoke/rescue4.rb +1 -1
- data/smoke/respond_to.rb +1 -1
- data/smoke/rest1.rb +2 -2
- data/smoke/rest2.rb +1 -1
- data/smoke/rest3.rb +6 -6
- data/smoke/rest4.rb +2 -2
- data/smoke/rest5.rb +1 -1
- data/smoke/rest6.rb +1 -1
- data/smoke/retry1.rb +2 -2
- data/smoke/simple.rb +1 -1
- data/smoke/step.rb +3 -3
- data/smoke/struct-keyword_init.rb +6 -16
- data/smoke/struct.rb +1 -1
- data/smoke/struct2.rb +1 -1
- data/smoke/struct3.rb +1 -1
- data/smoke/struct4.rb +1 -1
- data/smoke/struct5.rb +2 -2
- data/smoke/struct6.rb +2 -2
- data/smoke/struct7.rb +1 -1
- data/smoke/super1.rb +4 -4
- data/smoke/super3.rb +3 -2
- data/smoke/super4.rb +7 -5
- data/smoke/super5.rb +6 -4
- data/smoke/symbol-proc-attr.rb +1 -1
- data/smoke/tap1.rb +2 -2
- data/smoke/toplevel.rb +1 -1
- data/smoke/type_var.rb +3 -3
- data/smoke/user-demo.rb +1 -1
- data/smoke/wrong-extend.rb +1 -0
- data/smoke/wrong-include.rb +1 -0
- data/smoke/wrong-include2.rb +1 -1
- data/testbed/goodcheck-Gemfile.lock +1 -1
- data/typeprof.gemspec +1 -1
- metadata +25 -5
data/lib/typeprof/import.rb
CHANGED
@@ -3,6 +3,10 @@ require "rbs"
|
|
3
3
|
module TypeProf
|
4
4
|
class RBSReader
|
5
5
|
def initialize
|
6
|
+
@repo = RBS::Repository.new
|
7
|
+
Config.gem_repo_dirs.each do |dir|
|
8
|
+
@repo.add(Pathname(dir))
|
9
|
+
end
|
6
10
|
@env, @builtin_env_json = RBSReader.get_builtin_env
|
7
11
|
end
|
8
12
|
|
@@ -11,7 +15,7 @@ module TypeProf
|
|
11
15
|
unless @builtin_env
|
12
16
|
@builtin_env = RBS::Environment.new
|
13
17
|
|
14
|
-
loader = RBS::EnvironmentLoader.new
|
18
|
+
loader = RBS::EnvironmentLoader.new(repository: @repo)
|
15
19
|
new_decls = loader.load(env: @builtin_env).map {|decl,| decl }
|
16
20
|
@builtin_env_json = load_rbs(@builtin_env, new_decls)
|
17
21
|
end
|
@@ -24,22 +28,30 @@ module TypeProf
|
|
24
28
|
end
|
25
29
|
|
26
30
|
def load_library(lib)
|
27
|
-
loader = RBS::EnvironmentLoader.new(core_root: nil)
|
31
|
+
loader = RBS::EnvironmentLoader.new(core_root: nil, repository: @repo)
|
28
32
|
loader.add(library: lib)
|
29
33
|
|
30
34
|
case lib
|
35
|
+
when 'bigdecimal-math'
|
36
|
+
loader.add(library: 'bigdecimal')
|
31
37
|
when "yaml"
|
32
38
|
loader.add(library: "pstore")
|
33
39
|
loader.add(library: "dbm")
|
40
|
+
when "logger"
|
41
|
+
loader.add(library: "monitor")
|
42
|
+
when "csv"
|
43
|
+
loader.add(library: "forwardable")
|
44
|
+
when "prime"
|
45
|
+
loader.add(library: "singleton")
|
34
46
|
end
|
35
47
|
|
36
48
|
new_decls = loader.load(env: @env).map {|decl,| decl }
|
37
49
|
RBSReader.load_rbs(@env, new_decls)
|
38
50
|
end
|
39
51
|
|
40
|
-
def
|
41
|
-
loader = RBS::EnvironmentLoader.new(core_root: nil)
|
42
|
-
loader.add(path: path)
|
52
|
+
def load_paths(paths)
|
53
|
+
loader = RBS::EnvironmentLoader.new(core_root: nil, repository: @repo)
|
54
|
+
paths.each {|path| loader.add(path: path) }
|
43
55
|
new_decls = loader.load(env: @env).map {|decl,| decl }
|
44
56
|
RBSReader.load_rbs(@env, new_decls)
|
45
57
|
end
|
@@ -69,6 +81,7 @@ module TypeProf
|
|
69
81
|
class RBS2JSON
|
70
82
|
def initialize(all_env, cur_env)
|
71
83
|
@all_env, @cur_env = all_env, cur_env
|
84
|
+
@alias_resolution_stack = {}
|
72
85
|
end
|
73
86
|
|
74
87
|
def dump_json
|
@@ -116,13 +129,13 @@ module TypeProf
|
|
116
129
|
end
|
117
130
|
|
118
131
|
type_params = nil
|
119
|
-
|
120
|
-
extended_modules = []
|
132
|
+
modules = { include: [], extend: [], prepend: [] }
|
121
133
|
methods = {}
|
122
134
|
attr_methods = {}
|
123
135
|
ivars = {}
|
124
136
|
cvars = {}
|
125
137
|
rbs_sources = {}
|
138
|
+
visibility = true
|
126
139
|
|
127
140
|
decls.each do |decl|
|
128
141
|
decl = decl.decl
|
@@ -143,7 +156,7 @@ module TypeProf
|
|
143
156
|
end
|
144
157
|
end
|
145
158
|
|
146
|
-
method_def = conv_method_def(method_types)
|
159
|
+
method_def = conv_method_def(method_types, visibility)
|
147
160
|
rbs_source = [(member.kind == :singleton ? "self." : "") + member.name.to_s, member.types.map {|type| type.location.source }]
|
148
161
|
if member.instance?
|
149
162
|
methods[[false, name]] = method_def
|
@@ -155,13 +168,13 @@ module TypeProf
|
|
155
168
|
end
|
156
169
|
when RBS::AST::Members::AttrReader
|
157
170
|
ty = conv_type(member.type)
|
158
|
-
attr_methods[[false, member.name]] = attr_method_def(:reader, member.name, ty)
|
171
|
+
attr_methods[[false, member.name]] = attr_method_def(:reader, member.name, ty, visibility)
|
159
172
|
when RBS::AST::Members::AttrWriter
|
160
173
|
ty = conv_type(member.type)
|
161
|
-
attr_methods[[false, member.name]] = attr_method_def(:writer, member.name, ty)
|
174
|
+
attr_methods[[false, member.name]] = attr_method_def(:writer, member.name, ty, visibility)
|
162
175
|
when RBS::AST::Members::AttrAccessor
|
163
176
|
ty = conv_type(member.type)
|
164
|
-
attr_methods[[false, member.name]] = attr_method_def(:accessor, member.name, ty)
|
177
|
+
attr_methods[[false, member.name]] = attr_method_def(:accessor, member.name, ty, visibility)
|
165
178
|
when RBS::AST::Members::Alias
|
166
179
|
# XXX: an alias to attr methods?
|
167
180
|
if member.instance?
|
@@ -176,11 +189,15 @@ module TypeProf
|
|
176
189
|
when RBS::AST::Members::Include
|
177
190
|
name = member.name
|
178
191
|
if name.kind == :class
|
192
|
+
# including a module
|
179
193
|
mod = conv_type_name(name)
|
180
194
|
type_args = member.args.map {|type| conv_type(type) }
|
181
|
-
|
195
|
+
modules[:include] << [mod, type_args]
|
182
196
|
else
|
183
|
-
# including an interface
|
197
|
+
# including an interface
|
198
|
+
mod = conv_type_name(name)
|
199
|
+
type_args = member.args.map {|type| conv_type(type) }
|
200
|
+
modules[:include] << [mod, type_args]
|
184
201
|
end
|
185
202
|
|
186
203
|
when RBS::AST::Members::Extend
|
@@ -188,7 +205,17 @@ module TypeProf
|
|
188
205
|
if name.kind == :class
|
189
206
|
mod = conv_type_name(name)
|
190
207
|
type_args = member.args.map {|type| conv_type(type) }
|
191
|
-
|
208
|
+
modules[:extend] << [mod, type_args]
|
209
|
+
else
|
210
|
+
# extending a module with an interface is not supported yet
|
211
|
+
end
|
212
|
+
|
213
|
+
when RBS::AST::Members::Prepend
|
214
|
+
name = member.name
|
215
|
+
if name.kind == :class
|
216
|
+
mod = conv_type_name(name)
|
217
|
+
type_args = member.args.map {|type| conv_type(type) }
|
218
|
+
modules[:prepend] << [mod, type_args]
|
192
219
|
else
|
193
220
|
# extending a module with an interface is not supported yet
|
194
221
|
end
|
@@ -198,7 +225,10 @@ module TypeProf
|
|
198
225
|
when RBS::AST::Members::ClassVariable
|
199
226
|
cvars[member.name] = conv_type(member.type)
|
200
227
|
|
201
|
-
when RBS::AST::Members::Public
|
228
|
+
when RBS::AST::Members::Public
|
229
|
+
visibility = true
|
230
|
+
when RBS::AST::Members::Private
|
231
|
+
visibility = false
|
202
232
|
|
203
233
|
# The following declarations are ignoreable because they are handled in other level
|
204
234
|
when RBS::AST::Declarations::Constant
|
@@ -216,8 +246,7 @@ module TypeProf
|
|
216
246
|
type_params: type_params,
|
217
247
|
superclass: superclass,
|
218
248
|
members: {
|
219
|
-
|
220
|
-
extended_modules: extended_modules,
|
249
|
+
modules: modules,
|
221
250
|
methods: methods,
|
222
251
|
attr_methods: attr_methods,
|
223
252
|
ivars: ivars,
|
@@ -297,10 +326,14 @@ module TypeProf
|
|
297
326
|
return RBS::BuiltinNames::Object.name, []
|
298
327
|
end
|
299
328
|
|
300
|
-
def conv_method_def(rbs_method_types)
|
301
|
-
rbs_method_types.map do |method_type|
|
329
|
+
def conv_method_def(rbs_method_types, visibility)
|
330
|
+
sig_rets = rbs_method_types.map do |method_type|
|
302
331
|
conv_func(method_type.type_params, method_type.type, method_type.block)
|
303
332
|
end
|
333
|
+
{
|
334
|
+
sig_rets: sig_rets,
|
335
|
+
visibility: visibility,
|
336
|
+
}
|
304
337
|
end
|
305
338
|
|
306
339
|
def conv_func(type_params, func, block)
|
@@ -330,11 +363,12 @@ module TypeProf
|
|
330
363
|
}
|
331
364
|
end
|
332
365
|
|
333
|
-
def attr_method_def(kind, name, ty)
|
366
|
+
def attr_method_def(kind, name, ty, visibility)
|
334
367
|
{
|
335
368
|
kind: kind,
|
336
369
|
ivar: name,
|
337
370
|
ty: ty,
|
371
|
+
visibility: visibility,
|
338
372
|
}
|
339
373
|
end
|
340
374
|
|
@@ -407,8 +441,17 @@ module TypeProf
|
|
407
441
|
raise NotImplementedError
|
408
442
|
end
|
409
443
|
when RBS::Types::Alias
|
410
|
-
|
411
|
-
|
444
|
+
if @alias_resolution_stack[ty.name]
|
445
|
+
[:any]
|
446
|
+
else
|
447
|
+
begin
|
448
|
+
@alias_resolution_stack[ty.name] = true
|
449
|
+
alias_decl = @all_env.alias_decls[ty.name]
|
450
|
+
alias_decl ? conv_type(alias_decl.decl.type) : [:any]
|
451
|
+
ensure
|
452
|
+
@alias_resolution_stack.delete(ty.name)
|
453
|
+
end
|
454
|
+
end
|
412
455
|
when RBS::Types::Union
|
413
456
|
[:union, ty.types.map {|ty2| conv_type(ty2) }.compact]
|
414
457
|
when RBS::Types::Optional
|
@@ -455,9 +498,9 @@ module TypeProf
|
|
455
498
|
Import.new(scratch, json).import
|
456
499
|
end
|
457
500
|
|
458
|
-
def self.
|
459
|
-
|
460
|
-
Import.new(scratch, scratch.rbs_reader.
|
501
|
+
def self.import_rbs_files(scratch, rbs_paths)
|
502
|
+
rbs_paths = rbs_paths.map {|rbs_path| Pathname(rbs_path) }
|
503
|
+
Import.new(scratch, scratch.rbs_reader.load_paths(rbs_paths)).import(true)
|
461
504
|
end
|
462
505
|
|
463
506
|
def self.import_rbs_code(scratch, rbs_name, rbs_code)
|
@@ -502,22 +545,25 @@ module TypeProf
|
|
502
545
|
|
503
546
|
classes.each do |klass, superclass_type_args, members|
|
504
547
|
@scratch.add_superclass_type_args!(klass, superclass_type_args&.map {|ty| conv_type(ty) })
|
505
|
-
|
506
|
-
extended_modules = members[:extended_modules]
|
548
|
+
modules = members[:modules]
|
507
549
|
methods = members[:methods]
|
508
550
|
attr_methods = members[:attr_methods]
|
509
551
|
ivars = members[:ivars]
|
510
552
|
cvars = members[:cvars]
|
511
553
|
rbs_sources = members[:rbs_sources]
|
512
554
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
555
|
+
modules.each do |kind, mods|
|
556
|
+
mods.each do |mod, type_args|
|
557
|
+
type_args = type_args&.map {|ty| conv_type(ty) }
|
558
|
+
case kind
|
559
|
+
when :include
|
560
|
+
@scratch.mix_module(:after, klass, path_to_klass(mod), type_args, false, nil)
|
561
|
+
when :extend
|
562
|
+
@scratch.mix_module(:after, klass, path_to_klass(mod), type_args, true, nil)
|
563
|
+
when :prepend
|
564
|
+
@scratch.mix_module(:before, klass, path_to_klass(mod), type_args, false, nil)
|
565
|
+
end
|
566
|
+
end
|
521
567
|
end
|
522
568
|
|
523
569
|
methods.each do |(singleton, method_name), mdef|
|
@@ -530,7 +576,7 @@ module TypeProf
|
|
530
576
|
kind = mdef[:kind]
|
531
577
|
ivar = mdef[:ivar]
|
532
578
|
ty = conv_type(mdef[:ty]).remove_type_vars
|
533
|
-
@scratch.add_attr_method(klass,
|
579
|
+
@scratch.add_attr_method(klass, ivar, :"@#{ ivar }", kind, mdef[:visibility], nil)
|
534
580
|
@scratch.add_ivar_write!(Type::Instance.new(klass), :"@#{ ivar }", ty, nil)
|
535
581
|
end
|
536
582
|
|
@@ -560,11 +606,11 @@ module TypeProf
|
|
560
606
|
end
|
561
607
|
|
562
608
|
def conv_method_def(method_name, mdef, rbs_source)
|
563
|
-
sig_rets = mdef.flat_map do |sig_ret|
|
609
|
+
sig_rets = mdef[:sig_rets].flat_map do |sig_ret|
|
564
610
|
conv_func(sig_ret)
|
565
611
|
end
|
566
612
|
|
567
|
-
TypedMethodDef.new(sig_rets, rbs_source)
|
613
|
+
TypedMethodDef.new(sig_rets, rbs_source, mdef[:visibility])
|
568
614
|
end
|
569
615
|
|
570
616
|
def conv_func(sig_ret)
|
@@ -664,7 +710,9 @@ module TypeProf
|
|
664
710
|
klass = Type::Builtin[:obj]
|
665
711
|
path.each do |name|
|
666
712
|
klass = @scratch.get_constant(klass, name)
|
667
|
-
|
713
|
+
if klass == Type.any
|
714
|
+
raise TypeProfError.new("A constant `#{ path.join("::") }' is used but not defined in RBS")
|
715
|
+
end
|
668
716
|
end
|
669
717
|
klass
|
670
718
|
end
|
data/lib/typeprof/iseq.rb
CHANGED
@@ -206,8 +206,76 @@ module TypeProf
|
|
206
206
|
end
|
207
207
|
end
|
208
208
|
|
209
|
-
#
|
210
|
-
|
209
|
+
# flow-sensitive analysis for `case var; when A; when B; when C; end`
|
210
|
+
# find a pattern: getlocal, (dup, putobject(true), getconstant(class name), checkmatch, branch)* for ..Ruby 3.0
|
211
|
+
# find a pattern: getlocal, (putobject(true), getconstant(class name), top(1), send(===), branch)* for Ruby 3.1..
|
212
|
+
case_branch_list = []
|
213
|
+
if (RUBY_VERSION.split(".") <=> %w(3 1 0)) < 0
|
214
|
+
(@insns.size - 1).times do |i|
|
215
|
+
insn0, getlocal_operands = @insns[i]
|
216
|
+
next unless [:getlocal, :getblockparam, :getblockparamproxy].include?(insn0) && getlocal_operands[1] == 0
|
217
|
+
nops = [i]
|
218
|
+
new_insns = []
|
219
|
+
j = i + 1
|
220
|
+
while true
|
221
|
+
case @insns[j]
|
222
|
+
when [:dup, []]
|
223
|
+
break unless @insns[j + 1] == [:putnil, []]
|
224
|
+
break unless @insns[j + 2] == [:putobject, [true]]
|
225
|
+
break unless @insns[j + 3][0] == :getconstant # TODO: support A::B::C
|
226
|
+
break unless @insns[j + 4] == [:checkmatch, [2]]
|
227
|
+
break unless @insns[j + 5][0] == :branch
|
228
|
+
target_pc = @insns[j + 5][1][1]
|
229
|
+
break unless @insns[target_pc] == [:pop, []]
|
230
|
+
nops << j << (j + 4) << target_pc
|
231
|
+
new_insns << [j + 5, [:getlocal_checkmatch_branch, [getlocal_operands, @insns[j + 5][1]]]]
|
232
|
+
j += 6
|
233
|
+
when [:pop, []]
|
234
|
+
nops << j
|
235
|
+
case_branch_list << [nops, new_insns]
|
236
|
+
break
|
237
|
+
else
|
238
|
+
break
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
else
|
243
|
+
(@insns.size - 1).times do |i|
|
244
|
+
insn0, getlocal_operands = @insns[i]
|
245
|
+
next unless [:getlocal, :getblockparam, :getblockparamproxy].include?(insn0) && getlocal_operands[1] == 0
|
246
|
+
nops = []
|
247
|
+
new_insns = []
|
248
|
+
j = i + 1
|
249
|
+
while true
|
250
|
+
case @insns[j]
|
251
|
+
when [:putnil, []]
|
252
|
+
break unless @insns[j + 1] == [:putobject, [true]]
|
253
|
+
break unless @insns[j + 2][0] == :getconstant # TODO: support A::B::C
|
254
|
+
break unless @insns[j + 3] == [:topn, [1]]
|
255
|
+
break unless @insns[j + 4] == [:send, [{:mid=>:===, :flag=>20, :orig_argc=>1}, nil]]
|
256
|
+
break unless @insns[j + 5][0] == :branch
|
257
|
+
target_pc = @insns[j + 5][1][1]
|
258
|
+
break unless @insns[target_pc] == [:pop, []]
|
259
|
+
nops << (j + 4) #<< target_pc
|
260
|
+
new_insns << [j + 5, [:arg_getlocal_send_branch, [getlocal_operands, @insns[j + 4][1], @insns[j + 5][1]]]]
|
261
|
+
j += 6
|
262
|
+
when [:pop, []]
|
263
|
+
#nops << j
|
264
|
+
case_branch_list << [nops, new_insns]
|
265
|
+
break
|
266
|
+
else
|
267
|
+
break
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
case_branch_list.each do |nops, new_insns|
|
273
|
+
nops.each {|i| @insns[i] = [:nop, []] }
|
274
|
+
new_insns.each {|i, insn| @insns[i] = insn }
|
275
|
+
end
|
276
|
+
|
277
|
+
# find a pattern: getlocal(recv), ..., send (is_a?, respond_to?), branch
|
278
|
+
recv_getlocal_send_branch_list = []
|
211
279
|
(@insns.size - 1).times do |i|
|
212
280
|
insn, operands = @insns[i]
|
213
281
|
if insn == :getlocal && operands[1] == 0
|
@@ -216,7 +284,7 @@ module TypeProf
|
|
216
284
|
while @insns[j]
|
217
285
|
sp = check_send_branch(sp, j)
|
218
286
|
if sp == :match
|
219
|
-
|
287
|
+
recv_getlocal_send_branch_list << [i, j]
|
220
288
|
break
|
221
289
|
end
|
222
290
|
break if !sp
|
@@ -224,13 +292,54 @@ module TypeProf
|
|
224
292
|
end
|
225
293
|
end
|
226
294
|
end
|
227
|
-
|
295
|
+
recv_getlocal_send_branch_list.each do |i, j|
|
228
296
|
next if (i + 1 .. j + 1).any? {|i| branch_targets[i] }
|
229
297
|
_insn, getlocal_operands = @insns[i]
|
230
298
|
_insn, send_operands = @insns[j]
|
231
299
|
_insn, branch_operands = @insns[j + 1]
|
232
300
|
@insns[j] = [:nop]
|
233
|
-
@insns[j + 1] = [:
|
301
|
+
@insns[j + 1] = [:recv_getlocal_send_branch, [getlocal_operands, send_operands, branch_operands]]
|
302
|
+
end
|
303
|
+
|
304
|
+
# find a pattern: getlocal, send (===), branch
|
305
|
+
arg_getlocal_send_branch_list = []
|
306
|
+
(@insns.size - 1).times do |i|
|
307
|
+
insn1, operands1 = @insns[i]
|
308
|
+
next unless insn1 == :getlocal && operands1[1] == 0
|
309
|
+
insn2, operands2 = @insns[i + 1]
|
310
|
+
next unless insn2 == :send
|
311
|
+
send_opt = operands2[0]
|
312
|
+
next unless send_opt[:flag] == 16 && send_opt[:orig_argc] == 1
|
313
|
+
insn3, _operands3 = @insns[i + 2]
|
314
|
+
next unless insn3 == :branch
|
315
|
+
arg_getlocal_send_branch_list << i
|
316
|
+
end
|
317
|
+
arg_getlocal_send_branch_list.each do |i|
|
318
|
+
next if (i .. i + 2).any? {|i| branch_targets[i] }
|
319
|
+
_insn, getlocal_operands = @insns[i]
|
320
|
+
_insn, send_operands = @insns[i + 1]
|
321
|
+
_insn, branch_operands = @insns[i + 2]
|
322
|
+
@insns[i + 1] = [:nop]
|
323
|
+
@insns[i + 2] = [:arg_getlocal_send_branch, [getlocal_operands, send_operands, branch_operands]]
|
324
|
+
end
|
325
|
+
|
326
|
+
# find a pattern: send (block_given?), branch
|
327
|
+
send_branch_list = []
|
328
|
+
(@insns.size - 1).times do |i|
|
329
|
+
insn, _operands = @insns[i]
|
330
|
+
if insn == :send
|
331
|
+
insn, _operands = @insns[i + 1]
|
332
|
+
if insn == :branch
|
333
|
+
send_branch_list << i
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
send_branch_list.each do |i|
|
338
|
+
next if branch_targets[i + 1]
|
339
|
+
_insn, send_operands = @insns[i]
|
340
|
+
_insn, branch_operands = @insns[i + 1]
|
341
|
+
@insns[i] = [:nop]
|
342
|
+
@insns[i + 1] = [:send_branch, [send_operands, branch_operands]]
|
234
343
|
end
|
235
344
|
|
236
345
|
# find a pattern: getlocal, dup, branch
|
@@ -267,42 +376,6 @@ module TypeProf
|
|
267
376
|
@insns[i + 1] = [:getlocal_branch, [getlocal_operands, branch_operands]]
|
268
377
|
end
|
269
378
|
end
|
270
|
-
|
271
|
-
# flow-sensitive analysis for `case var; when A; when B; when C; end`
|
272
|
-
# find a pattern: getlocal, (dup, putobject(true), getconstant(class name), checkmatch, branch)*
|
273
|
-
case_branch_list = []
|
274
|
-
(@insns.size - 1).times do |i|
|
275
|
-
insn0, getlocal_operands = @insns[i]
|
276
|
-
next unless [:getlocal, :getblockparam, :getblockparamproxy].include?(insn0) && getlocal_operands[1] == 0
|
277
|
-
nops = [i]
|
278
|
-
new_insns = []
|
279
|
-
j = i + 1
|
280
|
-
while true
|
281
|
-
case @insns[j]
|
282
|
-
when [:dup, []]
|
283
|
-
break unless @insns[j + 1] == [:putnil, []]
|
284
|
-
break unless @insns[j + 2] == [:putobject, [true]]
|
285
|
-
break unless @insns[j + 3][0] == :getconstant # TODO: support A::B::C
|
286
|
-
break unless @insns[j + 4] == [:checkmatch, [2]]
|
287
|
-
break unless @insns[j + 5][0] == :branch
|
288
|
-
target_pc = @insns[j + 5][1][1]
|
289
|
-
break unless @insns[target_pc] == [:pop, []]
|
290
|
-
nops << j << (j + 4) << target_pc
|
291
|
-
new_insns << [j + 5, [:getlocal_checkmatch_branch, [getlocal_operands, @insns[j + 5][1]]]]
|
292
|
-
j += 6
|
293
|
-
when [:pop, []]
|
294
|
-
nops << j
|
295
|
-
case_branch_list << [nops, new_insns]
|
296
|
-
break
|
297
|
-
else
|
298
|
-
break
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
case_branch_list.each do |nops, new_insns|
|
303
|
-
nops.each {|i| @insns[i] = [:nop, []] }
|
304
|
-
new_insns.each {|i, insn| @insns[i] = insn }
|
305
|
-
end
|
306
379
|
end
|
307
380
|
|
308
381
|
def check_send_branch(sp, j)
|
@@ -348,6 +421,8 @@ module TypeProf
|
|
348
421
|
sp -= argc
|
349
422
|
return :match if insn == :send && sp == 0 && @insns[j + 1][0] == :branch
|
350
423
|
sp += 1
|
424
|
+
when :arg_getlocal_send_branch
|
425
|
+
return # not implemented
|
351
426
|
when :invokeblock
|
352
427
|
opt, = operands
|
353
428
|
sp -= opt[:orig_argc]
|