ytljit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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