Commit acdd2cd8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Rewrite calls to BoxedMethodDescriptors

ie one of the common entrypoints to capi code.
parent e9661371
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "capi/types.h" #include "capi/types.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/rewrite_args.h"
namespace pyston { namespace pyston {
...@@ -44,17 +45,17 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe ...@@ -44,17 +45,17 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
Box* rtn; Box* rtn;
if (call_flags == METH_NOARGS) { if (call_flags == METH_NOARGS) {
assert(varargs->size() == 0); RELEASE_ASSERT(varargs->size() == 0, "");
assert(kwargs->d.size() == 0); RELEASE_ASSERT(kwargs->d.size() == 0, "");
rtn = (Box*)self->method->ml_meth(obj, NULL); rtn = (Box*)self->method->ml_meth(obj, NULL);
} else if (call_flags == METH_VARARGS) { } 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); rtn = (Box*)self->method->ml_meth(obj, varargs);
} else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) { } else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs); rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs);
} else if (call_flags == METH_O) { } else if (call_flags == METH_O) {
assert(kwargs->d.size() == 0); RELEASE_ASSERT(kwargs->d.size() == 0, "");
assert(varargs->size() == 1); RELEASE_ASSERT(varargs->size() == 1, "");
rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]); rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]);
} else { } else {
RELEASE_ASSERT(0, "0x%x", call_flags); RELEASE_ASSERT(0, "0x%x", call_flags);
...@@ -64,4 +65,83 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe ...@@ -64,4 +65,83 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
assert(rtn && "should have set + thrown an exception!"); assert(rtn && "should have set + thrown an exception!");
return rtn; 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;
}
} }
...@@ -228,6 +228,8 @@ public: ...@@ -228,6 +228,8 @@ public:
} }
static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args); 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) { static void gcHandler(GCVisitor* v, Box* _o) {
assert(_o->cls == method_cls); assert(_o->cls == method_cls);
......
...@@ -1739,8 +1739,9 @@ void setupCAPI() { ...@@ -1739,8 +1739,9 @@ void setupCAPI() {
method_cls->giveAttr("__get__", method_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, CLFunction* method_call_cl = boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, 0, true, true);
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->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze(); method_cls->freeze();
......
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