Skip to main content

Module small_int

Module small_int 

Source
Expand description

The interned small-Int range (§4.3).

§4.3’s uniform object model is normative “even if later optimizations intern small integers, use tagged pointers, or eliminate allocations through escape analysis” — provided such an optimization “preserves reference and aliasing semantics”. For Int there are none to preserve, and the language already ships the existence proof: Unit and Bool are interned singletons, so every true in every program is one object (crate::immortal::Immortals).

Why sharing an Int is unobservable. There is no identity operator in the language — praxis_hir’s BinOp is arithmetic, comparison and the two logical connectives, and nothing else. == on Int lowers to Inst::IntCmp over extracted payloads; the structural fallback praxis_struct_eq has no pointer fast path either. Map/Set/Counter keys go through DynamicKey, whose eq does open with a pointer comparison — but that is a fast path for structural equality, and int_equals is reflexive, so sharing an object can only make it fire more often, never change the answer. And an Int payload is never written after its allocation: Inst::StoreScalar has no builder site and the backend’s arm for it is a documented no-op.

Why not Float or Text. Float fails the reflexivity argument that carries DynamicKey’s fast path — float_equals is IEEE, so NaN ≠ NaN — and interning it would make two separately-written NaN literals compare equal as map keys. Text fails a different test: TextPayload::Owned(OwnedText) is not Copy, and Heap::alloc_immortal requires Copy because an immortal is invisible to Heap’s Drop — an immortal Text would leak its Box<str> at teardown.

Char passes every leg of the argument above, and crate::small_char is the second interned scalar range (ADR-107): char_equals is a reflexive u32 ==, a CharPayload is Copy, and ASCII is a bounded set. It is a separate module rather than a second constant here because the two ranges have different consumers — this one is read by three crates and by generated code, and that one only by the runtime.

This module is the one statement of the range. praxis-mir asks index_of whether a literal is in range at compile time and praxis-runtime asks it again at run time; the Cranelift backend derives the element offset from the same SMALL_INT_MIN. A second spelling of the bounds anywhere would let the compiler emit a table read for a value the table does not hold.

Constants§

INLINE_INTERN_SITE
Everything the Cranelift backend bakes in to answer an in-range Int inline, as one value (ADR-113).
SMALL_INT_COUNT
How many Ints the table holds — the length of Immortals::small_ints and the bound every index derived from index_of respects.
SMALL_INT_MAX
The highest Int the runtime interns.
SMALL_INT_MIN
The lowest Int the runtime interns.
SMALL_INT_STRIDE
The size of one table element, for the backend’s element-offset arithmetic.

Functions§

index_of
v’s index in the interned table, or None if v is outside the range.