typeprof 0.15.3 → 0.20.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/Gemfile.lock +5 -5
- data/doc/ide.md +81 -0
- data/doc/typeprof-for-ide-log.png +0 -0
- data/doc/typeprof-for-ide.png +0 -0
- data/exe/typeprof +5 -1
- data/lib/typeprof/analyzer.rb +235 -56
- data/lib/typeprof/arguments.rb +1 -0
- data/lib/typeprof/builtin.rb +23 -23
- data/lib/typeprof/cli.rb +23 -5
- data/lib/typeprof/code-range.rb +177 -0
- data/lib/typeprof/config.rb +41 -20
- data/lib/typeprof/container-type.rb +3 -0
- data/lib/typeprof/export.rb +191 -15
- data/lib/typeprof/import.rb +33 -9
- data/lib/typeprof/insns-def.rb +1 -0
- data/lib/typeprof/iseq.rb +224 -17
- data/lib/typeprof/lsp.rb +884 -0
- data/lib/typeprof/method.rb +15 -11
- data/lib/typeprof/type.rb +50 -42
- data/lib/typeprof/utils.rb +18 -1
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +3 -5
- data/typeprof-lsp +3 -0
- data/typeprof.gemspec +2 -2
- data/vscode/.gitignore +5 -0
- data/vscode/.vscode/launch.json +16 -0
- data/vscode/.vscodeignore +7 -0
- data/vscode/README.md +22 -0
- data/vscode/development.md +31 -0
- data/vscode/package-lock.json +3249 -0
- data/vscode/package.json +71 -0
- data/vscode/sandbox/test.rb +24 -0
- data/vscode/src/extension.ts +299 -0
- data/vscode/tsconfig.json +15 -0
- metadata +21 -334
- data/smoke/alias.rb +0 -31
- data/smoke/alias2.rb +0 -21
- data/smoke/any-cbase.rb +0 -5
- data/smoke/any1.rb +0 -16
- data/smoke/any2.rb +0 -18
- data/smoke/arguments.rb +0 -17
- data/smoke/arguments2.rb +0 -56
- data/smoke/array-each.rb +0 -15
- data/smoke/array-each2.rb +0 -16
- data/smoke/array-each3.rb +0 -13
- data/smoke/array-ltlt.rb +0 -14
- data/smoke/array-ltlt2.rb +0 -17
- data/smoke/array-map.rb +0 -12
- data/smoke/array-map2.rb +0 -11
- data/smoke/array-map3.rb +0 -23
- data/smoke/array-mul.rb +0 -18
- data/smoke/array-plus1.rb +0 -11
- data/smoke/array-plus2.rb +0 -16
- data/smoke/array-pop.rb +0 -12
- data/smoke/array-range-aref.rb +0 -71
- data/smoke/array-replace.rb +0 -13
- data/smoke/array-s-aref.rb +0 -12
- data/smoke/array1.rb +0 -27
- data/smoke/array10.rb +0 -15
- data/smoke/array11.rb +0 -14
- data/smoke/array12.rb +0 -25
- data/smoke/array13.rb +0 -31
- data/smoke/array14.rb +0 -14
- data/smoke/array15.rb +0 -16
- data/smoke/array2.rb +0 -28
- data/smoke/array3.rb +0 -26
- data/smoke/array4.rb +0 -15
- data/smoke/array5.rb +0 -14
- data/smoke/array6.rb +0 -17
- data/smoke/array7.rb +0 -14
- data/smoke/array8.rb +0 -13
- data/smoke/array9.rb +0 -13
- data/smoke/attr-module.rb +0 -24
- data/smoke/attr-vis.rb +0 -43
- data/smoke/attr-vis.rbs +0 -4
- data/smoke/attr.rb +0 -28
- data/smoke/autoload.rb +0 -14
- data/smoke/backtrace.rb +0 -33
- data/smoke/block-ambiguous.rb +0 -37
- data/smoke/block-args1-rest.rb +0 -64
- data/smoke/block-args1.rb +0 -60
- data/smoke/block-args2-rest.rb +0 -64
- data/smoke/block-args2.rb +0 -60
- data/smoke/block-args3-rest.rb +0 -75
- data/smoke/block-args3.rb +0 -71
- data/smoke/block-blockarg.rb +0 -28
- data/smoke/block-kwarg.rb +0 -53
- data/smoke/block1.rb +0 -23
- data/smoke/block10.rb +0 -15
- data/smoke/block11.rb +0 -40
- data/smoke/block12.rb +0 -23
- data/smoke/block13.rb +0 -9
- data/smoke/block13.rbs +0 -3
- data/smoke/block14.rb +0 -18
- data/smoke/block2.rb +0 -15
- data/smoke/block3.rb +0 -38
- data/smoke/block4.rb +0 -19
- data/smoke/block5.rb +0 -21
- data/smoke/block6.rb +0 -21
- data/smoke/block7.rb +0 -19
- data/smoke/block8.rb +0 -28
- data/smoke/block9.rb +0 -13
- data/smoke/block_given.rb +0 -37
- data/smoke/blown.rb +0 -13
- data/smoke/break1.rb +0 -19
- data/smoke/break2.rb +0 -16
- data/smoke/break3.rb +0 -13
- data/smoke/break4.rb +0 -17
- data/smoke/case.rb +0 -17
- data/smoke/case2.rb +0 -18
- data/smoke/case3.rb +0 -17
- data/smoke/class-hierarchy.rb +0 -54
- data/smoke/class-hierarchy2.rb +0 -27
- data/smoke/class-new.rb +0 -15
- data/smoke/class.rb +0 -7
- data/smoke/class_eval.rb +0 -22
- data/smoke/class_instance_var.rb +0 -9
- data/smoke/class_method.rb +0 -25
- data/smoke/class_method2.rb +0 -21
- data/smoke/class_method3.rb +0 -29
- data/smoke/constant1.rb +0 -46
- data/smoke/constant2.rb +0 -36
- data/smoke/constant3.rb +0 -10
- data/smoke/constant4.rb +0 -12
- data/smoke/context-sensitive1.rb +0 -13
- data/smoke/cvar.rb +0 -31
- data/smoke/cvar2.rb +0 -17
- data/smoke/define_method.rb +0 -16
- data/smoke/define_method2.rb +0 -18
- data/smoke/define_method3.rb +0 -14
- data/smoke/define_method3.rbs +0 -3
- data/smoke/define_method4.rb +0 -15
- data/smoke/define_method4.rbs +0 -3
- data/smoke/define_method5.rb +0 -12
- data/smoke/define_method6.rb +0 -19
- data/smoke/define_method7.rb +0 -18
- data/smoke/demo.rb +0 -81
- data/smoke/demo1.rb +0 -17
- data/smoke/demo10.rb +0 -21
- data/smoke/demo11.rb +0 -12
- data/smoke/demo2.rb +0 -15
- data/smoke/demo3.rb +0 -17
- data/smoke/demo4.rb +0 -27
- data/smoke/demo5.rb +0 -16
- data/smoke/demo6.rb +0 -22
- data/smoke/demo7.rb +0 -15
- data/smoke/demo8.rb +0 -19
- data/smoke/demo9.rb +0 -18
- data/smoke/dummy-execution1.rb +0 -15
- data/smoke/dummy-execution2.rb +0 -16
- data/smoke/dummy_element.rb +0 -14
- data/smoke/ensure1.rb +0 -21
- data/smoke/enum_for.rb +0 -15
- data/smoke/enum_for2.rb +0 -17
- data/smoke/enumerator.rb +0 -16
- data/smoke/expandarray1.rb +0 -23
- data/smoke/expandarray2.rb +0 -24
- data/smoke/extended.rb +0 -38
- data/smoke/fib.rb +0 -28
- data/smoke/flip-flop.rb +0 -28
- data/smoke/flow1.rb +0 -17
- data/smoke/flow10.rb +0 -17
- data/smoke/flow11.rb +0 -17
- data/smoke/flow2.rb +0 -15
- data/smoke/flow3.rb +0 -15
- data/smoke/flow4.rb +0 -5
- data/smoke/flow5.rb +0 -20
- data/smoke/flow6.rb +0 -20
- data/smoke/flow7.rb +0 -21
- data/smoke/flow8.rb +0 -14
- data/smoke/flow9.rb +0 -12
- data/smoke/for.rb +0 -9
- data/smoke/freeze.rb +0 -12
- data/smoke/function.rb +0 -17
- data/smoke/gvar.rb +0 -14
- data/smoke/gvar2.rb +0 -15
- data/smoke/gvar2.rbs +0 -1
- data/smoke/hash-bot.rb +0 -12
- data/smoke/hash-fetch.rb +0 -28
- data/smoke/hash-merge-bang.rb +0 -12
- data/smoke/hash1.rb +0 -20
- data/smoke/hash2.rb +0 -13
- data/smoke/hash3.rb +0 -14
- data/smoke/hash4.rb +0 -11
- data/smoke/hash5.rb +0 -14
- data/smoke/huge_union.rb +0 -86
- data/smoke/identifier_keywords.rb +0 -17
- data/smoke/included.rb +0 -38
- data/smoke/inheritance.rb +0 -34
- data/smoke/inheritance2.rb +0 -35
- data/smoke/inherited.rb +0 -26
- data/smoke/initialize.rb +0 -28
- data/smoke/instance_eval.rb +0 -18
- data/smoke/instance_eval2.rb +0 -10
- data/smoke/instance_eval3.rb +0 -25
- data/smoke/instance_eval4.rb +0 -12
- data/smoke/int_times.rb +0 -15
- data/smoke/integer.rb +0 -11
- data/smoke/ivar.rb +0 -31
- data/smoke/ivar2.rb +0 -30
- data/smoke/ivar3.rb +0 -17
- data/smoke/ivar3.rbs +0 -3
- data/smoke/ivar4.rb +0 -21
- data/smoke/kernel-class.rb +0 -13
- data/smoke/keyword1.rb +0 -12
- data/smoke/keyword2.rb +0 -12
- data/smoke/keyword3.rb +0 -12
- data/smoke/keyword4.rb +0 -12
- data/smoke/keyword5.rb +0 -16
- data/smoke/kwrest.rb +0 -13
- data/smoke/kwrest.rbs +0 -3
- data/smoke/kwsplat1.rb +0 -43
- data/smoke/kwsplat2.rb +0 -13
- data/smoke/lit-complex.rb +0 -10
- data/smoke/lit-encoding.rb +0 -10
- data/smoke/manual-rbs.rb +0 -29
- data/smoke/manual-rbs.rbs +0 -3
- data/smoke/manual-rbs2.rb +0 -21
- data/smoke/manual-rbs2.rbs +0 -8
- data/smoke/manual-rbs3.rb +0 -13
- data/smoke/manual-rbs3.rbs +0 -3
- data/smoke/masgn1.rb +0 -14
- data/smoke/masgn2.rb +0 -18
- data/smoke/masgn3.rb +0 -13
- data/smoke/method_in_branch.rb +0 -23
- data/smoke/method_missing.rb +0 -29
- data/smoke/module1.rb +0 -29
- data/smoke/module2.rb +0 -28
- data/smoke/module3.rb +0 -33
- data/smoke/module4.rb +0 -35
- data/smoke/module5.rb +0 -17
- data/smoke/module6.rb +0 -40
- data/smoke/module_function1.rb +0 -29
- data/smoke/module_function2.rb +0 -29
- data/smoke/multiple-include.rb +0 -15
- data/smoke/multiple-superclass.rb +0 -28
- data/smoke/next1.rb +0 -21
- data/smoke/next2.rb +0 -17
- data/smoke/noname.rb +0 -9
- data/smoke/object-send1.rb +0 -23
- data/smoke/object-send2.rb +0 -10
- data/smoke/object-send3.rb +0 -18
- data/smoke/once.rb +0 -13
- data/smoke/optional1.rb +0 -14
- data/smoke/optional2.rb +0 -16
- data/smoke/optional3.rb +0 -11
- data/smoke/or_raise.rb +0 -18
- data/smoke/parameterizedd-self.rb +0 -20
- data/smoke/parameterizedd-self2.rb +0 -15
- data/smoke/pathname1.rb +0 -14
- data/smoke/pathname2.rb +0 -14
- data/smoke/pattern-match1.rb +0 -19
- data/smoke/pattern-match2.rb +0 -16
- data/smoke/prepend1.rb +0 -33
- data/smoke/prepend2.rb +0 -10
- data/smoke/prepend2.rbs +0 -9
- data/smoke/primitive_method.rb +0 -19
- data/smoke/printf.rb +0 -20
- data/smoke/proc.rb +0 -20
- data/smoke/proc2.rb +0 -17
- data/smoke/proc3.rb +0 -15
- data/smoke/proc4.rb +0 -12
- data/smoke/proc5.rb +0 -19
- data/smoke/proc6.rb +0 -13
- data/smoke/proc7.rb +0 -32
- data/smoke/public.rb +0 -38
- data/smoke/range.rb +0 -14
- data/smoke/rbs-alias.rb +0 -10
- data/smoke/rbs-alias.rbs +0 -4
- data/smoke/rbs-attr.rb +0 -27
- data/smoke/rbs-attr.rbs +0 -5
- data/smoke/rbs-attr2.rb +0 -11
- data/smoke/rbs-attr2.rbs +0 -3
- data/smoke/rbs-extend.rb +0 -10
- data/smoke/rbs-extend.rbs +0 -7
- data/smoke/rbs-interface.rb +0 -25
- data/smoke/rbs-interface.rbs +0 -12
- data/smoke/rbs-module.rb +0 -26
- data/smoke/rbs-module.rbs +0 -4
- data/smoke/rbs-opt-and-rest.rb +0 -10
- data/smoke/rbs-opt-and-rest.rbs +0 -3
- data/smoke/rbs-proc1.rb +0 -10
- data/smoke/rbs-proc1.rbs +0 -3
- data/smoke/rbs-proc2.rb +0 -21
- data/smoke/rbs-proc2.rbs +0 -3
- data/smoke/rbs-proc3.rb +0 -14
- data/smoke/rbs-proc3.rbs +0 -4
- data/smoke/rbs-record.rb +0 -18
- data/smoke/rbs-record.rbs +0 -4
- data/smoke/rbs-tyvar.rb +0 -19
- data/smoke/rbs-tyvar.rbs +0 -5
- data/smoke/rbs-tyvar2.rb +0 -21
- data/smoke/rbs-tyvar2.rbs +0 -9
- data/smoke/rbs-tyvar3.rb +0 -18
- data/smoke/rbs-tyvar3.rbs +0 -5
- data/smoke/rbs-tyvar4.rb +0 -37
- data/smoke/rbs-tyvar5.rb +0 -13
- data/smoke/rbs-tyvar5.rbs +0 -8
- data/smoke/rbs-tyvar6.rb +0 -18
- data/smoke/rbs-tyvar6.rbs +0 -12
- data/smoke/rbs-tyvar7.rb +0 -12
- data/smoke/rbs-tyvar7.rbs +0 -7
- data/smoke/rbs-vars.rb +0 -35
- data/smoke/rbs-vars.rbs +0 -7
- data/smoke/redo1.rb +0 -22
- data/smoke/redo2.rb +0 -23
- data/smoke/req-keyword.rb +0 -13
- data/smoke/require1.rb +0 -13
- data/smoke/require2.rb +0 -13
- data/smoke/rescue1.rb +0 -21
- data/smoke/rescue2.rb +0 -23
- data/smoke/rescue3.rb +0 -20
- data/smoke/rescue4.rb +0 -17
- data/smoke/respond_to.rb +0 -23
- data/smoke/rest-farg.rb +0 -11
- data/smoke/rest1.rb +0 -26
- data/smoke/rest2.rb +0 -31
- data/smoke/rest3.rb +0 -37
- data/smoke/rest4.rb +0 -19
- data/smoke/rest5.rb +0 -11
- data/smoke/rest6.rb +0 -12
- data/smoke/retry1.rb +0 -21
- data/smoke/return.rb +0 -14
- data/smoke/reveal.rb +0 -13
- data/smoke/simple.rb +0 -12
- data/smoke/singleton_class.rb +0 -8
- data/smoke/singleton_method.rb +0 -12
- data/smoke/step.rb +0 -18
- data/smoke/string-split.rb +0 -12
- data/smoke/struct-keyword_init.rb +0 -10
- data/smoke/struct.rb +0 -13
- data/smoke/struct2.rb +0 -25
- data/smoke/struct3.rb +0 -14
- data/smoke/struct4.rb +0 -7
- data/smoke/struct5.rb +0 -16
- data/smoke/struct6.rb +0 -15
- data/smoke/struct7.rb +0 -17
- data/smoke/stub-keyword.rb +0 -10
- data/smoke/super1.rb +0 -69
- data/smoke/super2.rb +0 -16
- data/smoke/super3.rb +0 -20
- data/smoke/super4.rb +0 -45
- data/smoke/super5.rb +0 -38
- data/smoke/svar1.rb +0 -13
- data/smoke/symbol-proc-attr.rb +0 -22
- data/smoke/symbol-proc-attr2.rb +0 -15
- data/smoke/symbol-proc-bot.rb +0 -13
- data/smoke/symbol-proc.rb +0 -25
- data/smoke/tap1.rb +0 -18
- data/smoke/toplevel.rb +0 -13
- data/smoke/two-map.rb +0 -18
- data/smoke/type_var.rb +0 -11
- data/smoke/typed_method.rb +0 -16
- data/smoke/uninitialize-var.rb +0 -13
- data/smoke/union-recv.rb +0 -35
- data/smoke/user-demo.rb +0 -15
- data/smoke/wrong-extend.rb +0 -27
- data/smoke/wrong-include.rb +0 -27
- data/smoke/wrong-include2.rb +0 -17
- data/smoke/wrong-rbs.rb +0 -15
- data/smoke/wrong-rbs.rbs +0 -7
- data/testbed/ao.rb +0 -297
- data/testbed/diff-lcs-entrypoint.rb +0 -4
- data/testbed/goodcheck-Gemfile.lock +0 -51
data/lib/typeprof/iseq.rb
CHANGED
@@ -2,6 +2,17 @@ module TypeProf
|
|
2
2
|
class ISeq
|
3
3
|
# https://github.com/ruby/ruby/pull/4468
|
4
4
|
CASE_WHEN_CHECKMATCH = RubyVM::InstructionSequence.compile("case 1; when Integer; end").to_a.last.any? {|insn,| insn == :checkmatch }
|
5
|
+
# https://github.com/ruby/ruby/blob/v3_0_2/vm_core.h#L1206
|
6
|
+
VM_ENV_DATA_SIZE = 3
|
7
|
+
# Check if Ruby 3.1 or later
|
8
|
+
RICH_AST = begin RubyVM::AbstractSyntaxTree.parse("1", keep_script_lines: true).node_id; true; rescue; false; end
|
9
|
+
|
10
|
+
FileInfo = Struct.new(
|
11
|
+
:node_id2node,
|
12
|
+
:definition_table,
|
13
|
+
:caller_table,
|
14
|
+
:created_iseqs,
|
15
|
+
)
|
5
16
|
|
6
17
|
class << self
|
7
18
|
def compile(file)
|
@@ -20,17 +31,67 @@ module TypeProf
|
|
20
31
|
opt[:operands_unification] = false
|
21
32
|
opt[:coverage_enabled] = false
|
22
33
|
|
34
|
+
parse_opts = {}
|
35
|
+
parse_opts[:keep_script_lines] = true if RICH_AST
|
36
|
+
|
37
|
+
unless defined?(RubyVM::InstructionSequence)
|
38
|
+
puts "Currently, TypeProf can work on a Ruby implementation that supports RubyVM::InstructionSequence, such as CRuby."
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
23
42
|
if str
|
43
|
+
node = RubyVM::AbstractSyntaxTree.parse(str, **parse_opts)
|
24
44
|
iseq = RubyVM::InstructionSequence.compile(str, path, **opt)
|
25
45
|
else
|
46
|
+
node = RubyVM::AbstractSyntaxTree.parse_file(path, **parse_opts)
|
26
47
|
iseq = RubyVM::InstructionSequence.compile_file(path, **opt)
|
27
48
|
end
|
28
49
|
|
29
|
-
|
50
|
+
node_id2node = {}
|
51
|
+
build_ast_node_id_table(node, node_id2node) if RICH_AST
|
52
|
+
|
53
|
+
file_info = FileInfo.new(node_id2node, CodeRangeTable.new, CodeRangeTable.new, [])
|
54
|
+
iseq_rb = new(iseq.to_a, file_info)
|
55
|
+
iseq_rb.collect_local_variable_info(file_info) if RICH_AST
|
56
|
+
file_info.created_iseqs.each do |iseq|
|
57
|
+
iseq.unify_instructions
|
58
|
+
end
|
59
|
+
|
60
|
+
return iseq_rb, file_info.definition_table, file_info.caller_table
|
61
|
+
end
|
62
|
+
|
63
|
+
private def build_ast_node_id_table(node, tbl = {})
|
64
|
+
tbl[node.node_id] = node
|
65
|
+
node.children.each do |child|
|
66
|
+
build_ast_node_id_table(child, tbl) if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
67
|
+
end
|
68
|
+
tbl
|
69
|
+
end
|
70
|
+
|
71
|
+
def code_range_from_node(node)
|
72
|
+
CodeRange.new(
|
73
|
+
CodeLocation.new(node.first_lineno, node.first_column),
|
74
|
+
CodeLocation.new(node.last_lineno, node.last_column),
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_node_by_id(node, id)
|
79
|
+
node = RubyVM::AbstractSyntaxTree.parse(node) if node.is_a?(String)
|
80
|
+
|
81
|
+
return node if id == node.node_id
|
82
|
+
|
83
|
+
node.children.each do |child|
|
84
|
+
if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
85
|
+
ret = find_node_by_id(child, id)
|
86
|
+
return ret if ret
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
nil
|
30
91
|
end
|
31
92
|
end
|
32
93
|
|
33
|
-
Insn = Struct.new(:insn, :operands, :lineno)
|
94
|
+
Insn = Struct.new(:insn, :operands, :lineno, :code_range, :definitions)
|
34
95
|
class Insn
|
35
96
|
def check?(insn_cmp, operands_cmp = nil)
|
36
97
|
return insn == insn_cmp && (!operands_cmp || operands == operands_cmp)
|
@@ -39,14 +100,19 @@ module TypeProf
|
|
39
100
|
|
40
101
|
ISEQ_FRESH_ID = [0]
|
41
102
|
|
42
|
-
def initialize(iseq)
|
103
|
+
def initialize(iseq, file_info)
|
104
|
+
file_info.created_iseqs << self
|
105
|
+
|
43
106
|
@id = (ISEQ_FRESH_ID[0] += 1)
|
44
107
|
|
45
|
-
_magic, _major_version, _minor_version, _format_type,
|
108
|
+
_magic, _major_version, _minor_version, _format_type, misc,
|
46
109
|
@name, @path, @absolute_path, @start_lineno, @type,
|
47
110
|
@locals, @fargs_format, catch_table, insns = *iseq
|
48
111
|
|
49
|
-
|
112
|
+
fl, fc, ll, lc = misc[:code_location]
|
113
|
+
@iseq_code_range = CodeRange.new(CodeLocation.new(fl, fc), CodeLocation.new(ll, lc))
|
114
|
+
|
115
|
+
convert_insns(insns, misc[:node_ids] || [], file_info)
|
50
116
|
|
51
117
|
add_body_start_marker(insns)
|
52
118
|
|
@@ -54,13 +120,13 @@ module TypeProf
|
|
54
120
|
|
55
121
|
labels = create_label_table(insns)
|
56
122
|
|
57
|
-
@insns = setup_insns(insns, labels)
|
123
|
+
@insns = setup_insns(insns, labels, file_info)
|
58
124
|
|
59
125
|
@fargs_format[:opt] = @fargs_format[:opt].map {|l| labels[l] } if @fargs_format[:opt]
|
60
126
|
|
61
127
|
@catch_table = []
|
62
128
|
catch_table.map do |type, iseq, first, last, cont, stack_depth|
|
63
|
-
iseq = iseq ? ISeq.new(iseq) : nil
|
129
|
+
iseq = iseq ? ISeq.new(iseq, file_info) : nil
|
64
130
|
target = labels[cont]
|
65
131
|
entry = [type, iseq, target, stack_depth]
|
66
132
|
labels[first].upto(labels[last]) do |i|
|
@@ -69,17 +135,78 @@ module TypeProf
|
|
69
135
|
end
|
70
136
|
end
|
71
137
|
|
138
|
+
def_node_id = misc[:def_node_id]
|
139
|
+
if def_node_id && file_info.node_id2node[def_node_id] && (@type == :method || @type == :block)
|
140
|
+
def_node = file_info.node_id2node[def_node_id]
|
141
|
+
method_name_token_range = extract_method_name_token_range(def_node)
|
142
|
+
if method_name_token_range
|
143
|
+
@callers = Utils::MutableSet.new
|
144
|
+
file_info.caller_table[method_name_token_range] = @callers
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
72
148
|
rename_insn_types
|
149
|
+
end
|
73
150
|
|
74
|
-
|
151
|
+
def extract_method_name_token_range(node)
|
152
|
+
case @type
|
153
|
+
when :method
|
154
|
+
regex = if node.type == :DEFS
|
155
|
+
/^def\s+(?:\w+)\s*\.\s*(\w+)/
|
156
|
+
else
|
157
|
+
/^def\s+(\w+)/
|
158
|
+
end
|
159
|
+
return nil unless node.source =~ regex
|
160
|
+
zero_loc = CodeLocation.new(1, 0)
|
161
|
+
name_start = $~.begin(1)
|
162
|
+
name_length = $~.end(1) - name_start
|
163
|
+
name_head_loc = zero_loc.advance_cursor(name_start, node.source)
|
164
|
+
name_tail_loc = name_head_loc.advance_cursor(name_length, node.source)
|
165
|
+
return CodeRange.new(
|
166
|
+
CodeLocation.new(
|
167
|
+
node.first_lineno + (name_head_loc.lineno - 1),
|
168
|
+
name_head_loc.lineno == 1 ? node.first_column + name_head_loc.column : name_head_loc.column
|
169
|
+
),
|
170
|
+
CodeLocation.new(
|
171
|
+
node.first_lineno + (name_tail_loc.lineno - 1),
|
172
|
+
name_tail_loc.lineno == 1 ? node.first_column + name_tail_loc.column : name_tail_loc.column
|
173
|
+
),
|
174
|
+
)
|
175
|
+
when :block
|
176
|
+
return ISeq.code_range_from_node(node)
|
177
|
+
end
|
75
178
|
end
|
76
179
|
|
77
180
|
def source_location(pc)
|
78
181
|
"#{ @path }:#{ @insns[pc].lineno }"
|
79
182
|
end
|
80
183
|
|
184
|
+
def detailed_source_location(pc)
|
185
|
+
code_range = @insns[pc].code_range
|
186
|
+
if code_range
|
187
|
+
[@path, code_range]
|
188
|
+
else
|
189
|
+
[@path]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def add_called_iseq(pc, callee_iseq)
|
194
|
+
if callee_iseq && @insns[pc].definitions
|
195
|
+
@insns[pc].definitions << [callee_iseq.path, callee_iseq.iseq_code_range]
|
196
|
+
end
|
197
|
+
if callee_iseq.callers
|
198
|
+
callee_iseq.callers << [@path, @insns[pc].code_range]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def add_def_loc(pc, detailed_loc)
|
203
|
+
if detailed_loc && @insns[pc].definitions
|
204
|
+
@insns[pc].definitions << detailed_loc
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
81
208
|
attr_reader :name, :path, :absolute_path, :start_lineno, :type, :locals, :fargs_format, :catch_table, :insns
|
82
|
-
attr_reader :id
|
209
|
+
attr_reader :id, :iseq_code_range, :callers
|
83
210
|
|
84
211
|
def pretty_print(q)
|
85
212
|
q.text "ISeq["
|
@@ -118,7 +245,7 @@ module TypeProf
|
|
118
245
|
end
|
119
246
|
|
120
247
|
# Remove lineno entry and convert instructions to Insn instances
|
121
|
-
def convert_insns(insns)
|
248
|
+
def convert_insns(insns, node_ids, file_info)
|
122
249
|
ninsns = []
|
123
250
|
lineno = 0
|
124
251
|
insns.each do |e|
|
@@ -129,7 +256,25 @@ module TypeProf
|
|
129
256
|
ninsns << e
|
130
257
|
when Array
|
131
258
|
insn, *operands = e
|
132
|
-
|
259
|
+
node_id = node_ids.shift
|
260
|
+
node = file_info.node_id2node[node_id]
|
261
|
+
if node
|
262
|
+
code_range = ISeq.code_range_from_node(node)
|
263
|
+
case insn
|
264
|
+
when :send, :invokesuper
|
265
|
+
opt, blk_iseq = operands
|
266
|
+
opt[:node_id] = node_id
|
267
|
+
if blk_iseq
|
268
|
+
misc = blk_iseq[4] # iseq's "misc" field
|
269
|
+
misc[:def_node_id] = node_id
|
270
|
+
end
|
271
|
+
when :definemethod, :definesmethod
|
272
|
+
iseq = operands[1]
|
273
|
+
misc = iseq[4] # iseq's "misc" field
|
274
|
+
misc[:def_node_id] = node_id
|
275
|
+
end
|
276
|
+
end
|
277
|
+
ninsns << Insn.new(insn, operands, lineno, code_range, nil)
|
133
278
|
else
|
134
279
|
raise "unknown iseq entry: #{ e }"
|
135
280
|
end
|
@@ -156,7 +301,7 @@ module TypeProf
|
|
156
301
|
i = insns.index(label) + 1
|
157
302
|
end
|
158
303
|
|
159
|
-
insns.insert(i, Insn.new(:_iseq_body_start, [], @start_lineno))
|
304
|
+
insns.insert(i, Insn.new(:_iseq_body_start, [], @start_lineno, nil, nil))
|
160
305
|
end
|
161
306
|
end
|
162
307
|
|
@@ -198,7 +343,7 @@ module TypeProf
|
|
198
343
|
labels
|
199
344
|
end
|
200
345
|
|
201
|
-
def setup_insns(insns, labels)
|
346
|
+
def setup_insns(insns, labels, file_info)
|
202
347
|
ninsns = []
|
203
348
|
insns.each do |e|
|
204
349
|
case e
|
@@ -208,7 +353,7 @@ module TypeProf
|
|
208
353
|
operands = (INSN_TABLE[e.insn] || []).zip(e.operands).map do |type, operand|
|
209
354
|
case type
|
210
355
|
when "ISEQ"
|
211
|
-
operand && ISeq.new(operand)
|
356
|
+
operand && ISeq.new(operand, file_info)
|
212
357
|
when "lindex_t", "rb_num_t", "VALUE", "ID", "GENTRY", "CALL_DATA"
|
213
358
|
operand
|
214
359
|
when "OFFSET"
|
@@ -221,7 +366,12 @@ module TypeProf
|
|
221
366
|
end
|
222
367
|
end
|
223
368
|
|
224
|
-
|
369
|
+
if e.code_range && should_collect_defs(e.insn)
|
370
|
+
definition = Utils::MutableSet.new
|
371
|
+
file_info.definition_table[e.code_range] = definition
|
372
|
+
end
|
373
|
+
|
374
|
+
ninsns << Insn.new(e.insn, operands, e.lineno, e.code_range, definition)
|
225
375
|
else
|
226
376
|
raise "unknown iseq entry: #{ e }"
|
227
377
|
end
|
@@ -229,6 +379,63 @@ module TypeProf
|
|
229
379
|
ninsns
|
230
380
|
end
|
231
381
|
|
382
|
+
def should_collect_defs(insn_kind)
|
383
|
+
case insn_kind
|
384
|
+
when :send, :getinstancevariable, :getconstant
|
385
|
+
return true
|
386
|
+
else
|
387
|
+
return false
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
# Collect local variable use and definition info recursively
|
392
|
+
def collect_local_variable_info(file_info, absolute_level = 0, parent_variable_tables = {})
|
393
|
+
# e.g.
|
394
|
+
# variable_tables[abs_level][idx] = [[path, code_range]]
|
395
|
+
current_variables = []
|
396
|
+
variable_tables = parent_variable_tables.merge({
|
397
|
+
absolute_level => current_variables
|
398
|
+
})
|
399
|
+
|
400
|
+
dummy_def_range = CodeRange.new(
|
401
|
+
CodeLocation.new(@start_lineno, 0),
|
402
|
+
CodeLocation.new(@start_lineno, 1),
|
403
|
+
)
|
404
|
+
# Fill tail elements with parameters
|
405
|
+
(@fargs_format[:lead_num] || 0).times do |offset|
|
406
|
+
current_variables[VM_ENV_DATA_SIZE + @locals.length - offset - 1] ||= Utils::MutableSet.new
|
407
|
+
current_variables[VM_ENV_DATA_SIZE + @locals.length - offset - 1] << [@path, dummy_def_range]
|
408
|
+
end
|
409
|
+
|
410
|
+
@insns.each do |insn|
|
411
|
+
next unless insn.insn == :getlocal || insn.insn == :setlocal
|
412
|
+
|
413
|
+
idx = insn.operands[0]
|
414
|
+
# note: level is relative value to the current level
|
415
|
+
level = insn.operands[1]
|
416
|
+
target_abs_level = absolute_level - level
|
417
|
+
variable_tables[target_abs_level] ||= {}
|
418
|
+
variable_tables[target_abs_level][idx] ||= Utils::MutableSet.new
|
419
|
+
|
420
|
+
case insn.insn
|
421
|
+
when :setlocal
|
422
|
+
variable_tables[target_abs_level][idx] << [path, insn.code_range]
|
423
|
+
when :getlocal
|
424
|
+
file_info.definition_table[insn.code_range] = variable_tables[target_abs_level][idx]
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
@insns.each do |insn|
|
429
|
+
insn.operands.each do |operand|
|
430
|
+
next unless operand.is_a?(ISeq)
|
431
|
+
operand.collect_local_variable_info(
|
432
|
+
file_info, absolute_level + 1,
|
433
|
+
variable_tables
|
434
|
+
)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
232
439
|
def rename_insn_types
|
233
440
|
@insns.each do |insn|
|
234
441
|
case insn.insn
|
@@ -331,7 +538,7 @@ module TypeProf
|
|
331
538
|
break unless @insns[j + 1].check?(:putobject, [true])
|
332
539
|
break unless @insns[j + 2].check?(:getconstant) # TODO: support A::B::C
|
333
540
|
break unless @insns[j + 3].check?(:topn, [1])
|
334
|
-
break unless @insns[j + 4].check?(:send,
|
541
|
+
break unless @insns[j + 4].check?(:send) && @insns[j + 4].operands[0].slice(:mid, :flag, :orig_argc) == {:mid=>:===, :flag=>20, :orig_argc=>1}
|
335
542
|
break unless @insns[j + 5].check?(:branch)
|
336
543
|
target_pc = @insns[j + 5].operands[1]
|
337
544
|
break unless @insns[target_pc].check?(:pop, [])
|
@@ -497,7 +704,7 @@ module TypeProf
|
|
497
704
|
sp += 1
|
498
705
|
when :newhashfromarray
|
499
706
|
raise NotImplementedError, "newhashfromarray"
|
500
|
-
when :newrange, :tostring
|
707
|
+
when :newrange, :tostring, :anytostring
|
501
708
|
sp -= 2
|
502
709
|
return nil if sp <= 0
|
503
710
|
sp += 1
|