Commit a9813b80 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #648 from kmod/perf6

reduce api conversions
parents 79505a1a 76c861ad
# simple benchmark to test iteration over extension objects
import itertools
def f(c):
for i in c:
pass
l = []
for i in xrange(100):
l.append(itertools.chain(*[range(500) for j in xrange(500)]))
c = itertools.chain(*l)
f(c)
def f(n):
for i in xrange(n):
pass
f(100000000)
def f():
u = u"a" * 100
c = unicode
for i in xrange(2000000):
c(u)
f()
...@@ -743,10 +743,13 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr ...@@ -743,10 +743,13 @@ void Rewriter::_call(RewriterVar* result, bool has_side_effects, void* func_addr
if (has_side_effects) { if (has_side_effects) {
// We need some fixed amount of space at the beginning of the IC that we can use to invalidate // We need some fixed amount of space at the beginning of the IC that we can use to invalidate
// it by writing a jmp. // it by writing a jmp.
// FIXME this check is conservative, since actually we just have to verify that the return // TODO this check is conservative, since actually we just have to verify that the return
// address is at least IC_INVALDITION_HEADER_SIZE bytes past the beginning, but we're // address is at least IC_INVALDITION_HEADER_SIZE bytes past the beginning, but we're
// checking based on the beginning of the call. I think the load+call might actually // checking based on the beginning of the call. I think the load+call might actually
// always larger than the invalidation jmp. // always larger than the invalidation jmp.
while (assembler->bytesWritten() < IC_INVALDITION_HEADER_SIZE)
assembler->nop();
assert(assembler->bytesWritten() >= IC_INVALDITION_HEADER_SIZE); assert(assembler->bytesWritten() >= IC_INVALDITION_HEADER_SIZE);
} }
......
...@@ -827,7 +827,7 @@ static PyObject* slot_tp_iter(PyObject* self) noexcept { ...@@ -827,7 +827,7 @@ static PyObject* slot_tp_iter(PyObject* self) noexcept {
return PySeqIter_New(self); return PySeqIter_New(self);
} }
static PyObject* slot_tp_iternext(PyObject* self) noexcept { /* Pyston change: static */ PyObject* slot_tp_iternext(PyObject* self) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpiternext", SLOT_AVOIDABILITY(self)); STAT_TIMER(t0, "us_timer_slot_tpiternext", SLOT_AVOIDABILITY(self));
static PyObject* next_str; static PyObject* next_str;
...@@ -957,7 +957,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { ...@@ -957,7 +957,7 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
return res; return res;
} }
static PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept { /* Pyston change: static */ PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self)); STAT_TIMER(t0, "us_timer_slot_tpnew", SLOT_AVOIDABILITY(self));
try { try {
......
...@@ -35,6 +35,8 @@ PyObject* mro_external(PyObject* self) noexcept; ...@@ -35,6 +35,8 @@ PyObject* mro_external(PyObject* self) noexcept;
int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept; int type_set_bases(PyTypeObject* type, PyObject* value, void* context) noexcept;
PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept; PyObject* slot_tp_richcompare(PyObject* self, PyObject* other, int op) noexcept;
PyObject* slot_tp_iternext(PyObject* self) noexcept;
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept;
} }
#endif #endif
...@@ -42,57 +42,9 @@ public: ...@@ -42,57 +42,9 @@ public:
return boxString(self->method_def->ml_name); return boxString(self->method_def->ml_name);
} }
static Box* __call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs) { static Box* __call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs);
STAT_TIMER(t0, "us_timer_boxedcapifunction__call__", (self->cls->is_user_defined ? 10 : 20)); static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
assert(self->cls == capifunc_cls); Box** args, const std::vector<BoxedString*>* keyword_names);
assert(varargs->cls == tuple_cls);
assert(kwargs->cls == dict_cls);
threading::GLPromoteRegion _gil_lock;
Box* rtn;
int flags = self->method_def->ml_flags;
auto func = self->method_def->ml_meth;
if (flags == METH_VARARGS) {
assert(kwargs->d.size() == 0);
rtn = (Box*)func(self->passthrough, varargs);
} else if (flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)func)(self->passthrough, varargs, kwargs);
} else if (flags == METH_NOARGS) {
assert(kwargs->d.size() == 0);
assert(varargs->size() == 0);
rtn = (Box*)func(self->passthrough, NULL);
} else if (flags == METH_O) {
if (kwargs->d.size() != 0) {
raiseExcHelper(TypeError, "%s() takes no keyword arguments", self->method_def->ml_name);
}
if (varargs->size() != 1) {
raiseExcHelper(TypeError, "%s() takes exactly one argument (%d given)", self->method_def->ml_name,
varargs->size());
}
rtn = (Box*)func(self->passthrough, varargs->elts[0]);
} else if (flags == METH_OLDARGS) {
/* the really old style */
if (kwargs == NULL || PyDict_Size(kwargs) == 0) {
int size = PyTuple_GET_SIZE(varargs);
Box* arg = varargs;
if (size == 1)
arg = PyTuple_GET_ITEM(varargs, 0);
else if (size == 0)
arg = NULL;
rtn = func(self->passthrough, arg);
} else {
raiseExcHelper(TypeError, "%.200s() takes no keyword arguments", self->method_def->ml_name);
}
} else {
RELEASE_ASSERT(0, "0x%x", flags);
}
checkAndThrowCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn;
}
static Box* getname(Box* b, void*) { static Box* getname(Box* b, void*) {
RELEASE_ASSERT(b->cls == capifunc_cls, ""); RELEASE_ASSERT(b->cls == capifunc_cls, "");
...@@ -102,9 +54,6 @@ public: ...@@ -102,9 +54,6 @@ public:
return None; return None;
} }
static Box* callInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names);
static void gcHandler(GCVisitor* v, Box* _o) { static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == capifunc_cls); assert(_o->cls == capifunc_cls);
BoxedCApiFunction* o = static_cast<BoxedCApiFunction*>(_o); BoxedCApiFunction* o = static_cast<BoxedCApiFunction*>(_o);
......
...@@ -531,7 +531,6 @@ public: ...@@ -531,7 +531,6 @@ public:
BoxedString* reprICAsString(); BoxedString* reprICAsString();
bool nonzeroIC(); bool nonzeroIC();
Box* hasnextOrNullIC(); Box* hasnextOrNullIC();
Box* nextIC();
friend class AttrWrapper; friend class AttrWrapper;
}; };
......
...@@ -248,7 +248,7 @@ Box* open(Box* arg1, Box* arg2, Box* arg3) { ...@@ -248,7 +248,7 @@ Box* open(Box* arg1, Box* arg2, Box* arg3) {
extern "C" Box* chr(Box* arg) { extern "C" Box* chr(Box* arg) {
i64 n = PyInt_AsLong(arg); i64 n = PyInt_AsLong(arg);
if (n == -1 && PyErr_Occurred()) if (n == -1 && PyErr_Occurred())
raiseExcHelper(TypeError, "an integer is required"); throwCAPIException();
if (n < 0 || n >= 256) { if (n < 0 || n >= 256) {
raiseExcHelper(ValueError, "chr() arg not in range(256)"); raiseExcHelper(ValueError, "chr() arg not in range(256)");
......
...@@ -633,25 +633,6 @@ extern "C" int PyObject_Print(PyObject* obj, FILE* fp, int flags) noexcept { ...@@ -633,25 +633,6 @@ extern "C" int PyObject_Print(PyObject* obj, FILE* fp, int flags) noexcept {
return internal_print(obj, fp, flags, 0); return internal_print(obj, fp, flags, 0);
}; };
extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept {
try {
Box* hasnext = iter->hasnextOrNullIC();
if (hasnext) {
if (hasnext->nonzeroIC())
return iter->nextIC();
else
return NULL;
} else {
return iter->nextIC();
}
} catch (ExcInfo e) {
if (e.matches(StopIteration))
return NULL;
setCAPIException(e);
}
return NULL;
}
extern "C" int PyCallable_Check(PyObject* x) noexcept { extern "C" int PyCallable_Check(PyObject* x) noexcept {
if (x == NULL) if (x == NULL)
return 0; return 0;
...@@ -1457,29 +1438,106 @@ extern "C" char* PyModule_GetFilename(PyObject* m) noexcept { ...@@ -1457,29 +1438,106 @@ extern "C" char* PyModule_GetFilename(PyObject* m) noexcept {
return PyString_AsString(fileobj); return PyString_AsString(fileobj);
} }
Box* BoxedCApiFunction::callInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* BoxedCApiFunction::__call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs) {
Box* arg1, Box* arg2, Box* arg3, Box** args, STAT_TIMER(t0, "us_timer_boxedcapifunction__call__", (self->cls->is_user_defined ? 10 : 20));
const std::vector<BoxedString*>* keyword_names) { assert(self->cls == capifunc_cls);
if (argspec != ArgPassSpec(2)) assert(varargs->cls == tuple_cls);
return callFunc(func, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); assert(kwargs->cls == dict_cls);
assert(arg1->cls == capifunc_cls); // Kind of silly to have asked callFunc to rearrange the arguments for us, just to pass things
BoxedCApiFunction* capifunc = static_cast<BoxedCApiFunction*>(arg1); // off to tppCall, but this case should be very uncommon (people explicitly asking for __call__)
if (capifunc->method_def->ml_flags != METH_O)
return callFunc(func, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); return BoxedCApiFunction::tppCall(self, NULL, ArgPassSpec(0, 0, true, true), varargs, kwargs, NULL, NULL, NULL);
}
Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
STAT_TIMER(t0, "us_timer_boxedcapifunction__call__", 10);
assert(_self->cls == capifunc_cls);
BoxedCApiFunction* self = static_cast<BoxedCApiFunction*>(_self);
if (rewrite_args) { if (rewrite_args) {
rewrite_args->arg1->addGuard((intptr_t)arg1); rewrite_args->obj->addGuard((intptr_t)self);
RewriterVar* r_passthrough = rewrite_args->arg1->getAttr(offsetof(BoxedCApiFunction, passthrough)); }
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)capifunc->method_def->ml_meth, r_passthrough,
rewrite_args->arg2); int flags = self->method_def->ml_flags;
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException); auto func = self->method_def->ml_meth;
ParamReceiveSpec paramspec(0, 0, true, false);
if (flags == METH_VARARGS) {
paramspec = ParamReceiveSpec(0, 0, true, false);
} else if (flags == (METH_VARARGS | METH_KEYWORDS)) {
paramspec = ParamReceiveSpec(0, 0, true, true);
} else if (flags == METH_NOARGS) {
paramspec = ParamReceiveSpec(0, 0, false, false);
} else if (flags == METH_O) {
paramspec = ParamReceiveSpec(1, 0, false, false);
} else if (flags == METH_OLDARGS) {
paramspec = ParamReceiveSpec(1, 0, false, false);
} else {
RELEASE_ASSERT(0, "0x%x", flags);
}
Box* oarg1 = NULL;
Box* oarg2 = NULL;
Box* oarg3 = NULL;
Box** oargs = NULL;
bool rewrite_success = false;
rearrangeArguments(paramspec, NULL, self->method_def->ml_name, NULL, rewrite_args, rewrite_success, argspec, arg1,
arg2, arg3, args, keyword_names, oarg1, oarg2, oarg3, args);
if (!rewrite_success)
rewrite_args = NULL;
RewriterVar* r_passthrough;
if (rewrite_args)
r_passthrough = rewrite_args->rewriter->loadConst((intptr_t)self->passthrough, Location::forArg(0));
Box* rtn;
if (flags == METH_VARARGS) {
rtn = (Box*)func(self->passthrough, oarg1);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1);
} else if (flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)func)(self->passthrough, oarg1, oarg2);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1,
rewrite_args->arg2);
} else if (flags == METH_NOARGS) {
rtn = (Box*)func(self->passthrough, NULL);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(
true, (void*)func, r_passthrough, rewrite_args->rewriter->loadConst(0, Location::forArg(1)));
} else if (flags == METH_O) {
rtn = (Box*)func(self->passthrough, oarg1);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1);
} else if (flags == METH_OLDARGS) {
/* the really old style */
rewrite_args = NULL;
int size = PyTuple_GET_SIZE(oarg1);
Box* arg = oarg1;
if (size == 1)
arg = PyTuple_GET_ITEM(oarg1, 0);
else if (size == 0)
arg = NULL;
rtn = func(self->passthrough, arg);
} else {
RELEASE_ASSERT(0, "0x%x", flags);
}
if (rewrite_args) {
rewrite_args->rewriter->call(false, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
Box* r = capifunc->method_def->ml_meth(capifunc->passthrough, arg2);
checkAndThrowCAPIException(); checkAndThrowCAPIException();
assert(r); assert(rtn && "should have set + thrown an exception!");
return r; return rtn;
} }
/* extension modules might be compiled with GC support so these /* extension modules might be compiled with GC support so these
...@@ -1546,8 +1604,8 @@ void setupCAPI() { ...@@ -1546,8 +1604,8 @@ void setupCAPI() {
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1))); new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
auto capi_call = new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, 0, true, true)); auto capi_call = new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, 0, true, true));
capi_call->f->internal_callable = BoxedCApiFunction::callInternal;
capifunc_cls->giveAttr("__call__", capi_call); capifunc_cls->giveAttr("__call__", capi_call);
capifunc_cls->tpp_call = BoxedCApiFunction::tppCall;
capifunc_cls->giveAttr("__name__", capifunc_cls->giveAttr("__name__",
new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCApiFunction::getname, NULL, NULL)); new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCApiFunction::getname, NULL, NULL));
capifunc_cls->giveAttr( capifunc_cls->giveAttr(
......
...@@ -347,6 +347,9 @@ Box* BoxedMethodDescriptor::callInternal(BoxedFunctionBase* f, CallRewriteArgs* ...@@ -347,6 +347,9 @@ Box* BoxedMethodDescriptor::callInternal(BoxedFunctionBase* f, CallRewriteArgs*
RELEASE_ASSERT(0, "0x%x", call_flags); RELEASE_ASSERT(0, "0x%x", call_flags);
} }
if (!rtn)
throwCAPIException();
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException); rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_rtn = r_rtn; rewrite_args->out_rtn = r_rtn;
rewrite_args->out_success = true; rewrite_args->out_success = true;
......
...@@ -68,7 +68,7 @@ protected: ...@@ -68,7 +68,7 @@ protected:
class CallattrIC : public RuntimeIC { class CallattrIC : public RuntimeIC {
public: public:
CallattrIC() : RuntimeIC((void*)callattr, 1, 160) {} CallattrIC() : RuntimeIC((void*)callattr, 1, 320) {}
Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, ArgPassSpec spec, Box* arg0, Box* arg1, Box* arg2, Box* call(Box* obj, BoxedString* attr, CallattrFlags flags, ArgPassSpec spec, Box* arg0, Box* arg1, Box* arg2,
Box** args, const std::vector<BoxedString*>* keyword_names) { Box** args, const std::vector<BoxedString*>* keyword_names) {
......
...@@ -41,23 +41,12 @@ public: ...@@ -41,23 +41,12 @@ public:
void next() override { void next() override {
STAT_TIMER(t0, "us_timer_iteratorgeneric_next", 0); STAT_TIMER(t0, "us_timer_iteratorgeneric_next", 0);
assert(iterator); Box* next = PyIter_Next(iterator);
Box* hasnext = iterator->hasnextOrNullIC(); if (next)
if (hasnext) { value = next;
if (hasnext->nonzeroIC()) { else {
value = iterator->nextIC(); checkAndThrowCAPIException();
} else { *this = *end();
*this = *end();
}
} else {
try {
value = iterator->nextIC();
} catch (ExcInfo e) {
if (e.matches(StopIteration))
*this = *end();
else
throw e;
}
} }
} }
......
...@@ -132,20 +132,14 @@ bool iterwrapperHasnextUnboxed(Box* s) { ...@@ -132,20 +132,14 @@ bool iterwrapperHasnextUnboxed(Box* s) {
RELEASE_ASSERT(s->cls == iterwrapper_cls, ""); RELEASE_ASSERT(s->cls == iterwrapper_cls, "");
BoxedIterWrapper* self = static_cast<BoxedIterWrapper*>(s); BoxedIterWrapper* self = static_cast<BoxedIterWrapper*>(s);
static BoxedString* next_str = static_cast<BoxedString*>(PyString_InternFromString("next")); Box* next = PyIter_Next(self->iter);
Box* next;
try {
next = callattr(self->iter, next_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }),
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} catch (ExcInfo e) {
if (e.matches(StopIteration)) {
self->next = NULL;
return false;
}
throw e;
}
self->next = next; self->next = next;
return true; if (!next) {
if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_StopIteration))
throwCAPIException();
PyErr_Clear();
}
return next != NULL;
} }
Box* iterwrapperHasnext(Box* s) { Box* iterwrapperHasnext(Box* s) {
......
...@@ -101,7 +101,7 @@ extern "C" Box* listPop(BoxedList* self, Box* idx) { ...@@ -101,7 +101,7 @@ extern "C" Box* listPop(BoxedList* self, Box* idx) {
int64_t n = PyInt_AsSsize_t(idx); int64_t n = PyInt_AsSsize_t(idx);
if (n == -1 && PyErr_Occurred()) if (n == -1 && PyErr_Occurred())
raiseExcHelper(TypeError, "an integer is required"); throwCAPIException();
if (n < 0) if (n < 0)
n = self->size + n; n = self->size + n;
......
...@@ -2723,11 +2723,22 @@ extern "C" Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, ...@@ -2723,11 +2723,22 @@ extern "C" Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope,
extern "C" Box* callattr(Box* obj, BoxedString* attr, CallattrFlags flags, ArgPassSpec argspec, Box* arg1, Box* arg2, extern "C" Box* callattr(Box* obj, BoxedString* attr, CallattrFlags flags, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) { Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
STAT_TIMER(t0, "us_timer_slowpath_callattr", 10); STAT_TIMER(t0, "us_timer_slowpath_callattr", 10);
#if 0
#if 0 && STAT_TIMERS
static uint64_t* st_id = Stats::getStatCounter("us_timer_slowpath_callattr_patchable"); static uint64_t* st_id = Stats::getStatCounter("us_timer_slowpath_callattr_patchable");
static uint64_t* st_id_nopatch = Stats::getStatCounter("us_timer_slowpath_callattr_nopatch"); static uint64_t* st_id_nopatch = Stats::getStatCounter("us_timer_slowpath_callattr_nopatch");
bool havepatch = (bool)getICInfo(__builtin_extract_return_addr(__builtin_return_address(0))); static uint64_t* st_id_megamorphic = Stats::getStatCounter("us_timer_slowpath_callattr_megamorphic");
ScopedStatTimer st(havepatch ? st_id : st_id_nopatch, 10); ICInfo* icinfo = getICInfo(__builtin_extract_return_addr(__builtin_return_address(0)));
uint64_t* counter;
if (!icinfo)
counter = st_id_nopatch;
else if (icinfo->isMegamorphic())
counter = st_id_megamorphic;
else {
//counter = Stats::getStatCounter("us_timer_slowpath_callattr_patchable_" + std::string(obj->cls->tp_name));
counter = Stats::getStatCounter("us_timer_slowpath_callattr_patchable_" + std::string(attr->s()));
}
ScopedStatTimer st(counter, 10);
#endif #endif
ASSERT(gc::isValidGCObject(obj), "%p", obj); ASSERT(gc::isValidGCObject(obj), "%p", obj);
...@@ -3504,6 +3515,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg ...@@ -3504,6 +3515,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
ASSERT(chosen_cf->spec->rtn_type->isFitBy(r->cls), "%s (%p) was supposed to return %s, but gave a %s", ASSERT(chosen_cf->spec->rtn_type->isFitBy(r->cls), "%s (%p) was supposed to return %s, but gave a %s",
g.func_addr_registry.getFuncNameAtAddress(chosen_cf->code, true, NULL).c_str(), chosen_cf->code, g.func_addr_registry.getFuncNameAtAddress(chosen_cf->code, true, NULL).c_str(), chosen_cf->code,
chosen_cf->spec->rtn_type->debugName().c_str(), r->cls->tp_name); chosen_cf->spec->rtn_type->debugName().c_str(), r->cls->tp_name);
assert(!PyErr_Occurred());
return r; return r;
} }
...@@ -3514,13 +3526,13 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -3514,13 +3526,13 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
if (obj->cls != function_cls && obj->cls != builtin_function_or_method_cls && obj->cls != instancemethod_cls) { if (obj->cls != function_cls && obj->cls != builtin_function_or_method_cls && obj->cls != instancemethod_cls) {
STAT_TIMER(t0, "us_timer_slowpath_runtimecall_nonfunction", 20);
// TODO: maybe eventually runtimeCallInternal should just be the default tpp_call? // TODO: maybe eventually runtimeCallInternal should just be the default tpp_call?
if (obj->cls->tpp_call) { if (obj->cls->tpp_call) {
return obj->cls->tpp_call(obj, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); return obj->cls->tpp_call(obj, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} }
STAT_TIMER(t0, "us_timer_slowpath_runtimecall_nonfunction", 20);
#if 0 #if 0
std::string per_name_stat_name = "zzz_runtimecall_nonfunction_" + std::string(obj->cls->tp_name); std::string per_name_stat_name = "zzz_runtimecall_nonfunction_" + std::string(obj->cls->tp_name);
uint64_t* counter = Stats::getStatCounter(per_name_stat_name); uint64_t* counter = Stats::getStatCounter(per_name_stat_name);
......
...@@ -47,6 +47,7 @@ void showBacktrace() { ...@@ -47,6 +47,7 @@ void showBacktrace() {
} }
void raiseExc(Box* exc_obj) { void raiseExc(Box* exc_obj) {
assert(!PyErr_Occurred());
throw ExcInfo(exc_obj->cls, exc_obj, None); throw ExcInfo(exc_obj->cls, exc_obj, None);
} }
...@@ -56,6 +57,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR ...@@ -56,6 +57,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR
Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL); Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL);
auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, file, func), None); auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, file, func), None);
assert(!PyErr_Occurred());
throw ExcInfo(exc->cls, exc, tb); throw ExcInfo(exc->cls, exc, tb);
} }
...@@ -175,6 +177,7 @@ extern "C" void raise0() { ...@@ -175,6 +177,7 @@ extern "C" void raise0() {
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType"); raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType");
exc_info->reraise = true; exc_info->reraise = true;
assert(!PyErr_Occurred());
throw * exc_info; throw * exc_info;
} }
...@@ -256,6 +259,7 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) { ...@@ -256,6 +259,7 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
auto exc_info = excInfoForRaise(arg0, arg1, arg2); auto exc_info = excInfoForRaise(arg0, arg1, arg2);
exc_info.reraise = reraise; exc_info.reraise = reraise;
assert(!PyErr_Occurred());
throw exc_info; throw exc_info;
} }
......
...@@ -238,9 +238,38 @@ Box* BoxedClass::callHasnextIC(Box* obj, bool null_on_nonexistent) { ...@@ -238,9 +238,38 @@ Box* BoxedClass::callHasnextIC(Box* obj, bool null_on_nonexistent) {
ArgPassSpec(0), nullptr, nullptr, nullptr, nullptr, nullptr); ArgPassSpec(0), nullptr, nullptr, nullptr, nullptr, nullptr);
} }
extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept {
if (iter->cls->tp_iternext != slot_tp_iternext) {
PyObject* result;
result = (*iter->cls->tp_iternext)(iter);
if (result == NULL && PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
return result;
}
try {
Box* hasnext = iter->hasnextOrNullIC();
if (hasnext) {
if (hasnext->nonzeroIC())
return iter->cls->callNextIC(iter);
else
return NULL;
} else {
return iter->cls->callNextIC(iter);
}
} catch (ExcInfo e) {
if (!e.matches(StopIteration))
setCAPIException(e);
return NULL;
}
}
Box* BoxedClass::callNextIC(Box* obj) { Box* BoxedClass::callNextIC(Box* obj) {
assert(obj->cls == this); assert(obj->cls == this);
// This would work, but it would have been better to just call tp_iternext
assert(this->tp_iternext == slot_tp_iternext);
auto ic = next_ic.get(); auto ic = next_ic.get();
if (!ic) { if (!ic) {
ic = new CallattrIC(); ic = new CallattrIC();
...@@ -303,11 +332,6 @@ Box* Box::hasnextOrNullIC() { ...@@ -303,11 +332,6 @@ Box* Box::hasnextOrNullIC() {
return this->cls->callHasnextIC(this, true); return this->cls->callHasnextIC(this, true);
} }
Box* Box::nextIC() {
return this->cls->callNextIC(this);
}
std::string builtinStr("__builtin__"); std::string builtinStr("__builtin__");
extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f) extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f)
...@@ -580,6 +604,42 @@ static void assertInitNone(Box* obj) { ...@@ -580,6 +604,42 @@ static void assertInitNone(Box* obj) {
} }
} }
static PyObject* cpython_type_call(PyTypeObject* type, PyObject* args, PyObject* kwds) noexcept {
PyObject* obj;
if (type->tp_new == NULL) {
PyErr_Format(PyExc_TypeError, "cannot create '%.100s' instances", type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, kwds);
if (obj != NULL) {
/* Ugly exception: when the call was type(something),
* don't call tp_init on the result. */
if (type == &PyType_Type && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1
&& (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
return obj;
/* If the returned object is not an instance of type,
* it won't be initialized. */
if (!PyType_IsSubtype(obj->cls, type))
return obj;
type = obj->cls;
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) && type->tp_init != NULL
&& type->tp_init(obj, args, kwds) < 0) {
Py_DECREF(obj);
obj = NULL;
}
}
return obj;
}
static PyObject* cpythonTypeCall(BoxedClass* type, PyObject* args, PyObject* kwds) {
Box* r = cpython_type_call(type, args, kwds);
if (!r)
throwCAPIException();
return r;
}
static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) { Box** args, const std::vector<BoxedString*>* keyword_names) {
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
...@@ -594,6 +654,29 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -594,6 +654,29 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
BoxedClass* cls = static_cast<BoxedClass*>(_cls); BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (cls->tp_new != object_cls->tp_new && cls->tp_new != slot_tp_new) {
// Looks like we're calling an extension class and we're not going to be able to
// separately rewrite the new + init calls. But we can rewrite the fact that we
// should just call the cpython version, which will end up working pretty well.
ParamReceiveSpec paramspec(1, false, true, true);
bool rewrite_success = false;
Box* oarg1, *oarg2, *oarg3, ** oargs = NULL;
rearrangeArguments(paramspec, NULL, "", NULL, rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args,
keyword_names, oarg1, oarg2, oarg3, oargs);
assert(oarg1 == cls);
if (!rewrite_success)
rewrite_args = NULL;
if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)cpythonTypeCall, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3);
rewrite_args->out_success = true;
}
return cpythonTypeCall(cls, oarg2, oarg3);
}
RewriterVar* r_ccls = NULL; RewriterVar* r_ccls = NULL;
RewriterVar* r_new = NULL; RewriterVar* r_new = NULL;
RewriterVar* r_init = NULL; RewriterVar* r_init = NULL;
...@@ -769,7 +852,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -769,7 +852,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
"We should only have allowed the rewrite to continue if we were guaranteed that made " "We should only have allowed the rewrite to continue if we were guaranteed that made "
"would have class cls!"); "would have class cls!");
} else { } else {
made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names); if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init)
made = objectNewNoArgs(cls);
else
made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names);
} }
assert(made); assert(made);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment