Commit 5294816c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #625 from kmod/perf

Some more perf hunting
parents 85f8fff2 acdd2cd8
......@@ -14,6 +14,7 @@
#include "capi/types.h"
#include "runtime/objmodel.h"
#include "runtime/rewrite_args.h"
namespace pyston {
......@@ -44,17 +45,17 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
Box* rtn;
if (call_flags == METH_NOARGS) {
assert(varargs->size() == 0);
assert(kwargs->d.size() == 0);
RELEASE_ASSERT(varargs->size() == 0, "");
RELEASE_ASSERT(kwargs->d.size() == 0, "");
rtn = (Box*)self->method->ml_meth(obj, NULL);
} else if (call_flags == METH_VARARGS) {
assert(kwargs->d.size() == 0);
RELEASE_ASSERT(kwargs->d.size() == 0, "");
rtn = (Box*)self->method->ml_meth(obj, varargs);
} else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs);
} else if (call_flags == METH_O) {
assert(kwargs->d.size() == 0);
assert(varargs->size() == 1);
RELEASE_ASSERT(kwargs->d.size() == 0, "");
RELEASE_ASSERT(varargs->size() == 1, "");
rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]);
} else {
RELEASE_ASSERT(0, "0x%x", call_flags);
......@@ -64,4 +65,83 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
assert(rtn && "should have set + thrown an exception!");
return rtn;
}
Box* BoxedMethodDescriptor::callInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec,
Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names) {
// TODO: could also handle cases where we have starargs but no positional args,
// and similarly for kwargs but no keywords
if (!rewrite_args || argspec.has_kwargs || argspec.has_starargs || argspec.num_keywords > 0 || argspec.num_args > 4)
return callFunc(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
assert(argspec.num_args >= 2);
int passed_varargs = argspec.num_args - 2;
assert(arg1->cls == method_cls);
BoxedMethodDescriptor* self = static_cast<BoxedMethodDescriptor*>(arg1);
Box* obj = arg2;
RewriterVar* r_obj = rewrite_args->arg2;
// We could also guard on the fields of the method object, but lets just guard on the object itself
// for now.
// TODO: what if it gets GC'd?
rewrite_args->arg1->addGuard((intptr_t)self);
int ml_flags = self->method->ml_flags;
RELEASE_ASSERT((ml_flags & METH_CLASS) == 0, "unimplemented");
if (!isSubclass(obj->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' object but received a '%s'", self->method->ml_name,
getFullNameOfClass(self->type).c_str(), getFullTypeName(obj).c_str());
r_obj->addAttrGuard(offsetof(Box, cls), (intptr_t)obj->cls);
int call_flags = ml_flags;
Box* rtn;
RewriterVar* r_rtn;
if (call_flags == METH_NOARGS) {
RELEASE_ASSERT(passed_varargs == 0, "");
rtn = (Box*)(self->method->ml_meth)(obj, NULL);
r_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, r_obj,
rewrite_args->rewriter->loadConst(0, Location::forArg(1)));
} else if (call_flags & METH_VARARGS) {
RELEASE_ASSERT(call_flags == METH_VARARGS || call_flags == (METH_VARARGS | METH_KEYWORDS), "");
Box* varargs;
RewriterVar* r_varargs;
if (passed_varargs == 0) {
varargs = EmptyTuple;
r_varargs = rewrite_args->rewriter->loadConst((intptr_t)EmptyTuple, Location::forArg(1));
} else if (passed_varargs == 1) {
varargs = BoxedTuple::create1(arg3);
r_varargs = rewrite_args->rewriter->call(false, (void*)BoxedTuple::create1, rewrite_args->arg3);
} else if (passed_varargs == 2) {
varargs = BoxedTuple::create2(arg3, args[0]);
r_varargs = rewrite_args->rewriter->call(false, (void*)BoxedTuple::create2, rewrite_args->arg3,
rewrite_args->args->getAttr(0, Location::forArg(1)));
} else {
RELEASE_ASSERT(0, "");
}
if (call_flags & METH_KEYWORDS) {
Box* kwargs = NULL;
RewriterVar* r_kwargs = rewrite_args->rewriter->loadConst(0);
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs);
r_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, r_obj, r_varargs, r_kwargs);
} else {
rtn = (Box*)(self->method->ml_meth)(obj, varargs);
r_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, r_obj, r_varargs);
}
} else if (call_flags == METH_O) {
RELEASE_ASSERT(passed_varargs == 1, "");
rtn = (Box*)(self->method->ml_meth)(obj, arg3);
r_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, r_obj, rewrite_args->arg3);
} else {
RELEASE_ASSERT(0, "0x%x", call_flags);
}
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_rtn = r_rtn;
rewrite_args->out_success = true;
return rtn;
}
}
......@@ -143,6 +143,7 @@ public:
DEFAULT_CLASS(wrapperdescr_cls);
static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner);
static Box* descr_get(Box* self, Box* inst, Box* owner) noexcept;
static Box* __call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args);
static void gcHandler(GCVisitor* v, Box* _o) {
......@@ -227,6 +228,8 @@ public:
}
static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args);
static Box* callInternal(BoxedFunctionBase* f, 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) {
assert(_o->cls == method_cls);
......
......@@ -69,6 +69,20 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo
return new BoxedWrapperObject(self, inst);
}
Box* BoxedWrapperDescriptor::descr_get(Box* _self, Box* inst, Box* owner) noexcept {
RELEASE_ASSERT(_self->cls == wrapperdescr_cls, "");
BoxedWrapperDescriptor* self = static_cast<BoxedWrapperDescriptor*>(_self);
if (inst == None)
return self;
if (!isSubclass(inst->cls, self->type))
PyErr_Format(TypeError, "Descriptor '' for '%s' objects doesn't apply to '%s' object",
getFullNameOfClass(self->type).c_str(), getFullTypeName(inst).c_str());
return new BoxedWrapperObject(self, inst);
}
Box* BoxedWrapperDescriptor::__call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args) {
RELEASE_ASSERT(descr->cls == wrapperdescr_cls, "");
......@@ -1725,8 +1739,9 @@ void setupCAPI() {
method_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
0, true, true)));
CLFunction* method_call_cl = boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, 0, true, true);
method_call_cl->internal_callable = BoxedMethodDescriptor::callInternal;
method_cls->giveAttr("__call__", new BoxedFunction(method_call_cl));
method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze();
......@@ -1737,6 +1752,7 @@ void setupCAPI() {
wrapperdescr_cls->giveAttr("__doc__",
new (pyston_getset_cls) BoxedGetsetDescriptor(wrapperdescrGetDoc, NULL, NULL));
wrapperdescr_cls->freeze();
wrapperdescr_cls->tp_descr_get = BoxedWrapperDescriptor::descr_get;
wrapperobject_cls->giveAttr(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true)));
......
......@@ -3416,12 +3416,15 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
Box* res = callable(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
return res;
} else if (obj->cls == instancemethod_cls) {
// TODO it's dumb but I should implement patchpoints here as well
// duplicated with callattr
BoxedInstanceMethod* im = static_cast<BoxedInstanceMethod*>(obj);
RewriterVar* r_im_func;
if (rewrite_args) {
r_im_func = rewrite_args->obj->getAttr(INSTANCEMETHOD_FUNC_OFFSET, Location::any());
}
if (rewrite_args && !rewrite_args->func_guarded) {
rewrite_args->obj->addAttrGuard(INSTANCEMETHOD_FUNC_OFFSET, (intptr_t)im->func);
r_im_func->addGuard((intptr_t)im->func);
}
// Guard on which type of instancemethod (bound or unbound)
......@@ -3431,13 +3434,12 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
rewrite_args->obj->addAttrGuard(INSTANCEMETHOD_OBJ_OFFSET, 0, im->obj != NULL);
}
// TODO guard on im->obj being NULL or not
if (im->obj == NULL) {
Box* f = im->func;
if (rewrite_args) {
rewrite_args->func_guarded = true;
rewrite_args->args_guarded = true;
rewrite_args->obj = rewrite_args->obj->getAttr(INSTANCEMETHOD_FUNC_OFFSET, Location::any());
rewrite_args->obj = r_im_func;
}
Box* res = runtimeCallInternal(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
return res;
......@@ -3446,10 +3448,7 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (npassed_args <= 2) {
Box* rtn;
if (rewrite_args) {
// Kind of weird that we don't need to give this a valid RewriterVar, but it shouldn't need to access it
// (since we've already guarded on the function).
// rewriter enforce that we give it one, though
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_im_func, rewrite_args->destination);
srewrite_args.arg1 = rewrite_args->obj->getAttr(INSTANCEMETHOD_OBJ_OFFSET, Location::any());
srewrite_args.func_guarded = true;
......
......@@ -857,6 +857,14 @@ static Box* functionGet(BoxedFunction* self, Box* inst, Box* owner) {
return new BoxedInstanceMethod(inst, self, owner);
}
static Box* function_descr_get(Box* self, Box* inst, Box* owner) noexcept {
RELEASE_ASSERT(self->cls == function_cls, "");
if (inst == None)
inst = NULL;
return new BoxedInstanceMethod(inst, self, owner);
}
static Box* functionCall(BoxedFunction* self, Box* args, Box* kwargs) {
RELEASE_ASSERT(self->cls == function_cls, "%s", getTypeName(self));
......@@ -2748,6 +2756,7 @@ void setupRuntime() {
function_cls->giveAttr("__defaults__", function_cls->getattr("func_defaults"));
function_cls->giveAttr("func_globals", function_cls->getattr("__globals__"));
function_cls->freeze();
function_cls->tp_descr_get = function_descr_get;
builtin_function_or_method_cls->giveAttr(
"__module__",
......
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