ytljit 0.0.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.
Files changed (47) hide show
  1. data/README +29 -0
  2. data/Rakefile +22 -0
  3. data/ext/code_alloc.c +266 -0
  4. data/ext/extconf.rb +3 -0
  5. data/ext/ytljit.c +527 -0
  6. data/ext/ytljit.h +285 -0
  7. data/lib/ytljit/asm.rb +205 -0
  8. data/lib/ytljit/asmext.rb +199 -0
  9. data/lib/ytljit/asmext_x64.rb +212 -0
  10. data/lib/ytljit/asmext_x86.rb +128 -0
  11. data/lib/ytljit/asmutil.rb +182 -0
  12. data/lib/ytljit/codespace.rb +92 -0
  13. data/lib/ytljit/error.rb +7 -0
  14. data/lib/ytljit/instruction.rb +138 -0
  15. data/lib/ytljit/instruction_ia.rb +1298 -0
  16. data/lib/ytljit/instruction_x64.rb +41 -0
  17. data/lib/ytljit/instruction_x86.rb +11 -0
  18. data/lib/ytljit/marshal.rb +133 -0
  19. data/lib/ytljit/matcher.rb +235 -0
  20. data/lib/ytljit/rubyvm.rb +63 -0
  21. data/lib/ytljit/struct.rb +125 -0
  22. data/lib/ytljit/type.rb +112 -0
  23. data/lib/ytljit/util.rb +63 -0
  24. data/lib/ytljit/vm.rb +1649 -0
  25. data/lib/ytljit/vm_codegen.rb +491 -0
  26. data/lib/ytljit/vm_inline_method.rb +85 -0
  27. data/lib/ytljit/vm_inspect.rb +74 -0
  28. data/lib/ytljit/vm_sendnode.rb +561 -0
  29. data/lib/ytljit/vm_trans.rb +508 -0
  30. data/lib/ytljit/vm_type.rb +299 -0
  31. data/lib/ytljit/vm_type_gen.rb +158 -0
  32. data/lib/ytljit/vm_typeinf.rb +98 -0
  33. data/lib/ytljit.rb +46 -0
  34. data/test/asmsample.rb +117 -0
  35. data/test/cstest.rb +61 -0
  36. data/test/marshaltest.rb +27 -0
  37. data/test/test_assemble.rb +148 -0
  38. data/test/test_assemble2.rb +286 -0
  39. data/test/test_codespace.rb +102 -0
  40. data/test/test_typeinf.rb +21 -0
  41. data/test/tivmtest.rb +54 -0
  42. data/test/vmtest.rb +59 -0
  43. data/test/vmtest2.rb +41 -0
  44. data/test/vmtest3.rb +22 -0
  45. data/test/vmtest_compile_only.rb +41 -0
  46. data/test/vmtest_execute_only.rb +22 -0
  47. metadata +121 -0
@@ -0,0 +1,41 @@
1
+ module YTLJit
2
+ module AssemblerUtilX64
3
+ def rex(dst, src)
4
+ rrex = 0
5
+ if dst.is_a?(OpReg64) then
6
+ rrex |= 0b1000
7
+ if dst.reg_no >= 8 then
8
+ rrex |= 0b1
9
+ end
10
+ end
11
+
12
+ if src.is_a?(OpReg64) then
13
+ rrex |= 0b1000
14
+ if src.reg_no >= 8 then
15
+ rrex |= 0b100
16
+ end
17
+ end
18
+
19
+ if src.is_a?(OpImmidiate64) then
20
+ rrex |= 0b1000
21
+ end
22
+
23
+ if rrex != 0 then
24
+ [[0x40 + rrex], "C"]
25
+ else
26
+ [[], ""]
27
+ end
28
+ end
29
+
30
+ def immidiate_call(addr, offset)
31
+ if offset.abs > 0x7fff_ffff then
32
+ addrent = @asm.add_value_entry(addr)
33
+ offset = addrent.value - @asm.current_address - 7
34
+ modseq, modfmt = modrm(:call, 2, offset, nil, addr)
35
+ [0x48, 0xff, *modseq, offset].pack("CC#{modfmt}L")
36
+ else
37
+ [0xe8, offset].pack("CL")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ module YTLJit
2
+ module AssemblerUtilX86
3
+ def rex(dst, src)
4
+ [[], ""]
5
+ end
6
+
7
+ def immidiate_call(addr, offset)
8
+ [0xe8, offset].pack("CL")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,133 @@
1
+ class Proc
2
+ @@iseq_cache = {}
3
+
4
+ def self._alloc
5
+ Proc.new {}
6
+ end
7
+
8
+ def _dump_data
9
+ orgiseq = self.to_iseq
10
+ piseq = @@iseq_cache[orgiseq]
11
+ if !piseq then
12
+ piseq = @@iseq_cache[orgiseq] = patch_iseq(orgiseq.to_a)
13
+ end
14
+
15
+ [piseq, self.binding.to_a]
16
+ end
17
+
18
+ def _load_data(obj)
19
+ iseq, env = obj
20
+ slf = env[0][0]
21
+ $_proc_para = [env, slf]
22
+ prc = lambda {
23
+ $_proc_para[1].instance_eval {
24
+ lambda {|env|
25
+ _lambda_replace
26
+ }
27
+ }.call($_proc_para[0].map {|ele| ele.reverse})
28
+ }
29
+
30
+ prc2 = VMLib::InstSeqTree.new(nil, prc.to_iseq.to_a)
31
+ iv = VMLib::InstSeqTree.new(nil, prc2.body[7][3])
32
+ lam = VMLib::InstSeqTree.new(nil, iv.body[5][3])
33
+ lam.body[4][1] = :lambda
34
+ lam.body[4][3] = iseq
35
+
36
+ prc2.header['type'] = :top
37
+
38
+ self.copy(ISeq.load(prc2.to_a).eval)
39
+ end
40
+
41
+ def patch_iseq(iseq, dbase = 0)
42
+ rbody = []
43
+ iseq2 = VMLib::InstSeqTree.new(nil, iseq)
44
+
45
+ iseq2.body.each do |ele|
46
+ rbody.push ele
47
+ if ele.is_a?(Array) then
48
+ case ele[0]
49
+ when :send
50
+ if ele[3] then
51
+ ele[3] = patch_iseq(VMLib::InstSeqTree.new(iseq, ele[3]), dbase + 1)
52
+ end
53
+
54
+ when :getdynamic
55
+ off = ele[1]
56
+ dep = ele[2]
57
+ if dep > dbase then
58
+ rbody.pop
59
+ rbody.push [:getdynamic, 3, 1 + dbase]
60
+ rbody.push [:putobject, dep - 1 - dbase]
61
+ rbody.push [:opt_aref, 0]
62
+ rbody.push [:putobject, off]
63
+ rbody.push [:opt_aref, 0]
64
+ end
65
+
66
+ when :setdynamic
67
+ off = ele[1]
68
+ dep = ele[2]
69
+ if dep > dbase then
70
+ rbody.pop
71
+ rbody.push [:getdynamic, 3, 1 + dbase]
72
+ rbody.push [:putobject, dep - 1 - dbase]
73
+ rbody.push [:opt_aref, 0]
74
+ rbody.push [:putobject, off]
75
+ rbody.push [:topn, 2]
76
+ rbody.push [:send, :[]=, 2, nil, 0, 0]
77
+ rbody.push [:swap]
78
+ rbody.push [:pop]
79
+ end
80
+
81
+ when :getlocal
82
+ off = ele[1]
83
+ rbody.pop
84
+ rbody.push [:getdynamic, 2, 1 + dbase]
85
+ rbody.push [:dup]
86
+ rbody.push [:opt_length]
87
+ rbody.push [:putobject, 1]
88
+ rbody.push [:opt_sub]
89
+ rbody.push [:putobject, dbase]
90
+ rbody.push [:opt_add]
91
+ rbody.push [:opt_aref, 0]
92
+ rbody.push [:putobject, off]
93
+ rbody.push [:opt_aref, 0]
94
+
95
+ when :setlocal
96
+ off = ele[1]
97
+ rbody.pop
98
+ rbody.push [:getdynamic, 2, 1 + dbase]
99
+ rbody.push [:dup]
100
+ rbody.push [:opt_length]
101
+ rbody.push [:putobject, 1]
102
+ rbody.push [:opt_sub]
103
+ rbody.push [:putobject, dbase]
104
+ rbody.push [:opt_add]
105
+ rbody.push [:opt_aref, 0]
106
+ rbody.push [:putobject, off]
107
+ rbody.push [:topn, 2]
108
+ rbody.push [:send, :[]=, 2, nil, 0, 0]
109
+ rbody.push [:swap]
110
+ rbody.push [:pop]
111
+ end
112
+ end
113
+ end
114
+
115
+ iseq2.body = rbody
116
+ iseq2.to_a
117
+ end
118
+ end
119
+
120
+ module YTLJit
121
+ class CodeSpace
122
+ def _dump_data
123
+ [@refer_operands, current_pos, code]
124
+ end
125
+
126
+ def _load_data(obj)
127
+ self[0] = obj.pop
128
+ current_pos = obj.pop
129
+ @org_base_address = base_address
130
+ @refer_operands = obj.pop
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,235 @@
1
+ # Pattern matcher
2
+ # Usage
3
+ # When pattern matched, block is yielded with argument is hash that maps
4
+ # symbol to value.
5
+ #
6
+ # mat = Matcher.new
7
+ # mat.pattern([:a, :b]) {|hash|
8
+ # p hash
9
+ # }
10
+ # mat.match([1, 2])
11
+ #
12
+ # Output "{:a => 1, :b => 2}"
13
+ #
14
+ # [Class_Name, Symbol] is special case.
15
+ # Match when class of corresponding value is Class_Name. And bind
16
+ # Symbol in argument hash of block.
17
+ #
18
+ # mat.pattern([:a, [Array, :d]]) {|hash|
19
+ # p hash
20
+ # }
21
+ # mat.match([1, [3, 4, 5]])
22
+ #
23
+ # Output "{:a=>1, :d=>[3, 4, 5]}"
24
+ #
25
+ #
26
+ # You can use multiple patterns
27
+ # When multiple patterns matched execute a block for 1 pattern. But
28
+ # execution pattern is undefined.
29
+ #
30
+ # mat = Matcher.new
31
+ # mat.pattern([:a, :b]) {|hash|
32
+ # p hash
33
+ # }
34
+ # mat.pattern(:a) {|hash|
35
+ # p hash
36
+ # }
37
+ # mat.pattern([:a, [:b, :d]]) {|hash|
38
+ # p hash
39
+ # }
40
+ # mat.pattern([:a, [Array, :d], :c]) {|hash|
41
+ # p hash
42
+ # }
43
+ # mat.match([1, [2, 3]]) # => {:a=>1, :b=>[2, 3]}
44
+ # mat.match([1, [2, 3], 4]) # => {:a=>1, :d=>[2, 3], :c=>4}
45
+ # mat.match([1, [2, 3], 4, 5]) # => {:a=>[1, [2, 3], 4, 5]}
46
+ #
47
+
48
+ #
49
+ class QuotedObj
50
+ def self.quote(obj)
51
+ self.new(obj)
52
+ end
53
+
54
+ def initialize(obj)
55
+ @obj = obj
56
+ end
57
+
58
+ attr :obj
59
+ end
60
+
61
+ class Matcher
62
+ def initialize
63
+ @cache = {}
64
+ @code = nil
65
+ @pattern = []
66
+ end
67
+
68
+ def match(src)
69
+ unless @code
70
+ compile
71
+ end
72
+ @src = src
73
+ @code.eval
74
+ end
75
+
76
+ def pattern(pat, &block)
77
+ unless @code
78
+ @pattern.push [pat, block]
79
+ end
80
+ end
81
+
82
+ def compile
83
+ info = {}
84
+ @pattern.each do |pat|
85
+ env = {}
86
+ cond = compile_aux(pat[0], [], env, [])[0]
87
+ info[cond] = [env, pat[1]]
88
+ end
89
+ @code = code_gen(info)
90
+ end
91
+
92
+ def compile_aux(pat, stack, env, cond)
93
+ status = :normal
94
+ case pat
95
+ when Array
96
+ if pat[0].is_a?(Class) then
97
+ cond.push "(#{get_patref(stack)}.is_a?(#{pat[0]}))"
98
+ env[pat[1]] = "#{get_patref(stack)}"
99
+ else
100
+ cond.push "(#{get_patref(stack)}.is_a?(Array))"
101
+ stack.push 0
102
+ pat.each_with_index do |ele, i|
103
+ stack[-1] = i
104
+ cond, st = compile_aux(ele, stack, env, cond)
105
+ if st == :return then
106
+ stack.pop
107
+ return [cond, status]
108
+ end
109
+ end
110
+ stack[-1] = pat.size
111
+ cond.push "(#{get_patref(stack)} == nil)"
112
+ stack.pop
113
+ end
114
+
115
+ when Symbol
116
+ patstr = pat.to_s
117
+ if patstr[0] == '_' then
118
+ npat = patstr[1..-1].to_sym
119
+ if env[npat] then
120
+ cond.push "#{get_patref_rest(stack)} == #{env[npat]}"
121
+ else
122
+ env[npat] = get_patref_rest(stack)
123
+ end
124
+ status = :return
125
+ else
126
+ if env[pat] then
127
+ cond.push "(#{get_patref(stack)}.is_a?(Symbol) or #{get_patref(stack)} == #{env[pat]})"
128
+ else
129
+ env[pat] = get_patref(stack).to_s
130
+ end
131
+ end
132
+
133
+ when QuotedObj
134
+ cond.push "(#{get_patref(stack)} == #{pat.obj.inspect})"
135
+
136
+ else
137
+ cond.push "(#{get_patref(stack)} == #{pat})"
138
+ end
139
+
140
+ return [cond, status]
141
+ end
142
+
143
+ def get_patref(stack)
144
+ code = "@src"
145
+ stack.each do |n|
146
+ code += "[#{n}]"
147
+ end
148
+ code
149
+ end
150
+
151
+ def get_patref_rest(stack)
152
+ code = "@src"
153
+ top = stack.pop
154
+ stack.each do |n|
155
+ code += "[#{n}]"
156
+ end
157
+ code += "[#{top}.. -1]"
158
+ stack.push top
159
+ code
160
+ end
161
+
162
+ def code_gen(info)
163
+ ct = {}
164
+ info.each do |carr, val|
165
+ cursor = ct
166
+ carr.each do |cele|
167
+ cursor[cele] ||= {}
168
+ cursor = cursor[cele]
169
+ end
170
+ cursor[nil] = val
171
+ end
172
+
173
+ code = <<-EOS
174
+ org_self = self
175
+ ObjectSpace._id2ref(#{self.object_id}).instance_eval do
176
+ #{cond_gen(ct, 0)}
177
+ end
178
+ EOS
179
+ RubyVM::InstructionSequence.compile(code)
180
+ end
181
+
182
+ def cond_gen(tr, level)
183
+ code = ""
184
+ tr.each do |cond, nxt|
185
+ if cond then
186
+ code << "if #{cond} then \n"
187
+ code << cond_gen(nxt, level + 1)
188
+ code << "end\n"
189
+ end
190
+ end
191
+ if tr[nil] then
192
+ code << "#{exec_gen(tr[nil])} \n"
193
+ end
194
+ code
195
+ end
196
+
197
+ def exec_gen(para)
198
+ hash = "{"
199
+ para[0].each do |key, value|
200
+ hash << ":#{key} => #{value},"
201
+ end
202
+ hash << "}"
203
+
204
+ proc = para[1]
205
+ "break ObjectSpace._id2ref(#{proc.object_id}).call(#{hash})"
206
+ end
207
+ end
208
+
209
+ if __FILE__ == $0 then
210
+ mat = Matcher.new
211
+ mat.pattern([:a, :b]) {|hash|
212
+ p hash
213
+ }
214
+ mat.pattern([:a, :_b]) {|hash|
215
+ p hash
216
+ }
217
+ mat.pattern(:a) {|hash|
218
+ p hash
219
+ }
220
+ mat.pattern([:a, [:b, :_c], 1]) {|hash|
221
+ p hash
222
+ }
223
+ mat.pattern([:a, [Array, :d], :c]) {|hash|
224
+ p hash
225
+ }
226
+ mat.pattern([QuotedObj.quote(:a), [Array, :d], :c]) {|hash|
227
+ p hash
228
+ }
229
+ mat.match([1, [2, 3]])
230
+ mat.match([1, [2, 3, 4], 4, :a])
231
+ mat.match([1, [2, 3, 4], 1])
232
+ mat.match([1, [2, 3], 4, 5])
233
+ mat.match([:a, [2, 3], 2 ])
234
+ end
235
+
@@ -0,0 +1,63 @@
1
+ # -*- coding: cp932 -*-
2
+ #
3
+ # rubyvm.rb - structured bytecode library
4
+ #
5
+ #
6
+ module VMLib
7
+ class InstSeqTree
8
+ Headers = %w(magic major_version minor_version format_type
9
+ misc name filename filepath line type locals args
10
+ exception_table)
11
+
12
+ # call-seq:
13
+ # VMLib::InstSeqTree.new(parent, iseq)
14
+ # parent Partent of InstSeqTree
15
+ # For example, when you will construct InstSeqTree of
16
+ # the method body, you must 'parent' is InstSeqTree of definition
17
+ # code of the method.
18
+ # If parent is none, 'parent' is nil.
19
+ # iseq Instruction Sequence, Normally the result of
20
+ # VM::InstructionSequence.compile(...) or
21
+ # VM::InstructionSequence.compile_file(...)
22
+ def initialize(parent = nil, iseq = nil)
23
+ @lblock = {}
24
+ @lblock_list = [nil]
25
+
26
+ @header = {}
27
+ @body = nil
28
+ @parent = parent
29
+
30
+ Headers.each do |name|
31
+ @header[name] = nil
32
+ end
33
+
34
+ if iseq then
35
+ init_from_ary(iseq.to_a)
36
+ end
37
+ end
38
+
39
+ attr :header
40
+ attr_accessor :body
41
+ attr :parent
42
+
43
+ def init_from_ary(ary)
44
+ i = 0
45
+ Headers.each do |name|
46
+ @header[name] = ary[i]
47
+ i = i + 1
48
+ end
49
+
50
+ @body = ary[i]
51
+ end
52
+
53
+ def to_a
54
+ res = []
55
+ Headers.each do |name|
56
+ res.push @header[name]
57
+ end
58
+
59
+ res.push @body
60
+ res
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,125 @@
1
+ module YTLJit
2
+ module AsmType
3
+ class StructMember<TypeCommon
4
+ def initialize(type, offset)
5
+ @type = type
6
+ @offset = offset
7
+ end
8
+
9
+ attr :offset
10
+
11
+ def size
12
+ @type.size
13
+ end
14
+
15
+ def [](name)
16
+ @type[name, @offset]
17
+ end
18
+ end
19
+
20
+ class Struct<TypeCommon
21
+ def initialize(*spec)
22
+ @member = []
23
+ @size = nil
24
+ stat = 0
25
+ curvar = []
26
+ spec.each do |token|
27
+ case stat
28
+ when 0
29
+ curvar.push token
30
+ stat = 1
31
+
32
+ when 1
33
+ curvar.push token
34
+ stat = 2
35
+
36
+ when 2
37
+ if token.is_a?(Integer) then
38
+ curvar.push token
39
+ @member.push curvar
40
+ curvar = []
41
+ stat = 0
42
+ else
43
+ @member.push curvar
44
+ if token then
45
+ curvar = [token]
46
+ stat = 1
47
+ else
48
+ curvar = []
49
+ stat = 0
50
+ end
51
+ end
52
+ end
53
+ # assert(stat == 0)
54
+ end
55
+ @member.push curvar
56
+ end
57
+
58
+ def offset_of(name, base = 0)
59
+ offset = 0
60
+ @member.each do |e|
61
+ if e[1] == name then
62
+ return offset + base
63
+ end
64
+ offset += e[2] ? e[2] : e[0].size
65
+ end
66
+ raise "No such member #{name} in #{self}"
67
+ end
68
+
69
+ def type_of(name)
70
+ offset = 0
71
+ @member.each do |e|
72
+ if e[1] == name then
73
+ return e[0]
74
+ end
75
+ end
76
+ raise "No such member #{name} in #{self}"
77
+ end
78
+
79
+ def size
80
+ if @size then
81
+ @size
82
+ else
83
+ @size = 0
84
+ @member.each do |e|
85
+ @size += e[2] ? e[2] : e[0].size
86
+ end
87
+ @size
88
+ end
89
+ end
90
+
91
+ def [](name, base = 0)
92
+ offset = 0
93
+ @member.each do |e|
94
+ if e[1] == name then
95
+ return StructMember.new(e[0], offset + base)
96
+ end
97
+ offset += e[2] ? e[2] : e[0].size
98
+ end
99
+ raise "No such member #{name} in #{self}"
100
+ end
101
+ end
102
+
103
+ class Union<Struct
104
+ def offset_of(name, base = 0)
105
+ base
106
+ end
107
+
108
+ def size
109
+ if @size then
110
+ @size
111
+ else
112
+ @size = 0
113
+ @member.each do |e|
114
+ @size = [@size, e[2] ? e[2] : e[0].size].max
115
+ end
116
+ @size
117
+ end
118
+ end
119
+
120
+ def [](name, base = 0)
121
+ StructMember.new(type_of(name), base)
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,112 @@
1
+ module YTLJit
2
+
3
+ module AsmType
4
+ class TypeCommon
5
+ def initialize
6
+ @type = nil
7
+ @size = nil
8
+ @alignment = nil
9
+ end
10
+
11
+ attr :type
12
+ attr :size
13
+ attr :alignment
14
+ end
15
+
16
+ class Scalar<TypeCommon
17
+ def initialize(size, align = 4, kind = :int)
18
+ @size = size
19
+ @alignment = align
20
+ @kind = kind
21
+ end
22
+ end
23
+
24
+ class PointedData<TypeCommon
25
+ def initialize(type, index, offset)
26
+ @type = type
27
+ @index = index
28
+ @offset = offset
29
+ end
30
+
31
+ attr :index
32
+ attr :offset
33
+
34
+ def size
35
+ @reftype.size
36
+ end
37
+
38
+ def alignment
39
+ @reftype.alignment
40
+ end
41
+ end
42
+
43
+ class Pointer<TypeCommon
44
+ def initialize(type)
45
+ @type = type
46
+ end
47
+
48
+ def size
49
+ MACHINE_WORD.size
50
+ end
51
+
52
+ def alignment
53
+ MACHINE_WORD.alignment
54
+ end
55
+
56
+ def [](n = 0, offset = 0)
57
+ PointedData.new(@reftype, n, offset)
58
+ end
59
+ end
60
+
61
+ class Array<TypeCommon
62
+ def initialize(type, size)
63
+ @type = type
64
+ @size = size
65
+ end
66
+
67
+ def size
68
+ @size * @type.size
69
+ end
70
+
71
+ def alignment
72
+ @type.alignment
73
+ end
74
+
75
+ def [](n = 0, offset = 0)
76
+ PointedData.new(@reftype, n, offset)
77
+ end
78
+ end
79
+
80
+ @@type_table = {}
81
+ def self.deftype(name, tinfo)
82
+ type = Scalar.new(*tinfo)
83
+ const_set(name.to_s.upcase, type)
84
+ @@type_table[name] = type
85
+ end
86
+
87
+ def self.type_table
88
+ @@type_table
89
+ end
90
+
91
+ deftype :void, [0, 1]
92
+ deftype :int8, [1, 1]
93
+ deftype :sint8, [1, 1]
94
+ deftype :uint8, [1, 1]
95
+ deftype :int16, [2, 2]
96
+ deftype :uint16, [2, 2]
97
+ deftype :int32, [4, 4]
98
+ deftype :uint32, [4, 4]
99
+ deftype :int64, [8, 8]
100
+ deftype :uint64, [8, 8]
101
+ deftype :double, [8, 8]
102
+ deftype :float, [4, 4]
103
+
104
+ case $ruby_platform
105
+ when /i.86/
106
+ deftype :machine_word, [4, 4]
107
+
108
+ when /x86_64/
109
+ deftype :machine_word, [8, 8]
110
+ end
111
+ end
112
+ end