Class: YTLJit::VM::Node::SendNode

Inherits:
BaseNode show all
Includes:
HaveChildlenMixin, NodeUtil, OptFlagOp, SendUtil, SendNodeCodeGen
Defined in:
lib/ytljit/vm_sendnode.rb

Overview

Send methodes

Constant Summary collapse

@@current_node =
nil
@@special_node_tab =
{}
@@macro_tab =
{}
@@user_defined_method_tab =
{}

Constants included from AbsArch

AbsArch::AL, AbsArch::BL, AbsArch::CL, AbsArch::DL, AbsArch::FUNC_ARG, AbsArch::FUNC_ARG_YTL, AbsArch::FUNC_FLOAT_ARG, AbsArch::FUNC_FLOAT_ARG_YTL, AbsArch::INDIRECT_BPR, AbsArch::INDIRECT_RETR, AbsArch::INDIRECT_SPR, AbsArch::INDIRECT_TMPR, AbsArch::INDIRECT_TMPR2, AbsArch::INDIRECT_TMPR3

Constants included from SSE

SSE::XMM0, SSE::XMM1, SSE::XMM2, SSE::XMM3, SSE::XMM4, SSE::XMM5, SSE::XMM6, SSE::XMM7

Constants inherited from BaseNode

BaseNode::ESCAPE_LEVEL

Instance Attribute Summary collapse

Attributes included from HaveChildlenMixin

#body

Attributes inherited from BaseNode

#code_space, #debug_info, #element_node_list, #id, #is_escape, #parent, #ti_observee, #ti_observer, #type

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SendUtil

#compile_c_fixarg, #compile_c_fixarg_raw, #compile_c_vararg, #compile_ytl, #gen_eval_self, #signature

Methods included from NodeUtil

#search_class_top, #search_end, #search_frame_info, #search_top

Methods included from SendNodeCodeGen

#gen_make_argv

Methods included from CommonCodeGen

#dump_context, #gen_alloca, #gen_call, #gen_save_thepr

Methods included from OptFlagOp

#is_args_blockarg, #is_args_splat, #is_fcall, #is_opt_send, #is_super, #is_tailcall, #is_tailrecursion, #is_vcall

Methods inherited from BaseNode

#add_element_node, #add_element_node_backward, #add_element_node_backward_aux, #decide_type, #decide_type_core, #decide_type_once, #gen_type_inference_proc, #inference_type, #marge_element_node, #marge_type, #same_type, #search_valid_signature, #set_escape_node, #set_escape_node_backward, #ti_add_observer, #ti_changed, #ti_del_link, #ti_reset, #ti_update

Methods included from TypeListWithSignature

#add_type, #set_type_list, #type_list, #type_list_initvar

Methods included from Inspect

#inspect_by_graph

Constructor Details

#initialize(parent, func, arguments, op_flag, seqno) ⇒ SendNode

Returns a new instance of SendNode.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/ytljit/vm_sendnode.rb', line 140

def initialize(parent, func, arguments, op_flag, seqno)
  super(parent)
  @func = func
  @arguments = arguments
  @opt_flag = op_flag
  @seq_no = seqno
  @next_node = @@current_node
  @@current_node = self

  @class_top = search_class_top
  @frame_info = search_frame_info

  @modified_instance_var = nil
  @modified_local_var = [{}]

  @result_cache = nil
  @method_signature = []
  @yield_signature_cache = {}

  @current_exception_table = nil
end

Instance Attribute Details

#argumentsObject

Returns the value of attribute arguments.



163
164
165
# File 'lib/ytljit/vm_sendnode.rb', line 163

def arguments
  @arguments
end

#class_topObject (readonly)

Returns the value of attribute class_top.



166
167
168
# File 'lib/ytljit/vm_sendnode.rb', line 166

def class_top
  @class_top
end

#current_exception_tableObject

Returns the value of attribute current_exception_table.



174
175
176
# File 'lib/ytljit/vm_sendnode.rb', line 174

def current_exception_table
  @current_exception_table
end

#frame_infoObject (readonly)

Returns the value of attribute frame_info.



167
168
169
# File 'lib/ytljit/vm_sendnode.rb', line 167

def frame_info
  @frame_info
end

#funcObject

Returns the value of attribute func.



162
163
164
# File 'lib/ytljit/vm_sendnode.rb', line 162

def func
  @func
end

#modified_instance_varObject (readonly)

Returns the value of attribute modified_instance_var.



169
170
171
# File 'lib/ytljit/vm_sendnode.rb', line 169

def modified_instance_var
  @modified_instance_var
end

#modified_local_varObject (readonly)

Returns the value of attribute modified_local_var.



168
169
170
# File 'lib/ytljit/vm_sendnode.rb', line 168

def modified_local_var
  @modified_local_var
end

#next_nodeObject (readonly)

Returns the value of attribute next_node.



165
166
167
# File 'lib/ytljit/vm_sendnode.rb', line 165

def next_node
  @next_node
end

#opt_flagObject (readonly)

Returns the value of attribute opt_flag.



164
165
166
# File 'lib/ytljit/vm_sendnode.rb', line 164

def opt_flag
  @opt_flag
end

#result_cacheObject

Returns the value of attribute result_cache.



170
171
172
# File 'lib/ytljit/vm_sendnode.rb', line 170

def result_cache
  @result_cache
end

#seq_noObject (readonly)

Returns the value of attribute seq_no.



171
172
173
# File 'lib/ytljit/vm_sendnode.rb', line 171

def seq_no
  @seq_no
end

#yield_signature_cacheObject (readonly)

Returns the value of attribute yield_signature_cache.



172
173
174
# File 'lib/ytljit/vm_sendnode.rb', line 172

def yield_signature_cache
  @yield_signature_cache
end

Class Method Details

.add_special_send_node(name) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/ytljit/vm_sendnode.rb', line 65

def self.add_special_send_node(name)
  oldcls = @@special_node_tab[name]
  if oldcls == nil or self < oldcls then
    @@special_node_tab[name] = self

  else
    raise "Illigal SendNode #{self} #{name}"
  end
end

.get_macro_tabObject



57
58
59
# File 'lib/ytljit/vm_sendnode.rb', line 57

def self.get_macro_tab
  @@macro_tab
end

.get_user_defined_method_tabObject



61
62
63
# File 'lib/ytljit/vm_sendnode.rb', line 61

def self.get_user_defined_method_tab
  @@user_defined_method_tab
end

.macro_expand(context, func, arguments, op_flag, seqno) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/ytljit/vm_sendnode.rb', line 75

def self.macro_expand(context, func, arguments, op_flag, seqno)
  if @@macro_tab[func.name] and 
      (op_flag & (0b11 << 3)) != 0 then
    cclsnode = context.current_class_node
    if context.current_method_node == nil then
      cclsnode = cclsnode.make_klassclass_node
    end

    cclsnode.klass_object.ancestors.each do |ccls|
      cnode = ClassTopNode.get_class_top_node(ccls)
      cobj = nil
      if cnode then
        cobj = cnode.klass_object
      end

      if @@user_defined_method_tab[func.name] and
          @@user_defined_method_tab[func.name].include?(cobj) then
        return nil
      end

      mproc = @@macro_tab[func.name][cobj]
      if mproc then
        args = []
        arguments[3..-1].each do |ele|
          argruby = ele.to_ruby(ToRubyContext.new).ret_code.last
          args.push eval(argruby)
        end

        # define used methods in macro
        @@macro_tab.each do |name, val|
          val.each do |rec, proc|
            if rec.is_a?(Module) then
              name1 = ("ytl__eval_" + name.to_s).to_sym
              if proc.is_a?(Proc)
                rec.class_eval {define_method(name1, &proc)}
              end
            end
          end
        end

        # call eval included method
        return mproc.call(*args)
      end
    end
  end

  nil
end

.make_send_node(parent, func, arguments, op_flag, seqno) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/ytljit/vm_sendnode.rb', line 124

def self.make_send_node(parent, func, arguments, op_flag, seqno)
  spcl = @@special_node_tab[func.name]
  newobj = nil
  if spcl then
    newobj = spcl.new(parent, func, arguments, op_flag, seqno)
  else
    newobj = self.new(parent, func, arguments, op_flag, seqno)
  end
  func.parent = newobj
  arguments.each do |ele|
    ele.parent = newobj
  end

  newobj
end

.nodeObject



53
54
55
# File 'lib/ytljit/vm_sendnode.rb', line 53

def self.node
  @@current_node
end

Instance Method Details

#check_signature_changed(context, signat, metsigent, cursig) ⇒ Object



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/ytljit/vm_sendnode.rb', line 265

def check_signature_changed(context, signat, metsigent, cursig)
  if metsigent then
    if metsigent[1][1] != signat[1] then
      # Why not push, because it excepted type inference about
      # this signature after. So reduce search loop.
      @method_signature.unshift [cursig, signat]
      context.convergent = false
      signat[1].ruby_type < metsigent[1][1].ruby_type
    else
      false
    end

  else
    @method_signature.unshift [cursig, signat]
    false
  end
end

#collect_candidate_type(context) ⇒ Object



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# File 'lib/ytljit/vm_sendnode.rb', line 377

