コード例 #1
0
ファイル: class.c プロジェクト: 1nueve/MacRuby
static VALUE
rb_obj_superclass(VALUE klass, SEL sel)
{
    VALUE cl = RCLASS_SUPER(klass);
    while (rb_class_hidden(cl)) {
	cl = RCLASS_SUPER(cl);
    }
    return rb_class_real(cl, true);
}
コード例 #2
0
ファイル: load.c プロジェクト: betacraft/ruby-vernac
static VALUE
rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
{
    VALUE klass = rb_class_real(rb_vm_cbase());
    if (NIL_P(klass)) {
	rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
    }
    return rb_mod_autoload(klass, sym, file);
}
コード例 #3
0
ファイル: marshal.c プロジェクト: agrimm/ruby-benchmark-suite
static VALUE
class2path(VALUE klass)
{
    VALUE path = rb_class_path(klass);
    const char *n;

    n = must_not_be_anonymous((TYPE(klass) == T_CLASS ? "class" : "module"), path);
    if (rb_path_to_class(path) != rb_class_real(klass)) {
	rb_raise(rb_eTypeError, "%s can't be referred to", n);
    }
    return path;
}
コード例 #4
0
ファイル: class.c プロジェクト: fi8on/ruby
/*!
 * Creates a singleton class for \a obj.
 * \pre \a obj must not a immediate nor a special const.
 * \pre \a obj must not a Class object.
 * \pre \a obj has no singleton class.
 */
