Tagged pointers and fast-pathed CFNumber integers in Lion
Tagged pointers are a new feature in Lion and the OS X v10.7 SDK. They provide an alternative representation of objects based on the fact that not every integer can represent the memory address of an arbitrary Objective-C object since allocators return 16-byte aligned addresses.
In Lion, the Objective-C runtime and Core Foundation tag pointers as follows:
Every tagged pointer has its lowest bit set, hence tagged pointers are odd integers;
The next 3 bits (from lowest to highest) define the tagged object class. At the moment, there are classes for integers, managed objects, and dates;
The next 4 bits are for type information specific to the tagged object class.
Thus the lowest eight bits in the memory address are used as tag metadata, and the remaining 24 or 56 bits are used as payload.
CFNumber (and, consequently,
NSNumber) takes advantage of tagged pointers for integers — if an integer can fit in the payload of a tagged pointer then no actual
CFNumber is created. Instead, the memory address represents the integer number itself according to the following layout:
6 5 4 3 2 1 0 3210987654321098765432109876543210987654321098765432109876543210 ........................................................xxxx0011 | | | +-- (1 bit) always 1 for tagged pointers | | +----- (3 bits) 001 is the tagged object class for integers | +--------- (4 bits) for integers, xxxx is either: | 0000 for 8-bit integers, | 0100 for 16-bit integers, | 1000 for 32-bit integers, | 1100 for 64-bit integers +------------------------------------------------------------------ (56 bits) payload with the actual integer value
Given a tagged pointer, obtaining its underlying integer value is as simple (and fast) as a shift right by 8 bits of data that’s already stored in a register. Preliminary tests by Joshua Weinberg yielded a speedup of 2.42 in both creating
NSNumber objects and reading its integer value.
Since there are no actual
CFNumber/NSNumber objects, there’s no need for memory management.
In order for a tagged pointer to behave as an object, the Objective-C runtime keeps an isa table (
_objc_tagged_isa_table) that maps the four lowest bits of a tagged pointer (effectively, its tagged object class) to the isa pointer that’s expected for Objective-C objects. This table is used by
object_getClass() (and its corresponding private function) so that the correct isa is returned when querying tagged pointers. Note that directly accessing the isa pointer via
->isa will break in this case. Developers should use
Warning: this post is based upon CF-635. It is internal information, and subject to change in future releases.