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,491 @@
1
+ module YTLJit
2
+
3
+ =begin
4
+ Stack layout (on stack frame)
5
+
6
+
7
+ Hi | |Argn | |
8
+ | | : | |
9
+ | |Arg2(self) | |
10
+ | |Arg1(block pointer) | |
11
+ | |Arg0(parent frame) | -+
12
+ | |Return Address |
13
+ +- |old bp | <-+
14
+ |old bp on stack | -+
15
+ EBP-> |Local Vars1 |
16
+ | |
17
+ | |
18
+ |Local Varsn |
19
+ |Pointer to Env |
20
+ SP -> | |
21
+ | |
22
+ LO
23
+
24
+
25
+ Stack layout (on heap frame)
26
+
27
+ |
28
+ Hi | |Arg0(parent frame) | -+
29
+ | |Arg1(block pointer) |
30
+ | |Arg2(self) |
31
+ | | : |
32
+ | |Arg n |
33
+ | |Return Address |
34
+ +- |old bp | <---+
35
+ |Pointer to Env | -+ |
36
+ SP -> | | | |
37
+ LO | | | |
38
+ | |
39
+ | |
40
+ +- | | | |
41
+ | |free func | | |
42
+ | |mark func | | |
43
+ | |T_DATA | <-+ |
44
+ | |
45
+ | |
46
+ | |Arg n | |
47
+ | | : | |
48
+ | |Arg3(exception status) | |
49
+ | |Arg2(block pointer) | |
50
+ | |Arg1(parent frame) | |
51
+ | |Arg0(self) | |
52
+ | |Not used(reserved) | |
53
+ | |Not used(reserved) | |
54
+ | |old bp on stack | -----+
55
+ EBP-> |Local Vars1 |
56
+ | | |
57
+ | | |
58
+ +->|Local Varsn |
59
+
60
+ enter procedure
61
+ push EBP
62
+ SP -> EBP
63
+ allocate frame (stack or heap)
64
+ Copy arguments if allocate frame on heap
65
+ store EBP on the top of frame
66
+ Address of top of frame -> EBP
67
+
68
+ leave procedure
69
+ Dereference of EBP -> ESP
70
+ pop EBP
71
+ ret
72
+
73
+ =end
74
+
75
+ module VM
76
+ class CollectInfoContext
77
+ def initialize(tnode)
78
+ @top_node = tnode
79
+ @modified_local_var = []
80
+ @modified_instance_var = {}
81
+ @yield_node = []
82
+ end
83
+
84
+ attr :top_node
85
+ attr :modified_local_var
86
+ attr_accessor :modified_instance_var
87
+ attr_accessor :yield_node
88
+
89
+ def merge_local_var(lvlist)
90
+ res = nil
91
+ lvlist.each do |lvs|
92
+ if res then
93
+ lvs.each_with_index do |lvt, i|
94
+ dst = res[i]
95
+ lvt.each do |idx, vall|
96
+ dst[idx] = dst[idx] | vall
97
+ end
98
+ end
99
+ else
100
+ res = lvs.map {|lvt| lvt.dup}
101
+ end
102
+ end
103
+
104
+ @modified_local_var = res
105
+ end
106
+
107
+ def merge_instance_var(lvlist)
108
+ res = nil
109
+ lvlist.each do |lvs|
110
+ if res then
111
+ lvs.each do |name, vall|
112
+ res[name] = res[name] | vall
113
+ end
114
+ else
115
+ res = lvs.dup
116
+ end
117
+ end
118
+
119
+ @modified_instance_var = res
120
+ end
121
+ end
122
+
123
+ class TypeInferenceContext
124
+ def initialize(tnode)
125
+ @top_node = tnode
126
+ @current_method_signature_node = []
127
+ @convergent = false
128
+ end
129
+
130
+ def to_key(offset = -1)
131
+ cursig = @current_method_signature_node[offset]
132
+ res = cursig.map { |enode|
133
+ if enode.is_a?(Node::BaseNode) then
134
+ enode.decide_type_once(to_key(offset - 1))
135
+ enode.type
136
+ else
137
+ enode
138
+ end
139
+ }
140
+ res
141
+ end
142
+
143
+ attr :top_node
144
+ attr :current_method_signature_node
145
+ attr_accessor :convergent
146
+ end
147
+
148
+ class CompileContext
149
+ include AbsArch
150
+ def initialize(tnode)
151
+ @top_node = tnode
152
+ @code_space = nil
153
+
154
+ # Signature of current compiling method
155
+ # It is array, because method may be nest.
156
+ @current_method_signature = []
157
+
158
+ # RETR(EAX, RAX) or RETFR(STO, XM0) or Immdiage object
159
+ @ret_reg = RETR
160
+ @ret_node = nil
161
+ @depth_reg = {}
162
+ @stack_content = []
163
+ @reg_content = {}
164
+
165
+ # Use only type inference compile mode
166
+ @slf = nil
167
+ end
168
+
169
+ attr :top_node
170
+ attr :code_space
171
+
172
+ attr :current_method_signature
173
+
174
+ attr :depth_reg
175
+ attr_accessor :ret_reg
176
+ attr_accessor :ret_node
177
+
178
+ attr :reg_content
179
+ attr :stack_content
180
+
181
+ attr_accessor :slf
182
+
183
+ def set_reg_content(dst, val)
184
+ if dst.is_a?(FunctionArgument) then
185
+ dst = dst.dst_opecode
186
+ end
187
+ if dst.is_a?(OpRegistor) then
188
+ if val.is_a?(OpRegistor)
189
+ @reg_content[dst] = @reg_content[val]
190
+ else
191
+ @reg_content[dst] = val
192
+ end
193
+ elsif dst.is_a?(OpIndirect) and dst.reg == SPR then
194
+ wsiz = AsmType::MACHINE_WORD.size
195
+ if val.is_a?(OpRegistor)
196
+ cpustack_setn(dst.disp.value / wsiz, @reg_content[val])
197
+ else
198
+ cpustack_setn(dst.disp.value / wsiz, val)
199
+ end
200
+ else
201
+ p "foo"
202
+ p dst
203
+ end
204
+ end
205
+
206
+ def cpustack_push(reg)
207
+ @stack_content.push @reg_content[reg]
208
+ end
209
+
210
+ def cpustack_pop(reg)
211
+ @reg_content[reg] = @stack_content.pop
212
+ end
213
+
214
+ def cpustack_setn(offset, val)
215
+ @stack_content[-offset] = val
216
+ end
217
+
218
+ def cpustack_pushn(num)
219
+ wsiz = AsmType::MACHINE_WORD.size
220
+ (num / wsiz).times do |i|
221
+ @stack_content.push 1.2
222
+ end
223
+ end
224
+
225
+ def cpustack_popn(num)
226
+ wsiz = AsmType::MACHINE_WORD.size
227
+ (num / wsiz).times do |i|
228
+ @stack_content.pop
229
+ end
230
+ end
231
+
232
+ def set_code_space(cs)
233
+ oldcs = @code_space
234
+ @top_node.add_code_space(@code_space, cs)
235
+ @code_space = cs
236
+ asm = @top_node.asm_tab[cs]
237
+ if asm == nil then
238
+ @top_node.asm_tab[cs] = Assembler.new(cs)
239
+ end
240
+
241
+ oldcs
242
+ end
243
+
244
+ def assembler
245
+ @top_node.asm_tab[@code_space]
246
+ end
247
+
248
+ def reset_using_reg
249
+ @depth_reg = {}
250
+ end
251
+
252
+ def start_using_reg_aux(reg)
253
+ if @depth_reg[reg] then
254
+ assembler.with_retry do
255
+ assembler.push(reg)
256
+ cpustack_push(reg)
257
+ end
258
+ else
259
+ @depth_reg[reg] = 0
260
+ end
261
+ @depth_reg[reg] += 1
262
+ end
263
+
264
+ def start_using_reg(reg)
265
+ case reg
266
+ when OpRegistor
267
+ if reg != TMPR then
268
+ start_using_reg_aux(reg)
269
+ end
270
+
271
+ when OpIndirect
272
+ case reg.reg
273
+ when BPR
274
+
275
+ else
276
+ start_using_reg_aux(reg.reg)
277
+ end
278
+
279
+ when FunctionArgument
280
+ regdst = reg.dst_opecode
281
+ if regdst.is_a?(OpRegistor)
282
+ start_using_reg_aux(regdst)
283
+ end
284
+ end
285
+ end
286
+
287
+ def end_using_reg_aux(reg)
288
+ if @depth_reg[reg] then
289
+ @depth_reg[reg] -= 1
290
+ else
291
+ raise "Not saved reg #{reg}"
292
+ end
293
+ if @depth_reg[reg] != 0 then
294
+ assembler.with_retry do
295
+ assembler.pop(reg)
296
+ cpustack_pop(reg)
297
+ end
298
+ else
299
+ @depth_reg[reg] = nil
300
+ @reg_content.delete(reg)
301
+ end
302
+ end
303
+
304
+ def end_using_reg(reg)
305
+ case reg
306
+ when OpRegistor
307
+ if reg != TMPR then
308
+ end_using_reg_aux(reg)
309
+ end
310
+
311
+ when OpIndirect
312
+ case reg.reg
313
+ when BPR
314
+
315
+ else
316
+ end_using_reg_aux(reg.reg)
317
+ end
318
+
319
+ when FunctionArgument
320
+ regdst = reg.dst_opecode
321
+ if regdst.is_a?(OpRegistor) then
322
+ end_using_reg_aux(regdst)
323
+ end
324
+ end
325
+ end
326
+
327
+ def to_key(offset = -1)
328
+ @current_method_signature[offset]
329
+ end
330
+ end
331
+
332
+ module Node
333
+ module MethodTopCodeGen
334
+ include AbsArch
335
+
336
+ def gen_method_prologue(context)
337
+ asm = context.assembler
338
+
339
+ asm.with_retry do
340
+ # Make linkage of frame pointer
341
+ asm.push(BPR)
342
+ asm.mov(BPR, SPR)
343
+ asm.push(BPR)
344
+ asm.mov(BPR, SPR)
345
+ end
346
+
347
+ context
348
+ end
349
+ end
350
+
351
+ module MethodEndCodeGen
352
+ include AbsArch
353
+
354
+ def gen_method_epilogue(context)
355
+ asm = context.assembler
356
+
357
+ # Make linkage of frame pointer
358
+ asm.with_retry do
359
+ asm.mov(SPR, BPR)
360
+ asm.pop(BPR)
361
+ asm.mov(SPR, BPR)
362
+ asm.pop(BPR)
363
+ end
364
+
365
+ context
366
+ end
367
+ end
368
+
369
+ module IfNodeCodeGen
370
+ include AbsArch
371
+ end
372
+
373
+ module LocalVarNodeCodeGen
374
+ include AbsArch
375
+
376
+ def gen_pursue_parent_function(context, depth)
377
+ asm = context.assembler
378
+ if depth != 0 then
379
+ context.start_using_reg(TMPR2)
380
+ cframe = frame_info
381
+ asm.with_retry do
382
+ asm.mov(TMPR2, BPR)
383
+ depth.times do
384
+ asm.mov(TMPR2, cframe.offset_arg(0, TMPR2))
385
+ cframe = cframe.previous_frame
386
+ end
387
+ end
388
+ context.set_reg_content(TMPR2, cframe)
389
+ context.ret_reg = TMPR2
390
+ else
391
+ context.ret_reg = BPR
392
+ end
393
+ context
394
+ end
395
+ end
396
+ end
397
+
398
+ module SendNodeCodeGen
399
+ include AbsArch
400
+
401
+ def dump_context(context)
402
+ print "---- Reg map ----\n"
403
+ context.reg_content.each do |key, value|
404
+ print "#{key} #{value.class} \n"
405
+ end
406
+
407
+ print "---- Stack map ----\n"
408
+ @frame_info.frame_layout.each_with_index do |vinf, i|
409
+ ro = @frame_info.real_offset(i)
410
+ if mlv = @modified_local_var[0][ro] then
411
+ print " #{mlv.class} \n"
412
+ else
413
+ print " #{vinf.class} \n"
414
+ end
415
+ end
416
+ context.stack_content.each do |value|
417
+ print " #{value.class} \n"
418
+ end
419
+ end
420
+
421
+ def gen_make_argv(context)
422
+ casm = context.assembler
423
+ rarg = @arguments[3..-1]
424
+
425
+ # make argv
426
+ casm = context.assembler
427
+ argbyte = rarg.size * AsmType::MACHINE_WORD.size
428
+ casm.with_retry do
429
+ casm.sub(SPR, argbyte)
430
+ end
431
+ context.cpustack_pushn(argbyte)
432
+
433
+ rarg.each_with_index do |arg, i|
434
+ context = arg.compile(context)
435
+ context.ret_node.decide_type_once(context.to_key)
436
+ rtype = context.ret_node.type
437
+ context = rtype.gen_boxing(context)
438
+ casm = context.assembler
439
+ dst = OpIndirect.new(SPR, i * AsmType::MACHINE_WORD.size)
440
+ if context.ret_reg.is_a?(OpRegistor) or
441
+ context.ret_reg.is_a?(OpImmidiate32) or
442
+ context.ret_reg.is_a?(OpImmidiate8) then
443
+
444
+ casm.with_retry do
445
+ casm.mov(dst, context.ret_reg)
446
+ end
447
+
448
+ else
449
+ casm.with_retry do
450
+ casm.mov(TMPR, context.ret_reg)
451
+ casm.mov(dst, TMPR)
452
+ end
453
+ end
454
+ context.cpustack_setn(i * AsmType::MACHINE_WORD.size, context.ret_node)
455
+ end
456
+
457
+ # Copy Stack Pointer
458
+ # TMPR2 doesnt need save. Because already saved in outside
459
+ # of send node
460
+ casm.with_retry do
461
+ casm.mov(TMPR2, SPR)
462
+ end
463
+ context.set_reg_content(TMPR2, SPR)
464
+
465
+ # stack, generate call ...
466
+ context = yield(context, rarg)
467
+
468
+ # adjust stack
469
+ casm = context.assembler
470
+ casm.with_retry do
471
+ casm.add(SPR, argbyte)
472
+ end
473
+ context.cpustack_popn(argbyte)
474
+
475
+ context
476
+ end
477
+
478
+ def gen_call(context, fnc, numarg)
479
+ casm = context.assembler
480
+
481
+ callpos = nil
482
+ casm.with_retry do
483
+ dmy, callpos = casm.call_with_arg(fnc, numarg)
484
+ end
485
+ @var_return_address = casm.output_stream.var_base_address(callpos)
486
+ dump_context(context)
487
+ context
488
+ end
489
+ end
490
+ end
491
+ end
@@ -0,0 +1,85 @@
1
+ module YTLJit
2
+ module VM
3
+ module ArithmeticOperationUtil
4
+ def gen_arithmetic_operation(context, inst, tempreg, resreg)
5
+ context.start_using_reg(tempreg)
6
+ asm = context.assembler
7
+ asm.with_retry do
8
+ asm.mov(tempreg, context.ret_reg)
9
+ end
10
+ context.set_reg_content(tempreg, context.ret_node)
11
+
12
+ # @argunemnts[1] is block
13
+ # @argunemnts[2] is self
14
+ # eval 2nd, 3thr, ... arguments and added
15
+ @arguments[3..-1].each do |aele|
16
+ context = aele.compile(context)
17
+ context.ret_node.decide_type_once(context.to_key)
18
+ rtype = context.ret_node.type
19
+ context = rtype.gen_unboxing(context)
20
+
21
+ asm = context.assembler
22
+ asm.with_retry do
23
+ asm.send(inst, tempreg, context.ret_reg)
24
+ end
25
+ end
26
+
27
+ asm.with_retry do
28
+ asm.mov(resreg, tempreg)
29
+ end
30
+ context.end_using_reg(tempreg)
31
+
32
+ context.ret_node = self
33
+ context.ret_reg = resreg
34
+
35
+ decide_type_once(context.to_key)
36
+ if type.boxed then
37
+ context = type.gen_boxing(context)
38
+ end
39
+
40
+ context
41
+ end
42
+ end
43
+
44
+ module CompareOperationUtil
45
+ def gen_compare_operation(context, inst, tempreg, resreg)
46
+ context.start_using_reg(tempreg)
47
+ asm = context.assembler
48
+ asm.with_retry do
49
+ asm.mov(tempreg, context.ret_reg)
50
+ end
51
+ context.set_reg_content(tempreg, context.ret_node)
52
+
53
+ # @argunemnts[1] is block
54
+ # @argunemnts[2] is self
55
+ # eval 2nd arguments and compare
56
+ aele = @arguments[3]
57
+ context = aele.compile(context)
58
+ context.ret_node.decide_type_once(context.to_key)
59
+ rtype = context.ret_node.type
60
+ context = rtype.gen_unboxing(context)
61
+
62
+ asm = context.assembler
63
+ asm.with_retry do
64
+ if context.ret_reg != resreg then
65
+ asm.mov(resreg, context.ret_reg)
66
+ end
67
+ asm.cmp(resreg, tempreg)
68
+ asm.send(inst, resreg)
69
+ asm.add(resreg, resreg)
70
+ end
71
+ context.end_using_reg(tempreg)
72
+
73
+ context.ret_node = self
74
+ context.ret_reg = resreg
75
+
76
+ decide_type_once(context.to_key)
77
+ if type.boxed then
78
+ context = type.gen_boxing(context)
79
+ end
80
+
81
+ context
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,74 @@
1
+ require 'tempfile'
2
+ # require 'rubygems'
3
+ # require 'drx'
4
+
5
+
6
+ module YTLJit
7
+ module VM
8
+ module Node
9
+ module Inspect
10
+ def inspect_by_graph
11
+ Inspector.new(self)
12
+ # self.see
13
+ end
14
+ end
15
+
16
+ class Inspector
17
+ def initialize(obj)
18
+ File.open('vm_struct.dot', "w") {|fp|
19
+ @fp = fp
20
+ @appear_objects = {}
21
+ @appear_objects[obj.__id__] = true
22
+ @fp.print "digraph G {\n"
23
+ inspect_aux(obj)
24
+ @fp.print "#{obj.__id__} [label=\"#{obj.class.name}\"]\n"
25
+ @fp.print "}\n"
26
+ }
27
+ end
28
+
29
+ def inspect_aux(obj)
30
+ case obj
31
+ when Array
32
+ i = 0
33
+ obj.each do |vobj|
34
+ emit(obj, vobj)
35
+ @fp.print "#{obj.__id__} -> #{vobj.__id__} [label=\"#{i}\"]\n"
36
+ i += 1
37
+ end
38
+
39
+ when Hash
40
+ obj.each do |key, vobj|
41
+ emit(obj, vobj)
42
+ if key or vobj then
43
+ @fp.print "#{obj.__id__} -> #{vobj.__id__} [label=\"#{key}\"]\n"
44
+ end
45
+ end
46
+
47
+ else
48
+ obj.instance_variables.each do |vstr|
49
+ vobj = obj.instance_variable_get(vstr)
50
+ if vobj then
51
+ @fp.print "#{obj.__id__} -> #{vobj.__id__} [label=\"#{vstr}\"]\n"
52
+ end
53
+ emit(obj, vobj)
54
+ end
55
+ end
56
+ end
57
+ private :inspect_aux
58
+
59
+ def emit(pobj, vobj)
60
+ if vobj.is_a?(Symbol) or vobj.is_a?(Fixnum) or vobj.is_a?(String) then
61
+ @fp.print "#{vobj.__id__} [label=\"#{vobj.inspect}\"]\n"
62
+ else
63
+ @fp.print "#{vobj.__id__} [label=\"#{vobj.class.name}\"]\n"
64
+ end
65
+ if @appear_objects[vobj.__id__] != true then
66
+ @appear_objects[vobj.__id__] = true
67
+ inspect_aux(vobj)
68
+ end
69
+ end
70
+ private :emit
71
+ end
72
+ end
73
+ end
74
+ end