static VALUE rb_mod_modfunc(VALUE module, SEL sel, int argc, VALUE *argv) { if (TYPE(module) != T_MODULE) { rb_raise(rb_eTypeError, "module_function must be called for modules"); } secure_visibility(module); if (argc == 0) { rb_vm_set_current_scope(module, SCOPE_MODULE_FUNC); return module; } set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (int i = 0; i < argc; i++) { ID id = rb_to_id(argv[i]); IMP imp = NULL; rb_vm_method_node_t *node = NULL; SEL sel = 0; if (rb_vm_lookup_method2((Class)module, id, &sel, &imp, &node) || (TYPE(module) == T_MODULE && rb_vm_lookup_method2((Class)rb_cObject, id, &sel, &imp, &node))) { rb_vm_define_method2(*(Class *)module, sel, node, -1, false); } else { rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); } } return module; }
static void rb_export_method(VALUE klass, ID name, ID noex) { rb_vm_method_node_t *node; SEL sel; if (klass == rb_cObject) { rb_secure(4); } if (!rb_vm_lookup_method2((Class)klass, name, &sel, NULL, &node)) { if (TYPE(klass) != T_MODULE || !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL, &node)) { rb_print_undef(klass, name, 0); } } #if 0 // TODO if (node->nd_noex != noex) { // TODO if the method exists on a super class, we should add a new method // with the correct noex that calls super assert(!rb_vm_lookup_method((Class)RCLASS_SUPER(klass), sel, NULL, NULL)); node->nd_noex = noex; } #endif }
static VALUE rb_mod_modfunc(VALUE module, SEL sel, int argc, VALUE *argv) { int i; if (TYPE(module) != T_MODULE) { rb_raise(rb_eTypeError, "module_function must be called for modules"); } secure_visibility(module); if (argc == 0) { // TODO change scope! return module; } set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (i = 0; i < argc; i++) { ID id = rb_to_id(argv[i]); IMP imp; rb_vm_method_node_t *node; SEL sel; if (!rb_vm_lookup_method2((Class)module, id, &sel, &imp, &node)) { // Methods are checked in set_method_visibility(). rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); } rb_vm_define_method2(*(Class *)module, sel, node, false); } return module; }
static void rb_export_method(VALUE klass, ID name, ID noex) { rb_vm_method_node_t *node; SEL sel; if (klass == rb_cObject) { rb_secure(4); } if (!rb_vm_lookup_method2((Class)klass, name, &sel, NULL, &node)) { if (TYPE(klass) != T_MODULE || !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL, &node)) { rb_print_undef(klass, name, 0); } } if (node == NULL) { rb_raise(rb_eRuntimeError, "can't change visibility of non Ruby method `%s'", sel_getName(sel)); } long flags = (node->flags & ~VM_METHOD_PRIVATE) & ~VM_METHOD_PROTECTED; switch (noex) { case NOEX_PRIVATE: flags |= VM_METHOD_PRIVATE; break; case NOEX_PROTECTED: flags |= VM_METHOD_PROTECTED; break; default: break; } if (node->flags != flags) { if (node->klass == (Class)klass) { node->flags = flags; } else { rb_vm_define_method2((Class)klass, sel, node, flags, false); } } }
rb_vm_method_t * rb_vm_get_method(VALUE klass, VALUE obj, ID mid, int scope) { SEL sel = 0; IMP imp = NULL; rb_vm_method_node_t *node = NULL; // TODO honor scope if (!rb_vm_lookup_method2((Class)klass, mid, &sel, &imp, &node)) { rb_print_undef(klass, mid, 0); } Class k, oklass = (Class)klass; while ((k = class_getSuperclass(oklass)) != NULL) { if (!rb_vm_lookup_method(k, sel, NULL, NULL)) { break; } oklass = k; } Method method = class_getInstanceMethod((Class)klass, sel); assert(method != NULL); int arity; rb_vm_method_node_t *new_node; if (node == NULL) { arity = rb_method_getNumberOfArguments(method) - 2; new_node = NULL; } else { arity = rb_vm_arity_n(node->arity); new_node = (rb_vm_method_node_t *)xmalloc(sizeof(rb_vm_method_node_t)); memcpy(new_node, node, sizeof(rb_vm_method_node_t)); } rb_vm_method_t *m = (rb_vm_method_t *)xmalloc(sizeof(rb_vm_method_t)); m->oclass = (VALUE)oklass; m->rclass = klass; GC_WB(&m->recv, obj); m->sel = sel; m->arity = arity; GC_WB(&m->node, new_node); // Let's allocate a static cache here, since a rb_vm_method_t must always // point to the method it was created from. struct mcache *c = (struct mcache *)xmalloc(sizeof(struct mcache)); if (new_node == NULL) { fill_ocache(c, obj, oklass, imp, sel, method, arity); } else { fill_rcache(c, oklass, sel, new_node); } GC_WB(&m->cache, c); return m; }
static VALUE check_method_visibility(VALUE mod, ID id, int visi) { rb_vm_method_node_t *node; if (rb_vm_lookup_method2((Class)mod, id, NULL, NULL, &node)) { if (node != NULL) { if ((node->flags & NOEX_MASK) == visi) { return Qtrue; } } } return Qfalse; }
static VALUE rb_mod_method_defined(VALUE mod, SEL sel, VALUE mid) { ID id = rb_to_id(mid); if (rb_obj_respond_to2(Qnil, mod, id, true, false)) { rb_vm_method_node_t *node; if (rb_vm_lookup_method2((Class)mod, id, NULL, NULL, &node)) { if (node != NULL) { if (node->flags & NOEX_PRIVATE) { return Qfalse; } } return Qtrue; } } return Qfalse; }