How Method Signature Encoding Works in mulle-objc-runtime

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 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. This struct captures everything the runtime needs for stack allocation and register mapping:

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:

#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:

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:

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 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →