Commit 5a6a15cf authored by Kevin Modzelewski's avatar Kevin Modzelewski

Allow capi calls through typecallinner

note: people need to `find -name '*.pyston.so' -delete`, since although
I think we correctly know to try to rebuild the sharedmodules,
distutils won't end up rebuilding it.
parent 324397a3
...@@ -960,7 +960,7 @@ static Box* _intNew(Box* val, Box* base) { ...@@ -960,7 +960,7 @@ static Box* _intNew(Box* val, Box* base) {
raiseExcHelper(TypeError, ""); raiseExcHelper(TypeError, "");
} }
if (!isSubclass(r->cls, int_cls) && !isSubclass(r->cls, long_cls)) { if (!PyInt_Check(r) && !PyLong_Check(r)) {
raiseExcHelper(TypeError, "__int__ returned non-int (type %s)", r->cls->tp_name); raiseExcHelper(TypeError, "__int__ returned non-int (type %s)", r->cls->tp_name);
} }
return r; return r;
......
...@@ -599,22 +599,13 @@ extern "C" CLFunction* unboxCLFunction(Box* b) { ...@@ -599,22 +599,13 @@ extern "C" CLFunction* unboxCLFunction(Box* b) {
return static_cast<BoxedFunction*>(b)->f; return static_cast<BoxedFunction*>(b)->f;
} }
template <ExceptionStyle S>
static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names); Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
template <ExceptionStyle S> template <ExceptionStyle S>
static Box* typeTppCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* typeTppCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI) { Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI) {
if (S == CAPI) {
try {
return typeTppCall<CXX>(self, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
assert(S == CXX);
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
if (argspec.has_starargs || argspec.has_kwargs) { if (argspec.has_starargs || argspec.has_kwargs) {
...@@ -636,7 +627,7 @@ static Box* typeTppCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -636,7 +627,7 @@ static Box* typeTppCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSpec ar
ArgPassSpec new_argspec ArgPassSpec new_argspec
= bindObjIntoArgs(self, r_bind_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args); = bindObjIntoArgs(self, r_bind_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args);
return typeCallInner(rewrite_args, new_argspec, arg1, arg2, arg3, new_args, keyword_names); return typeCallInner<S>(rewrite_args, new_argspec, arg1, arg2, arg3, new_args, keyword_names);
} }
static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1,
...@@ -653,7 +644,7 @@ static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args ...@@ -653,7 +644,7 @@ static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args
return callFunc<CXX>(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); return callFunc<CXX>(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} }
return typeCallInner(rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); return typeCallInner<CXX>(rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} }
// For use on __init__ return values // For use on __init__ return values
...@@ -720,8 +711,20 @@ static Box* unicodeNewHelper(BoxedClass* type, Box* string, Box* encoding_obj, B ...@@ -720,8 +711,20 @@ static Box* unicodeNewHelper(BoxedClass* type, Box* string, Box* encoding_obj, B
return r; return r;
} }
static Box* objectNewNoArgs(BoxedClass* cls) noexcept {
assert(isSubclass(cls->cls, type_cls));
#ifndef NDEBUG
static BoxedString* new_str = internStringImmortal("__new__");
static BoxedString* init_str = internStringImmortal("__init__");
assert(typeLookup(cls, new_str, NULL) == typeLookup(object_cls, new_str, NULL)
&& typeLookup(cls, init_str, NULL) != typeLookup(object_cls, init_str, NULL));
#endif
return new (cls) Box();
}
template <ExceptionStyle S>
static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names) { Box** args, const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI) {
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
int npositional = argspec.num_args; int npositional = argspec.num_args;
...@@ -730,16 +733,22 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -730,16 +733,22 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
Box* _cls = arg1; Box* _cls = arg1;
if (!isSubclass(_cls->cls, type_cls)) { if (!isSubclass(_cls->cls, type_cls)) {
raiseExcHelper(TypeError, "descriptor '__call__' requires a 'type' object but received an '%s'", if (S == CAPI)
getTypeName(_cls)); PyErr_Format(TypeError, "descriptor '__call__' requires a 'type' object but received an '%s'",
getTypeName(_cls));
else
raiseExcHelper(TypeError, "descriptor '__call__' requires a 'type' object but received an '%s'",
getTypeName(_cls));
} }
BoxedClass* cls = static_cast<BoxedClass*>(_cls); BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (cls == unicode_cls && !argspec.has_kwargs && !argspec.has_starargs if (cls == unicode_cls && !argspec.has_kwargs && !argspec.has_starargs
&& (argspec.num_args == 1 || (argspec.num_args == 2 && arg2->cls == str_cls))) { && (argspec.num_args == 1 || (argspec.num_args == 2 && arg2->cls == str_cls)) && S == CXX) {
// unicode() takes an "encoding" parameter which can cause the constructor to return unicode subclasses. // unicode() takes an "encoding" parameter which can cause the constructor to return unicode subclasses.
assert(S == CXX && "implement me");
if (rewrite_args) { if (rewrite_args) {
rewrite_args->arg1->addGuard((intptr_t)cls); rewrite_args->arg1->addGuard((intptr_t)cls);
if (argspec.num_args >= 2) if (argspec.num_args >= 2)
...@@ -772,10 +781,13 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -772,10 +781,13 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
return unicodeNewHelper(cls, oarg2, oarg3, oargs); return unicodeNewHelper(cls, oarg2, oarg3, oargs);
} }
if (cls->tp_new != object_cls->tp_new && cls->tp_new != slot_tp_new) { if (cls->tp_new != object_cls->tp_new && cls->tp_new != slot_tp_new && S == CXX) {
// Looks like we're calling an extension class and we're not going to be able to // Looks like we're calling an extension class and we're not going to be able to
// separately rewrite the new + init calls. But we can rewrite the fact that we // separately rewrite the new + init calls. But we can rewrite the fact that we
// should just call the cpython version, which will end up working pretty well. // should just call the cpython version, which will end up working pretty well.
assert(S == CXX && "implement me");
ParamReceiveSpec paramspec(1, false, true, true); ParamReceiveSpec paramspec(1, false, true, true);
bool rewrite_success = false; bool rewrite_success = false;
Box* oarg1, *oarg2, *oarg3, ** oargs = NULL; Box* oarg1, *oarg2, *oarg3, ** oargs = NULL;
...@@ -848,15 +860,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -848,15 +860,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// Special-case functions to allow them to still rewrite: // Special-case functions to allow them to still rewrite:
if (new_attr->cls != function_cls) { if (new_attr->cls != function_cls) {
Box* descr_r = processDescriptorOrNull(new_attr, None, cls); try {
if (descr_r) { Box* descr_r = processDescriptorOrNull(new_attr, None, cls);
new_attr = descr_r; if (descr_r) {
rewrite_args = NULL; new_attr = descr_r;
rewrite_args = NULL;
}
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
} }
} }
} else { } else {
new_attr = typeLookup(cls, new_str, NULL); new_attr = typeLookup(cls, new_str, NULL);
new_attr = processDescriptor(new_attr, None, cls); try {
new_attr = processDescriptor(new_attr, None, cls);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
} }
assert(new_attr && "This should always resolve"); assert(new_attr && "This should always resolve");
...@@ -895,7 +923,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -895,7 +923,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
if (allowable_news.empty()) { if (allowable_news.empty()) {
for (BoxedClass* allowed_cls : { object_cls, enumerate_cls, xrange_cls, tuple_cls, list_cls, dict_cls }) { for (BoxedClass* allowed_cls : { object_cls, enumerate_cls, xrange_cls, tuple_cls, list_cls, dict_cls }) {
auto new_obj = typeLookup(allowed_cls, new_str, NULL); auto new_obj = typeLookup(allowed_cls, new_str, NULL);
gc::registerPermanentRoot(new_obj); gc::registerPermanentRoot(new_obj, /* allow_duplicates= */ true);
allowable_news.push_back(new_obj); allowable_news.push_back(new_obj);
} }
} }
...@@ -982,6 +1010,20 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -982,6 +1010,20 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
ArgPassSpec new_argspec = argspec; ArgPassSpec new_argspec = argspec;
if (S == CAPI && cls->tp_new != object_cls->tp_new && cls->tp_init != object_cls->tp_init) {
// If there's a custom new and custom init, in CAPI mode we don't have any way of handling
// any exceptions thrown by the new.
rewrite_args = NULL;
}
if (S == CAPI && cls->tp_init != object_cls->tp_init) {
// If there's a custom init, in CAPI mode we don't have any way of handling the exception that
// we assertInitNone might have to throw from the init returning non-None.
// TODO actually looks we only have to be doing that check for Python-level objects; ie in CPython
// that check is done in slot_tp_init
rewrite_args = NULL;
}
if (rewrite_args) { if (rewrite_args) {
if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init) { if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init) {
// Fast case: if we are calling object_new, we normally doesn't look at the arguments at all. // Fast case: if we are calling object_new, we normally doesn't look at the arguments at all.
...@@ -992,6 +1034,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -992,6 +1034,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// a custom internal callable to object.__new__ // a custom internal callable to object.__new__
made = objectNewNoArgs(cls); made = objectNewNoArgs(cls);
r_made = rewrite_args->rewriter->call(true, (void*)objectNewNoArgs, r_ccls); r_made = rewrite_args->rewriter->call(true, (void*)objectNewNoArgs, r_ccls);
assert(made);
} else { } else {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_new, rewrite_args->destination); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_new, rewrite_args->destination);
srewrite_args.args_guarded = rewrite_args->args_guarded; srewrite_args.args_guarded = rewrite_args->args_guarded;
...@@ -1008,8 +1051,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1008,8 +1051,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
if (new_npassed_args >= 4) if (new_npassed_args >= 4)
srewrite_args.args = rewrite_args->args; srewrite_args.args = rewrite_args->args;
made made = runtimeCallInternal<S>(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names);
= runtimeCallInternal<CXX>(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names); if (!made) {
assert(S == CAPI);
return NULL;
}
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1023,10 +1069,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1023,10 +1069,16 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
"We should only have allowed the rewrite to continue if we were guaranteed that made " "We should only have allowed the rewrite to continue if we were guaranteed that made "
"would have class cls!"); "would have class cls!");
} else { } else {
if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init) if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init) {
made = objectNewNoArgs(cls); made = objectNewNoArgs(cls);
else assert(made);
made = runtimeCallInternal<CXX>(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names); } else
made = runtimeCallInternal<S>(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names);
if (!made) {
assert(S == CAPI);
return NULL;
}
} }
assert(made); assert(made);
...@@ -1076,18 +1128,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1076,18 +1128,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// initrtn = callattrInternal<CXX>(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, // initrtn = callattrInternal<CXX>(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3,
// args, keyword_names); // args, keyword_names);
initrtn initrtn = runtimeCallInternal<S>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
= runtimeCallInternal<CXX>(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names);
if (!initrtn) {
assert(S == CAPI);
return NULL;
}
if (!srewrite_args.out_success) { if (!srewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
assert(S == CXX && "this need to be converted");
rewrite_args->rewriter->call(true, (void*)assertInitNone, srewrite_args.out_rtn); rewrite_args->rewriter->call(true, (void*)assertInitNone, srewrite_args.out_rtn);
} }
} else { } else {
rewrite_args = NULL; rewrite_args = NULL;
init_attr = processDescriptor(init_attr, made, cls); try {
init_attr = processDescriptor(init_attr, made, cls);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
ArgPassSpec init_argspec = argspec; ArgPassSpec init_argspec = argspec;
init_argspec.num_args--; init_argspec.num_args--;
...@@ -1096,17 +1161,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1096,17 +1161,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
// If we weren't passed the args array, it's not safe to index into it // If we weren't passed the args array, it's not safe to index into it
if (passed <= 2) if (passed <= 2)
initrtn initrtn = runtimeCallInternal<S>(init_attr, NULL, init_argspec, arg2, arg3, NULL, NULL, keyword_names);
= runtimeCallInternal<CXX>(init_attr, NULL, init_argspec, arg2, arg3, NULL, NULL, keyword_names);
else else
initrtn = runtimeCallInternal<CXX>(init_attr, NULL, init_argspec, arg2, arg3, args[0], &args[1], initrtn = runtimeCallInternal<S>(init_attr, NULL, init_argspec, arg2, arg3, args[0], &args[1],
keyword_names); keyword_names);
if (!initrtn) {
assert(S == CAPI);
return NULL;
}
}
assert(initrtn);
if (S == CAPI && initrtn != None) {
PyErr_Format(TypeError, "__init__() should return None, not '%s'", getTypeName(initrtn));
return NULL;
} }
assertInitNone(initrtn); assertInitNone(initrtn);
} else { } else {
if (new_attr == NULL && npassed_args != 1) { if (new_attr == NULL && npassed_args != 1) {
// TODO not npassed args, since the starargs or kwargs could be null // TODO not npassed args, since the starargs or kwargs could be null
raiseExcHelper(TypeError, objectNewParameterTypeErrorMsg()); if (S == CAPI) {
PyErr_SetString(TypeError, objectNewParameterTypeErrorMsg());
return NULL;
} else
raiseExcHelper(TypeError, objectNewParameterTypeErrorMsg());
} }
} }
...@@ -1115,6 +1194,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1115,6 +1194,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
assert(made);
return made; return made;
} }
...@@ -2405,17 +2485,6 @@ void attrwrapperDel(Box* b, llvm::StringRef attr) { ...@@ -2405,17 +2485,6 @@ void attrwrapperDel(Box* b, llvm::StringRef attr) {
AttrWrapper::delitem(b, boxString(attr)); AttrWrapper::delitem(b, boxString(attr));
} }
Box* objectNewNoArgs(BoxedClass* cls) {
assert(isSubclass(cls->cls, type_cls));
#ifndef NDEBUG
static BoxedString* new_str = internStringImmortal("__new__");
static BoxedString* init_str = internStringImmortal("__init__");
assert(typeLookup(cls, new_str, NULL) == typeLookup(object_cls, new_str, NULL)
&& typeLookup(cls, init_str, NULL) != typeLookup(object_cls, init_str, NULL));
#endif
return new (cls) Box();
}
static int excess_args(PyObject* args, PyObject* kwds) noexcept { static int excess_args(PyObject* args, PyObject* kwds) noexcept {
return PyTuple_GET_SIZE(args) || (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)); return PyTuple_GET_SIZE(args) || (kwds && PyDict_Check(kwds) && PyDict_Size(kwds));
} }
......
...@@ -1007,7 +1007,6 @@ public: ...@@ -1007,7 +1007,6 @@ public:
static void gcHandler(GCVisitor* v, Box* _o); static void gcHandler(GCVisitor* v, Box* _o);
}; };
Box* objectNewNoArgs(BoxedClass* cls);
Box* objectSetattr(Box* obj, Box* attr, Box* value); Box* objectSetattr(Box* obj, Box* attr, Box* value);
Box* unwrapAttrWrapper(Box* b); Box* unwrapAttrWrapper(Box* b);
......
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