static inline VALUE
make_singleton_class(VALUE obj)
{
    VALUE orig_class = RBASIC(obj)->klass;
    VALUE klass = rb_class_boot(orig_class);

    FL_SET(klass, FL_SINGLETON);
    RBASIC(obj)->klass = klass;
    rb_singleton_class_attached(klass, obj);

    METACLASS_OF(klass) = METACLASS_OF(rb_class_real(orig_class));
    return klass;
}
コード例 #5
0
ファイル: class.c プロジェクト: Watson1978/MacRuby
static void
check_class_super(ID id, VALUE klass, VALUE super)
{
    VALUE k = klass;
    do {
	k = RCLASS_SUPER(k);
    }
    while (k != 0 && rb_class_hidden(k));

    if (rb_class_real(k, true) != super) {
	rb_name_error(id, "%s is already defined", rb_id2name(id));
    }
}
コード例 #6
0
ファイル: class.c プロジェクト: asimoov/emscripted-ruby
VALUE
rb_make_metaclass(VALUE obj, VALUE super)
{
    VALUE klass = rb_class_boot(super);
    FL_SET(klass, FL_SINGLETON);
    RBASIC(obj)->klass = klass;
    rb_singleton_class_attached(klass, obj);
    if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
	RBASIC(klass)->klass = klass;
	RCLASS(klass)->super = RBASIC(rb_class_real(RCLASS(obj)->super))->klass;
    }
    else {
	VALUE metasuper = RBASIC(rb_class_real(super))->klass;

	/* metaclass of a superclass may be NULL at boot time */
	if (metasuper) {
	    RBASIC(klass)->klass = metasuper;
	}
    }

    return klass;
}
コード例 #7
0
ファイル: rbosa.c プロジェクト: bmorton/rubyosa
static VALUE
rbosa_element_eql (VALUE self, VALUE other)
{
    AEDesc *    self_desc;
    AEDesc *    other_desc; 
    Size        data_size;
    void *      self_data;
    void *      other_data;
    OSErr       error;
    Boolean     ok;

    if (!rb_obj_is_kind_of (other, rb_class_real (rb_class_of (self))))
        return Qfalse;

    self_desc = rbosa_element_aedesc (self);
    other_desc = rbosa_element_aedesc (other);

    if (self_desc == other_desc)
        return Qtrue;

    if (self_desc->descriptorType != other_desc->descriptorType)
        return Qfalse;

    data_size = AEGetDescDataSize (self_desc);
    if (data_size != AEGetDescDataSize (other_desc))
        return Qfalse;
  
    self_data = (void *)malloc (data_size);
    other_data = (void *)malloc (data_size);  
    ok = 0;

    if (self_data == NULL || other_data == NULL)
        rb_fatal ("cannot allocate memory");

    error = AEGetDescData (self_desc, self_data, data_size);
    if (error != noErr)
        goto bails;

    error = AEGetDescData (other_desc, other_data, data_size);
    if (error != noErr)
        goto bails;
    
    ok = memcmp (self_data, other_data, data_size) == 0;

bails:
    free (self_data);
    free (other_data);

    return CBOOL2RVAL (ok);
}
コード例 #8
0
ファイル: unmixer_mri.c プロジェクト: meh/blockenspiel
static VALUE do_unmix(VALUE self, VALUE receiver, VALUE module) {
  VALUE klass = CLASS_OF(receiver);
  while (klass != rb_class_real(klass)) {
    VALUE super = RCLASS_SUPER(klass);
    if (BUILTIN_TYPE(super) == T_ICLASS && CLASS_OF(super) == module) {
      if (RCLASS_SUPER(module) && BUILTIN_TYPE(RCLASS_SUPER(module)) == T_ICLASS) {
        remove_nested_module(super, module);
      }
      RCLASS_SUPER(klass) = RCLASS_SUPER(super);
      rb_clear_cache();
    }
    klass = super;
  }
  return receiver;
}
コード例 #9
0
ファイル: marshal.c プロジェクト: Sophrinix/iphone-macruby
static VALUE
class2path(VALUE klass)
{
    VALUE path = rb_class_path(klass);
    const char *n = RSTRING_PTR(path);

    if (n[0] == '#') {
	rb_raise(rb_eTypeError, "can't dump anonymous %s %s",
		 (TYPE(klass) == T_CLASS ? "class" : "module"),
		 n);
    }
    if (rb_path2class(n) != rb_class_real(klass)) {
	rb_raise(rb_eTypeError, "%s can't be referred", n);
    }
    return path;
}
コード例 #10
0
ファイル: rbgobj_type.c プロジェクト: benolee/ruby-gnome2
const RGObjClassInfo *
rbgobj_lookup_class(VALUE klass)
{
    VALUE data = rb_hash_aref(klass_to_cinfo, klass);
    if (!NIL_P(data)){
        RGObjClassInfo* cinfo;
        Data_Get_Struct(data, RGObjClassInfo, cinfo);
        return cinfo;
    }

    if (TYPE(klass) == T_CLASS) {
        VALUE super;
        if (FL_TEST(klass, FL_SINGLETON)) {
            super = rb_class_real(klass);
        } else {
            super = rb_funcall(klass, id_superclass, 0);
        }
        return rbgobj_lookup_class(super);
    }

    rb_raise(rb_eRuntimeError, "can't get gobject class information");
}
コード例 #11
0
ファイル: dispatcher.cpp プロジェクト: Hunter-Dolan/MacRuby
VALUE
rb_vm_dispatch(void *_vm, struct mcache *cache, VALUE top, VALUE self,
	Class klass, SEL sel, rb_vm_block_t *block, unsigned char opt,
	int argc, const VALUE *argv)
{
    RoxorVM *vm = (RoxorVM *)_vm;

#if ROXOR_VM_DEBUG
    bool cached = true;
#endif
    bool cache_method = true;

    Class current_super_class = vm->get_current_super_class();
    SEL current_super_sel = vm->get_current_super_sel();

    if (opt & DISPATCH_SUPER) {
	// TODO
	goto recache;
    }

    if (cache->sel != sel || cache->klass != klass || cache->flag == 0) {
recache:
#if ROXOR_VM_DEBUG
	cached = false;
#endif

	Method method;
	if (opt & DISPATCH_SUPER) {
	    if (!sel_equal(klass, current_super_sel, sel)) {
		current_super_sel = sel;
		current_super_class = klass;
	    }
	    else {
		// Let's make sure the current_super_class is valid before
		// using it; we check this by verifying that it's a real
		// super class of the current class, as we may be calling
		// a super method of the same name but on a totally different
		// class hierarchy.
		Class k = klass;
		bool current_super_class_ok = false;
		while (k != NULL) {
		    if (k == current_super_class) {
			current_super_class_ok = true;
			break;
		    }
		    k = class_getSuperclass(k);
		}
		if (!current_super_class_ok) {
		    current_super_class = klass;
		}
	    }
	    method = rb_vm_super_lookup(current_super_class, sel,
		    &current_super_class);
	}
	else {
	    current_super_sel = 0;
	    method = class_getInstanceMethod(klass, sel);
	}

	if (method != NULL) {
recache2:
	    IMP imp = method_getImplementation(method);

	    if (UNAVAILABLE_IMP(imp)) {
		// Method was undefined.
		goto call_method_missing;
	    }

	    rb_vm_method_node_t *node = GET_CORE()->method_node_get(method);

	    if (node != NULL) {
		// ruby call
		fill_rcache(cache, klass, sel, node);
	    }
	    else {
		// objc call
		fill_ocache(cache, self, klass, imp, sel, method, argc);
	    }

	    if (opt & DISPATCH_SUPER) {
		cache->flag |= MCACHE_SUPER;
	    }
	}
	else {
	    // Method is not found...

#if !defined(MACRUBY_STATIC)
	    // Force a method resolving, because the objc cache might be
	    // wrong.
	    if (rb_vm_resolve_method(klass, sel)) {
		goto recache;
	    }
#endif

	    // Does the receiver implements -forwardInvocation:?
	    if ((opt & DISPATCH_SUPER) == 0
		    && rb_objc_supports_forwarding(self, sel)) {

//#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
		// In earlier versions of the Objective-C runtime, there seems
		// to be a bug where class_getInstanceMethod isn't atomic,
		// and might return NULL while at the exact same time another
		// thread registers the related method.
		// As a work-around, we double-check if the method still does
		// not exist here. If he does, we can dispatch it properly.

		// note: OS X 10.7 also, this workaround is required. see #1476
		method = class_getInstanceMethod(klass, sel);
		if (method != NULL) {
		    goto recache2;
		}
//#endif
		fill_ocache(cache, self, klass, (IMP)objc_msgSend, sel, NULL,
			argc);
		goto dispatch;
	    }

	    // Let's see if are not trying to call a Ruby method that accepts
	    // a regular argument then an optional Hash argument, to be
	    // compatible with the Ruby specification.
	    const char *selname = (const char *)sel;
	    size_t selname_len = strlen(selname);
	    if (argc > 1) {
		const char *p = strchr(selname, ':');
		if (p != NULL && p + 1 != '\0') {
		    char *tmp = (char *)malloc(selname_len + 1);
		    assert(tmp != NULL);
		    strncpy(tmp, selname, p - selname + 1);
		    tmp[p - selname + 1] = '\0';
		    sel = sel_registerName(tmp);
		    VALUE h = rb_hash_new();
		    bool ok = true;
		    p += 1;
		    for (int i = 1; i < argc; i++) {
			const char *p2 = strchr(p, ':');
			if (p2 == NULL) {
			    ok = false;
			    break;
			}
			strlcpy(tmp, p, selname_len);
			tmp[p2 - p] = '\0';
			p = p2 + 1; 
			rb_hash_aset(h, ID2SYM(rb_intern(tmp)), argv[i]);
		    }
		    free(tmp);
		    tmp = NULL;
		    if (ok) {
			argc = 2;
			((VALUE *)argv)[1] = h; // bad, I know...
			Method m = class_getInstanceMethod(klass, sel);
			if (m != NULL) {	
			    method = m;
			    cache_method = false;
			    goto recache2;
			}
		    }
		}
	    }

	    // Enable helpers for classes which are not RubyObject based.
	    if ((RCLASS_VERSION(klass) & RCLASS_IS_OBJECT_SUBCLASS)
		    != RCLASS_IS_OBJECT_SUBCLASS) {
		// Let's try to see if we are not given a helper selector.
		SEL new_sel = helper_sel(selname, selname_len);
		if (new_sel != NULL) {
		    Method m = class_getInstanceMethod(klass, new_sel);
		    if (m != NULL) {
		    	sel = new_sel;
		    	method = m;
		    	// We need to invert arguments because
		    	// #[]= and setObject:forKey: take arguments
		    	// in a reverse order
		    	if (new_sel == selSetObjectForKey && argc == 2) {
		    	    VALUE swap = argv[0];
		    	    ((VALUE *)argv)[0] = argv[1];
		    	    ((VALUE *)argv)[1] = swap;
		    	    cache_method = false;
		    	}
		    	goto recache2;
		    }
		}
	    }

	    // Let's see if we are not trying to call a BridgeSupport function.
	    if (selname[selname_len - 1] == ':') {
		selname_len--;
	    }
	    std::string name(selname, selname_len);
	    bs_element_function_t *bs_func = GET_CORE()->find_bs_function(name);
	    if (bs_func != NULL) {
		if ((unsigned)argc < bs_func->args_count
			|| ((unsigned)argc > bs_func->args_count
				&& bs_func->variadic == false)) {
		    rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
			argc, bs_func->args_count);
		}
		std::string types;
		vm_gen_bs_func_types(argc, argv, bs_func, types);

		cache->flag = MCACHE_FCALL;
		cache->sel = sel;
		cache->klass = klass;
		cache->as.fcall.bs_function = bs_func;
		cache->as.fcall.imp = (IMP)dlsym(RTLD_DEFAULT, bs_func->name);
		assert(cache->as.fcall.imp != NULL);
		cache->as.fcall.stub = (rb_vm_c_stub_t *)GET_CORE()->gen_stub(
			types, bs_func->variadic, bs_func->args_count, false);
	    }
	    else {
		// Still nothing, then let's call #method_missing.
		goto call_method_missing;
	    }
	}
    }

