Skip to content

Comments

gh-143414: Implement unique reference tracking for JIT, optimize unpacking of such tuples#144300

Open
reidenong wants to merge 28 commits intopython:mainfrom
reidenong:branch-unique-reference-tracking
Open

gh-143414: Implement unique reference tracking for JIT, optimize unpacking of such tuples#144300
reidenong wants to merge 28 commits intopython:mainfrom
reidenong:branch-unique-reference-tracking

Conversation

@reidenong
Copy link
Contributor

@reidenong reidenong commented Jan 28, 2026

  1. Implements unique reference tracking to references in the JIT Optimizer.
  2. Uses the unique reference tracking to eliminate unnecessary reference counting for uniquely referenced tuples. ex:
x, y, z = f()

Some notes:

  • Only implements the unique reference tracking (and relevant optimization) for tuples in _BUILD_TUPLE, to be extended to other objects in the future
  • Objects are deemed as not uniquely referenced when they are made aliases or duplicated, in uops of _LOAD_FAST_* and _COPY.

Would appreciate any feedback.
Thanks

@reidenong
Copy link
Contributor Author

reidenong commented Jan 28, 2026

Discussed with @Fidget-Spinner, will reopen the PR after implementing PyStackRef_CLOSE_SPECIALIZED for _UNPACK_SEQUENCE_UNIQUE_TUPLE

@reidenong reidenong marked this pull request as draft January 28, 2026 18:38
@reidenong reidenong marked this pull request as ready for review January 29, 2026 11:04
@Fidget-Spinner
Copy link
Member

Windows Ci failure looks possibly related, can you please look into it?

@reidenong reidenong marked this pull request as draft January 31, 2026 06:39
@reidenong reidenong marked this pull request as ready for review January 31, 2026 16:36
Copy link
Member

@Fidget-Spinner Fidget-Spinner left a comment

Choose a reason for hiding this comment

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

This is excellent. Just 2 comments, then I think it's safe to merge.


op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) {
assert(oparg > 0);
bottom = PyJitRef_IsUnique(bottom) ? PyJitRef_StripReferenceInfo(bottom) : bottom;
Copy link
Member

Choose a reason for hiding this comment

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

We only need to strip unique info here, not the borrow info too. This way we still get refcount elimination with the borrow.

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 this is consistent with the code?

If the ref is unique, we remove the unique tag, otherwise we leave it as is. Since a ref cannot be both unique and borrowed at the same time, borrowed/invalid refs will be maintained.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good, thanks!

@bedevere-app
Copy link

bedevere-app bot commented Feb 5, 2026

Thanks for making the requested changes!

@markshannon: please review the changes made to this pull request.

@bedevere-app bedevere-app bot requested a review from markshannon February 5, 2026 13:30
Copy link
Member

@markshannon markshannon left a comment

Choose a reason for hiding this comment

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

I think we should be very conservative in the analysis, and only track references on the evaluation stack. It simplifies the code a bit, and means we don't need to worry about escapes.

FTR, this optimizations is going to be rendered obsolete by #120619 which will eliminate many temporary tuples entirely.
BUILD_TUPLE 2; _RETURN_VALUE; UNPACK 2 -> _RETURN_PAIR

}

op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) {
if (PyJitRef_IsUnique(seq)) {
Copy link
Member

Choose a reason for hiding this comment

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

Do the length check here, and not in the uop at runtime. If we have tracked the uniqueness of the reference, we most likely know the size of the tuple

assert(oparg == 2);
PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq);
assert(PyTuple_CheckExact(seq_o));
DEOPT_IF(PyTuple_GET_SIZE(seq_o) != 2);
Copy link
Member

Choose a reason for hiding this comment

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

Do this check in the optimizer

PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq);
assert(PyTuple_CheckExact(seq_o));
assert(PyTuple_GET_SIZE(seq_o) == oparg);
DEOPT_IF(!_PyObject_IsUniquelyReferenced(seq_o));
Copy link
Member

Choose a reason for hiding this comment

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

If we only track references on the evaluation stack, then there is no need for this check as the reference cannot escape.

As soon as a value is stored in a local, it is unlikely to only have one reference to it when we actually use it.
Only tracking references on the stack means we don't need to worry about the various forms of LOAD_FAST, just STORE_FAST.

@bedevere-app
Copy link

bedevere-app bot commented Feb 6, 2026

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@reidenong
Copy link
Contributor Author

Thanks for the explanation on only tracking references on the stack. Since we remove uniqueness on STORE_FAST, I'm wondering if it is still necessary to perform PyJitRef_RemoveUnique on each LOAD_FAST*?

I have made the requested changes; please review again.

@bedevere-app
Copy link

bedevere-app bot commented Feb 6, 2026

Thanks for making the requested changes!

@markshannon: please review the changes made to this pull request.

@bedevere-app bedevere-app bot requested a review from markshannon February 6, 2026 14:29
@Fidget-Spinner
Copy link
Member

wondering if it is still necessary to perform PyJitRef_RemoveUnique on each LOAD_FAST*?

Probably not.

@reidenong
Copy link
Contributor Author

@markshannon Hi hope you're well, I’ve implemented the suggested changes, could you please let me know if everything looks good, or if there’s anything further I should adjust? Specifically I suspect PyJitRef_RemoveUnique on LOAD_FAST* is redundant but would like some confirmation on the matter.

Thanks!

Copy link
Member

@markshannon markshannon left a comment

Choose a reason for hiding this comment

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

Just two places where uniqueness removals should be asserts, as the ref should not be unique at that point. Otherwise, this looks good.

if (sym_is_null(value)) {
ctx->done = true;
}
value = PyJitRef_RemoveUnique(value);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
value = PyJitRef_RemoveUnique(value);
assert(!PyJitRef_IsUnique(value));

Any ref stored in a local should not be treated as unique


op(_LOAD_FAST, (-- value)) {
value = GETLOCAL(oparg);
value = PyJitRef_RemoveUnique(value);
Copy link
Member

Choose a reason for hiding this comment

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

Likewise

@bedevere-app
Copy link

bedevere-app bot commented Feb 20, 2026

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@reidenong
Copy link
Contributor Author

I have made the requested changes; please review again. Thanks!

@bedevere-app
Copy link

bedevere-app bot commented Feb 21, 2026

Thanks for making the requested changes!

@markshannon: please review the changes made to this pull request.

@bedevere-app bedevere-app bot requested a review from markshannon February 21, 2026 05:18
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.

4 participants