Class: CastOff::Compiler::SimpleIR::GuardIR

Inherits:
IR
  • Object
show all
Defined in:
lib/cast_off/compile/ir/guard_ir.rb

Direct Known Subclasses

JumpGuard, StandardGuard

Constant Summary collapse

GUARD_DEOPTIMIZATION_TEMPLATE =
ERB.new("  /* depth = <%= @insn.depth %> */\n%  @information.undefined_variables.each do |var|\n%    @insn.iseq.initialize_for_guards(var) if var.is_a?(LocalVariable)\n%  end\n%  top = @insn.iseq\n%  a = [@insn.iseq]\n%  a = @insn.iseq.ancestors.reverse + a if @translator.inline_block?\n%  a.each_with_index do |s, idx|\n  {\n%    bug() unless @dependent_local_variables[s]\n%    bug() unless @dependent_stack_variables[s]\n%    local_c = @dependent_local_variables[s].size()\n%    stack_c = @dependent_stack_variables[s].size()\n%    if @translator.inline_block?\n    int local_c = <%= local_c %>;\n    VALUE local_v[<%= local_c %>];\n%    end\n    int stack_c = <%= stack_c %>;\n    VALUE stack_v[<%= stack_c %>];\n    rb_iseq_t *iseq = <%= s %>;\n%    @dependent_local_variables[s].each_with_index do |v, i|\n%      if @translator.inline_block?\n    local_v[<%= i %>] = <%= get_variable(v).boxed_form %>;\n%      end\n%    end\n%    @dependent_stack_variables[s].each_with_index do |v, i|\n    stack_v[<%= i %>] = <%= get_variable(v).boxed_form %>;\n%    end\n%    method_p = (s.itype == :method ? 1 : 0)\n%    lambda_p = (s.itype == :method ? 0 : 'lambda_p')\n%    top_p    = (top == s ? 1 : 0)\n%    bottom_p = (s.root? ? 1 : 0)\n%    if @translator.inline_block?\n%      if s.root?\n    thval = rb_thread_current();\n    th = DATA_PTR(thval);\n    specval = 0;\n    lfp = 0;\n    dfp = 0;\n%      else\n    <%= s.loopkey.dopt_func %>(&<%= s.loopkey %>, specval);\n%      end\n%      if s == top\n    return cast_off_deoptimize_inline(self, iseq, NULL, pc, local_c, local_v, stack_c, stack_v, <%= top_p %>, <%= bottom_p %>, <%= method_p %>, lfp, dfp);\n%      else\n%        bug() unless idx + 1 < a.size\n%        biseq = a[idx + 1]\n%        bug() unless biseq.parent_pc\n    specval = cast_off_deoptimize_inline(self, iseq, <%= biseq %>, <%= biseq.parent_pc %>, local_c, local_v, stack_c, stack_v, <%= top_p %>, <%= bottom_p %>, <%= method_p %>, lfp, dfp);\n%        if s.root?\n    lfp = th->cfp->lfp;\n%        end\n    dfp = th->cfp->dfp;\n%      end\n%    else\n    {\nVALUE return_value = cast_off_deoptimize_noinline(self, iseq, pc, stack_c, stack_v, <%= method_p %>, <%= lambda_p %>, <%= s.parent_pc ? s.parent_pc : -1 %>);\n%      if s.catch_exception?\nTH_POP_TAG2();\n%      end\nreturn return_value;\n    }\n%    end\n  }\n%  end\n  rb_bug(\"should not be reached\");\n", 0, '%-', 'g2')
GUARD_EXCEPTION_FUNCTION_TEMPLATE =
ERB.new("NORETURN(static inline int <THROW_EXCEPTION_FUNCTION_NAME>(VALUE obj));\nstatic inline int <THROW_EXCEPTION_FUNCTION_NAME>(VALUE obj)\n{\n  VALUE path0 = rb_class_path(rb_class_of(obj));\n  VALUE path1 = rb_class_path(rb_obj_class(obj));\n  rb_raise(rb_eCastOffExecutionError, \"\\\\\ntype mismatch: guard(<%= @guard_value %>:<%= \"\\\#{@insn.pc}: \\\#{@insn.op}, depth = \\\#{@insn.depth}\" %>)\\\\n\\\\\nname = <%= @insn.iseq.name %>, line = <%= @source_line %>: source = %s\\\\n\\\\\nexpected <%= @guard_value.types %> but %s, %s\\\\n\\\\\n<%= @translator.target_name() %>\", <%= @source.to_s.inspect %>, RSTRING_PTR(path0), RSTRING_PTR(path1));\n}\n", 0, '%-', 'g1')
GUARD_RECOMPILATION_FUNCTION_TEMPLATE =
ERB.new("NOINLINE(static void <RECOMPILATION_FUNCTION_NAME>(VALUE obj));\nstatic void <RECOMPILATION_FUNCTION_NAME>(VALUE obj)\n{\n#if 1\n  if(!sampling_table) register_sampling_table(rb_hash_new());\n%  count = 0\n%  done = []\n%  queue = [@guard_value]\n%  while (val = queue.pop)\n%    bug() if done.include?(val)\n%    done << val\n%    bug() unless val.is_a?(Variable)\n%    defs = get_definition(val)\n%    defs.each do |defn|\n%      case defn\n%      when SubIR\n%        case defn.src\n%        when LocalVariable, DynamicVariable, InstanceVariable, ClassVariable, GlobalVariable, Self\n%          count += 1\n  sampling_variable(obj, ID2SYM(rb_intern(\"<%= defn.src.source %>\")));\n%          if !queue.include?(defn.src) && !done.include?(defn.src)\n%            dlog(\"add recompilation queue \\\#{defn.src}\")\n%            queue << defn.src\n%          end\n%        when ConstWrapper\n%          # Fixme\n  /* <%= defn.src.path %> */\n%        when Literal, Argument, TmpBuffer\n%          # nothing to do\n%        else\n%          bug(defn.src)\n%        end\n%      when InvokeIR\n%        recv = defn.param_variables.first\n%        if recv.dynamic?\n%          bug() if val == @guard_value\n%          next\n%        end\n%        recv.types.each do |k|\n%          recv_class = @translator.get_c_classname(k)\n%          bug() unless recv_class\n%          count += 1\n  __sampling_poscall(obj, <%= recv_class %>, ID2SYM(rb_intern(\"<%= defn.method_id %>\")));\n%        end\n%      end\n%    end\n%  end\n%  if count > 0\n  rb_funcall(rb_mCastOff, rb_intern(\"re_compile\"), 2, rb_str_new2(\"<%= @translator.signiture() %>\"), sampling_table_val);\n%  else\n%    dlog(\"skip recompilation: defs = \\\#{defs.join(\"\\\\n\")}\")\n%  end\n#endif\n}\n", 0, '%-', '__recompilation')
GUARD_TEMPLATE =
ERB.new("%bug() if @guard_value.undefined? || @guard_value.dynamic?\n<%= guard_begin() %>\n%func = @translator.declare_recompilation_function(GUARD_RECOMPILATION_FUNCTION_TEMPLATE.trigger(binding))\n    <%= func %>(<%= @guard_value %>);\n%if @configuration.deoptimize?\n    goto <%= @insn.guard_label %>;\n%  @insn.iseq.inject_guard(@insn, GUARD_DEOPTIMIZATION_TEMPLATE.trigger(binding))\n%else\n%  func = @translator.declare_throw_exception_function(GUARD_EXCEPTION_FUNCTION_TEMPLATE.trigger(binding))\n    <%= func %>(<%= guard_value %>);\n%end\n<%= guard_end() %>\n", 0, '%-', 'g0')
GUARD_CHECK_TEMPLATE =
ERB.new("%if @guard_value.is_just?(NilClass)\n  if (UNLIKELY(!NIL_P(<%= @guard_value %>))) {\n%elsif @guard_value.is_just?(TrueClass)\n  if (UNLIKELY(<%= @guard_value %> != Qtrue)) {\n%elsif @guard_value.is_just?(FalseClass)\n  if (UNLIKELY(<%= @guard_value %> != Qfalse)) {\n%elsif @guard_value.is_just?(Symbol)\n  if (UNLIKELY(!SYMBOL_P(<%= @guard_value %>))) {\n%elsif @guard_value.is_just?(Fixnum)\n  if (UNLIKELY(!FIXNUM_P(<%= @guard_value %>))) {\n%else\n%  if simple?\n%    func = @translator.declare_class_check_function(CLASS_CHECK_FUNCTION_TEMPLATE_SIMPLE.trigger(binding))\n  if (UNLIKELY(!<%= func %>(<%= @guard_value %>))) {\n%  else\n%    func = @translator.declare_class_check_function(CLASS_CHECK_FUNCTION_TEMPLATE_COMPLEX.trigger(binding))\n  if (UNLIKELY(!<%= func %>(<%= @guard_value %>, rb_class_of(<%= @guard_value %>)))) {\n%  end\n%end\n\n", 0, '%-', 'g3')
CLASS_CHECK_FUNCTION_TEMPLATE_SIMPLE =
ERB.new("static inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj)\n{\n  if (0) {\n%if @guard_value.is_also?(NilClass)\n  } else if (NIL_P(obj)) {\n    return 1;\n%end\n%if @guard_value.is_also?(TrueClass)\n  } else if (obj == Qtrue) {\n    return 1;\n%end\n%if @guard_value.is_also?(FalseClass)\n  } else if (obj == Qfalse) {\n    return 1;\n%end\n%if @guard_value.is_also?(Symbol)\n  } else if (SYMBOL_P(obj)) {\n    return 1;\n%end\n%if @guard_value.is_also?(Fixnum)\n  } else if (FIXNUM_P(obj)) {\n    return 1;\n%end\n  } else {\n    return 0;\n  }\n}\n", 0, '%-', 'g4')
CLASS_CHECK_FUNCTION_TEMPLATE_COMPLEX =
ERB.new("NOINLINE(static int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass));\n\nstatic inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj, VALUE klass)\n{\n  if (0) {\n%  @guard_value.types.each do |klass|\n%    name = @translator.get_c_classname(klass)\n%    raise(CompileError.new(\"can't generate guard for \\\#{klass}, you should pass binding to CastOff (\\\#{klass.singleton? ? 1 : 0})\")) unless name\n  } else if (LIKELY(klass == <%= name %>)) {\n    return 1;\n%  end\n  } else {\n    if (LIKELY(<CLASS_CHECK_FUNCTION_NAME>_failed(obj, klass))) {\nreturn 1;\n    } else {\nreturn 0;\n    }\n  }\n}\n\nstatic int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass)\n{\n  if (UNLIKELY(FL_TEST(klass, FL_SINGLETON) && empty_method_table_p(klass))) {\n    return <CLASS_CHECK_FUNCTION_NAME>(obj, rb_obj_class(obj));\n  }\n  return 0;\n}\n", 0, '%-', 'g4')

Instance Attribute Summary collapse

Attributes inherited from IR

#alias, #insn

Instance Method Summary collapse

Methods inherited from IR

#add_sampling_variable, #alive, #alive?, #dispatch_method?, #generate_guard, #get_definition, #get_definition_str, #get_usage, #get_variable, #inlining_target?, #propergate_guard_usage, #reset, #sampling_variable, #set_info, #standard_guard_target, #vanish, #vanish?

Methods included from Util

#bug, #dlog, #todo, #vlog

Constructor Details

#initialize(val, vars, insn, cfg) ⇒ GuardIR

Returns a new instance of GuardIR.



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 247

def initialize(val, vars, insn, cfg)
  super(insn, cfg)
  @guard_value = val
  bug() unless @guard_value.is_a?(Variable)
  @values = [@guard_value]
  @variables = []
  @variables_without_result = []
  @variables << @guard_value
  @variables_without_result << @guard_value
  @result_variable = nil
  @source = @insn.source
  @source = @source.empty? ? nil : @source
  @source_line = @insn.line.to_s
  if @configuration.deoptimize?
    @dependent_local_variables = get_dependent_local_variables(vars)
    @dependent_stack_variables = get_dependent_stack_variables(vars)
    @dependent_variables = @dependent_local_variables.values.flatten + @dependent_stack_variables.values.flatten
  end
