Skip to content

Conversation

@cocolato
Copy link
Contributor

@cocolato cocolato commented Feb 3, 2026

Split RETURN_VALUE and YIELD_VALUE into macro form with a new _MAKE_HEAP_SAFE micro-op, so the tier2 optimizer can eliminate unnecessary PyStackRef_MakeHeapSafe() calls when the value is already heap-safe (owned or immortal).

@markshannon markshannon changed the title gh-144388: Add new uop _RETURN_VALUE_HEAP_SAFE to avoid refcount operation gh-144540: Add new uop _RETURN_VALUE_HEAP_SAFE to avoid refcount operation Feb 6, 2026
@markshannon
Copy link
Member

@cocolato in future can you avoid referencing the meta-issue in PRs. Make a new issue if you need to. I've done that for this PR already.

@markshannon
Copy link
Member

The removal of the "heap safe" check can be done for any return and for yields as well.
If we split the instructions into micro-ops it makes the optimizations simpler and more effective.
#144540

@cocolato cocolato changed the title gh-144540: Add new uop _RETURN_VALUE_HEAP_SAFE to avoid refcount operation gh-144540: Split RETURN_VALUE/YIELD_VALUE into _MAKE_HEAP_SAFE + micro-ops Feb 6, 2026
@cocolato cocolato changed the title gh-144540: Split RETURN_VALUE/YIELD_VALUE into _MAKE_HEAP_SAFE + micro-ops Add uop to eliminate unnecessary refcount operations in RETURN_VALUE and YIELD_VALUE Feb 6, 2026
@cocolato cocolato changed the title Add uop to eliminate unnecessary refcount operations in RETURN_VALUE and YIELD_VALUE gh-144540: Add uop to eliminate unnecessary refcount operations in RETURN_VALUE and YIELD_VALUE Feb 6, 2026
@cocolato cocolato changed the title gh-144540: Add uop to eliminate unnecessary refcount operations in RETURN_VALUE and YIELD_VALUE gh-144540: Add _MAKE_HEAP_SAFE uop to eliminate unnecessary refcount operations in RETURN_VALUE and YIELD_VALUE Feb 6, 2026
@cocolato
Copy link
Contributor Author

cocolato commented Feb 6, 2026

@cocolato in future can you avoid referencing the meta-issue in PRs. Make a new issue if you need to. I've done that for this PR already.

Sorry about that, and thanks for letting me know! I've updated the code.

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.

Take care with the negation of predicates. The opposite of "knowing x is true", is "not knowing that x is true", not "knowing that x is false".

Can you add a test case that fails for this PR as written.
Something like:

cond = False
def f(a):
    if cond:
        del a
    return a
def g():
    x = 1
    return f(x)
for _ in range(THRESHOLD):
    g()

g will pass a borrowed reference to f which will then incorrectly return a borrowed reference.


op(_MAKE_HEAP_SAFE, (value -- value)) {
// If the value is not borrowed, or is immortal, it's heap-safe.
if (!PyJitRef_IsBorrowed(value) ||
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is right. PyJitRef_IsBorrowed(value) means that we know that the reference value is borrowed, but !PyJitRef_IsBorrowed(value) merely means that we don't know that it is borrowed, not that we know it isn't borrowed.

I think we can only apply this to immortal values.

@bedevere-app
Copy link

bedevere-app bot commented Feb 9, 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.

@cocolato
Copy link
Contributor Author

cocolato commented Feb 10, 2026

Can you add a test case that fails for this PR as written. Something like:

cond = False
def f(a):
    if cond:
        del a
    return a
def g():
    x = 1
    return f(x)
for _ in range(THRESHOLD):
    g()

In this case, because a is a small int, so it will be optimized by immortal check, I wrote other simple fail test after we only check immortal return values:

def returns_owned(x):
       return x + 1

If this does not meet our expectations, I can add more tests later.

@cocolato
Copy link
Contributor Author

I have made the requested changes; please review again

@bedevere-app
Copy link

bedevere-app bot commented Feb 10, 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 10, 2026 04:28
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.

2 participants