Skip to content

Avoid creating temporary objects in BINARY_SLICE #144569

Open

Description

@Fidget-Spinner

Feature or enhancement

Proposal:

Currently BINARY_SLICE looks like this:

        op(_BINARY_SLICE, (container, start, stop -- res)) {
            PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start),
                                                        PyStackRef_AsPyObjectSteal(stop));
            PyObject *res_o;
            if (slice == NULL) {
                res_o = NULL;
            }
            else {
                res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice);
                Py_DECREF(slice);
            }
            PyStackRef_CLOSE(container);
            ERROR_IF(res_o == NULL);
            res = PyStackRef_FromPyObjectSteal(res_o);
        }

Note that we build a slice just for getitem, only to throw it away immediately after.

We can scalar replace the slice in BINARY_SLICE after recording the types. If we record the container type, we can call the slice dispatcher underneath directly without boxing the slice object. See for example BINARY_OP_SUBSCR_LIST_SLICE

We'd need to guard on the type recorded.

I propose to do this in the current optimizer pass rather than the partial evaluation pass, as this is just a simple optimization within a single op, while the PE pass can handle inter-instruction optimization.

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

Linked PRs

Activity

  1. Fidget-Spinner commented on Feb 7, 2026

    @Fidget-Spinner
    MemberAuthor

    @cocolato would you like to take this up? It should be a single peephole optimization so there isn't an issue about correctness. I can guide you on how to do it if you need help.

    Pinging @markshannon. Since this is a single peephole optimization affecting a single instruction, I strongly feel it should be done in the current optimizer pass rather than the PE pass.

  2. cocolato commented on Feb 7, 2026

    @cocolato
    Member

    @cocolato would you like to take this up? It should be a single peephole optimization so there isn't an issue about correctness. I can guide you on how to do it if you need help.

    Sure, I'd like to work on this. Thanks for reaching out!

  3. Fidget-Spinner commented on Feb 7, 2026

    @Fidget-Spinner
    MemberAuthor

    @cocolato btw, I sent you an email!

  4. changed the title [-]Scalar replacement of BINARY_SLICE[/-] [+]Avoid creating temporary objects in BINARY_SLICE[/+] on Feb 9, 2026
  5. markshannon commented on Feb 9, 2026

    @markshannon
    Member

    I wouldn't describe this as "scalar replacement". We just want to avoid creating the temporary object within the one instruction.

    One other thing that should be done to make this work well:
    In the AST optimizer, 2-slices are converted to constants, which prevents this optimization working as well as it should.

    def f(s):
        return s[:1]

    is compiled to:

      LOAD_FAST_BORROW    s
      LOAD_CONST          slice(None, 1, None)
      BINARY_OP           []
      RETURN_VALUE
    

    but is should be compiled to:

      LOAD_FAST_BORROW    s
      LOAD_CONST          None
      LOAD_SMALL_INT      1
      BINARY_SLICE
      RETURN_VALUE
    

    But take care to still convert 3-slices to constants:
    The slice [::-1] should still be constant folded.

  6. markshannon commented on Feb 9, 2026

    @markshannon
    Member

    In fact, it might be worth optimizing for the two constant slices [:] and [::-1] as they are common idioms for copy and reverse.

  7. cocolato commented on Feb 10, 2026

    @cocolato
    Member

    One other thing that should be done to make this work well:
    In the AST optimizer, 2-slices are converted to constants, which prevents this optimization working as well as it should.

    I think this would degrade Tier 1 performance. Do we really need to remove the constant optimization for 2-slices?

  8. added a commit that references this issue on Mar 2, 2026
  9. added a commit that references this issue on Apr 25, 2026
  10. koxudaxi commented on Aug 24, 2026

    @koxudaxi
    Contributor

    I'm looking at adding the same BINARY_SLICE fast path for exact bytes as a follow-up to gh-144590.

    @cocolato, are you already working on this, or would you mind if I open a PR?

  11. cocolato commented on Aug 24, 2026

    @cocolato
    Member

    @cocolato, are you already working on this, or would you mind if I open a PR?

    Sure, feel free to open a PR :)

  12. koxudaxi commented on Aug 24, 2026

    @koxudaxi
    Contributor

    Thanks! I opened #156318.

  13. added 2 commits that reference this issue on Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)topic-JITtype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions