NODE * rb_method_node(VALUE klass, ID id) { return NULL; #if 0 // TODO NODE *node = rb_objc_method_node(klass, id, NULL, NULL); if (node == NULL && id != ID_ALLOCATOR) { const char *id_str = rb_id2name(id); size_t slen = strlen(id_str); if (strcmp(id_str, "retain") == 0 || strcmp(id_str, "release") == 0 || strcmp(id_str, "zone") == 0) { char buf[100]; snprintf(buf, sizeof buf, "__rb_%s__", id_str); return rb_method_node(klass, rb_intern(buf)); } else { if (id_str[slen - 1] == ':') { return NULL; } else { char buf[100]; snprintf(buf, sizeof buf, "%s:", id_str); return rb_method_node(klass, rb_intern(buf)); } } } return node; #endif }
static inline VALUE vm_call_super(rb_thread_t * const th, const int argc, const VALUE * const argv) { VALUE recv = th->cfp->self; VALUE klass; ID id; NODE *body; rb_control_frame_t *cfp = th->cfp; if (!cfp->iseq) { klass = cfp->method_class; klass = RCLASS_SUPER(klass); if (klass == 0) { klass = vm_search_normal_superclass(cfp->method_class, recv); } id = cfp->method_id; } else { rb_bug("vm_call_super: should not be reached"); } body = rb_method_node(klass, id); /* this returns NODE_METHOD */ if (!body) { return method_missing(recv, id, argc, argv, 0); } return vm_call0(th, klass, recv, id, (ID)body->nd_file, argc, argv, body->nd_body, CALL_SUPER); }
static inline void vm_send_optimize(rb_control_frame_t * const reg_cfp, NODE ** const mn, rb_num_t * const flag, rb_num_t * const num, ID * const id, const VALUE klass) { if (*mn && nd_type((*mn)->nd_body) == NODE_CFUNC) { NODE *node = (*mn)->nd_body; extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); if (node->nd_cfnc == rb_f_send) { int i = *num - 1; VALUE 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); } *mn = rb_method_node(klass, *id); *num -= 1; DEC_SP(1); *flag |= VM_CALL_FCALL_BIT; } } }
int rb_method_basic_definition_p(VALUE klass, ID id) { NODE *node = rb_method_node(klass, id); if (node && (node->nd_noex & NOEX_BASIC)) return 1; return 0; }
rb_alloc_func_t rb_get_alloc_func(VALUE klass) { NODE *n; Check_Type(klass, T_CLASS); n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR); if (!n) return 0; if (nd_type(n) != NODE_METHOD) return 0; n = n->nd_body; if (nd_type(n) != NODE_CFUNC) return 0; return (rb_alloc_func_t)n->nd_cfnc; }
static VALUE rb_mod_protected_method_defined(VALUE mod, VALUE mid) { ID id = rb_to_id(mid); NODE *method; method = rb_method_node(mod, id); if (method) { if (VISI_CHECK(method->nd_noex, NOEX_PROTECTED)) return Qtrue; } return Qfalse; }
static VALUE rb_mod_public_method_defined(VALUE mod, VALUE mid) { ID id = rb_to_id(mid); NODE *method; method = rb_method_node(mod, id); if (method) { if (VISI_CHECK(method->nd_noex, NOEX_PUBLIC)) return Qtrue; } return Qfalse; }
int rb_method_boundp(VALUE klass, ID id, int ex) { NODE *method; if ((method = rb_method_node(klass, id)) != 0) { if (ex && (method->nd_noex & NOEX_PRIVATE)) { return Qfalse; } return Qtrue; } return Qfalse; }
static VALUE rb_mod_private_method_defined(VALUE mod, SEL sel, VALUE mid) { ID id = rb_to_id(mid); NODE *method; method = rb_method_node(mod, id); if (method) { if (VISI_CHECK(method->nd_noex, NOEX_PRIVATE)) return Qtrue; } return Qfalse; }
static NODE * search_method(VALUE klass, ID id, VALUE *klassp) { NODE *node; if (klass == 0) { return NULL; } node = rb_method_node(klass, id); if (node != NULL) { if (klassp != NULL) { /* TODO honour klassp */ *klassp = klass; } } return node; }
int rb_obj_respond_to(VALUE obj, ID id, int priv) { VALUE klass = CLASS_OF(obj); if (rb_method_node(klass, idRespond_to) == basic_respond_to) { return rb_method_boundp(klass, id, !priv); } else { VALUE args[2]; int n = 0; args[n++] = ID2SYM(id); if (priv) args[n++] = Qtrue; return RTEST(rb_funcall2(obj, idRespond_to, n, args)); } }
void Init_eval_method(void) { #undef rb_intern rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1); basic_respond_to = rb_method_node(rb_cObject, idRespond_to); rb_register_mark_object((VALUE)basic_respond_to); rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1); rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1); rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2); rb_define_private_method(rb_cModule, "public", rb_mod_public, -1); rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1); rb_define_private_method(rb_cModule, "private", rb_mod_private, -1); rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1); rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1); rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1); rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1); rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1); rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1); rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1); rb_define_singleton_method(rb_vm_top_self(), "public", top_public, -1); rb_define_singleton_method(rb_vm_top_self(), "private", top_private, -1); object_id = rb_intern("object_id"); __send__ = rb_intern("__send__"); eqq = rb_intern("==="); each = rb_intern("each"); aref = rb_intern("[]"); aset = rb_intern("[]="); match = rb_intern("=~"); missing = rb_intern("method_missing"); added = rb_intern("method_added"); singleton_added = rb_intern("singleton_method_added"); removed = rb_intern("method_removed"); singleton_removed = rb_intern("singleton_method_removed"); undefined = rb_intern("method_undefined"); singleton_undefined = rb_intern("singleton_method_undefined"); }
static inline VALUE vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, int argc, const VALUE *argv, const NODE *body, int nosuper) { VALUE val; rb_block_t *blockptr = 0; if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n", rb_id2name(id), ruby_node_name(nd_type(body)), argc, (void *)th->passed_block); if (th->passed_block) { blockptr = th->passed_block; th->passed_block = 0; } again: switch (nd_type(body)) { case RUBY_VM_METHOD_NODE:{ rb_control_frame_t *reg_cfp; VALUE iseqval = (VALUE)body->nd_body; int i; rb_vm_set_finish_env(th); reg_cfp = th->cfp; CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) { *reg_cfp->sp++ = argv[i]; } vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv); val = vm_exec(th); break; } case NODE_CFUNC: { EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); { rb_control_frame_t *reg_cfp = th->cfp; rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); cfp->method_id = oid; cfp->method_class = klass; val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv); if (reg_cfp != th->cfp + 1) { SDR2(reg_cfp); SDR2(th->cfp-5); rb_bug("cfp consistency error - call0"); th->cfp = reg_cfp; } vm_pop_frame(th); } EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); break; } case NODE_ATTRSET:{ if (argc != 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } val = rb_ivar_set(recv, body->nd_vid, argv[0]); break; } case NODE_IVAR: { if (argc != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } val = rb_attr_get(recv, body->nd_vid); break; } case NODE_BMETHOD:{ val = vm_call_bmethod(th, oid, body->nd_cval, recv, klass, argc, (VALUE *)argv, blockptr); break; } case NODE_ZSUPER:{ klass = RCLASS_SUPER(klass); if (!klass || !(body = rb_method_node(klass, id))) { return method_missing(recv, id, argc, argv, 0); } RUBY_VM_CHECK_INTS(); nosuper = CALL_SUPER; body = body->nd_body; goto again; } default: rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body))); } RUBY_VM_CHECK_INTS(); return val; }
int rb_mod_method_arity(VALUE mod, ID id) { NODE *node = rb_method_node(mod, id); return rb_node_arity(node); }
static inline VALUE vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp, const int num, rb_block_t * const blockptr, const VALUE flag, const ID id, const NODE * mn, const VALUE recv) { VALUE val; start_method_dispatch: if (mn != 0) { if ((mn->nd_noex == 0)) { /* dispatch method */ NODE *node; normal_method_dispatch: node = mn->nd_body; switch (nd_type(node)) { case RUBY_VM_METHOD_NODE:{ vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv); return Qundef; } case NODE_CFUNC:{ val = vm_call_cfunc(th, cfp, num, id, (ID)mn->nd_file, recv, mn->nd_clss, flag, node, blockptr); break; } case NODE_ATTRSET:{ val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1)); cfp->sp -= 2; break; } case NODE_IVAR:{ if (num != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num); } val = rb_attr_get(recv, node->nd_vid); cfp->sp -= 1; break; } case NODE_BMETHOD:{ VALUE *argv = ALLOCA_N(VALUE, num); MEMCPY(argv, cfp->sp - num, VALUE, num); cfp->sp += - num - 1; val = vm_call_bmethod(th, (ID)mn->nd_file, node->nd_cval, recv, mn->nd_clss, num, argv, blockptr); break; } case NODE_ZSUPER:{ VALUE klass; klass = RCLASS_SUPER(mn->nd_clss); mn = rb_method_node(klass, id); if (mn != 0) { goto normal_method_dispatch; } else { goto start_method_dispatch; } } default:{ printf("node: %s\n", ruby_node_name(nd_type(node))); rb_bug("eval_invoke_method: unreachable"); /* unreachable */ break; } } } else { int noex_safe; if (!(flag & VM_CALL_FCALL_BIT) && (mn->nd_noex & 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 (((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) && !(flag & VM_CALL_SEND_BIT)) { VALUE defined_class = mn->nd_clss; if (TYPE(defined_class) == T_ICLASS) { defined_class = RBASIC(defined_class)->klass; } if (!rb_obj_is_kind_of(cfp->self, rb_class_real(defined_class))) { val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); } else { goto normal_method_dispatch; } } else if ((noex_safe = NOEX_SAFE(mn->nd_noex)) > 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 */ if (id == idMethodMissing) { rb_bug("method missing"); } else { int stat = 0; if (flag & VM_CALL_VCALL_BIT) { stat |= NOEX_VCALL; } if (flag & VM_CALL_SUPER_BIT) { stat |= NOEX_SUPER; } val = vm_method_missing(th, id, recv, num, blockptr, stat); } } RUBY_VM_CHECK_INTS(); return val; }