From 7cb96d41a52d5ce4b2485ff542edc88fa246bc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Wed, 25 Sep 2019 13:51:06 +0900 Subject: [PATCH] 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. --- class.c | 50 ++++++++++++++++++++++++++++++++++++++----------- method.h | 3 ++- proc.c | 2 -- vm_insnhelper.c | 1 - vm_method.c | 11 ----------- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/class.c b/class.c index b4aeb59e25..308033d2cb 100644 --- a/class.c +++ b/class.c @@ -956,25 +956,48 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) 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 move_refined_method(ID key, VALUE value, void *data) { + const tuple *ptr = data; 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->body.refined.orig_me) { - const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me; - 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; + return ID_TABLE_REPLACE; } 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; } } @@ -1000,7 +1023,12 @@ rb_prepend_module(VALUE klass, VALUE module) RCLASS_SET_ORIGIN(klass, origin); RCLASS_M_TBL(origin) = RCLASS_M_TBL(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); if (changed < 0) diff --git a/method.h b/method.h index 1ce5d4c96b..b46336b51e 100644 --- a/method.h +++ b/method.h @@ -185,6 +185,8 @@ STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body)==8); ((def)->type == VM_METHOD_TYPE_REFINED && \ 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_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); @@ -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_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); diff --git a/proc.c b/proc.c index 465135d505..67e29643bb 100644 --- a/proc.c +++ b/proc.c @@ -15,8 +15,6 @@ #include "vm_core.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 * versions */ #define PROC_NEW_REQUIRES_BLOCK 0 diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 0a43f949af..f144d1157c 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -19,7 +19,6 @@ #include "ruby/config.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 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, diff --git a/vm_method.c b/vm_method.c index 7bb675ebcc..6d052220c2 100644 --- a/vm_method.c +++ b/vm_method.c @@ -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; } -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* make_method_entry_refined(VALUE owner, rb_method_entry_t *me) {