Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jitruby/ext/method_data.c.rpp  view on Meta::CPAN

/* Okay to not pop this temporary frame, since it will be popped by the
 * caller
 */
#define FIX_FRAME() \
  struct FRAME _frame = *ruby_frame; \
  _frame.last_class = RCLASS(ruby_frame->last_class)->super; \
  _frame.prev = ruby_frame; \
  ruby_frame = &_frame; \

static NODE * data_memo_node()
{
  return (NODE *)(RBASIC(ruby_frame->prev->last_class)->klass);
}

#endif

typedef VALUE (*Method_Func)(ANYARGS);

static Method_Func actual_cfunc()
{
  return data_memo_node()->nd_cfnc;
}

static VALUE data_wrapper_m1(int argc, VALUE * argv, VALUE self)
{
  VALUE result;
  FIX_FRAME();
  result = (*actual_cfunc())(argc, argv, self);
  return result;
}

static VALUE data_wrapper_0(VALUE self)
{
  VALUE result;
  FIX_FRAME();
  result = (*actual_cfunc())(self);
  return result;
}

#ruby <<END
  (1..MAX_ARGS).each do |i|
    params = (1..i).map { |j| "VALUE arg#{j}" }.join(', ')
    args = (1..i).map { |j| "arg#{j}" }.join(', ')

    puts <<-END
static VALUE data_wrapper_#{i}(VALUE self, #{params})
{
  VALUE result;
  FIX_FRAME();
  result = (*actual_cfunc())(self, #{args});
  return result;
}
    END
  end

  nil
END

/* Define a method and attach data to it.
 *
 * The method looks to ruby like a normal aliased CFUNC, with a modified
 * origin class:
 *
 * NODE_FBODY
 *   |- (u1) orig - origin class
 *   |  |- basic
 *   |  |  |- flags - origin class flags + FL_SINGLETON
 *   |  |  +- klass - NODE_MEMO
 *   |  |     |- (u1) cfnc - actual C function to call
 *   |  |     |- (u2) rval - stored data
 *   |  |     +- (u3) 0
 *   |  |- iv_tbl - 0
 *   |  |- m_tbl - 0
 *   |  +- super - actual origin class
 *   |- (u2) mid - name of the method
 *   +- (u3) head - NODE_CFUNC
 *      |- (u1) cfnc - wrapper function to call
 *      +- (u2) argc - function arity
 *
 * Or, on YARV:
 *
 * NODE_FBODY
 *   |- (u1) oid - name of the method
 *   +- (u2) body - NODE_METHOD
 *      |- (u1) clss - origin class
 *      |  |- basic
 *      |  |  |- flags - origin class flags + FL_SINGLETON
 *      |  |  +- klass - NODE_MEMO
 *      |  |     |- (u1) cfnc - actual C function to call
 *      |  |     |- (u2) rval - stored data
 *      |  |     +- (u3) 0
 *      |  |- ptr - rb_classext_t
 *      |  |  |- super - actual origin class
 *      |  |  +- iv_tbl - 0
 *      |  |- m_tbl - 0
 *      |  +- iv_index_tbl - 0?
 *      |- (u2) body - NODE_CFUNC
 *      |  |- (u1) cfnc - wrapper function to call
 *      |  |- (u2) argc - function arity
 *      +- (u3) noex - NOEX_PUBLIC
 *
 * When the wrapper function is called, last_class is set to the origin
 * class found in the FBODY node.  So that the method data will be
 * accessible, and so last_class will point to klass and not to our MEMO
 * node, it is necessary to "fix" the current frame.
 *
 * Pre-YARV, this means we duplicate the current frame and set last_class:
 *
 * ruby_frame
 *   |- last_class - klass
 *   |- prev
 *   |  |- last_class - NODE_MEMO
 *   |  |  |- (u1) cfnc - actual C function to call
 *   |  |  |- (u2) rval - stored data
 *   |  |  +- (u3) 0
 *   |  |- prev - the real previous frame
 *   |  +- ...
 *   +- ...
 *
 * The method data is then accessible via
 * ruby_frame->prev->last_class->rval.



( run in 1.949 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )