# Understanding the Mulle-ObjC Load Info Structure: How Code Is Loaded into the Runtime

> Discover the mulle_objc_loadinfo structure and how mulle-objc runtime safely registers code. Learn about the metadata container for classes, categories, strings and version compatibility.

- Repository: [mulle-objc/mulle-objc-runtime](https://github.com/mulle-objc/mulle-objc-runtime)
- Tags: internals
- Published: 2026-03-07

---

**The `mulle_objc_loadinfo` structure is a compiler-populated metadata container defined in [`src/mulle-objc-load.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.h) that describes classes, categories, strings, and version compatibility, which the runtime processes through `mulle_objc_loadinfo_enqueue_nofail` in [`src/mulle-objc-load.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.c) to safely register code into a universe.**

The `mulle-objc/mulle-objc-runtime` repository implements a unique loading mechanism where compiled object files carry self-describing metadata rather than relying on external registration functions. This **load info structure** serves as the single source of truth for everything the runtime must add to a universe when a `.o` file is linked.

## What Is the Load Info Structure?

The `struct _mulle_objc_loadinfo` acts as a manifest generated by the compiler. It lives in **[`src/mulle-objc-load.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.h)** (lines 83–95) and aggregates pointers to tables describing classes, categories, inheritance links, and constant strings.

### Core Structure Definition

```c
struct _mulle_objc_loadinfo
{
    struct mulle_objc_loadversion   version;
    struct _mulle_objc_loaduniverse *loaduniverse;
    struct _mulle_objc_loadclasslist    *loadclasslist;
    struct _mulle_objc_loadcategorylist *loadcategorylist;
    struct _mulle_objc_superlist        *loadsuperlist;
    struct _mulle_objc_loadstringlist   *loadstringlist;
    struct _mulle_objc_loadhashedstringlist *loadhashedstringlist;
    char *origin;
};

```

### Field-by-Field Breakdown

- **`version`** – Contains three version numbers (`load`, `runtime`, `foundation`) plus a bitmask. The runtime checks these via `_mulle_objc_universe_assert_runtimeversion` to guarantee binary compatibility between the compiled code and the executing universe.

- **`loaduniverse`** – If non-NULL, explicitly requests a specific universe ID. The runtime registers this universe globally via `mulle_objc_global_register_universe` before processing any classes.

- **`loadclasslist`** – Points to an array of `struct _mulle_objc_loadclass` entries. Each entry carries a class identifier, name, superclass reference, ivar layout, method lists, property list, protocol list, and the originating object file name.

- **`loadcategorylist`** – Analogous to `loadclasslist` but describes categories that extend existing classes, including their method and property additions.

- **`loadsuperlist`** – Holds inheritance linkage information required for fast `super` message dispatch, populated via `mulle_objc_loadsuperlist_enqueue_nofail`.

- **`loadstringlist`** – References pre-created constant `NSString` objects needed during class initialization, loaded without holding locks via `mulle_objc_loadstringlist_enqueue_nofail`.

- **`loadhashedstringlist`** – Optional debug structure storing hashed strings for quick method name lookup. Controlled by the `unsorted` bit in the version field.

- **`origin`** – Human-readable source file path indicating where the load info originated, useful for debugging and trace output.

## How Code Is Loaded into the Runtime

The loading process centers on the **`mulle_objc_loadinfo_enqueue_nofail`** function declared in [`src/mulle-objc-load.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.h) and implemented in **[`src/mulle-objc-load.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.c)**. The compiler emits calls to this function for each object file, deferring execution via `mulle_atinit` to run after static initialization but before user code executes.

### The Entry Point and Deferred Execution

When an object file is linked, the compiler generates a stub that registers the load info for later processing:

```c
mulle_atinit(_mulle_objc_loadinfo_enqueue_nofail, info, 0, comment);

```

This defers execution until the runtime environment is ready, ensuring static initializers complete first. The public wrapper `mulle_objc_loadinfo_enqueue_nofail` forwards to the internal implementation `_mulle_objc_loadinfo_enqueue_nofail` after printing optional trace messages (lines 57–74 in [`src/mulle-objc-load.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.c)).

### The Loading Pipeline Step-by-Step

The implementation in [`src/mulle-objc-load.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.c) (lines 49–141) executes the following sequence:

1. **Universe selection** – Determines the target universe (default or specified by `loaduniverse`) and registers it globally.

2. **Version validation** – Compares the three version fields against the current runtime, aborting with a descriptive error on mismatch.

3. **Callback veto check** – Optionally invokes `should_load_loadinfo` to allow embedding applications to skip specific load info objects.

4. **Load constant strings** – Processes `loadstringlist` without acquiring locks, installing `NSString` constants needed by subsequent steps.

5. **Load hashed strings** – If present, optionally sorts them (unless the `unsorted` bit is set) and registers them for fast lookup.

6. **Load super-class information** – Populates the fast-super dispatch table via `mulle_objc_loadsuperlist_enqueue_nofail`.

7. **Acquire wait-queue lock** – Calls `_mulle_objc_universe_lock_waitqueues` to serialize modifications to class and category tables.

8. **Register classes** – `mulle_objc_loadclasslist_enqueue_nofail` allocates class and metaclass structures, installs ivars, method lists, properties, and protocols.

9. **Register categories** – `mulle_objc_loadcategorylist_enqueue_nofail` merges category methods and properties into target classes.

10. **Execute +load methods** – Builds a temporary `struct _mulle_objc_callqueue`, walks it via `mulle_objc_callqueue_walk`, and invokes each class or category `+load` method to maintain Objective-C load-time semantics.

11. **Release lock** – Calls `_mulle_objc_universe_unlock_waitqueues` to finalize the load and allow normal execution.

### Universe Selection and Version Validation

Before mutating any runtime structures, the code validates compatibility. The **`loaduniverse`** field allows compiled code to target specific universe instances, while the **`version`** field prevents loading code compiled against incompatible runtime or foundation versions. This ensures that binary metadata matches the executing environment's ABI.

### Registering Classes and Categories

The **`loadclasslist`** and **`loadcategorylist`** fields drive the core metadata registration. Each class entry triggers allocation of `struct _mulle_objc_class` pairs (class and metaclass), installation of instance variable layouts, and registration of method dispatch tables. Categories are attached to existing classes, with their methods inserted into the class's method lists according to Objective-C precedence rules.

### Executing +load Methods

After all metadata is registered, the runtime constructs a temporary call queue to handle **`+load`** invocations. This queue ensures that class loads execute before category loads, and that dependencies respect the loading order. The **`mulle_objc_callqueue`** infrastructure (defined in [`src/mulle-objc-callqueue.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-callqueue.h)) manages this ordered execution before the final unlock releases the universe for normal message passing.

## Summary

- The **`mulle_objc_loadinfo`** structure in [`src/mulle-objc-load.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.h) serves as a compiler-generated manifest describing all runtime metadata in a compiled object file.
- Loading occurs through **`mulle_objc_loadinfo_enqueue_nofail`**, which defers execution via `mulle_atinit` until after static initialization.
- The pipeline validates version compatibility, selects or creates the target universe, loads constant strings and super-class tables, then locks wait-queues to safely register classes and categories.
- **`+load`** methods execute from a temporary call queue after all metadata registration completes but before the wait-queue lock is released.
- Key implementation files include **[`src/mulle-objc-load.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-load.c)** for the loading logic and **`src/mulle-objc-universe.h/c`** for universe management and version checking.

## Frequently Asked Questions

### What happens if the version numbers in the load info structure do not match the runtime?

The runtime calls `_mulle_objc_universe_assert_runtimeversion` to compare the `load`, `runtime`, and `foundation` version fields. If any value is incompatible, the function aborts execution with a descriptive error message, preventing crashes from ABI mismatches between compiled code and the running universe.

### Can an application prevent specific load info structures from being processed?

Yes. The runtime checks for an optional **`should_load_loadinfo`** callback before proceeding with loading. If this callback returns false, the runtime skips the entire load info object, allowing embedding applications to veto loading of specific compiled object files or libraries.

### Why are constant strings loaded before acquiring the wait-queue lock?

The **`loadstringlist`** is processed via `mulle_objc_loadstringlist_enqueue_nofail` before locking because constant `NSString` objects are immutable global data that do not mutate shared runtime structures. Loading them early ensures they are available for class and category registration while avoiding unnecessary lock contention during the string installation phase.

### How does the runtime handle the +load method execution order?

The runtime builds a temporary **`struct _mulle_objc_callqueue`** after registering all classes and categories. It walks this queue via `mulle_objc_callqueue_walk` (defined in [`src/mulle-objc-callqueue.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-callqueue.c)), invoking each `+load` method in the correct order: class loads execute before category loads, respecting dependencies. This occurs while the wait-queue lock is still held, ensuring no other threads interact with partially initialized classes.