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; }
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; }
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; }
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; }
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; }
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; }