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.
- data/README +29 -0
- data/Rakefile +22 -0
- data/ext/code_alloc.c +266 -0
- data/ext/extconf.rb +3 -0
- data/ext/ytljit.c +527 -0
- data/ext/ytljit.h +285 -0
- data/lib/ytljit/asm.rb +205 -0
- data/lib/ytljit/asmext.rb +199 -0
- data/lib/ytljit/asmext_x64.rb +212 -0
- data/lib/ytljit/asmext_x86.rb +128 -0
- data/lib/ytljit/asmutil.rb +182 -0
- data/lib/ytljit/codespace.rb +92 -0
- data/lib/ytljit/error.rb +7 -0
- data/lib/ytljit/instruction.rb +138 -0
- data/lib/ytljit/instruction_ia.rb +1298 -0
- data/lib/ytljit/instruction_x64.rb +41 -0
- data/lib/ytljit/instruction_x86.rb +11 -0
- data/lib/ytljit/marshal.rb +133 -0
- data/lib/ytljit/matcher.rb +235 -0
- data/lib/ytljit/rubyvm.rb +63 -0
- data/lib/ytljit/struct.rb +125 -0
- data/lib/ytljit/type.rb +112 -0
- data/lib/ytljit/util.rb +63 -0
- data/lib/ytljit/vm.rb +1649 -0
- data/lib/ytljit/vm_codegen.rb +491 -0
- data/lib/ytljit/vm_inline_method.rb +85 -0
- data/lib/ytljit/vm_inspect.rb +74 -0
- data/lib/ytljit/vm_sendnode.rb +561 -0
- data/lib/ytljit/vm_trans.rb +508 -0
- data/lib/ytljit/vm_type.rb +299 -0
- data/lib/ytljit/vm_type_gen.rb +158 -0
- data/lib/ytljit/vm_typeinf.rb +98 -0
- data/lib/ytljit.rb +46 -0
- data/test/asmsample.rb +117 -0
- data/test/cstest.rb +61 -0
- data/test/marshaltest.rb +27 -0
- data/test/test_assemble.rb +148 -0
- data/test/test_assemble2.rb +286 -0
- data/test/test_codespace.rb +102 -0
- data/test/test_typeinf.rb +21 -0
- data/test/tivmtest.rb +54 -0
- data/test/vmtest.rb +59 -0
- data/test/vmtest2.rb +41 -0
- data/test/vmtest3.rb +22 -0
- data/test/vmtest_compile_only.rb +41 -0
- data/test/vmtest_execute_only.rb +22 -0
- 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
|