Пример #1
0
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
}
Пример #2
0
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);
}
Пример #3
0
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;
	}
    }
}
Пример #4
0
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;
}
Пример #5
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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));
    }
}
Пример #12
0
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");
}
Пример #13
0
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;
}
Пример #14
0
int
rb_mod_method_arity(VALUE mod, ID id)
{
    NODE *node = rb_method_node(mod, id);
    return rb_node_arity(node);
}
Пример #15
0
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;
}