Skip to content

Instantly share code, notes, and snippets.

@TheFox
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheFox/1c4984523df14f2ff5f8 to your computer and use it in GitHub Desktop.
Save TheFox/1c4984523df14f2ff5f8 to your computer and use it in GitHub Desktop.
Objc call_category_loads
// Original: http://www.opensource.apple.com/source/objc4/objc4-646/runtime/objc-loadmethod.mm
static BOOL call_category_loads(void){
// ...
int used = loadable_categories_used;
// ...
loadable_categories_used = 0;
// ...
new_categories_added = (loadable_categories_used > 0);
for (i = 0; i < loadable_categories_used; i++) {
if (used == allocated) {
allocated = allocated*2 + 16;
cats = (struct loadable_category *)
_realloc_internal(cats, allocated * sizeof(struct loadable_category));
}
cats[used++] = loadable_categories[i];
}
if (loadable_categories) _free_internal(loadable_categories);
if (used) {
loadable_categories = cats;
// ...
} else {
// ...
loadable_categories = nil;
// ...
}
// ...
return new_categories_added;
}
/*
Created @ 16.02.2015 by Christian Mayer <http://fox21.at>
Compile with
clang++ -I darwin/objc4-646/runtime my_call_category_loads.cpp -o my_call_category_loads
*/
#include <stdio.h>
#include <unistd.h>
#include <cstddef>
#include <objc/objc.h>
#if __OBJC2__
typedef struct method_t *Method;
typedef struct ivar_t *Ivar;
typedef struct category_t *Category;
typedef struct property_t *objc_property_t;
#else
typedef struct old_method *Method;
typedef struct old_ivar *Ivar;
typedef struct old_category *Category;
typedef struct old_property *objc_property_t;
#endif
typedef void(*load_method_t)(id, SEL);
struct loadable_class {
Class cls;
IMP method;
};
struct loadable_category {
Category cat;
IMP method;
};
static struct loadable_class *loadable_classes = nil;
static int loadable_classes_used = 0;
static int loadable_classes_allocated = 0;
static struct loadable_category *loadable_categories = nil;
static int loadable_categories_used = 0;
static int loadable_categories_allocated = 0;
static void my_call_class_loads(void){
puts("exec my_call_class_loads()");
int i;
struct loadable_class *classes = loadable_classes;
int used = loadable_classes_used;
loadable_classes = nil;
loadable_classes_allocated = 0;
loadable_classes_used = 0;
for(i = 0; i < used; i++){
//sleep(1);
printf("\t iterate 'used': %d\n", i);
/*
Class cls = classes[i].cls;
load_method_t load_method = (load_method_t)classes[i].method;
if(!cls)
continue;
if(PrintLoading){
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
}
(*load_method)(cls, SEL_load);*/
}
//if(classes) _free_internal(classes);
puts("");
}
static BOOL my_call_category_loads(void){
puts("exec my_call_category_loads()");
int i, shift;
BOOL new_categories_added = NO;
struct loadable_category *cats = loadable_categories;
int used = loadable_categories_used;
int allocated = loadable_categories_allocated;
loadable_categories = nil;
loadable_categories_allocated = 0;
loadable_categories_used = 0;
for(i = 0; i < used; i++){
//sleep(1);
printf("\t iterate 'used' A: %d\n", i);
/*
Category cat = cats[i].cat;
load_method_t load_method = (load_method_t)cats[i].method;
Class cls;
if(!cat)
continue;
cls = _category_getClass(cat);
if(cls && cls->isLoadable()){
if(PrintLoading){
_objc_inform("LOAD: +[%s(%s) load]\n", cls->nameForLogging(), _category_getName(cat));
}
(*load_method)(cls, SEL_load);
cats[i].cat = nil;
}*/
}
shift = 0;
for(i = 0; i < used; i++){
//sleep(1);
printf("\t iterate 'used' B: %d\n", i);
/*if(cats[i].cat){
cats[i-shift] = cats[i];
}
else{
shift++;
}*/
}
used -= shift;
printf("\t used: %d\n", used);
printf("\t loadable_categories_used: %d\n", loadable_categories_used);
new_categories_added = (loadable_categories_used > 0);
//new_categories_added = (used > 0);
for(i = 0; i < loadable_categories_used; i++){
//for(i = 0; i < used; i++){
//sleep(1);
printf("\t iterate 'loadable_categories_used': %d %d\n", i, allocated);
if(used == allocated){
allocated = allocated * 2 + 16;
printf("\t allocated: %d\n", allocated);
//cats = (struct loadable_category *)_realloc_internal(cats, allocated * sizeof(struct loadable_category));
printf("\t cats = ... _realloc_internal(...);\n");
}
//cats[used++] = loadable_categories[i];
}
printf("\t loadable_categories: %p\n", loadable_categories);
if(loadable_categories)
//_free_internal(loadable_categories);
printf("\t _free_internal(loadable_categories);\n");
if(used){
loadable_categories = cats;
loadable_categories_used = used;
loadable_categories_allocated = allocated;
}
else{
if(cats)
//_free_internal(cats);
printf("\t _free_internal(cats);\n");
loadable_categories = nil;
loadable_categories_used = 0;
loadable_categories_allocated = 0;
}
/*if(PrintLoading){
if(loadable_categories_used != 0){
_objc_inform("LOAD: %d categories still waiting for +load\n", loadable_categories_used);
}
}*/
printf("\t new_categories_added: %d\n", new_categories_added);
puts("");
return new_categories_added;
}
void my_call_load_methods(void){
static BOOL loading = NO;
BOOL more_categories;
//recursive_mutex_assert_locked(&loadMethodLock);
if (loading) return;
loading = YES;
//void *pool = objc_autoreleasePoolPush();
do{
while(loadable_classes_used > 0){
printf("call my_call_class_loads() in my_call_load_methods(): %d\n", loadable_classes_used);
my_call_class_loads();
//sleep(1);
}
more_categories = my_call_category_loads();
printf("more_categories = %d\n", more_categories);
printf("loadable_classes_used = %d\n", loadable_classes_used);
//sleep(1);
}while(loadable_classes_used > 0 || more_categories);
//objc_autoreleasePoolPop(pool);
loading = NO;
puts("");
}
int main (int argc, const char * argv[]){
// Test with pseudo data
loadable_classes_used = 3;
loadable_categories_used = 5;
my_call_load_methods();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment