static inline VALUE
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
	      int num, volatile VALUE recv, const rb_block_t *blockptr,
	      const rb_method_entry_t *me)
{
    volatile VALUE val = 0;
    const rb_method_definition_t *def = me->def;
    rb_control_frame_t *cfp;

    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);

    cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
			recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
    cfp->me = me;
    reg_cfp->sp -= num + 1;

    val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1);

    if (reg_cfp != th->cfp + 1) {
	rb_bug("cfp consistency error - send");
    }
#ifdef __llvm__
#define RB_LLVM_GUARD(v) RB_GC_GUARD(v)
    RB_LLVM_GUARD(reg_cfp);
#endif

    vm_pop_frame(th);

    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);

    return val;
}
Beispiel #2
0
static inline VALUE
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
	      int num, ID id, ID oid, VALUE recv, VALUE klass,
	      VALUE flag, const NODE *mn, const rb_block_t *blockptr)
{
    VALUE val;

    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
    {
	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;

	reg_cfp->sp -= num + 1;

	val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);

	if (reg_cfp != th->cfp + 1) {
	    rb_bug("cfp consistency error - send");
	}

	vm_pop_frame(th);
    }
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);

    return val;
}
Beispiel #3
0
static
PyObject*
compile_and_invoke(DispatcherObject *self, PyObject *args, PyObject *kws, PyObject *locals)
{
    /* Compile a new one */
    PyObject *cfa, *cfunc, *retval;
    cfa = PyObject_GetAttrString((PyObject*)self, "_compile_for_args");
    if (cfa == NULL)
        return NULL;

    /* NOTE: we call the compiled function ourselves instead of
       letting the Python derived class do it.  This is for proper
       behaviour of globals() in jitted functions (issue #476). */
    cfunc = PyObject_Call(cfa, args, kws);
    Py_DECREF(cfa);

    if (cfunc == NULL)
        return NULL;

    if (PyObject_TypeCheck(cfunc, &PyCFunction_Type)) {
        retval = call_cfunc(self, cfunc, args, kws, locals);
    } else {
        /* Re-enter interpreter */
        retval = PyObject_Call(cfunc, args, kws);
    }
    Py_DECREF(cfunc);

    return retval;
}
Beispiel #4
0
static inline VALUE
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
	      int num, ID id, ID oid, VALUE recv, VALUE klass,
	      VALUE flag, const NODE *mn, const rb_block_t *blockptr)
{
    VALUE val = 0;
    int state = 0;

    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
    TH_PUSH_TAG(th);
    if (th->event_flags & RUBY_EVENT_C_RETURN) {
	state = TH_EXEC_TAG();
    }
    else {
	_th->tag = _tag.prev;
    }
    if (state == 0) {
	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;

	reg_cfp->sp -= num + 1;

	val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);

	if (reg_cfp != th->cfp + 1) {
	    rb_bug("cfp consistency error - send");
	}

	vm_pop_frame(th);
    }
    TH_POP_TAG();
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
    if (state) TH_JUMP_TAG(th, state);

    return val;
}
Beispiel #5
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;
}
Beispiel #6
0
static PyObject*
Dispatcher_call(DispatcherObject *self, PyObject *args, PyObject *kws)
{
    PyObject *tmptype, *retval = NULL;
    int *tys;
    int argct;
    int i;
    int prealloc[24];
    int matches;
    PyObject *cfunc;
    PyThreadState *ts = PyThreadState_Get();
    PyObject *locals = NULL;
    if (ts->use_tracing && ts->c_profilefunc)
        locals = PyEval_GetLocals();
    if (self->fold_args) {
        if (find_named_args(self, &args, &kws))
            return NULL;
    }
    else
        Py_INCREF(args);
    /* Now we own a reference to args */

    argct = PySequence_Fast_GET_SIZE(args);

    if (argct < (Py_ssize_t) (sizeof(prealloc) / sizeof(int)))
        tys = prealloc;
    else
        tys = malloc(argct * sizeof(int));

    for (i = 0; i < argct; ++i) {
        tmptype = PySequence_Fast_GET_ITEM(args, i);
        tys[i] = typeof_typecode((PyObject *) self, tmptype);
        if (tys[i] == -1) {
            if (self->can_fallback){
                /* We will clear the exception if fallback is allowed. */
                PyErr_Clear();
            } else {
                goto CLEANUP;
            }
        }
    }

    /* If compilation is enabled, ensure that an exact match is found and if
     * not compile one */
    self->exact_match_required |= self->can_compile;

    /* We only allow unsafe conversions if compilation of new specializations
       has been disabled. */
    cfunc = dispatcher_resolve(self->dispatcher, tys, &matches,
                               !self->can_compile, self->exact_match_required);

    if (matches == 0 && !self->can_compile) {
        /*
         * If we can't compile a new specialization, look for
         * matching signatures for which conversions haven't been
         * registered on the C++ TypeManager.
         */
        int res = search_new_conversions((PyObject *) self, args, kws);
        if (res < 0) {
            retval = NULL;
            goto CLEANUP;
        }
        if (res > 0) {
            /* Retry with the newly registered conversions */
            cfunc = dispatcher_resolve(self->dispatcher, tys, &matches,
                                       !self->can_compile,
                                       self->exact_match_required);
        }
    }

    if (matches == 1) {
        /* Definition is found */
        retval = call_cfunc(self, cfunc, args, kws, locals);
    } else if (matches == 0) {
        /* No matching definition */
        if (self->can_compile) {
            retval = compile_and_invoke(self, args, kws, locals);
        } else if (self->fallbackdef) {
            /* Have object fallback */
            retval = call_cfunc(self, self->fallbackdef, args, kws, locals);
        } else {
            /* Raise TypeError */
            explain_matching_error((PyObject *) self, args, kws);
            retval = NULL;
        }
    } else if (self->can_compile) {
        /* Ambiguous, but are allowed to compile */
        retval = compile_and_invoke(self, args, kws, locals);
    } else {
        /* Ambiguous */
        explain_ambiguous((PyObject *) self, args, kws);
        retval = NULL;
    }

CLEANUP:
    if (tys != prealloc)
        free(tys);
    Py_DECREF(args);

    return retval;
}