Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get some of the limited API working with Py_LIMITED_API defined #5550

Merged
merged 41 commits into from Aug 14, 2023

Conversation

da-woods
Copy link
Contributor

This gets a minimal limited API example working with Py_LIMITED_API defined, and adds a small test to prove it.

This gets a minimal limited API example working with Py_LIMITED_API
defined, and adds a small test to prove it.
if (pos >= PyTuple_GET_SIZE(kwds)) break;
key = PyTuple_GET_ITEM(kwds, pos);
if (pos >= __Pyx_PyTuple_GET_SIZE(kwds)) break;
key = __Pyx_PyTuple_GET_ITEM(kwds, pos);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GET_ITEM call should rather be guarded by SAFE_MACROS and BORROWED_REFS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still thinking about this. In both cases the BORROWED_REFS guard looks hard to implement, and isn't necessary for limited API support (where we allow borrowed refs by default).

So I'd rather just do SAFE_MACROS at this stage.

I've moved __Pyx_PyTuple_GET_SIZE inside SAFE_MACROS but I don't think this is the right solution so may come back and change it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should now be handled (at the cost of some complication)

@@ -414,7 +414,7 @@ static int __Pyx_MergeKeywords(PyObject *kwdict, PyObject *source_mapping) {
// (because it's an old version of CPython or it's not CPython at all),
// then the ..._FASTCALL macros simply alias ..._VARARGS

#define __Pyx_Arg_VARARGS(args, i) PyTuple_GET_ITEM(args, i)
#define __Pyx_Arg_VARARGS(args, i) __Pyx_PyTuple_GET_ITEM(args, i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, we shouldn't unconditionally use the macro.

Cython/Utility/ObjectHandling.c Outdated Show resolved Hide resolved
#else
PyObject *from_bytes, *result;
PyObject *py_bytes = NULL, *arg_tuple = NULL, *kwds = NULL, *order_str = NULL;
from_bytes = PyObject_GetAttrString((PyObject*)&PyInt_Type, "from_bytes");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that looks expensive. But having it work at all is probably still better than having it fail..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the fallback code for "int type is bigger than long long" or "int type is bigger than long and Python doesn't define PY_LONG_LONG". So practically I doubt it gets used much.

But yeah, I expect it's expensive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, PY_LONG_LONG is now always defined in recent CPython versions. I think since back when they switched to C99 or a bit later, when they noticed that their code actually doesn't compile without HAVE_LONG_LONG any more. :)

@da-woods
Copy link
Contributor Author

Closing and re-opening (there's an extra commit that github doesn't seem to have noticed...)

@da-woods da-woods closed this Jul 22, 2023
@da-woods da-woods reopened this Jul 22, 2023
@da-woods da-woods changed the title Get a some of the limited API working with Py_LIMITED_API defined Get some of the limited API working with Py_LIMITED_API defined Jul 23, 2023
#if CYTHON_COMPILING_IN_LIMITED_API
// Note that the limited API doesn't know about PyCodeObject, so the type of this
// is PyObject (unlike for the main API)
static CYTHON_INLINE PyObject* __Pyx_PyCode_New(int a, int p, int k, int l, int s, int f,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also refactored this slightly again, since it used replace and so was also broken on Py3.7. Might be a bit more performant than before, but probably relies on somewhat unstable (Python) API

@aws-taylor
Copy link
Contributor

Two other small ones related to the (non) existence of tp_free in PyTypeObject:

code.putln("(*Py_TYPE(o)->tp_free)(o);")

Reading through https://hg.python.org/cpython/rev/655d7a55c165, it seems like the fix is probably something along the lines of:

code.putln("((freefunc)PyType_GetSlot(Py_TYPE(o), Py_tp_free))(o);")

@da-woods
Copy link
Contributor Author

Two other small ones related to the (non) existence of tp_free in PyTypeObject:

The follow up PR to this will do classes. I'd got the first of those lines. I hadn't got the second, but I'll make sure it add it - thanks

@aws-taylor
Copy link
Contributor

Two other small ones related to the (non) existence of tp_free in PyTypeObject:

The follow up PR to this will do classes. I'd got the first of those lines. I hadn't got the second, but I'll make sure it add it - thanks

Awesome. Thanks again for this change; I'm really hoping this can get out the door. If it wasn't obvious, I'm working through a stack of errors for my own codebase. Let me know if you'd prefer I open tickets as I come across issues or just piggy-back here.

@aws-taylor
Copy link
Contributor

Another 2 I came across related to tp_basicsize:

Unlike tp_free, there doesn't appear to be a slot macro for Py_tp_basicsize. I think this is because under the limited API, there are no built-in types, and thus there are no special types for which sizeof != tp_basicsize. If that's true, then I think the fix may be to simply ignore this clause in the if statement when compiling with the limited API, because it'll always be true. There may also be a fix involving basicsize_builtins_map.

@da-woods
Copy link
Contributor Author

The PyPy failure looks to be a mess up with fused function optional arguments.

The code it's generating is

values[3] = __Pyx_Arg_NEWREF(((PyObject *)((long)((long)2))));

With the __Pyx_Arg_NEWREF being added by this PR, and being the bit that's breaking. However it's plainly wrong even without this PR - it just isn't generating invalid reference counting.

Unfortunately this pretty much blocks this PR until that's sorted I think.

@aws-taylor
Copy link
Contributor

Another 1-liner related to tp_dictoffset:

Per https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_dictoffset, tp_dictoffset is supposed to be considered write-only. I think the fix might be:

if (dictoffset == 0 && PyObject_GenericGetDict(b, NULL) )

@da-woods
Copy link
Contributor Author

Another 1-liner related to tp_dictoffset:

This is already fixed in the follow-up

tp_basicsize

This isn't. It probably isn't too hard - it's already conditional on CYTHON_COMPILING_IN_CPYTHON (which is off with the limited API) - the condition just needs to be moved to exclude the code, rather than being part of the if-statement

@da-woods
Copy link
Contributor Author

Depends on #5614


// Cython uses these constants but they are not available in the limited API.
// (it'd be nice if there was a more robust way of looking these up)
#ifndef CO_OPTIMIZED
Copy link
Contributor Author

@da-woods da-woods Aug 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these would be better read from inspect when the module is initialized (i.e. much like the debug flag) - it feels a bit against the spirit of the limited API to just redefine constants that have been intentionally excluded.

With that said, I'll create an issue when this PR is done rather than try to make too many more changes.

@da-woods da-woods closed this Aug 13, 2023
@da-woods da-woods reopened this Aug 13, 2023
@da-woods da-woods added this to the 3.0.1 milestone Aug 14, 2023
@da-woods da-woods merged commit e1d9c5a into cython:master Aug 14, 2023
75 checks passed
@da-woods da-woods deleted the limited-api-with-py-limited-api branch August 14, 2023 11:35
@da-woods da-woods restored the limited-api-with-py-limited-api branch August 14, 2023 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants