PyLongObject: just use GMP?

To answer @tim.one ‘s questions about pypy: basically we still use python2’s approach to representing ints. The int/long distinction is still there internally. ints that fit into a machine word are stored (boxed) as one type of representation. For larger ints we use a big integer representation. We use the full 64 bits for small integers (1<<63 does not fit into an int64_t, it’s one too big).

We tried tagging very early on, but the cost of tag checks everwhere turned out not to be worth it. Tagging requires every operation on all objects to have an extra check. Instead, we leaned heavily into having the jit remove allocations for objects with predictable lifetimes. The jit can reason about integers quite effectively, we have a range analysis, a known bits analysis, and plenty of integer optimizations (all checked for correctness by an smt solver at vm build time).

As you also described, we have runtime switchable list storage strategies, that store the content of type homogeneous lists of ints/floats in an unboxed way. This saves allocations when creating the list. Additionally, when iterating over the list we only do a single check of the strategy before the loop to gain knowledge about the types of all the list elements at once.

We also store instance fields in an unboxed way, as long as all the instances of a class store the same type in these fields.

It’s not entirely true that we don’t have a C API. We emulate the cpython one, but it’s not super efficient. The reasons is as was pointed out various times, the internal representation of an int and it’s external one differ.

Anyway, I’m not sure what cpython can learn from this. I guess that getting unboxing into its jit would be good? That you could think about storage strategies for lists? But I suppose both would be quite a way off.

Happy to answer more questions.

5 Likes