2006-12-31 18:02:22 +03:00
|
|
|
/*
|
* method.h, internal.h iseq.h: declare internal functions.
* compile.c, eval.c, iseq.c, object.c, parse.y, proc.c, process.c,
thread.c, vm.c, vm_eval.c, vm_insnhelper.c, vm_method.c: don't
declare internal functions.
Note that rb_method_entry_eq() is defined in vm_method.c but
there was a declaration in proc.c with different const-ness.
Now it is declared in method.h with same const-ness to the
definition.
* object.c (rb_mod_module_exec): don't declare functions declared in
include/ruby/intern.h.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32163 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2011-06-18 07:49:33 +04:00
|
|
|
* This file is included by vm.c
|
2006-12-31 18:02:22 +03:00
|
|
|
*/
|
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
#include "id_table.h"
|
|
|
|
|
2015-06-02 07:20:30 +03:00
|
|
|
#define METHOD_DEBUG 0
|
|
|
|
|
2015-12-18 05:32:17 +03:00
|
|
|
static int vm_redefinition_check_flag(VALUE klass);
|
2011-08-25 02:02:03 +04:00
|
|
|
static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2013-05-02 11:54:17 +04:00
|
|
|
#define object_id idObject_id
|
|
|
|
#define added idMethod_added
|
|
|
|
#define singleton_added idSingleton_method_added
|
|
|
|
#define removed idMethod_removed
|
|
|
|
#define singleton_removed idSingleton_method_removed
|
|
|
|
#define undefined idMethod_undefined
|
|
|
|
#define singleton_undefined idSingleton_method_undefined
|
|
|
|
#define attached id__attached__
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
|
|
|
#define ruby_running (GET_VM()->running)
|
|
|
|
/* int ruby_running = 0; */
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
vm_ccs_dump_i(ID mid, VALUE val, void *data)
|
2011-06-13 15:25:44 +04:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
const struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)val;
|
|
|
|
fprintf(stderr, " | %s (%d) ", rb_id2name(mid), ccs->len);
|
|
|
|
rp(ccs->cme);
|
|
|
|
|
|
|
|
for (int i=0; i<ccs->len; i++) {
|
|
|
|
fprintf(stderr, " | [%d] ", i); vm_ci_dump(ccs->entries[i].ci);
|
|
|
|
rp_m( " | ", ccs->entries[i].cc);
|
2019-12-12 00:10:39 +03:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
2015-11-18 16:59:57 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static void
|
|
|
|
vm_ccs_dump(VALUE klass, ID target_mid)
|
|
|
|
{
|
|
|
|
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
|
|
|
|
if (cc_tbl) {
|
|
|
|
const struct rb_class_cc_entries *ccs;
|
|
|
|
if (target_mid) {
|
|
|
|
if (rb_id_table_lookup(cc_tbl, target_mid, (VALUE *)&ccs)) {
|
2020-02-26 05:45:29 +03:00
|
|
|
fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
|
2020-01-08 10:14:01 +03:00
|
|
|
vm_ccs_dump_i(target_mid, (VALUE)ccs, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-02-26 05:45:29 +03:00
|
|
|
fprintf(stderr, " [CCTB] %p\n", (void *)cc_tbl);
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_id_table_foreach(cc_tbl, vm_ccs_dump_i, (void *)target_mid);
|
|
|
|
}
|
2015-11-18 16:59:57 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static enum rb_id_table_iterator_result
|
|
|
|
vm_cme_dump_i(ID mid, VALUE val, void *data)
|
|
|
|
{
|
|
|
|
ID target_mid = (ID)data;
|
|
|
|
if (target_mid == 0 || mid == target_mid) {
|
|
|
|
rp_m(" > ", val);
|
2015-11-18 16:59:57 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
return ID_TABLE_CONTINUE;
|
|
|
|
}
|
2015-11-18 16:59:57 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static VALUE
|
|
|
|
vm_mtbl_dump(VALUE klass, ID target_mid)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "# vm_mtbl\n");
|
|
|
|
while (klass) {
|
|
|
|
rp_m(" -> ", klass);
|
|
|
|
rb_method_entry_t *me;
|
|
|
|
|
|
|
|
if (RCLASS_M_TBL(klass)) {
|
|
|
|
if (target_mid != 0) {
|
|
|
|
if (rb_id_table_lookup(RCLASS_M_TBL(klass), target_mid, (VALUE *)&me)) {
|
|
|
|
rp_m(" [MTBL] ", me);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-02-26 05:45:29 +03:00
|
|
|
fprintf(stderr, " ## RCLASS_M_TBL (%p)\n", (void *)RCLASS_M_TBL(klass));
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_id_table_foreach(RCLASS_M_TBL(klass), vm_cme_dump_i, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr, " MTBL: NULL\n");
|
|
|
|
}
|
|
|
|
if (RCLASS_CALLABLE_M_TBL(klass)) {
|
|
|
|
if (target_mid != 0) {
|
|
|
|
if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, (VALUE *)&me)) {
|
|
|
|
rp_m(" [CM**] ", me);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr, " ## RCLASS_CALLABLE_M_TBL\n");
|
|
|
|
rb_id_table_foreach(RCLASS_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (RCLASS_CC_TBL(klass)) {
|
|
|
|
vm_ccs_dump(klass, target_mid);
|
|
|
|
}
|
|
|
|
klass = RCLASS_SUPER(klass);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_vm_mtbl_dump(const char *msg, VALUE klass, ID target_mid)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "[%s] ", msg);
|
|
|
|
vm_mtbl_dump(klass, target_mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
vm_me_invalidate_cache(rb_callable_method_entry_t *cme)
|
|
|
|
{
|
|
|
|
VM_ASSERT(IMEMO_TYPE_P(cme, imemo_ment));
|
|
|
|
VM_ASSERT(callable_method_entry_p(cme));
|
|
|
|
METHOD_ENTRY_INVALIDATED_SET(cme);
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_cme_invalidate);
|
2011-06-13 15:25:44 +04:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
* 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-29 04:52:38 +04:00
|
|
|
rb_clear_constant_cache(void)
|
|
|
|
{
|
2013-12-09 14:51:02 +04:00
|
|
|
INC_GLOBAL_CONSTANT_STATE();
|
* 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-29 04:52:38 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static rb_method_entry_t *rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def);
|
|
|
|
const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me);
|
2020-07-19 17:13:21 +03:00
|
|
|
static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id);
|
2020-01-08 10:14:01 +03:00
|
|
|
|
|
|
|
static void
|
|
|
|
clear_method_cache_by_id_in_class(VALUE klass, ID mid)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
|
2020-08-02 06:05:19 +03:00
|
|
|
if (!(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS))) rb_bug("type confusion"); // temporary. Remove before release
|
2013-12-10 02:50:44 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (LIKELY(RCLASS_EXT(klass)->subclasses == NULL)) {
|
|
|
|
// no subclasses
|
|
|
|
// check only current class
|
2013-12-10 02:50:44 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
|
|
|
|
struct rb_class_cc_entries *ccs;
|
|
|
|
|
|
|
|
// invalidate CCs
|
|
|
|
if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
|
|
|
|
rb_vm_ccs_free(ccs);
|
|
|
|
rb_id_table_delete(cc_tbl, mid);
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove from callable_m_tbl, if exists
|
|
|
|
struct rb_id_table *cm_tbl;
|
|
|
|
if ((cm_tbl = RCLASS_CALLABLE_M_TBL(klass)) != NULL) {
|
|
|
|
rb_id_table_delete(cm_tbl, mid);
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
|
|
|
|
}
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
|
2015-11-18 16:59:57 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
else {
|
2020-07-19 17:13:21 +03:00
|
|
|
const rb_callable_method_entry_t *cme = complemented_callable_method_entry(klass, mid);
|
2020-01-08 10:14:01 +03:00
|
|
|
|
|
|
|
if (cme) {
|
|
|
|
// invalidate cme if found to invalidate the inline method cache.
|
|
|
|
|
|
|
|
if (METHOD_ENTRY_CACHED(cme)) {
|
2020-03-10 20:45:49 +03:00
|
|
|
if (METHOD_ENTRY_COMPLEMENTED(cme)) {
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// invalidate cc by invalidating cc->cme
|
|
|
|
VALUE owner = cme->owner;
|
|
|
|
VM_ASSERT(BUILTIN_TYPE(owner) == T_CLASS);
|
2020-08-11 01:19:17 +03:00
|
|
|
const rb_method_entry_t *new_cme = rb_method_entry_clone((const rb_method_entry_t *)cme);
|
|
|
|
VALUE origin = RCLASS_ORIGIN(owner);
|
|
|
|
rb_method_table_insert(origin, RCLASS_M_TBL(origin), mid, new_cme);
|
2020-03-10 20:45:49 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
vm_me_invalidate_cache((rb_callable_method_entry_t *)cme);
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_cme);
|
|
|
|
}
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
// invalidate complement tbl
|
|
|
|
if (METHOD_ENTRY_COMPLEMENTED(cme)) {
|
|
|
|
VALUE defined_class = cme->defined_class;
|
|
|
|
struct rb_id_table *cm_tbl = RCLASS_CALLABLE_M_TBL(defined_class);
|
|
|
|
VM_ASSERT(cm_tbl != NULL);
|
|
|
|
int r = rb_id_table_delete(cm_tbl, mid);
|
|
|
|
VM_ASSERT(r == TRUE); (void)r;
|
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
|
|
|
|
}
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(cc_invalidate_tree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_iclass_method_cache_by_id(VALUE iclass, VALUE d)
|
|
|
|
{
|
|
|
|
VM_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
|
|
|
|
ID mid = (ID)d;
|
|
|
|
clear_method_cache_by_id_in_class(iclass, mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_iclass_method_cache_by_id_for_refinements(VALUE klass, VALUE d)
|
|
|
|
{
|
|
|
|
if (RB_TYPE_P(klass, T_ICLASS)) {
|
|
|
|
ID mid = (ID)d;
|
|
|
|
clear_method_cache_by_id_in_class(klass, mid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_clear_method_cache(VALUE klass_or_module, ID mid)
|
|
|
|
{
|
|
|
|
if (RB_TYPE_P(klass_or_module, T_MODULE)) {
|
|
|
|
VALUE module = klass_or_module; // alias
|
|
|
|
|
|
|
|
if (FL_TEST(module, RMODULE_IS_REFINEMENT)) {
|
|
|
|
VALUE refined_class = rb_refinement_module_get_refined_class(module);
|
|
|
|
rb_clear_method_cache(refined_class, mid);
|
|
|
|
rb_class_foreach_subclass(refined_class, clear_iclass_method_cache_by_id_for_refinements, mid);
|
|
|
|
}
|
|
|
|
rb_class_foreach_subclass(module, clear_iclass_method_cache_by_id, mid);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
clear_method_cache_by_id_in_class(klass_or_module, mid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// gc.c
|
|
|
|
void rb_cc_table_free(VALUE klass);
|
|
|
|
|
|
|
|
static int
|
|
|
|
invalidate_all_cc(void *vstart, void *vend, size_t stride, void *data)
|
|
|
|
{
|
|
|
|
VALUE v = (VALUE)vstart;
|
|
|
|
for (; v != (VALUE)vend; v += stride) {
|
|
|
|
if (RBASIC(v)->flags) { // liveness check
|
|
|
|
if (RB_TYPE_P(v, T_CLASS) ||
|
|
|
|
RB_TYPE_P(v, T_ICLASS)) {
|
|
|
|
if (RCLASS_CC_TBL(v)) {
|
|
|
|
rb_cc_table_free(v);
|
|
|
|
}
|
|
|
|
RCLASS_CC_TBL(v) = NULL;
|
|
|
|
}
|
|
|
|
}
|
* 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 09:25:06 +04:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
return 0; // continue to iteration
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_clear_method_cache_all(void)
|
|
|
|
{
|
|
|
|
rb_objspace_each_objects(invalidate_all_cc, NULL);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2020-08-11 01:19:17 +03:00
|
|
|
void
|
|
|
|
rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me)
|
|
|
|
{
|
|
|
|
VALUE table_owner = klass;
|
|
|
|
if (RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass)) {
|
|
|
|
table_owner = RBASIC(table_owner)->klass;
|
|
|
|
}
|
|
|
|
VM_ASSERT(RB_TYPE_P(table_owner, T_CLASS) || RB_TYPE_P(table_owner, T_ICLASS) || RB_TYPE_P(table_owner, T_MODULE));
|
|
|
|
VM_ASSERT(table == RCLASS_M_TBL(table_owner));
|
|
|
|
rb_id_table_insert(table, method_id, (VALUE)me);
|
|
|
|
RB_OBJ_WRITTEN(table_owner, Qundef, (VALUE)me);
|
|
|
|
}
|
|
|
|
|
2009-08-27 13:31:11 +04:00
|
|
|
VALUE
|
drop-in type check for rb_define_method
The rb_define_method function takes a pointer to ANYARGS-ed functions,
which in fact varies 18 different prototypes. We still need to
preserve ANYARGS for storages but why not check the consistencies if
possible.
Q&As:
Q: Where did the magic number "18" came from in the description above?
A: Count the case branch of vm_method.c:call_cfunc_invoker_func().
Note also that the 18 branches has lasted for at least 25 years.
See also 200e0ee2fd3c1c006c528874a88f684447215524.
Q: What is this __weakref__ thing?
A: That is a kind of function overloading mechanism that GCC provides.
In this case for instance rb_define_method0 is an alias of
rb_define_method, with a strong type.
Q: What is this __transparent_union__ thing?
A: That is another kind of function overloading mechanism that GCC
provides. In this case the attributed function pointer is either
VALUE(*)(int,VALUE*,VALUE) or VALUE(*)(int,const VALUE*,VALUE).
This is better than void* or ANYARGS because we can reject all
other possibilities than the two.
Q: What does this rb_define_method macro mean?
A: It selects appropriate alias of the rb_define_method function,
depending on the arity.
Q: Why the prototype change of rb_f_notimplement?
A: Function pointer to rb_f_notimplement is special cased in
vm_method.c:rb_add_method_cfunc(). That should be handled by the
__builtin_choose_expr chain inside of rb_define_method macro
expansion. In order to do so, comparison like (func ==
rb_f_notimplement) is inappropriate for __builtin_choose_expr's
expression (which must be a compile-time integer constant but the
address of rb_f_notimplement is not fixed until the linker). So
instead we are using __builtin_types_compatible_p, and in doing so
we need to distinguish rb_f_notimplement from others, by type.
2019-08-28 11:11:23 +03:00
|
|
|
rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
|
2009-07-15 18:59:41 +04:00
|
|
|
{
|
|
|
|
rb_notimplement();
|
2012-04-14 03:45:37 +04:00
|
|
|
|
2018-07-24 08:38:07 +03:00
|
|
|
UNREACHABLE_RETURN(Qnil);
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
|
2009-08-27 13:31:11 +04:00
|
|
|
static void
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_visibility_t visi)
|
2009-07-15 18:59:41 +04:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, (void *)1, visi);
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2012-10-18 11:44:09 +04:00
|
|
|
if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc);
|
2009-07-15 18:59:41 +04:00
|
|
|
if (func != rb_f_notimplement) {
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_cfunc_t opt;
|
|
|
|
opt.func = func;
|
|
|
|
opt.argc = argc;
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, visi);
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_define_notimplement_method_id(klass, mid, visi);
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static void
|
|
|
|
rb_method_definition_release(rb_method_definition_t *def, int complemented)
|
2011-07-25 18:29:28 +04:00
|
|
|
{
|
2015-06-02 07:20:30 +03:00
|
|
|
if (def != NULL) {
|
2015-11-18 11:15:51 +03:00
|
|
|
const int alias_count = def->alias_count;
|
|
|
|
const int complemented_count = def->complemented_count;
|
|
|
|
VM_ASSERT(alias_count >= 0);
|
|
|
|
VM_ASSERT(complemented_count >= 0);
|
2015-06-06 13:19:48 +03:00
|
|
|
|
2015-11-18 11:15:51 +03:00
|
|
|
if (alias_count + complemented_count == 0) {
|
2018-11-26 21:16:54 +03:00
|
|
|
if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:%d,%d (remove)\n", (void *)def,
|
2018-11-26 21:16:39 +03:00
|
|
|
rb_id2name(def->original_id), alias_count, complemented_count);
|
|
|
|
VM_ASSERT(def->type == VM_METHOD_TYPE_BMETHOD ? def->body.bmethod.hooks == NULL : TRUE);
|
2015-06-06 13:19:48 +03:00
|
|
|
xfree(def);
|
2010-05-05 21:51:21 +04:00
|
|
|
}
|
|
|
|
else {
|
2020-01-08 10:14:01 +03:00
|
|
|
if (complemented) {
|
|
|
|
VM_ASSERT(def->complemented_count > 0);
|
|
|
|
def->complemented_count--;
|
|
|
|
}
|
|
|
|
else if (def->alias_count > 0) {
|
|
|
|
def->alias_count--;
|
|
|
|
}
|
2015-11-18 11:15:51 +03:00
|
|
|
|
2018-01-02 09:41:40 +03:00
|
|
|
if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:%d->%d,%d->%d (dec)\n", (void *)def, rb_id2name(def->original_id),
|
2015-11-18 11:15:51 +03:00
|
|
|
alias_count, def->alias_count, complemented_count, def->complemented_count);
|
2010-05-05 00:25:09 +04:00
|
|
|
}
|
2009-08-28 06:45:41 +04:00
|
|
|
}
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
void
|
|
|
|
rb_free_method_entry(const rb_method_entry_t *me)
|
|
|
|
{
|
|
|
|
rb_method_definition_release(me->def, METHOD_ENTRY_COMPLEMENTED(me));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
|
2009-09-29 08:37:52 +04:00
|
|
|
|
2015-06-02 07:20:30 +03:00
|
|
|
static VALUE
|
2019-02-22 10:25:51 +03:00
|
|
|
(*call_cfunc_invoker_func(int argc))(VALUE recv, int argc, const VALUE *, VALUE (*func)(ANYARGS))
|
2015-06-02 07:20:30 +03:00
|
|
|
{
|
|
|
|
switch (argc) {
|
|
|
|
case -2: return &call_cfunc_m2;
|
|
|
|
case -1: return &call_cfunc_m1;
|
|
|
|
case 0: return &call_cfunc_0;
|
|
|
|
case 1: return &call_cfunc_1;
|
|
|
|
case 2: return &call_cfunc_2;
|
|
|
|
case 3: return &call_cfunc_3;
|
|
|
|
case 4: return &call_cfunc_4;
|
|
|
|
case 5: return &call_cfunc_5;
|
|
|
|
case 6: return &call_cfunc_6;
|
|
|
|
case 7: return &call_cfunc_7;
|
|
|
|
case 8: return &call_cfunc_8;
|
|
|
|
case 9: return &call_cfunc_9;
|
|
|
|
case 10: return &call_cfunc_10;
|
|
|
|
case 11: return &call_cfunc_11;
|
|
|
|
case 12: return &call_cfunc_12;
|
|
|
|
case 13: return &call_cfunc_13;
|
|
|
|
case 14: return &call_cfunc_14;
|
|
|
|
case 15: return &call_cfunc_15;
|
|
|
|
default:
|
|
|
|
rb_bug("call_cfunc_func: unsupported length: %d", argc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static void
|
|
|
|
setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
|
|
|
|
{
|
|
|
|
cfunc->func = func;
|
|
|
|
cfunc->argc = argc;
|
|
|
|
cfunc->invoker = call_cfunc_invoker_func(argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
MJIT_FUNC_EXPORTED void
|
|
|
|
rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
|
|
|
|
{
|
|
|
|
*(rb_method_definition_t **)&me->def = def;
|
|
|
|
|
|
|
|
if (opts != NULL) {
|
|
|
|
switch (def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
|
|
|
{
|
|
|
|
rb_method_iseq_t *iseq_body = (rb_method_iseq_t *)opts;
|
|
|
|
rb_cref_t *method_cref, *cref = iseq_body->cref;
|
|
|
|
|
|
|
|
/* setup iseq first (before invoking GC) */
|
|
|
|
RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, iseq_body->iseqptr);
|
|
|
|
|
|
|
|
if (0) vm_cref_dump("rb_method_definition_create", cref);
|
|
|
|
|
|
|
|
if (cref) {
|
|
|
|
method_cref = cref;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
method_cref = vm_cref_new_toplevel(GET_EC()); /* TODO: can we reuse? */
|
|
|
|
}
|
|
|
|
|
|
|
|
RB_OBJ_WRITE(me, &def->body.iseq.cref, method_cref);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
{
|
|
|
|
rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
|
|
|
|
setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), cfunc->func, cfunc->argc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_ATTRSET:
|
|
|
|
case VM_METHOD_TYPE_IVAR:
|
|
|
|
{
|
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
|
|
|
rb_control_frame_t *cfp;
|
|
|
|
int line;
|
|
|
|
|
|
|
|
def->body.attr.id = (ID)(VALUE)opts;
|
|
|
|
|
|
|
|
cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
|
|
|
|
|
|
|
if (cfp && (line = rb_vm_get_sourceline(cfp))) {
|
|
|
|
VALUE location = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line));
|
|
|
|
RB_OBJ_WRITE(me, &def->body.attr.location, rb_ary_freeze(location));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VM_ASSERT(def->body.attr.location == 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_BMETHOD:
|
|
|
|
RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts);
|
|
|
|
return;
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
|
|
|
setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), rb_f_notimplement, -1);
|
|
|
|
return;
|
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:
|
2020-02-18 06:39:30 +03:00
|
|
|
def->body.optimize_type = (enum method_optimized_type)(intptr_t)opts;
|
2019-10-03 06:26:41 +03:00
|
|
|
return;
|
|
|
|
case VM_METHOD_TYPE_REFINED:
|
|
|
|
{
|
|
|
|
const rb_method_refined_t *refined = (rb_method_refined_t *)opts;
|
|
|
|
RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me);
|
|
|
|
RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case VM_METHOD_TYPE_ALIAS:
|
|
|
|
RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts);
|
|
|
|
return;
|
|
|
|
case VM_METHOD_TYPE_ZSUPER:
|
|
|
|
case VM_METHOD_TYPE_UNDEF:
|
|
|
|
case VM_METHOD_TYPE_MISSING:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-02 07:20:30 +03:00
|
|
|
static void
|
2015-06-25 11:37:27 +03:00
|
|
|
method_definition_reset(const rb_method_entry_t *me)
|
2015-06-02 07:20:30 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_definition_t *def = me->def;
|
2015-06-25 10:59:23 +03:00
|
|
|
|
2015-06-02 07:20:30 +03:00
|
|
|
switch(def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
2015-07-22 01:52:59 +03:00
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.iseq.iseqptr);
|
2015-06-02 07:20:30 +03:00
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.iseq.cref);
|
|
|
|
break;
|
2015-06-25 00:44:58 +03:00
|
|
|
case VM_METHOD_TYPE_ATTRSET:
|
2015-06-02 07:20:30 +03:00
|
|
|
case VM_METHOD_TYPE_IVAR:
|
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.attr.location);
|
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_BMETHOD:
|
2018-11-26 21:16:54 +03:00
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc);
|
2018-11-26 21:16:39 +03:00
|
|
|
/* give up to check all in a list */
|
|
|
|
if (def->body.bmethod.hooks) rb_gc_writebarrier_remember((VALUE)me);
|
2015-06-02 07:20:30 +03:00
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_REFINED:
|
2015-06-04 01:27:51 +03:00
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.orig_me);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.refined.owner);
|
2015-06-02 07:20:30 +03:00
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_ALIAS:
|
|
|
|
RB_OBJ_WRITTEN(me, Qundef, def->body.alias.original_me);
|
|
|
|
break;
|
2015-06-25 00:44:58 +03:00
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
case VM_METHOD_TYPE_ZSUPER:
|
|
|
|
case VM_METHOD_TYPE_MISSING:
|
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:
|
|
|
|
case VM_METHOD_TYPE_UNDEF:
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
|
|
|
break;
|
2015-06-02 07:20:30 +03:00
|
|
|
}
|
2015-06-25 10:59:23 +03:00
|
|
|
}
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
MJIT_FUNC_EXPORTED rb_method_definition_t *
|
|
|
|
rb_method_definition_create(rb_method_type_t type, ID mid)
|
2019-09-20 11:01:53 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_definition_t *def;
|
|
|
|
def = ZALLOC(rb_method_definition_t);
|
|
|
|
def->type = type;
|
|
|
|
def->original_id = mid;
|
2019-12-17 09:49:41 +03:00
|
|
|
static uintptr_t method_serial = 1;
|
|
|
|
def->method_serial = method_serial++;
|
2019-10-03 06:26:41 +03:00
|
|
|
return def;
|
2015-06-02 07:20:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static rb_method_definition_t *
|
2015-06-25 10:59:23 +03:00
|
|
|
method_definition_addref(rb_method_definition_t *def)
|
2015-06-02 07:20:30 +03:00
|
|
|
{
|
2015-06-06 13:19:48 +03:00
|
|
|
def->alias_count++;
|
2018-01-02 09:41:40 +03:00
|
|
|
if (METHOD_DEBUG) fprintf(stderr, "+%p-%s:%d\n", (void *)def, rb_id2name(def->original_id), def->alias_count);
|
2015-06-02 07:20:30 +03:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2015-11-18 11:15:51 +03:00
|
|
|
static rb_method_definition_t *
|
|
|
|
method_definition_addref_complement(rb_method_definition_t *def)
|
|
|
|
{
|
|
|
|
def->complemented_count++;
|
2018-01-02 09:41:40 +03:00
|
|
|
if (METHOD_DEBUG) fprintf(stderr, "+%p-%s:%d\n", (void *)def, rb_id2name(def->original_id), def->complemented_count);
|
2015-11-18 11:15:51 +03:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static rb_method_entry_t *
|
|
|
|
rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def)
|
|
|
|
{
|
|
|
|
rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
return me;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
filter_defined_class(VALUE klass)
|
|
|
|
{
|
|
|
|
switch (BUILTIN_TYPE(klass)) {
|
|
|
|
case T_CLASS:
|
|
|
|
return klass;
|
|
|
|
case T_MODULE:
|
|
|
|
return 0;
|
|
|
|
case T_ICLASS:
|
|
|
|
break;
|
2020-04-08 09:13:37 +03:00
|
|
|
default:
|
|
|
|
break;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
rb_bug("filter_defined_class: %s", rb_obj_info(klass));
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *
|
|
|
|
rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def)
|
2015-06-02 07:20:30 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def);
|
|
|
|
METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE);
|
|
|
|
if (def != NULL) method_definition_reset(me);
|
|
|
|
return me;
|
2015-06-02 07:20:30 +03:00
|
|
|
}
|
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
const rb_method_entry_t *
|
2015-06-02 07:20:30 +03:00
|
|
|
rb_method_entry_clone(const rb_method_entry_t *src_me)
|
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class,
|
2020-01-08 10:14:01 +03:00
|
|
|
method_definition_addref(src_me->def));
|
|
|
|
if (METHOD_ENTRY_COMPLEMENTED(src_me)) {
|
|
|
|
method_definition_addref_complement(src_me->def);
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
|
|
|
return me;
|
2015-06-02 07:20:30 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
|
2016-11-05 16:15:26 +03:00
|
|
|
rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID called_id, VALUE defined_class)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_definition_t *def = src_me->def;
|
|
|
|
rb_method_entry_t *me;
|
|
|
|
struct {
|
|
|
|
const struct rb_method_entry_struct *orig_me;
|
|
|
|
VALUE owner;
|
|
|
|
} refined = {0};
|
2017-12-26 13:32:58 +03:00
|
|
|
|
|
|
|
if (!src_me->defined_class &&
|
|
|
|
def->type == VM_METHOD_TYPE_REFINED &&
|
|
|
|
def->body.refined.orig_me) {
|
|
|
|
const rb_method_entry_t *orig_me =
|
|
|
|
rb_method_entry_clone(def->body.refined.orig_me);
|
|
|
|
RB_OBJ_WRITE((VALUE)orig_me, &orig_me->defined_class, defined_class);
|
2019-10-03 06:26:41 +03:00
|
|
|
refined.orig_me = orig_me;
|
|
|
|
refined.owner = orig_me->owner;
|
|
|
|
def = NULL;
|
2017-12-26 13:32:58 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-10-03 06:26:41 +03:00
|
|
|
def = method_definition_addref_complement(def);
|
|
|
|
}
|
|
|
|
me = rb_method_entry_alloc(called_id, src_me->owner, defined_class, def);
|
|
|
|
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
|
|
|
METHOD_ENTRY_COMPLEMENTED_SET(me);
|
|
|
|
if (!def) {
|
|
|
|
def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, called_id);
|
|
|
|
rb_method_definition_set(me, def, &refined);
|
2017-12-26 13:32:58 +03:00
|
|
|
}
|
2015-11-18 11:15:51 +03:00
|
|
|
|
|
|
|
VM_ASSERT(RB_TYPE_P(me->owner, T_MODULE));
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
return (rb_callable_method_entry_t *)me;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
void
|
|
|
|
rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
|
|
|
{
|
|
|
|
*(rb_method_definition_t **)&dst->def = method_definition_addref(src->def);
|
|
|
|
method_definition_reset(dst);
|
|
|
|
dst->called_id = src->called_id;
|
|
|
|
RB_OBJ_WRITE((VALUE)dst, &dst->owner, src->owner);
|
|
|
|
RB_OBJ_WRITE((VALUE)dst, &dst->defined_class, src->defined_class);
|
|
|
|
METHOD_ENTRY_FLAGS_COPY(dst, src);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
|
* 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 17:08:41 +04:00
|
|
|
{
|
2015-06-25 10:59:23 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
2019-10-03 06:26:41 +03:00
|
|
|
return;
|
2015-06-25 10:59:23 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-10-03 06:26:41 +03:00
|
|
|
struct {
|
|
|
|
struct rb_method_entry_struct *orig_me;
|
|
|
|
VALUE owner;
|
|
|
|
} refined;
|
|
|
|
rb_method_definition_t *def;
|
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
rb_vm_check_redefinition_opt_method(me, me->owner);
|
2019-10-03 06:26:41 +03:00
|
|
|
|
|
|
|
refined.orig_me =
|
|
|
|
rb_method_entry_alloc(me->called_id, me->owner,
|
|
|
|
me->defined_class ?
|
|
|
|
me->defined_class : owner,
|
|
|
|
method_definition_addref(me->def));
|
|
|
|
METHOD_ENTRY_FLAGS_COPY(refined.orig_me, me);
|
|
|
|
refined.owner = owner;
|
|
|
|
|
|
|
|
def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id);
|
|
|
|
rb_method_definition_set(me, def, (void *)&refined);
|
|
|
|
METHOD_ENTRY_VISI_SET(me, METHOD_VISI_PUBLIC);
|
2015-06-25 10:59:23 +03:00
|
|
|
}
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static inline rb_method_entry_t *
|
|
|
|
lookup_method_table(VALUE klass, ID id)
|
|
|
|
{
|
|
|
|
st_data_t body;
|
|
|
|
struct rb_id_table *m_tbl = RCLASS_M_TBL(klass);
|
|
|
|
|
|
|
|
if (rb_id_table_lookup(m_tbl, id, &body)) {
|
|
|
|
return (rb_method_entry_t *) body;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* 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 17:08:41 +04:00
|
|
|
void
|
|
|
|
rb_add_refined_method_entry(VALUE refined_class, ID mid)
|
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me = lookup_method_table(refined_class, mid);
|
* 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 17:08:41 +04:00
|
|
|
|
|
|
|
if (me) {
|
2019-10-03 06:26:41 +03:00
|
|
|
make_method_entry_refined(refined_class, me);
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(refined_class, mid);
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, METHOD_VISI_PUBLIC);
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
}
|
2012-11-07 08:09:51 +04:00
|
|
|
|
2015-12-18 05:32:17 +03:00
|
|
|
static void
|
2019-12-13 02:47:59 +03:00
|
|
|
check_override_opt_method_i(VALUE klass, VALUE arg)
|
2015-12-18 05:32:17 +03:00
|
|
|
{
|
|
|
|
ID mid = (ID)arg;
|
|
|
|
const rb_method_entry_t *me, *newme;
|
|
|
|
|
|
|
|
if (vm_redefinition_check_flag(klass)) {
|
|
|
|
me = lookup_method_table(RCLASS_ORIGIN(klass), mid);
|
|
|
|
if (me) {
|
|
|
|
newme = rb_method_entry(klass, mid);
|
|
|
|
if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner);
|
|
|
|
}
|
|
|
|
}
|
2019-12-13 02:47:59 +03:00
|
|
|
rb_class_foreach_subclass(klass, check_override_opt_method_i, (VALUE)mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_override_opt_method(VALUE klass, VALUE mid)
|
|
|
|
{
|
|
|
|
if (rb_vm_check_optimizable_mid(mid)) {
|
|
|
|
check_override_opt_method_i(klass, mid);
|
|
|
|
}
|
2015-12-18 05:32:17 +03:00
|
|
|
}
|
|
|
|
|
2015-06-25 10:59:23 +03:00
|
|
|
/*
|
|
|
|
* klass->method_table[mid] = method_entry(defined_class, visi, def)
|
|
|
|
*
|
2015-10-26 12:38:22 +03:00
|
|
|
* If def is given (!= NULL), then just use it and ignore original_id and otps.
|
2015-06-25 10:59:23 +03:00
|
|
|
* If not given, then make a new def with original_id and opts.
|
|
|
|
*/
|
2019-10-03 06:26:41 +03:00
|
|
|
static rb_method_entry_t *
|
2015-06-25 10:59:23 +03:00
|
|
|
rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibility_t visi,
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_type_t type, rb_method_definition_t *def, ID original_id, void *opts)
|
2009-07-15 18:59:41 +04:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me;
|
2015-08-12 11:43:55 +03:00
|
|
|
struct rb_id_table *mtbl;
|
2009-07-15 18:59:41 +04:00
|
|
|
st_data_t data;
|
* 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 17:08:41 +04:00
|
|
|
int make_refined = 0;
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
VALUE orig_klass;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
if (NIL_P(klass)) {
|
|
|
|
klass = rb_cObject;
|
|
|
|
}
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
orig_klass = klass;
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (!FL_TEST(klass, FL_SINGLETON) &&
|
2009-07-15 18:59:41 +04:00
|
|
|
type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
|
2014-06-15 17:21:21 +04:00
|
|
|
type != VM_METHOD_TYPE_ZSUPER) {
|
|
|
|
switch (mid) {
|
|
|
|
case idInitialize:
|
|
|
|
case idInitialize_copy:
|
|
|
|
case idInitialize_clone:
|
|
|
|
case idInitialize_dup:
|
|
|
|
case idRespond_to_missing:
|
2015-06-03 04:39:16 +03:00
|
|
|
visi = METHOD_VISI_PRIVATE;
|
2014-06-15 17:21:21 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2020-06-02 01:54:47 +03:00
|
|
|
if (type != VM_METHOD_TYPE_REFINED) {
|
|
|
|
rb_class_modify_check(klass);
|
|
|
|
}
|
2012-11-07 08:09:51 +04:00
|
|
|
|
2015-06-25 10:59:23 +03:00
|
|
|
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
|
|
|
|
VALUE refined_class = rb_refinement_module_get_refined_class(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 17:08:41 +04:00
|
|
|
rb_add_refined_method_entry(refined_class, mid);
|
|
|
|
}
|
|
|
|
if (type == VM_METHOD_TYPE_REFINED) {
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *old_me = lookup_method_table(RCLASS_ORIGIN(klass), mid);
|
* 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 17:08:41 +04:00
|
|
|
if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
klass = RCLASS_ORIGIN(klass);
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (klass != orig_klass) {
|
|
|
|
rb_clear_method_cache(orig_klass, mid);
|
|
|
|
}
|
2012-11-07 08:09:51 +04:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
mtbl = RCLASS_M_TBL(klass);
|
|
|
|
|
|
|
|
/* check re-definition */
|
2015-08-12 11:43:55 +03:00
|
|
|
if (rb_id_table_lookup(mtbl, mid, &data)) {
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *old_me = (rb_method_entry_t *)data;
|
|
|
|
rb_method_definition_t *old_def = old_me->def;
|
2009-08-28 06:45:41 +04:00
|
|
|
|
2009-09-29 08:37:52 +04:00
|
|
|
if (rb_method_definition_eq(old_def, def)) return old_me;
|
2011-08-25 02:02:03 +04:00
|
|
|
rb_vm_check_redefinition_opt_method(old_me, klass);
|
2015-06-25 10:59:23 +03:00
|
|
|
|
|
|
|
if (old_def->type == VM_METHOD_TYPE_REFINED) make_refined = 1;
|
2009-07-15 18:59:41 +04:00
|
|
|
|
|
|
|
if (RTEST(ruby_verbose) &&
|
2009-10-03 16:19:19 +04:00
|
|
|
type != VM_METHOD_TYPE_UNDEF &&
|
2015-06-06 13:19:48 +03:00
|
|
|
(old_def->alias_count == 0) &&
|
2017-08-17 17:58:11 +03:00
|
|
|
!make_refined &&
|
2009-09-13 04:34:11 +04:00
|
|
|
old_def->type != VM_METHOD_TYPE_UNDEF &&
|
2015-06-01 13:26:05 +03:00
|
|
|
old_def->type != VM_METHOD_TYPE_ZSUPER &&
|
|
|
|
old_def->type != VM_METHOD_TYPE_ALIAS) {
|
2015-05-21 12:01:44 +03:00
|
|
|
const rb_iseq_t *iseq = 0;
|
2009-09-30 08:15:46 +04:00
|
|
|
|
2014-11-25 21:44:12 +03:00
|
|
|
rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid));
|
2009-09-30 08:15:46 +04:00
|
|
|
switch (old_def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
2015-06-02 07:20:30 +03:00
|
|
|
iseq = def_iseq_ptr(old_def);
|
2009-09-30 08:15:46 +04:00
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_BMETHOD:
|
2018-11-26 21:16:54 +03:00
|
|
|
iseq = rb_proc_get_iseq(old_def->body.bmethod.proc, 0);
|
2009-09-30 08:15:46 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-12-20 08:26:07 +03:00
|
|
|
if (iseq) {
|
2017-06-01 03:05:33 +03:00
|
|
|
rb_compile_warning(RSTRING_PTR(rb_iseq_path(iseq)),
|
2016-12-20 08:26:07 +03:00
|
|
|
FIX2INT(iseq->body->location.first_lineno),
|
2014-11-25 21:44:12 +03:00
|
|
|
"previous definition of %"PRIsVALUE" was here",
|
|
|
|
rb_id2str(old_def->original_id));
|
2009-09-30 08:15:46 +04:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
|
2015-06-25 10:59:23 +03:00
|
|
|
/* create method entry */
|
2019-10-03 06:26:41 +03:00
|
|
|
me = rb_method_entry_create(mid, defined_class, visi, NULL);
|
|
|
|
if (def == NULL) def = rb_method_definition_create(type, original_id);
|
|
|
|
rb_method_definition_set(me, def, opts);
|
2010-05-05 21:51:21 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(klass, mid);
|
2009-08-28 06:45:41 +04:00
|
|
|
|
2009-07-15 18:59:41 +04:00
|
|
|
/* check mid */
|
2018-12-07 02:06:13 +03:00
|
|
|
if (klass == rb_cObject) {
|
|
|
|
switch (mid) {
|
|
|
|
case idInitialize:
|
|
|
|
case idRespond_to_missing:
|
|
|
|
case idMethodMissing:
|
|
|
|
case idRespond_to:
|
|
|
|
rb_warn("redefining Object#%s may cause infinite loop", rb_id2name(mid));
|
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
/* check mid */
|
|
|
|
if (mid == object_id || mid == id__send__) {
|
2014-10-23 20:02:46 +04:00
|
|
|
if (type == VM_METHOD_TYPE_ISEQ && search_method(klass, mid, 0)) {
|
2009-07-15 18:59:41 +04:00
|
|
|
rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
* 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 17:08:41 +04:00
|
|
|
if (make_refined) {
|
2019-10-03 06:26:41 +03:00
|
|
|
make_method_entry_refined(klass, me);
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
|
2020-08-11 01:19:17 +03:00
|
|
|
rb_method_table_insert(klass, mtbl, mid, me);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2015-06-25 10:59:23 +03:00
|
|
|
VM_ASSERT(me->def != NULL);
|
|
|
|
|
2015-12-18 05:32:17 +03:00
|
|
|
/* check optimized method override by a prepended module */
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (RB_TYPE_P(orig_klass, T_MODULE)) {
|
2015-12-18 05:32:17 +03:00
|
|
|
check_override_opt_method(klass, (VALUE)mid);
|
|
|
|
}
|
|
|
|
|
2009-09-12 19:03:02 +04:00
|
|
|
return me;
|
|
|
|
}
|
|
|
|
|
2009-09-12 19:46:42 +04:00
|
|
|
#define CALL_METHOD_HOOK(klass, hook, mid) do { \
|
|
|
|
const VALUE arg = ID2SYM(mid); \
|
2011-01-14 17:26:27 +03:00
|
|
|
VALUE recv_class = (klass); \
|
|
|
|
ID hook_id = (hook); \
|
|
|
|
if (FL_TEST((klass), FL_SINGLETON)) { \
|
|
|
|
recv_class = rb_ivar_get((klass), attached); \
|
2009-09-12 19:46:42 +04:00
|
|
|
hook_id = singleton_##hook; \
|
|
|
|
} \
|
2016-07-29 14:57:14 +03:00
|
|
|
rb_funcallv(recv_class, hook_id, 1, &arg); \
|
2009-09-12 19:46:42 +04:00
|
|
|
} while (0)
|
|
|
|
|
2009-09-12 19:03:02 +04:00
|
|
|
static void
|
|
|
|
method_added(VALUE klass, ID mid)
|
|
|
|
{
|
2012-09-08 13:52:26 +04:00
|
|
|
if (ruby_running) {
|
2009-09-12 19:46:42 +04:00
|
|
|
CALL_METHOD_HOOK(klass, added, mid);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-05 11:41:04 +03:00
|
|
|
void
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_visibility_t visi)
|
2009-08-28 06:45:41 +04:00
|
|
|
{
|
2019-04-05 11:41:04 +03:00
|
|
|
rb_method_entry_make(klass, mid, klass, visi, type, NULL, mid, opts);
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
|
* 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 17:08:41 +04:00
|
|
|
if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
|
2011-07-12 12:15:47 +04:00
|
|
|
method_added(klass, mid);
|
|
|
|
}
|
2009-08-28 06:45:41 +04:00
|
|
|
}
|
|
|
|
|
2019-04-05 11:15:11 +03:00
|
|
|
MJIT_FUNC_EXPORTED void
|
2015-07-22 01:52:59 +03:00
|
|
|
rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi)
|
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-03-06 15:24:58 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
struct { /* should be same fields with rb_method_iseq_struct */
|
|
|
|
const rb_iseq_t *iseqptr;
|
|
|
|
rb_cref_t *cref;
|
|
|
|
} iseq_body;
|
|
|
|
|
|
|
|
iseq_body.iseqptr = iseq;
|
|
|
|
iseq_body.cref = cref;
|
2015-06-04 19:08:40 +03:00
|
|
|
rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, &iseq_body, visi);
|
2015-05-30 21:45:28 +03:00
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static rb_method_entry_t *
|
2013-12-13 17:29:23 +04:00
|
|
|
method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_visibility_t visi, VALUE defined_class)
|
2009-08-28 06:45:41 +04:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *newme = rb_method_entry_make(klass, mid, defined_class, visi,
|
2015-06-25 10:59:23 +03:00
|
|
|
me->def->type, method_definition_addref(me->def), 0, NULL);
|
2015-06-02 07:20:30 +03:00
|
|
|
method_added(klass, mid);
|
|
|
|
return newme;
|
2009-08-28 06:45:41 +04:00
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_visibility_t visi)
|
2013-12-13 17:29:23 +04:00
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
return method_entry_set(klass, mid, me, visi, klass);
|
2013-12-13 17:29:23 +04:00
|
|
|
}
|
|
|
|
|
2012-09-08 13:52:26 +04:00
|
|
|
#define UNDEF_ALLOC_FUNC ((rb_alloc_func_t)-1)
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
2008-01-12 12:27:43 +03:00
|
|
|
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
|
|
|
Check_Type(klass, T_CLASS);
|
2012-09-08 13:52:26 +04:00
|
|
|
RCLASS_EXT(klass)->allocator = func;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_undef_alloc_func(VALUE klass)
|
|
|
|
{
|
2012-09-08 13:52:26 +04:00
|
|
|
rb_define_alloc_func(klass, UNDEF_ALLOC_FUNC);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
rb_alloc_func_t
|
|
|
|
rb_get_alloc_func(VALUE klass)
|
|
|
|
{
|
|
|
|
Check_Type(klass, T_CLASS);
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2012-09-08 13:52:26 +04:00
|
|
|
for (; klass; klass = RCLASS_SUPER(klass)) {
|
|
|
|
rb_alloc_func_t allocator = RCLASS_EXT(klass)->allocator;
|
|
|
|
if (allocator == UNDEF_ALLOC_FUNC) break;
|
|
|
|
if (allocator) return allocator;
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
2012-09-08 13:52:26 +04:00
|
|
|
return 0;
|
2007-09-08 19:07:18 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_method_entry_t *
|
|
|
|
rb_method_entry_at(VALUE klass, ID id)
|
|
|
|
{
|
|
|
|
return lookup_method_table(klass, id);
|
|
|
|
}
|
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
static inline rb_method_entry_t*
|
* 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 17:08:41 +04:00
|
|
|
search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2020-02-20 08:02:01 +03:00
|
|
|
rb_method_entry_t *me = NULL;
|
2012-11-30 06:11:59 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(mc_search);
|
|
|
|
|
2018-08-07 15:00:54 +03:00
|
|
|
for (; klass; klass = RCLASS_SUPER(klass)) {
|
2017-02-21 11:18:15 +03:00
|
|
|
RB_DEBUG_COUNTER_INC(mc_search_super);
|
2020-01-08 10:14:01 +03:00
|
|
|
if ((me = lookup_method_table(klass, id)) != 0) {
|
|
|
|
break;
|
|
|
|
}
|
2012-10-06 11:32:45 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (defined_class_ptr) *defined_class_ptr = klass;
|
|
|
|
|
|
|
|
if (me == NULL) RB_DEBUG_COUNTER_INC(mc_search_notfound);
|
|
|
|
|
|
|
|
VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me));
|
* 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 17:08:41 +04:00
|
|
|
return me;
|
2012-10-06 11:32:45 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static rb_method_entry_t *
|
|
|
|
search_method_protect(VALUE klass, ID id, VALUE *defined_class_ptr)
|
2013-05-13 09:51:14 +04:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_method_entry_t *me = search_method(klass, id, defined_class_ptr);
|
|
|
|
|
|
|
|
if (!UNDEFINED_METHOD_ENTRY_P(me)) {
|
|
|
|
return me;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-13 09:51:14 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_method_entry_t *
|
|
|
|
rb_method_entry(VALUE klass, ID id)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2020-04-23 04:24:49 +03:00
|
|
|
return search_method_protect(klass, id, NULL);
|
2020-01-08 10:14:01 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static inline const rb_callable_method_entry_t *
|
|
|
|
prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_t * const me, int create)
|
|
|
|
{
|
|
|
|
struct rb_id_table *mtbl;
|
|
|
|
const rb_callable_method_entry_t *cme;
|
2014-03-03 03:24:38 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (me) {
|
|
|
|
if (me->defined_class == 0) {
|
|
|
|
RB_DEBUG_COUNTER_INC(mc_cme_complement);
|
|
|
|
VM_ASSERT(RB_TYPE_P(defined_class, T_ICLASS) || RB_TYPE_P(defined_class, T_MODULE));
|
|
|
|
VM_ASSERT(me->defined_class == 0);
|
|
|
|
|
|
|
|
mtbl = RCLASS_CALLABLE_M_TBL(defined_class);
|
|
|
|
|
|
|
|
if (mtbl && rb_id_table_lookup(mtbl, id, (VALUE *)&cme)) {
|
|
|
|
RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
|
|
|
|
VM_ASSERT(callable_method_entry_p(cme));
|
|
|
|
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
|
|
|
|
}
|
|
|
|
else if (create) {
|
|
|
|
if (!mtbl) {
|
|
|
|
mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = rb_id_table_create(0);
|
|
|
|
}
|
|
|
|
cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class);
|
|
|
|
rb_id_table_insert(mtbl, id, (VALUE)cme);
|
2020-08-11 01:19:17 +03:00
|
|
|
RB_OBJ_WRITTEN(defined_class, Qundef, (VALUE)cme);
|
2020-01-08 10:14:01 +03:00
|
|
|
VM_ASSERT(callable_method_entry_p(cme));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cme = (const rb_callable_method_entry_t *)me;
|
|
|
|
VM_ASSERT(callable_method_entry_p(cme));
|
|
|
|
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
|
|
|
|
}
|
|
|
|
return cme;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
else {
|
|
|
|
return NULL;
|
2016-07-13 08:19:12 +03:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static const rb_callable_method_entry_t *
|
2020-07-19 17:13:21 +03:00
|
|
|
complemented_callable_method_entry(VALUE klass, ID id)
|
2020-01-08 10:14:01 +03:00
|
|
|
{
|
|
|
|
VALUE defined_class;
|
|
|
|
rb_method_entry_t *me = search_method_protect(klass, id, &defined_class);
|
|
|
|
return prepare_callable_method_entry(defined_class, id, me, FALSE);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static const rb_callable_method_entry_t *
|
|
|
|
cached_callable_method_entry(VALUE klass, ID mid)
|
* 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 09:25:06 +04:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
|
|
|
|
struct rb_class_cc_entries *ccs;
|
* 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 09:25:06 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
|
|
|
|
VM_ASSERT(vm_ccs_p(ccs));
|
|
|
|
|
|
|
|
if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) {
|
|
|
|
VM_ASSERT(ccs->cme->called_id == mid);
|
|
|
|
RB_DEBUG_COUNTER_INC(ccs_found);
|
|
|
|
return ccs->cme;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_vm_ccs_free(ccs);
|
|
|
|
rb_id_table_delete(cc_tbl, mid);
|
|
|
|
}
|
* 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 09:25:06 +04:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
return NULL;
|
* 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 09:25:06 +04:00
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
static void
|
|
|
|
cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_t *cme)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
|
|
|
|
struct rb_class_cc_entries *ccs;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (!cc_tbl) {
|
|
|
|
cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2);
|
|
|
|
}
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (rb_id_table_lookup(cc_tbl, mid, (VALUE *)&ccs)) {
|
|
|
|
VM_ASSERT(ccs->cme == cme);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ccs = vm_ccs_create(klass, cme);
|
|
|
|
rb_id_table_insert(cc_tbl, mid, (VALUE)ccs);
|
|
|
|
}
|
* 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 17:08:41 +04:00
|
|
|
}
|
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
static const rb_callable_method_entry_t *
|
2020-01-08 10:14:01 +03:00
|
|
|
callable_method_entry(VALUE klass, ID mid, VALUE *defined_class_ptr)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
|
|
|
|
const rb_callable_method_entry_t *cme = cached_callable_method_entry(klass, mid);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (cme) {
|
|
|
|
if (defined_class_ptr != NULL) *defined_class_ptr = cme->defined_class;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
else {
|
2020-01-08 10:14:01 +03:00
|
|
|
VALUE defined_class;
|
|
|
|
rb_method_entry_t *me = search_method_protect(klass, mid, &defined_class);
|
|
|
|
if (defined_class_ptr) *defined_class_ptr = defined_class;
|
|
|
|
cme = prepare_callable_method_entry(defined_class, mid, me, TRUE);
|
|
|
|
if (cme) cache_callable_method_entry(klass, mid, cme);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return cme;
|
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_callable_method_entry(VALUE klass, ID mid)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
return callable_method_entry(klass, mid, NULL);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static const rb_method_entry_t *resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr);
|
|
|
|
|
2015-06-04 19:02:01 +03:00
|
|
|
static const rb_method_entry_t *
|
2015-08-11 04:33:32 +03:00
|
|
|
method_entry_resolve_refinement(VALUE klass, ID id, int with_refinement, VALUE *defined_class_ptr)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_method_entry_t *me = search_method_protect(klass, id, defined_class_ptr);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
|
|
|
if (me) {
|
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
|
|
|
if (with_refinement) {
|
|
|
|
const rb_cref_t *cref = rb_vm_cref();
|
|
|
|
VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
|
|
|
|
me = resolve_refined_method(refinements, me, defined_class_ptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
me = resolve_refined_method(Qnil, me, defined_class_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me)) me = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return me;
|
|
|
|
}
|
|
|
|
|
2020-06-03 17:05:55 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_method_entry_t *
|
2019-01-28 14:45:21 +03:00
|
|
|
rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
|
|
|
|
{
|
|
|
|
return method_entry_resolve_refinement(klass, id, TRUE, defined_class_ptr);
|
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
|
2017-10-06 08:55:11 +03:00
|
|
|
rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_callable_method_entry_t *cme = callable_method_entry(klass, id, defined_class_ptr);
|
|
|
|
if (cme == NULL || cme->def->type != VM_METHOD_TYPE_REFINED) {
|
|
|
|
return cme;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
|
|
|
|
const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, TRUE, dcp);
|
|
|
|
return prepare_callable_method_entry(*dcp, id, me, TRUE);
|
|
|
|
}
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const rb_method_entry_t *
|
2017-10-06 08:55:11 +03:00
|
|
|
rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2017-10-06 08:55:11 +03:00
|
|
|
return method_entry_resolve_refinement(klass, id, FALSE, defined_class_ptr);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
|
2017-10-06 08:55:11 +03:00
|
|
|
rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
{
|
2017-10-06 08:55:11 +03:00
|
|
|
VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
|
|
|
|
const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, FALSE, dcp);
|
2020-01-08 10:14:01 +03:00
|
|
|
return prepare_callable_method_entry(*dcp, id, me, TRUE);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static const rb_method_entry_t *
|
|
|
|
resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr)
|
* 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 17:08:41 +04:00
|
|
|
{
|
2018-12-18 18:11:17 +03:00
|
|
|
while (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
* 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 17:08:41 +04:00
|
|
|
VALUE refinement;
|
2018-12-18 19:11:07 +03:00
|
|
|
const rb_method_entry_t *tmp_me;
|
2018-12-18 18:11:17 +03:00
|
|
|
VALUE super;
|
* 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 17:08:41 +04:00
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
refinement = find_refinement(refinements, me->owner);
|
2018-12-18 18:11:18 +03:00
|
|
|
if (!NIL_P(refinement)) {
|
2020-01-08 10:14:01 +03:00
|
|
|
tmp_me = search_method_protect(refinement, me->called_id, defined_class_ptr);
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
|
|
|
if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
|
|
|
|
return tmp_me;
|
|
|
|
}
|
* 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 17:08:41 +04:00
|
|
|
}
|
2018-12-18 18:11:17 +03:00
|
|
|
|
|
|
|
tmp_me = me->def->body.refined.orig_me;
|
|
|
|
if (tmp_me) {
|
|
|
|
if (defined_class_ptr) *defined_class_ptr = tmp_me->defined_class;
|
|
|
|
return tmp_me;
|
|
|
|
}
|
|
|
|
|
|
|
|
super = RCLASS_SUPER(me->owner);
|
|
|
|
if (!super) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
me = search_method_protect(super, me->called_id, defined_class_ptr);
|
* 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 17:08:41 +04:00
|
|
|
}
|
2018-12-18 18:11:17 +03:00
|
|
|
return me;
|
2012-08-02 15:34:19 +04:00
|
|
|
}
|
|
|
|
|
2015-06-04 19:02:01 +03:00
|
|
|
const rb_method_entry_t *
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me)
|
2012-08-02 15:34:19 +04:00
|
|
|
{
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
return resolve_refined_method(refinements, me, NULL);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2019-11-18 06:13:08 +03:00
|
|
|
MJIT_FUNC_EXPORTED
|
2018-12-18 16:59:46 +03:00
|
|
|
const rb_callable_method_entry_t *
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me)
|
2012-12-09 12:48:34 +04:00
|
|
|
{
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
VALUE defined_class = me->defined_class;
|
|
|
|
const rb_method_entry_t *resolved_me = resolve_refined_method(refinements, (const rb_method_entry_t *)me, &defined_class);
|
2012-12-09 12:48:34 +04:00
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
if (resolved_me && resolved_me->defined_class == 0) {
|
2016-11-05 16:15:26 +03:00
|
|
|
return rb_method_entry_complement_defined_class(resolved_me, me->called_id, defined_class);
|
2013-10-17 12:44:26 +04:00
|
|
|
}
|
|
|
|
else {
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
return (const rb_callable_method_entry_t *)resolved_me;
|
2013-10-17 12:44:26 +04:00
|
|
|
}
|
2012-12-09 12:48:34 +04:00
|
|
|
}
|
|
|
|
|
2009-09-12 19:27:59 +04:00
|
|
|
static void
|
2009-09-12 19:31:43 +04:00
|
|
|
remove_method(VALUE klass, ID mid)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-08-12 11:43:55 +03:00
|
|
|
VALUE data;
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me = 0;
|
2013-02-14 05:30:47 +04:00
|
|
|
VALUE self = klass;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2012-06-27 17:40:37 +04:00
|
|
|
klass = RCLASS_ORIGIN(klass);
|
2018-07-27 16:57:14 +03:00
|
|
|
rb_class_modify_check(klass);
|
2008-12-15 08:15:26 +03:00
|
|
|
if (mid == object_id || mid == id__send__ || mid == idInitialize) {
|
2009-07-05 03:14:43 +04:00
|
|
|
rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2015-08-12 11:43:55 +03:00
|
|
|
if (!rb_id_table_lookup(RCLASS_M_TBL(klass), mid, &data) ||
|
2019-10-03 06:26:41 +03:00
|
|
|
!(me = (rb_method_entry_t *)data) ||
|
2015-02-03 09:26:48 +03:00
|
|
|
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) ||
|
|
|
|
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
2015-10-28 09:24:12 +03:00
|
|
|
rb_name_err_raise("method `%1$s' not defined in %2$s",
|
|
|
|
klass, ID2SYM(mid));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2015-02-03 09:26:48 +03:00
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
if (klass != self) {
|
|
|
|
rb_clear_method_cache(self, mid);
|
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(klass, mid);
|
2015-08-12 11:43:55 +03:00
|
|
|
rb_id_table_delete(RCLASS_M_TBL(klass), mid);
|
2007-05-02 10:21:58 +04:00
|
|
|
|
2011-08-25 02:02:03 +04:00
|
|
|
rb_vm_check_redefinition_opt_method(me, klass);
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2015-02-03 09:26:48 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED) {
|
|
|
|
rb_add_refined_method_entry(klass, mid);
|
|
|
|
}
|
|
|
|
|
2013-02-14 05:30:47 +04:00
|
|
|
CALL_METHOD_HOOK(self, removed, mid);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2009-09-12 19:27:59 +04:00
|
|
|
void
|
|
|
|
rb_remove_method_id(VALUE klass, ID mid)
|
|
|
|
{
|
|
|
|
remove_method(klass, mid);
|
|
|
|
}
|
2009-08-27 13:31:11 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
|
|
|
rb_remove_method(VALUE klass, const char *name)
|
|
|
|
{
|
|
|
|
remove_method(klass, rb_intern(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* remove_method(symbol) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* remove_method(string) -> self
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* Removes the method identified by _symbol_ from the current
|
2019-03-28 06:33:36 +03:00
|
|
|
* class. For an example, see Module#undef_method.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
2006-12-31 18:02:22 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
2011-07-26 20:05:35 +04:00
|
|
|
VALUE v = argv[i];
|
2014-07-09 10:14:41 +04:00
|
|
|
ID id = rb_check_id(&v);
|
2011-07-26 20:05:35 +04:00
|
|
|
if (!id) {
|
2015-10-28 09:24:12 +03:00
|
|
|
rb_name_err_raise("method `%1$s' not defined in %2$s",
|
|
|
|
mod, v);
|
2011-07-26 20:05:35 +04:00
|
|
|
}
|
|
|
|
remove_method(mod, id);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me;
|
2012-08-02 15:08:44 +04:00
|
|
|
VALUE defined_class;
|
2018-03-12 09:54:43 +03:00
|
|
|
VALUE origin_class = RCLASS_ORIGIN(klass);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2018-03-12 09:54:43 +03:00
|
|
|
me = search_method(origin_class, name, &defined_class);
|
2020-01-08 10:14:01 +03:00
|
|
|
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!me && RB_TYPE_P(klass, T_MODULE)) {
|
* 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 17:08:41 +04:00
|
|
|
me = search_method(rb_cObject, name, &defined_class);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2015-01-08 10:31:45 +03:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me) ||
|
2015-01-12 11:18:10 +03:00
|
|
|
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
2016-01-03 07:59:54 +03:00
|
|
|
rb_print_undef(klass, name, METHOD_VISI_UNDEF);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2015-06-06 13:19:48 +03:00
|
|
|
if (METHOD_ENTRY_VISI(me) != visi) {
|
2011-08-25 02:02:03 +04:00
|
|
|
rb_vm_check_redefinition_opt_method(me, klass);
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2018-03-12 09:54:43 +03:00
|
|
|
if (klass == defined_class || origin_class == defined_class) {
|
2019-10-03 06:26:41 +03:00
|
|
|
METHOD_ENTRY_VISI_SET(me, visi);
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2015-06-04 01:27:51 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_REFINED && me->def->body.refined.orig_me) {
|
2015-06-11 02:55:33 +03:00
|
|
|
METHOD_ENTRY_VISI_SET((rb_method_entry_t *)me->def->body.refined.orig_me, visi);
|
* 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 17:08:41 +04:00
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(klass, name);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, visi);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-03 04:39:16 +03:00
|
|
|
#define BOUND_PRIVATE 0x01
|
|
|
|
#define BOUND_RESPONDS 0x02
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
int
|
|
|
|
rb_method_boundp(VALUE klass, ID id, int ex)
|
|
|
|
{
|
2018-11-22 11:29:02 +03:00
|
|
|
const rb_method_entry_t *me;
|
|
|
|
|
|
|
|
if (ex & BOUND_RESPONDS) {
|
|
|
|
me = method_entry_resolve_refinement(klass, id, TRUE, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
me = rb_method_entry_without_refinements(klass, id, NULL);
|
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (me != NULL) {
|
2020-06-03 02:40:11 +03:00
|
|
|
if (ex & ~BOUND_RESPONDS) {
|
|
|
|
switch (METHOD_ENTRY_VISI(me)) {
|
|
|
|
case METHOD_VISI_PRIVATE:
|
|
|
|
return 0;
|
|
|
|
case METHOD_VISI_PROTECTED:
|
|
|
|
if (ex & BOUND_RESPONDS) return 0;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2015-06-06 13:19:48 +03:00
|
|
|
if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
|
2015-06-03 04:39:16 +03:00
|
|
|
if (ex & BOUND_RESPONDS) return 2;
|
2010-07-21 09:00:53 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2010-07-21 09:00:53 +04:00
|
|
|
return 0;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-11-13 20:20:11 +03:00
|
|
|
static void
|
|
|
|
vm_cref_set_visibility(rb_method_visibility_t method_visi, int module_func)
|
|
|
|
{
|
|
|
|
rb_scope_visibility_t *scope_visi = (rb_scope_visibility_t *)&rb_vm_cref()->scope_visi;
|
|
|
|
scope_visi->method_visi = method_visi;
|
|
|
|
scope_visi->module_func = module_func;
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:44:56 +03:00
|
|
|
void
|
2015-06-03 17:07:24 +03:00
|
|
|
rb_scope_visibility_set(rb_method_visibility_t visi)
|
2015-05-31 23:44:56 +03:00
|
|
|
{
|
2015-11-13 20:20:11 +03:00
|
|
|
vm_cref_set_visibility(visi, FALSE);
|
2015-06-03 04:39:16 +03:00
|
|
|
}
|
|
|
|
|
2019-08-25 03:11:06 +03:00
|
|
|
static void
|
|
|
|
scope_visibility_check(void)
|
|
|
|
{
|
|
|
|
/* Check for public/protected/private/module_function called inside a method */
|
|
|
|
rb_control_frame_t *cfp = rb_current_execution_context()->cfp+1;
|
|
|
|
if (cfp && cfp->iseq && cfp->iseq->body->type == ISEQ_TYPE_METHOD) {
|
|
|
|
rb_warn("calling %s without arguments inside a method may not have the intended effect",
|
|
|
|
rb_id2name(rb_frame_this_func()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-03 17:07:24 +03:00
|
|
|
static void
|
|
|
|
rb_scope_module_func_set(void)
|
2015-06-03 04:39:16 +03:00
|
|
|
{
|
2019-08-25 03:11:06 +03:00
|
|
|
scope_visibility_check();
|
2015-11-13 20:20:11 +03:00
|
|
|
vm_cref_set_visibility(METHOD_VISI_PRIVATE, TRUE);
|
2015-05-31 23:44:56 +03:00
|
|
|
}
|
|
|
|
|
2019-08-01 03:03:11 +03:00
|
|
|
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
|
|
|
rb_attr(VALUE klass, ID id, int read, int write, int ex)
|
|
|
|
{
|
2015-06-24 11:29:03 +03:00
|
|
|
ID attriv;
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_visibility_t visi;
|
2019-04-05 11:15:11 +03:00
|
|
|
const rb_execution_context_t *ec = GET_EC();
|
2019-08-01 03:03:11 +03:00
|
|
|
const rb_cref_t *cref = rb_vm_cref_in_context(klass, klass);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2019-08-01 03:03:11 +03:00
|
|
|
if (!ex || !cref) {
|
2015-06-03 04:39:16 +03:00
|
|
|
visi = METHOD_VISI_PUBLIC;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-04-05 11:15:21 +03:00
|
|
|
switch (vm_scope_visibility_get(ec)) {
|
2015-06-24 11:31:43 +03:00
|
|
|
case METHOD_VISI_PRIVATE:
|
2019-04-05 11:15:21 +03:00
|
|
|
if (vm_scope_module_func_check(ec)) {
|
2015-05-21 09:40:27 +03:00
|
|
|
rb_warning("attribute accessor as module_function");
|
|
|
|
}
|
2015-06-24 11:31:43 +03:00
|
|
|
visi = METHOD_VISI_PRIVATE;
|
|
|
|
break;
|
|
|
|
case METHOD_VISI_PROTECTED:
|
2015-06-03 04:39:16 +03:00
|
|
|
visi = METHOD_VISI_PROTECTED;
|
2015-06-24 11:31:43 +03:00
|
|
|
break;
|
|
|
|
default:
|
2015-06-03 04:39:16 +03:00
|
|
|
visi = METHOD_VISI_PUBLIC;
|
2015-06-24 11:31:43 +03:00
|
|
|
break;
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-24 11:29:03 +03:00
|
|
|
attriv = rb_intern_str(rb_sprintf("@%"PRIsVALUE, rb_id2str(id)));
|
2006-12-31 18:02:22 +03:00
|
|
|
if (read) {
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, visi);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
if (write) {
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, visi);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_undef(VALUE klass, ID id)
|
|
|
|
{
|
2017-01-18 08:23:53 +03:00
|
|
|
const rb_method_entry_t *me;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2009-11-18 04:13:54 +03:00
|
|
|
if (NIL_P(klass)) {
|
|
|
|
rb_raise(rb_eTypeError, "no class to undef method");
|
|
|
|
}
|
2018-07-27 16:57:14 +03:00
|
|
|
rb_class_modify_check(klass);
|
2008-12-15 08:15:26 +03:00
|
|
|
if (id == object_id || id == id__send__ || id == idInitialize) {
|
2009-07-05 03:14:43 +04:00
|
|
|
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
* 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 17:08:41 +04:00
|
|
|
me = search_method(klass, id, 0);
|
2017-01-18 08:23:53 +03:00
|
|
|
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
|
|
|
|
me = rb_resolve_refined_method(Qnil, me);
|
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2013-09-30 05:49:21 +04:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me) ||
|
2015-01-12 11:18:10 +03:00
|
|
|
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
2015-10-24 10:35:57 +03:00
|
|
|
rb_method_name_error(klass, rb_id2str(id));
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, METHOD_VISI_PUBLIC);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2009-09-12 19:46:42 +04:00
|
|
|
CALL_METHOD_HOOK(klass, undefined, id);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* undef_method(symbol) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* undef_method(string) -> self
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* Prevents the current class from responding to calls to the named
|
|
|
|
* method. Contrast this with <code>remove_method</code>, which deletes
|
|
|
|
* the method from the particular class; Ruby will still search
|
|
|
|
* superclasses and mixed-in modules for a possible receiver.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* class Parent
|
|
|
|
* def hello
|
|
|
|
* puts "In parent"
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* class Child < Parent
|
|
|
|
* def hello
|
|
|
|
* puts "In child"
|
|
|
|
* end
|
|
|
|
* end
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* c = Child.new
|
|
|
|
* c.hello
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* class Child
|
|
|
|
* remove_method :hello # remove from child, still in parent
|
|
|
|
* end
|
|
|
|
* c.hello
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* class Child
|
|
|
|
* undef_method :hello # prevent any calls to 'hello'
|
|
|
|
* end
|
|
|
|
* c.hello
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* <em>produces:</em>
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* In child
|
|
|
|
* In parent
|
|
|
|
* prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
2011-07-26 20:05:35 +04:00
|
|
|
VALUE v = argv[i];
|
2014-07-09 10:14:41 +04:00
|
|
|
ID id = rb_check_id(&v);
|
2011-07-26 20:05:35 +04:00
|
|
|
if (!id) {
|
|
|
|
rb_method_name_error(mod, v);
|
|
|
|
}
|
|
|
|
rb_undef(mod, id);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2018-08-13 16:48:27 +03:00
|
|
|
static rb_method_visibility_t
|
|
|
|
check_definition_visibility(VALUE mod, int argc, VALUE *argv)
|
|
|
|
{
|
|
|
|
const rb_method_entry_t *me;
|
|
|
|
VALUE mid, include_super, lookup_mod = mod;
|
|
|
|
int inc_super;
|
|
|
|
ID id;
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "11", &mid, &include_super);
|
|
|
|
id = rb_check_id(&mid);
|
|
|
|
if (!id) return METHOD_VISI_UNDEF;
|
|
|
|
|
|
|
|
if (argc == 1) {
|
|
|
|
inc_super = 1;
|
2019-01-09 16:58:49 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-08-13 16:48:27 +03:00
|
|
|
inc_super = RTEST(include_super);
|
|
|
|
if (!inc_super) {
|
|
|
|
lookup_mod = RCLASS_ORIGIN(mod);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
me = rb_method_entry_without_refinements(lookup_mod, id, NULL);
|
|
|
|
if (me) {
|
|
|
|
if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) return METHOD_VISI_UNDEF;
|
|
|
|
if (!inc_super && me->owner != mod) return METHOD_VISI_UNDEF;
|
|
|
|
return METHOD_ENTRY_VISI(me);
|
|
|
|
}
|
|
|
|
return METHOD_VISI_UNDEF;
|
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-08-13 16:48:27 +03:00
|
|
|
* mod.method_defined?(symbol, inherit=true) -> true or false
|
|
|
|
* mod.method_defined?(string, inherit=true) -> true or false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Returns +true+ if the named method is defined by
|
2018-08-13 16:48:27 +03:00
|
|
|
* _mod_. If _inherit_ is set, the lookup will also search _mod_'s
|
|
|
|
* ancestors. Public and protected methods are matched.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* def method1() end
|
2015-10-30 06:36:21 +03:00
|
|
|
* def protected_method1() end
|
|
|
|
* protected :protected_method1
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* def method2() end
|
2015-10-30 06:36:21 +03:00
|
|
|
* def private_method2() end
|
|
|
|
* private :private_method2
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* include A
|
|
|
|
* def method3() end
|
|
|
|
* end
|
|
|
|
*
|
2015-10-30 06:36:21 +03:00
|
|
|
* A.method_defined? :method1 #=> true
|
|
|
|
* C.method_defined? "method1" #=> true
|
|
|
|
* C.method_defined? "method2" #=> true
|
2018-08-13 16:48:27 +03:00
|
|
|
* C.method_defined? "method2", true #=> true
|
|
|
|
* C.method_defined? "method2", false #=> false
|
2015-10-30 06:36:21 +03:00
|
|
|
* C.method_defined? "method3" #=> true
|
|
|
|
* C.method_defined? "protected_method1" #=> true
|
|
|
|
* C.method_defined? "method4" #=> false
|
|
|
|
* C.method_defined? "private_method2" #=> false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_mod_method_defined(int argc, VALUE *argv, VALUE mod)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_method_visibility_t visi = check_definition_visibility(mod, argc, argv);
|
|
|
|
return (visi == METHOD_VISI_PUBLIC || visi == METHOD_VISI_PROTECTED) ? Qtrue : Qfalse;
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
2009-07-15 18:59:41 +04:00
|
|
|
static VALUE
|
2018-08-13 16:48:27 +03:00
|
|
|
check_definition(VALUE mod, int argc, VALUE *argv, rb_method_visibility_t visi)
|
2009-07-15 18:59:41 +04:00
|
|
|
{
|
2018-08-13 16:48:27 +03:00
|
|
|
return (check_definition_visibility(mod, argc, argv) == visi) ? Qtrue : Qfalse;
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-08-13 16:48:27 +03:00
|
|
|
* mod.public_method_defined?(symbol, inherit=true) -> true or false
|
|
|
|
* mod.public_method_defined?(string, inherit=true) -> true or false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Returns +true+ if the named public method is defined by
|
2018-08-13 16:48:27 +03:00
|
|
|
* _mod_. If _inherit_ is set, the lookup will also search _mod_'s
|
|
|
|
* ancestors.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* def method1() end
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* protected
|
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* include A
|
|
|
|
* def method3() end
|
|
|
|
* end
|
|
|
|
*
|
2018-08-13 16:48:27 +03:00
|
|
|
* A.method_defined? :method1 #=> true
|
|
|
|
* C.public_method_defined? "method1" #=> true
|
|
|
|
* C.public_method_defined? "method1", true #=> true
|
|
|
|
* C.public_method_defined? "method1", false #=> true
|
|
|
|
* C.public_method_defined? "method2" #=> false
|
|
|
|
* C.method_defined? "method2" #=> true
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
2018-08-13 16:48:27 +03:00
|
|
|
return check_definition(mod, argc, argv, METHOD_VISI_PUBLIC);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-08-13 16:48:27 +03:00
|
|
|
* mod.private_method_defined?(symbol, inherit=true) -> true or false
|
|
|
|
* mod.private_method_defined?(string, inherit=true) -> true or false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Returns +true+ if the named private method is defined by
|
2018-08-13 16:48:27 +03:00
|
|
|
* _mod_. If _inherit_ is set, the lookup will also search _mod_'s
|
|
|
|
* ancestors.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* def method1() end
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* private
|
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* include A
|
|
|
|
* def method3() end
|
|
|
|
* end
|
|
|
|
*
|
2018-08-13 16:48:27 +03:00
|
|
|
* A.method_defined? :method1 #=> true
|
|
|
|
* C.private_method_defined? "method1" #=> false
|
|
|
|
* C.private_method_defined? "method2" #=> true
|
|
|
|
* C.private_method_defined? "method2", true #=> true
|
|
|
|
* C.private_method_defined? "method2", false #=> false
|
|
|
|
* C.method_defined? "method2" #=> false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
2018-08-13 16:48:27 +03:00
|
|
|
return check_definition(mod, argc, argv, METHOD_VISI_PRIVATE);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-08-13 16:48:27 +03:00
|
|
|
* mod.protected_method_defined?(symbol, inherit=true) -> true or false
|
|
|
|
* mod.protected_method_defined?(string, inherit=true) -> true or false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Returns +true+ if the named protected method is defined
|
2018-08-13 16:48:27 +03:00
|
|
|
* _mod_. If _inherit_ is set, the lookup will also search _mod_'s
|
|
|
|
* ancestors.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* def method1() end
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* protected
|
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* include A
|
|
|
|
* def method3() end
|
|
|
|
* end
|
|
|
|
*
|
2018-08-13 16:48:27 +03:00
|
|
|
* A.method_defined? :method1 #=> true
|
|
|
|
* C.protected_method_defined? "method1" #=> false
|
|
|
|
* C.protected_method_defined? "method2" #=> true
|
|
|
|
* C.protected_method_defined? "method2", true #=> true
|
|
|
|
* C.protected_method_defined? "method2", false #=> false
|
|
|
|
* C.method_defined? "method2" #=> true
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
2018-08-13 16:48:27 +03:00
|
|
|
return check_definition(mod, argc, argv, METHOD_VISI_PROTECTED);
|
2009-07-15 18:59:41 +04:00
|
|
|
}
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2009-07-15 18:59:41 +04:00
|
|
|
int
|
|
|
|
rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
|
|
|
|
{
|
2009-09-29 08:37:52 +04:00
|
|
|
return rb_method_definition_eq(m1->def, m2->def);
|
|
|
|
}
|
|
|
|
|
2015-05-30 21:45:28 +03:00
|
|
|
static const rb_method_definition_t *
|
|
|
|
original_method_definition(const rb_method_definition_t *def)
|
|
|
|
{
|
|
|
|
again:
|
|
|
|
if (def) {
|
|
|
|
switch (def->type) {
|
|
|
|
case VM_METHOD_TYPE_REFINED:
|
2015-06-04 01:27:51 +03:00
|
|
|
if (def->body.refined.orig_me) {
|
|
|
|
def = def->body.refined.orig_me->def;
|
2015-05-30 21:45:28 +03:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_ALIAS:
|
|
|
|
def = def->body.alias.original_me->def;
|
|
|
|
goto again;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED int
|
2009-09-29 08:37:52 +04:00
|
|
|
rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
|
|
|
|
{
|
2015-05-30 21:45:28 +03:00
|
|
|
d1 = original_method_definition(d1);
|
|
|
|
d2 = original_method_definition(d2);
|
|
|
|
|
2009-09-29 08:49:00 +04:00
|
|
|
if (d1 == d2) return 1;
|
|
|
|
if (!d1 || !d2) return 0;
|
2015-05-30 21:45:28 +03:00
|
|
|
if (d1->type != d2->type) return 0;
|
|
|
|
|
2009-08-28 06:45:41 +04:00
|
|
|
switch (d1->type) {
|
2009-07-15 18:59:41 +04:00
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
2015-06-02 17:32:33 +03:00
|
|
|
return d1->body.iseq.iseqptr == d2->body.iseq.iseqptr;
|
2009-07-15 18:59:41 +04:00
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
return
|
2009-08-28 06:45:41 +04:00
|
|
|
d1->body.cfunc.func == d2->body.cfunc.func &&
|
|
|
|
d1->body.cfunc.argc == d2->body.cfunc.argc;
|
2009-07-15 18:59:41 +04:00
|
|
|
case VM_METHOD_TYPE_ATTRSET:
|
|
|
|
case VM_METHOD_TYPE_IVAR:
|
2010-03-22 14:44:01 +03:00
|
|
|
return d1->body.attr.id == d2->body.attr.id;
|
2009-07-15 18:59:41 +04:00
|
|
|
case VM_METHOD_TYPE_BMETHOD:
|
2018-11-26 21:16:54 +03:00
|
|
|
return RTEST(rb_equal(d1->body.bmethod.proc, d2->body.bmethod.proc));
|
2009-09-28 07:09:16 +04:00
|
|
|
case VM_METHOD_TYPE_MISSING:
|
|
|
|
return d1->original_id == d2->original_id;
|
2009-07-15 18:59:41 +04:00
|
|
|
case VM_METHOD_TYPE_ZSUPER:
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
|
|
|
case VM_METHOD_TYPE_UNDEF:
|
|
|
|
return 1;
|
2009-08-06 10:44:10 +04:00
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:
|
2009-08-28 06:45:41 +04:00
|
|
|
return d1->body.optimize_type == d2->body.optimize_type;
|
2015-05-30 21:45:28 +03:00
|
|
|
case VM_METHOD_TYPE_REFINED:
|
|
|
|
case VM_METHOD_TYPE_ALIAS:
|
|
|
|
break;
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
2015-05-30 21:45:28 +03:00
|
|
|
rb_bug("rb_method_definition_eq: unsupported type: %d\n", d1->type);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
2012-02-21 04:13:44 +04:00
|
|
|
static st_index_t
|
|
|
|
rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
|
|
|
|
{
|
|
|
|
hash = rb_hash_uint(hash, def->type);
|
2015-05-30 21:45:28 +03:00
|
|
|
def = original_method_definition(def);
|
|
|
|
|
|
|
|
if (!def) return hash;
|
|
|
|
|
2012-02-21 04:13:44 +04:00
|
|
|
switch (def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
2015-06-02 17:32:33 +03:00
|
|
|
return rb_hash_uint(hash, (st_index_t)def->body.iseq.iseqptr);
|
2012-02-21 04:13:44 +04:00
|
|
|
case VM_METHOD_TYPE_CFUNC:
|
|
|
|
hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
|
|
|
|
return rb_hash_uint(hash, def->body.cfunc.argc);
|
|
|
|
case VM_METHOD_TYPE_ATTRSET:
|
|
|
|
case VM_METHOD_TYPE_IVAR:
|
|
|
|
return rb_hash_uint(hash, def->body.attr.id);
|
|
|
|
case VM_METHOD_TYPE_BMETHOD:
|
2018-11-26 21:16:39 +03:00
|
|
|
return rb_hash_proc(hash, def->body.bmethod.proc);
|
2012-02-21 04:13:44 +04:00
|
|
|
case VM_METHOD_TYPE_MISSING:
|
|
|
|
return rb_hash_uint(hash, def->original_id);
|
|
|
|
case VM_METHOD_TYPE_ZSUPER:
|
|
|
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
|
|
|
case VM_METHOD_TYPE_UNDEF:
|
|
|
|
return hash;
|
|
|
|
case VM_METHOD_TYPE_OPTIMIZED:
|
|
|
|
return rb_hash_uint(hash, def->body.optimize_type);
|
* 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 17:08:41 +04:00
|
|
|
case VM_METHOD_TYPE_REFINED:
|
2015-05-30 21:45:28 +03:00
|
|
|
case VM_METHOD_TYPE_ALIAS:
|
|
|
|
break; /* unreachable */
|
* 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 17:08:41 +04:00
|
|
|
}
|
2012-02-21 04:13:44 +04:00
|
|
|
rb_bug("rb_hash_method_definition: unsupported method type (%d)\n", def->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
st_index_t
|
2012-03-15 05:39:00 +04:00
|
|
|
rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me)
|
|
|
|
{
|
2012-02-21 04:13:44 +04:00
|
|
|
return rb_hash_method_definition(hash, me->def);
|
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
void
|
2015-06-02 18:06:29 +03:00
|
|
|
rb_alias(VALUE klass, ID alias_name, ID original_name)
|
2006-12-31 18:02:22 +03:00
|
|
|
{
|
2015-06-02 18:06:29 +03:00
|
|
|
const VALUE target_klass = klass;
|
2013-12-13 17:29:23 +04:00
|
|
|
VALUE defined_class;
|
2015-06-04 19:02:01 +03:00
|
|
|
const rb_method_entry_t *orig_me;
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_visibility_t visi = METHOD_VISI_UNDEF;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2009-11-17 17:53:32 +03:00
|
|
|
if (NIL_P(klass)) {
|
|
|
|
rb_raise(rb_eTypeError, "no class to make alias");
|
|
|
|
}
|
|
|
|
|
2018-07-27 16:57:14 +03:00
|
|
|
rb_class_modify_check(klass);
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2010-01-08 17:10:58 +03:00
|
|
|
again:
|
2015-06-02 18:06:29 +03:00
|
|
|
orig_me = search_method(klass, original_name, &defined_class);
|
2020-01-08 10:14:01 +03:00
|
|
|
|
2015-05-26 16:16:18 +03:00
|
|
|
if (orig_me && orig_me->def->type == VM_METHOD_TYPE_REFINED) {
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
orig_me = rb_resolve_refined_method(Qnil, orig_me);
|
2015-05-26 16:16:18 +03:00
|
|
|
}
|
2009-07-15 18:59:41 +04:00
|
|
|
|
2015-01-12 10:45:49 +03:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(orig_me) ||
|
2015-01-12 11:18:10 +03:00
|
|
|
UNDEFINED_REFINED_METHOD_P(orig_me->def)) {
|
2011-09-29 15:07:45 +04:00
|
|
|
if ((!RB_TYPE_P(klass, T_MODULE)) ||
|
2015-06-02 18:06:29 +03:00
|
|
|
(orig_me = search_method(rb_cObject, original_name, &defined_class),
|
2012-08-02 15:08:44 +04:00
|
|
|
UNDEFINED_METHOD_ENTRY_P(orig_me))) {
|
2016-01-03 07:59:54 +03:00
|
|
|
rb_print_undef(klass, original_name, METHOD_VISI_UNDEF);
|
2006-12-31 18:02:22 +03:00
|
|
|
}
|
|
|
|
}
|
2015-05-30 21:45:28 +03:00
|
|
|
|
2010-01-08 17:10:58 +03:00
|
|
|
if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) {
|
|
|
|
klass = RCLASS_SUPER(klass);
|
2015-06-02 18:06:29 +03:00
|
|
|
original_name = orig_me->def->original_id;
|
2015-06-06 13:19:48 +03:00
|
|
|
visi = METHOD_ENTRY_VISI(orig_me);
|
2010-01-08 17:10:58 +03:00
|
|
|
goto again;
|
|
|
|
}
|
2015-05-30 21:45:28 +03:00
|
|
|
|
2015-06-06 13:19:48 +03:00
|
|
|
if (visi == METHOD_VISI_UNDEF) visi = METHOD_ENTRY_VISI(orig_me);
|
2015-05-30 21:45:28 +03:00
|
|
|
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
if (orig_me->defined_class == 0) {
|
2016-03-08 18:29:48 +03:00
|
|
|
rb_method_entry_make(target_klass, alias_name, target_klass, visi,
|
|
|
|
VM_METHOD_TYPE_ALIAS, NULL, orig_me->called_id,
|
|
|
|
(void *)rb_method_entry_clone(orig_me));
|
|
|
|
method_added(target_klass, alias_name);
|
2015-05-30 21:45:28 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *alias_me;
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
|
|
|
|
alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner);
|
|
|
|
RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass);
|
2020-03-22 19:30:20 +03:00
|
|
|
RB_OBJ_WRITE(alias_me, &alias_me->defined_class, orig_me->defined_class);
|
2015-06-02 07:20:30 +03:00
|
|
|
}
|
2015-05-30 21:45:28 +03:00
|
|
|
}
|
2006-12-31 18:02:22 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* alias_method(new_name, old_name) -> self
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
|
|
|
|
* be used to retain access to methods that are overridden.
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* module Mod
|
|
|
|
* alias_method :orig_exit, :exit
|
|
|
|
* def exit(code=0)
|
|
|
|
* puts "Exiting with code #{code}"
|
|
|
|
* orig_exit(code)
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* include Mod
|
|
|
|
* exit(99)
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* <em>produces:</em>
|
* compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
pack.c, parse.y, re.c, thread.c, vm.c, vm_dump.c, call_cfunc.ci,
thread_pthread.ci, thread_win32.ci: fixed indentation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12431 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-06-05 08:25:10 +04:00
|
|
|
*
|
2006-12-31 18:02:22 +03:00
|
|
|
* Exiting with code 99
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
|
|
|
|
{
|
2011-07-26 20:05:35 +04:00
|
|
|
ID oldid = rb_check_id(&oldname);
|
|
|
|
if (!oldid) {
|
|
|
|
rb_print_undef_str(mod, oldname);
|
|
|
|
}
|
|
|
|
rb_alias(mod, rb_to_id(newname), oldid);
|
2006-12-31 18:02:22 +03:00
|
|
|
return mod;
|
|
|
|
}
|
2007-12-24 12:07:20 +03:00
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static void
|
2015-06-03 04:39:16 +03:00
|
|
|
set_method_visibility(VALUE self, int argc, const VALUE *argv, rb_method_visibility_t visi)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
|
|
|
int i;
|
2011-12-03 15:52:14 +04:00
|
|
|
|
2015-11-15 12:28:45 +03:00
|
|
|
rb_check_frozen(self);
|
2011-12-03 15:52:14 +04:00
|
|
|
if (argc == 0) {
|
2013-05-25 06:27:34 +04:00
|
|
|
rb_warning("%"PRIsVALUE" with no argument is just ignored",
|
|
|
|
QUOTE_ID(rb_frame_callee()));
|
2013-05-25 06:28:51 +04:00
|
|
|
return;
|
2011-12-03 15:52:14 +04:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
for (i = 0; i < argc; i++) {
|
2011-07-26 20:05:35 +04:00
|
|
|
VALUE v = argv[i];
|
|
|
|
ID id = rb_check_id(&v);
|
|
|
|
if (!id) {
|
|
|
|
rb_print_undef_str(self, v);
|
|
|
|
}
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_export_method(self, id, visi);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 06:58:45 +04:00
|
|
|
static VALUE
|
2015-06-03 04:39:16 +03:00
|
|
|
set_visibility(int argc, const VALUE *argv, VALUE module, rb_method_visibility_t visi)
|
2013-05-31 06:58:45 +04:00
|
|
|
{
|
|
|
|
if (argc == 0) {
|
2019-08-25 03:11:06 +03:00
|
|
|
scope_visibility_check();
|
|
|
|
rb_scope_visibility_set(visi);
|
2013-05-31 06:58:45 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-06-03 04:39:16 +03:00
|
|
|
set_method_visibility(module, argc, argv, visi);
|
2013-05-31 06:58:45 +04:00
|
|
|
}
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* public -> self
|
|
|
|
* public(symbol, ...) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* public(string, ...) -> self
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* With no arguments, sets the default visibility for subsequently
|
|
|
|
* defined methods to public. With arguments, sets the named methods to
|
|
|
|
* have public visibility.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_public(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
return set_visibility(argc, argv, module, METHOD_VISI_PUBLIC);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* protected -> self
|
|
|
|
* protected(symbol, ...) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* protected(string, ...) -> self
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* With no arguments, sets the default visibility for subsequently
|
|
|
|
* defined methods to protected. With arguments, sets the named methods
|
|
|
|
* to have protected visibility.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
2017-01-19 12:34:30 +03:00
|
|
|
*
|
|
|
|
* If a method has protected visibility, it is callable only where
|
|
|
|
* <code>self</code> of the context is the same as the method.
|
|
|
|
* (method definition or instance_eval). This behavior is different from
|
|
|
|
* Java's protected method. Usually <code>private</code> should be used.
|
|
|
|
*
|
|
|
|
* Note that a protected method is slow because it can't use inline cache.
|
|
|
|
*
|
|
|
|
* To show a private method on RDoc, use <code>:doc:</code> instead of this.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_protected(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
return set_visibility(argc, argv, module, METHOD_VISI_PROTECTED);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* private -> self
|
|
|
|
* private(symbol, ...) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* private(string, ...) -> self
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* With no arguments, sets the default visibility for subsequently
|
|
|
|
* defined methods to private. With arguments, sets the named methods
|
|
|
|
* to have private visibility.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module Mod
|
|
|
|
* def a() end
|
|
|
|
* def b() end
|
|
|
|
* private
|
|
|
|
* def c() end
|
|
|
|
* private :a
|
|
|
|
* end
|
|
|
|
* Mod.private_instance_methods #=> [:a, :c]
|
2017-01-19 12:34:30 +03:00
|
|
|
*
|
|
|
|
* Note that to show a private method on RDoc, use <code>:doc:</code>.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_private(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
return set_visibility(argc, argv, module, METHOD_VISI_PRIVATE);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ruby2_keywords(method_name, ...) -> self
|
|
|
|
*
|
|
|
|
* For the given method names, marks the method as passing keywords through
|
|
|
|
* a normal argument splat. This should only be called on methods that
|
|
|
|
* accept an argument splat (<tt>*args</tt>) but not explicit keywords or
|
|
|
|
* a keyword splat. It marks the method such that if the method is called
|
|
|
|
* with keyword arguments, the final hash argument is marked with a special
|
|
|
|
* flag such that if it is the final element of a normal argument splat to
|
2019-11-28 02:13:35 +03:00
|
|
|
* another method call, and that method call does not include explicit
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
* keywords or a keyword splat, the final element is interpreted as keywords.
|
|
|
|
* In other words, keywords will be passed through the method to other
|
|
|
|
* methods.
|
|
|
|
*
|
|
|
|
* This should only be used for methods that delegate keywords to another
|
|
|
|
* method, and only for backwards compatibility with Ruby versions before
|
|
|
|
* 2.7.
|
|
|
|
*
|
|
|
|
* This method will probably be removed at some point, as it exists only
|
2019-11-28 02:13:35 +03:00
|
|
|
* for backwards compatibility. As it does not exist in Ruby versions
|
|
|
|
* before 2.7, check that the module responds to this method before calling
|
|
|
|
* it. Also, be aware that if this method is removed, the behavior of the
|
|
|
|
* method will change so that it does not pass through keywords.
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
*
|
|
|
|
* module Mod
|
|
|
|
* def foo(meth, *args, &block)
|
|
|
|
* send(:"do_#{meth}", *args, &block)
|
|
|
|
* end
|
|
|
|
* ruby2_keywords(:foo) if respond_to?(:ruby2_keywords, true)
|
|
|
|
* end
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
VALUE origin_class = RCLASS_ORIGIN(module);
|
|
|
|
|
2020-01-02 04:06:16 +03:00
|
|
|
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
rb_check_frozen(module);
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
VALUE v = argv[i];
|
|
|
|
ID name = rb_check_id(&v);
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *me;
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
VALUE defined_class;
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
rb_print_undef_str(module, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
me = search_method(origin_class, name, &defined_class);
|
|
|
|
if (!me && RB_TYPE_P(module, T_MODULE)) {
|
|
|
|
me = search_method(rb_cObject, name, &defined_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me) ||
|
|
|
|
UNDEFINED_REFINED_METHOD_P(me->def)) {
|
|
|
|
rb_print_undef(module, name, METHOD_VISI_UNDEF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (module == defined_class || origin_class == defined_class) {
|
2019-10-07 07:18:20 +03:00
|
|
|
switch (me->def->type) {
|
|
|
|
case VM_METHOD_TYPE_ISEQ:
|
|
|
|
if (me->def->body.iseq.iseqptr->body->param.flags.has_rest &&
|
|
|
|
!me->def->body.iseq.iseqptr->body->param.flags.has_kw &&
|
|
|
|
!me->def->body.iseq.iseqptr->body->param.flags.has_kwrest) {
|
|
|
|
me->def->body.iseq.iseqptr->body->param.flags.ruby2_keywords = 1;
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(module, name);
|
2019-10-07 07:18:20 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_warn("Skipping set of ruby2_keywords flag for %s (method accepts keywords or method does not accept argument splat)", rb_id2name(name));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VM_METHOD_TYPE_BMETHOD: {
|
|
|
|
VALUE procval = me->def->body.bmethod.proc;
|
|
|
|
if (vm_block_handler_type(procval) == block_handler_type_proc) {
|
|
|
|
procval = vm_proc_to_block_handler(VM_BH_TO_PROC(procval));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm_block_handler_type(procval) == block_handler_type_iseq) {
|
|
|
|
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
|
|
|
|
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
|
|
|
|
if (iseq->body->param.flags.has_rest &&
|
|
|
|
!iseq->body->param.flags.has_kw &&
|
|
|
|
!iseq->body->param.flags.has_kwrest) {
|
|
|
|
iseq->body->param.flags.ruby2_keywords = 1;
|
2020-01-08 10:14:01 +03:00
|
|
|
rb_clear_method_cache(module, name);
|
2019-10-07 07:18:20 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_warn("Skipping set of ruby2_keywords flag for %s (method accepts keywords or method does not accept argument splat)", rb_id2name(name));
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
default:
|
|
|
|
rb_warn("Skipping set of ruby2_keywords flag for %s (method not defined in Ruby)", rb_id2name(name));
|
|
|
|
break;
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_warn("Skipping set of ruby2_keywords flag for %s (can only set in method defining module)", rb_id2name(name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.public_class_method(symbol, ...) -> mod
|
2013-02-24 08:24:52 +04:00
|
|
|
* mod.public_class_method(string, ...) -> mod
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Makes a list of existing class methods public.
|
2013-02-24 08:24:52 +04:00
|
|
|
*
|
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
|
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PUBLIC);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* mod.private_class_method(symbol, ...) -> mod
|
2013-02-24 08:24:52 +04:00
|
|
|
* mod.private_class_method(string, ...) -> mod
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Makes existing class methods private. Often used to hide the default
|
|
|
|
* constructor <code>new</code>.
|
|
|
|
*
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
|
|
|
*
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
* class SimpleSingleton # Not thread safe
|
|
|
|
* private_class_method :new
|
|
|
|
* def SimpleSingleton.create(*args, &block)
|
|
|
|
* @me = new(*args, &block) if ! @me
|
|
|
|
* @me
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
|
|
|
|
{
|
2015-06-03 04:39:16 +03:00
|
|
|
set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PRIVATE);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* public
|
|
|
|
* public(symbol, ...)
|
2013-02-24 08:24:52 +04:00
|
|
|
* public(string, ...)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* With no arguments, sets the default visibility for subsequently
|
|
|
|
* defined methods to public. With arguments, sets the named methods to
|
|
|
|
* have public visibility.
|
2013-02-24 08:24:52 +04:00
|
|
|
*
|
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2019-08-29 04:57:48 +03:00
|
|
|
top_public(int argc, VALUE *argv, VALUE _)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
|
|
|
return rb_mod_public(argc, argv, rb_cObject);
|
|
|
|
}
|
|
|
|
|
2013-06-06 06:27:23 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* private
|
|
|
|
* private(symbol, ...)
|
|
|
|
* private(string, ...)
|
|
|
|
*
|
|
|
|
* With no arguments, sets the default visibility for subsequently
|
|
|
|
* defined methods to private. With arguments, sets the named methods to
|
|
|
|
* have private visibility.
|
|
|
|
*
|
|
|
|
* String arguments are converted to symbols.
|
|
|
|
*/
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
static VALUE
|
2019-08-29 04:57:48 +03:00
|
|
|
top_private(int argc, VALUE *argv, VALUE _)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
|
|
|
return rb_mod_private(argc, argv, rb_cObject);
|
|
|
|
}
|
|
|
|
|
2019-11-29 10:51:13 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* ruby2_keywords(method_name, ...) -> self
|
|
|
|
*
|
|
|
|
* For the given method names, marks the method as passing keywords through
|
|
|
|
* a normal argument splat. See Module#ruby2_keywords in detail.
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
top_ruby2_keywords(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
|
|
|
return rb_mod_ruby2_keywords(argc, argv, rb_cObject);
|
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* module_function(symbol, ...) -> self
|
2013-02-24 08:24:52 +04:00
|
|
|
* module_function(string, ...) -> self
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* Creates module functions for the named methods. These functions may
|
|
|
|
* be called with the module as a receiver, and also become available
|
|
|
|
* as instance methods to classes that mix in the module. Module
|
|
|
|
* functions are copies of the original, and so may be changed
|
|
|
|
* independently. The instance-method versions are made private. If
|
|
|
|
* used with no arguments, subsequently defined methods become module
|
|
|
|
* functions.
|
2013-02-24 08:24:52 +04:00
|
|
|
* String arguments are converted to symbols.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
|
|
|
* module Mod
|
|
|
|
* def one
|
|
|
|
* "This is one"
|
|
|
|
* end
|
|
|
|
* module_function :one
|
|
|
|
* end
|
|
|
|
* class Cls
|
|
|
|
* include Mod
|
2011-03-07 11:44:45 +03:00
|
|
|
* def call_one
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
* one
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* Mod.one #=> "This is one"
|
|
|
|
* c = Cls.new
|
2011-03-07 11:44:45 +03:00
|
|
|
* c.call_one #=> "This is one"
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
* module Mod
|
|
|
|
* def one
|
|
|
|
* "This is the new one"
|
|
|
|
* end
|
|
|
|
* end
|
|
|
|
* Mod.one #=> "This is one"
|
2011-03-07 11:44:45 +03:00
|
|
|
* c.call_one #=> "This is the new one"
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
ID id;
|
2009-07-15 18:59:41 +04:00
|
|
|
const rb_method_entry_t *me;
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(module, T_MODULE)) {
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
rb_raise(rb_eTypeError, "module_function must be called for modules");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 0) {
|
2015-06-03 17:07:24 +03:00
|
|
|
rb_scope_module_func_set();
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2015-06-03 04:39:16 +03:00
|
|
|
set_method_visibility(module, argc, argv, METHOD_VISI_PRIVATE);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
VALUE m = module;
|
|
|
|
|
|
|
|
id = rb_to_id(argv[i]);
|
|
|
|
for (;;) {
|
* 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 17:08:41 +04:00
|
|
|
me = search_method(m, id, 0);
|
2009-07-15 18:59:41 +04:00
|
|
|
if (me == 0) {
|
* 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 17:08:41 +04:00
|
|
|
me = search_method(rb_cObject, id, 0);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
2009-08-28 06:45:41 +04:00
|
|
|
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
2016-01-03 07:59:54 +03:00
|
|
|
rb_print_undef(module, id, METHOD_VISI_UNDEF);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
2009-08-28 06:45:41 +04:00
|
|
|
if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
|
2009-07-15 18:59:41 +04:00
|
|
|
break; /* normal case: need not to follow 'super' link */
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
m = RCLASS_SUPER(m);
|
|
|
|
if (!m)
|
|
|
|
break;
|
|
|
|
}
|
2015-06-03 04:39:16 +03:00
|
|
|
rb_method_entry_set(rb_singleton_class(module), id, me, METHOD_VISI_PUBLIC);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2019-10-29 05:37:25 +03:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma push_macro("rb_method_basic_definition_p")
|
|
|
|
#undef rb_method_basic_definition_p
|
|
|
|
#endif
|
2008-08-04 22:29:55 +04:00
|
|
|
int
|
|
|
|
rb_method_basic_definition_p(VALUE klass, ID id)
|
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_callable_method_entry_t *cme;
|
2016-02-24 05:38:43 +03:00
|
|
|
if (!klass) return TRUE; /* hidden object cannot be overridden */
|
2020-01-08 10:14:01 +03:00
|
|
|
cme = rb_callable_method_entry(klass, id);
|
|
|
|
return (cme && METHOD_ENTRY_BASIC(cme)) ? TRUE : FALSE;
|
2008-08-04 22:29:55 +04:00
|
|
|
}
|
2019-10-29 05:37:25 +03:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma pop_macro("rb_method_basic_definition_p")
|
|
|
|
#endif
|
2008-08-04 22:29:55 +04:00
|
|
|
|
2015-08-20 16:19:21 +03:00
|
|
|
static VALUE
|
2017-10-28 15:23:51 +03:00
|
|
|
call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID id,
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_callable_method_entry_t *cme, int argc, const VALUE *argv, int kw_splat)
|
2015-08-20 16:19:21 +03:00
|
|
|
{
|
2017-10-28 15:23:51 +03:00
|
|
|
VALUE passed_block_handler = vm_passed_block_handler(ec);
|
2019-09-19 01:30:59 +03:00
|
|
|
VALUE result = rb_vm_call_kw(ec, obj, id, argc, argv, cme, kw_splat);
|
2017-10-28 15:23:51 +03:00
|
|
|
vm_passed_block_handler_set(ec, passed_block_handler);
|
2015-08-20 16:19:21 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2017-10-28 15:23:51 +03:00
|
|
|
basic_obj_respond_to_missing(rb_execution_context_t *ec, VALUE klass, VALUE obj,
|
2015-08-20 16:19:21 +03:00
|
|
|
VALUE mid, VALUE priv)
|
|
|
|
{
|
|
|
|
VALUE defined_class, args[2];
|
|
|
|
const ID rtmid = idRespond_to_missing;
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_callable_method_entry_t *const cme = callable_method_entry(klass, rtmid, &defined_class);
|
2015-08-20 16:19:21 +03:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (!cme || METHOD_ENTRY_BASIC(cme)) return Qundef;
|
2015-08-20 16:19:21 +03:00
|
|
|
args[0] = mid;
|
|
|
|
args[1] = priv;
|
2020-01-08 10:14:01 +03:00
|
|
|
return call_method_entry(ec, defined_class, obj, rtmid, cme, 2, args, RB_NO_KEYWORDS);
|
2015-08-20 16:19:21 +03:00
|
|
|
}
|
|
|
|
|
2009-09-23 12:46:44 +04:00
|
|
|
static inline int
|
2017-10-28 15:23:51 +03:00
|
|
|
basic_obj_respond_to(rb_execution_context_t *ec, VALUE obj, ID id, int pub)
|
2009-09-23 12:46:44 +04:00
|
|
|
{
|
|
|
|
VALUE klass = CLASS_OF(obj);
|
2015-08-22 09:43:14 +03:00
|
|
|
VALUE ret;
|
2009-09-23 12:46:44 +04:00
|
|
|
|
2015-06-03 04:39:16 +03:00
|
|
|
switch (rb_method_boundp(klass, id, pub|BOUND_RESPONDS)) {
|
2009-10-04 21:05:59 +04:00
|
|
|
case 2:
|
2009-09-25 06:51:36 +04:00
|
|
|
return FALSE;
|
2009-10-04 21:05:59 +04:00
|
|
|
case 0:
|
2017-10-28 15:23:51 +03:00
|
|
|
ret = basic_obj_respond_to_missing(ec, klass, obj, ID2SYM(id),
|
2015-08-22 09:43:14 +03:00
|
|
|
pub ? Qfalse : Qtrue);
|
|
|
|
return RTEST(ret) && ret != Qundef;
|
2009-10-04 21:05:59 +04:00
|
|
|
default:
|
|
|
|
return TRUE;
|
2009-09-23 12:46:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 08:13:28 +03:00
|
|
|
static int
|
2017-10-28 15:23:51 +03:00
|
|
|
vm_respond_to(rb_execution_context_t *ec, VALUE klass, VALUE obj, ID id, int priv)
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
{
|
2015-08-20 02:53:12 +03:00
|
|
|
VALUE defined_class;
|
|
|
|
const ID resid = idRespond_to;
|
2020-01-08 10:14:01 +03:00
|
|
|
const rb_callable_method_entry_t *const cme = callable_method_entry(klass, resid, &defined_class);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
if (!cme) return -1;
|
|
|
|
if (METHOD_ENTRY_BASIC(cme)) {
|
2015-08-22 09:43:14 +03:00
|
|
|
return -1;
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-02-05 11:25:27 +04:00
|
|
|
int argc = 1;
|
|
|
|
VALUE args[2];
|
2015-08-20 08:13:28 +03:00
|
|
|
VALUE result;
|
2015-08-20 02:53:12 +03:00
|
|
|
|
2013-02-05 11:25:27 +04:00
|
|
|
args[0] = ID2SYM(id);
|
|
|
|
args[1] = Qtrue;
|
|
|
|
if (priv) {
|
2020-01-08 10:14:01 +03:00
|
|
|
argc = rb_method_entry_arity((const rb_method_entry_t *)cme);
|
2015-08-20 08:13:28 +03:00
|
|
|
if (argc > 2) {
|
|
|
|
rb_raise(rb_eArgError,
|
|
|
|
"respond_to? must accept 1 or 2 arguments (requires %d)",
|
|
|
|
argc);
|
|
|
|
}
|
|
|
|
if (argc != 1) {
|
2013-02-05 11:25:27 +04:00
|
|
|
argc = 2;
|
|
|
|
}
|
2013-02-06 08:35:23 +04:00
|
|
|
else if (!NIL_P(ruby_verbose)) {
|
2020-01-08 10:14:01 +03:00
|
|
|
VALUE location = rb_method_entry_location((const rb_method_entry_t *)cme);
|
2016-01-19 03:39:12 +03:00
|
|
|
rb_warn("%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") uses"
|
|
|
|
" the deprecated method signature, which takes one parameter",
|
2013-02-05 11:25:27 +04:00
|
|
|
(FL_TEST(klass, FL_SINGLETON) ? obj : klass),
|
|
|
|
(FL_TEST(klass, FL_SINGLETON) ? '.' : '#'),
|
|
|
|
QUOTE_ID(id));
|
2013-02-06 08:35:23 +04:00
|
|
|
if (!NIL_P(location)) {
|
2013-05-13 13:56:22 +04:00
|
|
|
VALUE path = RARRAY_AREF(location, 0);
|
|
|
|
VALUE line = RARRAY_AREF(location, 1);
|
2013-02-06 08:35:23 +04:00
|
|
|
if (!NIL_P(path)) {
|
|
|
|
rb_compile_warn(RSTRING_PTR(path), NUM2INT(line),
|
|
|
|
"respond_to? is defined here");
|
|
|
|
}
|
|
|
|
}
|
2013-02-05 11:25:27 +04:00
|
|
|
}
|
|
|
|
}
|
2020-01-08 10:14:01 +03:00
|
|
|
result = call_method_entry(ec, defined_class, obj, resid, cme, argc, args, RB_NO_KEYWORDS);
|
2015-08-20 08:13:28 +03:00
|
|
|
return RTEST(result);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 08:13:28 +03:00
|
|
|
int
|
|
|
|
rb_obj_respond_to(VALUE obj, ID id, int priv)
|
|
|
|
{
|
2017-10-28 15:23:51 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
2020-06-03 17:06:06 +03:00
|
|
|
return rb_ec_obj_respond_to(ec, obj, id, priv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_ec_obj_respond_to(rb_execution_context_t *ec, VALUE obj, ID id, int priv)
|
|
|
|
{
|
2015-08-22 09:43:14 +03:00
|
|
|
VALUE klass = CLASS_OF(obj);
|
2017-10-28 15:23:51 +03:00
|
|
|
int ret = vm_respond_to(ec, klass, obj, id, priv);
|
|
|
|
if (ret == -1) ret = basic_obj_respond_to(ec, obj, id, !priv);
|
2015-08-22 09:43:14 +03:00
|
|
|
return ret;
|
2015-08-20 08:13:28 +03:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
int
|
|
|
|
rb_respond_to(VALUE obj, ID id)
|
|
|
|
{
|
* compile.c, cont.c, gc.c, insns.def, iseq.c, iseq.h, process.c,
thread.c, vm.c, vm_core.h, vm_dump.c, vm_eval.c,
vm_insnhelper.c, vm_method.c, template/insns_info.inc.tmpl,
tool/instruction.rb: fixed types.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-09-22 00:58:26 +04:00
|
|
|
return rb_obj_respond_to(obj, id, FALSE);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
}
|
|
|
|
|
2009-09-23 12:46:44 +04:00
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-02-13 18:02:26 +04:00
|
|
|
* obj.respond_to?(symbol, include_all=false) -> true or false
|
2013-02-24 08:24:52 +04:00
|
|
|
* obj.respond_to?(string, include_all=false) -> true or false
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*
|
2012-02-13 18:02:26 +04:00
|
|
|
* Returns +true+ if _obj_ responds to the given method. Private and
|
|
|
|
* protected methods are included in the search only if the optional
|
|
|
|
* second parameter evaluates to +true+.
|
2009-04-21 22:41:07 +04:00
|
|
|
*
|
|
|
|
* If the method is not implemented,
|
|
|
|
* as Process.fork on Windows, File.lchmod on GNU/Linux, etc.,
|
|
|
|
* false is returned.
|
2009-09-25 07:33:26 +04:00
|
|
|
*
|
|
|
|
* If the method is not defined, <code>respond_to_missing?</code>
|
|
|
|
* method is called and the result is returned.
|
2013-02-24 08:24:52 +04:00
|
|
|
*
|
|
|
|
* When the method name parameter is given as a string, the string is
|
|
|
|
* converted to a symbol.
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
obj_respond_to(int argc, VALUE *argv, VALUE obj)
|
|
|
|
{
|
|
|
|
VALUE mid, priv;
|
|
|
|
ID id;
|
2017-10-28 15:23:51 +03:00
|
|
|
rb_execution_context_t *ec = GET_EC();
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "11", &mid, &priv);
|
2014-07-09 10:14:41 +04:00
|
|
|
if (!(id = rb_check_id(&mid))) {
|
2017-10-28 15:23:51 +03:00
|
|
|
VALUE ret = basic_obj_respond_to_missing(ec, CLASS_OF(obj), obj,
|
2015-08-22 09:43:14 +03:00
|
|
|
rb_to_symbol(mid), priv);
|
|
|
|
if (ret == Qundef) ret = Qfalse;
|
|
|
|
return ret;
|
2011-07-26 20:05:30 +04:00
|
|
|
}
|
2017-10-28 15:23:51 +03:00
|
|
|
if (basic_obj_respond_to(ec, obj, id, !RTEST(priv)))
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
return Qtrue;
|
2009-09-23 12:46:44 +04:00
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2009-09-25 07:33:26 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2012-02-13 18:02:26 +04:00
|
|
|
* obj.respond_to_missing?(symbol, include_all) -> true or false
|
2013-02-24 08:24:52 +04:00
|
|
|
* obj.respond_to_missing?(string, include_all) -> true or false
|
2009-09-25 07:33:26 +04:00
|
|
|
*
|
2012-12-01 17:54:54 +04:00
|
|
|
* DO NOT USE THIS DIRECTLY.
|
|
|
|
*
|
2009-09-25 07:33:26 +04:00
|
|
|
* Hook method to return whether the _obj_ can respond to _id_ method
|
|
|
|
* or not.
|
|
|
|
*
|
2013-02-24 08:24:52 +04:00
|
|
|
* When the method name parameter is given as a string, the string is
|
|
|
|
* converted to a symbol.
|
|
|
|
*
|
2013-08-31 08:30:18 +04:00
|
|
|
* See #respond_to?, and the example of BasicObject.
|
2009-09-25 07:33:26 +04:00
|
|
|
*/
|
2009-09-23 12:46:44 +04:00
|
|
|
static VALUE
|
2011-07-22 13:33:41 +04:00
|
|
|
obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
|
2009-09-23 12:46:44 +04:00
|
|
|
{
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2014-09-18 04:36:37 +04:00
|
|
|
void
|
|
|
|
Init_Method(void)
|
|
|
|
{
|
2020-01-08 10:14:01 +03:00
|
|
|
//
|
2014-09-18 04:36:37 +04:00
|
|
|
}
|
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
void
|
2007-12-24 12:07:20 +03:00
|
|
|
Init_eval_method(void)
|
|
|
|
{
|
2008-06-09 13:25:32 +04:00
|
|
|
#undef rb_intern
|
2008-08-16 04:20:31 +04:00
|
|
|
#define rb_intern(str) rb_intern_const(str)
|
2008-06-09 13:25:32 +04:00
|
|
|
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
|
2009-10-17 09:34:51 +04:00
|
|
|
rb_define_method(rb_mKernel, "respond_to_missing?", obj_respond_to_missing, 2);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2017-11-29 20:47:59 +03:00
|
|
|
rb_define_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
|
|
|
|
rb_define_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
|
|
|
|
rb_define_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
|
|
|
|
rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
|
|
|
|
rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
|
|
|
|
rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
|
Add Module#ruby2_keywords for passing keywords through regular argument splats
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
2019-09-21 19:03:36 +03:00
|
|
|
rb_define_private_method(rb_cModule, "ruby2_keywords", rb_mod_ruby2_keywords, -1);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2018-08-13 16:48:27 +03:00
|
|
|
rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, -1);
|
|
|
|
rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, -1);
|
|
|
|
rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, -1);
|
|
|
|
rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, -1);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
|
|
|
|
rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
|
|
|
|
|
2013-01-07 16:42:48 +04:00
|
|
|
rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
|
|
|
|
"public", top_public, -1);
|
|
|
|
rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
|
|
|
|
"private", top_private, -1);
|
2019-11-29 10:51:13 +03:00
|
|
|
rb_define_private_method(rb_singleton_class(rb_vm_top_self()),
|
|
|
|
"ruby2_keywords", top_ruby2_keywords, -1);
|
* eval_method.c: renamed from vm_method.c. "vm_method.c" is included
by "vm.c".
* vm_eval.c: added. Some codes are moved from "eval.c"
* common.mk: fix for above changes.
* compile.c: make a vm_eval(0)
* eval.c, eval_error.c, eval_intern.h, eval_jump.c, proc.c, vm.c,
id.c, id.h, vm_core.h, vm_dump.c, vm_evalbody.c, vm_insnhelper.c,
blockinlining.c: fix for above changes. and do some refactoring.
this changes improve rb_yield() performance.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-24 21:50:17 +04:00
|
|
|
|
2012-03-12 07:44:40 +04:00
|
|
|
{
|
2015-07-01 11:17:58 +03:00
|
|
|
#define REPLICATE_METHOD(klass, id) do { \
|
* method.h: introduce rb_callable_method_entry_t to remove
rb_control_frame_t::klass.
[Bug #11278], [Bug #11279]
rb_method_entry_t data belong to modules/classes.
rb_method_entry_t::owner points defined module or class.
module M
def foo; end
end
In this case, owner is M.
rb_callable_method_entry_t data belong to only classes.
For modules, MRI creates corresponding T_ICLASS internally.
rb_callable_method_entry_t can also belong to T_ICLASS.
rb_callable_method_entry_t::defined_class points T_CLASS or
T_ICLASS.
rb_method_entry_t data for classes (not for modules) are also
rb_callable_method_entry_t data because it is completely same data.
In this case, rb_method_entry_t::owner == rb_method_entry_t::defined_class.
For example, there are classes C and D, and incldues M,
class C; include M; end
class D; include M; end
then, two T_ICLASS objects for C's super class and D's super class
will be created.
When C.new.foo is called, then M#foo is searcheed and
rb_callable_method_t data is used by VM to invoke M#foo.
rb_method_entry_t data is only one for M#foo.
However, rb_callable_method_entry_t data are two (and can be more).
It is proportional to the number of including (and prepending)
classes (the number of T_ICLASS which point to the module).
Now, created rb_callable_method_entry_t are collected when
the original module M was modified. We can think it is a cache.
We need to select what kind of method entry data is needed.
To operate definition, then you need to use rb_method_entry_t.
You can access them by the following functions.
* rb_method_entry(VALUE klass, ID id);
* rb_method_entry_with_refinements(VALUE klass, ID id);
* rb_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
To invoke methods, then you need to use rb_callable_method_entry_t
which you can get by the following APIs corresponding to the
above listed functions.
* rb_callable_method_entry(VALUE klass, ID id);
* rb_callable_method_entry_with_refinements(VALUE klass, ID id);
* rb_callable_method_entry_without_refinements(VALUE klass, ID id);
* rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
VM pushes rb_callable_method_entry_t, so that rb_vm_frame_method_entry()
returns rb_callable_method_entry_t.
You can check a super class of current method by
rb_callable_method_entry_t::defined_class.
* method.h: renamed from rb_method_entry_t::klass to
rb_method_entry_t::owner.
* internal.h: add rb_classext_struct::callable_m_tbl to cache
rb_callable_method_entry_t data.
We need to consider abotu this field again because it is only
active for T_ICLASS.
* class.c (method_entry_i): ditto.
* class.c (rb_define_attr): rb_method_entry() does not takes
defiend_class_ptr.
* gc.c (mark_method_entry): mark RCLASS_CALLABLE_M_TBL() for T_ICLASS.
* cont.c (fiber_init): rb_control_frame_t::klass is removed.
* proc.c: fix `struct METHOD' data structure because
rb_callable_method_t has all information.
* vm_core.h: remove several fields.
* rb_control_frame_t::klass.
* rb_block_t::klass.
And catch up changes.
* eval.c: catch up changes.
* gc.c: ditto.
* insns.def: ditto.
* vm.c: ditto.
* vm_args.c: ditto.
* vm_backtrace.c: ditto.
* vm_dump.c: ditto.
* vm_eval.c: ditto.
* vm_insnhelper.c: ditto.
* vm_method.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-07-03 14:24:50 +03:00
|
|
|
const rb_method_entry_t *me = rb_method_entry((klass), (id)); \
|
2015-07-01 11:17:58 +03:00
|
|
|
rb_method_entry_set((klass), (id), me, METHOD_ENTRY_VISI(me)); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
REPLICATE_METHOD(rb_eException, idMethodMissing);
|
|
|
|
REPLICATE_METHOD(rb_eException, idRespond_to);
|
|
|
|
REPLICATE_METHOD(rb_eException, idRespond_to_missing);
|
2012-03-12 07:44:40 +04:00
|
|
|
}
|
2007-12-24 12:07:20 +03:00
|
|
|
}
|