2020-04-10 08:11:40 +03:00
|
|
|
#ifndef RUBY_METHOD_H
|
|
|
|
#define RUBY_METHOD_H 1
|
2009-07-16 04:37:25 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
method.h -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Wed Jul 15 20:02:33 2009
|
|
|
|
|
|
|
|
Copyright (C) 2009 Koichi Sasada
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
* 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
|
|
|
#include "internal.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/imemo.h"
|
|
|
|
#include "internal/compilers.h"
|
|
|
|
#include "internal/static_assert.h"
|
* 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
|
|
|
|
2012-12-13 07:50:19 +04:00
|
|
|
#ifndef END_OF_ENUMERATION
|
2013-10-22 16:59:27 +04:00
|
|
|
# if defined(__GNUC__) &&! defined(__STRICT_ANSI__)
|
2012-12-13 07:50:19 +04:00
|
|
|
# define END_OF_ENUMERATION(key)
|
|
|
|
# else
|
|
|
|
# define END_OF_ENUMERATION(key) END_OF_##key##_PLACEHOLDER = 0
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2015-06-05 14:42:34 +03:00
|
|
|
/* cref */
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
METHOD_VISI_UNDEF = 0x00,
|
|
|
|
METHOD_VISI_PUBLIC = 0x01,
|
|
|
|
METHOD_VISI_PRIVATE = 0x02,
|
2015-10-28 09:24:12 +03:00
|
|
|
METHOD_VISI_PROTECTED = 0x03,
|
|
|
|
|
|
|
|
METHOD_VISI_MASK = 0x03
|
2015-06-05 14:42:34 +03:00
|
|
|
} rb_method_visibility_t;
|
|
|
|
|
|
|
|
typedef struct rb_scope_visi_struct {
|
2018-08-22 07:04:06 +03:00
|
|
|
BITFIELD(rb_method_visibility_t, method_visi, 3);
|
2015-06-05 14:42:34 +03:00
|
|
|
unsigned int module_func : 1;
|
|
|
|
} rb_scope_visibility_t;
|
|
|
|
|
2017-10-21 17:31:21 +03:00
|
|
|
/*! CREF (Class REFerence) */
|
2015-06-05 14:42:34 +03:00
|
|
|
typedef struct rb_cref_struct {
|
|
|
|
VALUE flags;
|
2019-04-20 04:19:47 +03:00
|
|
|
VALUE refinements;
|
2021-12-03 02:53:39 +03:00
|
|
|
VALUE klass_or_self;
|
2019-04-20 04:19:47 +03:00
|
|
|
struct rb_cref_struct * next;
|
2015-11-13 20:20:11 +03:00
|
|
|
const rb_scope_visibility_t scope_visi;
|
2015-06-05 14:42:34 +03:00
|
|
|
} rb_cref_t;
|
|
|
|
|
2009-07-16 04:37:25 +04:00
|
|
|
/* method data type */
|
|
|
|
|
2015-06-02 07:20:30 +03:00
|
|
|
typedef struct rb_method_entry_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
VALUE flags;
|
|
|
|
VALUE defined_class;
|
2015-06-02 07:20:30 +03:00
|
|
|
struct rb_method_definition_struct * const def;
|
2019-10-03 06:26:41 +03:00
|
|
|
ID called_id;
|
|
|
|
VALUE owner;
|
2015-06-02 07:20:30 +03:00
|
|
|
} 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
|
|
|
typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */
|
2019-10-03 06:26:41 +03:00
|
|
|
VALUE flags;
|
* 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 VALUE defined_class;
|
|
|
|
struct rb_method_definition_struct * const def;
|
2019-10-03 06:26:41 +03:00
|
|
|
ID called_id;
|
* 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 VALUE owner;
|
|
|
|
} rb_callable_method_entry_t;
|
|
|
|
|
2015-06-11 02:55:33 +03:00
|
|
|
#define METHOD_ENTRY_VISI(me) (rb_method_visibility_t)(((me)->flags & (IMEMO_FL_USER0 | IMEMO_FL_USER1)) >> (IMEMO_FL_USHIFT+0))
|
|
|
|
#define METHOD_ENTRY_BASIC(me) (int) (((me)->flags & (IMEMO_FL_USER2 )) >> (IMEMO_FL_USHIFT+2))
|
2020-01-08 10:14:01 +03:00
|
|
|
#define METHOD_ENTRY_COMPLEMENTED(me) ((me)->flags & IMEMO_FL_USER3)
|
2020-06-03 02:21:22 +03:00
|
|
|
#define METHOD_ENTRY_COMPLEMENTED_SET(me) ((me)->flags |= IMEMO_FL_USER3)
|
2020-01-08 10:14:01 +03:00
|
|
|
#define METHOD_ENTRY_CACHED(me) ((me)->flags & IMEMO_FL_USER4)
|
2020-06-03 02:21:22 +03:00
|
|
|
#define METHOD_ENTRY_CACHED_SET(me) ((me)->flags |= IMEMO_FL_USER4)
|
2020-01-08 10:14:01 +03:00
|
|
|
#define METHOD_ENTRY_INVALIDATED(me) ((me)->flags & IMEMO_FL_USER5)
|
2020-06-03 02:21:22 +03:00
|
|
|
#define METHOD_ENTRY_INVALIDATED_SET(me) ((me)->flags |= IMEMO_FL_USER5)
|
2019-10-03 06:26:41 +03:00
|
|
|
|
|
|
|
static inline void
|
|
|
|
METHOD_ENTRY_VISI_SET(rb_method_entry_t *me, rb_method_visibility_t visi)
|
|
|
|
{
|
|
|
|
VM_ASSERT((int)visi >= 0 && visi <= 3);
|
|
|
|
me->flags = (me->flags & ~(IMEMO_FL_USER0 | IMEMO_FL_USER1)) | (visi << (IMEMO_FL_USHIFT+0));
|
|
|
|
}
|
|
|
|
static inline void
|
|
|
|
METHOD_ENTRY_BASIC_SET(rb_method_entry_t *me, unsigned int basic)
|
|
|
|
{
|
|
|
|
VM_ASSERT(basic <= 1);
|
|
|
|
me->flags = (me->flags & ~(IMEMO_FL_USER2 )) | (basic << (IMEMO_FL_USHIFT+2));
|
|
|
|
}
|
|
|
|
static inline void
|
|
|
|
METHOD_ENTRY_FLAGS_SET(rb_method_entry_t *me, rb_method_visibility_t visi, unsigned int basic)
|
|
|
|
{
|
|
|
|
VM_ASSERT((int)visi >= 0 && visi <= 3);
|
|
|
|
VM_ASSERT(basic <= 1);
|
|
|
|
me->flags =
|
|
|
|
(me->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) |
|
2019-10-03 06:48:20 +03:00
|
|
|
((visi << (IMEMO_FL_USHIFT+0)) | (basic << (IMEMO_FL_USHIFT+2)));
|
2019-10-03 06:26:41 +03:00
|
|
|
}
|
|
|
|
static inline void
|
|
|
|
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
|
|
|
{
|
|
|
|
dst->flags =
|
2023-09-20 03:48:41 +03:00
|
|
|
(dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2
|
|
|
|
|IMEMO_FL_USER3)) |
|
|
|
|
(src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3));
|
2019-10-03 06:26:41 +03:00
|
|
|
}
|
2015-06-11 02:55:33 +03:00
|
|
|
|
2009-07-16 04:37:25 +04:00
|
|
|
typedef enum {
|
2017-10-21 17:31:21 +03:00
|
|
|
VM_METHOD_TYPE_ISEQ, /*!< Ruby method */
|
|
|
|
VM_METHOD_TYPE_CFUNC, /*!< C method */
|
|
|
|
VM_METHOD_TYPE_ATTRSET, /*!< attr_writer or attr_accessor */
|
|
|
|
VM_METHOD_TYPE_IVAR, /*!< attr_reader or attr_accessor */
|
2009-07-16 04:37:25 +04:00
|
|
|
VM_METHOD_TYPE_BMETHOD,
|
|
|
|
VM_METHOD_TYPE_ZSUPER,
|
2015-05-30 21:45:28 +03:00
|
|
|
VM_METHOD_TYPE_ALIAS,
|
2009-07-16 04:37:25 +04:00
|
|
|
VM_METHOD_TYPE_UNDEF,
|
|
|
|
VM_METHOD_TYPE_NOTIMPLEMENTED,
|
2017-10-21 17:31:21 +03:00
|
|
|
VM_METHOD_TYPE_OPTIMIZED, /*!< Kernel#send, Proc#call, etc */
|
|
|
|
VM_METHOD_TYPE_MISSING, /*!< wrapper for method_missing(id) */
|
|
|
|
VM_METHOD_TYPE_REFINED, /*!< refinement */
|
2012-12-13 07:50:19 +04:00
|
|
|
|
|
|
|
END_OF_ENUMERATION(VM_METHOD_TYPE)
|
2009-07-16 04:37:25 +04:00
|
|
|
} rb_method_type_t;
|
2018-01-28 17:16:48 +03:00
|
|
|
#define VM_METHOD_TYPE_MINIMUM_BITS 4
|
2019-05-31 04:05:38 +03:00
|
|
|
STATIC_ASSERT(VM_METHOD_TYPE_MINIMUM_BITS,
|
|
|
|
VM_METHOD_TYPE_REFINED <= (1<<VM_METHOD_TYPE_MINIMUM_BITS));
|
2009-07-16 04:37:25 +04:00
|
|
|
|
2015-09-19 04:53:34 +03:00
|
|
|
#ifndef rb_iseq_t
|
2015-06-02 07:20:30 +03:00
|
|
|
typedef struct rb_iseq_struct rb_iseq_t;
|
2015-09-19 04:53:34 +03:00
|
|
|
#define rb_iseq_t rb_iseq_t
|
|
|
|
#endif
|
2015-06-02 07:20:30 +03:00
|
|
|
|
|
|
|
typedef struct rb_method_iseq_struct {
|
`Primitive.mandatory_only?` for fast path
Compare with the C methods, A built-in methods written in Ruby is
slower if only mandatory parameters are given because it needs to
check the argumens and fill default values for optional and keyword
parameters (C methods can check the number of parameters with `argc`,
so there are no overhead). Passing mandatory arguments are common
(optional arguments are exceptional, in many cases) so it is important
to provide the fast path for such common cases.
`Primitive.mandatory_only?` is a special builtin function used with
`if` expression like that:
```ruby
def self.at(time, subsec = false, unit = :microsecond, in: nil)
if Primitive.mandatory_only?
Primitive.time_s_at1(time)
else
Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
end
end
```
and it makes two ISeq,
```
def self.at(time, subsec = false, unit = :microsecond, in: nil)
Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
end
def self.at(time)
Primitive.time_s_at1(time)
end
```
and (2) is pointed by (1). Note that `Primitive.mandatory_only?`
should be used only in a condition of an `if` statement and the
`if` statement should be equal to the methdo body (you can not
put any expression before and after the `if` statement).
A method entry with `mandatory_only?` (`Time.at` on the above case)
is marked as `iseq_overload`. When the method will be dispatch only
with mandatory arguments (`Time.at(0)` for example), make another
method entry with ISeq (2) as mandatory only method entry and it
will be cached in an inline method cache.
The idea is similar discussed in https://bugs.ruby-lang.org/issues/16254
but it only checks mandatory parameters or more, because many cases
only mandatory parameters are given. If we find other cases (optional
or keyword parameters are used frequently and it hurts performance),
we can extend the feature.
2021-11-12 20:12:20 +03:00
|
|
|
const rb_iseq_t * iseqptr; /*!< iseq pointer, should be separated from iseqval */
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_cref_t * cref; /*!< class reference, should be marked */
|
|
|
|
} rb_method_iseq_t; /* check rb_add_method_iseq() when modify the fields */
|
2015-06-02 07:20:30 +03:00
|
|
|
|
2009-07-16 04:37:25 +04:00
|
|
|
typedef struct rb_method_cfunc_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
VALUE (*func)(ANYARGS);
|
|
|
|
VALUE (*invoker)(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS));
|
|
|
|
int argc;
|
2009-07-16 04:37:25 +04:00
|
|
|
} rb_method_cfunc_t;
|
|
|
|
|
2010-03-22 14:44:01 +03:00
|
|
|
typedef struct rb_method_attr_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
ID id;
|
|
|
|
VALUE location; /* should be marked */
|
2010-03-22 14:44:01 +03:00
|
|
|
} rb_method_attr_t;
|
|
|
|
|
2015-05-30 21:45:28 +03:00
|
|
|
typedef struct rb_method_alias_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
struct rb_method_entry_struct * original_me; /* original_me->klass is original owner */
|
2015-05-30 21:45:28 +03:00
|
|
|
} rb_method_alias_t;
|
|
|
|
|
2015-06-04 01:27:51 +03:00
|
|
|
typedef struct rb_method_refined_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
struct rb_method_entry_struct * orig_me;
|
2015-06-04 01:27:51 +03:00
|
|
|
} rb_method_refined_t;
|
|
|
|
|
2018-11-26 21:16:39 +03:00
|
|
|
typedef struct rb_method_bmethod_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
VALUE proc; /* should be marked */
|
2018-11-26 21:16:39 +03:00
|
|
|
struct rb_hook_list_struct *hooks;
|
2020-09-25 12:31:04 +03:00
|
|
|
VALUE defined_ractor;
|
2018-11-26 21:16:39 +03:00
|
|
|
} rb_method_bmethod_t;
|
|
|
|
|
2017-05-19 09:00:53 +03:00
|
|
|
enum method_optimized_type {
|
|
|
|
OPTIMIZED_METHOD_TYPE_SEND,
|
|
|
|
OPTIMIZED_METHOD_TYPE_CALL,
|
2018-01-07 22:18:49 +03:00
|
|
|
OPTIMIZED_METHOD_TYPE_BLOCK_CALL,
|
2021-11-18 05:01:31 +03:00
|
|
|
OPTIMIZED_METHOD_TYPE_STRUCT_AREF,
|
|
|
|
OPTIMIZED_METHOD_TYPE_STRUCT_ASET,
|
2017-05-19 09:00:53 +03:00
|
|
|
OPTIMIZED_METHOD_TYPE__MAX
|
|
|
|
};
|
|
|
|
|
2021-11-17 18:43:40 +03:00
|
|
|
typedef struct rb_method_optimized {
|
|
|
|
enum method_optimized_type type;
|
2021-11-18 05:01:31 +03:00
|
|
|
unsigned int index;
|
2021-11-17 18:43:40 +03:00
|
|
|
} rb_method_optimized_t;
|
|
|
|
|
2019-07-22 23:20:04 +03:00
|
|
|
struct rb_method_definition_struct {
|
2019-10-03 06:26:41 +03:00
|
|
|
BITFIELD(rb_method_type_t, type, VM_METHOD_TYPE_MINIMUM_BITS);
|
`Primitive.mandatory_only?` for fast path
Compare with the C methods, A built-in methods written in Ruby is
slower if only mandatory parameters are given because it needs to
check the argumens and fill default values for optional and keyword
parameters (C methods can check the number of parameters with `argc`,
so there are no overhead). Passing mandatory arguments are common
(optional arguments are exceptional, in many cases) so it is important
to provide the fast path for such common cases.
`Primitive.mandatory_only?` is a special builtin function used with
`if` expression like that:
```ruby
def self.at(time, subsec = false, unit = :microsecond, in: nil)
if Primitive.mandatory_only?
Primitive.time_s_at1(time)
else
Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
end
end
```
and it makes two ISeq,
```
def self.at(time, subsec = false, unit = :microsecond, in: nil)
Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
end
def self.at(time)
Primitive.time_s_at1(time)
end
```
and (2) is pointed by (1). Note that `Primitive.mandatory_only?`
should be used only in a condition of an `if` statement and the
`if` statement should be equal to the methdo body (you can not
put any expression before and after the `if` statement).
A method entry with `mandatory_only?` (`Time.at` on the above case)
is marked as `iseq_overload`. When the method will be dispatch only
with mandatory arguments (`Time.at(0)` for example), make another
method entry with ISeq (2) as mandatory only method entry and it
will be cached in an inline method cache.
The idea is similar discussed in https://bugs.ruby-lang.org/issues/16254
but it only checks mandatory parameters or more, because many cases
only mandatory parameters are given. If we find other cases (optional
or keyword parameters are used frequently and it hurts performance),
we can extend the feature.
2021-11-12 20:12:20 +03:00
|
|
|
unsigned int iseq_overload: 1;
|
2022-01-26 18:28:39 +03:00
|
|
|
unsigned int no_redef_warning: 1;
|
2023-09-20 19:26:31 +03:00
|
|
|
unsigned int aliased : 1;
|
|
|
|
int reference_count : 28;
|
* 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
|
|
|
|
2009-07-16 04:37:25 +04:00
|
|
|
union {
|
2019-10-03 06:48:20 +03:00
|
|
|
rb_method_iseq_t iseq;
|
|
|
|
rb_method_cfunc_t cfunc;
|
|
|
|
rb_method_attr_t attr;
|
|
|
|
rb_method_alias_t alias;
|
|
|
|
rb_method_refined_t refined;
|
2018-11-26 21:16:39 +03:00
|
|
|
rb_method_bmethod_t bmethod;
|
2021-11-17 18:43:40 +03:00
|
|
|
rb_method_optimized_t optimized;
|
2009-07-16 04:37:25 +04:00
|
|
|
} body;
|
2015-06-03 04:39:16 +03:00
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
ID original_id;
|
2019-12-17 09:49:41 +03:00
|
|
|
uintptr_t method_serial;
|
2019-07-22 23:20:04 +03:00
|
|
|
};
|
2017-05-19 09:00:53 +03:00
|
|
|
|
2020-08-11 01:19:17 +03:00
|
|
|
struct rb_id_table;
|
|
|
|
|
2017-05-19 09:00:53 +03:00
|
|
|
typedef struct rb_method_definition_struct rb_method_definition_t;
|
2023-09-22 23:14:09 +03:00
|
|
|
STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8);
|
2009-08-28 06:45:41 +04:00
|
|
|
|
|
|
|
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
|
2015-01-12 11:18:10 +03:00
|
|
|
#define UNDEFINED_REFINED_METHOD_P(def) \
|
|
|
|
((def)->type == VM_METHOD_TYPE_REFINED && \
|
2015-06-04 01:27:51 +03:00
|
|
|
UNDEFINED_METHOD_ENTRY_P((def)->body.refined.orig_me))
|
2009-08-28 06:45:41 +04:00
|
|
|
|
2021-11-17 18:43:40 +03:00
|
|
|
void rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi);
|
2015-06-03 04:39:16 +03:00
|
|
|
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi);
|
2015-07-22 01:52:59 +03:00
|
|
|
void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi);
|
2021-11-17 18:43:40 +03:00
|
|
|
void rb_add_method_optimized(VALUE klass, ID mid, enum method_optimized_type, unsigned int index, rb_method_visibility_t 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
|
|
|
void rb_add_refined_method_entry(VALUE refined_class, 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
|
|
|
|
2019-10-03 06:26:41 +03:00
|
|
|
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex);
|
2023-09-20 19:26:31 +03:00
|
|
|
rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, 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
|
|
|
|
|
|
|
const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
|
|
|
|
|
|
|
|
const rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
2019-01-28 14:45:21 +03:00
|
|
|
const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class);
|
2017-10-06 08:55:11 +03:00
|
|
|
const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID 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
|
|
|
const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me);
|
2017-12-05 10:16:42 +03:00
|
|
|
RUBY_SYMBOL_EXPORT_BEGIN
|
2017-12-05 11:56:50 +03:00
|
|
|
const rb_method_entry_t *rb_resolve_me_location(const rb_method_entry_t *, VALUE[5]);
|
2017-12-05 10:16:42 +03:00
|
|
|
RUBY_SYMBOL_EXPORT_END
|
* 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_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id);
|
2022-09-14 23:15:55 +03:00
|
|
|
const rb_callable_method_entry_t *rb_callable_method_entry_or_negative(VALUE klass, ID id);
|
2017-10-06 08:55:11 +03:00
|
|
|
const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class);
|
|
|
|
const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class);
|
2010-05-05 00:25:09 +04:00
|
|
|
|
2009-07-16 04:37:25 +04:00
|
|
|
int rb_method_entry_arity(const rb_method_entry_t *me);
|
* 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
|
|
|
int rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2);
|
2012-02-21 04:13:44 +04:00
|
|
|
st_index_t rb_hash_method_entry(st_index_t hash, const rb_method_entry_t *me);
|
2010-05-05 00:25:09 +04:00
|
|
|
|
2015-08-20 02:53:12 +03:00
|
|
|
VALUE rb_method_entry_location(const rb_method_entry_t *me);
|
2013-02-06 08:35:23 +04:00
|
|
|
|
2015-05-30 21:30:42 +03:00
|
|
|
void rb_free_method_entry(const rb_method_entry_t *me);
|
2009-07-16 04:37:25 +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
|
|
|
const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
|
2016-11-05 16:15:26 +03:00
|
|
|
const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID called_id, VALUE defined_class);
|
2019-10-03 06:26:41 +03:00
|
|
|
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
|
2015-06-02 07:20:30 +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);
|
|
|
|
|
2015-06-03 17:07:24 +03:00
|
|
|
void rb_scope_visibility_set(rb_method_visibility_t);
|
|
|
|
|
2018-06-03 08:10:41 +03:00
|
|
|
VALUE rb_unnamed_parameters(int arity);
|
|
|
|
|
2020-01-08 10:14:01 +03:00
|
|
|
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
|
2023-07-31 10:17:55 +03:00
|
|
|
void rb_clear_all_refinement_method_cache(void);
|
2020-01-08 10:14:01 +03:00
|
|
|
|
2015-09-19 04:48:48 +03:00
|
|
|
#endif /* RUBY_METHOD_H */
|