|
1 | 1 | # mulle-objc-runtime Library Documentation for AI |
2 | | -<!-- Keywords: runtime, objective-c --> |
| 2 | +<!-- Keywords: objc, runtime, classes, methods, universe, messaging --> |
3 | 3 |
|
4 | 4 | ## 1. Introduction & Purpose |
5 | 5 |
|
6 | | -mulle-objc-runtime is the core runtime engine for mulle-objc, implementing dynamic dispatch, method lookup, object creation/destruction, and all fundamental Objective-C semantics. It is the foundation on which all mulle-objc code runs, providing the metaclass system, message dispatch, and object lifecycle management. |
| 6 | +- A lightweight, portable Objective-C runtime implemented in C11. Implements class/object metadata, method dispatch, property/ivar layout, signature parsing, and load-time installation of compiled ObjC class data. |
| 7 | +- Solves: provide an Objective-C runtime for environments without Apple's runtime, with focus on speed (inline calls), multi-threading, and multiple coexisting "universes". |
| 8 | +- Key features: fast inlineable messaging, per-class caches, tagged pointers (TPS), retain/release built-ins, binary load format (loadinfo). |
| 9 | +- Relationship: foundational runtime used by MulleObjC and depends on mulle-core and mulle-core-all-load. |
7 | 10 |
|
8 | 11 | ## 2. Key Concepts & Design Philosophy |
9 | 12 |
|
10 | | -- **Message Dispatch**: Fast lookup and invocation of methods via selectors |
11 | | -- **Dynamic Typing**: Runtime type system with metaclasses |
12 | | -- **Object Lifecycle**: Initialization, copying, destruction of objects |
13 | | -- **Selector Management**: Global selector registry and caching |
14 | | -- **Inline Cache**: Fast-path caching of method lookups for performance |
15 | | -- **Non-Thread-Safe by Default**: Requires external synchronization for concurrent access |
| 13 | +- Universe: multiple independent runtimes can coexist; a universe encapsulates class tables, tagged pointers, and allocators. |
| 14 | +- Inline messaging: the runtime favors inlineable call paths and caches (fastmethod tables, imp caches) for speed. |
| 15 | +- IDs not names: classes/selectors/protocols use unique IDs (hashes) rather than string lookups. |
| 16 | +- Load-time install model: compiler emits binary loadinfo structures which are enqueued into a universe to install classes, categories, methods and strings. |
| 17 | +- Low-level C-first API: headers expose structs and functions for AIs to reason about runtime behavior without Objective-C sugar. |
16 | 18 |
|
17 | 19 | ## 3. Core API & Data Structures |
18 | 20 |
|
19 | | -### Primary Structures |
20 | | - |
21 | | -- `struct mulle_objc_class`: Represents a class (contains methods, ivars, superclass) |
22 | | -- `struct mulle_objc_object`: Base object structure (isa pointer, retained count) |
23 | | -- `struct mulle_objc_method`: Method definition (selector, implementation, signature) |
24 | | -- `mulle_objc_methodid_t`: Selector/method identifier |
25 | | -- `mulle_objc_implementation_t`: Function pointer for method implementation |
26 | | - |
27 | | -### Core Functions (Representative) |
28 | | - |
29 | | -#### Object Manipulation |
30 | | - |
31 | | -- `mulle_objc_retain(obj)` → `id`: Increments retain count |
32 | | -- `mulle_objc_release(obj)` → `id`: Decrements retain count |
33 | | -- `mulle_objc_autorelease(obj)` → `id`: Adds to autorelease pool |
34 | | -- `mulle_objc_dealloc(obj)` → `void`: Deallocates object |
35 | | - |
36 | | -#### Method Dispatch |
37 | | - |
38 | | -- `mulle_objc_call_class_method(...)`: Invoke class method |
39 | | -- `mulle_objc_call_instance_method(...)`: Invoke instance method |
40 | | -- `mulle_objc_send_message(obj, sel)`: Send message with selector |
41 | | - |
42 | | -#### Class/Metadata |
43 | | - |
44 | | -- `mulle_objc_class_for_classid(id)`: Lookup class by ID |
45 | | -- `mulle_objc_classid_for_name(name)`: Get class ID by name |
46 | | -- `mulle_objc_method_for_classid_and_methodid(...)`: Find method |
| 21 | +### 3.1. [mulle-objc-runtime.h] |
| 22 | +- Purpose: umbrella header; includes core public headers and compile-time checks (TPS/FCS/TAO flags). |
| 23 | +- Note: compile Objective-C code with the same compile-time flags used to build the runtime. |
| 24 | + |
| 25 | +### 3.2. [mulle-objc-universe.h | mulle-objc-universe-global.h] |
| 26 | +- struct _mulle_objc_universe |
| 27 | + - Purpose: runtime instance container (class tables, tagged pointer config, allocators, debug/config). |
| 28 | + - Key fields: class cache tables, tagged pointer tables, allocator pointers, config flags. |
| 29 | + - Lifecycle functions: |
| 30 | + - mulle_objc_global_get_universe_inline / mulle_objc_global_get_defaultuniverse: get universe pointer. |
| 31 | + - __mulle_objc_global_register_universe / __mulle_objc_global_unregister_universe: register named universes. |
| 32 | + - mulle_objc_global_reset_universetable: clear registered universes (cleanup). |
| 33 | + - Core operations: get allocator, lookup/register classes and universes, iterate universes. |
| 34 | + |
| 35 | +### 3.3. [mulle-objc-class.h | mulle-objc-class-struct.h] |
| 36 | +- struct _mulle_objc_class |
| 37 | + - Purpose: represents a class (infraclass/metaclass) and its runtime metadata. |
| 38 | + - Key fields: name, superclass, allocationsize, methodlists pointerarray, classid, inheritance flags, kvc pivot, cache pivot. |
| 39 | + - Lifecycle functions: |
| 40 | + - _mulle_objc_class_init / _mulle_objc_class_done: initialize and cleanup class structures. |
| 41 | + - _mulle_objc_class_setup_pointerarrays: finalize pointer arrays after creation. |
| 42 | + - Core operations: |
| 43 | + - mulle_objc_class_add_methodlist, _mulle_objc_class_add_methodlist_nocache: add methods/categories. |
| 44 | + - _mulle_objc_class_lookup_method / mulle_objc_class_lookup_method: method lookup (uses imp caches). |
| 45 | + - _mulle_objc_class_invalidate_impcache / invalidate_kvccache: cache invalidation. |
| 46 | + - Accessors: mulle_objc_class_get_name, get_instancesize, get_universe, get_metaclass, is_infraclass/is_metaclass. |
| 47 | + - Inspection: count depth, get methodlists count, is_sane checks. |
| 48 | + |
| 49 | +### 3.4. [mulle-objc-object.h | mulle-objc-objectheader.h] |
| 50 | +- struct _mulle_objc_objectheader |
| 51 | + - Purpose: header prefixed to every instance, contains retain count and isa. |
| 52 | + - Key fields: _retaincount_1 (atomic), _isa pointer. |
| 53 | + - Helpers: _mulle_objc_objectheader_init, get/set isa, get_retaincount. |
| 54 | +- Object helpers: |
| 55 | + - _mulle_objc_object_get_isa, mulle_objc_object_get_universe, object extra pointer accessors, ivar read/write helpers. |
| 56 | + - Tagged pointers: tagged pointer path exists (TPS); functions handle TPS index and fallback. |
| 57 | + |
| 58 | +### 3.5. [mulle-objc-method.h | mulle-objc-methodlist.h] |
| 59 | +- struct _mulle_objc_descriptor / _mulle_objc_method |
| 60 | + - Purpose: describes method id, name, signature and implementation function pointer. |
| 61 | + - Key fields: methodid, signature, name, bits (attributes), implementation (atomic function pointer). |
| 62 | + - Operations: get/set implementation, cas_implementation (atomic replace), bsearch/sort utilities, method family helpers. |
| 63 | +- struct _mulle_objc_methodlist |
| 64 | + - Purpose: contiguous method array (n_methods + methods[]). Category id + origin. |
| 65 | + - Operations: sort, binary search vs linear search threshold (heuristic), enumeration, adding +load to callqueue. |
| 66 | + |
| 67 | +### 3.6. [mulle-objc-property.h] |
| 68 | +- struct _mulle_objc_property |
| 69 | + - Purpose: property descriptor with getter/setter/adder/remover methodids, ivarid and bits. |
| 70 | + - Operations: accessors for name, signature, getter/setter ids, bit tests (readonly/dynamic/observable/etc.). |
| 71 | + |
| 72 | +### 3.7. [mulle-objc-ivar.h] |
| 73 | +- struct _mulle_objc_ivar |
| 74 | + - Purpose: ivar descriptor for name/signature and offset. |
| 75 | + - API: get_name, get_signature, get_offset, bsearch and sort helpers. |
| 76 | + |
| 77 | +### 3.8. [mulle-objc-load.h] |
| 78 | +- load data structures: _mulle_objc_loadinfo, _mulle_objc_loadclass, _mulle_objc_loadcategory |
| 79 | + - Purpose: describe binary emitted class/category/method/property data to be installed into a universe. |
| 80 | + - Core operations: mulle_objc_loadinfo_enqueue_nofail(info) — enqueue and install into runtime; mulle_objc_universe_assert_loadinfo for compatibility checks. |
| 81 | + - Versioning: MULLE_OBJC_RUNTIME_LOAD_VERSION and load version bits in structures. |
| 82 | + |
| 83 | +### 3.9. [mulle-objc-signature.h] |
| 84 | +- Signature/type parsing helpers |
| 85 | + - API: mulle_objc_signature_supply_typeinfo, mulle_objc_signature_next_type, supply_size_and_alignment, signature enumerator helpers. |
| 86 | + - Purpose: parse ObjC encoded signatures into size/alignment/typeinfo for marshalling and call ABI classification. |
| 87 | + |
| 88 | +### 3.10. [mulle-objc-retain-release.h] |
| 89 | +- Built-in retain/release mechanisms |
| 90 | + - Inline retain/release helpers (_mulle_objc_object_retain_inline, _mulle_objc_object_release_inline) for performance and special constants (MULLE_OBJC_NEVER_RELEASE etc.). |
| 91 | + - API for bulk retain/release of object arrays, finalize/dealloc helpers. |
| 92 | + |
| 93 | +### 3.11. [mulle-objc-protocol.h] |
| 94 | +- struct _mulle_objc_protocol: protocolid + name; sort/bsearch helpers; protocols live in universe tables. |
47 | 95 |
|
48 | 96 | ## 4. Performance Characteristics |
49 | 97 |
|
50 | | -- **Message Dispatch**: O(1) average with inline cache; O(depth) without cache where depth is inheritance chain |
51 | | -- **Retain/Release**: O(1) atomic operation |
52 | | -- **Memory**: Fixed per-object overhead; efficient object layout |
53 | | -- **Inlining**: Many operations can be inlined for performance |
54 | | -- **Thread Safety**: Not thread-safe by default; external locking required |
| 98 | +- Method dispatch: optimized via per-class imp caches and optional fastmethod tables. Cache hit is effectively O(1). Cold lookup may walk methodlists: cost depends on methodlist size (binary search O(log n) for large lists, linear for small). |
| 99 | +- Methodlist search: binary search used for n_methods >= 14 (heuristic), otherwise linear scan. |
| 100 | +- Retain/release: inline atomic increment/decrement for the common case (O(1)). Special states (SLOW_RELEASE, NEVER_RELEASE) trigger method calls. |
| 101 | +- Loading: code loading uses global synchronization but normal operation avoids global locks; per-class +initialize uses per-class synchronization. |
| 102 | +- Memory vs speed: class structures are sizable (~1 KB/class on 64-bit) to favor runtime speed and cache locality. |
| 103 | +- Thread-safety: designed for multi-threading; many structures use atomic pointers and concurrent maps. Loading and certain initialization paths still require locking. |
55 | 104 |
|
56 | 105 | ## 5. AI Usage Recommendations & Patterns |
57 | 106 |
|
58 | | -### Best Practices |
59 | | - |
60 | | -- **Use High-Level APIs**: Prefer NSObject/Foundation APIs over runtime directly |
61 | | -- **Cache Selectors**: Store frequently-used selector IDs |
62 | | -- **Error Handling**: Check nil returns from method calls |
63 | | -- **Memory Management**: Always balance retain/release calls |
64 | | -- **Avoid Direct Struct Access**: Use accessor functions instead |
65 | | - |
66 | | -### Common Pitfalls |
67 | | - |
68 | | -- **Thread Safety**: No automatic synchronization; use locks for concurrent access |
69 | | -- **Selector ID Lookups**: Looking up selector IDs repeatedly has overhead |
70 | | -- **Exception Safety**: Manual memory management; ensure cleanup in error paths |
71 | | -- **Class Registration**: Classes must be properly registered before use |
72 | | -- **Method Signatures**: Mismatched signatures lead to undefined behavior |
| 107 | +- Best practices: |
| 108 | + - Use umbrella header <mulle-objc-runtime/mulle-objc-runtime.h> for high-level operations. |
| 109 | + - Always use supplied lifecycle functions (_init/_done, enqueue loadinfo) instead of manually mutating structs. |
| 110 | + - Respect compile-time options (TPS/FCS/TAO) — mismatch leads to incompatible behavior. |
| 111 | + - Prefer inline API helpers (mulle_objc_object_get_isa, mulle_objc_method_get_implementation) for performance. |
| 112 | +- Common pitfalls: |
| 113 | + - Do not directly modify struct internals in multi-threaded contexts; use provided functions. |
| 114 | + - Be aware of tagged pointers: some helpers return NULL or different behavior for TPS objects. |
| 115 | + - loadinfo structures passed to enqueue must reside in permanent memory until universe destructed. |
| 116 | +- Idioms: |
| 117 | + - Use mulle_objc_loadinfo_enqueue_nofail to install compiled class data. |
| 118 | + - Use signature parsing helpers to marshal parameters for manual call dispatch. |
73 | 119 |
|
74 | 120 | ## 6. Integration Examples |
75 | 121 |
|
76 | | -### Example 1: Basic Message Sending |
| 122 | +### Example 1: Getting a class name from an instance |
77 | 123 |
|
78 | 124 | ```c |
| 125 | +// 3-space indent, C89 rules |
79 | 126 | #include <mulle-objc-runtime/mulle-objc-runtime.h> |
80 | 127 |
|
81 | | -// Send "init" message to object |
82 | | -mulle_objc_method_id_t init_sel = mulle_objc_methodid_for_name("init"); |
83 | | -id result = mulle_objc_send_message(obj, init_sel); |
84 | | -``` |
| 128 | +void |
| 129 | +print_class_name( void *obj) |
| 130 | +{ |
| 131 | + struct _mulle_objc_class *cls; |
85 | 132 |
|
86 | | -### Example 2: Memory Management |
87 | | - |
88 | | -```c |
89 | | -id obj = ...; |
90 | | -mulle_objc_retain(obj); |
91 | | -// Use obj... |
92 | | -mulle_objc_release(obj); |
| 133 | + cls = mulle_objc_object_get_isa( obj); |
| 134 | + if( cls) |
| 135 | + printf( "class: %s\n", mulle_objc_class_get_name( cls)); |
| 136 | +} |
93 | 137 | ``` |
94 | 138 |
|
95 | | -### Example 3: Class Lookup |
| 139 | +### Example 2: Parsing a method signature |
96 | 140 |
|
97 | 141 | ```c |
98 | | -mulle_objc_classid_t classid = mulle_objc_classid_for_name("MyClass"); |
99 | | -struct mulle_objc_class *cls = mulle_objc_class_for_classid(classid); |
| 142 | +#include <mulle-objc-runtime/mulle-objc-runtime.h> |
| 143 | +
|
| 144 | +void |
| 145 | +dump_signature( char *sig) |
| 146 | +{ |
| 147 | + struct mulle_objc_typeinfo info; |
| 148 | +
|
| 149 | + while( mulle_objc_signature_supply_typeinfo( sig, NULL, &info)) |
| 150 | + { |
| 151 | + printf( "type=%s size=%zu\n", info.type, info.natural_size); |
| 152 | + sig = mulle_objc_signature_next_type( sig); |
| 153 | + if( ! sig || ! *sig) |
| 154 | + break; |
| 155 | + } |
| 156 | +} |
100 | 157 | ``` |
101 | 158 |
|
102 | 159 | ## 7. Dependencies |
103 | 160 |
|
104 | | -- mulle-c11 |
105 | | -- mulle-allocator |
106 | | -- mulle-concurrent (for thread-safe operations) |
| 161 | +- mulle-core (mulle-core amalgamation) |
| 162 | +- mulle-core-all-load |
| 163 | +- mulle-allocator (via mulle-core) |
| 164 | +- mulle-sde for build/install integration |
| 165 | + |
| 166 | +## 8. Shortcut |
| 167 | + |
| 168 | +- If an existing TOC.md is present, prefer to inspect its commit history. This file was generated from README.md and the public headers under src/ to produce an AI-friendly concise API map. |
0 commit comments