dispatch:
    if (cache->flag & MCACHE_RCALL) {
	if (!cache_method) {
	    cache->flag = 0;
	}

#if ROXOR_VM_DEBUG
	printf("ruby dispatch %c[<%s %p> %s] (imp %p block %p argc %d opt %d cache %p cached %s)\n",
		class_isMetaClass(klass) ? '+' : '-',
		class_getName(klass),
		(void *)self,
		sel_getName(sel),
		cache->as.rcall.node->ruby_imp,
		block,
		argc,
		opt,
		cache,
		cached ? "true" : "false");
#endif

	bool block_already_current = vm->is_block_current(block);
	Class current_klass = vm->get_current_class();
	if (!block_already_current) {
	    vm->add_current_block(block);
	}
	vm->set_current_class(NULL);

	Class old_current_super_class = vm->get_current_super_class();
	vm->set_current_super_class(current_super_class);
	SEL old_current_super_sel = vm->get_current_super_sel();
	vm->set_current_super_sel(current_super_sel);

	const bool should_pop_broken_with =
	    sel != selInitialize && sel != selInitialize2;

	struct Finally {
	    bool block_already_current;
	    Class current_class;
	    Class current_super_class;
	    SEL current_super_sel;
	    bool should_pop_broken_with;
	    RoxorVM *vm;
	    Finally(bool _block_already_current, Class _current_class,
		    Class _current_super_class, SEL _current_super_sel,
		    bool _should_pop_broken_with, RoxorVM *_vm) {
		block_already_current = _block_already_current;
		current_class = _current_class;
		current_super_class = _current_super_class;
		current_super_sel = _current_super_sel;
		should_pop_broken_with = _should_pop_broken_with;
		vm = _vm;
	    }
	    ~Finally() {
		if (!block_already_current) {
		    vm->pop_current_block();
		}
		vm->set_current_class(current_class);
		if (should_pop_broken_with) {
		    vm->pop_broken_with();
		}
		vm->set_current_super_class(current_super_class);
		vm->set_current_super_sel(current_super_sel);
		vm->pop_current_binding();
	    }
	} finalizer(block_already_current, current_klass,
		old_current_super_class, old_current_super_sel,
		should_pop_broken_with, vm);

	// DTrace probe: method__entry
	if (MACRUBY_METHOD_ENTRY_ENABLED()) {
	    char *class_name = (char *)rb_class2name((VALUE)klass);
	    char *method_name = (char *)sel_getName(sel);
	    char file[PATH_MAX];
	    unsigned long line = 0;
	    GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line,
		    NULL, 0);
	    MACRUBY_METHOD_ENTRY(class_name, method_name, file, line);
	}

	VALUE v = ruby_dispatch(top, self, sel, cache->as.rcall.node,
		opt, argc, argv);

	// DTrace probe: method__return
	if (MACRUBY_METHOD_RETURN_ENABLED()) {
	    char *class_name = (char *)rb_class2name((VALUE)klass);
	    char *method_name = (char *)sel_getName(sel);
	    char file[PATH_MAX];
	    unsigned long line = 0;
	    GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line,
		    NULL, 0);
	    MACRUBY_METHOD_RETURN(class_name, method_name, file, line);
	}

	return v;
    }
    else if (cache->flag & MCACHE_OCALL) {
	if (cache->as.ocall.argc != argc) {
	    goto recache;
	}
	if (!cache_method) {
	    cache->flag = 0;
	}

	if (block != NULL) {
	    rb_warn("passing a block to an Objective-C method - " \
		    "will be ignored");
	}
	else if (sel == selNew) {
	    if (self == rb_cNSMutableArray) {
		self = rb_cRubyArray;
	    }
	}
	else if (sel == selClass) {
	    // Because +[NSObject class] returns self.
	    if (RCLASS_META(klass)) {
		return RCLASS_MODULE(self) ? rb_cModule : rb_cClass;
	    }
	    // Because the CF classes should be hidden, for Ruby compat.
	    if (self == Qnil) {
		return rb_cNilClass;
	    }
	    if (self == Qtrue) {
		return rb_cTrueClass;
	    }
	    if (self == Qfalse) {
		return rb_cFalseClass;
	    }
	    return rb_class_real((VALUE)klass, true);
	}

#if ROXOR_VM_DEBUG
	printf("objc dispatch %c[<%s %p> %s] imp=%p cache=%p argc=%d (cached=%s)\n",
		class_isMetaClass(klass) ? '+' : '-',
		class_getName(klass),
		(void *)self,
		sel_getName(sel),
		cache->as.ocall.imp,
		cache,
		argc,
		cached ? "true" : "false");
#endif

	id ocrcv = RB2OC(self);

 	if (cache->as.ocall.bs_method != NULL) {
	    Class ocklass = object_getClass(ocrcv);
	    for (int i = 0; i < (int)cache->as.ocall.bs_method->args_count;
		    i++) {
		bs_element_arg_t *arg = &cache->as.ocall.bs_method->args[i];
		if (arg->sel_of_type != NULL) {
		    // BridgeSupport tells us that this argument contains a
		    // selector of the given type, but we don't have any
		    // information regarding the target. RubyCocoa and the
		    // other ObjC bridges do not really require it since they
		    // use the NSObject message forwarding mechanism, but
		    // MacRuby registers all methods in the runtime.
		    //
		    // Therefore, we apply here a naive heuristic by assuming
		    // that either the receiver or one of the arguments of this
		    // call is the future target.
		    const int arg_i = arg->index;
		    assert(arg_i >= 0 && arg_i < argc);
		    if (argv[arg_i] != Qnil) {
			ID arg_selid = rb_to_id(argv[arg_i]);
			SEL arg_sel = sel_registerName(rb_id2name(arg_selid));

			if (reinstall_method_maybe(ocklass, arg_sel,
				    arg->sel_of_type)) {
			    goto sel_target_found;
			}
			for (int j = 0; j < argc; j++) {
			    if (j != arg_i && !SPECIAL_CONST_P(argv[j])) {
				if (reinstall_method_maybe(*(Class *)argv[j],
					    arg_sel, arg->sel_of_type)) {
				    goto sel_target_found;
				}
			    }
			}
		    }

sel_target_found:
		    // There can only be one sel_of_type argument.
		    break; 
		}
	    }
	}

	return __rb_vm_objc_dispatch(cache->as.ocall.stub, cache->as.ocall.imp,
		ocrcv, sel, argc, argv);
    }
    else if (cache->flag & MCACHE_FCALL) {
#if ROXOR_VM_DEBUG
	printf("C dispatch %s() imp=%p argc=%d (cached=%s)\n",
		cache->as.fcall.bs_function->name,
		cache->as.fcall.imp,
		argc,
		cached ? "true" : "false");
#endif
	return (*cache->as.fcall.stub)(cache->as.fcall.imp, argc, argv);
    }

    printf("method dispatch is b0rked\n");
    abort();

