* revert r37993 to avoid SEGV in tests.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38022 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2012-11-30 02:11:59 +00:00
Родитель 696ebcd8ca
Коммит 9e44974874
12 изменённых файлов: 171 добавлений и 373 удалений

Просмотреть файл

@ -1,3 +1,7 @@
Fri Nov 30 11:07:45 2012 Shugo Maeda <shugo@ruby-lang.org>
* revert r37993 to avoid SEGV in tests.
Fri Nov 30 10:38:54 2012 Eric Hodel <drbrain@segment7.net>
* lib/rdoc/ri/driver.rb: Relaxed matching for pages to be more

16
class.c
Просмотреть файл

@ -677,13 +677,6 @@ rb_include_module(VALUE klass, VALUE module)
if (changed) rb_clear_cache();
}
static int
add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
{
rb_add_refined_method_entry((VALUE) data, (ID) key);
return ST_CONTINUE;
}
static int
include_modules_at(VALUE klass, VALUE c, VALUE module)
{
@ -714,13 +707,6 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
}
}
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
VALUE refined_class =
rb_refinement_module_get_refined_class(klass);
st_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i,
(st_data_t) refined_class);
}
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
changed = 1;
skip:
@ -752,7 +738,7 @@ rb_prepend_module(VALUE klass, VALUE module)
RCLASS_SUPER(klass) = origin;
RCLASS_ORIGIN(klass) = origin;
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL(klass) = st_init_numtable();
RCLASS_M_TBL(klass) = 0;
}
changed = include_modules_at(klass, klass, module);
if (changed < 0)

12
eval.c
Просмотреть файл

@ -1187,14 +1187,6 @@ rb_mod_using(VALUE self, VALUE module)
return self;
}
VALUE rb_refinement_module_get_refined_class(VALUE module)
{
ID id_refined_class;
CONST_ID(id_refined_class, "__refined_class__");
return rb_attr_get(module, id_refined_class);
}
static VALUE
refinement_module_include(int argc, VALUE *argv, VALUE module)
{
@ -1203,9 +1195,11 @@ refinement_module_include(int argc, VALUE *argv, VALUE module)
rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
VALUE result = rb_mod_include(argc, argv, module);
NODE *cref;
ID id_refined_class;
VALUE klass, c;
klass = rb_refinement_module_get_refined_class(module);
CONST_ID(id_refined_class, "__refined_class__");
klass = rb_attr_get(module, id_refined_class);
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
(cref = rb_vm_get_cref(cfp->iseq, cfp->ep)) &&

4
gc.c
Просмотреть файл

@ -2410,7 +2410,6 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
const rb_method_definition_t *def = me->def;
gc_mark(objspace, me->klass);
again:
if (!def) return;
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
@ -2423,9 +2422,6 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
case VM_METHOD_TYPE_IVAR:
gc_mark(objspace, def->body.attr.location);
break;
case VM_METHOD_TYPE_REFINED:
def = def->body.orig_def;
goto again;
default:
break; /* ignore */
}

Просмотреть файл

@ -99,9 +99,6 @@ NORETURN(void rb_async_bug_errno(const char *,int));
const char *rb_builtin_type_name(int t);
const char *rb_builtin_class_name(VALUE x);
/* eval.c */
VALUE rb_refinement_module_get_refined_class(VALUE module);
/* eval_error.c */
void ruby_error_print(void);
VALUE rb_get_backtrace(VALUE info);

Просмотреть файл

@ -42,8 +42,7 @@ typedef enum {
VM_METHOD_TYPE_NOTIMPLEMENTED,
VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
VM_METHOD_TYPE_MISSING, /* wrapper for method_missing(id) */
VM_METHOD_TYPE_CFUNC_FRAMELESS,
VM_METHOD_TYPE_REFINED,
VM_METHOD_TYPE_CFUNC_FRAMELESS
} rb_method_type_t;
struct rb_call_info_struct;
@ -73,7 +72,6 @@ typedef struct rb_method_definition_struct {
OPTIMIZED_METHOD_TYPE_SEND,
OPTIMIZED_METHOD_TYPE_CALL
} optimize_type;
struct rb_method_definition_struct *orig_def;
} body;
int alias_count;
} rb_method_definition_t;
@ -96,16 +94,9 @@ struct unlinked_method_entry_list_entry {
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
void rb_add_refined_method_entry(VALUE refined_class, ID mid);
rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
rb_method_entry_t *me,
rb_method_entry_t *me_buf,
VALUE *defined_class_ptr);
rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
rb_method_entry_t *me_buf,
VALUE *defined_class_ptr);
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
rb_method_entry_t *rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id, VALUE *define_class_ptr);
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id, VALUE *define_class_ptr);
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
int rb_method_entry_arity(const rb_method_entry_t *me);

Просмотреть файл

@ -1337,7 +1337,7 @@ rb_obj_cmp(VALUE obj1, VALUE obj2)
static VALUE
rb_mod_to_s(VALUE klass)
{
ID id_defined_at;
ID id_refined_class, id_defined_at;
VALUE refined_class, defined_at;
if (FL_TEST(klass, FL_SINGLETON)) {
@ -1357,7 +1357,8 @@ rb_mod_to_s(VALUE klass)
return s;
}
refined_class = rb_refinement_module_get_refined_class(klass);
CONST_ID(id_refined_class, "__refined_class__");
refined_class = rb_attr_get(klass, id_refined_class);
if (!NIL_P(refined_class)) {
VALUE s = rb_usascii_str_new2("#<refinement:");

4
proc.c
Просмотреть файл

@ -917,7 +917,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
rb_method_flag_t flag = NOEX_UNDEF;
again:
me = rb_method_entry_with_refinements(klass, id, &meb, &defined_class);
me = rb_method_entry(klass, id, &defined_class);
if (UNDEFINED_METHOD_ENTRY_P(me)) {
ID rmiss = rb_intern("respond_to_missing?");
VALUE sym = ID2SYM(id);
@ -1682,8 +1682,6 @@ rb_method_entry_arity(const rb_method_entry_t *me)
default:
break;
}
case VM_METHOD_TYPE_REFINED:
return -1;
}
}
rb_bug("rb_method_entry_arity: invalid method entry type (%d)", def->type);

Просмотреть файл

@ -726,6 +726,7 @@ class TestRefinement < Test::Unit::TestCase
end
def test_inline_method_cache
skip "can't implement efficiently with the current implementation of refinements"
c = InlineMethodCache::C.new
f = Proc.new { c.foo }
assert_equal("original", f.call)
@ -821,31 +822,4 @@ class TestRefinement < Test::Unit::TestCase
end
end
end
module RedifineRefinedMethod
class C
def foo
"original"
end
end
module M
refine C do
def foo
"refined"
end
end
end
class C
def foo
"redefined"
end
end
end
def test_redefine_refined_method
c = RedifineRefinedMethod::C.new
assert_equal("refined", RedifineRefinedMethod::M.module_eval { c.foo })
end
end

Просмотреть файл

@ -179,17 +179,7 @@ vm_call0_body(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
case VM_METHOD_TYPE_BMETHOD:
return vm_call_bmethod_body(th, ci, argv);
case VM_METHOD_TYPE_ZSUPER:
case VM_METHOD_TYPE_REFINED:
{
if (ci->me->def->type == VM_METHOD_TYPE_REFINED &&
ci->me->def->body.orig_def) {
rb_method_entry_t orig_me;
orig_me = *ci->me;
orig_me.def = ci->me->def->body.orig_def;
ci->me = &orig_me;
goto again;
}
ci->defined_class = RCLASS_SUPER(ci->defined_class);
if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) {
@ -284,7 +274,8 @@ stack_check(void)
}
static inline rb_method_entry_t *
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
VALUE *defined_class_ptr);
static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
#define NOEX_OK NOEX_NOSUPER
@ -304,11 +295,11 @@ static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t
*/
static inline VALUE
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
call_type scope, VALUE self)
call_type scope, VALUE self, VALUE refinements)
{
VALUE defined_class;
rb_method_entry_t *me =
rb_search_method_entry(recv, mid, &defined_class);
rb_search_method_entry(refinements, recv, mid, &defined_class);
rb_thread_t *th = GET_THREAD();
int call_status = rb_method_call_status(th, me, scope, self);
@ -372,7 +363,7 @@ check_funcall(VALUE recv, ID mid, int argc, VALUE *argv)
}
}
me = rb_search_method_entry(recv, mid, &defined_class);
me = rb_search_method_entry(Qnil, recv, mid, &defined_class);
call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
if (call_status != NOEX_OK) {
if (rb_method_basic_definition_p(klass, idMethodMissing)) {
@ -437,7 +428,8 @@ rb_type_str(enum ruby_value_type type)
}
static inline rb_method_entry_t *
rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
VALUE *defined_class_ptr)
{
VALUE klass = CLASS_OF(recv);
@ -476,7 +468,8 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
rb_id2name(mid), type, (void *)recv, flags, klass);
}
}
return rb_method_entry(klass, mid, defined_class_ptr);
return rb_method_entry_get_with_refinements(refinements, klass, mid,
defined_class_ptr);
}
static inline int
@ -540,7 +533,7 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc
static inline VALUE
rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
{
return rb_call0(recv, mid, argc, argv, scope, Qundef);
return rb_call0(recv, mid, argc, argv, scope, Qundef, Qnil);
}
NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
@ -793,24 +786,10 @@ rb_funcall_passing_block_with_refinements(VALUE recv, ID mid, int argc,
const VALUE *argv,
VALUE refinements)
{
VALUE defined_class;
rb_method_entry_t meb, *me =
rb_search_method_entry(recv, mid, &defined_class);
rb_thread_t *th;
int call_status;
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
me = rb_resolve_refined_method(refinements, me, &meb,
&defined_class);
}
PASS_PASSED_BLOCK_TH(GET_THREAD());
th = GET_THREAD();
call_status = rb_method_call_status(th, me, CALL_PUBLIC, Qundef);
if (call_status != NOEX_OK) {
return method_missing(recv, mid, argc, argv, call_status);
}
stack_check();
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
return rb_call0(recv, mid, argc, argv, CALL_PUBLIC, Qundef,
refinements);
}
static VALUE
@ -837,7 +816,7 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
id = rb_to_id(vid);
}
PASS_PASSED_BLOCK_TH(th);
return rb_call0(recv, id, argc, argv, scope, self);
return rb_call0(recv, id, argc, argv, scope, self, Qnil);
}
/*

Просмотреть файл

@ -1694,47 +1694,6 @@ vm_call_method_missing(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
return vm_call_method(th, reg_cfp, &ci_entry);
}
static VALUE
copy_refinement_iclass(VALUE iclass, VALUE superclass)
{
VALUE result, c;
Check_Type(iclass, T_ICLASS);
c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
iclass = RCLASS_SUPER(iclass);
while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
RCLASS_SUPER(c));
RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
iclass = RCLASS_SUPER(iclass);
}
return result;
}
static VALUE
find_refinement(VALUE refinements, VALUE klass)
{
VALUE refinement;
if (NIL_P(refinements)) {
return Qnil;
}
refinement = rb_hash_lookup(refinements, klass);
if (NIL_P(refinement) &&
BUILTIN_TYPE(klass) == T_ICLASS) {
refinement = rb_hash_lookup(refinements,
RBASIC(klass)->klass);
if (!NIL_P(refinement)) {
refinement = copy_refinement_iclass(refinement, klass);
}
}
return refinement;
}
static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci);
static inline VALUE
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
{
@ -1776,10 +1735,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
return vm_call_bmethod(th, cfp, ci);
}
case VM_METHOD_TYPE_ZSUPER:{
VALUE klass;
zsuper_method_dispatch:
klass = RCLASS_SUPER(ci->me->klass);
VALUE klass = RCLASS_SUPER(ci->me->klass);
ci_temp = *ci;
ci = &ci_temp;
@ -1822,44 +1778,6 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
break;
case VM_METHOD_TYPE_UNDEF:
break;
case VM_METHOD_TYPE_REFINED:{
NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep);
VALUE refinements = cref ? cref->nd_refinements : Qnil;
VALUE refinement, defined_class;
rb_method_entry_t orig_me, *me;
ci_temp = *ci;
ci = &ci_temp;
refinement = find_refinement(refinements,
ci->defined_class);
if (NIL_P(refinement)) {
goto no_refinement_dispatch;
}
me = rb_method_entry(refinement, ci->mid, &defined_class);
if (me) {
if (ci->call == vm_call_super_method &&
cfp->me &&
rb_method_definition_eq(me->def, cfp->me->def)) {
goto no_refinement_dispatch;
}
ci->me = me;
ci->defined_class = defined_class;
if (me->def->type != VM_METHOD_TYPE_REFINED) {
goto normal_method_dispatch;
}
}
no_refinement_dispatch:
if (ci->me->def->body.orig_def) {
orig_me = *ci->me;
orig_me.def = ci->me->def->body.orig_def;
ci->me = &orig_me;
goto normal_method_dispatch;
}
else {
goto zsuper_method_dispatch;
}
}
}
rb_bug("vm_call_method: unsupported method type (%d)", ci->me->def->type);
}
@ -1923,12 +1841,6 @@ vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
return vm_call_method(th, reg_cfp, ci);
}
static VALUE
vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
{
return vm_call_method(th, reg_cfp, ci);
}
/* super */
static inline VALUE
@ -2017,7 +1929,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
/* TODO: use inline cache */
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
ci->call = vm_call_super_method;
ci->call = vm_call_general;
while (iseq && !iseq->klass) {
iseq = iseq->parent_iseq;
@ -2025,7 +1937,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) {
ci->klass = RCLASS_SUPER(ci->defined_class);
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
ci->me = rb_method_entry_get_with_refinements(Qnil, ci->klass, ci->mid, &ci->defined_class);
}
}

Просмотреть файл

@ -4,7 +4,7 @@
#define CACHE_SIZE 0x800
#define CACHE_MASK 0x7ff
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
#define NOEX_NOREDEF 0
#ifndef NOEX_NOREDEF
@ -21,6 +21,7 @@ struct cache_entry { /* method hash table. */
VALUE filled_version; /* filled state version */
ID mid; /* method's id */
VALUE klass; /* receiver's class */
VALUE refinements; /* refinements */
rb_method_entry_t *me;
VALUE defined_class;
};
@ -154,12 +155,6 @@ rb_free_method_entry(rb_method_entry_t *me)
if (def) {
if (def->alias_count == 0) {
if (def->type == VM_METHOD_TYPE_REFINED) {
def->body.orig_def->alias_count--;
if (def->body.orig_def->alias_count == 0) {
xfree(def->body.orig_def);
}
}
xfree(def);
}
else if (def->alias_count > 0) {
@ -172,50 +167,7 @@ rb_free_method_entry(rb_method_entry_t *me)
static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
static inline rb_method_entry_t *
lookup_method_table(VALUE klass, ID id)
{
st_data_t body;
st_table *m_tbl = RCLASS_M_TBL(klass);
if (st_lookup(m_tbl, id, &body)) {
return (rb_method_entry_t *) body;
}
else {
return 0;
}
}
static void
make_method_entry_refined(rb_method_entry_t *me)
{
rb_method_definition_t *new_def;
if (me->def && me->def->type == VM_METHOD_TYPE_REFINED)
return;
new_def = ALLOC(rb_method_definition_t);
new_def->type = VM_METHOD_TYPE_REFINED;
new_def->original_id = me->called_id;
new_def->alias_count = 0;
new_def->body.orig_def = me->def;
rb_vm_check_redefinition_opt_method(me, me->klass);
if (me->def) me->def->alias_count++;
me->def = new_def;
}
void
rb_add_refined_method_entry(VALUE refined_class, ID mid)
{
rb_method_entry_t *me = lookup_method_table(refined_class, mid);
if (me) {
make_method_entry_refined(me);
}
else {
rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
NOEX_PUBLIC);
}
}
void rb_redefine_opt_method(VALUE, ID);
static rb_method_entry_t *
rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
@ -227,7 +179,6 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
#endif
st_table *mtbl;
st_data_t data;
int make_refined = 0;
if (NIL_P(klass)) {
klass = rb_cObject;
@ -248,19 +199,14 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
rklass = klass;
#endif
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
VALUE refined_class =
rb_refinement_module_get_refined_class(klass);
ID id_refined_class;
VALUE refined_class;
rb_add_refined_method_entry(refined_class, mid);
}
if (type == VM_METHOD_TYPE_REFINED) {
rb_method_entry_t *old_me =
lookup_method_table(RCLASS_ORIGIN(klass), mid);
if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
}
else {
klass = RCLASS_ORIGIN(klass);
CONST_ID(id_refined_class, "__refined_class__");
refined_class = rb_ivar_get(klass, id_refined_class);
rb_redefine_opt_method(refined_class, mid);
}
klass = RCLASS_ORIGIN(klass);
mtbl = RCLASS_M_TBL(klass);
/* check re-definition */
@ -276,8 +222,6 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
}
#endif
rb_vm_check_redefinition_opt_method(old_me, klass);
if (old_def->type == VM_METHOD_TYPE_REFINED)
make_refined = 1;
if (RTEST(ruby_verbose) &&
type != VM_METHOD_TYPE_UNDEF &&
@ -330,10 +274,6 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
}
}
if (make_refined) {
make_method_entry_refined(me);
}
st_insert(mtbl, mid, (st_data_t) me);
return me;
@ -401,12 +341,7 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
int line;
rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
rb_method_definition_t *def = ALLOC(rb_method_definition_t);
if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
me->def->body.orig_def = def;
}
else {
me->def = def;
}
me->def = def;
def->type = type;
def->original_id = mid;
def->alias_count = 0;
@ -444,13 +379,10 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
case VM_METHOD_TYPE_ZSUPER:
case VM_METHOD_TYPE_UNDEF:
break;
case VM_METHOD_TYPE_REFINED:
def->body.orig_def = (rb_method_definition_t *) opts;
break;
default:
rb_bug("rb_add_method: unsupported method type (%d)\n", type);
}
if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
if (type != VM_METHOD_TYPE_UNDEF) {
method_added(klass, mid);
}
return me;
@ -493,18 +425,86 @@ rb_get_alloc_func(VALUE klass)
return 0;
}
static inline rb_method_entry_t*
search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
static VALUE
copy_refinement_iclass(VALUE iclass, VALUE superclass)
{
rb_method_entry_t *me;
VALUE result, c;
for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
if ((me = lookup_method_table(klass, id)) != 0) break;
Check_Type(iclass, T_ICLASS);
c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
iclass = RCLASS_SUPER(iclass);
while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
RCLASS_SUPER(c));
RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
iclass = RCLASS_SUPER(iclass);
}
return result;
}
static inline int
lookup_method_table(VALUE klass, ID id, st_data_t *body)
{
st_table *m_tbl = RCLASS_M_TBL(klass);
if (!m_tbl) {
m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(RBASIC(klass)->klass));
}
return st_lookup(m_tbl, id, body);
}
static inline rb_method_entry_t*
search_method_with_refinements(VALUE klass, ID id, VALUE refinements,
VALUE *defined_class_ptr)
{
st_data_t body;
VALUE iclass, skipped_class = Qnil;
for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
if (klass != skipped_class) {
iclass = rb_hash_lookup(refinements, klass);
if (NIL_P(iclass) && BUILTIN_TYPE(klass) == T_ICLASS) {
iclass = rb_hash_lookup(refinements, RBASIC(klass)->klass);
if (!NIL_P(iclass))
iclass = copy_refinement_iclass(iclass, klass);
}
if (!NIL_P(iclass)) {
skipped_class = klass;
klass = iclass;
}
}
if (lookup_method_table(klass, id, &body)) break;
}
if (defined_class_ptr)
*defined_class_ptr = klass;
return me;
return (rb_method_entry_t *)body;
}
static inline rb_method_entry_t*
search_method_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
{
st_data_t body;
for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
if (lookup_method_table(klass, id, &body)) break;
}
if (defined_class_ptr)
*defined_class_ptr = klass;
return (rb_method_entry_t *)body;
}
static rb_method_entry_t*
search_method(VALUE klass, ID id, VALUE refinements, VALUE *defined_class_ptr)
{
if (NIL_P(refinements)) {
return search_method_without_refinements(klass, id, defined_class_ptr);
}
else {
return search_method_with_refinements(klass, id, refinements,
defined_class_ptr);
}
}
/*
@ -514,17 +514,19 @@ search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
* rb_method_entry() simply.
*/
rb_method_entry_t *
rb_method_entry_get_without_cache(VALUE klass, ID id,
rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id,
VALUE *defined_class_ptr)
{
VALUE defined_class;
rb_method_entry_t *me = search_method(klass, id, &defined_class);
rb_method_entry_t *me = search_method(klass, id, refinements,
&defined_class);
if (ruby_running) {
struct cache_entry *ent;
ent = cache + EXPR1(klass, id);
ent = cache + EXPR1(klass, refinements, id);
ent->filled_version = GET_VM_STATE_VERSION();
ent->klass = klass;
ent->refinements = refinements;
ent->defined_class = defined_class;
if (UNDEFINED_METHOD_ENTRY_P(me)) {
@ -544,89 +546,37 @@ rb_method_entry_get_without_cache(VALUE klass, ID id,
}
rb_method_entry_t *
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id,
VALUE *defined_class_ptr)
{
#if OPT_GLOBAL_METHOD_CACHE
struct cache_entry *ent;
ent = cache + EXPR1(klass, id);
ent = cache + EXPR1(klass, refinements, id);
if (ent->filled_version == GET_VM_STATE_VERSION() &&
ent->mid == id && ent->klass == klass) {
ent->mid == id && ent->klass == klass &&
ent->refinements == refinements) {
if (defined_class_ptr)
*defined_class_ptr = ent->defined_class;
return ent->me;
}
#endif
return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
}
static rb_method_entry_t *
get_original_method_entry(VALUE refinements,
rb_method_entry_t *me, rb_method_entry_t *me_buf,
VALUE *defined_class_ptr)
{
if (me->def->body.orig_def) {
*me_buf = *me;
me_buf->def = me->def->body.orig_def;
return me_buf;
}
else {
rb_method_entry_t *tmp_me;
tmp_me = rb_method_entry(RCLASS_SUPER(me->klass), me->called_id,
defined_class_ptr);
return rb_resolve_refined_method(refinements, tmp_me, me_buf,
defined_class_ptr);
}
return rb_method_entry_get_without_cache(klass, refinements, id,
defined_class_ptr);
}
rb_method_entry_t *
rb_resolve_refined_method(VALUE refinements, rb_method_entry_t *me,
rb_method_entry_t *me_buf,
VALUE *defined_class_ptr)
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
{
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
VALUE refinement;
rb_method_entry_t *tmp_me;
NODE *cref = rb_vm_cref();
VALUE refinements = Qnil;
refinement = find_refinement(refinements, me->klass);
if (NIL_P(refinement)) {
return get_original_method_entry(refinements, me, me_buf,
defined_class_ptr);
}
tmp_me = rb_method_entry(refinement, me->called_id,
defined_class_ptr);
if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
return tmp_me;
}
else {
return get_original_method_entry(refinements, me, me_buf,
defined_class_ptr);
}
if (cref && !NIL_P(cref->nd_refinements)) {
refinements = cref->nd_refinements;
}
else {
return me;
}
}
rb_method_entry_t *
rb_method_entry_with_refinements(VALUE klass, ID id,
rb_method_entry_t *me_buf,
VALUE *defined_class_ptr)
{
VALUE defined_class;
rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class);
if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
NODE *cref = rb_vm_cref();
VALUE refinements = cref ? cref->nd_refinements : Qnil;
me = rb_resolve_refined_method(refinements, me, me_buf,
&defined_class);
}
if (defined_class_ptr)
*defined_class_ptr = defined_class;
return me;
return rb_method_entry_get_with_refinements(refinements, klass, id,
defined_class_ptr);
}
static void
@ -725,9 +675,9 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
rb_secure(4);
}
me = search_method(klass, name, &defined_class);
me = search_method(klass, name, Qnil, &defined_class);
if (!me && RB_TYPE_P(klass, T_MODULE)) {
me = search_method(rb_cObject, name, &defined_class);
me = search_method(rb_cObject, name, Qnil, &defined_class);
}
if (UNDEFINED_METHOD_ENTRY_P(me)) {
@ -749,9 +699,7 @@ rb_export_method(VALUE klass, ID name, rb_method_flag_t noex)
int
rb_method_boundp(VALUE klass, ID id, int ex)
{
rb_method_entry_t meb;
rb_method_entry_t *me =
rb_method_entry_with_refinements(klass, id, &meb, 0);
rb_method_entry_t *me = rb_method_entry(klass, id, 0);
if (me != 0) {
if ((ex & ~NOEX_RESPONDS) &&
@ -817,6 +765,9 @@ void
rb_undef(VALUE klass, ID id)
{
rb_method_entry_t *me;
NODE *cref = rb_vm_cref();
VALUE refinements = Qnil;
void rb_using_refinement(NODE *cref, VALUE klass, VALUE module);
if (NIL_P(klass)) {
rb_raise(rb_eTypeError, "no class to undef method");
@ -832,7 +783,10 @@ rb_undef(VALUE klass, ID id)
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
}
me = search_method(klass, id, 0);
if (cref && !NIL_P(cref->nd_refinements)) {
refinements = cref->nd_refinements;
}
me = search_method(klass, id, refinements, 0);
if (UNDEFINED_METHOD_ENTRY_P(me)) {
const char *s0 = " class";
@ -853,6 +807,11 @@ rb_undef(VALUE klass, ID id)
rb_id2name(id), s0, rb_class2name(c));
}
if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
VALUE mod = rb_module_new();
rb_using_refinement(cref, klass, mod);
klass = mod;
}
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
CALL_METHOD_HOOK(klass, undefined, id);
@ -1074,10 +1033,6 @@ rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
static int
rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
{
if (d1 && d1->type == VM_METHOD_TYPE_REFINED)
d1 = d1->body.orig_def;
if (d2 && d2->type == VM_METHOD_TYPE_REFINED)
d2 = d2->body.orig_def;
if (d1 == d2) return 1;
if (!d1 || !d2) return 0;
if (d1->type != d2->type) {
@ -1112,7 +1067,6 @@ rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_defini
static st_index_t
rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
{
again:
hash = rb_hash_uint(hash, def->type);
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
@ -1133,9 +1087,6 @@ rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
return hash;
case VM_METHOD_TYPE_OPTIMIZED:
return rb_hash_uint(hash, def->body.optimize_type);
case VM_METHOD_TYPE_REFINED:
def = def->body.orig_def;
goto again;
default:
rb_bug("rb_hash_method_definition: unsupported method type (%d)\n", def->type);
}
@ -1165,11 +1116,11 @@ rb_alias(VALUE klass, ID name, ID def)
}
again:
orig_me = search_method(klass, def, 0);
orig_me = search_method(klass, def, Qnil, 0);
if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
if ((!RB_TYPE_P(klass, T_MODULE)) ||
(orig_me = search_method(rb_cObject, def, 0),
(orig_me = search_method(rb_cObject, def, Qnil, 0),
UNDEFINED_METHOD_ENTRY_P(orig_me))) {
rb_print_undef(klass, def, 0);
}
@ -1445,9 +1396,9 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
id = rb_to_id(argv[i]);
for (;;) {
me = search_method(m, id, 0);
me = search_method(m, id, Qnil, 0);
if (me == 0) {
me = search_method(rb_cObject, id, 0);
me = search_method(rb_cObject, id, Qnil, 0);
}
if (UNDEFINED_METHOD_ENTRY_P(me)) {
rb_print_undef(module, id, 0);
@ -1560,6 +1511,21 @@ obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
return Qfalse;
}
void
rb_redefine_opt_method(VALUE klass, ID mid)
{
st_data_t data;
rb_method_entry_t *me = 0;
VALUE origin = RCLASS_ORIGIN(klass);
if (!st_lookup(RCLASS_M_TBL(origin), mid, &data) ||
!(me = (rb_method_entry_t *)data) ||
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
return;
}
rb_vm_check_redefinition_opt_method(me, origin);
}
void
Init_eval_method(void)
{