refactor delete rb_method_entry_copy

The deleted function was to destructively overwrite existing method
entries, which is now considered to be a bad idea.  Delete it, and
assign a newly created method entry instead.
This commit is contained in:
卜部昌平 2019-09-25 13:51:06 +09:00
Родитель 3207979278
Коммит 7cb96d41a5
5 изменённых файлов: 41 добавлений и 26 удалений

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

@ -956,25 +956,48 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
return method_changed; return method_changed;
} }
typedef struct tuple {
struct RClass *klass;
struct RClass *origin;
} tuple;
static enum rb_id_table_iterator_result
inject_refined_method(ID *key, VALUE *value, void *data, int _)
{
const tuple *ptr = data;
const rb_method_entry_t *me = *(rb_method_entry_t **) value;
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me;
rb_method_entry_t *new_me =
rb_method_entry_create(
me->called_id,
me->owner,
me->defined_class,
rb_method_definition_create(
me->def->type,
me->def->original_id,
&(rb_method_refined_t) {
.orig_me = NULL,
.owner = me->def->body.refined.owner, }));
METHOD_ENTRY_FLAGS_COPY(new_me, me);
rb_id_table_insert(RCLASS_M_TBL(ptr->klass), *key, (VALUE)new_me);
RB_OBJ_WRITTEN(ptr->klass, Qundef, new_me);
*value = (VALUE)rb_method_entry_clone(orig_me);
RB_OBJ_WRITTEN(ptr->origin, Qundef, orig_me);
return ID_TABLE_CONTINUE;
}
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
move_refined_method(ID key, VALUE value, void *data) move_refined_method(ID key, VALUE value, void *data)
{ {
const tuple *ptr = data;
rb_method_entry_t *me = (rb_method_entry_t *) value; rb_method_entry_t *me = (rb_method_entry_t *) value;
VALUE klass = (VALUE)data;
struct rb_id_table *tbl = RCLASS_M_TBL(klass);
if (me->def->type == VM_METHOD_TYPE_REFINED) { if (me->def->type == VM_METHOD_TYPE_REFINED) {
if (me->def->body.refined.orig_me) { if (me->def->body.refined.orig_me) {
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me; return ID_TABLE_REPLACE;
RB_OBJ_WRITE(me, &me->def->body.refined.orig_me, NULL);
new_me = rb_method_entry_clone(me);
rb_id_table_insert(tbl, key, (VALUE)new_me);
RB_OBJ_WRITTEN(klass, Qundef, new_me);
rb_method_entry_copy(me, orig_me);
return ID_TABLE_CONTINUE;
} }
else { else {
rb_id_table_insert(tbl, key, (VALUE)me); rb_id_table_insert(RCLASS_M_TBL(ptr->klass), key, (VALUE)me);
return ID_TABLE_DELETE; return ID_TABLE_DELETE;
} }
} }
@ -1000,7 +1023,12 @@ rb_prepend_module(VALUE klass, VALUE module)
RCLASS_SET_ORIGIN(klass, origin); RCLASS_SET_ORIGIN(klass, origin);
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass); RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL_INIT(klass); RCLASS_M_TBL_INIT(klass);
rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass); rb_id_table_foreach_with_replace_with_key(
RCLASS_M_TBL(origin),
move_refined_method,
inject_refined_method,
&(tuple) { RCLASS(klass), RCLASS(origin), },
true);
} }
changed = include_modules_at(klass, klass, module, FALSE); changed = include_modules_at(klass, klass, module, FALSE);
if (changed < 0) if (changed < 0)

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

@ -185,6 +185,8 @@ STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body)==8);
((def)->type == VM_METHOD_TYPE_REFINED && \ ((def)->type == VM_METHOD_TYPE_REFINED && \
UNDEFINED_METHOD_ENTRY_P((def)->body.refined.orig_me)) UNDEFINED_METHOD_ENTRY_P((def)->body.refined.orig_me))
const rb_method_definition_t *rb_method_definition_create(rb_method_type_t which, ID what, const void *how);
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi); void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_visibility_t visi);
void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi); void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi);
void rb_add_refined_method_entry(VALUE refined_class, ID mid); void rb_add_refined_method_entry(VALUE refined_class, ID mid);
@ -221,7 +223,6 @@ void rb_sweep_method_entry(void *vm);
const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me); const rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me);
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); 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);
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
void rb_scope_visibility_set(rb_method_visibility_t); void rb_scope_visibility_set(rb_method_visibility_t);

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

@ -15,8 +15,6 @@
#include "vm_core.h" #include "vm_core.h"
#include "iseq.h" #include "iseq.h"
extern const rb_method_definition_t *rb_method_definition_create(rb_method_type_t type, ID mid, const void *opts);
/* Proc.new with no block will raise an exception in the future /* Proc.new with no block will raise an exception in the future
* versions */ * versions */
#define PROC_NEW_REQUIRES_BLOCK 0 #define PROC_NEW_REQUIRES_BLOCK 0

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

@ -19,7 +19,6 @@
#include "ruby/config.h" #include "ruby/config.h"
#include "debug_counter.h" #include "debug_counter.h"
extern const rb_method_definition_t *rb_method_definition_create(rb_method_type_t type, ID mid, const void *opts);
extern void rb_method_entry_spoof(const rb_method_entry_t *me); extern void rb_method_entry_spoof(const rb_method_entry_t *me);
extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2); extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
extern VALUE rb_make_no_method_exception(VALUE exc, VALUE format, VALUE obj, extern VALUE rb_make_no_method_exception(VALUE exc, VALUE format, VALUE obj,

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

@ -546,17 +546,6 @@ rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID cal
return (rb_callable_method_entry_t *)me; return (rb_callable_method_entry_t *)me;
} }
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 rb_method_entry_t* static rb_method_entry_t*
make_method_entry_refined(VALUE owner, rb_method_entry_t *me) make_method_entry_refined(VALUE owner, rb_method_entry_t *me)
{ {