rb_method_entry_t * rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr) { if (me && me->def->type == VM_METHOD_TYPE_REFINED) { VALUE refinement; rb_method_entry_t *tmp_me; refinement = find_refinement(refinements, me->klass); if (NIL_P(refinement)) { return get_original_method_entry(refinements, me, 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, defined_class_ptr); } } else { return (rb_method_entry_t *)me; } }
int rb_method_basic_definition_p(VALUE klass, ID id) { const rb_method_entry_t *me = rb_method_entry(klass, id, 0); if (me && (me->flag & NOEX_BASIC)) return 1; return 0; }
int rb_obj_basic_to_s_p(VALUE obj) { const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s")); if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == rb_any_to_s) return 1; return 0; }
static VALUE check_definition(VALUE mod, ID mid, rb_method_flag_t noex) { const rb_method_entry_t *me; me = rb_method_entry(mod, mid); if (me) { if (VISI_CHECK(me->flag, noex)) return Qtrue; } return Qfalse; }
rb_alloc_func_t rb_get_alloc_func(VALUE klass) { rb_method_entry_t *me; Check_Type(klass, T_CLASS); me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR); if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC) { return (rb_alloc_func_t)me->def->body.cfunc.func; } else { return 0; } }
rb_method_entry_t * rb_method_entry_with_refinements(VALUE klass, ID id, 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, &defined_class); } if (defined_class_ptr) *defined_class_ptr = defined_class; return me; }
int rb_method_boundp(VALUE klass, ID id, int ex) { rb_method_entry_t *me = rb_method_entry(klass, id); if (me != 0) { if ((ex & ~NOEX_RESPONDS) && (me->flag & NOEX_PRIVATE)) { return FALSE; } if (!me->def) return 0; if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) { if (ex & NOEX_RESPONDS) return 2; return 0; } return 1; } return 0; }
rb_method_entry_t * rb_method_entry_without_refinements(VALUE klass, ID id, 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) { me = rb_resolve_refined_method(Qnil, me, &defined_class); } if (defined_class_ptr) *defined_class_ptr = defined_class; if (UNDEFINED_METHOD_ENTRY_P(me)) { return 0; } else { return me; } }
static rb_method_entry_t * get_original_method_entry(VALUE refinements, const rb_method_entry_t *me, VALUE *defined_class_ptr) { VALUE super; if (me->def->body.orig_me) { return me->def->body.orig_me; } else if (!(super = RCLASS_SUPER(me->klass))) { return 0; } else { rb_method_entry_t *tmp_me; tmp_me = rb_method_entry(super, me->called_id, defined_class_ptr); return rb_resolve_refined_method(refinements, tmp_me, defined_class_ptr); } }
static inline VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, int num, const rb_block_t *blockptr, VALUE flag, ID id, const rb_method_entry_t *me, VALUE recv) { VALUE val; start_method_dispatch: if (me != 0) { if ((me->flag == 0)) { normal_method_dispatch: switch (me->def->type) { case VM_METHOD_TYPE_ISEQ:{ vm_setup_method(th, cfp, recv, num, blockptr, flag, me); return Qundef; } case VM_METHOD_TYPE_NOTIMPLEMENTED: case VM_METHOD_TYPE_CFUNC:{ val = vm_call_cfunc(th, cfp, num, recv, blockptr, me); break; } case VM_METHOD_TYPE_ATTRSET:{ if (num != 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num); } val = rb_ivar_set(recv, me->def->body.attr.id, *(cfp->sp - 1)); cfp->sp -= 2; break; } case VM_METHOD_TYPE_IVAR:{ if (num != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num); } val = rb_attr_get(recv, me->def->body.attr.id); cfp->sp -= 1; break; } case VM_METHOD_TYPE_MISSING:{ VALUE *argv = ALLOCA_N(VALUE, num+1); argv[0] = ID2SYM(me->def->original_id); MEMCPY(argv+1, cfp->sp - num, VALUE, num); cfp->sp += - num - 1; th->passed_block = blockptr; val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv); break; } case VM_METHOD_TYPE_BMETHOD:{ VALUE *argv = ALLOCA_N(VALUE, num); MEMCPY(argv, cfp->sp - num, VALUE, num); cfp->sp += - num - 1; val = vm_call_bmethod(th, recv, num, argv, blockptr, me); break; } case VM_METHOD_TYPE_ZSUPER:{ VALUE klass = RCLASS_SUPER(me->klass); me = rb_method_entry(klass, id); if (me != 0) { goto normal_method_dispatch; } else { goto start_method_dispatch; } } case VM_METHOD_TYPE_OPTIMIZED:{ switch (me->def->body.optimize_type) { case OPTIMIZED_METHOD_TYPE_SEND: { rb_control_frame_t *reg_cfp = cfp; rb_num_t i = num - 1; VALUE sym; if (num == 0) { rb_raise(rb_eArgError, "no method name given"); } sym = TOPN(i); id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); /* shift arguments */ if (i > 0) { MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); } me = rb_method_entry(CLASS_OF(recv), id); num -= 1; DEC_SP(1); flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT; goto start_method_dispatch; } case OPTIMIZED_METHOD_TYPE_CALL: { rb_proc_t *proc; int argc = num; VALUE *argv = ALLOCA_N(VALUE, num); GetProcPtr(recv, proc); MEMCPY(argv, cfp->sp - num, VALUE, num); cfp->sp -= num + 1; val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr); break; } default: rb_bug("eval_invoke_method: unsupported optimized method type (%d)", me->def->body.optimize_type); } break; } default:{ rb_bug("eval_invoke_method: unsupported method type (%d)", me->def->type); break; } } } else { int noex_safe; if (!(flag & VM_CALL_FCALL_BIT) && (me->flag & NOEX_MASK) & NOEX_PRIVATE) { int stat = NOEX_PRIVATE; if (flag & VM_CALL_VCALL_BIT) { stat |= NOEX_VCALL; } val = vm_method_missing(th, id, recv, num, blockptr, stat); } else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) { VALUE defined_class = me->klass; if (RB_TYPE_P(defined_class, T_ICLASS)) { defined_class = RBASIC(defined_class)->klass; } if (!rb_obj_is_kind_of(cfp->self, defined_class)) { val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); } else { goto normal_method_dispatch; } } else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level && (noex_safe > 2)) { rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id)); } else { goto normal_method_dispatch; } } } else { /* method missing */ int stat = 0; if (flag & VM_CALL_VCALL_BIT) { stat |= NOEX_VCALL; } if (flag & VM_CALL_SUPER_BIT) { stat |= NOEX_SUPER; } if (id == idMethodMissing) { VALUE *argv = ALLOCA_N(VALUE, num); vm_method_missing_args(th, argv, num - 1, 0, stat); rb_raise_method_missing(th, num, argv, recv, stat); } else { val = vm_method_missing(th, id, recv, num, blockptr, stat); } } RUBY_VM_CHECK_INTS(); return val; }