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

EOS
CLASS_CHECK_FUNCTION_TEMPLATE_SIMPLE =
ERB.new(<<-EOS, 0, '%-', 'g4')
static inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj)
{
  if (0) {
%if @guard_value.is_also?(NilClass)
  } else if (NIL_P(obj)) {
    return 1;
%end
%if @guard_value.is_also?(TrueClass)
  } else if (obj == Qtrue) {
    return 1;
%end
%if @guard_value.is_also?(FalseClass)
  } else if (obj == Qfalse) {
    return 1;
%end
%if @guard_value.is_also?(Symbol)
  } else if (SYMBOL_P(obj)) {
    return 1;
%end
%if @guard_value.is_also?(Fixnum)
  } else if (FIXNUM_P(obj)) {
    return 1;
%end
  } else {
    return 0;
  }
}
EOS
CLASS_CHECK_FUNCTION_TEMPLATE_COMPLEX =
ERB.new(<<-EOS, 0, '%-', 'g4')
NOINLINE(static int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass));

static inline int <CLASS_CHECK_FUNCTION_NAME>(VALUE obj, VALUE klass)
{
  if (0) {
%  @guard_value.types.each do |klass|
%    name = @translator.get_c_classname(klass)
%    raise(CompileError.new("can't generate guard for \#{klass}, you should pass binding to CastOff (\#{klass.singleton? ? 1 : 0})")) unless name
  } else if (LIKELY(klass == <%= name %>)) {
    return 1;
%  end
  } else {
    if (LIKELY(<CLASS_CHECK_FUNCTION_NAME>_failed(obj, klass))) {
return 1;
    } else {
return 0;
    }
  }
}

static int <CLASS_CHECK_FUNCTION_NAME>_failed(VALUE obj, VALUE klass)
{
  if (UNLIKELY(FL_TEST(klass, FL_SINGLETON) && empty_method_table_p(klass))) {
    return <CLASS_CHECK_FUNCTION_NAME>(obj, rb_obj_class(obj));
  }
  return 0;
}
EOS

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