Skip to content

TypedPython: native ints in impure functions, with in-place promotion on overflow #232

Open

Description

@b-re-w

Found while measuring #150: compiling an impure function whose loops do only object operations is slower than CPython 3.15's specialising interpreter. wordfreq's word_of takes 248.6 ms compiled against 95.7 ms interpreted, and the whole benchmark drops from 1.1x to 0.8x of CPython (compiled/develop 1.335). Interim fix in #150: such functions stay interpreted (cost rule).

Why it is slow. In an impure function an int local is a CPython object, so every iteration does three things:

  • boxes constants;
  • calls generic PyNumber_*/PyObject_RichCompare;
  • looks up globals and builtins through dict lookups.

The interpreter's BINARY_OP_ADD_INT, LOAD_GLOBAL_BUILTIN caches and small-int cache beat that.

The real fix:

  1. Keep int locals of impure functions as native i64 and box only at object boundaries.
    • Hard part: an impure function cannot deopt after an effect. On i64 overflow it must promote to object arithmetic in place, carrying the value as a PyLong for the rest of that variable's live range, with the same results as CPython.
  2. Pre-box constants once, in module state.
  3. Cache global and builtin lookups behind the existing dict-watcher epoch, instead of a dict lookup per use. This also removes the per-call creation of the "builtins" string.

Done when: wordfreq's word_of and main compile without the cost rule rejecting them, are faster than the interpreter (interleaved, quiet window), and overflow tests at the i64 boundary in impure functions match CPython.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions