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,26 +3411,9 @@ 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_DECREF(arg1);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
if (!paramspec.takes_kwargs)
arg2 = NULL;
AUTO_XDECREF(arg2);
if (!rewrite_success)
rewrite_args = NULL;
if (rewrite_args) {
if (!paramspec.takes_kwargs)
......@@ -3453,9 +3436,15 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp
}
Box* r = self->cls->tp_call(self, arg1, arg2);
if (!r && S == CXX)
if (S == CXX && !r)
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,20 +553,12 @@ 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;
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
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
......@@ -587,14 +579,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
return (Box*)NULL;
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "getattr(): attribute name must be string");
return NULL;
return (Box*)NULL;
} else
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
......@@ -651,6 +644,12 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
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,15 +687,7 @@ 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);
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
Box* obj = arg1;
Box* _str = arg2;
......@@ -720,14 +711,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
}
_str = coerceUnicodeToStr<S>(_str);
if (S == CAPI && !_str)
return NULL;
return (Box*)NULL;
if (!PyString_Check(_str)) {
Py_DECREF(_str);
if (S == CAPI) {
PyErr_SetString(TypeError, "hasattr(): attribute name must be string");
return NULL;
return (Box*)NULL;
} else
raiseExcHelper(TypeError, "hasattr(): attribute name must be string");
}
......@@ -779,6 +771,12 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
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,15 +1797,7 @@ 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;
auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) {
RewriterVar* r_passthrough = NULL;
if (rewrite_args)
r_passthrough = rewrite_args->rewriter->loadConst((intptr_t)self->passthrough, Location::forArg(0));
......@@ -1814,12 +1806,13 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa
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);
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->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);
......@@ -1831,8 +1824,8 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa
} 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);
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);
......@@ -1872,10 +1865,14 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa
rewrite_args->out_success = true;
}
if (!rtn)
if (S == CXX && !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,15 +318,7 @@ 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;
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))
......@@ -343,8 +326,9 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
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());
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) {
......@@ -368,7 +352,8 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
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->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)) {
{
......@@ -385,12 +370,13 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
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->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);
rtn = ((Box * (*)(Box*, Box*, Box*, Box**))self->method->ml_meth)(arg1, arg2, arg3, args);
}
if (rewrite_args) {
if (paramspec.totalReceived() == 2)
......@@ -416,16 +402,18 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A
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;
}
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,19 +634,11 @@ 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_DECREF_ARGS(paramspec, arg1, arg2, arg3, oargs);
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);
if (!rewrite_success)
rewrite_args = NULL;
#endif
Box* rtn;
if (flags == PyWrapperFlag_KEYWORDS) {
......@@ -667,7 +647,8 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wk, rewrite_args->arg1, rewrite_args->arg2,
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);
......@@ -678,7 +659,8 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
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);
......@@ -690,7 +672,8 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1,
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);
......@@ -701,7 +684,8 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
if (rewrite_args) {
auto rewriter = rewrite_args->rewriter;
rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2,
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);
......@@ -711,9 +695,15 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args,
RELEASE_ASSERT(0, "%d", flags);
}
if (!rtn)
if (S == CXX && !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);
int numArgs = function->md->numReceivedArgs();
if (numArgs > 0)
Py_XINCREF(arg1);
if (numArgs > 1)
Py_XINCREF(arg2);
if (numArgs > 2)
Py_XINCREF(arg3);
int numArgs = function->md->numReceivedArgs();
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);
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);
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,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);
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);
decrefOargs(rewrite_args->args, oargs_owned, 1);
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);
rewrite_args->out_success = true;
}
return unicodeNewHelper(cls, arg2, arg3, oargs);
return unicodeNewHelper(static_cast<BoxedClass*>(arg1), arg2, arg3, args);
};
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,18 +863,9 @@ 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
......@@ -891,6 +875,9 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
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,6 +1200,9 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
}
};
// 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);
......@@ -1245,6 +1214,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
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;
}
if (!rewrite_success)
rewrite_args = NULL;
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);
Py_DECREF(made);
Py_DECREF(arg2);
Py_XDECREF(arg3);
if (err == -1) {
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;
};
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