Commit 147549c9 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #1176 from kmod/rearrange_and_call

Make rearrangeArgs take a callback instead passing back values
parents 02c0a74c 8201e339
......@@ -776,7 +776,7 @@ check$1 test$1: $(PYTHON_EXE_DEPS) pyston$1
@# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k --exit-code-only --skip-failing -t50 $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t600 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -a=-X -R pyston$1 -j$(TEST_THREADS) -a=-n -a=-S -k $(TESTS_DIR) $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -a=-X -R pyston$1 -j$(TEST_THREADS) -a=-n -a=-S -t50 -k $(TESTS_DIR) $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-O -a=-S -k $(TESTS_DIR) $(ARGS)
.PHONY: run$1 dbg$1
......
......@@ -3411,51 +3411,40 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
paramspec.takes_kwargs = false;
}
bool rewrite_success = false;
Box** oargs = NULL;
try {
rearrangeArguments(paramspec, NULL, "", NULL, rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args,
oargs, keyword_names, NULL);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
if (!paramspec.takes_kwargs)
arg2 = NULL;
AUTO_DECREF(arg1);
if (!paramspec.takes_kwargs)
arg2 = NULL;
AUTO_XDECREF(arg2);
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;
}
if (!rewrite_success)
rewrite_args = NULL;
Box* r = self->cls->tp_call(self, arg1, arg2);
if (S == CXX && !r)
throwCAPIException();
return r;
};
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;
return callCXXFromStyle<S>([&]() {
return rearrangeArgumentsAndCall(paramspec, NULL, "", NULL, rewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names, continuation);
});
}
extern "C" void PyType_RequestHcAttrs(PyTypeObject* cls, int offset) noexcept {
......
......@@ -262,15 +262,16 @@ 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 varargsIndex() const { return num_args; }
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
......
......@@ -553,104 +553,103 @@ template <ExceptionStyle S>
Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
static Box* defaults[] = { NULL };
bool rewrite_success = false;
rearrangeArguments(ParamReceiveSpec(3, 1, false, false), NULL, "getattr", defaults, rewrite_args, rewrite_success,
argspec, arg1, arg2, arg3, args, NULL, keyword_names, NULL);
if (!rewrite_success)
rewrite_args = NULL;
Box* obj = arg1;
Box* _str = arg2;
Box* default_value = arg3;
AUTO_DECREF(obj);
AUTO_DECREF(_str);
AUTO_XDECREF(default_value);
if (rewrite_args) {
// We need to make sure that the attribute string will be the same.
// Even though the passed string might not be the exact attribute name
// that we end up looking up (because we need to encode it or intern it),
// guarding on that object means (for strings and unicode) that the string
// value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL;
else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
rewrite_args->arg2->addGuard((intptr_t)arg2);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
Box* obj = arg1;
Box* _str = arg2;
Box* default_value = arg3;
if (rewrite_args) {
// We need to make sure that the attribute string will be the same.
// Even though the passed string might not be the exact attribute name
// that we end up looking up (because we need to encode it or intern it),
// guarding on that object means (for strings and unicode) that the string
// value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL;
else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
rewrite_args->arg2->addGuard((intptr_t)arg2);
}
}
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
_str = coerceUnicodeToStr<S>(_str);
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "getattr(): attribute name must be string");
return NULL;
} else
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
if (S == CAPI && !_str)
return (Box*)NULL;
BoxedString* str = static_cast<BoxedString*>(_str);
if (!PyString_CHECK_INTERNED(str))
internStringMortalInplace(str);
AUTO_DECREF(str);
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "getattr(): attribute name must be string");
return (Box*)NULL;
} else
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
Box* rtn;
RewriterVar* r_rtn;
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
// TODO could make the return valid in the NOEXC_POSSIBLE case via a helper
if (!grewrite_args.isSuccessful())
rewrite_args = NULL;
else {
ReturnConvention return_convention;
std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
if (default_value)
rewrite_args = NULL;
BoxedString* str = static_cast<BoxedString*>(_str);
if (!PyString_CHECK_INTERNED(str))
internStringMortalInplace(str);
AUTO_DECREF(str);
Box* rtn;
RewriterVar* r_rtn;
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
// TODO could make the return valid in the NOEXC_POSSIBLE case via a helper
if (!grewrite_args.isSuccessful())
rewrite_args = NULL;
else {
ReturnConvention return_convention;
std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
if (default_value)
rewrite_args = NULL;
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN
|| (default_value == NULL && return_convention == ReturnConvention::MAYBE_EXC));
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN
|| (default_value == NULL && return_convention == ReturnConvention::MAYBE_EXC));
} else {
rtn = getattrInternal<CAPI>(obj, str);
}
} else {
rtn = getattrInternal<CAPI>(obj, str);
}
if (rewrite_args) {
assert(PyString_CHECK_INTERNED(str) == SSTATE_INTERNED_IMMORTAL);
RewriterVar* r_str = rewrite_args->rewriter->loadConst((intptr_t)str, Location::forArg(2));
RewriterVar* final_rtn
= rewrite_args->rewriter->call(false, (void*)getattrFuncHelper, r_rtn, rewrite_args->arg1, r_str,
rewrite_args->arg3)->setType(RefType::OWNED);
r_rtn->refConsumed();
if (rewrite_args) {
assert(PyString_CHECK_INTERNED(str) == SSTATE_INTERNED_IMMORTAL);
RewriterVar* r_str = rewrite_args->rewriter->loadConst((intptr_t)str, Location::forArg(2));
RewriterVar* final_rtn
= rewrite_args->rewriter->call(false, (void*)getattrFuncHelper, r_rtn, rewrite_args->arg1, r_str,
rewrite_args->arg3)->setType(RefType::OWNED);
r_rtn->refConsumed();
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(final_rtn);
rewrite_args->out_success = true;
rewrite_args->out_rtn = final_rtn;
}
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(final_rtn);
rewrite_args->out_success = true;
rewrite_args->out_rtn = final_rtn;
}
Box* r = getattrFuncHelper(rtn, obj, str, default_value);
if (S == CXX && !r)
throwCAPIException();
return r;
};
Box* r = getattrFuncHelper(rtn, obj, str, default_value);
if (S == CXX && !r)
throwCAPIException();
return r;
return callCXXFromStyle<S>([&]() {
return rearrangeArgumentsAndCall(ParamReceiveSpec(3, 1, false, false), NULL, "getattr", defaults, rewrite_args,
argspec, arg1, arg2, arg3, args, keyword_names, continuation);
});
}
Box* setattrFunc(Box* obj, Box* _str, Box* value) {
......@@ -688,97 +687,96 @@ static Box* hasattrFuncHelper(STOLEN(Box*) return_val) noexcept {
template <ExceptionStyle S>
Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
Box* arg2, Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
bool rewrite_success = false;
rearrangeArguments(ParamReceiveSpec(2, 0, false, false), NULL, "hasattr", NULL, rewrite_args, rewrite_success,
argspec, arg1, arg2, arg3, args, NULL, keyword_names, NULL);
if (!rewrite_success)
rewrite_args = NULL;
AUTO_DECREF(arg1);
AUTO_DECREF(arg2);
Box* obj = arg1;
Box* _str = arg2;
if (rewrite_args) {
// We need to make sure that the attribute string will be the same.
// Even though the passed string might not be the exact attribute name
// that we end up looking up (because we need to encode it or intern it),
// guarding on that object means (for strings and unicode) that the string
// value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL;
else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
Box* obj = arg1;
Box* _str = arg2;
if (rewrite_args) {
// We need to make sure that the attribute string will be the same.
// Even though the passed string might not be the exact attribute name
// that we end up looking up (because we need to encode it or intern it),
// guarding on that object means (for strings and unicode) that the string
// value is fixed.
if (!PyString_CheckExact(_str) && !PyUnicode_CheckExact(_str))
rewrite_args = NULL;
else {
if (PyString_CheckExact(_str) && PyString_CHECK_INTERNED(_str) == SSTATE_INTERNED_IMMORTAL) {
// can avoid keeping the extra gc reference
} else {
rewrite_args->rewriter->addGCReference(_str);
}
rewrite_args->arg2->addGuard((intptr_t)arg2);
rewrite_args->arg2->addGuard((intptr_t)arg2);
}
}
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
_str = coerceUnicodeToStr<S>(_str);
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "hasattr(): attribute name must be string");
return NULL;
} else
raiseExcHelper(TypeError, "hasattr(): attribute name must be string");
}
if (S == CAPI && !_str)
return (Box*)NULL;
BoxedString* str = static_cast<BoxedString*>(_str);
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "hasattr(): attribute name must be string");
return (Box*)NULL;
} else
raiseExcHelper(TypeError, "hasattr(): attribute name must be string");
}
if (!PyString_CHECK_INTERNED(str))
internStringMortalInplace(str);
AUTO_DECREF(str);
BoxedString* str = static_cast<BoxedString*>(_str);
Box* rtn;
RewriterVar* r_rtn;
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.isSuccessful())
rewrite_args = NULL;
else {
ReturnConvention return_convention;
std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
if (!PyString_CHECK_INTERNED(str))
internStringMortalInplace(str);
AUTO_DECREF(str);
Box* rtn;
RewriterVar* r_rtn;
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.isSuccessful())
rewrite_args = NULL;
else {
ReturnConvention return_convention;
std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
rewrite_args = NULL;
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN);
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN);
} else {
rtn = getattrInternal<CAPI>(obj, str);
}
} else {
rtn = getattrInternal<CAPI>(obj, str);
}
if (rewrite_args) {
RewriterVar* final_rtn
= rewrite_args->rewriter->call(false, (void*)hasattrFuncHelper, r_rtn)->setType(RefType::OWNED);
r_rtn->refConsumed();
if (rewrite_args) {
RewriterVar* final_rtn
= rewrite_args->rewriter->call(false, (void*)hasattrFuncHelper, r_rtn)->setType(RefType::OWNED);
r_rtn->refConsumed();
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(final_rtn);
rewrite_args->out_success = true;
rewrite_args->out_rtn = final_rtn;
}
if (S == CXX)
rewrite_args->rewriter->checkAndThrowCAPIException(final_rtn);
rewrite_args->out_success = true;
rewrite_args->out_rtn = final_rtn;
}
Box* r = hasattrFuncHelper(rtn);
if (S == CXX && !r)
throwCAPIException();
return r;
Box* r = hasattrFuncHelper(rtn);
if (S == CXX && !r)
throwCAPIException();
return r;
};
return callCXXFromStyle<S>([&]() {
return rearrangeArgumentsAndCall(ParamReceiveSpec(2, 0, false, false), NULL, "hasattr", NULL, rewrite_args,
argspec, arg1, arg2, arg3, args, keyword_names, continuation);
});
}
Box* map2(Box* f, Box* container) {
......
......@@ -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
......
......@@ -311,15 +311,6 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
RELEASE_ASSERT(0, "0x%x", call_flags);
}
Box** oargs = NULL;
Box* oargs_array[1] = { NULL };
if (paramspec.totalReceived() > 3) {
assert((paramspec.totalReceived() - 3) <= sizeof(oargs_array) / sizeof(oargs_array[0]));
oargs = oargs_array;
}
bool oargs_owned[1];
bool arg1_class_guarded = false;
if (rewrite_args && argspec.num_args >= 1) {
// Try to do the guard before rearrangeArguments if possible:
......@@ -327,105 +318,102 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
arg1_class_guarded = true;
}
bool rewrite_success = false;
rearrangeArguments(paramspec, NULL, self->method->ml_name, defaults, rewrite_args, rewrite_success, argspec, arg1,
arg2, arg3, args, oargs, keyword_names, oargs_owned);
AUTO_DECREF_ARGS(paramspec, arg1, arg2, arg3, oargs);
if (!rewrite_success)
rewrite_args = NULL;
if (ml_flags & METH_CLASS) {
rewrite_args = NULL;
if (!PyType_Check(arg1))
raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", self->method->ml_name,
getFullTypeName(arg1).c_str());
} else {
if (!isSubclass(arg1->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' arg1 but received a '%s'", self->method->ml_name,
getFullNameOfClass(self->type).c_str(), getFullTypeName(arg1).c_str());
}
if (rewrite_args && !arg1_class_guarded) {
rewrite_args->arg1->addAttrGuard(offsetof(Box, cls), (intptr_t)arg1->cls);
}
Box* rtn;
if (call_flags == METH_NOARGS) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, NULL);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->rewriter->loadConst(0, Location::forArg(1)))
->setType(RefType::OWNED);
} else if (call_flags == METH_VARARGS) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, arg2);
}
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
} else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(arg1, arg2, arg3);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED);
} else if (call_flags == METH_O) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, arg2);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
if (ml_flags & METH_CLASS) {
rewrite_args = NULL;
if (!PyType_Check(arg1))
raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", self->method->ml_name,
getFullTypeName(arg1).c_str());
} else {
if (!isSubclass(arg1->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' arg1 but received a '%s'",
self->method->ml_name, getFullNameOfClass(self->type).c_str(),
getFullTypeName(arg1).c_str());
}
if (rewrite_args)
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
} else if ((call_flags & ~(METH_O3 | METH_D3)) == 0) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = ((Box * (*)(Box*, Box*, Box*, Box**))self->method->ml_meth)(arg1, arg2, arg3, oargs);
if (rewrite_args && !arg1_class_guarded) {
rewrite_args->arg1->addAttrGuard(offsetof(Box, cls), (intptr_t)arg1->cls);
}
if (rewrite_args) {
if (paramspec.totalReceived() == 2)
Box* rtn;
if (call_flags == METH_NOARGS) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, NULL);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->rewriter->loadConst(0, Location::forArg(1)))
->setType(RefType::OWNED);
} else if (call_flags == METH_VARARGS) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, arg2);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 3)
} else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(arg1, arg2, arg3);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED);
else if (paramspec.totalReceived() > 3)
} else if (call_flags == METH_O) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = (Box*)self->method->ml_meth(arg1, arg2);
}
if (rewrite_args)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3,
rewrite_args->args)->setType(RefType::OWNED);
else
abort();
rewrite_args->arg2)->setType(RefType::OWNED);
} else if ((call_flags & ~(METH_O3 | METH_D3)) == 0) {
{
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
rtn = ((Box * (*)(Box*, Box*, Box*, Box**))self->method->ml_meth)(arg1, arg2, arg3, args);
}
if (rewrite_args) {
if (paramspec.totalReceived() == 2)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2)->setType(RefType::OWNED);
else if (paramspec.totalReceived() == 3)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED);
else if (paramspec.totalReceived() > 3)
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1,
rewrite_args->arg2, rewrite_args->arg3,
rewrite_args->args)->setType(RefType::OWNED);
else
abort();
}
} else {
RELEASE_ASSERT(0, "0x%x", call_flags);
}
} else {
RELEASE_ASSERT(0, "0x%x", call_flags);
}
if (!rtn)
throwCAPIException();
if (!rtn)
throwCAPIException();
if (rewrite_args && oargs)
decrefOargs(rewrite_args->args, oargs_owned, 1);
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;
}
return rtn;
};
return rtn;
return rearrangeArgumentsAndCall(paramspec, NULL, self->method->ml_name, defaults, rewrite_args, argspec, arg1,
arg2, arg3, args, keyword_names, continuation);
}
static Box* methodGetName(Box* b, void*) {
assert(b->cls == method_cls);
const char* s = static_cast<BoxedMethodDescriptor*>(b)->method->ml_name;
......@@ -646,74 +634,76 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
RELEASE_ASSERT(0, "%d", flags);
}
Box** oargs = NULL;
bool rewrite_success = false;
rearrangeArguments(paramspec, NULL, self->wrapper->name.data(), NULL, rewrite_args, rewrite_success, argspec, arg1,
arg2, arg3, args, oargs, keyword_names, NULL);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
#ifndef NDEBUG
if (paramspec.takes_varargs)
assert(arg2 && arg2->cls == tuple_cls);
#endif
AUTO_DECREF_ARGS(paramspec, arg1, arg2, arg3, oargs);
Box* rtn;
if (flags == PyWrapperFlag_KEYWORDS) {
wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
rtn = (*wk)(arg1, arg2, self->wrapped, arg3);
if (paramspec.takes_varargs)
assert(arg2 && arg2->cls == tuple_cls);
if (!rewrite_success)
rewrite_args = NULL;
Box* rtn;
if (flags == PyWrapperFlag_KEYWORDS) {
wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
rtn = (*wk)(arg1, arg2, self->wrapped, arg3);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wk, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)),
rewrite_args->arg3)->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else if (flags == PyWrapperFlag_PYSTON || flags == 0) {
rtn = (*wrapper)(arg1, arg2, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else if (flags == PyWrapperFlag_1ARG) {
wrapperfunc_1arg wrapper_1arg = (wrapperfunc_1arg)wrapper;
rtn = (*wrapper_1arg)(arg1, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(1)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn
= rewriter->call(true, (void*)wk, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)),
rewrite_args->arg3)->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else if (flags == PyWrapperFlag_PYSTON || flags == 0) {
rtn = (*wrapper)(arg1, arg2, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn
= rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else if (flags == PyWrapperFlag_1ARG) {
wrapperfunc_1arg wrapper_1arg = (wrapperfunc_1arg)wrapper;
rtn = (*wrapper_1arg)(arg1, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn
= rewriter->call(true, (void*)wrapper, rewrite_args->arg1,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(1)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else if (flags == PyWrapperFlag_2ARG) {
rtn = (*wrapper)(arg1, arg2, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn
= rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else {
RELEASE_ASSERT(0, "%d", flags);
}
} else if (flags == PyWrapperFlag_2ARG) {
rtn = (*wrapper)(arg1, arg2, self->wrapped);
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)))
->setType(RefType::OWNED);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true;
}
} else {
RELEASE_ASSERT(0, "%d", flags);
}
if (S == CXX && !rtn)
throwCAPIException();
return rtn;
};
if (!rtn)
throwCAPIException();
return rtn;
return callCXXFromStyle<S>([&]() {
return rearrangeArgumentsAndCall(paramspec, NULL, self->wrapper->name.data(), NULL, rewrite_args, argspec, arg1,
arg2, arg3, args, keyword_names, continuation);
});
}
static Box* wrapperdescrGetDoc(Box* b, void*) {
......
......@@ -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);
......
......@@ -4032,10 +4032,34 @@ static llvm::StringRef getFunctionName(FunctionMetadata* f) {
return "<unknown function>";
}
template <typename FuncNameCB>
// A hacky little class that lets us save on some parameter size.
// We want to pass enough information to rearrangeArgumentsAndCallInternal so that
// it knows how to get the function name when it needs to (only when an exception is thrown),
// and there are a couple different ways that it might need to do that. So we pass through this
// class that steals some bits from the pointers.
class FuncNameGetter {
private:
uint64_t data;
// Can't be the lsb since a const char* is only 1-byte aligned.
static constexpr uint64_t BIT = (1L << 63);
public:
FuncNameGetter(const char* name) : data((uint64_t)name) { assert(!(data & BIT)); }
FuncNameGetter(FunctionMetadata* md) : data(((uint64_t)md) ^ BIT) { assert(data & BIT); }
const char* operator()() {
if (data & BIT) {
FunctionMetadata* md = (FunctionMetadata*)(data ^ BIT);
return getFunctionName(md).data();
} else {
return (const char*)data;
}
}
};
static int placeKeyword(const ParamNames* param_names, llvm::SmallVector<bool, 8>& params_filled, BoxedString* kw_name,
Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs, BoxedDict* okwargs,
FuncNameCB func_name_cb) {
FuncNameGetter func_name_cb) {
assert(kw_val);
assert(kw_name);
......@@ -4120,25 +4144,10 @@ public:
}
};
void decrefOargs(RewriterVar* oargs, bool* oargs_owned, int num_oargs) {
for (int i = 0; i < num_oargs; i++) {
if (oargs_owned[i]) {
oargs->deregisterOwnedAttr(i * sizeof(Box*));
oargs->getAttr(i * sizeof(Box*))->setType(RefType::OWNED);
}
}
}
template <Rewritable rewritable, typename FuncNameCB>
void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* param_names, FuncNameCB func_name_cb,
Box** defaults, _CallRewriteArgsBase* rewrite_args, bool& rewrite_success,
ArgPassSpec argspec, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** args, Box** oargs,
const std::vector<BoxedString*>* keyword_names, bool* oargs_owned) {
if (rewritable == NOT_REWRITABLE) {
assert(!rewrite_args);
rewrite_args = NULL;
}
Box* rearrangeArgumentsAndCallInternal(ParamReceiveSpec paramspec, const ParamNames* param_names,
FuncNameGetter func_name_cb, Box** defaults, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names, FunctorPointer continuation) {
/*
* Procedure:
* - First match up positional arguments; any extra go to varargs. error if too many.
......@@ -4147,44 +4156,17 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
* - error about missing parameters
*/
int num_output_args = paramspec.totalReceived();
int num_passed_args = argspec.totalPassed();
assert((oargs != NULL) == (num_output_args > 3));
assert((defaults != NULL) == (paramspec.num_defaults != 0));
if (rewrite_args && oargs) {
assert(oargs_owned);
memset(oargs_owned, 0, (num_output_args - 3) * sizeof(bool));
}
if (rewrite_args) {
rewrite_success = false; // default case
}
auto propagate_args = [&]() {
if (num_output_args >= 1)
Py_XINCREF(oarg1);
if (num_output_args >= 2)
Py_XINCREF(oarg2);
if (num_output_args >= 3)
Py_XINCREF(oarg3);
if (num_output_args >= 3) {
memcpy(oargs, args, sizeof(Box*) * (num_output_args - 3));
for (int i = 0; i < num_output_args - 3; i++) {
Py_XINCREF(oargs[i]);
}
}
};
// Super fast path:
if (argspec.num_keywords == 0 && !argspec.has_starargs && !paramspec.takes_varargs && !argspec.has_kwargs
&& argspec.num_args == paramspec.num_args && !paramspec.takes_kwargs) {
rewrite_success = true;
propagate_args();
return;
return continuation(rewrite_args, arg1, arg2, arg3, args);
}
int num_output_args = paramspec.totalReceived();
int num_passed_args = argspec.totalPassed();
// Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple
// django-admin test this covers something like 93% of all calls to callFunc.
if (argspec.num_keywords == 0 && argspec.has_starargs == paramspec.takes_varargs && !argspec.has_kwargs
......@@ -4195,7 +4177,7 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
assert(num_output_args == num_passed_args + 1);
int idx = paramspec.kwargsIndex();
assert(idx < 3);
getArg(idx, oarg1, oarg2, oarg3, NULL) = NULL; // pass NULL for kwargs
getArg(idx, arg1, arg2, arg3, NULL) = NULL; // pass NULL for kwargs
if (rewrite_args) {
if (idx == 0)
rewrite_args->arg1 = rewrite_args->rewriter->loadConst(0)->setType(RefType::BORROWED);
......@@ -4215,31 +4197,28 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
// received by the caller are always tuples).
// This is why we can't pass kwargs here.
if (argspec.has_starargs) {
Box* given_varargs = getArg(argspec.num_args + argspec.num_keywords, oarg1, oarg2, oarg3, args);
Box* given_varargs = getArg(argspec.num_args + argspec.num_keywords, arg1, arg2, arg3, args);
if (given_varargs->cls == tuple_cls) {
if (rewrite_args) {
getArg(argspec.num_args + argspec.num_keywords, rewrite_args)
->addAttrGuard(offsetof(Box, cls), (intptr_t)tuple_cls);
}
rewrite_success = true;
propagate_args();
return;
return continuation(rewrite_args, arg1, arg2, arg3, args);
}
} else {
rewrite_success = true;
propagate_args();
return;
return continuation(rewrite_args, arg1, arg2, arg3, args);
}
}
// Save the original values:
Box* arg1 = oarg1;
Box* arg2 = oarg2;
Box* arg3 = oarg3;
Box* oarg1, *oarg2, *oarg3;
oarg1 = oarg2 = oarg3 = NULL;
if (oargs)
Box** oargs = NULL;
// TODO: could we reuse the args array?
if (num_output_args > 3) {
oargs = (Box**)alloca(sizeof(Box*) * (num_output_args - 3));
memset(oargs, 0, sizeof(Box*) * (num_output_args - 3));
}
// Clear any increfs we did for when we throw an exception:
auto clear_refs = [&]() {
......@@ -4268,9 +4247,6 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
// At this point we are not allowed to abort the rewrite any more, since we will start
// modifying rewrite_args.
if (rewrite_args)
rewrite_success = true;
if (rewrite_args) {
// We might have trouble if we have more output args than input args,
// such as if we need more space to pass defaults.
......@@ -4346,6 +4322,7 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
unused_positional.push_back(PySequence_Fast_GET_ITEM(varargs, i));
}
bool varargs_owned = false;
if (paramspec.takes_varargs) {
int varargs_idx = paramspec.num_args;
if (rewrite_args) {
......@@ -4354,7 +4331,6 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
RewriterVar* varargs_val;
int varargs_size = unused_positional_rvars.size();
bool is_owned = false;
if (varargs_size == 0) {
varargs_val
......@@ -4374,7 +4350,7 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
};
varargs_val = rewrite_args->rewriter->call(true, create_ptrs[varargs_size], unused_positional_rvars)
->setType(RefType::OWNED);
is_owned = true;
varargs_owned = true;
}
if (varargs_val) {
......@@ -4385,13 +4361,12 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
if (varargs_idx == 2)
rewrite_args->arg3 = varargs_val;
if (varargs_idx >= 3) {
if (is_owned) {
if (varargs_owned) {
rewrite_args->args->registerOwnedAttr((varargs_idx - 3) * sizeof(Box*));
rewrite_args->args->setAttr((varargs_idx - 3) * sizeof(Box*), varargs_val,
RewriterVar::SetattrType::HANDED_OFF);
oargs_owned[varargs_idx - 3] = true;
varargs_val->refConsumed();
} else {
rewrite_args->args->setAttr((varargs_idx - 3) * sizeof(Box*), varargs_val);
......@@ -4607,25 +4582,28 @@ void rearrangeArgumentsInternal(ParamReceiveSpec paramspec, const ParamNames* pa
getArg(arg_idx, oarg1, oarg2, oarg3, oargs) = xincref(default_obj);
}
cleanup.cancel();
if (rewrite_args && varargs_owned) {
Box* r = continuation(rewrite_args, oarg1, oarg2, oarg3, oargs);
int varargs_idx = paramspec.varargsIndex();
if (varargs_idx >= 3) {
rewrite_args->args->deregisterOwnedAttr((varargs_idx - 3) * sizeof(Box*));
rewrite_args->args->getAttr((varargs_idx - 3) * sizeof(Box*))->setType(RefType::OWNED);
}
return r;
} else {
return continuation(rewrite_args, oarg1, oarg2, oarg3, oargs);
}
}
template <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*& oarg1, Box*& oarg2, Box*& oarg3, Box** args, Box** oargs,
const std::vector<BoxedString*>* keyword_names, bool* oargs_owned) {
auto func = [func_name]() { return func_name; };
return rearrangeArgumentsInternal<rewritable>(paramspec, param_names, func, defaults, rewrite_args, rewrite_success,
argspec, oarg1, oarg2, oarg3, args, oargs, keyword_names,
oargs_owned);
}
template void rearrangeArguments<REWRITABLE>(ParamReceiveSpec, const ParamNames*, const char*, Box**,
_CallRewriteArgsBase*, bool&, ArgPassSpec, Box*&, Box*&, Box*&, Box**,
Box**, const std::vector<BoxedString*>*, bool*);
template void rearrangeArguments<NOT_REWRITABLE>(ParamReceiveSpec, const ParamNames*, const char*, Box**,
_CallRewriteArgsBase*, bool&, ArgPassSpec, Box*&, Box*&, Box*&, Box**,
Box**, const std::vector<BoxedString*>*, bool*);
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) {
return rearrangeArgumentsAndCallInternal(paramspec, param_names, func_name, defaults, rewrite_args, argspec, arg1,
arg2, arg3, args, keyword_names, continuation);
}
static StatCounter slowpath_callfunc("slowpath_callfunc");
template <ExceptionStyle S, Rewritable rewritable>
......@@ -4658,50 +4636,57 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
rewrite_args->rewriter->addDependenceOn(func->dependent_ics);
}
Box** oargs = NULL;
bool* oargs_owned = NULL;
bool rewrite_success = false;
int num_output_args = paramspec.totalReceived();
int num_passed_args = argspec.totalPassed();
if (num_output_args > 3) {
int size = (num_output_args - 3) * sizeof(Box*);
oargs = (Box**)alloca(size);
memset(&oargs[0], 0, size);
bool rearrange_rewrite_failed = false;
auto orig_rewrite_args = rewrite_args;
auto continuation = [=, &rearrange_rewrite_failed](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3,
Box** args) {
if (orig_rewrite_args && !rewrite_args)
rearrange_rewrite_failed = true;
oargs_owned = (bool*)alloca((num_output_args - 3) * sizeof(bool));
}
BoxedClosure* closure = func->closure;
try {
auto func_name_cb = [md]() { return getFunctionName(md).data(); };
rearrangeArgumentsInternal<rewritable>(
paramspec, &md->param_names, func_name_cb, paramspec.num_defaults ? func->defaults->elts : NULL,
rewrite_args, rewrite_success, argspec, arg1, arg2, arg3, args, oargs, keyword_names, oargs_owned);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
// special handling for generators:
// the call to function containing a yield should just create a new generator object.
Box* res;
if (md->isGenerator()) {
res = createGenerator(func, arg1, arg2, arg3, args);
if (rewrite_args) {
RewriterVar* r_arg1 = num_output_args >= 1 ? rewrite_args->arg1 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg2 = num_output_args >= 2 ? rewrite_args->arg2 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg3 = num_output_args >= 3 ? rewrite_args->arg3 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_args = num_output_args >= 4 ? rewrite_args->args : rewrite_args->rewriter->loadConst(0);
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)createGenerator, rewrite_args->obj, r_arg1, r_arg2,
r_arg3, r_args)->setType(RefType::OWNED);
if (num_output_args < 1)
arg1 = NULL;
if (num_output_args < 2)
arg2 = NULL;
if (num_output_args < 3)
arg3 = NULL;
AUTO_XDECREF(arg1);
AUTO_XDECREF(arg2);
AUTO_XDECREF(arg3);
AUTO_XDECREF_ARRAY(oargs, num_output_args - 3);
rewrite_args->out_success = true;
}
} else {
res = callCLFunc<S, rewritable>(md, rewrite_args, num_output_args, closure, NULL, func->globals, arg1, arg2,
arg3, args);
}
if (rewrite_args && !rewrite_success) {
// These are the cases that we weren't able to rewrite.
// So instead, just rewrite them to be a call to callFunc, which helps a little bit.
// TODO we should extract the rest of this function from the end of this block,
// put it in a different function, and have the rewrites target that.
return res;
};
Box* r = callCXXFromStyle<S>([&] {
return rearrangeArgumentsAndCallInternal(paramspec, &md->param_names, md,
paramspec.num_defaults ? func->defaults->elts : NULL, rewrite_args,
argspec, arg1, arg2, arg3, args, keyword_names, continuation);
});
if (S == CAPI && !r)
return NULL;
if (rearrange_rewrite_failed) {
// If we weren't able to rewrite, at least rewrite to callFunc, which helps a little bit.
// Only do this if rearrangeArguments was the reason we couldn't rewrite, since it is one
// of the few functions that is careful to not write anything out if it can't rewrite.
//
// TODO we should extract the continuation, put it in a different function, and have the rewrites target that.
// Note(kmod): I tried moving this section to runtimeCallInternal, ie to the place that calls
// callFunc. The thought was that this would let us apply this same optimization to other
......@@ -4760,34 +4745,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
}
}
BoxedClosure* closure = func->closure;
// special handling for generators:
// the call to function containing a yield should just create a new generator object.
Box* res;
if (md->isGenerator()) {
res = createGenerator(func, arg1, arg2, arg3, oargs);
if (rewrite_args) {
RewriterVar* r_arg1 = num_output_args >= 1 ? rewrite_args->arg1 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg2 = num_output_args >= 2 ? rewrite_args->arg2 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg3 = num_output_args >= 3 ? rewrite_args->arg3 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_args = num_output_args >= 4 ? rewrite_args->args : rewrite_args->rewriter->loadConst(0);
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)createGenerator, rewrite_args->obj, r_arg1, r_arg2, r_arg3,
r_args)->setType(RefType::OWNED);
rewrite_args->out_success = true;
}
} else {
res = callCLFunc<S, rewritable>(md, rewrite_args, num_output_args, closure, NULL, func->globals, arg1, arg2,
arg3, oargs);
}
if (rewrite_args && num_output_args > 3)
decrefOargs(rewrite_args->args, oargs_owned, num_output_args - 3);
return res;
return r;
}
template <ExceptionStyle S>
......
......@@ -292,26 +292,28 @@ 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.
using FunctorPointer
= llvm::function_ref<Box*(CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** 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.
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);
// 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.
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,26 @@ 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;
}
return InitHelper::call(made, cls, arg2, arg3);
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);
};
return callCXXFromStyle<S>([&]() {
return rearrangeArgumentsAndCall(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args, argspec,
made, arg2, arg3, args, keyword_names, continuation);
});
}
// If __new__ returns a subclass, supposed to call that subclass's __init__.
......@@ -1343,30 +1318,35 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
assert(tpinit == cls->tp_init);
}
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) {
Py_DECREF(made);
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
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_success)
rewrite_args = NULL;
int err = tpinit(made, arg2, arg3);
assert(arg2->cls == tuple_cls);
assert(!arg3 || arg3->cls == dict_cls);
if (err == -1)
return (Box*)NULL;
if (rewrite_args) {
auto r_err = rewrite_args->rewriter->call(true, (void*)tpinit, r_made, rewrite_args->arg2,
rewrite_args->arg3);
assert(S == CXX && "this need to be converted");
rewrite_args->rewriter->checkAndThrowCAPIException(r_err, -1, assembler::MovType::L);
rewrite_args->out_success = true;
}
return (Box*)1;
};
int err = tpinit(made, arg2, arg3);
Py_DECREF(made);
Py_DECREF(arg2);
Py_XDECREF(arg3);
if (err == -1) {
Box* _t;
try {
_t = rearrangeArgumentsAndCall(ParamReceiveSpec(1, 0, true, true), NULL, "", NULL, rewrite_args,
argspec, made, arg2, arg3, args, keyword_names, continuation);
} catch (ExcInfo e) {
setCAPIException(e);
_t = NULL;
}
if (_t == NULL) {
Py_DECREF(made);
if (S == CAPI)
return NULL;
......@@ -1375,11 +1355,10 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
if (rewrite_args) {
auto r_err
= rewrite_args->rewriter->call(true, (void*)tpinit, r_made, rewrite_args->arg2, rewrite_args->arg3);
assert(S == CXX && "this need to be converted");
rewrite_args->rewriter->checkAndThrowCAPIException(r_err, -1, assembler::MovType::L);
if (!rewrite_args->out_success)
rewrite_args = NULL;
else
rewrite_args->out_success = false;
}
}
} else {
......
......@@ -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;
......@@ -457,6 +422,32 @@ template <typename B> B* xincref(B* b) {
return b;
}
// Helper function: calls a CXX-style function from a templated function. This is more efficient than the
// easier-to-type version:
//
// try {
// return f();
// } catch (ExcInfo e) {
// if (S == CAPI) {
// setCAPIException(e);
// return NULL;
// } else
// throw e;
// }
//
// since this version does not need the try-catch block when called from a CXX-style function
template <ExceptionStyle S, typename Functor> Box* callCXXFromStyle(Functor f) {
if (S == CAPI) {
try {
return f();
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else
return f();
}
//#define DISABLE_INT_FREELIST
extern "C" int PyInt_ClearFreeList() noexcept;
......
# 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