diff --git a/class.c b/class.c index aaf754146d..b4aeb59e25 100644 --- a/class.c +++ b/class.c @@ -956,41 +956,25 @@ 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 = *(const rb_method_entry_t **) value; - const rb_method_entry_t *orig_me = me->def->body.refined.orig_me; - const rb_method_entry_t *new_me = - rb_method_entry_from_template( - me, &(rb_method_refined_t) { - .orig_me = NULL, - .owner = me->def->body.refined.owner, }); - 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; - const rb_method_entry_t *me = (const 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->body.refined.orig_me) { - return ID_TABLE_REPLACE; + 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; } else { - rb_id_table_insert(RCLASS_M_TBL(ptr->klass), key, (VALUE)me); + rb_id_table_insert(tbl, key, (VALUE)me); return ID_TABLE_DELETE; } } @@ -1016,12 +1000,7 @@ 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_with_replace_with_key( - RCLASS_M_TBL(origin), - move_refined_method, - inject_refined_method, - &(tuple) { RCLASS(klass), RCLASS(origin), }, - true); + rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass); } changed = include_modules_at(klass, klass, module, FALSE); if (changed < 0) diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c index cb571caa4b..8503c9d6c6 100644 --- a/ext/coverage/coverage.c +++ b/ext/coverage/coverage.c @@ -123,7 +123,7 @@ method_coverage_i(void *vstart, void *vend, size_t stride, void *data) for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) { if (RB_TYPE_P(v, T_IMEMO) && imemo_type(v) == imemo_ment) { - const rb_method_entry_t *me = (const rb_method_entry_t *) v; + const rb_method_entry_t *me = (rb_method_entry_t *) v; VALUE path, first_lineno, first_column, last_lineno, last_column; VALUE data[5], ncoverage, methods; VALUE methods_id = ID2SYM(rb_intern("methods")); diff --git a/gc.c b/gc.c index 52b3a66b6c..c9f26cc174 100644 --- a/gc.c +++ b/gc.c @@ -7829,9 +7829,9 @@ void rb_update_st_references(struct st_table *ht) } static void -gc_ref_update_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me) +gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me) { - const rb_method_definition_t *def = me->def; + rb_method_definition_t *def = me->def; UPDATE_IF_MOVED(objspace, me->owner); UPDATE_IF_MOVED(objspace, me->defined_class); diff --git a/id_table.c b/id_table.c index b383fcf81d..f566582479 100644 --- a/id_table.c +++ b/id_table.c @@ -269,62 +269,57 @@ rb_id_table_delete(struct rb_id_table *tbl, ID id) void rb_id_table_foreach_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, rb_id_table_update_callback_func_t *replace, void *data) { - rb_id_table_foreach_with_replace_with_key(tbl, func, replace, data, false); + int i, capa = tbl->capa; + + for (i=0; iitems[i].val, data); + assert(key != 0); + + if (ret == ID_TABLE_REPLACE) { + VALUE val = tbl->items[i].val; + ret = (*replace)(NULL, &val, data, TRUE); + tbl->items[i].val = val; + } + else if (ret == ID_TABLE_STOP) + return; + } + } } void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data) { - rb_id_table_foreach_with_replace_with_key(tbl, func, 0, data, true); -} + int i, capa = tbl->capa; -typedef struct tuple { - rb_id_table_foreach_values_func_t *const func; - void *const data; -} tuple; + for (i=0; iitems[i].val, data); + assert(key != 0); -static enum rb_id_table_iterator_result -cdr(ID car, VALUE cdr, void *data) -{ - const tuple *ptr = data; - return ptr->func(cdr, ptr->data); + if (ret == ID_TABLE_DELETE) + hash_delete_index(tbl, i); + else if (ret == ID_TABLE_STOP) + return; + } + } } void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data) { - rb_id_table_foreach_with_replace( - tbl, cdr, 0, &(tuple) { func, data, }); -} + int i, capa = tbl->capa; -void -rb_id_table_foreach_with_replace_with_key( - struct rb_id_table *tbl, - rb_id_table_foreach_func_t *func, - rb_id_table_update_callback_func_t *replace, - void *data, - bool needkey) -{ - for (int i = 0; i < tbl->capa; i++) { - if (ITEM_KEY_ISSET(tbl, i)) { - const id_key_t key = ITEM_GET_KEY(tbl, i); - assert(key != 0); - ID k = needkey ? key2id(key) : 0; - VALUE v = tbl->items[i].val; - switch (func(k, v, data)) { - case ID_TABLE_DELETE: - hash_delete_index(tbl, i); - /* FALLTHROUGH */ - case ID_TABLE_CONTINUE: - continue; - case ID_TABLE_STOP: - return; - case ID_TABLE_REPLACE: - if (replace) { - replace(&k, &v, data, true); - tbl->items[i].val = v; - } - } - } + for (i=0; iitems[i].val, data); + + if (ret == ID_TABLE_DELETE) + hash_delete_index(tbl, i); + else if (ret == ID_TABLE_STOP) + return; + } } } diff --git a/id_table.h b/id_table.h index 19181190ea..abd9eb5f38 100644 --- a/id_table.h +++ b/id_table.h @@ -10,6 +10,7 @@ enum rb_id_table_iterator_result { ID_TABLE_STOP = ST_STOP, ID_TABLE_DELETE = ST_DELETE, ID_TABLE_REPLACE = ST_REPLACE, + ID_TABLE_ITERATOR_RESULT_END }; struct rb_id_table *rb_id_table_create(size_t size); @@ -28,7 +29,6 @@ typedef enum rb_id_table_iterator_result rb_id_table_foreach_func_t(ID id, VALUE typedef enum rb_id_table_iterator_result rb_id_table_foreach_values_func_t(VALUE val, void *data); void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data); void rb_id_table_foreach_with_replace(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, rb_id_table_update_callback_func_t *replace, void *data); -void rb_id_table_foreach_with_replace_with_key(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, rb_id_table_update_callback_func_t *replace, void *data, bool needkey); void rb_id_table_foreach_values(struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data); #endif /* RUBY_ID_TABLE_H */ diff --git a/insns.def b/insns.def index e3edc5e29f..f365106e2c 100644 --- a/insns.def +++ b/insns.def @@ -911,7 +911,7 @@ invokeblock // attr rb_snum_t sp_inc = sp_inc_of_invokeblock(ci); { static struct rb_call_cache cc = { - 0, 0, NULL, vm_invokeblock_i, + 0, 0, NULL, NULL, vm_invokeblock_i, }; VALUE bh = VM_BLOCK_HANDLER_NONE; diff --git a/internal.h b/internal.h index dee7775d95..2346703d68 100644 --- a/internal.h +++ b/internal.h @@ -2330,6 +2330,7 @@ enum method_missing_reason { MISSING_NONE = 0x40 }; struct rb_callable_method_entry_struct; +struct rb_method_definition_struct; struct rb_execution_context_struct; struct rb_control_frame_struct; struct rb_calling_info; @@ -2341,6 +2342,7 @@ struct rb_call_cache { /* inline cache: values */ const struct rb_callable_method_entry_struct *me; + const struct rb_method_definition_struct *def; VALUE (*call)(struct rb_execution_context_struct *ec, struct rb_control_frame_struct *cfp, diff --git a/method.h b/method.h index b203f7112d..84ade7fef3 100644 --- a/method.h +++ b/method.h @@ -49,23 +49,54 @@ typedef struct rb_cref_struct { /* method data type */ typedef struct rb_method_entry_struct { - const VALUE flags; - const VALUE defined_class; + VALUE flags; + VALUE defined_class; struct rb_method_definition_struct * const def; - const ID called_id; - const VALUE owner; + ID called_id; + VALUE owner; } rb_method_entry_t; typedef struct rb_callable_method_entry_struct { /* same fields with rb_method_entry_t */ - const VALUE flags; + VALUE flags; const VALUE defined_class; struct rb_method_definition_struct * const def; - const ID called_id; + ID called_id; const VALUE owner; } rb_callable_method_entry_t; #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)) +#define METHOD_ENTRY_COMPLEMENTED(me) ((me)->flags & IMEMO_FL_USER3) +#define METHOD_ENTRY_COMPLEMENTED_SET(me) ((me)->flags = (me)->flags | IMEMO_FL_USER3) + +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)) | + ((visi << (IMEMO_FL_USHIFT+0)) | (basic << (IMEMO_FL_USHIFT+2))); +} +static inline void +METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src) +{ + dst->flags = + (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) | + (src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)); +} typedef enum { VM_METHOD_TYPE_ISEQ, /*!< Ruby method */ @@ -93,32 +124,32 @@ typedef struct rb_iseq_struct rb_iseq_t; #endif typedef struct rb_method_iseq_struct { - const rb_iseq_t *const iseqptr; /*!< iseq pointer, should be separated from iseqval */ - rb_cref_t *const cref; /*!< class reference, should be marked */ -} rb_method_iseq_t; + rb_iseq_t * iseqptr; /*!< iseq pointer, should be separated from iseqval */ + rb_cref_t * cref; /*!< class reference, should be marked */ +} rb_method_iseq_t; /* check rb_add_method_iseq() when modify the fields */ typedef struct rb_method_cfunc_struct { - VALUE (*const func)(ANYARGS); - VALUE (*const invoker)(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS)); - const int argc; + VALUE (*func)(ANYARGS); + VALUE (*invoker)(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS)); + int argc; } rb_method_cfunc_t; typedef struct rb_method_attr_struct { - const ID id; - const VALUE location; /* should be marked */ + ID id; + VALUE location; /* should be marked */ } rb_method_attr_t; typedef struct rb_method_alias_struct { - const struct rb_method_entry_struct *const original_me; /* original_me->klass is original owner */ + struct rb_method_entry_struct * original_me; /* original_me->klass is original owner */ } rb_method_alias_t; typedef struct rb_method_refined_struct { - const struct rb_method_entry_struct *const orig_me; - const VALUE owner; + struct rb_method_entry_struct * orig_me; + VALUE owner; } rb_method_refined_t; typedef struct rb_method_bmethod_struct { - const VALUE proc; /* should be marked */ + VALUE proc; /* should be marked */ struct rb_hook_list_struct *hooks; } rb_method_bmethod_t; @@ -130,22 +161,22 @@ enum method_optimized_type { }; struct rb_method_definition_struct { - BITFIELD(rb_method_type_t, const type, VM_METHOD_TYPE_MINIMUM_BITS); + BITFIELD(rb_method_type_t, type, VM_METHOD_TYPE_MINIMUM_BITS); int alias_count : 28; int complemented_count : 28; union { - const rb_method_iseq_t iseq; - const rb_method_cfunc_t cfunc; - const rb_method_attr_t attr; - const rb_method_alias_t alias; - const rb_method_refined_t refined; + 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; rb_method_bmethod_t bmethod; - const enum method_optimized_type optimize_type; + enum method_optimized_type optimize_type; } body; - const ID original_id; + ID original_id; }; typedef struct rb_method_definition_struct rb_method_definition_t; @@ -161,9 +192,8 @@ void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *c void rb_add_refined_method_entry(VALUE refined_class, ID mid); void rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_visibility_t visi); -const rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex); -const rb_method_entry_t *rb_method_entry_from_template(const rb_method_entry_t *template, const void *opts); -const rb_method_entry_t *rb_method_entry_for_missing(ID mid, VALUE klass); +rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex); +rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def); const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id); @@ -193,6 +223,7 @@ 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 0fd2126fff..667b86ac1b 100644 --- a/proc.c +++ b/proc.c @@ -1426,7 +1426,7 @@ bm_compact(void *ptr) UPDATE_REFERENCE(data->recv); UPDATE_REFERENCE(data->klass); UPDATE_REFERENCE(data->iclass); - UPDATE_TYPED_REFERENCE(const rb_method_entry_t *, data->me); + UPDATE_TYPED_REFERENCE(rb_method_entry_t *, data->me); } static size_t @@ -1474,9 +1474,19 @@ mnew_missing(VALUE klass, VALUE obj, ID id, VALUE mclass) { struct METHOD *data; VALUE method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); + rb_method_entry_t *me; + rb_method_definition_t *def; + RB_OBJ_WRITE(method, &data->recv, obj); RB_OBJ_WRITE(method, &data->klass, klass); - RB_OBJ_WRITE(method, &data->me, rb_method_entry_for_missing(id, klass)); + + def = ZALLOC(rb_method_definition_t); + def->type = VM_METHOD_TYPE_MISSING; + def->original_id = id; + + me = rb_method_entry_create(id, klass, METHOD_VISI_UNDEF, def); + + RB_OBJ_WRITE(method, &data->me, me); OBJ_INFECT(method, klass); @@ -1519,7 +1529,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, if (me->defined_class) { VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class)); id = me->def->original_id; - me = (const rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass); + me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass); } else { VALUE klass = RCLASS_SUPER(me->owner); @@ -1557,7 +1567,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) me = rb_method_entry_with_refinements(klass, id, &iclass); } else { - me = (const rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass); + me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(klass, id, &iclass); } return mnew_from_me(me, klass, iclass, obj, id, mclass, scope); } @@ -2947,7 +2957,7 @@ method_super_method(VALUE method) super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); mid = data->me->called_id; if (!super_class) return Qnil; - me = (const rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass); + me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass); if (!me) return Qnil; return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE); } diff --git a/vm.c b/vm.c index 16a15c2151..e104688d71 100644 --- a/vm.c +++ b/vm.c @@ -298,6 +298,17 @@ rb_vm_cref_new_toplevel(void) return vm_cref_new_toplevel(GET_EC()); } +static void +vm_cref_dump(const char *mesg, const rb_cref_t *cref) +{ + fprintf(stderr, "vm_cref_dump: %s (%p)\n", mesg, (void *)cref); + + while (cref) { + fprintf(stderr, "= cref| klass: %s\n", RSTRING_PTR(rb_class_path(CREF_CLASS(cref)))); + cref = CREF_NEXT(cref); + } +} + void rb_vm_block_ep_update(VALUE obj, const struct rb_block *dst, const VALUE *ep) { @@ -1595,7 +1606,7 @@ static enum rb_id_table_iterator_result check_redefined_method(ID mid, VALUE value, void *data) { VALUE klass = (VALUE)data; - const rb_method_entry_t *me = (const rb_method_entry_t *)value; + const rb_method_entry_t *me = (rb_method_entry_t *)value; const rb_method_entry_t *newme = rb_method_entry(klass, mid); if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner); diff --git a/vm_backtrace.c b/vm_backtrace.c index 3a8ad9143d..44a4ac0784 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -1349,7 +1349,7 @@ frame2iseq(VALUE frame) return (const rb_iseq_t *)frame; case imemo_ment: { - const rb_callable_method_entry_t *cme = (const rb_callable_method_entry_t *)frame; + const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame; switch (cme->def->type) { case VM_METHOD_TYPE_ISEQ: return cme->def->body.iseq.iseqptr; @@ -1405,7 +1405,7 @@ frame2klass(VALUE frame) if (frame == Qnil) return Qnil; if (RB_TYPE_P(frame, T_IMEMO)) { - const rb_callable_method_entry_t *cme = (const rb_callable_method_entry_t *)frame; + const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame; if (imemo_type(frame) == imemo_ment) { return cme->defined_class; diff --git a/vm_core.h b/vm_core.h index 192165b497..8eb155585e 100644 --- a/vm_core.h +++ b/vm_core.h @@ -491,7 +491,7 @@ rb_iseq_check(const rb_iseq_t *iseq) } static inline const rb_iseq_t * -def_iseq_ptr(const rb_method_definition_t *def) +def_iseq_ptr(rb_method_definition_t *def) { #if VM_CHECK_MODE > 0 if (def->type != VM_METHOD_TYPE_ISEQ) rb_bug("def_iseq_ptr: not iseq (%d)", def->type); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index ef5a6db1af..127c8c3f9e 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -19,7 +19,8 @@ #include "ruby/config.h" #include "debug_counter.h" -extern void rb_method_entry_spoof(const rb_method_entry_t *me); +extern rb_method_definition_t *rb_method_definition_create(rb_method_type_t type, ID mid); +extern void rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts); 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, int argc, const VALUE *argv, int priv); @@ -578,8 +579,8 @@ vm_getspecial(const rb_execution_context_t *ec, const VALUE *lep, rb_num_t key, return val; } -PUREFUNC(static const rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar)); -static const rb_callable_method_entry_t * +PUREFUNC(static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar)); +static rb_callable_method_entry_t * check_method_entry(VALUE obj, int can_be_svar) { if (obj == Qfalse) return NULL; @@ -590,7 +591,7 @@ check_method_entry(VALUE obj, int can_be_svar) switch (imemo_type(obj)) { case imemo_ment: - return (const rb_callable_method_entry_t *)obj; + return (rb_callable_method_entry_t *)obj; case imemo_cref: return NULL; case imemo_svar: @@ -609,7 +610,7 @@ MJIT_STATIC const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp) { const VALUE *ep = cfp->ep; - const rb_callable_method_entry_t *me; + rb_callable_method_entry_t *me; while (!VM_ENV_LOCAL_P(ep)) { if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me; @@ -620,7 +621,7 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp) } static rb_cref_t * -method_entry_cref(const rb_callable_method_entry_t *me) +method_entry_cref(rb_callable_method_entry_t *me) { switch (me->def->type) { case VM_METHOD_TYPE_ISEQ: @@ -644,7 +645,7 @@ check_cref(VALUE obj, int can_be_svar) switch (imemo_type(obj)) { case imemo_ment: - return method_entry_cref((const rb_callable_method_entry_t *)obj); + return method_entry_cref((rb_callable_method_entry_t *)obj); case imemo_cref: return (rb_cref_t *)obj; case imemo_svar: @@ -1390,6 +1391,9 @@ calccall(const struct rb_call_info *ci, const struct rb_call_cache *cc, const rb else if (LIKELY(cc->me != me)) { return vm_call_general; /* normal cases */ } + else if (UNLIKELY(cc->def != me->def)) { + return vm_call_general; /* cc->me was refined elsewhere */ + } /* "Calling a formerly-public method, which is now privatised, with an * explicit receiver" is the only situation we have to check here. A * formerly-private method now publicised is an absolutely safe thing. @@ -1412,6 +1416,7 @@ rb_vm_search_method_slowpath(const struct rb_call_info *ci, struct rb_call_cache GET_GLOBAL_METHOD_STATE(), RCLASS_SERIAL(klass), me, + me ? me->def : NULL, calccall(ci, cc, me), }; VM_ASSERT(callable_method_entry_p(cc->me)); @@ -2573,31 +2578,32 @@ find_defined_class_by_owner(VALUE current_class, VALUE target_owner) return current_class; /* maybe module function */ } -static const void* -aliased_callable_method_entry0(const rb_method_entry_t *me) +static const rb_callable_method_entry_t * +aliased_callable_method_entry(const rb_callable_method_entry_t *me) { const rb_method_entry_t *orig_me = me->def->body.alias.original_me; const rb_callable_method_entry_t *cme; - if (orig_me->defined_class != 0) { - VM_ASSERT(callable_class_p(orig_me->defined_class)); - return orig_me; - } - else { + if (orig_me->defined_class == 0) { VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner); VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE)); cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class); - const rb_method_entry_t *ret = - rb_method_entry_from_template((const rb_method_entry_t*)me, cme); - rb_method_entry_spoof(ret); - return ret; - } -} -static const rb_callable_method_entry_t* -aliased_callable_method_entry(const rb_callable_method_entry_t *me) -{ - return aliased_callable_method_entry0((const void*)me); + if (me->def->alias_count + me->def->complemented_count == 0) { + RB_OBJ_WRITE(me, &me->def->body.alias.original_me, cme); + } + else { + rb_method_definition_t *def = + rb_method_definition_create(VM_METHOD_TYPE_ALIAS, me->def->original_id); + rb_method_definition_set((rb_method_entry_t *)me, def, (void *)cme); + } + } + else { + cme = (const rb_callable_method_entry_t *)orig_me; + } + + VM_ASSERT(callable_method_entry_p(cme)); + return cme; } static const rb_callable_method_entry_t * diff --git a/vm_method.c b/vm_method.c index 1508b9a481..554d209110 100644 --- a/vm_method.c +++ b/vm_method.c @@ -41,7 +41,7 @@ struct cache_entry { rb_serial_t method_state; rb_serial_t class_serial; ID mid; - const rb_method_entry_t* me; + rb_method_entry_t* me; VALUE defined_class; }; @@ -132,7 +132,9 @@ rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_me { if (argc < -2 || 15 < argc) rb_raise(rb_eArgError, "arity out of range: %d for -2..15", argc); if (func != rb_f_notimplement) { - rb_method_cfunc_t opt = { func, 0, argc, }; + rb_method_cfunc_t opt; + opt.func = func; + opt.argc = argc; rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, visi); } else { @@ -140,11 +142,9 @@ rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_me } } -void -rb_free_method_entry(const rb_method_entry_t *me) +static void +rb_method_definition_release(rb_method_definition_t *def, int complemented) { - rb_method_definition_t *def = me->def; - if (def != NULL) { const int alias_count = def->alias_count; const int complemented_count = def->complemented_count; @@ -158,7 +158,7 @@ rb_free_method_entry(const rb_method_entry_t *me) xfree(def); } else { - if (def->complemented_count > 0) def->complemented_count--; + if (complemented) def->complemented_count--; else if (def->alias_count > 0) def->alias_count--; if (METHOD_DEBUG) fprintf(stderr, "-%p-%s:%d->%d,%d->%d (dec)\n", (void *)def, rb_id2name(def->original_id), @@ -167,17 +167,23 @@ rb_free_method_entry(const rb_method_entry_t *me) } } -static inline const rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr); +void +rb_free_method_entry(const rb_method_entry_t *me) +{ + rb_method_definition_release(me->def, METHOD_ENTRY_COMPLEMENTED(me)); +} + +static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr); extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2); -static inline const rb_method_entry_t * +static inline rb_method_entry_t * lookup_method_table(VALUE klass, ID id) { st_data_t body; struct rb_id_table *m_tbl = RCLASS_M_TBL(klass); if (rb_id_table_lookup(m_tbl, id, &body)) { - return (const rb_method_entry_t *) body; + return (rb_method_entry_t *) body; } else { return 0; @@ -211,10 +217,98 @@ static VALUE } } +static void +setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc) +{ + cfunc->func = func; + cfunc->argc = argc; + cfunc->invoker = call_cfunc_invoker_func(argc); +} + +MJIT_FUNC_EXPORTED void +rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts) +{ + *(rb_method_definition_t **)&me->def = def; + + if (opts != NULL) { + switch (def->type) { + case VM_METHOD_TYPE_ISEQ: + { + rb_method_iseq_t *iseq_body = (rb_method_iseq_t *)opts; + rb_cref_t *method_cref, *cref = iseq_body->cref; + + /* setup iseq first (before invoking GC) */ + RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, iseq_body->iseqptr); + + if (0) vm_cref_dump("rb_method_definition_create", cref); + + if (cref) { + method_cref = cref; + } + else { + method_cref = vm_cref_new_toplevel(GET_EC()); /* TODO: can we reuse? */ + } + + RB_OBJ_WRITE(me, &def->body.iseq.cref, method_cref); + return; + } + case VM_METHOD_TYPE_CFUNC: + { + rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts; + setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), cfunc->func, cfunc->argc); + return; + } + case VM_METHOD_TYPE_ATTRSET: + case VM_METHOD_TYPE_IVAR: + { + const rb_execution_context_t *ec = GET_EC(); + rb_control_frame_t *cfp; + int line; + + def->body.attr.id = (ID)(VALUE)opts; + + cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp); + + if (cfp && (line = rb_vm_get_sourceline(cfp))) { + VALUE location = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line)); + RB_OBJ_WRITE(me, &def->body.attr.location, rb_ary_freeze(location)); + } + else { + VM_ASSERT(def->body.attr.location == 0); + } + return; + } + case VM_METHOD_TYPE_BMETHOD: + RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts); + return; + case VM_METHOD_TYPE_NOTIMPLEMENTED: + setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), rb_f_notimplement, -1); + return; + case VM_METHOD_TYPE_OPTIMIZED: + def->body.optimize_type = (enum method_optimized_type)opts; + return; + case VM_METHOD_TYPE_REFINED: + { + const rb_method_refined_t *refined = (rb_method_refined_t *)opts; + RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me); + RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner); + return; + } + case VM_METHOD_TYPE_ALIAS: + RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts); + return; + case VM_METHOD_TYPE_ZSUPER: + case VM_METHOD_TYPE_UNDEF: + case VM_METHOD_TYPE_MISSING: + return; + } + } +} + static void method_definition_reset(const rb_method_entry_t *me) { - const rb_method_definition_t *def = me->def; + rb_method_definition_t *def = me->def; switch(def->type) { case VM_METHOD_TYPE_ISEQ: @@ -247,218 +341,14 @@ method_definition_reset(const rb_method_entry_t *me) } } -static rb_cref_t* -the_top_cref(void) +MJIT_FUNC_EXPORTED rb_method_definition_t * +rb_method_definition_create(rb_method_type_t type, ID mid) { - static rb_cref_t *top = NULL; - if (!top) { - top = vm_cref_new_toplevel(GET_EC()); - rb_gc_register_mark_object((VALUE)top); // cref is an IMEMO. - } - return top; -} - -static rb_method_iseq_t -the_method_iseq(const rb_method_iseq_t *p) -{ - return (rb_method_iseq_t) { - .iseqptr = p->iseqptr, - .cref = p->cref ? p->cref : the_top_cref(), - }; -} - -static rb_method_cfunc_t -the_method_cfunc(const rb_method_cfunc_t *p) -{ - return (rb_method_cfunc_t) { - .func = p->func, - .invoker = call_cfunc_invoker_func(p->argc), - .argc = p->argc, - }; -} - -static VALUE -the_location(void) -{ - const rb_execution_context_t *ec = GET_EC(); - const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp); - int line; - - if (!cfp) { - return Qfalse; - } - else if (! (line = rb_vm_get_sourceline(cfp))) { - return Qfalse; - } - else { - VALUE loc = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line)); - rb_ary_freeze(loc); - return loc; - } -} - -static rb_method_attr_t -the_method_attr(const void *p) -{ - return (rb_method_attr_t) { - .id = (ID)(VALUE)p, - .location = the_location(), - }; -} - -static rb_method_bmethod_t -the_method_bmethod(const void *p) -{ - return (rb_method_bmethod_t) { - .proc = (VALUE)p, - .hooks = NULL, - }; -} - -static rb_method_cfunc_t -the_method_notimplemented(void) -{ - return (rb_method_cfunc_t) { - .func = rb_f_notimplement, - .invoker = call_cfunc_m1, - .argc = -1, - }; -} - -static enum method_optimized_type -the_method_optimized(const void *p) -{ - return (enum method_optimized_type)p; -} - -static rb_method_refined_t -the_method_refined(const rb_method_refined_t *p) -{ - if (!p) { - return (rb_method_refined_t) { 0, }; - } - else { - return (rb_method_refined_t) { - .orig_me = p->orig_me, - .owner = p->owner, - }; - } -} - -static rb_method_alias_t -the_method_alias(const rb_method_entry_t *p) -{ - return (rb_method_alias_t) { - .original_me = p, - }; -} - -static rb_method_definition_t -rb_method_definition_new(rb_method_type_t type, ID mid, const void *opts) -{ - switch (type) { - case VM_METHOD_TYPE_ISEQ: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .iseq = the_method_iseq(opts), - } - }; - - case VM_METHOD_TYPE_CFUNC: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .cfunc = the_method_cfunc(opts), - } - }; - - case VM_METHOD_TYPE_ATTRSET: - case VM_METHOD_TYPE_IVAR: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .attr = the_method_attr(opts), - } - }; - - case VM_METHOD_TYPE_BMETHOD: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .bmethod = the_method_bmethod(opts), - } - }; - - case VM_METHOD_TYPE_NOTIMPLEMENTED: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .cfunc = the_method_notimplemented(), - } - }; - - case VM_METHOD_TYPE_OPTIMIZED: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .optimize_type = the_method_optimized(opts), - } - }; - - case VM_METHOD_TYPE_REFINED: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .refined = the_method_refined(opts), - } - }; - - case VM_METHOD_TYPE_ALIAS: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - .body = { - .alias = the_method_alias(opts), - } - }; - - case VM_METHOD_TYPE_ZSUPER: - case VM_METHOD_TYPE_UNDEF: - case VM_METHOD_TYPE_MISSING: - return (rb_method_definition_t) { - .type = type, - .original_id = mid, - }; - } - - UNREACHABLE_RETURN((rb_method_definition_t){0}); -} - -MJIT_FUNC_EXPORTED void -rb_method_entry_spoof(const rb_method_entry_t *me) -{ - VALUE v = (VALUE)me; - VALUE o = me->owner; - rb_id_table_insert(RCLASS_M_TBL(o), me->called_id, v); - RB_OBJ_WRITTEN(o, Qundef, v); - rb_clear_method_cache_by_class(o); -} - -static const rb_method_definition_t * -rb_method_definition_create(rb_method_type_t type, ID mid, const void *opts) -{ - rb_method_definition_t template = rb_method_definition_new(type, mid, opts); - void *ptr = ALLOC(rb_method_definition_t); - memcpy(ptr, &template, sizeof template); - return ptr; + rb_method_definition_t *def; + def = ZALLOC(rb_method_definition_t); + def->type = type; + def->original_id = mid; + return def; } static rb_method_definition_t * @@ -477,15 +367,10 @@ method_definition_addref_complement(rb_method_definition_t *def) return def; } -static const rb_method_entry_t * -rb_method_entry_alloc(VALUE flags, ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def) +static rb_method_entry_t * +rb_method_entry_alloc(ID called_id, VALUE owner, VALUE defined_class, const rb_method_definition_t *def) { - VALUE v = rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class); - RBASIC(v)->flags = - (RBASIC(v)->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) | - (flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)); - const rb_method_entry_t *me = (void *)v; - method_definition_reset(me); + rb_method_entry_t *me = (rb_method_entry_t *)rb_imemo_new(imemo_ment, (VALUE)def, (VALUE)called_id, owner, defined_class); return me; } @@ -503,58 +388,33 @@ filter_defined_class(VALUE klass) rb_bug("filter_defined_class: %s", rb_obj_info(klass)); } -static inline VALUE -method_entry_flags(rb_method_visibility_t visi) +rb_method_entry_t * +rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def) { - return (visi << (IMEMO_FL_USHIFT+0)) | - ((!ruby_running) << (IMEMO_FL_USHIFT+2)); -} - -MJIT_FUNC_EXPORTED const rb_method_entry_t * -rb_method_entry_from_template( - const rb_method_entry_t *me, - const void *body) -{ - return rb_method_entry_alloc( - me->flags, - me->called_id, - me->owner, - me->defined_class, - rb_method_definition_create( - me->def->type, - me->def->original_id, - body)); -} - -const rb_method_entry_t * -rb_method_entry_for_missing(ID mid, VALUE klass) -{ - return rb_method_entry_alloc( - method_entry_flags(METHOD_VISI_UNDEF), - mid, - klass, - filter_defined_class(klass), - rb_method_definition_create( - VM_METHOD_TYPE_MISSING, - mid, - NULL)); + rb_method_entry_t *me = rb_method_entry_alloc(called_id, klass, filter_defined_class(klass), def); + METHOD_ENTRY_FLAGS_SET(me, visi, ruby_running ? FALSE : TRUE); + if (def != NULL) method_definition_reset(me); + return me; } const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me) { - return rb_method_entry_alloc( - src_me->flags, - src_me->called_id, - src_me->owner, - src_me->defined_class, - method_definition_addref(src_me->def)); + rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class, + method_definition_addref(src_me->def)); + METHOD_ENTRY_FLAGS_COPY(me, src_me); + return me; } MJIT_FUNC_EXPORTED 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_method_definition_t *def = src_me->def; + rb_method_definition_t *def = src_me->def; + rb_method_entry_t *me; + struct { + const struct rb_method_entry_struct *orig_me; + VALUE owner; + } refined = {0}; if (!src_me->defined_class && def->type == VM_METHOD_TYPE_REFINED && @@ -562,69 +422,73 @@ rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID cal const rb_method_entry_t *orig_me = rb_method_entry_clone(def->body.refined.orig_me); RB_OBJ_WRITE((VALUE)orig_me, &orig_me->defined_class, defined_class); - def = rb_method_definition_create( - VM_METHOD_TYPE_REFINED, - called_id, - &(rb_method_refined_t) { - .orig_me = orig_me, - .owner = orig_me->owner}); - + refined.orig_me = orig_me; + refined.owner = orig_me->owner; + def = NULL; } else { - def = method_definition_addref_complement((rb_method_definition_t *)def); + def = method_definition_addref_complement(def); + } + me = rb_method_entry_alloc(called_id, src_me->owner, defined_class, def); + METHOD_ENTRY_FLAGS_COPY(me, src_me); + METHOD_ENTRY_COMPLEMENTED_SET(me); + if (!def) { + def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, called_id); + rb_method_definition_set(me, def, &refined); } - const rb_method_entry_t *me = - rb_method_entry_alloc( - src_me->flags, - called_id, - src_me->owner, - defined_class, - def); VM_ASSERT(RB_TYPE_P(me->owner, T_MODULE)); - return (const rb_callable_method_entry_t *)me; + return (rb_callable_method_entry_t *)me; } -static const rb_method_entry_t* -make_method_entry_refined(VALUE owner, const rb_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 void +make_method_entry_refined(VALUE owner, rb_method_entry_t *me) { if (me->def->type == VM_METHOD_TYPE_REFINED) { - return me; + return; } else { + struct { + struct rb_method_entry_struct *orig_me; + VALUE owner; + } refined; + rb_method_definition_t *def; + rb_vm_check_redefinition_opt_method(me, me->owner); - /* :FIXME: can rb_method_entry_from_template be tweaked to also be - * applicable here? */ - return rb_method_entry_alloc( - method_entry_flags(METHOD_VISI_PUBLIC), - me->called_id, - me->owner, - me->defined_class, - rb_method_definition_create( - VM_METHOD_TYPE_REFINED, - me->called_id, - &(rb_method_refined_t) { - .owner = owner, - .orig_me = - rb_method_entry_alloc( - me->flags, - me->called_id, - me->owner, - me->defined_class ? - me->defined_class : owner, - method_definition_addref(me->def))})); + + refined.orig_me = + rb_method_entry_alloc(me->called_id, me->owner, + me->defined_class ? + me->defined_class : owner, + method_definition_addref(me->def)); + METHOD_ENTRY_FLAGS_COPY(refined.orig_me, me); + refined.owner = owner; + + def = rb_method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id); + rb_method_definition_set(me, def, (void *)&refined); + METHOD_ENTRY_VISI_SET(me, METHOD_VISI_PUBLIC); } } void rb_add_refined_method_entry(VALUE refined_class, ID mid) { - const rb_method_entry_t *me = lookup_method_table(refined_class, mid); + rb_method_entry_t *me = lookup_method_table(refined_class, mid); if (me) { - me = make_method_entry_refined(refined_class, me); - rb_method_entry_spoof(me); + make_method_entry_refined(refined_class, me); rb_clear_method_cache_by_class(refined_class); } else { @@ -654,10 +518,11 @@ check_override_opt_method(VALUE klass, VALUE arg) * If def is given (!= NULL), then just use it and ignore original_id and otps. * If not given, then make a new def with original_id and opts. */ -static const rb_method_entry_t * +static rb_method_entry_t * rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibility_t visi, - rb_method_type_t type, const rb_method_definition_t *def, ID original_id, void *opts) + rb_method_type_t type, rb_method_definition_t *def, ID original_id, void *opts) { + rb_method_entry_t *me; struct rb_id_table *mtbl; st_data_t data; int make_refined = 0; @@ -685,7 +550,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil rb_add_refined_method_entry(refined_class, mid); } if (type == VM_METHOD_TYPE_REFINED) { - const rb_method_entry_t *old_me = lookup_method_table(RCLASS_ORIGIN(klass), mid); + 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 { @@ -695,8 +560,8 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil /* check re-definition */ if (rb_id_table_lookup(mtbl, mid, &data)) { - const rb_method_entry_t *old_me = (const rb_method_entry_t *)data; - const rb_method_definition_t *old_def = old_me->def; + rb_method_entry_t *old_me = (rb_method_entry_t *)data; + rb_method_definition_t *old_def = old_me->def; if (rb_method_definition_eq(old_def, def)) return old_me; rb_vm_check_redefinition_opt_method(old_me, klass); @@ -733,16 +598,9 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil } /* create method entry */ - if (!def) { - def = rb_method_definition_create(type, original_id, opts); - } - const rb_method_entry_t *me = - rb_method_entry_alloc( - method_entry_flags(visi), - mid, - defined_class, - filter_defined_class(defined_class), - def); + me = rb_method_entry_create(mid, defined_class, visi, NULL); + if (def == NULL) def = rb_method_definition_create(type, original_id); + rb_method_definition_set(me, def, opts); rb_clear_method_cache_by_class(klass); @@ -764,7 +622,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil } if (make_refined) { - me = make_method_entry_refined(klass, me); + make_method_entry_refined(klass, me); } rb_id_table_insert(mtbl, mid, (VALUE)me); @@ -812,21 +670,27 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_ MJIT_FUNC_EXPORTED void rb_add_method_iseq(VALUE klass, ID mid, const rb_iseq_t *iseq, rb_cref_t *cref, rb_method_visibility_t visi) { - rb_method_iseq_t iseq_body = { iseq, cref }; + struct { /* should be same fields with rb_method_iseq_struct */ + const rb_iseq_t *iseqptr; + rb_cref_t *cref; + } iseq_body; + + iseq_body.iseqptr = iseq; + iseq_body.cref = cref; rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, &iseq_body, visi); } -static const rb_method_entry_t * +static rb_method_entry_t * method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_visibility_t visi, VALUE defined_class) { - const rb_method_entry_t *newme = rb_method_entry_make(klass, mid, defined_class, visi, + rb_method_entry_t *newme = rb_method_entry_make(klass, mid, defined_class, visi, me->def->type, method_definition_addref(me->def), 0, NULL); method_added(klass, mid); return newme; } -const rb_method_entry_t * +rb_method_entry_t * rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_visibility_t visi) { return method_entry_set(klass, mid, me, visi, klass); @@ -860,10 +724,10 @@ rb_get_alloc_func(VALUE klass) return 0; } -static inline const rb_method_entry_t* +static inline rb_method_entry_t* search_method(VALUE klass, ID id, VALUE *defined_class_ptr) { - const rb_method_entry_t *me; + rb_method_entry_t *me; for (; klass; klass = RCLASS_SUPER(klass)) { RB_DEBUG_COUNTER_INC(mc_search_super); @@ -887,12 +751,12 @@ rb_method_entry_at(VALUE klass, ID id) * if you need method entry with method cache (normal case), use * rb_method_entry() simply. */ -static const rb_method_entry_t * +static rb_method_entry_t * method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr) { VALUE defined_class; - const rb_method_entry_t *me = search_method(klass, id, &defined_class); + rb_method_entry_t *me = search_method(klass, id, &defined_class); if (ruby_running) { if (OPT_GLOBAL_METHOD_CACHE) { @@ -924,11 +788,11 @@ method_entry_get_without_cache(VALUE klass, ID id, } static void -verify_method_cache(VALUE klass, ID id, VALUE defined_class, const rb_method_entry_t *me) +verify_method_cache(VALUE klass, ID id, VALUE defined_class, rb_method_entry_t *me) { if (!VM_DEBUG_VERIFY_METHOD_CACHE) return; VALUE actual_defined_class; - const rb_method_entry_t *actual_me = + rb_method_entry_t *actual_me = method_entry_get_without_cache(klass, id, &actual_defined_class); if (me != actual_me || defined_class != actual_defined_class) { @@ -936,7 +800,7 @@ verify_method_cache(VALUE klass, ID id, VALUE defined_class, const rb_method_ent } } -static const rb_method_entry_t * +static rb_method_entry_t * method_entry_get(VALUE klass, ID id, VALUE *defined_class_ptr) { struct cache_entry *ent; @@ -977,7 +841,7 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ if (mtbl && rb_id_table_lookup(mtbl, id, (VALUE *)&me)) { RB_DEBUG_COUNTER_INC(mc_cme_complement_hit); - cme = (const rb_callable_method_entry_t *)me; + cme = (rb_callable_method_entry_t *)me; VM_ASSERT(callable_method_entry_p(cme)); } else { @@ -1001,7 +865,7 @@ MJIT_FUNC_EXPORTED const rb_callable_method_entry_t * rb_callable_method_entry(VALUE klass, ID id) { VALUE defined_class; - const rb_method_entry_t *me = method_entry_get(klass, id, &defined_class); + rb_method_entry_t *me = method_entry_get(klass, id, &defined_class); return prepare_callable_method_entry(defined_class, id, me); } @@ -1115,7 +979,7 @@ static void remove_method(VALUE klass, ID mid) { VALUE data; - const rb_method_entry_t *me = NULL; + rb_method_entry_t *me = 0; VALUE self = klass; klass = RCLASS_ORIGIN(klass); @@ -1125,7 +989,7 @@ remove_method(VALUE klass, ID mid) } if (!rb_id_table_lookup(RCLASS_M_TBL(klass), mid, &data) || - !(me = (const rb_method_entry_t *)data) || + !(me = (rb_method_entry_t *)data) || (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_name_err_raise("method `%1$s' not defined in %2$s", @@ -1183,18 +1047,10 @@ rb_mod_remove_method(int argc, VALUE *argv, VALUE mod) return mod; } -static inline void -METHOD_ENTRY_VISI_SET(rb_method_entry_t *me, rb_method_visibility_t visi) -{ - VM_ASSERT((int)visi >= 0 && visi <= 3); - VALUE flags = (me->flags & ~(IMEMO_FL_USER0 | IMEMO_FL_USER1)) | (visi << (IMEMO_FL_USHIFT+0)); - memcpy((void *)&me->flags, &flags, sizeof flags); -} - static void rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi) { - const rb_method_entry_t *me; + rb_method_entry_t *me; VALUE defined_class; VALUE origin_class = RCLASS_ORIGIN(klass); @@ -1212,7 +1068,7 @@ rb_export_method(VALUE klass, ID name, rb_method_visibility_t visi) rb_vm_check_redefinition_opt_method(me, klass); if (klass == defined_class || origin_class == defined_class) { - METHOD_ENTRY_VISI_SET((rb_method_entry_t *)me, visi); + METHOD_ENTRY_VISI_SET(me, visi); if (me->def->type == VM_METHOD_TYPE_REFINED && me->def->body.refined.orig_me) { METHOD_ENTRY_VISI_SET((rb_method_entry_t *)me->def->body.refined.orig_me, visi); @@ -1740,7 +1596,7 @@ rb_alias(VALUE klass, ID alias_name, ID original_name) method_added(target_klass, alias_name); } else { - const rb_method_entry_t *alias_me; + rb_method_entry_t *alias_me; alias_me = method_entry_set(target_klass, alias_name, orig_me, visi, orig_me->owner); RB_OBJ_WRITE(alias_me, &alias_me->owner, target_klass); @@ -1931,7 +1787,7 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module) for (i = 0; i < argc; i++) { VALUE v = argv[i]; ID name = rb_check_id(&v); - const rb_method_entry_t *me; + rb_method_entry_t *me; VALUE defined_class; if (!name) {