def collect_candidate_type(context)
  cursig = context.to_signature

  # get saved original signature
  metsigent = search_signature(cursig)

  # prev env
  context = @arguments[0].collect_candidate_type(context)

  # block is after detect method
  blknode = @arguments[1]

  # other
  @arguments[2.. -1].each do |arg|
    context = arg.collect_candidate_type(context)
  end

  # function select
  context = @func.collect_candidate_type(context)

  signat = signature(context)
  ysig = @yield_signature_cache[cursig]
  if ysig then
    signat[1] = blknode.decide_type_once(ysig)
  end
  if @func.is_a?(YieldNode) then
    signat[1] = cursig[0]
  end
=begin
  if changed then
    @arguments.each do |arg|
      arg.type = nil
    end
    signat = signature(context)
  end
=end

  mt, slf = get_send_method_node(cursig)
  if mt then
=begin
    changed = check_signature_changed(context, signat, 
                                      metsigent, cursig)
    if changed then
      mt.type_list(metsigent[1])[1] = []
      mt.ti_reset
    end
=end

    context = mt.collect_candidate_type(context, @arguments, signat)

    if blknode.is_a?(TopNode) then
      context.push_signature(@arguments, mt)
      # Have block
      context = collect_candidate_type_block(context, blknode, 
                                             signat, mt, cursig)
      context.pop_signature
      if signat[1] != blknode.type then
        signat[1] = blknode.type
        context = mt.collect_candidate_type(context, 
                                            @arguments, signat)
      end
    else
      context.push_signature(@arguments, mt)
      context = blknode.collect_candidate_type(context)
      context.pop_signature
    end
    same_type(self, mt, cursig, signat, context)

  else
    context = collect_candidate_type_regident(context, slf)
  end

  if @func.is_a?(YieldNode) then
    add_type(cursig, cursig[1])
    @type = nil
    decide_type_once(cursig)
  end
  @body.collect_candidate_type(context)
end

#collect_candidate_type_block(context, blknode, signat, mt, cursig) ⇒ Object



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/ytljit/vm_sendnode.rb', line 307

def collect_candidate_type_block(context, blknode, signat, mt, cursig)
  # traverse a nested block
  # mt and signat are set corresponding to the nest level of yield
  if @func.is_a?(YieldNode) and false then
    level = @depth
  else
    level = 0
  end
  nest = 0
  sn = nil
  while mt.yield_node.size == 0 and
      mt.send_nodes_with_block.size != 0
    sn = mt.send_nodes_with_block[0]
    mt, slf = sn.get_send_method_node(cursig)
    if mt == nil then
      return context
    end
    args = sn.arguments

    context.push_signature(args, mt)

    nest = nest + 1
    if mt.yield_node.size == 0 then
      break
    end
    ynode = mt.yield_node[0]
    yargs = ynode.arguments.dup
    (0..2).each do |n|
      cl = nest + level
      yargs[n] = context.current_method_signature_node[-1 - cl][n]
    end
    mt = args[1]
    context.push_signature(yargs, mt)
    nest = nest + 1
  end
  if sn then
    signat = sn.signature(context)
  end

  mt.yield_node.map do |ynode|
    yargs = ynode.arguments.dup
    yargs[2.. -1].each do |arg|
      context = arg.collect_candidate_type(context)
    end
    ysignat = ynode.signature(context)

    # inherit self from caller node
    # notice: this region pushed callee signature_node
    cl =   nest + level
    prevsig = context.to_signature(-2 - cl)
    inherit_from_callee(context, cursig, prevsig, ysignat, yargs, cl)
#            ysignat[1] = signat[0]
    
    # collect candidate type of block and yield
    context = blknode.collect_candidate_type(context, yargs, ysignat)
    same_type(ynode, blknode, signat, ysignat, context)
    @yield_signature_cache[cursig] = ysignat
    
    # fill type cache(@type) of block node
    blknode.type = nil
    blknode.decide_type_once(ysignat)
  end

  nest.times do 
    context.pop_signature
  end
  
  context
end

#collect_candidate_type_regident(context, slf) ⇒ Object



219
220
221
# File 'lib/ytljit/vm_sendnode.rb', line 219

def collect_candidate_type_regident(context, slf)
  context
end

#collect_info(context) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/ytljit/vm_sendnode.rb', line 230

def collect_info(context)
  @arguments.each do |arg|
    context = arg.collect_info(context)
  end
  context = @func.collect_info(context)
  if is_fcall or is_vcall then
    # Call method of same class
    mt = @class_top.get_method_tab[@func.name]
    if mt then
      miv = mt.modified_instance_var
      if miv then
        miv.each do |vname, vall|
          context.modified_instance_var[vname] = vall
        end
      end
    end
  end

  @modified_local_var    = context.modified_local_var.last
  @modified_instance_var = context.modified_instance_var

  context = fill_result_cache(context)

  @body.collect_info(context)
end

#compile(context) ⇒ Object



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# File 'lib/ytljit/vm_sendnode.rb', line 457

def compile(context)
  context = super(context)

  @type = nil
  cursig = context.to_signature
  context.start_using_reg(TMPR2)
  context.start_using_reg(PTMPR)
  callconv = @func.calling_convention(context)
  
  case callconv
  when :c_vararg
    context = compile_c_vararg(context)
    
  when :c_fixarg
    context = compile_c_fixarg(context)

  when :c_fixarg_raw
    context = compile_c_fixarg_raw(context)

  when :ytl
    context = compile_ytl(context)

  when :getter
    inode = @func.inline_node
    context = @arguments[2].compile(context)
    rectype = @arguments[2].decide_type_once(cursig)
    context = inode.compile_main_aux(context, context.ret_reg, rectype)

  when :setter
    inode = @func.inline_node
    context = @arguments[2].compile(context)
    rectype = @arguments[2].decide_type_once(cursig)
    context = inode.compile_main_aux(context, context.ret_reg, rectype, 
                                     @arguments[3], nil)

  when nil

  else
#            p @arguments[2].type_list(context.to_signature)
#            p @func.name
#            raise "Unsupported calling conversion #{callconv}"
  end
  
  decide_type_once(cursig)
  if !@type.boxed and 
      @type.ruby_type == Float then
    context.ret_reg = XMM0
  else
    context.ret_reg = RETR
  end
  context.ret_node = self
  context.end_using_reg(PTMPR)
  context.end_using_reg(TMPR2)
  
  context = @body.compile(context)
  context
end

#fill_result_cache(context) ⇒ Object

This is for reduce method call whose all arguments is constant. But all methods can’t apply because the method may have side effect.



226
227
228
# File 'lib/ytljit/vm_sendnode.rb', line 226

def fill_result_cache(context)
  context
end

#get_constant_valueObject



515
516
517
518
519
520
521
# File 'lib/ytljit/vm_sendnode.rb', line 515

def get_constant_value
  if @result_cache then
    [@result_cache]
  else
    nil
  end
end

#get_send_method_node(cursig) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/ytljit/vm_sendnode.rb', line 194

def get_send_method_node(cursig)
  mt = nil
  if @arguments[2].type_list(cursig) != [[], []] then
    @arguments[2].type = nil
  end
  slf = nil
  if is_fcall or is_vcall then
    slf =  @arguments[2].decide_type_once(cursig)
    mt = @func.method_top_node(@class_top, nil)
  else
    slf = @arguments[2].decide_type_once(cursig)
    if slf.instance_of?(RubyType::DefaultType0) then
      # Chaos
      #p debug_info
      #p cursig
      #p @arguments[2].instance_eval { @type_list }
      #            raise "chaos"
    end
    
    mt = @func.method_top_node(@class_top, slf)
  end

  [mt, slf]
end

#inherit_from_callee(context, cursig, prevsig, signat, args, nest) ⇒ Object

inherit self/block from caller node



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/ytljit/vm_sendnode.rb', line 284

def inherit_from_callee(context, cursig, prevsig, signat, args, nest)
  if context.is_a?(TypeInferenceContext) then
    (0..2).each do |n|
      args[n] = context.current_method_signature_node[-2 - nest][n]
    end
  end
  (0..2).each do |n|
    signat[n] = prevsig[n]
  end

  if args[2].decide_type_once(cursig).ruby_type == Object then
    context.current_method_signature_node.reverse.each {|e0| 
      if e0[2].class == SendNewArenaNode then
        if args[2].type then
          args[2] = e0[2]
          signat[2] = args[2].type
        end
        break
      end
    }
  end
end

#search_signature(cursig) ⇒ Object



256
257
258
259
260
261
262
263
# File 'lib/ytljit/vm_sendnode.rb', line 256

def search_signature(cursig)
  @method_signature.each do |tabent|
    if cursig == tabent[0] then
      return tabent
    end
  end
  nil
end

#traverse_childlen {|@func| ... } ⇒ Object

Yields:



186
187
188
189
190
191
192
# File 'lib/ytljit/vm_sendnode.rb', line 186

def traverse_childlen
  @arguments.each do |arg|
    yield arg
  end
  yield @func
  yield @body
end

#traverse_node(&blk) ⇒ Object



176
177
178
179
180
181
182
183
184
# File 'lib/ytljit/vm_sendnode.rb', line 176

def traverse_node(&blk)
  @arguments.each_with_index do |arg, i|
    if arg.is_a?(SendNode) then
      arg.traverse_node(&blk)
    else
      yield(arg, @arguments, i)
    end
  end
end