# How Method Signature Encoding Works in mulle-objc-runtime

> Discover how method signature encoding in mulle-objc-runtime uses compact ASCII strings to define memory layout and object ownership for efficient method dispatch.

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

---

**Method signature encoding in mulle-objc-runtime uses compact ASCII strings to represent method return types and parameters, which the runtime parses to determine memory layout, alignment, and object ownership semantics for method dispatch.**

The mulle-objc-runtime implements method signature encoding using the same fundamental approach as the Apple Objective-C runtime, where type information is serialized into portable character strings. These **signature strings** enable the runtime to calculate stack frame requirements, verify binary compatibility, and generate correct meta-ABI calling conventions without requiring debug symbols or external metadata.

## Method Signature Encoding Format

A method signature is a contiguous sequence of **type-encoding characters** (the standard `@encode` set) that describes the return value followed by each argument. For example, the signature `i@:@@` describes a method returning an `int` (`i`) and taking two `id` arguments, while automatically including the hidden `self` argument (`@`) and `_cmd` selector argument (`:`).

The encoding grammar supports scalar types, pointers, objects, and complex aggregates. **mulle-objc** extends the standard set with three additional codes to make object ownership explicit:

- `_C_ASSIGN_ID` (`=`) — "assign" semantics for non-retaining references
- `_C_COPY_ID` (`~`) — "copy" semantics for object copying
- `_C_RETAIN_ID` (`@`) — "retain" semantics (default for objects)
- `_C_ID` (`@`) — Alias for the retain semantics code

While the compiler may not yet emit the assign or copy codes in all contexts, the runtime fully understands and processes these ownership qualifiers when present in signatures.

## Core Signature Parsing Functions

The implementation in [`src/mulle-objc-signature.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.c) provides the primary API for consuming encoded signatures. The parser traverses the character array recursively, handling nested structures and arrays while accumulating size and alignment data.

Key functions include:

- **`_mulle_objc_signature_supply_typeinfo`** — Parses a single type fragment from the signature, populates a `struct mulle_objc_typeinfo` with size, alignment, and object flags, and returns a pointer to the next unparsed character.
- **`mulle_objc_signature_next_type`** — Skips one complete encoded type (including complex aggregates) and returns a pointer to the following type, enabling iteration over method parameters.
- **`mulle_objc_signature_supply_size_and_alignment`** — Computes the **byte size** and **alignment requirements** for a single type or an entire aggregate structure.
- **`mulle_objc_signature_count_typeinfos`** — Returns the total count of distinct type encodings present in a complete method signature.
- **`mulle_objc_signature_get_metaabiparamtype`** / **`mulle_objc_signature_get_metaabireturntype`** — Inspects return and parameter types to determine which meta-ABI calling convention (void, pointer, or struct-block) a method requires.
- **`mulle_objc_signature_enumerate`** — Provides an iterator interface that walks through the signature components (return type, `self`, `_cmd`, and explicit parameters) while maintaining per-type metadata.

All parsing ultimately flows through `_mulle_objc_type_parse`, which dispatches on the initial character to distinguish scalar types from complex aggregates like arrays (`[nT]`), structures (`{name=...}`), unions, and bitfields.

## The mulle_objc_typeinfo Structure

The parser extracts detailed layout information into the `mulle_objc_typeinfo` structure defined in [`src/mulle-objc-signature.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.h). This struct captures everything the runtime needs for stack allocation and register mapping:

```c
struct mulle_objc_typeinfo {
    char *type;                 // Pointer to start of encoded fragment
    char *pure_type_end;        // End of pure type (ignores @"..." class names)
    char *member_type_start;    // First member in structs/arrays
    char *name;                 // Class name for object types (e.g., @"NSString")
    unsigned int n_members;     // Number of members for aggregates
    size_t natural_size;        // Size in bytes of the C type
    size_t bits_size;           // Size in bits (used for meta-ABI calculations)
    int32_t invocation_offset;  // Offset used by NSInvocation
    uint16_t bits_struct_alignment;
    uint16_t natural_alignment;
    char has_object;            // True if type contains an object reference
    char has_retainable_type;   // True if type contains a retainable object
};

```

The `has_object` and `has_retainable_type` flags enable the garbage collector and reference counting systems to identify which parameters require memory management without parsing the signature repeatedly.

## Parsing Method Signatures in Practice

The following example demonstrates how to manually parse a method signature and inspect the layout of each argument:

```c
#include "mulle-objc-signature.h"
#include <stdio.h>

int main(void)
{
    const char *sig = "v@:@i";                     // void return, self, _cmd, id, int
    struct mulle_objc_typeinfo info;
    const char *p = sig;

    /* Skip return type, self, and _cmd */
    p = mulle_objc_signature_next_type(p);
    p = mulle_objc_signature_next_type(p);
    p = mulle_objc_signature_next_type(p);

    /* First explicit argument (id) */
    p = _mulle_objc_signature_supply_typeinfo((char *)p, NULL, &info);
    printf("arg0: size=%zu align=%u object=%d\n",
           info.natural_size, info.natural_alignment, info.has_object);

    /* Second explicit argument (int) */
    p = _mulle_objc_signature_supply_typeinfo((char *)p, NULL, &info);
    printf("arg1: size=%zu align=%u object=%d\n",
           info.natural_size, info.natural_alignment, info.has_object);
    
    return 0;
}

```

On a 64-bit platform, this outputs:

```text
arg0: size=8 align=8 object=1
arg1: size=4 align=4 object=0

```

This same API correctly handles nested structures and arrays because the parser follows the complete Objective-C type-encoding grammar recursively.

## Key Source Files

The method signature encoding system spans several files in the repository:

- [`src/mulle-objc-signature.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.h) — Public API declarations, `typeinfo` structure definition, and inline helper functions.
- [`src/mulle-objc-signature.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.c) — Full implementation of the parser, size/alignment calculators, and meta-ABI helpers.
- [`dox/API_SIGNATURE.md`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/dox/API_SIGNATURE.md) — Comprehensive documentation of the encoding character set and extensions.
- [`test/signature/parse_signature.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/test/signature/parse_signature.c) — Test suite exercising edge cases in signature parsing.

## Summary

- Method signature encoding represents types as compact ASCII strings using standard `@encode` characters plus mulle-objc ownership extensions.
- The `=` (assign), `~` (copy), and `@` (retain) codes enable explicit memory management semantics within the type system.
- Parsing functions in [`src/mulle-objc-signature.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.c) extract detailed layout metadata into `mulle_objc_typeinfo` structures.
- The parser handles complex aggregates recursively, calculating correct sizes and alignments for structs, unions, and arrays.
- This encoding mechanism drives meta-ABI compliance, method dispatch table generation, and binary compatibility verification.

## Frequently Asked Questions

### How does mulle-objc-runtime extend standard Objective-C type encoding?

The runtime adds three ownership-specific encoding characters to the standard set: `=` for assign semantics, `~` for copy semantics, and `@` for retain semantics (which is also the standard object encoding). These extensions allow the runtime to determine memory management behavior directly from the signature without additional metadata.

### What functions parse method signatures in the runtime?

The primary parsing function is `_mulle_objc_signature_supply_typeinfo()` in [`src/mulle-objc-signature.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-signature.c), which fills a `typeinfo` structure with size, alignment, and object flags. Supporting functions like `mulle_objc_signature_next_type()` enable iteration, while `mulle_objc_signature_count_typeinfos()` provides quick length calculations.

### Can the signature parser handle nested C structures and arrays?

Yes. The internal `_mulle_objc_type_parse` dispatcher recursively processes arrays (`[count type]`), structures (`{name=...}`), unions, and bitfields. This ensures accurate size and alignment calculations for arbitrarily complex parameter types passed to Objective-C methods.

### How does the runtime use signature encoding for method dispatch?

The runtime uses parsed signature information to determine the **meta-ABI calling convention** via `mulle_objc_signature_get_metaabireturntype()`. This decides whether a method returns void, a pointer, or a struct-block, ensuring correct register and stack usage during message sending.