end

Instance Attribute Details

#guard_valueObject (readonly)

Returns the value of attribute guard_value.



7
8
9
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 7

def guard_value
  @guard_value
end

#result_variableObject (readonly)

Returns the value of attribute result_variable.



7
8
9
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 7

def result_variable
  @result_variable
end

#valuesObject (readonly)

Returns the value of attribute values.



7
8
9
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 7

def values
  @values
end

#variablesObject (readonly)

Returns the value of attribute variables.



7
8
9
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 7

def variables
  @variables
end

#variables_without_resultObject (readonly)

Returns the value of attribute variables_without_result.



7
8
9
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 7

def variables_without_result
  @variables_without_result
end

Instance Method Details

#mark(defs) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 319

def mark(defs)
  if !@alive
    @alive = true
    defs.mark(@guard_value)
    if @configuration.deoptimize?
      bug() unless @dependent_variables
      @dependent_variables.each{|v| defs.mark(v)}
    end
    true
  else
    false
  end
end

#propergate_boxed_value(defs) ⇒ Object



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 272

def propergate_boxed_value(defs)
  change = false

  # forward
  change |= defs.propergate_boxed_value_forward(@guard_value)

  # backward
  if @guard_value.boxed?
    change |= defs.propergate_boxed_value_backward(@guard_value)
    if @configuration.deoptimize?
      bug() unless @dependent_variables
      @dependent_variables.each do |var|
        if var.is_a?(DynamicVariable)
          bug() unless var.boxed?
          next
        end
        vars = defs.get_variables(var)
        boxed_p = !!vars.find{|v| v.boxed?}
        next unless boxed_p
        vars.each do |v|
          change |= v.box()
          change |= defs.propergate_boxed_value_backward(v)
        end
      end
    end
  end

  change
end

#propergate_exact_class(defs) ⇒ Object

unboxing end ###



303
304
305
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 303

def propergate_exact_class(defs)
  defs.exact_class_resolve(@guard_value)
end

#to_cObject



307
308
309
310
311
312
313
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 307

def to_c()
  if @configuration.inject_guard? && !@guard_value.class_exact?
    bug() if @insn.pc == -1
    bug() unless @insn.depth
    GUARD_TEMPLATE.trigger(binding).chomp
  end
end

#type_propergation(defs) ⇒ Object



315
316
317
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 315

def type_propergation(defs)
  bug()
end

#unboxing_preludeObject

unboxing begin ###



268
269
270
# File 'lib/cast_off/compile/ir/guard_ir.rb', line 268

def unboxing_prelude()
  @guard_value.box() unless @guard_value.class_exact? && @guard_value.can_unbox?
end