Class: CastOff::Compiler::Iseq

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/cast_off/compile/iseq.rb

Defined Under Namespace

Classes: Args

Constant Summary collapse

IfuncNodeGeneratorTemplate =
ERB.new("static void <%= ifunc_node_generator() %>()\n{\n%# NEW_IFUNC \u306E\u7B2C\u4E8C\u5F15\u6570\u306F Proc \u306B\u5BFE\u3057\u3066\u6E21\u305B\u308B\u597D\u304D\u306A\u5024\n%#<%= @ifunc_node_name %> = NEW_IFUNC(<%= @ifunc_name %>, <%= self %>->self); \n  <%= @ifunc_node_name %> = NEW_IFUNC(<%= @ifunc_name %>, Qnil); \n%# nd_aid = 0 \u3060\u3068 rb_frame_this_func \u3067 <ifunc> \u3068\u306A\u308B\u3002\n  <%= @ifunc_node_name %>->nd_aid = 0;\n  rb_gc_register_mark_object((VALUE)<%= @ifunc_node_name %>);\n}\n", 0, '%-', 'io')
BlockGeneratorTemplate =
ERB.new("<%= declare_block_generator() %>\n{\n  VALUE thval = rb_thread_current();\n  rb_thread_t * th = DATA_PTR(thval);\n  rb_control_frame_t *cfp = th->cfp;\n  rb_block_t *blockptr = (rb_block_t *)(&(cfp)->self);\n  /* cfp \u306E self \u4EE5\u4E0B\u304C block \u69CB\u9020\u4F53\u306E\u30E1\u30F3\u30D0\u3068\u306A\u308B */\n\n  blockptr->iseq = (void *)<%= @ifunc_node_name %>;\n  blockptr->proc = 0;\n  blockptr->self = self; /* for CastOff.execute */\n\n  return blockptr;\n}\n", 0, '%-', 'io')
IfuncTemplate =
ERB.new("<%= declare_ifunc() %>\n{\n  /* decl variables */\n  rb_thread_t *th = current_thread();\n  VALUE cast_off_argv[<%= own_argv_size() %>];\n  VALUE cast_off_tmp;\n  VALUE sampling_tmp;\n  VALUE self = get_self(th);\n  int lambda_p = cast_off_lambda_p(arg, argc, argv);\n  int i, num;\n<%= declare_dfp %>\n<%= (own_local_variable_declarations).map{|v| \"  \#{v};\"}.join(\"\\n\") %>\n\n% bug() if root?\n  expand_dframe(th, <%= @lvars.size %>, <%= self %>, 0);\n<%= update_dfp %>\n\n%inits = own_initializations_for_guards\n%bug() if inits.uniq!\n%inits.join(\"\\n\")\n\n  /* setup arguments */\n  if (lambda_p) {\n% bug() if @args.simple? && @args.arg_size != @args.argc\n    num = cast_off_prepare_iter_api_lambda_args(<%= @args.arg_size %>, cast_off_argv, argc, argv, <%= @args.simple? ? 1 : 0 %>, <%= @args.argc %>, <%= @args.opt_len %>, <%= @args.post_len %>, <%= @args.post_start %>, <%= @args.rest_index %>);\n  } else {\n    num = cast_off_prepare_iter_api_block_args(<%= @args.arg_size %>, cast_off_argv, argc, argv, <%= @args.splat? ? 1 : 0 %>, <%= @args.argc %>, <%= @args.opt_len %>, <%= @args.post_len %>, <%= @args.post_start %>, <%= @args.rest_index %>);\n  }\n%if @args.block?\n  cast_off_argv[<%= @args.block_index %>] = blockarg;\n%end\n\n<%= enclose_begin %>\n\n%#if reference_constant?\n%#  check_cref(th);\n%#end\n\n  /* body */\n<%= own_c_function_body() %>\n\n%iterate_own_guards do |code, insns|\n{\n  long pc;\n  <%= enclose_end_deoptimize %>\n%code_label = \"deoptimize_\#{code.hash.to_s.gsub(/-/, \"_\")}\"\n%  insns.uniq.each do |insn|\n<%= insn.guard_label %>:\n  pc = <%= insn.pc %>;\n  goto <%= code_label %>;\n%  end\n<%= code_label %>:\n<%= code %>\n}\n%end\n\n<%= enclose_end %>\n}\n", 0, '%-', 'io')
ExceptionHandlerTemplate =
ERB.new("  {\n    int state;\n    rb_control_frame_t *volatile cfp;\n\n    th = current_thread();\n    cfp = th->cfp;\n\n    TH_PUSH_TAG(th);\n    if ((state = EXEC_TAG()) != 0) {\nVALUE excval;\n\nth = current_thread();\nwhile (th->cfp != cfp) {\n  th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);\n}\n\n%@excs.each do |(exc, entries)|\nswitch(state) {\n%  case exc\n%  when :break\ncase TAG_BREAK:\n  excval = catch_break(th);\n  if (excval != Qundef) {\n    switch((int)(cfp->pc - cfp->iseq->iseq_encoded)) {\n%    entries.each do |(pc, label, stack)|\n    case <%= pc %>:\n<%= update_dfp(12) %>\n      tmp<%= stack - 1 %> = excval; /* FIXME */\n      goto <%= label %>;\n%    end\n    default:\n      rb_bug(\"failed to found break target\");\n    }\n  }\n%  when :return\ncase TAG_RETURN:\n  excval = catch_return(th);\n  if (excval != Qundef) {\n    /* vm_pop_frame is called at the vm_call_method() */\n    TH_POP_TAG2();\n    return excval;\n  }\n%  else\n%    bug()\n%  end\n}\nTH_POP_TAG2();\nTH_JUMP_TAG(th, state);\n%end\n    }\n", 0, '%-', 'io')

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#bug, #dlog, #todo, #vlog

Constructor Details

#initialize(iseq, parent, depth, ppc) ⇒ Iseq

Returns a new instance of Iseq.



69
70
71
72
73
74
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
# File 'lib/cast_off/compile/iseq.rb', line 69

def initialize(iseq, parent, depth, ppc)
  bug() unless iseq.is_a?(RubyVM::InstructionSequence)
  @iseq = iseq
  ary = iseq.to_a
  @name = ary[5]
  @source_file = ary[7]
  @source_line = ary[8]
  @itype = ary[9] # iseq type
  args = ary[11]
  @args = Args.new(args, self)
  if @source_file && File.exist?(@source_file)
    @source = File.readlines(@source_file)
  else
    @source = nil
  end
  @parent = parent
  @children = {} # pc => iseq
  bug() unless depth.is_a?(Fixnum)
  @depth = depth
  @parent_pc = ppc
  @generation = 0

  p = @parent
  while p
    p = p.parent
    @generation += 1
  end
  bug() if !root? && @generation < 1

  # for code generator
  @argv_size = 1
  @initialize_for_guards = []
  @guard_codes = {}
  @local_variable_declarations = []
  @c_function_body = ""
  @c_name = "iseq_#{@iseq.hash.to_s.gsub(/-/, "_")}"
  @ifunc_name = "ifunc_#{@c_name}"
  @ifunc_node_name = "ifunc_node_#{@c_name}"
  @excs = {}
  @reference_constant_p = false
  @loopkey = nil
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def args
  @args
end

#childrenObject (readonly)

Returns the value of attribute children.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def children
  @children
end

#depthObject (readonly)

Returns the value of attribute depth.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def depth
  @depth
end

#generationObject (readonly)

Returns the value of attribute generation.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def generation
  @generation
end

#iseqObject (readonly)

Returns the value of attribute iseq.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def iseq
  @iseq
end

#itypeObject (readonly)

Returns the value of attribute itype.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def itype
  @itype
end

#loopkeyObject (readonly)

Returns the value of attribute loopkey.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def loopkey
  @loopkey
end

#lvarsObject (readonly)

Returns the value of attribute lvars.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def lvars
  @lvars
end

#nameObject (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def parent
  @parent
end

#parent_pcObject (readonly)

Returns the value of attribute parent_pc.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def parent_pc
  @parent_pc
end

#sourceObject (readonly)

Returns the value of attribute source.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def source
  @source
end

#source_fileObject (readonly)

Returns the value of attribute source_file.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def source_file
  @source_file
end

#source_lineObject (readonly)

Returns the value of attribute source_line.



8
9
10
# File 'lib/cast_off/compile/iseq.rb', line 8

def source_line
  @source_line
end

Instance Method Details

#add(child, pc) ⇒ Object



121
122
123
124
125
126
# File 'lib/cast_off/compile/iseq.rb', line 121

def add(child, pc)
  bug() unless child.is_a?(Iseq)
  bug() unless pc.is_a?(Fixnum)
  bug() if @children[pc]
  @children[pc] = child
end

#all_argv_sizeObject



169
170
171
172
173
# File 'lib/cast_off/compile/iseq.rb', line 169

def all_argv_size()
  o = own_argv_size()
  c = @children.values.map{|i| i.all_argv_size()}
  [o, c].flatten.max()
end

#all_c_function_bodyObject



154
155
156
157
158
# File 'lib/cast_off/compile/iseq.rb', line 154

def all_c_function_body()
  o = own_c_function_body()
  c = @children.values.map{|i| i.all_c_function_body() }.join("\n")
  [o, c].join("\n")
end

#all_initializations_for_guardsObject



197
198
199
200
201
202
203
204
# File 'lib/cast_off/compile/iseq.rb', line 197

def all_initializations_for_guards()
  # 外のブロックで定義されたローカル変数は、LocalVariable とはならないため。
  # ローカル変数は、全て初期化してしまって問題ない。
  ret = []
  ret += own_initializations_for_guards()
  @children.values.each{|c| ret += c.all_initializations_for_guards() }
  ret.uniq()
end

#all_local_variable_declarationsObject



183
184
185
186
187
# File 'lib/cast_off/compile/iseq.rb', line 183

def all_local_variable_declarations()
  o = own_local_variable_declarations()
  c = @children.values.map{|i| i.all_local_variable_declarations() }
  [o, c].flatten.uniq()
end

#ancestorsObject



132
133
134
135
136
137
138
139
140
# File 'lib/cast_off/compile/iseq.rb', line 132

def ancestors
  a = []
  s = self.parent
  while s
    a << s
    s = s.parent
  end
  a
end

#append_c_function_body(code) ⇒ Object



150
151
152
# File 'lib/cast_off/compile/iseq.rb', line 150

def append_c_function_body(code)
  @c_function_body = [@c_function_body, code].join("\n")
end

#block_generatorObject



282
283
284
# File 'lib/cast_off/compile/iseq.rb', line 282

def block_generator()
  "cast_off_create_block_#{@c_name}"
end

#catch_exception(exc, pc, label, stack) ⇒ Object



439
440
441
442
443
# File 'lib/cast_off/compile/iseq.rb', line 439

def catch_exception(exc, pc, label, stack)
  @excs[exc] ||= []
  entry = [pc, label, stack]
  @excs[exc] << entry unless @excs[exc].include?(entry)
end

#catch_exception?Boolean

Returns:

  • (Boolean)


435
436
437
# File 'lib/cast_off/compile/iseq.rb', line 435

def catch_exception?
  not @excs.empty?
end

#declare_block_generatorObject



274
275
276
# File 'lib/cast_off/compile/iseq.rb', line 274

def declare_block_generator()
  "rb_block_t *#{block_generator()}(VALUE self)"
end

#declare_dfp(indent = 2) ⇒ Object



286
287
288
289
# File 'lib/cast_off/compile/iseq.rb', line 286

def declare_dfp(indent = 2)
  indent = ' ' * indent
  (0..@generation).map{|i| "#{indent}VALUE *dfp#{i};"}.join("\n")
end

#declare_ifuncObject



357
358
359
# File 'lib/cast_off/compile/iseq.rb', line 357

def declare_ifunc()
  "static VALUE #{@ifunc_name}(VALUE arg, VALUE dummy, int argc, VALUE *argv, VALUE blockarg)"
end

#declare_ifunc_nodeObject



233
234
235
# File 'lib/cast_off/compile/iseq.rb', line 233

def declare_ifunc_node()
  "static NODE *#{@ifunc_node_name}"
end

#declare_local_variable(v) ⇒ Object



179
180
181
# File 'lib/cast_off/compile/iseq.rb', line 179

def declare_local_variable(v)
  @local_variable_declarations << v
end

#define_block_generatorObject



278
279
280
# File 'lib/cast_off/compile/iseq.rb', line 278

def define_block_generator()
  BlockGeneratorTemplate.trigger(binding)
end

#define_ifuncObject



361
362
363
# File 'lib/cast_off/compile/iseq.rb', line 361

def define_ifunc()
  IfuncTemplate.trigger(binding)
end

#define_ifunc_node_generatorObject



249
250
251
# File 'lib/cast_off/compile/iseq.rb', line 249

def define_ifunc_node_generator()
  IfuncNodeGeneratorTemplate.trigger(binding)
end

#delete_labels(ls) ⇒ Object



445
446
447
448
449
450
451
452
453
# File 'lib/cast_off/compile/iseq.rb', line 445

def delete_labels(ls)
  entries = @excs[:break]
  return unless entries
  entries.delete_if do |(pc, label, stack)|
    del_p = ls.include?(label)
    dlog("#{self}: delete break label #{label}") if del_p
    del_p
  end
end

#enclose_beginObject



418
419
420
421
# File 'lib/cast_off/compile/iseq.rb', line 418

def enclose_begin()
  return '' if @excs.empty?
  ExceptionHandlerTemplate.trigger(binding)
end

#enclose_endObject



423
424
425
426
427
428
429
# File 'lib/cast_off/compile/iseq.rb', line 423

def enclose_end()
  @excs.empty? ? '' : "    TH_POP_TAG();\n    rb_bug(\"enclose_end: should not be reached\");\n  }\n  EOS\nend\n"

#enclose_end_deoptimizeObject



431
432
433
# File 'lib/cast_off/compile/iseq.rb', line 431

def enclose_end_deoptimize()
  @excs.empty? ? '' : 'TH_POP_TAG2();'
end

#ifunc_node_generatorObject



253
254
255
# File 'lib/cast_off/compile/iseq.rb', line 253

def ifunc_node_generator()
  "generate_ifunc_node_#{@c_name}"
end

#initialize_for_guards(var) ⇒ Object



193
194
195
# File 'lib/cast_off/compile/iseq.rb', line 193

def initialize_for_guards(var)
  @initialize_for_guards << var
end

#inject_guard(insn, code) ⇒ Object



210
211
212
213
214
215
216
217
# File 'lib/cast_off/compile/iseq.rb', line 210

def inject_guard(insn, code)
  bug() unless insn.iseq == self
  if @guard_codes[code]
    @guard_codes[code] << insn
  else
    @guard_codes[code] = [insn]
  end
end

#iterate_all_guards(&b) ⇒ Object



219
220
221
222
# File 'lib/cast_off/compile/iseq.rb', line 219

def iterate_all_guards(&b)
  iterate_own_guards(&b)
  @children.values.each{|c| c.iterate_all_guards(&b)}
end

#iterate_all_iseq {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



228
229
230
231
# File 'lib/cast_off/compile/iseq.rb', line 228

def iterate_all_iseq(&b)
  yield(self)
  @children.values.each{|c| c.iterate_all_iseq(&b)}
end

#iterate_own_guardsObject



224
225
226
# File 'lib/cast_off/compile/iseq.rb', line 224

def iterate_own_guards()
  @guard_codes.each{|(code, insns)| yield(code, insns)}
end

#own_argv_sizeObject



175
176
177
# File 'lib/cast_off/compile/iseq.rb', line 175

def own_argv_size()
  @argv_size
end

#own_c_function_bodyObject



160
161
162
# File 'lib/cast_off/compile/iseq.rb', line 160

def own_c_function_body()
  @c_function_body
end

#own_initializations_for_guardsObject



206
207
208
# File 'lib/cast_off/compile/iseq.rb', line 206

def own_initializations_for_guards()
  @initialize_for_guards.map{|v| "  #{v} = Qnil;"}.uniq()
end

#own_local_variable_declarationsObject



189
190
191
# File 'lib/cast_off/compile/iseq.rb', line 189

def own_local_variable_declarations()
  @local_variable_declarations.uniq()
end

#reference_constantObject



142
143
144
# File 'lib/cast_off/compile/iseq.rb', line 142

def reference_constant
  @reference_constant_p = true
end

#reference_constant?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/cast_off/compile/iseq.rb', line 146

def reference_constant?
  @reference_constant_p
end

#root?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/cast_off/compile/iseq.rb', line 128

def root?
  !@parent
end

#set_local_variables(lvars) ⇒ Object



112
113
114
# File 'lib/cast_off/compile/iseq.rb', line 112

def set_local_variables(lvars)
  @lvars = lvars
end

#set_loopkey(k) ⇒ Object



116
117
118
119
# File 'lib/cast_off/compile/iseq.rb', line 116

def set_loopkey(k)
  bug() if root?
  @loopkey = k
end

#to_nameObject



455
456
457
# File 'lib/cast_off/compile/iseq.rb', line 455

def to_name
  "#{@name}: #{@source_file} #{@source_line}"
end

#to_sObject



459
460
461
# File 'lib/cast_off/compile/iseq.rb', line 459

def to_s
  @c_name
end

#update_dfp(indent = 2) ⇒ Object



291
292
293
294
# File 'lib/cast_off/compile/iseq.rb', line 291

def update_dfp(indent = 2)
  indent = ' ' * indent
  (0..@generation).map{|i| "#{indent}dfp#{i} = fetch_dfp(th, #{@generation - i});"}.join("\n")
end

#use_temporary_c_ary(size) ⇒ Object



164
165
166
167
# File 'lib/cast_off/compile/iseq.rb', line 164

def use_temporary_c_ary(size)
  @argv_size = size if size > @argv_size
"cast_off_argv"
end