Exemple #1
0
vm_resolve_args(VALUE **pargv, size_t argv_size, int *pargc, VALUE *args)
{
    unsigned int i, argc = *pargc, real_argc = 0, j = 0;
    VALUE *argv = *pargv;
    bool splat_arg_follows = false;
    for (i = 0; i < argc; i++) {
	VALUE arg = args[j++];
	if (arg == SPLAT_ARG_FOLLOWS) {
	    splat_arg_follows = true;
	    i--;
	}
	else {
	    if (splat_arg_follows) {
		VALUE ary = rb_check_convert_type(arg, T_ARRAY, "Array",
			"to_a");
		if (NIL_P(ary)) {
		    ary = rb_ary_new4(1, &arg);
		}
		int count = RARRAY_LEN(ary);
		if (real_argc + count >= argv_size) {
		    const size_t new_argv_size = real_argc + count + 100;
		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
			    * new_argv_size);
		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
		    argv = new_argv;
		    argv_size = new_argv_size;
		}
		int j;
		for (j = 0; j < count; j++) {
		    argv[real_argc++] = RARRAY_AT(ary, j);
		}
		splat_arg_follows = false;
	    }
	    else {
		if (real_argc >= argv_size) {
		    const size_t new_argv_size = real_argc + 100;
		    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE)
			    * new_argv_size);
		    memcpy(new_argv, argv, sizeof(VALUE) * argv_size);
		    argv = new_argv;
		    argv_size = new_argv_size;
		}
		argv[real_argc++] = arg;
	    }
	}
    }
    *pargv = argv;
    *pargc = real_argc;
}
Exemple #2
0
static VALUE
struct_alloc(VALUE klass)
{
    VALUE size;
    long n;
    NEWOBJ(st, struct RStruct);
    OBJSETUP(st, klass, T_STRUCT);

    size = rb_struct_iv_get(klass, "__size__");
    n = FIX2LONG(size);

    if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) {
        RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
        RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
	rb_mem_clear(st->as.ary, n);
    }
    else {
	if (n > 0) {
	    GC_WB(&st->as.heap.ptr, xmalloc_ptrs(sizeof(VALUE) * n));
	    rb_mem_clear(st->as.heap.ptr, n);
	}
	else {
	    st->as.heap.ptr = NULL;
	}
	st->as.heap.len = n;
    }

    return (VALUE)st;
}
Exemple #3
0
static VALUE
method_missing(VALUE obj, SEL sel, rb_vm_block_t *block, int argc,
	const VALUE *argv, rb_vm_method_missing_reason_t call_status)
{
    if (sel == selAlloc) {
        rb_raise(rb_eTypeError, "allocator undefined for %s",
		RSTRING_PTR(rb_inspect(obj)));
    }

    GET_VM()->set_method_missing_reason(call_status);

    VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * (argc + 1));

    char buf[100];
    int n = snprintf(buf, sizeof buf, "%s", sel_getName(sel));
    if (buf[n - 1] == ':') {
	// Let's see if there are more colons making this a real selector.
	bool multiple_colons = false;
	for (int i = 0; i < (n - 1); i++) {
	    if (buf[i] == ':') {
		multiple_colons = true;
		break;
	    }
	}
	if (!multiple_colons) {
	    // Not a typical multiple argument selector. So as this is
	    // probably a typical ruby method name, chop off the colon.
	    buf[n - 1] = '\0';
	}
    }
    new_argv[0] = ID2SYM(rb_intern(buf));
    MEMCPY(&new_argv[1], argv, VALUE, argc);

    // In case the missing selector _is_ method_missing: OR the object does
    // not respond to method_missing: (this can happen for NSProxy-based
    // objects), directly trigger the exception.
    Class k = (Class)CLASS_OF(obj);
    if (sel == selMethodMissing
	    || class_getInstanceMethod(k, selMethodMissing) == NULL) {
	rb_vm_method_missing(obj, argc + 1, new_argv);
	return Qnil; // never reached
    }
    else {
	return rb_vm_call2(block, obj, (VALUE)k, selMethodMissing, argc + 1,
		new_argv);
    }
}
Exemple #4
0
static force_inline VALUE
__rb_vm_bcall(VALUE self, SEL sel, VALUE dvars, rb_vm_block_t *b,
	IMP pimp, const rb_vm_arity_t &arity, int argc, const VALUE *argv)
{
    VALUE buf[100];
    if (arity.real != argc || arity.max == -1) {
	VALUE *new_argv;
	if (arity.real < 100) {
	    new_argv = buf;
	}
	else {
	    new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * arity.real);
	}
	vm_fix_args(argv, new_argv, arity, argc);
	argv = new_argv;
	argc = arity.real;
    }

    assert(pimp != NULL);

    VALUE (*imp)(VALUE, SEL, VALUE, rb_vm_block_t *,  ...) =
	(VALUE (*)(VALUE, SEL, VALUE, rb_vm_block_t *, ...))pimp;

    switch (argc) {
	case 0:
	    return (*imp)(self, sel, dvars, b);
	case 1:
	    return (*imp)(self, sel, dvars, b, argv[0]);
	case 2:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1]);
	case 3:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2]);
	case 4:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3]);
	case 5:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3], argv[4]);
	case 6:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3], argv[4], argv[5]);
	case 7:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3], argv[4], argv[5], argv[6]);
	case 8:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3], argv[4], argv[5], argv[6], argv[7]);
	case 9:
	    return (*imp)(self, sel, dvars, b, argv[0], argv[1], argv[2],
		    argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
    }

#if MACRUBY_STATIC
    rb_raise(rb_eRuntimeError,
	    "MacRuby static doesn't support passing more than 9 arguments");
#else
    rb_vm_long_arity_bstub_t *stub = (rb_vm_long_arity_bstub_t *)
	GET_CORE()->gen_large_arity_stub(argc, true);
    return (*stub)(pimp, (id)self, sel, dvars, b, argc, argv);
#endif
}
Exemple #5
0
static force_inline VALUE
vm_block_eval(RoxorVM *vm, rb_vm_block_t *b, SEL sel, VALUE self,
	int argc, const VALUE *argv)
{
    if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
	// Special case for blocks passed with rb_objc_block_call(), to
	// preserve API compatibility.
	VALUE (*pimp)(VALUE, VALUE, int, const VALUE *) =
	    (VALUE (*)(VALUE, VALUE, int, const VALUE *))b->imp;

	return (*pimp)(argc == 0 ? Qnil : argv[0], b->userdata, argc, argv);
    }
    else if ((b->flags & VM_BLOCK_EMPTY) == VM_BLOCK_EMPTY) {
	// Trying to call an empty block!
	return Qnil;
    }

    rb_vm_arity_t arity = b->arity;    

    if (argc < arity.min || argc > arity.max) {
	if (arity.max != -1
		&& (b->flags & VM_BLOCK_LAMBDA) == VM_BLOCK_LAMBDA) {
	    short limit = (argc < arity.min) ? arity.min : arity.max;
	    rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
		    argc, limit);
	}

	VALUE *new_argv;
	if (argc == 1 && TYPE(argv[0]) == T_ARRAY
		&& (arity.min > 1
		    || (arity.min == 1 && arity.min != arity.max))) {
	    // Expand the array.
	    const long ary_len = RARRAY_LEN(argv[0]);
	    if (ary_len > 0) {
		new_argv = (VALUE *)RARRAY_PTR(argv[0]);
	    }
	    else {
		new_argv = NULL;
	    }
	    argv = new_argv;
	    argc = ary_len;
	    if (argc >= arity.min
		    && (argc <= arity.max || b->arity.max == -1)) {
		goto block_call;
	    }
	}

	int new_argc;
	if (argc <= arity.min) {
	    new_argc = arity.min;
	}
	else if (argc > arity.max && b->arity.max != -1) {
	    new_argc = arity.max;
	}
	else {
	    new_argc = argc;
	}

	if (new_argc > 0) {
	    new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * new_argc);
	    for (int i = 0; i < new_argc; i++) {
		new_argv[i] = i < argc ? argv[i] : Qnil;
	    }
	}
	else {
	    new_argv = NULL;
	}

	argc = new_argc;
	argv = new_argv;
    }
#if ROXOR_VM_DEBUG
    printf("yield block %p argc %d arity %d\n", b, argc, arity.real);
#endif

block_call:

    if (b->flags & VM_BLOCK_ACTIVE) {
	b = dup_block(b);
    }
    b->flags |= VM_BLOCK_ACTIVE;

    Class old_current_class = vm->get_current_class();
    vm->set_current_class((Class)b->klass);

    struct Finally {
	RoxorVM *vm;
	rb_vm_block_t *b;
	Class c;
	Finally(RoxorVM *_vm, rb_vm_block_t *_b, Class _c) {
	    vm = _vm;
	    b = _b;
	    c = _c;
	}
	~Finally() {
	    b->flags &= ~VM_BLOCK_ACTIVE;
	    vm->set_current_class(c);
	}
    } finalizer(vm, b, old_current_class);

    if (b->flags & VM_BLOCK_METHOD) {
	rb_vm_method_t *m = (rb_vm_method_t *)b->imp;
	return rb_vm_dispatch(vm, (struct mcache *)m->cache, 0, m->recv,
		(Class)m->oclass, m->sel, NULL, DISPATCH_FCALL, argc, argv);
    }
    return __rb_vm_bcall(self, sel, (VALUE)b->dvars, b, b->imp, b->arity,
	    argc, argv);
}