How to Customize the Universe Configuration During MulleObjC Startup
You can customize the MulleObjC universe configuration by either modifying the global default configuration before startup using mulle_objc_global_set_default_universeconfiguration() or by providing a custom __register_mulle_objc_universe function to replace the default registration hook.
The mulle-objc/mulleobjc-startup repository provides the entry point that initializes the Objective-C runtime when your executable launches. Understanding how to customize the universe configuration during MulleObjC startup allows you to tune cache sizes, debug flags, and runtime behavior before any Objective-C code executes.
Understanding the MulleObjC Startup Sequence
The Registration Hook in src/MulleObjC-startup.m
The startup process centers on the __register_mulle_objc_universe symbol defined in src/MulleObjC-startup.m. This file exports the registration function through MULLE_OBJC_DEFINE__register_mulle_objc_universe, which expands the private include mulle-objc-startup-private.inc to create the exported symbol.
When the runtime loads, it calls this registration function, which internally invokes a static helper function called bang(). The bang() function creates a local struct _mulle_objc_universeconfiguration, copies global defaults into it, and passes this structure to MulleObjCBang()—the actual function that creates and initializes the universe.
The Universe Configuration Structure
The configuration is defined in include/MulleObjC/mulle-objc-universeconfiguration-private.h as struct _mulle_objc_universeconfiguration. This structure contains fields for object cache sizes, class table capacity, debug flags, and other runtime parameters that control memory usage and diagnostic output.
Method 1: Modify Global Defaults Before Startup
Using the Global Configuration Setter
The runtime provides two key functions for accessing and modifying the default configuration:
const struct _mulle_objc_universeconfiguration *
mulle_objc_global_get_default_universeconfiguration(void);
void
mulle_objc_global_set_default_universeconfiguration(
const struct _mulle_objc_universeconfiguration *config);
These functions are declared in mulle-objc-universeconfiguration-private.h. By calling mulle_objc_global_set_default_universeconfiguration() before the startup registration runs, you replace the default values that bang() copies into the local configuration structure.
Code Example: Constructor-Based Configuration
You can use a GCC constructor attribute to ensure your configuration runs before Objective-C initialization:
#include <MulleObjC/mulle-objc-universeconfiguration-private.h>
#include <MulleObjC/mulle-objc-startup-private.h>
#include <stdio.h>
/* This runs before any Objective-C code */
static void __attribute__((constructor)) configure_universe(void)
{
struct _mulle_objc_universeconfiguration custom = {
.object_cache_size = 64, /* smaller cache */
.debug_flags = MULLE_OBJC_DEBUG_CALLS /* enable tracing */
};
mulle_objc_global_set_default_universeconfiguration(&custom);
printf("Custom MulleObjC universe configured\n");
}
The constructor executes before __register_mulle_objc_universe from MulleObjC-startup.m, ensuring your values are picked up when bang() calls MulleObjCBang().
Method 2: Provide a Custom Registration Function
Replacing the Default bang() Implementation
Because __register_mulle_objc_universe is defined through a macro that creates a weak symbol, you can provide your own implementation. The linker will prefer your definition if it appears later in the link order.
Alternatively, you can replace the internal bang() callback that the default registration uses. This approach keeps the registration machinery but swaps the configuration building logic.
Code Example: Custom Universe Initialization
Here is how to replace the default behavior with a custom initialization:
#define MULLE_OBJC_DEFINE__register_mulle_objc_universe
#include <MulleObjC/mulle-objc-startup-private.inc>
#include <MulleObjC/mulle-objc-universeconfiguration-private.h>
#include <stdio.h>
static void my_universe_init(struct _mulle_objc_universe *universe,
struct mulle_allocator *allocator,
void *userinfo)
{
struct _mulle_objc_universeconfiguration cfg = {
.object_cache_size = 128,
.debug_flags = MULLE_OBJC_DEBUG_NONE
};
printf("my custom universe init\n");
MulleObjCBang(universe, allocator, &cfg);
}
/* Replace the default static “bang” with our version */
static void __attribute__((constructor)) replace_bang(void)
{
extern void (*_MulleObjC_startup_bang)(
struct _mulle_objc_universe *,
struct mulle_allocator *,
void *);
_MulleObjC_startup_bang = my_universe_init;
}
This example demonstrates both the macro definition to prevent duplicate symbols and the callback replacement technique.
Key Configuration Fields
When you customize the universe configuration during MulleObjC startup, these are the primary fields available in struct _mulle_objc_universeconfiguration:
- object_cache_size — Controls the size of the per-thread object cache, affecting memory usage and allocation performance.
- class_table_initial_capacity — Sets the initial hash table size for class lookups, which impacts method dispatch speed.
- debug_flags — A bitmask enabling various runtime diagnostics such as
MULLE_OBJC_DEBUG_CALLSfor call tracing orMULLE_OBJC_DEBUG_NONEfor production builds.
Consult mulle-objc-universeconfiguration-private.h in the MulleObjC repository for the complete structure definition and additional tuning parameters.
Summary
- The
mulleobjc-startuprepository provides__register_mulle_objc_universeinsrc/MulleObjC-startup.m, which initializes the runtime by callingMulleObjCBang()with a configuration structure. - You can customize the universe configuration during MulleObjC startup by calling
mulle_objc_global_set_default_universeconfiguration()before registration, typically using a GCC constructor attribute. - Alternatively, provide your own
__register_mulle_objc_universeimplementation or replace the internalbang()callback to build a completely custom configuration structure. - Key configuration fields include
object_cache_size,class_table_initial_capacity, anddebug_flags, all defined inmulle-objc-universeconfiguration-private.h.
Frequently Asked Questions
What is the MulleObjC universe?
The MulleObjC universe is the runtime environment that manages all Objective-C classes, objects, method caches, and thread-local storage within the Mulle Objective-C implementation. It is created during startup and persists for the lifetime of the process, governing memory allocation, method dispatch, and runtime diagnostics.
When does the universe configuration get applied?
The universe configuration is applied during the execution of __register_mulle_objc_universe, which runs automatically when the executable starts. Inside src/MulleObjC-startup.m, the bang() function copies the global default configuration into a local structure and passes it to MulleObjCBang() immediately before the universe is created.
Can I modify the universe after startup?
No, the universe configuration is immutable after initialization. The struct _mulle_objc_universeconfiguration is consumed during the creation of the universe in MulleObjCBang(), and the runtime does not provide APIs to reconfigure cache sizes or debug flags dynamically. You must customize the universe configuration during MulleObjC startup using the methods described above.
Where are the configuration functions declared?
The configuration accessor functions mulle_objc_global_get_default_universeconfiguration() and mulle_objc_global_set_default_universeconfiguration() are declared in include/MulleObjC/mulle-objc-universeconfiguration-private.h within the MulleObjC repository. The registration macro MULLE_OBJC_DEFINE__register_mulle_objc_universe is provided in include/MulleObjC/mulle-objc-startup-private.inc.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →