Commit 1a5e6053 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Change rearrangeArgs to taking a callback

This function is complicated because it has so many return values (out-parameters).
It also returns a decent amount of information about what the caller has to do
after it is done with the args (decref them, decref the rewritten ones, etc), and
the contract was getting very complicated.  It also had some complicated rules
about how the caller had to set up certain input arguments.

I also tried adding some optimizations to it, where it would sometimes not incref all
of the returned args; I tried continuing the current scheme by passing back some information
about which args needed to be decref'd or not.  This was really messy and was also a
perf hit.

So instead, switch it to being callback-based.  I think this should clean it up quite a bit
and also open up some room for more optimizations.

This commit is just a refactor -- it changes the name to rearrangeArgumentsAndCall, which takes
a "continuation" callback.  For now it just calls rearrangeArguments under the hood.
parent 69d40057
......@@ -3411,11 +3411,39 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
paramspec.takes_kwargs = false;
}
bool rewrite_success = false;
Box** oargs = NULL;
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
if (!paramspec.takes_kwargs)
arg2 = NULL;
if (rewrite_args) {
if (!paramspec.takes_kwargs)
rewrite_args->arg2 = rewrite_args->rewriter->loadConst(0, Location::forArg(2));
// Currently, guard that the value of tp_call didn't change, and then
// emit a call to the current function address.
// It might be better to just load the current value of tp_call and call it
// (after guarding it's not null), or maybe not. But the rewriter doesn't currently
// support calling a RewriterVar (can only call fixed function addresses).
RewriterVar* r_cls = rewrite_args->obj->getAttr(offsetof(Box, cls));
r_cls->addAttrGuard(offsetof(BoxedClass, tp_call), (intptr_t)self->cls->tp_call);
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)self->cls->tp_call, rewrite_args->obj,
rewrite_args->arg1, rewrite_args->arg2);
rewrite_args->out_rtn->setType(RefType::OWNED);
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
Box* r = self->cls->tp_call(self, arg1, arg2);
if (!r)
throwCAPIException();
return r;
};
try {
rearrangeArguments(paramspec, NULL, "", NULL, rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args,
oargs, keyword_names, NULL);
return rearrangeArgumentsAndCall(paramspec, NULL, "", NULL, rewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names, continuation);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
......@@ -3423,39 +3451,6 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
} else
throw e;
}
AUTO_DECREF(arg1);
if (!paramspec.takes_kwargs)
arg2 = NULL;
AUTO_XDECREF(arg2);
if (!rewrite_success)
rewrite_args = NULL;
if (rewrite_args) {
if (!paramspec.takes_kwargs)
rewrite_args->arg2 = rewrite_args->rewriter->loadConst(0, Location::forArg(2));
// Currently, guard that the value of tp_call didn't change, and then
// emit a call to the current function address.
// It might be better to just load the current value of tp_call and call it
// (after guarding it's not null), or maybe not. But the rewriter doesn't currently
// support calling a RewriterVar (can only call fixed function addresses).
RewriterVar* r_cls = rewrite_args->obj->getAttr(offsetof(Box, cls));
r_cls->addAttrGuard(offsetof(BoxedClass, tp_call), (intptr_t)self->cls->tp_call);
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)self->cls->tp_call, rewrite_args->obj,
rewrite_args->arg1, rewrite_args->arg2);
rewrite_args->out_rtn->setType(RefType::OWNED);
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
Box* r = self->cls->tp_call(self, arg1, arg2);
if (!r && S == CXX)
throwCAPIException();
return r;
}
extern "C" void PyType_RequestHcAttrs(PyTypeObject* cls, int offset) noexcept {
......
......@@ -262,15 +262,15 @@ struct ParamReceiveSpec {
assert(num_defaults <= MAX_DEFAULTS);
}
bool operator==(ParamReceiveSpec rhs) {
bool operator==(ParamReceiveSpec rhs) const {
return takes_varargs == rhs.takes_varargs && takes_kwargs == rhs.takes_kwargs
&& num_defaults == rhs.num_defaults && num_args == rhs.num_args;
}
bool operator!=(ParamReceiveSpec rhs) { return !(*this == rhs); }
bool operator!=(ParamReceiveSpec rhs) const { return !(*this == rhs); }
int totalReceived() { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); }
int kwargsIndex() { return num_args + (takes_varargs ? 1 : 0); }
int totalReceived() const { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); }
int kwargsIndex() const { return num_args + (takes_varargs ? 1 : 0); }
};
// Inline-caches contain fastpath code, and need to know that their fastpath is valid for a particular set
......
This diff is collapsed.
......@@ -1797,85 +1797,82 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa
// so we could just rearrangeArguments to the form that it wants and then call tp_new directly.
}
bool rewrite_success = false;
rearrangeArguments(paramspec, NULL, self->method_def->ml_name, defaults, rewrite_args, rewrite_success, argspec,
arg1, arg2, arg3, args, oargs, keyword_names, NULL);
AUTO_DECREF_ARGS(paramspec, arg1, arg2, arg3, oargs);
if (!rewrite_success)
rewrite_args = NULL;
RewriterVar* r_passthrough = NULL;
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, arg1);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1)
->setType(RefType::OWNED);
} else if (flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)func)(self->passthrough, arg1, arg2);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
} 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)))
->setType(RefType::OWNED);
} else if (flags == METH_O) {
rtn = (Box*)func(self->passthrough, arg1);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
RewriterVar* r_passthrough = NULL;
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1)
->setType(RefType::OWNED);
} else if ((flags & ~(METH_O3 | METH_D3)) == 0) {
assert(paramspec.totalReceived() <= 3); // would need to pass through oargs
rtn = ((Box * (*)(Box*, Box*, Box*, Box*))func)(self->passthrough, arg1, arg2, arg3);
if (rewrite_args) {
if (paramspec.totalReceived() == 1)
r_passthrough = rewrite_args->rewriter->loadConst((intptr_t)self->passthrough, Location::forArg(0));
Box* rtn;
if (flags == METH_VARARGS) {
rtn = (Box*)func(self->passthrough, arg1);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough,
rewrite_args->arg1)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 2)
} else if (flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)func)(self->passthrough, arg1, arg2);
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 3)
} 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->arg1,
rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED);
else
abort();
= rewrite_args->rewriter->call(true, (void*)func, r_passthrough,
rewrite_args->rewriter->loadConst(0, Location::forArg(1)))
->setType(RefType::OWNED);
} else if (flags == METH_O) {
rtn = (Box*)func(self->passthrough, arg1);
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough,
rewrite_args->arg1)->setType(RefType::OWNED);
} else if ((flags & ~(METH_O3 | METH_D3)) == 0) {
assert(paramspec.totalReceived() <= 3); // would need to pass through oargs
rtn = ((Box * (*)(Box*, Box*, Box*, Box*))func)(self->passthrough, arg1, arg2, arg3);
if (rewrite_args) {
if (paramspec.totalReceived() == 1)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough,
rewrite_args->arg1)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 2)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 3)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED);
else
abort();
}
} else if (flags == METH_OLDARGS) {
/* the really old style */
rewrite_args = NULL;
int size = PyTuple_GET_SIZE(arg1);
Box* arg = arg1;
if (size == 1)
arg = PyTuple_GET_ITEM(arg1, 0);
else if (size == 0)
arg = NULL;
rtn = func(self->passthrough, arg);
} else {
RELEASE_ASSERT(0, "0x%x", flags);
}
} else if (flags == METH_OLDARGS) {
/* the really old style */
rewrite_args = NULL;
int size = PyTuple_GET_SIZE(arg1);
Box* arg = arg1;
if (size == 1)
arg = PyTuple_GET_ITEM(arg1, 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->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
if (rewrite_args) {
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
if (S == CXX && !rtn)
throwCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn;
};
if (!rtn)
throwCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn;
return rearrangeArgumentsAndCall(paramspec, NULL, self->method_def->ml_name, defaults, rewrite_args, argspec, arg1,
arg2, arg3, args, keyword_names, continuation);
}
/* extension modules might be compiled with GC support so these
......
This diff is collapsed.
......@@ -429,11 +429,14 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunctionBase* function, Box* arg1
#endif
{
Py_INCREF(function);
Py_XINCREF(arg1);
Py_XINCREF(arg2);
Py_XINCREF(arg3);
int numArgs = function->md->numReceivedArgs();
if (numArgs > 0)
Py_XINCREF(arg1);
if (numArgs > 1)
Py_XINCREF(arg2);
if (numArgs > 2)
Py_XINCREF(arg3);
if (numArgs > 3) {
numArgs -= 3;
this->args = new (numArgs) GCdArray();
......@@ -631,15 +634,16 @@ static void generator_dealloc(BoxedGenerator* self) noexcept {
int numArgs = self->function->md->numReceivedArgs();
if (numArgs > 3) {
numArgs -= 3;
for (int i = 0; i < numArgs; i++) {
for (int i = 0; i < numArgs - 3; i++) {
Py_CLEAR(self->args->elts[i]);
}
}
Py_CLEAR(self->arg1);
Py_CLEAR(self->arg2);
Py_CLEAR(self->arg3);
if (numArgs > 2)
Py_CLEAR(self->arg3);
if (numArgs > 1)
Py_CLEAR(self->arg2);
if (numArgs > 0)
Py_CLEAR(self->arg1);
Py_CLEAR(self->function);
......@@ -667,15 +671,16 @@ static int generator_traverse(BoxedGenerator* self, visitproc visit, void* arg)
int numArgs = self->function->md->numReceivedArgs();
if (numArgs > 3) {
numArgs -= 3;
for (int i = 0; i < numArgs; i++) {
for (int i = 0; i < numArgs - 3; i++) {
Py_VISIT(self->args->elts[i]);
}
}
Py_VISIT(self->arg1);
Py_VISIT(self->arg2);
Py_VISIT(self->arg3);
if (numArgs > 2)
Py_VISIT(self->arg3);
if (numArgs > 1)
Py_VISIT(self->arg2);
if (numArgs > 0)
Py_VISIT(self->arg1);
Py_VISIT(self->function);
......
This diff is collapsed.
......@@ -292,26 +292,58 @@ struct CompareRewriteArgs {
: rewriter(rewriter), lhs(lhs), rhs(rhs), destination(destination), out_success(false), out_rtn(NULL) {}
};
// Passes the output arguments back through oarg. Passes the rewrite success by setting rewrite_success.
// Directly modifies rewrite_args args in place, but only if rewrite_success got set.
// oargs needs to be pre-allocated by the caller, since it's assumed that they will want to use alloca.
typedef Box* (*rearrange_target_t)(void*, CallRewriteArgs*, Box*, Box*, Box*, Box**);
// This is a magical helper class that converts a functor (in particular, lambdas) into a [function pointer, void* data]
// pair. This lets us pass the functor efficiently: we can avoid doing an allocation (by storing the functor on the
// stack),
// and also avoid making the receiving function have to be a template.
//
// In effect, it does what you would have to do to create a function pointer + void* pair, like one would pass to
// C-style functions.
class FunctorPointer {
private:
template <typename Functor> class ConversionHelper {
public:
static Box* call(void* f, CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
// static_assert(decltypeD
return (*(Functor*)f)(rewrite_args, arg1, arg2, arg3, args);
}
};
rearrange_target_t function_pointer;
void* functor;
public:
template <typename Functor>
FunctorPointer(Functor& f)
: function_pointer(ConversionHelper<Functor>::call), functor(&f) {}
Box* operator()(CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
return function_pointer(functor, rewrite_args, arg1, arg2, arg3, args);
}
};
// rearrangeArgumentsAndCall maps from a given set of arguments (the structure specified by an ArgPassSpec) to the
// parameter form than the receiving function expects (given by the ParamReceiveSpec). After it does this, it will
// call `continuation` and return the result.
//
// The caller is responsible for guarding for paramspec, argspec, param_names, and defaults.
// TODO Fix this function's signature. should we pass back out through args? the common case is that they
// match anyway. Or maybe it should call a callback function, which could save on the common case.
//
// Reference semantics: takes borrowed references, and everything written out is an owned reference.
// rearrangeArgumentsAndCall supports both CAPI- and CXX- exception styles for continuation, and will propagate them
// back to the caller. For now, it can also throw its own exceptions such as "not enough arguments", and will throw
// them in the CXX style.
template <Rewritable rewritable = REWRITABLE>
void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name,
Box** defaults, _CallRewriteArgsBase* rewrite_args, bool& rewrite_success, ArgPassSpec argspec,
Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** oargs,
const std::vector<BoxedString*>* keyword_names, bool* oargs_owned);
Box* rearrangeArgumentsAndCall(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name,
Box** defaults, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names,
FunctorPointer continuation);
// new_args should be allocated by the caller if at least three args get passed in.
// rewrite_args will get modified in place.
ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, _CallRewriteArgsBase* rewrite_args,
ArgPassSpec argspec, Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** new_args);
void decrefOargs(RewriterVar* oargs, bool* oargs_owned, int oargs_size);
} // namespace pyston
#endif
......@@ -833,32 +833,25 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
assert(S == CXX && "implement me");
ParamReceiveSpec paramspec(4, 3, false, false);
bool rewrite_success = false;
static ParamNames param_names({ "", "string", "encoding", "errors" }, "", "");
static Box* defaults[3] = { NULL, NULL, NULL };
Box* oargs[1] = { NULL };
bool oargs_owned[1];
rearrangeArguments(paramspec, &param_names, "unicode", defaults, rewrite_args, rewrite_success, argspec, arg1,
arg2, arg3, args, oargs, keyword_names, oargs_owned);
assert(arg1 == cls);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
assert(arg1 == cls);
AUTO_DECREF_ARGS(paramspec, arg1, arg2, arg3, oargs);
if (!rewrite_success)
rewrite_args = NULL;
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)unicodeNewHelper, rewrite_args->arg1, rewrite_args->arg2,
rewrite_args->arg3, rewrite_args->args)->setType(RefType::OWNED);
if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)unicodeNewHelper, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3,
rewrite_args->args)->setType(RefType::OWNED);
decrefOargs(rewrite_args->args, oargs_owned, 1);
rewrite_args->out_success = true;
}
rewrite_args->out_success = true;
}
return unicodeNewHelper(static_cast<BoxedClass*>(arg1), arg2, arg3, args);
};
return unicodeNewHelper(cls, arg2, arg3, oargs);
return rearrangeArgumentsAndCall(paramspec, &param_names, "unicode", defaults, rewrite_args, argspec, arg1,
arg2, arg3, args, keyword_names, continuation);
}
if (cls->tp_new != object_cls->tp_new && cls->tp_new != slot_tp_new && cls->tp_new != BaseException->tp_new
......@@ -870,27 +863,21 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
assert(S == CXX && "implement me");
ParamReceiveSpec paramspec(1, false, true, true);
bool rewrite_success = false;
Box** oargs = NULL;
rearrangeArguments(paramspec, NULL, "", NULL, rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args,
oargs, keyword_names, NULL);
assert(arg1 == cls);
AUTO_DECREF(arg1);
AUTO_DECREF(arg2);
AUTO_XDECREF(arg3);
if (!rewrite_success)
rewrite_args = NULL;
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
assert(arg1 == cls);
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)cpythonTypeCall, rewrite_args->arg1, rewrite_args->arg2,
rewrite_args->arg3)->setType(RefType::OWNED);
rewrite_args->out_success = true;
}
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)cpythonTypeCall, rewrite_args->arg1, rewrite_args->arg2,
rewrite_args->arg3)->setType(RefType::OWNED);
rewrite_args->out_success = true;
}
return cpythonTypeCall(cls, arg2, arg3);
return cpythonTypeCall(cls, arg2, arg3);
};
return rearrangeArgumentsAndCall(paramspec, NULL, "", NULL, rewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names, continuation);
}
if (argspec.has_starargs || argspec.has_kwargs)
......@@ -1196,27 +1183,6 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// will be, whereas this block can't; I'm not sure how to merge the functionality. That's
// probably just evidence of the overall convolutedness of this function.
// TODO: instead of rewriting to the capi-format, maybe we should do the rearrangearguments
// inside the helper?
bool rewrite_success = false;
try {
rearrangeArguments(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args, rewrite_success,
argspec, made, arg2, arg3, args, NULL, keyword_names, NULL);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
AUTO_DECREF(made);
AUTO_DECREF(arg2);
AUTO_XDECREF(arg3);
if (!rewrite_success)
rewrite_args = NULL;
class InitHelper {
public:
static Box* call(STOLEN(Box*) made, BoxedClass* cls, Box* args, Box* kwargs) noexcept(S == CAPI) {
......@@ -1234,17 +1200,32 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
};
assert(arg2->cls == tuple_cls);
assert(!arg3 || arg3->cls == dict_cls);
// TODO: instead of rewriting to the capi-format, maybe we should do the rearrangearguments
// inside the helper?
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
assert(arg2->cls == tuple_cls);
assert(!arg3 || arg3->cls == dict_cls);
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)InitHelper::call, r_made, r_ccls, rewrite_args->arg2,
rewrite_args->arg3)->setType(RefType::OWNED);
r_made->refConsumed();
rewrite_args->out_success = true;
if (rewrite_args) {
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)InitHelper::call, r_made, r_ccls, rewrite_args->arg2,
rewrite_args->arg3)->setType(RefType::OWNED);
r_made->refConsumed();
rewrite_args->out_success = true;
}
return InitHelper::call(made, cls, arg2, arg3);
};
try {
return rearrangeArgumentsAndCall(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args, argspec,
made, arg2, arg3, args, keyword_names, continuation);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
return InitHelper::call(made, cls, arg2, arg3);
}
// If __new__ returns a subclass, supposed to call that subclass's __init__.
......@@ -1343,10 +1324,22 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
assert(tpinit == cls->tp_init);
}
bool rewrite_success = false;
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
assert(arg2->cls == tuple_cls);
assert(!arg3 || arg3->cls == dict_cls);
int err = tpinit(made, arg2, arg3);
if (err == -1) {
throwCAPIException();
}
return (Box*)NULL;
};
try {
rearrangeArguments(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args, rewrite_success,
argspec, made, arg2, arg3, args, NULL, keyword_names, NULL);
Box* _t = rearrangeArgumentsAndCall(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args,
argspec, made, arg2, arg3, args, keyword_names, continuation);
assert(_t == NULL);
} catch (ExcInfo e) {
Py_DECREF(made);
if (S == CAPI) {
......@@ -1356,22 +1349,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
throw e;
}
if (!rewrite_success)
rewrite_args = NULL;
assert(arg2->cls == tuple_cls);
assert(!arg3 || arg3->cls == dict_cls);
int err = tpinit(made, arg2, arg3);
Py_DECREF(made);
Py_DECREF(arg2);
Py_XDECREF(arg3);
if (err == -1) {
Py_DECREF(made);
if (S == CAPI)
return NULL;
if (rewrite_args) {
if (!rewrite_args->out_success)
rewrite_args = NULL;
else
throwCAPIException();
rewrite_args->out_success = false;
}
if (rewrite_args) {
......
......@@ -413,41 +413,6 @@ public:
#define AUTO_DECREF_ARRAY(x, size) AutoDecrefArray<false> CAT(_autodecref_, __LINE__)((x), (size))
#define AUTO_XDECREF_ARRAY(x, size) AutoDecrefArray<true> CAT(_autodecref_, __LINE__)((x), (size))
class AutoDecrefArgs {
private:
int num_args;
Box* arg1, *arg2, *arg3;
Box** args;
public:
AutoDecrefArgs(int num_args, Box* arg1, Box* arg2, Box* arg3, Box** args)
: num_args(num_args), arg1(arg1), arg2(arg2), arg3(arg3), args(args) {}
AutoDecrefArgs(ParamReceiveSpec paramspec, Box* arg1, Box* arg2, Box* arg3, Box** args)
: num_args(paramspec.totalReceived()), arg1(arg1), arg2(arg2), arg3(arg3), args(args) {}
~AutoDecrefArgs() {
// TODO Minor optimization: only the last arg (kwargs) is allowed to be NULL.
switch (num_args) {
default:
for (int i = 0; i < num_args - 3; i++) {
Py_XDECREF(args[i]);
}
case 3:
Py_XDECREF(arg3);
case 2:
Py_XDECREF(arg2);
case 1:
Py_XDECREF(arg1);
case 0:
break;
}
}
};
// Note: this captures the first three args by value (like AUTO_DECREF) but the array by reference.
// You can also pass a ParamReceiveSpec instead of an int for num_args
#define AUTO_DECREF_ARGS(num_args, arg1, arg2, arg3, args) \
AutoDecrefArgs CAT(_autodecref_, __LINE__)((num_args), (arg1), (arg2), (arg3), (args))
template <typename B> B* incref(B* b) {
Py_INCREF(b);
return b;
......
# Tests to see if we add any extra refs to function arguments.
import sys
print sys.getrefcount(object())
def f(o):
print sys.getrefcount(o)
# This gives 3 for CPython and our interpreter, but 2 for the llvm tier:
# f(object())
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