2007-06-24 13:19:22 -04:00
|
|
|
/**********************************************************************
|
|
|
|
|
2008-11-14 06:31:10 -05:00
|
|
|
vm_insnhelper.c - instruction helper functions.
|
2007-06-24 13:19:22 -04:00
|
|
|
|
|
|
|
$Author$
|
|
|
|
|
|
|
|
Copyright (C) 2007 Koichi Sasada
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
/* finish iseq array */
|
|
|
|
#include "insns.inc"
|
2008-01-17 12:06:51 -05:00
|
|
|
#include <math.h>
|
2010-10-26 13:27:32 -04:00
|
|
|
#include "constant.h"
|
2011-05-18 09:41:54 -04:00
|
|
|
#include "internal.h"
|
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-12 16:52:12 -05:00
|
|
|
#include "probes.h"
|
2012-11-18 11:30:10 -05:00
|
|
|
#include "probes_helper.h"
|
2008-01-17 12:06:51 -05:00
|
|
|
|
2007-06-24 13:19:22 -04:00
|
|
|
/* control stack frame */
|
|
|
|
|
2007-08-06 07:36:30 -04:00
|
|
|
#ifndef INLINE
|
|
|
|
#define INLINE inline
|
|
|
|
#endif
|
|
|
|
|
2009-01-18 22:03:09 -05:00
|
|
|
static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
|
|
|
|
|
2012-12-25 04:57:07 -05:00
|
|
|
static void
|
|
|
|
vm_stackoverflow(void)
|
|
|
|
{
|
|
|
|
rb_exc_raise(sysstack_error);
|
|
|
|
}
|
|
|
|
|
2007-06-24 13:19:22 -04:00
|
|
|
static inline rb_control_frame_t *
|
2012-06-10 23:14:59 -04:00
|
|
|
vm_push_frame(rb_thread_t *th,
|
|
|
|
const rb_iseq_t *iseq,
|
|
|
|
VALUE type,
|
|
|
|
VALUE self,
|
2012-08-02 07:08:44 -04:00
|
|
|
VALUE klass,
|
2012-06-10 23:14:59 -04:00
|
|
|
VALUE specval,
|
|
|
|
const VALUE *pc,
|
|
|
|
VALUE *sp,
|
2012-07-03 22:11:37 -04:00
|
|
|
int local_size,
|
2013-08-06 04:33:05 -04:00
|
|
|
const rb_method_entry_t *me,
|
2013-08-06 04:59:24 -04:00
|
|
|
size_t stack_max)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-06-10 23:14:59 -04:00
|
|
|
rb_control_frame_t *const cfp = th->cfp - 1;
|
2007-06-24 13:19:22 -04:00
|
|
|
int i;
|
|
|
|
|
2012-06-10 23:14:59 -04:00
|
|
|
/* check stack overflow */
|
2013-08-06 04:59:24 -04:00
|
|
|
CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + (int)stack_max);
|
2013-08-06 04:33:05 -04:00
|
|
|
|
2009-11-06 21:45:08 -05:00
|
|
|
th->cfp = cfp;
|
2012-06-10 23:14:59 -04:00
|
|
|
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-18 23:08:50 -04:00
|
|
|
/* setup vm value stack */
|
2009-02-22 09:23:33 -05:00
|
|
|
|
2012-06-10 23:14:59 -04:00
|
|
|
/* initialize local variables */
|
2007-06-24 13:19:22 -04:00
|
|
|
for (i=0; i < local_size; i++) {
|
2012-06-10 23:14:59 -04:00
|
|
|
*sp++ = Qnil;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set special val */
|
2012-06-10 23:14:59 -04:00
|
|
|
*sp = specval;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-18 23:08:50 -04:00
|
|
|
/* setup vm control frame stack */
|
|
|
|
|
2008-05-19 14:47:56 -04:00
|
|
|
cfp->pc = (VALUE *)pc;
|
2007-06-24 13:19:22 -04:00
|
|
|
cfp->sp = sp + 1;
|
2012-09-28 00:05:36 -04:00
|
|
|
#if VM_DEBUG_BP_CHECK
|
|
|
|
cfp->bp_check = sp + 1;
|
|
|
|
#endif
|
2012-06-10 23:14:59 -04:00
|
|
|
cfp->ep = sp;
|
2008-05-19 14:47:56 -04:00
|
|
|
cfp->iseq = (rb_iseq_t *) iseq;
|
2007-11-08 20:29:24 -05:00
|
|
|
cfp->flag = type;
|
2007-06-24 13:19:22 -04:00
|
|
|
cfp->self = self;
|
2010-08-18 17:03:32 -04:00
|
|
|
cfp->block_iseq = 0;
|
2007-06-24 13:19:22 -04:00
|
|
|
cfp->proc = 0;
|
2012-07-03 22:11:37 -04:00
|
|
|
cfp->me = me;
|
2012-08-02 07:08:44 -04:00
|
|
|
if (klass) {
|
|
|
|
cfp->klass = klass;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, prev_cfp)) {
|
|
|
|
cfp->klass = Qnil;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cfp->klass = prev_cfp->klass;
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2007-08-12 15:12:55 -04:00
|
|
|
if (VMDEBUG == 2) {
|
|
|
|
SDR();
|
|
|
|
}
|
|
|
|
|
2007-06-24 13:19:22 -04:00
|
|
|
return cfp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2008-05-22 12:19:14 -04:00
|
|
|
vm_pop_frame(rb_thread_t *th)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
|
|
|
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
2007-08-12 15:12:55 -04:00
|
|
|
|
|
|
|
if (VMDEBUG == 2) {
|
|
|
|
SDR();
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* method dispatch */
|
2012-03-14 17:10:16 -04:00
|
|
|
static inline VALUE
|
2012-03-14 21:39:00 -04:00
|
|
|
rb_arg_error_new(int argc, int min, int max)
|
|
|
|
{
|
2012-03-14 17:10:16 -04:00
|
|
|
VALUE err_mess = 0;
|
|
|
|
if (min == max) {
|
|
|
|
err_mess = rb_sprintf("wrong number of arguments (%d for %d)", argc, min);
|
|
|
|
}
|
|
|
|
else if (max == UNLIMITED_ARGUMENTS) {
|
|
|
|
err_mess = rb_sprintf("wrong number of arguments (%d for %d+)", argc, min);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
err_mess = rb_sprintf("wrong number of arguments (%d for %d..%d)", argc, min, max);
|
|
|
|
}
|
|
|
|
return rb_exc_new3(rb_eArgError, err_mess);
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-03-14 17:10:16 -04:00
|
|
|
NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc));
|
2010-05-03 23:50:39 -04:00
|
|
|
static void
|
2012-03-14 17:10:16 -04:00
|
|
|
argument_error(const rb_iseq_t *iseq, int miss_argc, int min_argc, int max_argc)
|
2010-05-03 23:50:39 -04:00
|
|
|
{
|
2012-03-14 17:10:16 -04:00
|
|
|
VALUE exc = rb_arg_error_new(miss_argc, min_argc, max_argc);
|
2010-05-03 23:50:39 -04:00
|
|
|
VALUE bt = rb_make_backtrace();
|
|
|
|
VALUE err_line = 0;
|
|
|
|
|
|
|
|
if (iseq) {
|
2013-10-07 01:31:47 -04:00
|
|
|
int line_no = FIX2INT(rb_iseq_first_lineno(iseq->self));
|
2010-05-03 23:50:39 -04:00
|
|
|
|
|
|
|
err_line = rb_sprintf("%s:%d:in `%s'",
|
2012-06-03 22:49:37 -04:00
|
|
|
RSTRING_PTR(iseq->location.path),
|
|
|
|
line_no, RSTRING_PTR(iseq->location.label));
|
2010-05-03 23:50:39 -04:00
|
|
|
rb_funcall(bt, rb_intern("unshift"), 1, err_line);
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
|
|
|
|
rb_exc_raise(exc);
|
|
|
|
}
|
|
|
|
|
2013-03-12 09:20:50 -04:00
|
|
|
NORETURN(static void keyword_error(const char *error, VALUE keys));
|
|
|
|
static void
|
|
|
|
keyword_error(const char *error, VALUE keys)
|
|
|
|
{
|
|
|
|
const char *msg = RARRAY_LEN(keys) == 1 ? "" : "s";
|
|
|
|
keys = rb_ary_join(keys, rb_usascii_str_new2(", "));
|
|
|
|
rb_raise(rb_eArgError, "%s keyword%s: %"PRIsVALUE, error, msg, keys);
|
|
|
|
}
|
|
|
|
|
2011-12-26 09:20:09 -05:00
|
|
|
NORETURN(static void unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash));
|
|
|
|
static void
|
|
|
|
unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash)
|
|
|
|
{
|
2013-03-12 09:20:50 -04:00
|
|
|
VALUE keys;
|
2011-12-26 09:20:20 -05:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < iseq->arg_keywords; i++) {
|
|
|
|
rb_hash_delete(hash, ID2SYM(iseq->arg_keyword_table[i]));
|
|
|
|
}
|
|
|
|
keys = rb_funcall(hash, rb_intern("keys"), 0, 0);
|
2012-05-23 03:13:21 -04:00
|
|
|
if (!RB_TYPE_P(keys, T_ARRAY)) rb_raise(rb_eArgError, "unknown keyword");
|
2013-03-12 09:20:50 -04:00
|
|
|
keyword_error("unknown", keys);
|
2011-12-26 09:20:09 -05:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:10:34 -04:00
|
|
|
void
|
2012-03-14 21:39:00 -04:00
|
|
|
rb_error_arity(int argc, int min, int max)
|
|
|
|
{
|
2012-03-14 17:10:34 -04:00
|
|
|
rb_exc_raise(rb_arg_error_new(argc, min, max));
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* svar */
|
|
|
|
|
|
|
|
static inline NODE *
|
|
|
|
lep_svar_place(rb_thread_t *th, VALUE *lep)
|
|
|
|
{
|
|
|
|
VALUE *svar;
|
|
|
|
|
|
|
|
if (lep && th->root_lep != lep) {
|
|
|
|
svar = &lep[-1];
|
2008-06-06 10:48:07 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
svar = &th->root_svar;
|
|
|
|
}
|
|
|
|
if (NIL_P(*svar)) {
|
|
|
|
*svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil);
|
|
|
|
}
|
|
|
|
return (NODE *)*svar;
|
|
|
|
}
|
2008-06-06 10:48:07 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
2012-12-10 01:11:16 -05:00
|
|
|
lep_svar_get(rb_thread_t *th, VALUE *lep, rb_num_t key)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
NODE *svar = lep_svar_place(th, lep);
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
switch (key) {
|
|
|
|
case 0:
|
|
|
|
return svar->u1.value;
|
|
|
|
case 1:
|
|
|
|
return svar->u2.value;
|
|
|
|
default: {
|
2012-12-10 01:11:16 -05:00
|
|
|
const VALUE ary = svar->u3.value;
|
2008-06-06 10:48:07 -04:00
|
|
|
|
2012-12-10 01:11:16 -05:00
|
|
|
if (NIL_P(ary)) {
|
2012-10-14 15:58:59 -04:00
|
|
|
return Qnil;
|
2011-12-26 09:20:09 -05:00
|
|
|
}
|
|
|
|
else {
|
2012-12-10 01:11:16 -05:00
|
|
|
return rb_ary_entry(ary, key - DEFAULT_SPECIAL_VAR_COUNT);
|
2011-12-26 09:20:09 -05:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
2011-12-26 09:20:09 -05:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
2011-12-26 09:20:09 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static void
|
2012-12-10 01:11:16 -05:00
|
|
|
lep_svar_set(rb_thread_t *th, VALUE *lep, rb_num_t key, VALUE val)
|
2012-10-14 15:58:59 -04:00
|
|
|
{
|
|
|
|
NODE *svar = lep_svar_place(th, lep);
|
2008-05-21 11:18:15 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
switch (key) {
|
|
|
|
case 0:
|
|
|
|
svar->u1.value = val;
|
|
|
|
return;
|
|
|
|
case 1:
|
|
|
|
svar->u2.value = val;
|
|
|
|
return;
|
|
|
|
default: {
|
2012-12-10 01:11:16 -05:00
|
|
|
VALUE ary = svar->u3.value;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-12-10 01:11:16 -05:00
|
|
|
if (NIL_P(ary)) {
|
|
|
|
svar->u3.value = ary = rb_ary_new();
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-12-10 01:11:16 -05:00
|
|
|
rb_ary_store(ary, key - DEFAULT_SPECIAL_VAR_COUNT, val);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
2012-12-10 01:11:16 -05:00
|
|
|
vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
|
2012-10-14 15:58:59 -04:00
|
|
|
{
|
|
|
|
VALUE val;
|
|
|
|
|
|
|
|
if (type == 0) {
|
2012-12-10 01:11:16 -05:00
|
|
|
val = lep_svar_get(th, lep, key);
|
2008-06-06 10:48:07 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
VALUE backref = lep_svar_get(th, lep, 1);
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (type & 0x01) {
|
|
|
|
switch (type >> 1) {
|
|
|
|
case '&':
|
|
|
|
val = rb_reg_last_match(backref);
|
|
|
|
break;
|
|
|
|
case '`':
|
|
|
|
val = rb_reg_match_pre(backref);
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
val = rb_reg_match_post(backref);
|
|
|
|
break;
|
|
|
|
case '+':
|
|
|
|
val = rb_reg_match_last(backref);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rb_bug("unexpected back-ref");
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2008-06-06 10:48:07 -04:00
|
|
|
else {
|
2012-10-14 15:58:59 -04:00
|
|
|
val = rb_reg_nth_match((int)(type >> 1), backref);
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2008-06-06 10:48:07 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
return val;
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static NODE *
|
|
|
|
vm_get_cref0(const rb_iseq_t *iseq, const VALUE *ep)
|
|
|
|
{
|
|
|
|
while (1) {
|
|
|
|
if (VM_EP_LEP_P(ep)) {
|
|
|
|
if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL;
|
|
|
|
return iseq->cref_stack;
|
|
|
|
}
|
|
|
|
else if (ep[-1] != Qnil) {
|
|
|
|
return (NODE *)ep[-1];
|
|
|
|
}
|
|
|
|
ep = VM_EP_PREV_EP(ep);
|
2008-06-06 10:48:07 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
NODE *
|
|
|
|
rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *ep)
|
|
|
|
{
|
|
|
|
NODE *cref = vm_get_cref0(iseq, ep);
|
2011-12-26 09:20:09 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (cref == 0) {
|
|
|
|
rb_bug("rb_vm_get_cref: unreachable");
|
|
|
|
}
|
|
|
|
return cref;
|
|
|
|
}
|
2007-08-18 00:17:39 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static NODE *
|
|
|
|
vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
|
|
|
|
{
|
|
|
|
rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
|
|
|
|
NODE *cref = NEW_CREF(klass);
|
|
|
|
cref->nd_refinements = Qnil;
|
|
|
|
cref->nd_visi = noex;
|
2007-12-09 00:56:00 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (blockptr) {
|
|
|
|
cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->ep);
|
|
|
|
}
|
|
|
|
else if (cfp) {
|
|
|
|
cref->nd_next = vm_get_cref0(cfp->iseq, cfp->ep);
|
|
|
|
}
|
|
|
|
/* TODO: why cref->nd_next is 1? */
|
|
|
|
if (cref->nd_next && cref->nd_next != (void *) 1 &&
|
|
|
|
!NIL_P(cref->nd_next->nd_refinements)) {
|
|
|
|
COPY_CREF_OMOD(cref, cref->nd_next);
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2008-06-06 10:48:07 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return cref;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
NODE *cref = rb_vm_get_cref(iseq, ep);
|
|
|
|
VALUE klass = Qundef;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while (cref) {
|
|
|
|
if ((klass = cref->nd_clss) != 0) {
|
|
|
|
break;
|
2007-06-24 14:40:13 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
cref = cref->nd_next;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return klass;
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
vm_get_const_base(const rb_iseq_t *iseq, const VALUE *ep)
|
|
|
|
{
|
|
|
|
NODE *cref = rb_vm_get_cref(iseq, ep);
|
|
|
|
VALUE klass = Qundef;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while (cref) {
|
|
|
|
if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) &&
|
|
|
|
(klass = cref->nd_clss) != 0) {
|
|
|
|
break;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
cref = cref->nd_next;
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return klass;
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline void
|
|
|
|
vm_check_if_namespace(VALUE klass)
|
|
|
|
{
|
|
|
|
VALUE str;
|
|
|
|
if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE)) {
|
|
|
|
str = rb_inspect(klass);
|
|
|
|
rb_raise(rb_eTypeError, "%s is not a class/module",
|
|
|
|
StringValuePtr(str));
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline VALUE
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-12-29 07:22:01 -05:00
|
|
|
if (RB_TYPE_P(klass, T_MODULE) &&
|
2012-10-14 15:58:59 -04:00
|
|
|
FL_TEST(klass, RMODULE_IS_OVERLAID) &&
|
2012-12-29 07:22:01 -05:00
|
|
|
RB_TYPE_P(cfp->klass, T_ICLASS) &&
|
2012-10-14 15:58:59 -04:00
|
|
|
RBASIC(cfp->klass)->klass == klass) {
|
|
|
|
return cfp->klass;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return klass;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline VALUE
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
|
|
|
|
VALUE orig_klass, ID id, int is_defined)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE val;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (orig_klass == Qnil) {
|
|
|
|
/* in current lexical scope */
|
|
|
|
const NODE *root_cref = rb_vm_get_cref(iseq, th->cfp->ep);
|
|
|
|
const NODE *cref;
|
|
|
|
VALUE klass = orig_klass;
|
2009-07-15 10:59:41 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while (root_cref && root_cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) {
|
|
|
|
root_cref = root_cref->nd_next;
|
|
|
|
}
|
|
|
|
cref = root_cref;
|
|
|
|
while (cref && cref->nd_next) {
|
|
|
|
if (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) {
|
|
|
|
klass = Qnil;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
klass = cref->nd_clss;
|
|
|
|
}
|
|
|
|
cref = cref->nd_next;
|
2012-06-10 23:14:59 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (!NIL_P(klass)) {
|
|
|
|
VALUE av, am = 0;
|
|
|
|
st_data_t data;
|
|
|
|
search_continue:
|
|
|
|
if (RCLASS_CONST_TBL(klass) &&
|
|
|
|
st_lookup(RCLASS_CONST_TBL(klass), id, &data)) {
|
|
|
|
val = ((rb_const_entry_t*)data)->value;
|
|
|
|
if (val == Qundef) {
|
|
|
|
if (am == klass) break;
|
|
|
|
am = klass;
|
|
|
|
if (is_defined) return 1;
|
|
|
|
if (rb_autoloading_value(klass, id, &av)) return av;
|
|
|
|
rb_autoload_load(klass, id);
|
|
|
|
goto search_continue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (is_defined) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* search self */
|
|
|
|
if (root_cref && !NIL_P(root_cref->nd_clss)) {
|
|
|
|
klass = vm_get_iclass(th->cfp, root_cref->nd_clss);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
klass = CLASS_OF(th->cfp->self);
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (is_defined) {
|
|
|
|
return rb_const_defined(klass, id);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_const_get(klass, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vm_check_if_namespace(orig_klass);
|
|
|
|
if (is_defined) {
|
|
|
|
return rb_public_const_defined_from(orig_klass, id);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_public_const_get_from(orig_klass, id);
|
|
|
|
}
|
2010-01-24 08:52:32 -05:00
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline VALUE
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_get_cvar_base(NODE *cref, rb_control_frame_t *cfp)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE klass;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (!cref) {
|
|
|
|
rb_bug("vm_get_cvar_base: no cref");
|
|
|
|
}
|
2011-06-30 09:34:53 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while (cref->nd_next &&
|
|
|
|
(NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) ||
|
|
|
|
(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) {
|
|
|
|
cref = cref->nd_next;
|
|
|
|
}
|
|
|
|
if (!cref->nd_next) {
|
|
|
|
rb_warn("class variable access from toplevel");
|
|
|
|
}
|
2011-06-30 09:34:53 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
klass = vm_get_iclass(cfp, cref->nd_clss);
|
2011-06-30 09:34:53 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (NIL_P(klass)) {
|
|
|
|
rb_raise(rb_eTypeError, "no class variables available");
|
|
|
|
}
|
|
|
|
return klass;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_search_const_defined_class(const VALUE cbase, ID id)
|
2009-02-21 20:43:59 -05:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
if (rb_const_defined_at(cbase, id)) return cbase;
|
|
|
|
if (cbase == rb_cObject) {
|
|
|
|
VALUE tmp = RCLASS_SUPER(cbase);
|
|
|
|
while (tmp) {
|
|
|
|
if (rb_const_defined_at(tmp, id)) return tmp;
|
|
|
|
tmp = RCLASS_SUPER(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
#ifndef USE_IC_FOR_IVAR
|
|
|
|
#define USE_IC_FOR_IVAR 1
|
|
|
|
#endif
|
|
|
|
|
2012-10-16 13:07:23 -04:00
|
|
|
static inline VALUE
|
|
|
|
vm_getivar(VALUE obj, ID id, IC ic, rb_call_info_t *ci, int is_attr)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
#if USE_IC_FOR_IVAR
|
|
|
|
if (RB_TYPE_P(obj, T_OBJECT)) {
|
|
|
|
VALUE val = Qundef;
|
|
|
|
VALUE klass = RBASIC(obj)->klass;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2013-09-04 21:44:36 -04:00
|
|
|
if (LIKELY((!is_attr && ic->ic_seq == RCLASS_EXT(klass)->seq) ||
|
2012-10-16 13:07:23 -04:00
|
|
|
(is_attr && ci->aux.index > 0))) {
|
2013-08-20 13:41:13 -04:00
|
|
|
long index = !is_attr ? (long)ic->ic_value.index : ci->aux.index - 1;
|
2012-10-14 15:58:59 -04:00
|
|
|
long len = ROBJECT_NUMIV(obj);
|
|
|
|
VALUE *ptr = ROBJECT_IVPTR(obj);
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (index < len) {
|
|
|
|
val = ptr[index];
|
2007-08-06 07:36:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-10-14 15:58:59 -04:00
|
|
|
st_data_t index;
|
|
|
|
long len = ROBJECT_NUMIV(obj);
|
|
|
|
VALUE *ptr = ROBJECT_IVPTR(obj);
|
|
|
|
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (iv_index_tbl) {
|
|
|
|
if (st_lookup(iv_index_tbl, id, &index)) {
|
|
|
|
if ((long)index < len) {
|
|
|
|
val = ptr[index];
|
|
|
|
}
|
2012-10-16 13:07:23 -04:00
|
|
|
if (!is_attr) {
|
|
|
|
ic->ic_value.index = index;
|
2013-09-04 21:44:36 -04:00
|
|
|
ic->ic_seq = RCLASS_EXT(klass)->seq;
|
2012-10-16 13:07:23 -04:00
|
|
|
}
|
|
|
|
else { /* call_info */
|
2012-10-17 03:24:52 -04:00
|
|
|
ci->aux.index = index + 1;
|
2012-10-16 13:07:23 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
}
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-18 23:08:50 -04:00
|
|
|
}
|
2012-10-16 13:07:23 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (UNLIKELY(val == Qundef)) {
|
2012-10-16 13:07:23 -04:00
|
|
|
if (!is_attr) rb_warning("instance variable %s not initialized", rb_id2name(id));
|
2012-10-14 15:58:59 -04:00
|
|
|
val = Qnil;
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-18 23:08:50 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
return val;
|
|
|
|
}
|
2012-12-11 23:39:48 -05:00
|
|
|
#endif /* USE_IC_FOR_IVAR */
|
2012-12-11 23:40:55 -05:00
|
|
|
if (is_attr)
|
|
|
|
return rb_attr_get(obj, id);
|
2012-10-14 15:58:59 -04:00
|
|
|
return rb_ivar_get(obj, id);
|
2010-09-22 20:01:40 -04:00
|
|
|
}
|
|
|
|
|
2013-02-06 12:31:22 -05:00
|
|
|
static inline VALUE
|
2012-10-16 13:07:23 -04:00
|
|
|
vm_setivar(VALUE obj, ID id, VALUE val, IC ic, rb_call_info_t *ci, int is_attr)
|
2010-09-22 20:01:40 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
#if USE_IC_FOR_IVAR
|
|
|
|
rb_check_frozen(obj);
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (RB_TYPE_P(obj, T_OBJECT)) {
|
|
|
|
VALUE klass = RBASIC(obj)->klass;
|
|
|
|
st_data_t index;
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
|
2012-10-16 13:07:23 -04:00
|
|
|
if (LIKELY(
|
2013-09-04 21:44:36 -04:00
|
|
|
(!is_attr && ic->ic_seq == RCLASS_EXT(klass)->seq) ||
|
2012-10-16 13:07:23 -04:00
|
|
|
(is_attr && ci->aux.index > 0))) {
|
2013-08-20 13:41:13 -04:00
|
|
|
long index = !is_attr ? (long)ic->ic_value.index : ci->aux.index-1;
|
2012-10-14 15:58:59 -04:00
|
|
|
long len = ROBJECT_NUMIV(obj);
|
|
|
|
VALUE *ptr = ROBJECT_IVPTR(obj);
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (index < len) {
|
* gc.c: support RGENGC. [ruby-trunk - Feature #8339]
See this ticet about RGENGC.
* gc.c: Add several flags:
* RGENGC_DEBUG: if >0, then prints debug information.
* RGENGC_CHECK_MODE: if >0, add assertions.
* RGENGC_PROFILE: if >0, add profiling features.
check GC.stat and GC::Profiler.
* include/ruby/ruby.h: disable RGENGC by default (USE_RGENGC == 0).
* array.c: add write barriers for T_ARRAY and generate sunny objects.
* include/ruby/ruby.h (RARRAY_PTR_USE): added. Use this macro if
you want to access raw pointers. If you modify the contents which
pointer pointed, then you need to care write barrier.
* bignum.c, marshal.c, random.c: generate T_BIGNUM sunny objects.
* complex.c, include/ruby/ruby.h: add write barriers for T_COMPLEX
and generate sunny objects.
* rational.c (nurat_s_new_internal), include/ruby/ruby.h: add write
barriers for T_RATIONAL and generate sunny objects.
* internal.h: add write barriers for RBasic::klass.
* numeric.c (rb_float_new_in_heap): generate sunny T_FLOAT objects.
* object.c (rb_class_allocate_instance), range.c:
generate sunny T_OBJECT objects.
* string.c: add write barriers for T_STRING and generate sunny objects.
* variable.c: add write barriers for ivars.
* vm_insnhelper.c (vm_setivar): ditto.
* include/ruby/ruby.h, debug.c: use two flags
FL_WB_PROTECTED and FL_OLDGEN.
* node.h (NODE_FL_CREF_PUSHED_BY_EVAL, NODE_FL_CREF_OMOD_SHARED):
move flag bits.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40703 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 14:07:47 -04:00
|
|
|
OBJ_WRITE(obj, &ptr[index], val);
|
2013-02-06 12:31:22 -05:00
|
|
|
return val; /* inline cache hit */
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
|
2012-10-16 13:07:23 -04:00
|
|
|
if (!is_attr) {
|
|
|
|
ic->ic_value.index = index;
|
2013-09-04 21:44:36 -04:00
|
|
|
ic->ic_seq = RCLASS_EXT(klass)->seq;
|
2012-10-16 13:07:23 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ci->aux.index = index + 1;
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
/* fall through */
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
}
|
|
|
|
}
|
2012-12-11 23:39:48 -05:00
|
|
|
#endif /* USE_IC_FOR_IVAR */
|
2013-02-06 12:31:22 -05:00
|
|
|
return rb_ivar_set(obj, id, val);
|
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-22 20:20:28 -04:00
|
|
|
}
|
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-18 23:08:50 -04:00
|
|
|
|
2012-10-16 13:07:23 -04:00
|
|
|
static VALUE
|
|
|
|
vm_getinstancevariable(VALUE obj, ID id, IC ic)
|
|
|
|
{
|
|
|
|
return vm_getivar(obj, id, ic, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_setinstancevariable(VALUE obj, ID id, VALUE val, IC ic)
|
|
|
|
{
|
|
|
|
vm_setivar(obj, id, val, ic, 0, 0);
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
|
|
|
rb_num_t throw_state, VALUE throwobj)
|
2009-12-03 13:25:57 -05:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
int state = (int)(throw_state & 0xff);
|
|
|
|
int flag = (int)(throw_state & 0x8000);
|
|
|
|
rb_num_t level = throw_state >> 16;
|
2009-12-03 13:25:57 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (state != 0) {
|
|
|
|
VALUE *pt = 0;
|
|
|
|
if (flag != 0) {
|
|
|
|
pt = (void *) 1;
|
2009-12-03 13:25:57 -05:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
if (state == TAG_BREAK) {
|
|
|
|
rb_control_frame_t *cfp = GET_CFP();
|
|
|
|
VALUE *ep = GET_EP();
|
|
|
|
int is_orphan = 1;
|
|
|
|
rb_iseq_t *base_iseq = GET_ISEQ();
|
2009-12-03 13:25:57 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
search_parent:
|
|
|
|
if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {
|
|
|
|
if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
ep = cfp->ep;
|
|
|
|
goto search_parent;
|
|
|
|
}
|
|
|
|
ep = VM_EP_PREV_EP(ep);
|
|
|
|
base_iseq = base_iseq->parent_iseq;
|
2009-12-03 13:25:57 -05:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
|
|
|
if (cfp->ep == ep) {
|
|
|
|
goto search_parent;
|
|
|
|
}
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
rb_bug("VM (throw): can't find break base.");
|
|
|
|
}
|
2008-04-03 06:59:44 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
|
|
|
/* lambda{... break ...} */
|
|
|
|
is_orphan = 0;
|
|
|
|
pt = cfp->ep;
|
|
|
|
state = TAG_RETURN;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ep = VM_EP_PREV_EP(ep);
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
while ((VALUE *)cfp < th->stack + th->stack_size) {
|
|
|
|
if (cfp->ep == ep) {
|
|
|
|
VALUE epc = cfp->pc - cfp->iseq->iseq_encoded;
|
|
|
|
rb_iseq_t *iseq = cfp->iseq;
|
|
|
|
int i;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
for (i=0; i<iseq->catch_table_size; i++) {
|
|
|
|
struct iseq_catch_table_entry *entry = &iseq->catch_table[i];
|
|
|
|
|
|
|
|
if (entry->type == CATCH_TYPE_BREAK &&
|
|
|
|
entry->start < epc && entry->end >= epc) {
|
|
|
|
if (entry->cont == epc) {
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
found:
|
|
|
|
pt = ep;
|
|
|
|
is_orphan = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (is_orphan) {
|
|
|
|
rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK);
|
|
|
|
}
|
2011-03-31 05:07:42 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else if (state == TAG_RETRY) {
|
|
|
|
rb_num_t i;
|
|
|
|
pt = VM_EP_PREV_EP(GET_EP());
|
|
|
|
for (i = 0; i < level; i++) {
|
|
|
|
pt = GC_GUARDED_PTR_REF((VALUE *) * pt);
|
|
|
|
}
|
2011-03-31 05:07:42 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else if (state == TAG_RETURN) {
|
|
|
|
rb_control_frame_t *cfp = GET_CFP();
|
|
|
|
VALUE *ep = GET_EP();
|
|
|
|
VALUE *target_lep = VM_CF_LEP(cfp);
|
|
|
|
int in_class_frame = 0;
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* check orphan and get dfp */
|
|
|
|
while ((VALUE *) cfp < th->stack + th->stack_size) {
|
|
|
|
VALUE *lep = VM_CF_LEP(cfp);
|
|
|
|
|
|
|
|
if (!target_lep) {
|
|
|
|
target_lep = lep;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
if (lep == target_lep && cfp->iseq->type == ISEQ_TYPE_CLASS) {
|
|
|
|
in_class_frame = 1;
|
|
|
|
target_lep = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lep == target_lep) {
|
|
|
|
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
|
|
|
|
VALUE *tep = ep;
|
|
|
|
|
|
|
|
if (in_class_frame) {
|
|
|
|
/* lambda {class A; ... return ...; end} */
|
|
|
|
ep = cfp->ep;
|
|
|
|
goto valid_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (target_lep != tep) {
|
|
|
|
if (cfp->ep == tep) {
|
|
|
|
/* in lambda */
|
|
|
|
ep = cfp->ep;
|
|
|
|
goto valid_return;
|
|
|
|
}
|
|
|
|
tep = VM_EP_PREV_EP(tep);
|
|
|
|
}
|
2008-05-19 14:47:56 -04:00
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
if (cfp->ep == target_lep && cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
|
|
|
ep = target_lep;
|
|
|
|
goto valid_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2008-05-19 14:47:56 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
|
2008-05-19 14:47:56 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
valid_return:
|
|
|
|
pt = ep;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_bug("isns(throw): unsupport throw type");
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
th->state = state;
|
|
|
|
return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state);
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
else {
|
2012-10-14 15:58:59 -04:00
|
|
|
/* continue throw */
|
|
|
|
VALUE err = throwobj;
|
|
|
|
|
|
|
|
if (FIXNUM_P(err)) {
|
|
|
|
th->state = FIX2INT(err);
|
|
|
|
}
|
|
|
|
else if (SYMBOL_P(err)) {
|
|
|
|
th->state = TAG_THROW;
|
|
|
|
}
|
|
|
|
else if (BUILTIN_TYPE(err) == T_NODE) {
|
|
|
|
th->state = GET_THROWOBJ_STATE(err);
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
else {
|
2012-10-14 15:58:59 -04:00
|
|
|
th->state = TAG_RAISE;
|
|
|
|
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
return err;
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline void
|
|
|
|
vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag)
|
2007-06-24 13:19:22 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
int is_splat = flag & 0x01;
|
|
|
|
rb_num_t space_size = num + is_splat;
|
2013-07-24 05:57:49 -04:00
|
|
|
VALUE *base = cfp->sp;
|
|
|
|
const VALUE *ptr;
|
2012-10-14 15:58:59 -04:00
|
|
|
rb_num_t len;
|
2008-05-19 14:47:56 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (!RB_TYPE_P(ary, T_ARRAY)) {
|
|
|
|
ary = rb_ary_to_ary(ary);
|
2011-09-20 05:09:00 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
cfp->sp += space_size;
|
2008-05-19 14:47:56 -04:00
|
|
|
|
* include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
usecase of this macro is not acquire raw pointer, but acquire
read-only pointer. So we rename to better name.
RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
(I expect that nobody use it).
* array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
catch up this change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-25 04:24:34 -04:00
|
|
|
ptr = RARRAY_CONST_PTR(ary);
|
2012-10-14 15:58:59 -04:00
|
|
|
len = (rb_num_t)RARRAY_LEN(ary);
|
2008-05-19 14:47:56 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (flag & 0x02) {
|
|
|
|
/* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
|
|
|
|
rb_num_t i = 0, j;
|
|
|
|
|
|
|
|
if (len < num) {
|
|
|
|
for (i=0; i<num-len; i++) {
|
|
|
|
*base++ = Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j=0; i<num; i++, j++) {
|
|
|
|
VALUE v = ptr[len - j - 1];
|
|
|
|
*base++ = v;
|
|
|
|
}
|
|
|
|
if (is_splat) {
|
|
|
|
*base = rb_ary_new4(len - j, ptr);
|
|
|
|
}
|
2007-06-24 13:19:22 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
|
|
|
|
rb_num_t i;
|
|
|
|
VALUE *bptr = &base[space_size - 1];
|
2007-06-24 13:19:22 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
if (len <= i) {
|
|
|
|
for (; i<num; i++) {
|
|
|
|
*bptr-- = Qnil;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*bptr-- = ptr[i];
|
|
|
|
}
|
|
|
|
if (is_splat) {
|
|
|
|
if (num > len) {
|
|
|
|
*bptr = rb_ary_new();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*bptr = rb_ary_new4(len - num, ptr + num);
|
|
|
|
}
|
2011-09-02 01:36:49 -04:00
|
|
|
}
|
2011-09-01 04:31:24 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
RB_GC_GUARD(ary);
|
2011-09-01 04:31:24 -04:00
|
|
|
}
|
2009-09-06 03:40:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
|
2009-09-06 03:40:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static void
|
|
|
|
vm_search_method(rb_call_info_t *ci, VALUE recv)
|
2009-07-13 00:44:20 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE klass = CLASS_OF(recv);
|
2009-07-13 00:44:20 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
#if OPT_INLINE_METHOD_CACHE
|
* insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split
ruby_vm_global_state_version into two separate counters - one for the
global method state and one for the global constant state. This means
changes to constants do not affect method caches, and changes to
methods do not affect constant caches. In particular, this means
inclusions of modules containing constants no longer globally
invalidate the method cache.
* class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c:
rename rb_clear_cache_by_class to rb_clear_method_cache_by_class
* class.c, include/ruby/intern.h, variable.c, vm_method.c: add
rb_clear_constant_cache
* compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in
rb_call_info_struct to method_state
* vm_method.c: rename vmstat field in struct cache_entry to method_state
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43455 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-10-28 20:52:38 -04:00
|
|
|
if (LIKELY(GET_METHOD_STATE_VERSION() == ci->method_state && RCLASS_EXT(klass)->seq == ci->seq)) {
|
2012-10-14 15:58:59 -04:00
|
|
|
/* cache hit! */
|
2013-08-27 03:11:49 -04:00
|
|
|
return;
|
2009-07-13 00:44:20 -04:00
|
|
|
}
|
2013-08-27 03:11:49 -04:00
|
|
|
#endif
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 01:25:06 -04:00
|
|
|
|
2012-11-12 02:00:12 -05:00
|
|
|
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
ci->klass = klass;
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 01:25:06 -04:00
|
|
|
ci->call = vm_call_general;
|
2013-08-27 03:11:49 -04:00
|
|
|
#if OPT_INLINE_METHOD_CACHE
|
* insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split
ruby_vm_global_state_version into two separate counters - one for the
global method state and one for the global constant state. This means
changes to constants do not affect method caches, and changes to
methods do not affect constant caches. In particular, this means
inclusions of modules containing constants no longer globally
invalidate the method cache.
* class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c:
rename rb_clear_cache_by_class to rb_clear_method_cache_by_class
* class.c, include/ruby/intern.h, variable.c, vm_method.c: add
rb_clear_constant_cache
* compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in
rb_call_info_struct to method_state
* vm_method.c: rename vmstat field in struct cache_entry to method_state
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43455 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-10-28 20:52:38 -04:00
|
|
|
ci->method_state = GET_METHOD_STATE_VERSION();
|
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: Implement class hierarchy method cache invalidation.
[ruby-core:55053] [Feature #8426] [GH-387]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-04 01:25:06 -04:00
|
|
|
ci->seq = RCLASS_EXT(klass)->seq;
|
2009-07-13 00:44:20 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline int
|
|
|
|
check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
|
2009-09-06 03:40:24 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
if (me && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
|
|
|
me->def->body.cfunc.func == func) {
|
|
|
|
return 1;
|
2009-09-06 03:40:24 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
* array.c, gc.c, hash.c, object.c, string.c, struct.c,
transcode.c, variable.c, vm.c, vm_insnhelper.c, vm_method.c:
replace calls to rb_error_frozen() with rb_check_frozen(). a
patch from Run Paint Run Run at [ruby-core:32014]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29583 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2010-10-24 04:14:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static
|
|
|
|
#ifndef NO_BIG_INLINE
|
|
|
|
inline
|
|
|
|
#endif
|
|
|
|
VALUE
|
|
|
|
opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci)
|
|
|
|
{
|
|
|
|
if (FIXNUM_2_P(recv, obj) &&
|
|
|
|
BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) {
|
|
|
|
return (recv == obj) ? Qtrue : Qfalse;
|
|
|
|
}
|
|
|
|
else if (FLONUM_2_P(recv, obj) &&
|
|
|
|
BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) {
|
|
|
|
return (recv == obj) ? Qtrue : Qfalse;
|
|
|
|
}
|
|
|
|
else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
|
vm_insnhelper.h: RBASIC_CLASS
* vm_insnhelper.c (opt_eq_func): use RBASIC_CLASS() instead of HEAP_CLASS_OF().
* insns.def (opt_plus, opt_minus, opt_mult, opt_div, opt_mod, opt_lt),
(opt_gt, opt_ltlt, opt_aref, opt_aset, opt_length, opt_size),
(opt_empty_p, opt_succ): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42702 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-08-27 03:11:10 -04:00
|
|
|
if (RBASIC_CLASS(recv) == rb_cFloat &&
|
|
|
|
RBASIC_CLASS(obj) == rb_cFloat &&
|
2012-10-14 15:58:59 -04:00
|
|
|
BASIC_OP_UNREDEFINED_P(BOP_EQ, FLOAT_REDEFINED_OP_FLAG)) {
|
|
|
|
double a = RFLOAT_VALUE(recv);
|
|
|
|
double b = RFLOAT_VALUE(obj);
|
2009-09-06 03:40:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (isnan(a) || isnan(b)) {
|
|
|
|
return Qfalse;
|
2009-09-06 03:40:24 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
return (a == b) ? Qtrue : Qfalse;
|
2009-09-06 03:40:24 -04:00
|
|
|
}
|
vm_insnhelper.h: RBASIC_CLASS
* vm_insnhelper.c (opt_eq_func): use RBASIC_CLASS() instead of HEAP_CLASS_OF().
* insns.def (opt_plus, opt_minus, opt_mult, opt_div, opt_mod, opt_lt),
(opt_gt, opt_ltlt, opt_aref, opt_aset, opt_length, opt_size),
(opt_empty_p, opt_succ): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42702 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-08-27 03:11:10 -04:00
|
|
|
else if (RBASIC_CLASS(recv) == rb_cString &&
|
|
|
|
RBASIC_CLASS(obj) == rb_cString &&
|
2012-10-14 15:58:59 -04:00
|
|
|
BASIC_OP_UNREDEFINED_P(BOP_EQ, STRING_REDEFINED_OP_FLAG)) {
|
|
|
|
return rb_str_equal(recv, obj);
|
|
|
|
}
|
|
|
|
}
|
2009-09-06 03:40:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
{
|
|
|
|
vm_search_method(ci, recv);
|
|
|
|
|
|
|
|
if (check_cfunc(ci->me, rb_obj_equal)) {
|
|
|
|
return recv == obj ? Qtrue : Qfalse;
|
2009-09-06 03:40:24 -04:00
|
|
|
}
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
return Qundef;
|
2009-09-06 03:40:24 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 03:46:08 -04:00
|
|
|
VALUE
|
|
|
|
rb_equal_opt(VALUE obj1, VALUE obj2)
|
|
|
|
{
|
|
|
|
rb_call_info_t ci;
|
|
|
|
ci.mid = idEq;
|
|
|
|
ci.klass = 0;
|
* insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split
ruby_vm_global_state_version into two separate counters - one for the
global method state and one for the global constant state. This means
changes to constants do not affect method caches, and changes to
methods do not affect constant caches. In particular, this means
inclusions of modules containing constants no longer globally
invalidate the method cache.
* class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c:
rename rb_clear_cache_by_class to rb_clear_method_cache_by_class
* class.c, include/ruby/intern.h, variable.c, vm_method.c: add
rb_clear_constant_cache
* compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in
rb_call_info_struct to method_state
* vm_method.c: rename vmstat field in struct cache_entry to method_state
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43455 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-10-28 20:52:38 -04:00
|
|
|
ci.method_state = 0;
|
2013-08-27 03:46:08 -04:00
|
|
|
ci.me = NULL;
|
|
|
|
ci.defined_class = 0;
|
|
|
|
return opt_eq_func(obj1, obj2, &ci);
|
|
|
|
}
|
|
|
|
|
2013-09-07 02:44:31 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call0(rb_thread_t*, VALUE, ID, int, const VALUE*, const rb_method_entry_t*, VALUE);
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
check_match(VALUE pattern, VALUE target, enum vm_check_match_type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case VM_CHECKMATCH_TYPE_WHEN:
|
|
|
|
return pattern;
|
2013-09-07 02:44:31 -04:00
|
|
|
case VM_CHECKMATCH_TYPE_RESCUE:
|
2012-10-14 15:58:59 -04:00
|
|
|
if (!rb_obj_is_kind_of(pattern, rb_cModule)) {
|
|
|
|
rb_raise(rb_eTypeError, "class or module required for rescue clause");
|
|
|
|
}
|
2013-09-07 02:44:31 -04:00
|
|
|
/* fall through */
|
|
|
|
case VM_CHECKMATCH_TYPE_CASE: {
|
|
|
|
VALUE defined_class;
|
|
|
|
rb_method_entry_t *me = rb_method_entry_with_refinements(CLASS_OF(pattern), idEqq, &defined_class);
|
|
|
|
return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me, defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
rb_bug("check_match: unreachable");
|
|
|
|
}
|
|
|
|
}
|
2007-08-06 07:36:30 -04:00
|
|
|
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
#if defined(_MSC_VER) && _MSC_VER < 1300
|
|
|
|
#define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse;
|
|
|
|
#else
|
|
|
|
#define CHECK_CMP_NAN(a, b) /* do nothing */
|
|
|
|
#endif
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
double_cmp_lt(double a, double b)
|
|
|
|
{
|
|
|
|
CHECK_CMP_NAN(a, b);
|
|
|
|
return a < b ? Qtrue : Qfalse;
|
|
|
|
}
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
double_cmp_le(double a, double b)
|
|
|
|
{
|
|
|
|
CHECK_CMP_NAN(a, b);
|
|
|
|
return a <= b ? Qtrue : Qfalse;
|
|
|
|
}
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
double_cmp_gt(double a, double b)
|
|
|
|
{
|
|
|
|
CHECK_CMP_NAN(a, b);
|
|
|
|
return a > b ? Qtrue : Qfalse;
|
|
|
|
}
|
2012-06-10 23:14:59 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline VALUE
|
|
|
|
double_cmp_ge(double a, double b)
|
|
|
|
{
|
|
|
|
CHECK_CMP_NAN(a, b);
|
|
|
|
return a >= b ? Qtrue : Qfalse;
|
|
|
|
}
|
2012-06-10 23:14:59 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE *
|
|
|
|
vm_base_ptr(rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
rb_control_frame_t *prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
VALUE *bp = prev_cfp->sp + cfp->iseq->local_size + 1;
|
2010-05-09 14:21:39 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (cfp->iseq->type == ISEQ_TYPE_METHOD) {
|
|
|
|
/* adjust `self' */
|
|
|
|
bp += 1;
|
|
|
|
}
|
2008-06-17 15:27:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
#if VM_DEBUG_BP_CHECK
|
|
|
|
if (bp != cfp->bp_check) {
|
|
|
|
fprintf(stderr, "bp_check: %ld, bp: %ld\n",
|
|
|
|
(long)(cfp->bp_check - GET_THREAD()->stack),
|
|
|
|
(long)(bp - GET_THREAD()->stack));
|
|
|
|
rb_bug("vm_base_ptr: unreachable");
|
|
|
|
}
|
|
|
|
#endif
|
2011-07-10 05:04:44 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return bp;
|
|
|
|
}
|
2008-06-17 15:27:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* method call processes with call_info */
|
2008-06-17 15:27:24 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static void
|
|
|
|
vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|
|
|
{
|
2012-11-13 03:34:43 -05:00
|
|
|
#define SAVE_RESTORE_CI(expr, ci) do { \
|
|
|
|
int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \
|
|
|
|
expr; \
|
|
|
|
(ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \
|
|
|
|
} while (0)
|
|
|
|
|
2012-10-15 13:22:57 -04:00
|
|
|
if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) {
|
2012-10-14 15:58:59 -04:00
|
|
|
rb_proc_t *po;
|
|
|
|
VALUE proc;
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
proc = *(--cfp->sp);
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (proc != Qnil) {
|
|
|
|
if (!rb_obj_is_proc(proc)) {
|
2012-11-13 03:34:43 -05:00
|
|
|
VALUE b;
|
|
|
|
|
|
|
|
SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci);
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (NIL_P(b) || !rb_obj_is_proc(b)) {
|
|
|
|
rb_raise(rb_eTypeError,
|
|
|
|
"wrong argument type %s (expected Proc)",
|
|
|
|
rb_obj_classname(proc));
|
|
|
|
}
|
|
|
|
proc = b;
|
2007-08-06 07:36:30 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
GetProcPtr(proc, po);
|
|
|
|
ci->blockptr = &po->block;
|
|
|
|
RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
|
2007-08-06 07:36:30 -04:00
|
|
|
}
|
|
|
|
}
|
2012-10-18 05:41:55 -04:00
|
|
|
else if (ci->blockiseq != 0) { /* likely */
|
2012-10-14 15:58:59 -04:00
|
|
|
ci->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
|
|
|
|
ci->blockptr->iseq = ci->blockiseq;
|
|
|
|
ci->blockptr->proc = 0;
|
|
|
|
}
|
2007-08-06 07:36:30 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* expand top of stack? */
|
|
|
|
|
2012-10-15 13:22:57 -04:00
|
|
|
if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) {
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE ary = *(cfp->sp - 1);
|
2013-07-24 05:57:49 -04:00
|
|
|
const VALUE *ptr;
|
2012-10-14 15:58:59 -04:00
|
|
|
int i;
|
2012-11-13 03:34:43 -05:00
|
|
|
VALUE tmp;
|
|
|
|
|
|
|
|
SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
if (NIL_P(tmp)) {
|
|
|
|
/* do nothing */
|
2007-08-06 07:36:30 -04:00
|
|
|
}
|
|
|
|
else {
|
2012-10-14 15:58:59 -04:00
|
|
|
long len = RARRAY_LEN(tmp);
|
* include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
usecase of this macro is not acquire raw pointer, but acquire
read-only pointer. So we rename to better name.
RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
(I expect that nobody use it).
* array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
catch up this change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-25 04:24:34 -04:00
|
|
|
ptr = RARRAY_CONST_PTR(tmp);
|
2012-10-14 15:58:59 -04:00
|
|
|
cfp->sp -= 1;
|
|
|
|
|
2012-12-25 04:57:07 -05:00
|
|
|
CHECK_VM_STACK_OVERFLOW(cfp, len);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
*cfp->sp++ = ptr[i];
|
|
|
|
}
|
|
|
|
ci->argc += i-1;
|
2007-08-06 07:36:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-12 02:21:35 -04:00
|
|
|
static int
|
|
|
|
separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
|
|
|
|
{
|
|
|
|
VALUE *kwdhash = (VALUE *)arg;
|
|
|
|
|
|
|
|
if (!SYMBOL_P(key)) kwdhash++;
|
|
|
|
if (!*kwdhash) *kwdhash = rb_hash_new();
|
|
|
|
rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
extract_keywords(VALUE *orighash)
|
|
|
|
{
|
|
|
|
VALUE parthash[2] = {0, 0};
|
|
|
|
VALUE hash = *orighash;
|
|
|
|
|
|
|
|
if (RHASH_EMPTY_P(hash)) {
|
|
|
|
*orighash = 0;
|
|
|
|
return hash;
|
|
|
|
}
|
2013-05-26 12:19:04 -04:00
|
|
|
st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&parthash);
|
2013-04-12 02:21:35 -04:00
|
|
|
*orighash = parthash[1];
|
|
|
|
return parthash[0];
|
|
|
|
}
|
|
|
|
|
2012-12-29 21:06:28 -05:00
|
|
|
static inline int
|
2013-05-30 06:50:41 -04:00
|
|
|
vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, int m, VALUE *orig_argv, VALUE *kwd)
|
2012-12-29 21:06:28 -05:00
|
|
|
{
|
2013-04-12 02:21:35 -04:00
|
|
|
VALUE keyword_hash, orig_hash;
|
2012-12-29 21:06:28 -05:00
|
|
|
int i, j;
|
|
|
|
|
2013-05-30 06:50:41 -04:00
|
|
|
if (argc > m &&
|
2013-04-12 02:21:35 -04:00
|
|
|
!NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) &&
|
|
|
|
(keyword_hash = extract_keywords(&orig_hash)) != 0) {
|
|
|
|
if (!orig_hash) {
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
orig_argv[argc-1] = orig_hash;
|
|
|
|
}
|
2013-03-21 15:51:19 -04:00
|
|
|
i = 0;
|
|
|
|
if (iseq->arg_keyword_required) {
|
2013-03-12 09:20:50 -04:00
|
|
|
VALUE missing = Qnil;
|
2013-03-21 15:51:19 -04:00
|
|
|
for (; i < iseq->arg_keyword_required; i++) {
|
2013-04-12 02:21:35 -04:00
|
|
|
VALUE keyword = ID2SYM(iseq->arg_keyword_table[i]);
|
2013-05-26 12:19:04 -04:00
|
|
|
if (st_lookup(rb_hash_tbl_raw(keyword_hash), (st_data_t)keyword, 0))
|
2013-03-12 09:20:50 -04:00
|
|
|
continue;
|
|
|
|
if (NIL_P(missing)) missing = rb_ary_tmp_new(1);
|
2013-04-12 02:21:35 -04:00
|
|
|
rb_ary_push(missing, keyword);
|
2013-03-12 09:20:50 -04:00
|
|
|
}
|
|
|
|
if (!NIL_P(missing)) {
|
|
|
|
keyword_error("missing", missing);
|
|
|
|
}
|
2013-03-21 15:51:19 -04:00
|
|
|
}
|
|
|
|
if (iseq->arg_keyword_check) {
|
2013-03-12 09:20:50 -04:00
|
|
|
for (j = i; i < iseq->arg_keywords; i++) {
|
2013-05-26 12:19:04 -04:00
|
|
|
if (st_lookup(rb_hash_tbl_raw(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++;
|
2012-12-29 21:06:28 -05:00
|
|
|
}
|
2013-05-27 04:33:44 -04:00
|
|
|
if (RHASH_SIZE(keyword_hash) > (unsigned int)j) {
|
2012-12-29 21:06:28 -05:00
|
|
|
unknown_keyword_error(iseq, keyword_hash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-21 15:51:19 -04:00
|
|
|
else if (iseq->arg_keyword_required) {
|
2013-03-12 09:20:50 -04:00
|
|
|
VALUE missing = rb_ary_tmp_new(iseq->arg_keyword_required);
|
|
|
|
for (i = 0; i < iseq->arg_keyword_required; i++) {
|
|
|
|
rb_ary_push(missing, ID2SYM(iseq->arg_keyword_table[i]));
|
|
|
|
}
|
|
|
|
keyword_error("missing", missing);
|
|
|
|
}
|
2012-12-29 21:06:28 -05:00
|
|
|
else {
|
|
|
|
keyword_hash = rb_hash_new();
|
|
|
|
}
|
|
|
|
|
2013-01-06 22:09:28 -05:00
|
|
|
*kwd = keyword_hash;
|
2012-12-29 21:06:28 -05:00
|
|
|
|
|
|
|
return argc;
|
|
|
|
}
|
|
|
|
|
2012-10-18 02:14:39 -04:00
|
|
|
static inline int
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_callee_setup_arg_complex(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq, VALUE *orig_argv)
|
|
|
|
{
|
|
|
|
const int m = iseq->argc;
|
|
|
|
const int opts = iseq->arg_opts - (iseq->arg_opts > 0);
|
|
|
|
const int min = m + iseq->arg_post_len;
|
|
|
|
const int max = (iseq->arg_rest == -1) ? m + opts + iseq->arg_post_len : UNLIMITED_ARGUMENTS;
|
|
|
|
const int orig_argc = ci->argc;
|
|
|
|
int argc = orig_argc;
|
|
|
|
VALUE *argv = orig_argv;
|
2013-01-06 22:09:28 -05:00
|
|
|
VALUE keyword_hash = Qnil;
|
2012-10-14 20:57:37 -04:00
|
|
|
rb_num_t opt_pc = 0;
|
2007-08-23 03:10:56 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
th->mark_stack_len = argc + iseq->arg_size;
|
2007-08-23 03:10:56 -04:00
|
|
|
|
2012-12-29 21:06:28 -05:00
|
|
|
/* keyword argument */
|
2012-10-14 15:58:59 -04:00
|
|
|
if (iseq->arg_keyword != -1) {
|
2013-05-30 06:50:41 -04:00
|
|
|
argc = vm_callee_setup_keyword_arg(iseq, argc, m, orig_argv, &keyword_hash);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
if ((argc < min) || (argc > max && max != UNLIMITED_ARGUMENTS)) {
|
|
|
|
argument_error(iseq, argc, min, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
argv += m;
|
|
|
|
argc -= m;
|
|
|
|
|
|
|
|
/* post arguments */
|
|
|
|
if (iseq->arg_post_len) {
|
|
|
|
if (!(orig_argc < iseq->arg_post_start)) {
|
|
|
|
VALUE *new_argv = ALLOCA_N(VALUE, argc);
|
|
|
|
MEMCPY(new_argv, argv, VALUE, argc);
|
|
|
|
argv = new_argv;
|
2007-08-23 03:10:56 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len],
|
|
|
|
VALUE, iseq->arg_post_len);
|
2007-08-23 03:10:56 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* opt arguments */
|
|
|
|
if (iseq->arg_opts) {
|
|
|
|
if (argc > opts) {
|
|
|
|
argc -= opts;
|
|
|
|
argv += opts;
|
|
|
|
opt_pc = iseq->arg_opt_table[opts]; /* no opt */
|
2007-08-23 03:10:56 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
|
|
|
int i;
|
|
|
|
for (i = argc; i<opts; i++) {
|
|
|
|
orig_argv[i + m] = Qnil;
|
2007-08-23 03:10:56 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
opt_pc = iseq->arg_opt_table[argc];
|
|
|
|
argc = 0;
|
2007-08-23 03:10:56 -04:00
|
|
|
}
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* rest arguments */
|
|
|
|
if (iseq->arg_rest != -1) {
|
|
|
|
orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv);
|
|
|
|
argc = 0;
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2013-01-06 22:09:28 -05:00
|
|
|
/* keyword argument */
|
|
|
|
if (iseq->arg_keyword != -1) {
|
2013-09-29 05:50:24 -04:00
|
|
|
int i;
|
|
|
|
int arg_keywords_end = iseq->arg_keyword - (iseq->arg_block != -1);
|
|
|
|
for (i = iseq->arg_keywords; 0 < i; i--) {
|
|
|
|
orig_argv[arg_keywords_end - i] = Qnil;
|
|
|
|
}
|
2013-01-06 22:09:28 -05:00
|
|
|
orig_argv[iseq->arg_keyword] = keyword_hash;
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* block arguments */
|
|
|
|
if (iseq->arg_block != -1) {
|
|
|
|
VALUE blockval = Qnil;
|
|
|
|
const rb_block_t *blockptr = ci->blockptr;
|
|
|
|
|
|
|
|
if (blockptr) {
|
|
|
|
/* make Proc object */
|
|
|
|
if (blockptr->proc == 0) {
|
|
|
|
rb_proc_t *proc;
|
|
|
|
blockval = rb_vm_make_proc(th, blockptr, rb_cProc);
|
|
|
|
GetProcPtr(blockval, proc);
|
|
|
|
ci->blockptr = &proc->block;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
blockval = blockptr->proc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
orig_argv[iseq->arg_block] = blockval; /* Proc or nil */
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
th->mark_stack_len = 0;
|
|
|
|
return (int)opt_pc;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
|
2012-10-24 05:48:32 -04:00
|
|
|
static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
|
|
|
|
static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-14 20:44:04 -04:00
|
|
|
#define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \
|
2012-10-14 16:59:21 -04:00
|
|
|
if (LIKELY((iseq)->arg_simple & 0x01)) { \
|
|
|
|
/* simple check */ \
|
|
|
|
if ((ci)->argc != (iseq)->argc) { \
|
|
|
|
argument_error((iseq), ((ci)->argc), (iseq)->argc, (iseq)->argc); \
|
|
|
|
} \
|
2012-10-16 13:07:23 -04:00
|
|
|
(ci)->aux.opt_pc = 0; \
|
2012-10-16 17:20:11 -04:00
|
|
|
CI_SET_FASTPATH((ci), UNLIKELY((ci)->flag & VM_CALL_TAILCALL) ? vm_call_iseq_setup_tailcall : vm_call_iseq_setup_normal, !(is_lambda) && !((ci)->me->flag & NOEX_PROTECTED)); \
|
2012-10-14 16:59:21 -04:00
|
|
|
} \
|
|
|
|
else { \
|
2012-10-16 13:07:23 -04:00
|
|
|
(ci)->aux.opt_pc = vm_callee_setup_arg_complex((th), (ci), (iseq), (argv)); \
|
2012-10-14 16:59:21 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
2007-12-18 07:07:51 -05:00
|
|
|
{
|
2012-10-14 20:44:04 -04:00
|
|
|
VM_CALLEE_SETUP_ARG(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc, 0);
|
2012-10-14 15:58:59 -04:00
|
|
|
return vm_call_iseq_setup_2(th, cfp, ci);
|
2007-12-18 07:07:51 -05:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
2012-10-16 17:20:11 -04:00
|
|
|
{
|
|
|
|
if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) {
|
|
|
|
return vm_call_iseq_setup_normal(th, cfp, ci);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return vm_call_iseq_setup_tailcall(th, cfp, ci);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-18 02:14:39 -04:00
|
|
|
static inline VALUE
|
2012-10-16 17:20:11 -04:00
|
|
|
vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
2007-12-18 07:07:51 -05:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
int i;
|
|
|
|
VALUE *argv = cfp->sp - ci->argc;
|
|
|
|
rb_iseq_t *iseq = ci->me->def->body.iseq;
|
2012-10-16 17:20:11 -04:00
|
|
|
VALUE *sp = argv + iseq->arg_size;
|
2007-12-18 07:07:51 -05:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
/* clear local variables */
|
|
|
|
for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
|
|
|
|
*sp++ = Qnil;
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class,
|
|
|
|
VM_ENVVAL_BLOCK_PTR(ci->blockptr),
|
2013-08-06 04:33:05 -04:00
|
|
|
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
cfp->sp = argv - 1 /* recv */;
|
|
|
|
return Qundef;
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-18 02:14:39 -04:00
|
|
|
static inline VALUE
|
2012-10-16 17:20:11 -04:00
|
|
|
vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
VALUE *argv = cfp->sp - ci->argc;
|
|
|
|
rb_iseq_t *iseq = ci->me->def->body.iseq;
|
|
|
|
VALUE *src_argv = argv;
|
|
|
|
VALUE *sp_orig, *sp;
|
|
|
|
VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
|
2007-12-18 07:07:51 -05:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */
|
2009-08-15 14:18:07 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
RUBY_VM_CHECK_INTS(th);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
sp_orig = sp = cfp->sp;
|
2007-12-18 07:07:51 -05:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
/* push self */
|
|
|
|
sp[0] = ci->recv;
|
|
|
|
sp++;
|
2009-08-12 01:55:06 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
/* copy arguments */
|
|
|
|
for (i=0; i < iseq->arg_size; i++) {
|
|
|
|
*sp++ = src_argv[i];
|
|
|
|
}
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
/* clear local variables */
|
|
|
|
for (i = 0; i < iseq->local_size - iseq->arg_size; i++) {
|
|
|
|
*sp++ = Qnil;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-10-16 17:20:11 -04:00
|
|
|
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag,
|
|
|
|
ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr),
|
2013-08-06 04:33:05 -04:00
|
|
|
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max);
|
2012-10-16 17:20:11 -04:00
|
|
|
|
|
|
|
cfp->sp = sp_orig;
|
2012-10-14 15:58:59 -04:00
|
|
|
return Qundef;
|
2012-08-02 07:34:19 -04:00
|
|
|
}
|
|
|
|
|
2012-10-19 06:38:30 -04:00
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_m2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-08-02 07:34:19 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, rb_ary_new4(argc, argv));
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2012-10-19 06:38:30 -04:00
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_m1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(argc, argv, recv);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-19 06:38:30 -04:00
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_0(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_1(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_3(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_4(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_5(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_6(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_7(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_8(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_9(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_10(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_11(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_12(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_13(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_14(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-11-13 04:48:08 -05:00
|
|
|
call_cfunc_15(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
|
2012-10-19 06:38:30 -04:00
|
|
|
{
|
2012-11-13 04:48:08 -05:00
|
|
|
return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
|
2012-10-19 06:38:30 -04:00
|
|
|
}
|
|
|
|
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
#ifndef VM_PROFILE
|
|
|
|
#define VM_PROFILE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if VM_PROFILE
|
|
|
|
static int vm_profile_counter[4];
|
|
|
|
#define VM_PROFILE_UP(x) (vm_profile_counter[x]++)
|
|
|
|
#define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result)
|
2013-09-09 01:17:17 -04:00
|
|
|
static void
|
|
|
|
vm_profile_show_result(void)
|
2012-11-06 17:50:30 -05:00
|
|
|
{
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
fprintf(stderr, "VM Profile results: \n");
|
|
|
|
fprintf(stderr, "r->c call: %d\n", vm_profile_counter[0]);
|
|
|
|
fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[1]);
|
|
|
|
fprintf(stderr, "c->c call: %d\n", vm_profile_counter[2]);
|
|
|
|
fprintf(stderr, "r->c popf: %d\n", vm_profile_counter[3]);
|
2012-08-02 07:34:19 -04:00
|
|
|
}
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
#else
|
|
|
|
#define VM_PROFILE_UP(x)
|
|
|
|
#define VM_PROFILE_ATEXIT()
|
|
|
|
#endif
|
2012-08-02 07:34:19 -04:00
|
|
|
|
2013-09-09 01:17:19 -04:00
|
|
|
static inline
|
|
|
|
const rb_method_cfunc_t *
|
|
|
|
vm_method_cfunc_entry(const rb_method_entry_t *me)
|
|
|
|
{
|
|
|
|
#if VM_DEBUG_VERIFY_METHOD_CACHE
|
|
|
|
switch (me->def->type) {
|
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
|
|
|
break;
|
|
|
|
# define METHOD_BUG(t) case VM_METHOD_TYPE_##t: rb_bug("wrong method type: " #t)
|
|
|
|
METHOD_BUG(ISEQ);
|
|
|
|
METHOD_BUG(ATTRSET);
|
|
|
|
METHOD_BUG(IVAR);
|
|
|
|
METHOD_BUG(BMETHOD);
|
|
|
|
METHOD_BUG(ZSUPER);
|
|
|
|
METHOD_BUG(UNDEF);
|
|
|
|
METHOD_BUG(OPTIMIZED);
|
|
|
|
METHOD_BUG(MISSING);
|
|
|
|
METHOD_BUG(REFINED);
|
|
|
|
# undef METHOD_BUG
|
|
|
|
default:
|
|
|
|
rb_bug("wrong method type: %d", me->def->type);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return &me->def->body.cfunc;
|
|
|
|
}
|
|
|
|
|
2012-08-08 03:52:19 -04:00
|
|
|
static VALUE
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
2012-08-08 03:52:19 -04:00
|
|
|
{
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
VALUE val;
|
2012-10-14 15:58:59 -04:00
|
|
|
const rb_method_entry_t *me = ci->me;
|
2013-09-09 01:17:19 -04:00
|
|
|
const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(me);
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
int len = cfunc->argc;
|
2012-11-13 04:48:08 -05:00
|
|
|
|
|
|
|
/* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
VALUE recv = ci->recv;
|
2012-11-13 04:48:08 -05:00
|
|
|
VALUE defined_class = ci->defined_class;
|
|
|
|
rb_block_t *blockptr = ci->blockptr;
|
|
|
|
int argc = ci->argc;
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-11-30 21:13:06 -05:00
|
|
|
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-11-13 04:48:08 -05:00
|
|
|
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
|
2013-08-06 04:33:05 -04:00
|
|
|
VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me, 0);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-11-13 04:48:08 -05:00
|
|
|
if (len >= 0) rb_check_arity(argc, len, len);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-11-13 04:48:08 -05:00
|
|
|
reg_cfp->sp -= argc + 1;
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
VM_PROFILE_UP(0);
|
2012-11-13 04:48:08 -05:00
|
|
|
val = (*cfunc->invoker)(cfunc->func, recv, argc, reg_cfp->sp + 1);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
if (reg_cfp != th->cfp + 1) {
|
2012-10-19 06:38:30 -04:00
|
|
|
rb_bug("vm_call_cfunc - cfp consistency error");
|
2012-08-08 03:52:19 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_pop_frame(th);
|
2012-08-23 03:22:40 -04:00
|
|
|
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
|
2012-11-30 21:13:06 -05:00
|
|
|
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if OPT_CALL_CFUNC_WITHOUT_FRAME
|
|
|
|
static VALUE
|
|
|
|
vm_call_cfunc_latter(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
VALUE val;
|
|
|
|
int argc = ci->argc;
|
|
|
|
VALUE *argv = STACK_ADDR_FROM_TOP(argc);
|
2013-09-09 01:17:19 -04:00
|
|
|
const rb_method_cfunc_t *cfunc = vm_method_cfunc_entry(ci->me);
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
|
|
|
|
th->passed_ci = ci;
|
|
|
|
reg_cfp->sp -= argc + 1;
|
|
|
|
ci->aux.inc_sp = argc + 1;
|
|
|
|
VM_PROFILE_UP(0);
|
|
|
|
val = (*cfunc->invoker)(cfunc->func, ci, argv);
|
|
|
|
|
|
|
|
/* check */
|
|
|
|
if (reg_cfp == th->cfp) { /* no frame push */
|
|
|
|
if (UNLIKELY(th->passed_ci != ci)) {
|
|
|
|
rb_bug("vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p)", ci, th->passed_ci);
|
|
|
|
}
|
|
|
|
th->passed_ci = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (UNLIKELY(reg_cfp != RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp))) {
|
|
|
|
rb_bug("vm_call_cfunc_latter: cfp consistency error (%p, %p)", reg_cfp, th->cfp+1);
|
|
|
|
}
|
|
|
|
vm_pop_frame(th);
|
|
|
|
VM_PROFILE_UP(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
VALUE val;
|
|
|
|
const rb_method_entry_t *me = ci->me;
|
2013-09-09 01:17:19 -04:00
|
|
|
int len = vm_method_cfunc_entry(me)->argc;
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
VALUE recv = ci->recv;
|
|
|
|
|
|
|
|
if (len >= 0) rb_check_arity(ci->argc, len, len);
|
|
|
|
|
2012-11-30 21:13:06 -05:00
|
|
|
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil);
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
|
|
|
|
if (!(ci->me->flag & NOEX_PROTECTED) &&
|
|
|
|
!(ci->flag & VM_CALL_ARGS_SPLAT)) {
|
|
|
|
CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1);
|
|
|
|
}
|
|
|
|
val = vm_call_cfunc_latter(th, reg_cfp, ci);
|
|
|
|
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
|
2012-11-30 21:13:06 -05:00
|
|
|
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
|
2012-08-23 03:22:40 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return val;
|
2012-08-23 03:22:40 -04:00
|
|
|
}
|
|
|
|
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
void
|
|
|
|
vm_call_cfunc_push_frame(rb_thread_t *th)
|
|
|
|
{
|
|
|
|
rb_call_info_t *ci = th->passed_ci;
|
|
|
|
const rb_method_entry_t *me = ci->me;
|
|
|
|
th->passed_ci = 0;
|
|
|
|
|
|
|
|
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
|
|
|
|
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me);
|
|
|
|
|
|
|
|
if (ci->call != vm_call_general) {
|
|
|
|
ci->call = vm_call_cfunc_with_frame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
|
|
|
|
static VALUE
|
|
|
|
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
return vm_call_cfunc_with_frame(th, reg_cfp, ci);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call_ivar(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|
|
|
{
|
2012-10-16 13:07:23 -04:00
|
|
|
VALUE val = vm_getivar(ci->recv, ci->me->def->body.attr.id, 0, ci, 1);
|
2012-10-14 15:58:59 -04:00
|
|
|
cfp->sp -= 1;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_call_attrset(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
2012-08-23 03:22:40 -04:00
|
|
|
{
|
2013-02-06 12:31:22 -05:00
|
|
|
VALUE val = vm_setivar(ci->recv, ci->me->def->body.attr.id, *(cfp->sp - 1), 0, ci, 1);
|
2012-10-14 15:58:59 -04:00
|
|
|
cfp->sp -= 2;
|
2013-02-06 12:31:22 -05:00
|
|
|
return val;
|
2012-08-23 03:22:40 -04:00
|
|
|
}
|
|
|
|
|
2012-10-18 02:14:39 -04:00
|
|
|
static inline VALUE
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv)
|
2012-08-23 03:22:40 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
rb_proc_t *proc;
|
|
|
|
VALUE val;
|
|
|
|
|
2012-11-30 21:13:06 -05:00
|
|
|
RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id);
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
/* control block frame */
|
|
|
|
th->passed_me = ci->me;
|
|
|
|
GetProcPtr(ci->me->def->body.proc, proc);
|
|
|
|
val = vm_invoke_proc(th, proc, ci->recv, ci->defined_class, ci->argc, argv, ci->blockptr);
|
|
|
|
|
2012-11-20 04:48:24 -05:00
|
|
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, ci->recv, ci->me->called_id, ci->me->klass, val);
|
2012-11-29 12:55:54 -05:00
|
|
|
RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->me->klass, ci->me->called_id);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
return val;
|
2012-08-23 03:22:40 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call_bmethod(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
2012-08-23 03:22:40 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE *argv = ALLOCA_N(VALUE, ci->argc);
|
|
|
|
MEMCPY(argv, cfp->sp - ci->argc, VALUE, ci->argc);
|
|
|
|
cfp->sp += - ci->argc - 1;
|
|
|
|
|
|
|
|
return vm_call_bmethod_body(th, ci, argv);
|
2012-08-23 03:22:40 -04:00
|
|
|
}
|
2012-09-28 00:05:36 -04:00
|
|
|
|
2012-12-14 03:04:55 -05:00
|
|
|
static
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
__forceinline
|
|
|
|
#else
|
|
|
|
inline
|
|
|
|
#endif
|
|
|
|
VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
2012-09-28 00:05:36 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
int i = ci->argc - 1;
|
|
|
|
VALUE sym;
|
|
|
|
rb_call_info_t ci_entry;
|
2012-09-28 00:05:36 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (ci->argc == 0) {
|
|
|
|
rb_raise(rb_eArgError, "no method name given");
|
2012-09-28 00:05:36 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
ci_entry = *ci; /* copy ci entry */
|
|
|
|
ci = &ci_entry;
|
|
|
|
|
|
|
|
sym = TOPN(i);
|
|
|
|
|
|
|
|
if (SYMBOL_P(sym)) {
|
|
|
|
ci->mid = SYM2ID(sym);
|
2012-09-28 00:05:36 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else if (!(ci->mid = rb_check_id(&sym))) {
|
|
|
|
if (rb_method_basic_definition_p(CLASS_OF(ci->recv), idMethodMissing)) {
|
|
|
|
VALUE exc = make_no_method_exception(rb_eNoMethodError, NULL, ci->recv, rb_long2int(ci->argc), &TOPN(i));
|
|
|
|
rb_exc_raise(exc);
|
|
|
|
}
|
|
|
|
ci->mid = rb_to_id(sym);
|
|
|
|
}
|
2012-10-17 03:12:40 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* shift arguments */
|
|
|
|
if (i > 0) {
|
|
|
|
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
|
|
|
}
|
2012-12-09 03:48:34 -05:00
|
|
|
ci->me =
|
|
|
|
rb_method_entry_without_refinements(CLASS_OF(ci->recv),
|
|
|
|
ci->mid, &ci->defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
ci->argc -= 1;
|
|
|
|
DEC_SP(1);
|
2012-09-28 00:05:36 -04:00
|
|
|
|
2012-10-17 03:12:40 -04:00
|
|
|
ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
return vm_call_method(th, reg_cfp, ci);
|
2012-09-28 00:05:36 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
|
|
|
vm_call_opt_call(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
rb_proc_t *proc;
|
|
|
|
int argc = ci->argc;
|
|
|
|
VALUE *argv = ALLOCA_N(VALUE, argc);
|
|
|
|
GetProcPtr(ci->recv, proc);
|
|
|
|
MEMCPY(argv, cfp->sp - argc, VALUE, argc);
|
|
|
|
cfp->sp -= argc + 1;
|
|
|
|
|
|
|
|
return rb_vm_invoke_proc(th, proc, argc, argv, ci->blockptr);
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static VALUE
|
2012-10-17 03:12:40 -04:00
|
|
|
vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
2012-10-14 15:58:59 -04:00
|
|
|
{
|
2012-10-17 03:12:40 -04:00
|
|
|
VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc);
|
|
|
|
rb_call_info_t ci_entry;
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-17 03:12:40 -04:00
|
|
|
ci_entry.flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
|
|
|
|
ci_entry.argc = ci->argc+1;
|
|
|
|
ci_entry.mid = idMethodMissing;
|
|
|
|
ci_entry.blockptr = ci->blockptr;
|
|
|
|
ci_entry.recv = ci->recv;
|
|
|
|
ci_entry.me = rb_method_entry(CLASS_OF(ci_entry.recv), idMethodMissing, &ci_entry.defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-10-17 03:12:40 -04:00
|
|
|
/* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
|
2012-12-25 04:57:07 -05:00
|
|
|
CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
|
2012-10-17 03:12:40 -04:00
|
|
|
if (ci->argc > 0) {
|
|
|
|
MEMMOVE(argv+1, argv, VALUE, ci->argc);
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
argv[0] = ID2SYM(ci->mid);
|
2012-10-17 03:12:40 -04:00
|
|
|
INC_SP(1);
|
|
|
|
|
|
|
|
th->method_missing_reason = ci->aux.missing_reason;
|
|
|
|
return vm_call_method(th, reg_cfp, &ci_entry);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
2012-12-07 10:49:21 -05:00
|
|
|
static inline VALUE
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
find_refinement(VALUE refinements, VALUE klass)
|
|
|
|
{
|
|
|
|
if (NIL_P(refinements)) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
2012-12-07 10:49:21 -05:00
|
|
|
return rb_hash_lookup(refinements, klass);
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
|
|
|
|
static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
|
|
|
|
|
2013-02-23 23:36:00 -05:00
|
|
|
static rb_control_frame_t *
|
|
|
|
current_method_entry(rb_thread_t *th, rb_control_frame_t *cfp)
|
|
|
|
{
|
|
|
|
rb_control_frame_t *top_cfp = cfp;
|
|
|
|
|
|
|
|
if (cfp->iseq && cfp->iseq->type == ISEQ_TYPE_BLOCK) {
|
|
|
|
rb_iseq_t *local_iseq = cfp->iseq->local_iseq;
|
|
|
|
do {
|
|
|
|
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
|
|
|
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
|
|
|
|
/* TODO: orphan block */
|
|
|
|
return top_cfp;
|
|
|
|
}
|
|
|
|
} while (cfp->iseq != local_iseq);
|
|
|
|
}
|
|
|
|
return cfp;
|
|
|
|
}
|
|
|
|
|
2012-12-14 03:04:55 -05:00
|
|
|
static
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
__forceinline
|
|
|
|
#else
|
|
|
|
inline
|
|
|
|
#endif
|
|
|
|
VALUE
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
|
|
|
|
{
|
2012-10-15 13:40:50 -04:00
|
|
|
int enable_fastpath = 1;
|
2012-11-28 08:56:29 -05:00
|
|
|
rb_call_info_t ci_temp;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
|
|
|
start_method_dispatch:
|
|
|
|
if (ci->me != 0) {
|
|
|
|
if ((ci->me->flag == 0)) {
|
2013-08-29 04:03:23 -04:00
|
|
|
VALUE klass;
|
|
|
|
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
normal_method_dispatch:
|
|
|
|
switch (ci->me->def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:{
|
2012-10-15 13:40:50 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath);
|
2012-10-14 15:58:59 -04:00
|
|
|
return vm_call_iseq_setup(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 00:22:31 -04:00
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
2012-10-15 13:40:50 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath);
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_cfunc(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
case VM_METHOD_TYPE_ATTRSET:{
|
2013-06-18 10:01:32 -04:00
|
|
|
rb_check_arity(ci->argc, 1, 1);
|
2012-10-16 13:07:23 -04:00
|
|
|
ci->aux.index = 0;
|
2012-10-15 17:35:29 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_attrset(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_IVAR:{
|
2012-10-14 16:59:21 -04:00
|
|
|
rb_check_arity(ci->argc, 0, 0);
|
2012-10-16 13:07:23 -04:00
|
|
|
ci->aux.index = 0;
|
2012-10-15 17:35:29 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_ivar(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_MISSING:{
|
2012-10-17 03:12:40 -04:00
|
|
|
ci->aux.missing_reason = 0;
|
|
|
|
CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath);
|
|
|
|
return vm_call_method_missing(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_BMETHOD:{
|
2012-10-15 13:40:50 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath);
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_bmethod(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_ZSUPER:{
|
2013-08-29 04:03:23 -04:00
|
|
|
klass = ci->me->klass;
|
|
|
|
klass = RCLASS_ORIGIN(klass);
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
zsuper_method_dispatch:
|
2013-08-29 04:03:23 -04:00
|
|
|
klass = RCLASS_SUPER(klass);
|
2012-11-28 08:56:29 -05:00
|
|
|
ci_temp = *ci;
|
|
|
|
ci = &ci_temp;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
|
|
|
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
|
|
|
|
|
|
|
|
if (ci->me != 0) {
|
|
|
|
goto normal_method_dispatch;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto start_method_dispatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:{
|
|
|
|
switch (ci->me->def->body.optimize_type) {
|
2012-10-15 17:24:08 -04:00
|
|
|
case OPTIMIZED_METHOD_TYPE_SEND:
|
2012-10-15 13:40:50 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath);
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_opt_send(th, cfp, ci);
|
2012-10-15 17:24:08 -04:00
|
|
|
case OPTIMIZED_METHOD_TYPE_CALL:
|
2012-10-15 13:40:50 -04:00
|
|
|
CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath);
|
2012-10-16 17:49:18 -04:00
|
|
|
return vm_call_opt_call(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
default:
|
2012-10-15 17:24:08 -04:00
|
|
|
rb_bug("vm_call_method: unsupported optimized method type (%d)",
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
ci->me->def->body.optimize_type);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2012-10-23 16:53:35 -04:00
|
|
|
case VM_METHOD_TYPE_UNDEF:
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
break;
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
case VM_METHOD_TYPE_REFINED:{
|
|
|
|
NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep);
|
|
|
|
VALUE refinements = cref ? cref->nd_refinements : Qnil;
|
|
|
|
VALUE refinement, defined_class;
|
|
|
|
rb_method_entry_t *me;
|
|
|
|
|
|
|
|
refinement = find_refinement(refinements,
|
|
|
|
ci->defined_class);
|
|
|
|
if (NIL_P(refinement)) {
|
|
|
|
goto no_refinement_dispatch;
|
|
|
|
}
|
|
|
|
me = rb_method_entry(refinement, ci->mid, &defined_class);
|
|
|
|
if (me) {
|
2013-02-23 23:36:00 -05:00
|
|
|
if (ci->call == vm_call_super_method) {
|
|
|
|
rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
|
|
|
|
if (top_cfp->me &&
|
|
|
|
rb_method_definition_eq(me->def, top_cfp->me->def)) {
|
|
|
|
goto no_refinement_dispatch;
|
|
|
|
}
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
}
|
|
|
|
ci->me = me;
|
|
|
|
ci->defined_class = defined_class;
|
|
|
|
if (me->def->type != VM_METHOD_TYPE_REFINED) {
|
|
|
|
goto normal_method_dispatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
no_refinement_dispatch:
|
|
|
|
if (ci->me->def->body.orig_me) {
|
|
|
|
ci->me = ci->me->def->body.orig_me;
|
2013-10-17 04:44:26 -04:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(ci->me)) {
|
|
|
|
ci->me = 0;
|
|
|
|
goto start_method_dispatch;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto normal_method_dispatch;
|
|
|
|
}
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
}
|
|
|
|
else {
|
2013-08-29 04:03:23 -04:00
|
|
|
klass = ci->me->klass;
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
goto zsuper_method_dispatch;
|
|
|
|
}
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2012-10-23 16:53:35 -04:00
|
|
|
rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
int noex_safe;
|
2012-10-15 13:22:57 -04:00
|
|
|
if (!(ci->flag & VM_CALL_FCALL) && (ci->me->flag & NOEX_MASK) & NOEX_PRIVATE) {
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
int stat = NOEX_PRIVATE;
|
|
|
|
|
2012-10-15 13:22:57 -04:00
|
|
|
if (ci->flag & VM_CALL_VCALL) {
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
stat |= NOEX_VCALL;
|
|
|
|
}
|
2012-10-17 03:12:40 -04:00
|
|
|
ci->aux.missing_reason = stat;
|
|
|
|
CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
|
|
|
|
return vm_call_method_missing(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2012-10-15 13:22:57 -04:00
|
|
|
else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
2012-10-15 13:40:50 -04:00
|
|
|
enable_fastpath = 0;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
if (!rb_obj_is_kind_of(cfp->self, ci->defined_class)) {
|
2012-10-17 03:12:40 -04:00
|
|
|
ci->aux.missing_reason = NOEX_PROTECTED;
|
|
|
|
return vm_call_method_missing(th, cfp, ci);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto normal_method_dispatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((noex_safe = NOEX_SAFE(ci->me->flag)) > th->safe_level && (noex_safe > 2)) {
|
|
|
|
rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(ci->mid));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto normal_method_dispatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* method missing */
|
|
|
|
int stat = 0;
|
2012-10-15 13:22:57 -04:00
|
|
|
if (ci->flag & VM_CALL_VCALL) {
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
stat |= NOEX_VCALL;
|
|
|
|
}
|
2012-10-15 13:22:57 -04:00
|
|
|
if (ci->flag & VM_CALL_SUPER) {
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
stat |= NOEX_SUPER;
|
|
|
|
}
|
|
|
|
if (ci->mid == idMethodMissing) {
|
|
|
|
rb_control_frame_t *reg_cfp = cfp;
|
|
|
|
VALUE *argv = STACK_ADDR_FROM_TOP(ci->argc);
|
|
|
|
rb_raise_method_missing(th, ci->argc, argv, ci->recv, stat);
|
|
|
|
}
|
|
|
|
else {
|
2012-10-17 03:12:40 -04:00
|
|
|
ci->aux.missing_reason = stat;
|
|
|
|
CI_SET_FASTPATH(ci, vm_call_method_missing, 1);
|
|
|
|
return vm_call_method_missing(th, cfp, ci);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 17:49:18 -04:00
|
|
|
rb_bug("vm_call_method: unreachable");
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
return vm_call_method(th, reg_cfp, ci);
|
|
|
|
}
|
|
|
|
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
static VALUE
|
|
|
|
vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
return vm_call_method(th, reg_cfp, ci);
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* super */
|
|
|
|
|
|
|
|
static inline VALUE
|
|
|
|
vm_search_normal_superclass(VALUE klass)
|
|
|
|
{
|
2012-12-07 22:36:58 -05:00
|
|
|
if (BUILTIN_TYPE(klass) == T_ICLASS &&
|
|
|
|
FL_TEST(RBASIC(klass)->klass, RMODULE_IS_REFINEMENT)) {
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
klass = RBASIC(klass)->klass;
|
2012-12-07 22:36:58 -05:00
|
|
|
}
|
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 11:05:45 -05:00
|
|
|
klass = RCLASS_ORIGIN(klass);
|
|
|
|
return RCLASS_SUPER(klass);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_super_outside(void)
|
|
|
|
{
|
|
|
|
rb_raise(rb_eNoMethodError, "super called outside of method");
|
|
|
|
}
|
|
|
|
|
2013-05-05 05:57:02 -04:00
|
|
|
static int
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci)
|
|
|
|
{
|
|
|
|
while (iseq && !iseq->klass) {
|
|
|
|
iseq = iseq->parent_iseq;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iseq == 0) {
|
2013-05-05 05:57:02 -04:00
|
|
|
return -1;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ci->mid = iseq->defined_method_id;
|
|
|
|
|
|
|
|
if (iseq != iseq->local_iseq) {
|
|
|
|
/* defined by Module#define_method() */
|
|
|
|
rb_control_frame_t *lcfp = GET_CFP();
|
|
|
|
|
|
|
|
if (!sigval) {
|
|
|
|
/* zsuper */
|
2013-05-05 05:57:02 -04:00
|
|
|
return -2;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
while (lcfp->iseq != iseq) {
|
|
|
|
rb_thread_t *th = GET_THREAD();
|
|
|
|
VALUE *tep = VM_EP_PREV_EP(lcfp->ep);
|
|
|
|
while (1) {
|
|
|
|
lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp);
|
|
|
|
if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) {
|
2013-05-05 05:57:02 -04:00
|
|
|
return -1;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
if (lcfp->ep == tep) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* temporary measure for [Bug #2420] [Bug #3136] */
|
|
|
|
if (!lcfp->me) {
|
2013-05-05 05:57:02 -04:00
|
|
|
return -1;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ci->mid = lcfp->me->def->original_id;
|
|
|
|
ci->klass = vm_search_normal_superclass(lcfp->klass);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ci->klass = vm_search_normal_superclass(reg_cfp->klass);
|
|
|
|
}
|
2013-05-05 05:57:02 -04:00
|
|
|
|
|
|
|
return 0;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
|
|
|
{
|
2012-12-11 04:31:26 -05:00
|
|
|
VALUE current_defined_class;
|
2012-10-14 15:58:59 -04:00
|
|
|
rb_iseq_t *iseq = GET_ISEQ();
|
2013-09-02 14:21:13 -04:00
|
|
|
VALUE sigval = TOPN(ci->argc);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2012-12-11 04:31:26 -05:00
|
|
|
current_defined_class = GET_CFP()->klass;
|
|
|
|
if (NIL_P(current_defined_class)) {
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_super_outside();
|
|
|
|
}
|
|
|
|
|
2012-12-11 04:31:26 -05:00
|
|
|
if (!NIL_P(RCLASS_REFINED_CLASS(current_defined_class))) {
|
|
|
|
current_defined_class = RCLASS_REFINED_CLASS(current_defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
2012-12-11 04:31:26 -05:00
|
|
|
if (!FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) &&
|
|
|
|
!rb_obj_is_kind_of(ci->recv, current_defined_class)) {
|
2013-01-10 02:51:35 -05:00
|
|
|
VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ?
|
|
|
|
RBASIC(current_defined_class)->klass : current_defined_class;
|
|
|
|
|
|
|
|
rb_raise(rb_eTypeError,
|
|
|
|
"self has wrong type to call super in this context: "
|
|
|
|
"%s (expected %s)",
|
|
|
|
rb_obj_classname(ci->recv), rb_class2name(m));
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
|
2013-05-05 05:57:02 -04:00
|
|
|
switch (vm_search_superclass(GET_CFP(), iseq, sigval, ci)) {
|
|
|
|
case -1:
|
|
|
|
vm_super_outside();
|
|
|
|
case -2:
|
|
|
|
rb_raise(rb_eRuntimeError,
|
|
|
|
"implicit argument passing of super from method defined"
|
|
|
|
" by define_method() is not supported."
|
|
|
|
" Specify all arguments explicitly.");
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
/* TODO: use inline cache */
|
|
|
|
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
ci->call = vm_call_super_method;
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
while (iseq && !iseq->klass) {
|
|
|
|
iseq = iseq->parent_iseq;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) {
|
|
|
|
ci->klass = RCLASS_SUPER(ci->defined_class);
|
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 08:08:41 -05:00
|
|
|
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* yield */
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
block_proc_is_lambda(const VALUE procval)
|
|
|
|
{
|
|
|
|
rb_proc_t *proc;
|
|
|
|
|
|
|
|
if (procval) {
|
|
|
|
GetProcPtr(procval, proc);
|
|
|
|
return proc->is_lambda;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline VALUE
|
|
|
|
vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
|
|
|
VALUE self, int argc, const VALUE *argv,
|
|
|
|
const rb_block_t *blockargptr)
|
|
|
|
{
|
|
|
|
NODE *ifunc = (NODE *) block->iseq;
|
|
|
|
VALUE val, arg, blockarg;
|
|
|
|
int lambda = block_proc_is_lambda(block->proc);
|
|
|
|
|
|
|
|
if (lambda) {
|
|
|
|
arg = rb_ary_new4(argc, argv);
|
|
|
|
}
|
|
|
|
else if (argc == 0) {
|
|
|
|
arg = Qnil;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
arg = argv[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blockargptr) {
|
|
|
|
if (blockargptr->proc) {
|
|
|
|
blockarg = blockargptr->proc;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
blockarg = Qnil;
|
|
|
|
}
|
|
|
|
|
2013-06-17 08:47:26 -04:00
|
|
|
vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self,
|
|
|
|
0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
|
2013-08-06 04:33:05 -04:00
|
|
|
th->cfp->sp, 1, 0, 0);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
|
|
|
|
|
|
|
|
th->cfp++;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*--
|
|
|
|
* @brief on supplied all of optional, rest and post parameters.
|
|
|
|
* @pre iseq is block style (not lambda style)
|
|
|
|
*/
|
|
|
|
static inline int
|
|
|
|
vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq,
|
|
|
|
int argc, VALUE *argv)
|
|
|
|
{
|
|
|
|
rb_num_t opt_pc = 0;
|
|
|
|
int i;
|
|
|
|
const int m = iseq->argc;
|
|
|
|
const int r = iseq->arg_rest;
|
|
|
|
int len = iseq->arg_post_len;
|
|
|
|
int start = iseq->arg_post_start;
|
|
|
|
int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */
|
|
|
|
int psize = rsize > len ? len : rsize; /* # of post arguments */
|
|
|
|
int osize = 0; /* # of opt arguments */
|
|
|
|
VALUE ary;
|
|
|
|
|
|
|
|
/* reserves arguments for post parameters */
|
|
|
|
rsize -= psize;
|
|
|
|
|
|
|
|
if (iseq->arg_opts) {
|
|
|
|
const int opts = iseq->arg_opts - 1;
|
|
|
|
if (rsize > opts) {
|
|
|
|
osize = opts;
|
|
|
|
opt_pc = iseq->arg_opt_table[opts];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
osize = rsize;
|
|
|
|
opt_pc = iseq->arg_opt_table[rsize];
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
rsize -= osize;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (0) {
|
|
|
|
printf(" argc: %d\n", argc);
|
|
|
|
printf(" len: %d\n", len);
|
|
|
|
printf("start: %d\n", start);
|
|
|
|
printf("rsize: %d\n", rsize);
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (r == -1) {
|
|
|
|
/* copy post argument */
|
|
|
|
MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ary = rb_ary_new4(rsize, &argv[r]);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* copy post argument */
|
|
|
|
MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize);
|
|
|
|
argv[r] = ary;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
for (i=psize; i<len; i++) {
|
|
|
|
argv[start + i] = Qnil;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
return (int)opt_pc;
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
static inline int
|
|
|
|
vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq,
|
|
|
|
int orig_argc, VALUE *argv,
|
|
|
|
const rb_block_t *blockptr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int argc = orig_argc;
|
|
|
|
const int m = iseq->argc;
|
|
|
|
VALUE ary, arg0;
|
2013-01-06 22:09:28 -05:00
|
|
|
VALUE keyword_hash = Qnil;
|
2012-10-14 15:58:59 -04:00
|
|
|
int opt_pc = 0;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
th->mark_stack_len = argc;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/*
|
|
|
|
* yield [1, 2]
|
|
|
|
* => {|a|} => a = [1, 2]
|
|
|
|
* => {|a, b|} => a, b = [1, 2]
|
|
|
|
*/
|
|
|
|
arg0 = argv[0];
|
2012-10-27 19:22:10 -04:00
|
|
|
if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */
|
2013-06-01 04:21:37 -04:00
|
|
|
((m + iseq->arg_post_len) > 0 || /* positional arguments exist */
|
|
|
|
iseq->arg_opts > 2 || /* multiple optional arguments exist */
|
2013-06-01 04:21:39 -04:00
|
|
|
iseq->arg_keyword != -1 || /* any keyword arguments */
|
2013-06-01 04:21:37 -04:00
|
|
|
0) &&
|
2012-10-27 19:22:10 -04:00
|
|
|
argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */
|
|
|
|
th->mark_stack_len = argc = RARRAY_LENINT(ary);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-12-25 04:57:07 -05:00
|
|
|
CHECK_VM_STACK_OVERFLOW(th->cfp, argc);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
* include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
usecase of this macro is not acquire raw pointer, but acquire
read-only pointer. So we rename to better name.
RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
(I expect that nobody use it).
* array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
catch up this change.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-25 04:24:34 -04:00
|
|
|
MEMCPY(argv, RARRAY_CONST_PTR(ary), VALUE, argc);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2013-06-02 14:44:33 -04:00
|
|
|
else {
|
2013-06-03 23:47:02 -04:00
|
|
|
/* vm_push_frame current argv is at the top of sp because vm_invoke_block
|
|
|
|
* set sp at the first element of argv.
|
|
|
|
* Therefore when rb_check_array_type(arg0) called to_ary and called to_ary
|
|
|
|
* or method_missing run vm_push_frame, it initializes local variables.
|
|
|
|
* see also https://bugs.ruby-lang.org/issues/8484
|
|
|
|
*/
|
|
|
|
argv[0] = arg0;
|
2013-06-02 14:44:33 -04:00
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2013-06-01 04:21:39 -04:00
|
|
|
/* keyword argument */
|
|
|
|
if (iseq->arg_keyword != -1) {
|
|
|
|
argc = vm_callee_setup_keyword_arg(iseq, argc, m, argv, &keyword_hash);
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
for (i=argc; i<m; i++) {
|
2012-10-27 19:22:10 -04:00
|
|
|
argv[i] = Qnil;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
|
2012-10-27 19:22:10 -04:00
|
|
|
const int arg_size = iseq->arg_size;
|
|
|
|
if (arg_size < argc) {
|
|
|
|
/*
|
|
|
|
* yield 1, 2
|
|
|
|
* => {|a|} # truncate
|
|
|
|
*/
|
|
|
|
th->mark_stack_len = argc = arg_size;
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
else {
|
2012-10-27 19:22:10 -04:00
|
|
|
int r = iseq->arg_rest;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-27 19:22:10 -04:00
|
|
|
if (iseq->arg_post_len ||
|
|
|
|
iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
|
2012-10-14 15:58:59 -04:00
|
|
|
opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv);
|
2012-10-27 19:22:10 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (argc < r) {
|
|
|
|
/* yield 1
|
|
|
|
* => {|a, b, *r|}
|
|
|
|
*/
|
|
|
|
for (i=argc; i<r; i++) {
|
|
|
|
argv[i] = Qnil;
|
|
|
|
}
|
|
|
|
argv[r] = rb_ary_new();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
argv[r] = rb_ary_new4(argc-r, &argv[r]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
th->mark_stack_len = iseq->arg_size;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2013-01-06 22:09:28 -05:00
|
|
|
/* keyword argument */
|
|
|
|
if (iseq->arg_keyword != -1) {
|
2013-09-29 05:50:24 -04:00
|
|
|
int arg_keywords_end = iseq->arg_keyword - (iseq->arg_block != -1);
|
|
|
|
for (i = iseq->arg_keywords; 0 < i; i--) {
|
|
|
|
argv[arg_keywords_end - i] = Qnil;
|
|
|
|
}
|
2013-01-06 22:09:28 -05:00
|
|
|
argv[iseq->arg_keyword] = keyword_hash;
|
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
/* {|&b|} */
|
|
|
|
if (iseq->arg_block != -1) {
|
2012-10-27 19:22:10 -04:00
|
|
|
VALUE procval = Qnil;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-27 19:22:10 -04:00
|
|
|
if (blockptr) {
|
2012-10-14 15:58:59 -04:00
|
|
|
if (blockptr->proc == 0) {
|
|
|
|
procval = rb_vm_make_proc(th, blockptr, rb_cProc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
procval = blockptr->proc;
|
|
|
|
}
|
2012-10-27 19:22:10 -04:00
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
|
2012-10-27 19:22:10 -04:00
|
|
|
argv[iseq->arg_block] = procval;
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
|
2012-10-14 15:58:59 -04:00
|
|
|
th->mark_stack_len = 0;
|
|
|
|
return opt_pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
|
|
|
|
int argc, VALUE *argv, const rb_block_t *blockptr, int lambda)
|
|
|
|
{
|
|
|
|
if (0) { /* for debug */
|
|
|
|
printf(" argc: %d\n", argc);
|
|
|
|
printf("iseq argc: %d\n", iseq->argc);
|
|
|
|
printf("iseq opts: %d\n", iseq->arg_opts);
|
|
|
|
printf("iseq rest: %d\n", iseq->arg_rest);
|
|
|
|
printf("iseq post: %d\n", iseq->arg_post_len);
|
|
|
|
printf("iseq blck: %d\n", iseq->arg_block);
|
|
|
|
printf("iseq smpl: %d\n", iseq->arg_simple);
|
|
|
|
printf(" lambda: %s\n", lambda ? "true" : "false");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lambda) {
|
|
|
|
/* call as method */
|
|
|
|
rb_call_info_t ci_entry;
|
|
|
|
ci_entry.flag = 0;
|
|
|
|
ci_entry.argc = argc;
|
|
|
|
ci_entry.blockptr = (rb_block_t *)blockptr;
|
2012-10-14 20:44:04 -04:00
|
|
|
VM_CALLEE_SETUP_ARG(th, &ci_entry, iseq, argv, 1);
|
2012-10-16 13:07:23 -04:00
|
|
|
return ci_entry.aux.opt_pc;
|
2012-10-14 15:58:59 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr);
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2012-10-14 15:58:59 -04:00
|
|
|
vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
{
|
2012-10-14 15:58:59 -04:00
|
|
|
const rb_block_t *block = VM_CF_BLOCK_PTR(reg_cfp);
|
|
|
|
rb_iseq_t *iseq;
|
|
|
|
VALUE type = GET_ISEQ()->local_iseq->type;
|
|
|
|
|
|
|
|
if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) {
|
|
|
|
rb_vm_localjump_error("no block given (yield)", Qnil, 0);
|
|
|
|
}
|
|
|
|
iseq = block->iseq;
|
|
|
|
|
2012-10-16 16:30:17 -04:00
|
|
|
if (UNLIKELY(ci->flag & VM_CALL_ARGS_SPLAT)) {
|
|
|
|
vm_caller_setup_args(th, GET_CFP(), ci);
|
|
|
|
}
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
if (BUILTIN_TYPE(iseq) != T_NODE) {
|
|
|
|
int opt_pc;
|
|
|
|
const int arg_size = iseq->arg_size;
|
2013-08-08 21:49:38 -04:00
|
|
|
int is_lambda = block_proc_is_lambda(block->proc);
|
2012-10-14 15:58:59 -04:00
|
|
|
VALUE * const rsp = GET_SP() - ci->argc;
|
|
|
|
SET_SP(rsp);
|
|
|
|
|
2013-08-08 21:49:38 -04:00
|
|
|
opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, is_lambda);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
2013-08-08 21:49:38 -04:00
|
|
|
vm_push_frame(th, iseq,
|
|
|
|
is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK,
|
|
|
|
block->self,
|
2012-10-14 15:58:59 -04:00
|
|
|
block->klass,
|
|
|
|
VM_ENVVAL_PREV_EP_PTR(block->ep),
|
|
|
|
iseq->iseq_encoded + opt_pc,
|
|
|
|
rsp + arg_size,
|
2013-08-06 04:33:05 -04:00
|
|
|
iseq->local_size - arg_size, 0, iseq->stack_max);
|
2012-10-14 15:58:59 -04:00
|
|
|
|
|
|
|
return Qundef;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE val = vm_yield_with_cfunc(th, block, block->self, ci->argc, STACK_ADDR_FROM_TOP(ci->argc), 0);
|
|
|
|
POPN(ci->argc); /* TODO: should put before C/yield? */
|
|
|
|
return val;
|
|
|
|
}
|
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 12:59:05 -04:00
|
|
|
}
|
2013-08-20 13:41:13 -04:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_make_proc_with_iseq(rb_iseq_t *blockiseq)
|
|
|
|
{
|
|
|
|
rb_block_t *blockptr;
|
|
|
|
rb_thread_t *th = GET_THREAD();
|
|
|
|
rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
|
|
|
|
|
|
|
|
if (cfp == 0) {
|
2013-09-22 07:57:50 -04:00
|
|
|
rb_bug("vm_make_proc_with_iseq: unreachable");
|
2013-08-20 13:41:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
|
|
|
|
blockptr->iseq = blockiseq;
|
|
|
|
blockptr->proc = 0;
|
|
|
|
|
|
|
|
return rb_vm_make_proc(th, blockptr, rb_cProc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_once_exec(rb_iseq_t *iseq)
|
|
|
|
{
|
|
|
|
VALUE proc = vm_make_proc_with_iseq(iseq);
|
|
|
|
return rb_proc_call_with_block(proc, 0, 0, Qnil);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
vm_once_clear(VALUE data)
|
|
|
|
{
|
|
|
|
union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)data;
|
|
|
|
is->once.running_thread = NULL;
|
|
|
|
return Qnil;
|
|
|
|
}
|