call_method_missing:
    // Before calling method_missing, let's check if we are not in the following
    // cases:
    //
    //    def foo; end; foo(42)
    //    def foo(x); end; foo
    //
    // If yes, we need to raise an ArgumentError exception instead.
    const char *selname = sel_getName(sel);
    const size_t selname_len = strlen(selname);
    SEL new_sel = 0;

    if (argc > 0 && selname[selname_len - 1] == ':') {
	char buf[100];
	assert(sizeof buf > selname_len - 1);
	strlcpy(buf, selname, sizeof buf);
	buf[selname_len - 1] = '\0';
	new_sel = sel_registerName(buf);
    }
    else if (argc == 0) {
	char buf[100];
	snprintf(buf, sizeof buf, "%s:", selname);
	new_sel = sel_registerName(buf);
    }
    if (new_sel != 0) {
	Method m = class_getInstanceMethod(klass, new_sel);
	if (m != NULL) {
	    IMP mimp = method_getImplementation(m);
	    if (!UNAVAILABLE_IMP(mimp)) {
		unsigned expected_argc;
		rb_vm_method_node_t *node = GET_CORE()->method_node_get(m);
		if (node != NULL) {
		    expected_argc = node->arity.min;
		}
		else {
		    expected_argc = rb_method_getNumberOfArguments(m);
		    expected_argc -= 2; // removing receiver and selector
		}
		rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
			argc, expected_argc);
	    }
	}
    }

    rb_vm_method_missing_reason_t status;
    if (opt & DISPATCH_VCALL) {
	status = METHOD_MISSING_VCALL;
    }
    else if (opt & DISPATCH_SUPER) {
	status = METHOD_MISSING_SUPER;
    }
    else {
	status = METHOD_MISSING_DEFAULT;
    }
    return method_missing((VALUE)self, sel, block, argc, argv, status);
}
コード例 #12
0
ファイル: vm_eval.c プロジェクト: 3runo5ouza/rhodes
static inline VALUE
rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
	 int scope, VALUE self)
{
    NODE *body, *method;
    int noex;
    ID id = mid;
    struct cache_entry *ent;
    rb_thread_t *th = GET_THREAD();

    if (!klass) {
	rb_raise(rb_eNotImpError,
		 "method `%s' called on terminated object (%p)",
		 rb_id2name(mid), (void *)recv);
    }
    /* is it in the method cache? */
    ent = cache + EXPR1(klass, mid);

    if (ent->mid == mid && ent->klass == klass) {
	if (!ent->method)
	    return method_missing(recv, mid, argc, argv,
				  scope == 2 ? NOEX_VCALL : 0);
	id = ent->mid0;
	noex = ent->method->nd_noex;
	klass = ent->method->nd_clss;
	body = ent->method->nd_body;
    }
    else if ((method = rb_get_method_body(klass, id, &id)) != 0) {
	noex = method->nd_noex;
	klass = method->nd_clss;
	body = method->nd_body;
    }
    else {
	if (scope == 3) {
	    return method_missing(recv, mid, argc, argv, NOEX_SUPER);
	}
	return method_missing(recv, mid, argc, argv,
			      scope == 2 ? NOEX_VCALL : 0);
    }
    

    if (mid != idMethodMissing) {
	/* receiver specified form for private method */
	if (UNLIKELY(noex)) {
	    if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == 0) {
		return method_missing(recv, mid, argc, argv, NOEX_PRIVATE);
	    }

	    /* self must be kind of a specified form for protected method */
	    if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == 0) {
		VALUE defined_class = klass;
		
		if (TYPE(defined_class) == T_ICLASS) {
		    defined_class = RBASIC(defined_class)->klass;
		}

		if (self == Qundef) {
		    self = th->cfp->self;
		}
		if (!rb_obj_is_kind_of(self, rb_class_real(defined_class))) {
		    return method_missing(recv, mid, argc, argv, NOEX_PROTECTED);
		}
	    }

	    if (NOEX_SAFE(noex) > th->safe_level) {
		rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(mid));
	    }
	}
    }

    stack_check();
    return vm_call0(th, klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
}
コード例 #13
0
ファイル: vm_dump.c プロジェクト: rhenium/ruby
void
rb_vm_bugreport(const void *ctx)
{
#ifdef __linux__
# define PROC_MAPS_NAME "/proc/self/maps"
#endif
#ifdef PROC_MAPS_NAME
    enum {other_runtime_info = 1};
#else
    enum {other_runtime_info = 0};
#endif
    const rb_vm_t *const vm = GET_VM();

    preface_dump();

    if (vm) {
	SDR();
	rb_backtrace_print_as_bugreport();
	fputs("\n", stderr);
    }

    rb_dump_machine_register(ctx);

#if HAVE_BACKTRACE || defined(_WIN32)
    fprintf(stderr, "-- C level backtrace information "
	    "-------------------------------------------\n");
    rb_print_backtrace();


    fprintf(stderr, "\n");
#endif /* HAVE_BACKTRACE */

    if (other_runtime_info || vm) {
	fprintf(stderr, "-- Other runtime information "
		"-----------------------------------------------\n\n");
    }
    if (vm) {
	int i;
	VALUE name;
	long len;
	const int max_name_length = 1024;
# define LIMITED_NAME_LENGTH(s) \
	(((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len)

	name = vm->progname;
	fprintf(stderr, "* Loaded script: %.*s\n",
		LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
	fprintf(stderr, "\n");
	fprintf(stderr, "* Loaded features:\n\n");
	for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) {
	    name = RARRAY_AREF(vm->loaded_features, i);
	    if (RB_TYPE_P(name, T_STRING)) {
		fprintf(stderr, " %4d %.*s\n", i,
			LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
	    }
	    else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) {
		const char *const type = RB_TYPE_P(name, T_CLASS) ?
		    "class" : "module";
		name = rb_search_class_path(rb_class_real(name));
		if (!RB_TYPE_P(name, T_STRING)) {
		    fprintf(stderr, " %4d %s:<unnamed>\n", i, type);
		    continue;
		}
		fprintf(stderr, " %4d %s:%.*s\n", i, type,
			LIMITED_NAME_LENGTH(name), RSTRING_PTR(name));
	    }
	    else {
		VALUE klass = rb_search_class_path(rb_obj_class(name));
		if (!RB_TYPE_P(klass, T_STRING)) {
		    fprintf(stderr, " %4d #<%p:%p>\n", i,
			    (void *)CLASS_OF(name), (void *)name);
		    continue;
		}
		fprintf(stderr, " %4d #<%.*s:%p>\n", i,
			LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass),
			(void *)name);
	    }
	}
	fprintf(stderr, "\n");
    }

    {
#ifdef PROC_MAPS_NAME
	{
	    FILE *fp = fopen(PROC_MAPS_NAME, "r");
	    if (fp) {
		fprintf(stderr, "* Process memory map:\n\n");

		while (!feof(fp)) {
		    char buff[0x100];
		    size_t rn = fread(buff, 1, 0x100, fp);
		    if (fwrite(buff, 1, rn, stderr) != rn)
			break;
		}

		fclose(fp);
		fprintf(stderr, "\n\n");
	    }
	}
#endif /* __linux__ */
#ifdef HAVE_LIBPROCSTAT
# define MIB_KERN_PROC_PID_LEN 4
	int mib[MIB_KERN_PROC_PID_LEN];
	struct kinfo_proc kp;
	size_t len = sizeof(struct kinfo_proc);
	mib[0] = CTL_KERN;
	mib[1] = KERN_PROC;
	mib[2] = KERN_PROC_PID;
	mib[3] = getpid();
	if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) {
	    perror("sysctl");
	}
	else {
	    struct procstat *prstat = procstat_open_sysctl();
	    fprintf(stderr, "* Process memory map:\n\n");
	    procstat_vm(prstat, &kp);
	    procstat_close(prstat);
	    fprintf(stderr, "\n");
	}
#endif /* __FreeBSD__ */
    }
}
コード例 #14
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;
}
コード例 #15
0
ファイル: variable.c プロジェクト: kyab/MacRuby
VALUE
rb_class_name(VALUE klass)
{
    return rb_class_path(rb_class_real(klass, false));
}
コード例 #16
0
ファイル: variable.c プロジェクト: kyab/MacRuby
const char *
rb_obj_classname(VALUE obj)
{
    return rb_class2name(rb_class_real(CLASS_OF(obj), true));
}
コード例 #17
0
ファイル: ruby.c プロジェクト: sumitmah/jruby
VALUE rb_obj_class(VALUE object) {
  return rb_class_real(rb_class_of(object));
}