# How MulleObjC Handles C Pointers and Integer Datatypes: Atomic Storage and Tagged Pointers

> Discover how MulleObjC leverages atomic storage and tagged pointers for C pointers and integer datatypes, storing scalars directly in pointer addresses for efficient lock-free operations.

- Repository: [mulle-objc/mulleobjc](https://github.com/mulle-objc/mulleobjc)
- Tags: deep-dive
- Published: 2026-03-07

---

**MulleObjC treats C pointers and Objective-C integer primitives as atomic, first-class values using lock-free compare-and-swap operations and tagged-pointer encoding to store scalars directly within pointer addresses.**

The mulle-objc/mulleobjc runtime diverges from traditional Objective-C implementations by treating `NSInteger`, `NSUInteger`, and C pointers as fundamental value types that support atomic operations and pointer-embedding optimizations. This design eliminates heap allocations for small scalars while guaranteeing thread-safe access to integer instance variables without locks.

## Atomic Storage for Integer Datatypes

MulleObjC wraps integer primitives in atomic pointer containers, enabling lock-free concurrent access to numeric state.

### NSIntegerAtomic and NSUIntegerAtomic Unions

In [`src/MulleObjCIntegralType.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/MulleObjCIntegralType.h), the runtime defines `NSIntegerAtomic` and `NSUIntegerAtomic` as unions containing a `mulle_atomic_pointer_t`. These unions allow the runtime to store integer values within atomic pointer storage cells. The definition appears at lines 33-44, where the union overlays an integer value with the atomic pointer type, ensuring that integer instance variables occupy the same memory layout as object pointers.

Atomic accessor helpers are implemented at lines 49-88 of the same file. The `NSIntegerAtomicSet` and `NSIntegerAtomicGet` functions translate integer values to and from the atomic pointer container, while `NSIntegerAtomicUpdate` and `NSUIntegerAtomicUpdate` perform compare-and-swap loops to modify values atomically and return the previous state.

### Lock-Free Thread Safety with mulle_atomic_pointer_t

The runtime guarantees thread-safe integer updates by leveraging `_mulle_atomic_pointer_read` for atomic loads and `_mulle_atomic_pointer_cas` (compare-and-swap) for atomic stores. When updating an atomic integer property, `NSIntegerAtomicUpdate` executes a CAS loop that retries until the operation succeeds, eliminating the need for mutex locks or `@synchronize` blocks.

This mechanism is utilized throughout the class hierarchy. For example, [`src/class/NSThread.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSThread.h) and [`src/class/NSRecursiveLock-Private.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSRecursiveLock-Private.h) employ these atomic pointer reads for thread-related state management, while [`src/function/MulleObjCProperty.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCProperty.h) implements `_MulleObjCAcquirePointerAtomically` using the same primitives.

## Tagged Pointers for Scalar Values

MulleObjC implements tagged pointers to encode small scalar values—signed integers, unsigned integers, floats, and doubles—directly into the lower bits of a pointer address, avoiding heap allocation.

### Validity Checks for Small Integer Encoding

Before encoding a value as a tagged pointer, the runtime validates whether the scalar fits within the architecture-specific bit limits reserved for data. In [`src/protocol/MulleObjCTaggedPointer.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/MulleObjCTaggedPointer.h) (lines 81-92), the functions `MulleObjCTaggedPointerIsIntegerValue`, `MulleObjCTaggedPointerIsUnsignedIntegerValue`, `MulleObjCTaggedPointerIsFloatValue`, and `MulleObjCTaggedPointerIsDoubleValue` perform these bounds checks. If the value exceeds the storable range, the runtime falls back to standard heap allocation.

### Creating and Extracting Tagged Pointers

Creation functions at lines 111-144 of [`src/protocol/MulleObjCTaggedPointer.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/MulleObjCTaggedPointer.h) implement the encoding logic. `MulleObjCCreateTaggedPointerWithIntegerValueAndIndex` and its variants call runtime helpers such as `mulle_objc_create_integer_taggedpointer` to embed both the scalar value and a class index into the pointer address.

Extraction functions at lines 148-176 reverse this process. `MulleObjCTaggedPointerGetIntegerValue`, `MulleObjCTaggedPointerGetUnsignedIntegerValue`, and their float/double counterparts invoke `mulle_objc_taggedpointer_get_integer_value` to retrieve the original scalar from the pointer's payload bits.

### Class Index Routing

At lines 178-183 of [`src/protocol/MulleObjCTaggedPointer.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/MulleObjCTaggedPointer.h), `MulleObjCTaggedPointerGetIndex` extracts the class index stored within the tagged pointer. The runtime uses this index to route messages to the correct class methods, allowing tagged pointers to behave polymorphically like full objects while maintaining the performance characteristics of immediate values.

## Practical Implementation Examples

The following patterns demonstrate concrete usage of atomic integers and tagged pointers in MulleObjC code:

```c
/* Atomic integer storage and retrieval */
#include "MulleObjCIntegralType.h"

NSIntegerAtomic myInt;
NSIntegerAtomicSet(&myInt, 42);          // Atomic store via _mulle_atomic_pointer_cas
NSInteger v = NSIntegerAtomicGet(&myInt); // Atomic load via _mulle_atomic_pointer_read

```

```c
/* Creating a tagged pointer for a small signed integer */
#include "MulleObjCTaggedPointer.h"

if (MulleObjCTaggedPointerIsIntegerValue(7))
{
    void *tp = MulleObjCCreateTaggedPointerWithIntegerValueAndIndex(
                   7,
                   MulleObjCTaggedPointerClassGetIndex([MyClass class]));
    /* tp can be passed as an id or void* without heap allocation */
}

```

```c
/* Retrieving the original integer from a tagged pointer */
NSInteger original = MulleObjCTaggedPointerGetIntegerValue(tp);
/* Validates pointer tagging bits before extraction */

```

## Summary

- **Atomic integer types** use `mulle_atomic_pointer_t` unions defined in [`src/MulleObjCIntegralType.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/MulleObjCIntegralType.h) to provide lock-free thread safety for `NSInteger` and `NSUInteger` ivars.
- **Tagged pointers** store small scalars directly in pointer addresses via creation functions in [`src/protocol/MulleObjCTaggedPointer.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/MulleObjCTaggedPointer.h), avoiding heap allocation for values that fit within architecture-specific bit limits.
- **Validity checks** (`MulleObjCTaggedPointerIsIntegerValue`, etc.) ensure only representable values are encoded as tagged pointers.
- **Class index embedding** allows the runtime to treat tagged pointers as first-class objects, routing messages based on the encoded index extracted by `MulleObjCTaggedPointerGetIndex`.
- **Atomic updates** use compare-and-swap loops (`_mulle_atomic_pointer_cas`) rather than locks, providing wait-free progress guarantees for concurrent integer modifications.

## Frequently Asked Questions

### How does MulleObjC ensure thread-safe integer updates without locks?

MulleObjC wraps integers in `NSIntegerAtomic` or `NSUIntegerAtomic` unions containing a `mulle_atomic_pointer_t`. Update operations use `_mulle_atomic_pointer_cas` in retry loops to atomically compare and swap values, providing lock-free thread safety for ivar access.

### What is a tagged pointer in the MulleObjC runtime?

A tagged pointer is a pointer-sized value that encodes a small scalar (integer, float, or double) directly into the lower bits of the address, combined with a class index. The runtime treats these as immediate objects, eliminating heap allocation and reducing cache pressure for numeric values.

### Which scalar types support tagged pointer encoding?

According to [`src/protocol/MulleObjCTaggedPointer.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/MulleObjCTaggedPointer.h), MulleObjC supports tagged pointer encoding for signed integers (`NSInteger`), unsigned integers (`NSUInteger`), `float`, and `double`. Each type has specific validity checks (`MulleObjCTaggedPointerIsFloatValue`, etc.) to determine if the value fits within the available payload bits.

### Where are the atomic integer type definitions located?

The atomic integer union definitions and accessor helpers reside in [`src/MulleObjCIntegralType.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/MulleObjCIntegralType.h), specifically between lines 33-44 for the type structures and lines 49-88 for the atomic getter and setter implementations.