?? core.c
字號:
*/ for (i = 0; i < method_list->method_count; ++i) { Method_t kill_method = &method_list->method_list[i]; Method_t method; /* Remove any instance method found. */ method = searchForMethodInList (class->methods, kill_method->method_name); if (method) method->method_name = NULL; /* Remove any factory method found. */ method = searchForMethodInList (class->class_pointer->methods, kill_method->method_name); if (method) method->method_name = NULL; }}/* * This is a incomplete implementation of posing. This function does the * bulk of the work but does not initialize the class method caches. That is * a run-time specific operation. * * I implement posing by hiding SUPER_CLASS, creating new class and meta * class structures, initializing it with IMPOSTOR, and changing it such * that it is identified as SUPER_CLASS. SUPER_CLASS remains in the * hierarchy but is inaccessible by the means. The class hierarchy is then re * arranged such that all of the subclasses of SUPER_CLASS now inherit from * the new class structures -- except the impostor itself. The only dramatic * effect on the application is that subclasses of SUPER_CLASS cannot do a * [ .... superClass ] and expect their real super class. */Class_t class_poseAs (Class_t impostor, Class_t super_class){ Class_t new_class = (Class_t) calloc (1, sizeof (Class)); MetaClass_t new_meta_class = (MetaClass_t) calloc (1, sizeof (MetaClass)); node_ptr node; char *new_name = (char *) malloc (strlen (super_class->name) + 12); assert (new_class); assert (new_meta_class); assert (new_name); /* No dispatching while the the posing class is being built. The dispatch tables will be hacked on. */ MUTEX_LOCK (runtimeMutex); assert (impostor->info & CLS_CLASS); assert (super_class->info & CLS_CLASS); assert (impostor->instance_size == super_class->instance_size); /* Create the impostor class. */ new_class->class_pointer = new_meta_class; new_class->super_class = super_class; new_class->name = super_class->name; new_class->version = super_class->version; new_class->info = super_class->info; new_class->instance_size = super_class->instance_size; new_class->ivars = super_class->ivars; new_class->methods = impostor->methods; new_class->cache = &instance_method_record; /* Create the impostor meta class. */ new_meta_class->class_pointer = super_class->class_pointer->class_pointer; new_meta_class->super_class = super_class->class_pointer->super_class; new_meta_class->name = super_class->class_pointer->name; new_meta_class->version = super_class->class_pointer->version; new_meta_class->info = super_class->class_pointer->info; new_meta_class->instance_size = super_class->class_pointer->instance_size; new_meta_class->ivars = super_class->class_pointer->ivars; new_meta_class->methods = impostor->class_pointer->methods; new_meta_class->cache = &factory_method_record; /* * Delete the class from the hash table, change its name so that it * can no longer be found, then place it back into the hash table * using its new name. * * Don't worry about the class number. It is already assigned. * * Don't worry about dangling pointers. Life's a bitch. (A little bit * of memory is lost with the hash key.) */ hash_remove (class_hash_table, super_class->name); sprintf (new_name, "%s*", super_class->name); super_class->name = new_name; super_class->class_pointer->name = new_name; hash_add (&class_hash_table, super_class->name, super_class); /* * Now change all of the classes derived from super_class to be * derived from a impostor (except the impostor's impostor. */ for (node = hash_next (class_hash_table, NULL); node; node = hash_next (class_hash_table, node)) { Class_t class1 = node->value; if (class1->super_class == super_class) if (class1 != impostor) class1->super_class = new_class; } /* Place the impostor class in class hash table and assign it a class number. */ addClassToHash (new_class); /* Reinitialize the dispatch tables. */ initialize_dispatch_tables (); MUTEX_UNLOCK (runtimeMutex); /* Print out class tables if debugging. */ DEBUG_PRINTF ("dump of class tables class_poseAs\n"); debug_dump_classes (); return new_class;}/* * This routine is given a class and records all of the methods in its class * structure in the record table. */static voidrecord_methods_from_class (Class_t class){ MethodList_t method_list; method_list = class->methods; while (method_list) { record_methods_from_list (method_list); method_list = method_list->method_next; }}/* * This routine is given a list of methods and records each of the methods in * the record table. This is the routine that does the actual recording * work. */static voidrecord_methods_from_list (MethodList_t method_list){ int i; for (i = 0; i < method_list->method_count; ++i) { Method_t method = &method_list->method_list[i]; record_selector (method->method_name); }}SELsel_getUid (const STR name){ int i; for (i = 1; i <= record_entries (selector_record); ++i) if (!strcmp (name, record_get (i, selector_record))) return (SEL)i; /* Unable to locate selector. Return error value. */ return (SEL)0;}STRsel_getName (SEL selector){ return record_get ((unsigned int)selector, selector_record);}/* * Store the passed selector name in the selector record and return its * selector value (value returned by sel_getUid). */static SELrecord_selector (const char *sel){ int j; /* Find either the selector in the table or an empty slot. */ for (j = 1; j <= record_entries (selector_record); ++j) if (!strcmp (sel, record_get (j, selector_record))) return (SEL)j; /* Save the selector name. */ record_store (my_strdup (sel), selector_record); DEBUG_PRINTF ("Record: %s as: %#x\n", sel, j); return (SEL)j; }/* * Initialize the dispatch tables. This requires the initialization of the * instance_method_record and factory_method_record arrays and the arrays they * point to. * * The first array is indexed by a class number. Therefore its size is the * number of classes in the executable. The second array is indexed by a * selector id. Therefore its size is the number of unique selectors in the * application. * * When a method is sent to a object its class number is extracted from the * class structure and used in the first array. The selector id is used in * the second. The result value is a method implementation. */static voidinitialize_dispatch_tables (void){ int i; /* Check to make sure things are in place. */ assert (selector_record); /* Blow away the instance and factory method records. */ if (factory_method_record) { for (i = 1; i <= record_entries (factory_method_record); ++i) record_delete (record_get (i, factory_method_record)); record_delete (factory_method_record); } if (instance_method_record) { for (i = 1; i <= record_entries (instance_method_record); ++i) record_delete (record_get (i, instance_method_record)); record_delete (instance_method_record); } /* Reallocate the instance and factory method records. */ factory_method_record = record_new (); instance_method_record = record_new (); for (i = 1; i <= record_entries (selector_record); ++i) { record_store (record_new (), factory_method_record); record_store (record_new (), instance_method_record); } /* Fool all of the secondary records into thinking they have data. */ for (i = 1; i <= record_entries (selector_record); ++i) { struct record *record; node_ptr node; record = record_get (i, factory_method_record); for (node = hash_next (module_hash_table, NULL); node; node = hash_next (module_hash_table, node)) record_store (NULL, record); record = record_get (i, instance_method_record); for (node = hash_next (module_hash_table, NULL); node; node = hash_next (module_hash_table, node)) record_store (NULL, record); } /* For all classes fill in the methods implemented by the class and visiable from the class in the hierarchy. Those methods are assigned to the class. */ for (i = 1; i <= record_entries (selector_record); ++i) { /* i is a sel */ node_ptr node; for (node = hash_next (class_hash_table, NULL); node; node = hash_next (class_hash_table, node)) { Class_t class = node->value; MetaClass_t meta_class = class->class_pointer; int class_number = getClassNumber (class); Method_t method; /* DEBUG_PRINTF ("Assignment of sel=%s, class=%s (%#x, %#x)\n", sel_getName ((SEL)i), class->name, searchForMethodInHierarchy (class, (SEL)i), searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i)); */ method = searchForMethodInHierarchy (class, (SEL)i); if (method) record_store_at (class_number, method->method_imp, record_get (i, instance_method_record)); assert (class_number == getClassNumber ((Class_t)class->class_pointer)); method = searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i); if (method) record_store_at (class_number, method->method_imp, record_get (i, factory_method_record)); } }}/* * This method is called by the dispatch routines when a class has not been * initialized. This method is responsible for initializing the class. This * is accomplished by first testing the class itself for responding to the * +initialize method. If such a method is implemented then it is called. * Before exit, irregardless if the class implements +initialize, the class * is marked as initialized. */static void initialize_class (const char *name){ Method_t method = NULL; Class_t class = objc_getClass (name); SEL sel = sel_getUid ("initialize"); /* The class should not be initialized at this point. */ assert (!(class->info & CLS_INITIALIZED)); assert (!(class->class_pointer->info & CLS_INITIALIZED)); /* Search for the +initialize method. Call it if it exists. */ if (sel) method = searchForMethodInList (class->class_pointer->methods, sel_getName (sel)); if (method) { IMP imp; DEBUG_PRINTF ("Class: %s sending +%s\n", name, sel_getName (sel)); imp = get_imp ((Class_t)class->class_pointer, sel); assert (imp); (*imp)((id)class, sel); } /* Mark the class as initialized. */ class->info |= CLS_INITIALIZED; class->class_pointer->info |= CLS_INITIALIZED;}/* * Silly little function that checks to make sure the class hash table is * initialized. If it isn't initialized then do it. */static inline voidclass_hash_init (void){ static unsigned int init = 0; if (!init) class_hash_table = hash_new (CLASS_HASH_SIZE, (hash_func_type)hash_string, (compare_func_type)compare_strings); init = 1;}Class_t objc_getClass (const char *name){ Class_t class; /* Make sure the class hash table exists. */ class_hash_init (); class = hash_value_for_key (class_hash_table, name); return class;}MetaClass_t objc_getMetaClass (const char *name){ /* Meta classes are pointed to by the class's class_pointer. Just get the class and return its class_pointer. */ return (objc_getClass (name))->class_pointer;}voidaddClassToHash (Class_t class){ Class_t hClass; class_hash_init (); /* Check to see if the class is already in the hash table. */ hClass = hash_value_for_key (class_hash_table, class->name); if (!hClass) { /* The class isn't in the hash table. Add the class and assign a class number. */ static unsigned int class_number = 1; setClassNumber (class, class_number); setClassNumber ((Class_t)class->class_pointer, class_number); ++class_number; hash_add (&class_hash_table, class->name, class); }}void debug_dump_classes (void){ node_ptr node; int i; DEBUG_PRINTF ("class tables\n"); i = 0; for (node = hash_next (class_hash_table, NULL); node; node = hash_next (class_hash_table, node)) { Class_t class = node->value; DEBUG_PRINTF ("Class { /*%#x*/\n", class); DEBUG_PRINTF (" MetaClass_t class_pointer = %#x\n", class->class_pointer); DEBUG_PRINTF (" Class_t super_class = %#x\n", class->super_class); DEBUG_PRINTF (" char *name = %s\n", class->name); DEBUG_PRINTF (" long version = %ld\n", class->version); DEBUG_PRINTF (" long info = %#x\n", class->info); DEBUG_PRINTF (" long instance_size = %ld\n", class->instance_size); DEBUG_PRINTF (" IvarList_t ivars = %#x\n", class->ivars); DEBUG_PRINTF (" MethodList_t methods = %#x\n", class->methods); DEBUG_PRINTF (" cache_ptr cache = %#x\n", class->cache); DEBUG_PRINTF ("}[%d];\n", i++); } i = 0; for (node = hash_next (class_hash_table, NULL); node; node = hash_next (class_hash_table, node)) { Class_t class = (Class_t)((Class_t)(node->value))->class_pointer; DEBUG_PRINTF ("MetaClass { /*%#x*/\n", class); DEBUG_PRINTF (" MetaClass_t class_pointer = %#x\n", class->class_pointer); DEBUG_PRINTF (" MetaClass_t super_class = %#x\n", class->super_class); DEBUG_PRINTF (" char *name = %s\n", class->name); DEBUG_PRINTF (" long version = %ld\n", class->version); DEBUG_PRINTF (" long info = %#x\n", class->info); DEBUG_PRINTF (" long instance_size = %ld\n", class->instance_size); DEBUG_PRINTF (" IvarList_t ivars = %#x\n", class->ivars); DEBUG_PRINTF (" MethodList_t methods = %#x\n", class->methods); DEBUG_PRINTF (" cache_ptr cache = %#x\n", class->cache); DEBUG_PRINTF ("}[%d];\n", i++); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -