?? core.c
字號:
assert (initialized); /* Objective-C allows messages to be sent to a nil object. */ if (receiver) { /* Check for common programmer error. */ if (!receiver->class_pointer) { fprintf (stderr, "method %s sent to deallocated object %#x\n", sel_getName (sel), receiver); abort (); } /* Initialize the class if need be. */ if (!(receiver->class_pointer->info & CLS_INITIALIZED)) initialize_class (receiver->class_pointer->name); /* * If we're passed a object then its class_pointer is a Class. If * we're passed a Class then its class_pointer is a MetaClass. * Therefore, searching for a instance or class method * requires no special decision making here. * * Look for the method. */ imp = get_imp (receiver->class_pointer, sel); /* If the method cannot be found then perform error handling. */ if (!imp) imp = handle_runtime_error (receiver, sel); } /* Nice debugging messages if enabled. */ if (objc_trace) { printf ("trace: objc_msgSend , obj=%#x, class=%s, method=%s\n", receiver, receiver->class_pointer->name, sel_getName (sel)); fflush (stdout); } return imp;}IMP objc_msgSendSuper (Super_t super, SEL sel){ IMP imp; assert (initialized); if (!(super->class->info & CLS_INITIALIZED)) initialize_class (super->class->name); if (!(super->receiver->class_pointer->info & CLS_INITIALIZED)) initialize_class (super->receiver->class_pointer->name); imp = get_imp (super->class, sel); if (!imp) imp = handle_runtime_error (super->receiver, sel); if (objc_trace) { printf ("trace: objc_msgSendSuper , obj=%#x, class=%s, method=%s\n", super->receiver, super->receiver->class_pointer->name, sel_getName (sel)); fflush (stdout); } return imp;}/* * This function is called by objc_msgSend or objc_msgSendSuper when a * message is sent to a object which it does not recognize. */static IMP handle_runtime_error (id object, SEL sel){ IMP imp; /* * If the object recognizes the doesNotRecognize: method then we're * going to send it. */ imp = get_imp (object->class_pointer, sel_getUid ("doesNotRecognize:")); if (imp) error_static = (*imp)(object, sel_getUid ("doesNotRecognize:"), sel); else { /* * The object doesn't recognize the method. Check for * responding to error:. If it does then sent it. */ char msg[256 + strlen (sel_getName (sel)) + strlen (object->class_pointer->name)]; sprintf (msg, "%s does not recognize %s", object->class_pointer->name, sel_getName (sel)); imp = get_imp (object->class_pointer, sel_getUid ("error:")); if (imp) error_static = (*imp)(object, sel_getUid ("error:"), msg); else { /* * The object doesn't respond to doesNotRecognize: or * error:; Therefore, a default action is taken. */ fprintf (stderr, "%s\n", msg); abort (); } } /* * Either doesNotRecognize: or error: has been overridden. We have * to return that value as the default action. */ return return_error_static;}/* * This function is used by the run-time to provide a method where nil * objects can receive messages. * * This method simply returns self. */static id nil_method (id object, SEL sel, ...){ return object;}/* * This function is used by the run-time to provide a method where nil * objects can receive messages. * * This method simply returns self. * * Note: multiple thread problem area. */static id return_error_static (id object, SEL sel, ...){ return error_static;}/* * These variables provide a way for the defalut methods of object * allocation, destruction, and reallocation to be overridden. */id (*_alloc)(Class_t) = objc_object_create;id (*_dealloc)(id) = objc_object_dispose;id (*_realloc)(id, unsigned int) = objc_object_realloc;id (*_copy)(id) = objc_object_copy;void (*_error)(id, const char*, va_list) = objc_error;id objc_object_create (Class_t class){ id object; assert (class); /* * Allocate memory for the object, initialize the memory to 0, and * set the object's class_pointer. * * The object's class_pointer is the class's TEXT image. It is used by * the messager as the key to the class hash for methods. * * No need to initialize the class. That was done in objcInit. */ object = (id) xcalloc (1, class->instance_size); object->class_pointer = class; return object;}id objc_object_dispose (id object){ object->class_pointer = NULL; free (object); return nil;}id objc_object_realloc (id object, unsigned int length){ id obj; /* Can't resize a object smaller than its instance size. */ /* Don't use assert here; checks for user errors shouldn't depend on NDEBUG. */ if (length < object->class_pointer->instance_size) abort (); obj = (id) realloc (object, length); bzero ((char*)obj + object->class_pointer->instance_size, length - object->class_pointer->instance_size); return obj;}id objc_object_copy (id object){ id obj; obj = class_createInstance (object->class_pointer); bcopy (object, obj, objc_classSize (object)); return obj;}void objc_error (id object, const char *fmt, va_list ap){ vfprintf (stderr, fmt, ap); abort ();}/* Silly function to skip past a sequence of digits in a string. */static inline const char *skip_digits (const char *str){ while (isdigit (*str)) ++str; return str;}unsigned int method_getNumberOfArguments (Method_t method){ unsigned int num = 0; const char *args = &method->method_types[1]; while (*args) { /* Skip past size info. */ args = skip_digits (args); /* Argument type next. */ assert (*args); ++num; /* Step to next arg. */ ++args; } assert (num >= 2); return num;}unsigned int method_getArgumentInfo (Method_t method, int indx, const char **type, int *offset){ const char *args = skip_digits (&method->method_types[1]); int i; assert (method_getNumberOfArguments (method) >= indx); /* Step to arg. */ for (i = 0; i < indx; ++i) { ++args; args = skip_digits (args); } /* Return arg data. */ *type = args++; *offset = atoi (args); return indx;}/* This function is not thread safe. */Ivar_t object_getIvarAddress (id object, const char *name){ Class_t class = object->class_pointer; /* Here is the thread safe problem. */ Ivar_t ivar = NULL; do { IvarList_t ivars = class->ivars; int i; /* Look at all of the ivar names. */ for (i = 0; i < ivars->ivar_count; ++i) if (!strcmp (name, ivars->ivar_list[i].ivar_name)) ivar = &ivars->ivar_list[i]; /* * If the ivar wasn't found then lets look to the * super class. * * If the class is Object then the super class is NULL * and we're done. */ class = class->super_class; } while (!ivar && class); return ivar;}/* * Search for a method starting from the current class up its hierarchy. * * Return a pointer to the method's method structure if found. NULL otherwise. */Method_t searchForMethodInHierarchy (Class_t class, SEL sel){ Method_t method = NULL; const char* name; if (sel == 0) return NULL; name = sel_getName (sel); if (name == 0) return NULL; /* * Scan the method list of the class. If the method isn't found in * the list then step to its super class. */ do { method = searchForMethodInList (class->methods, name); class = class->super_class; } while (!method && class); return method;}/* * Given a linked list of method and a method's name. Search for the named * method's method structure. * * Return a pointer to the method's method structure if found. NULL otherwise. */Method_t searchForMethodInList (MethodList_t list, const char *name){ MethodList_t method_list = list; /* Check for bumbling. */ /* ??? Who generates the name? Is it the user, or part of this file? If we crash here, whose fault is it? */ assert (name); /* If not found then we'll search the list. */ while (method_list) { int i; /* Search the method list. */ for (i = 0; i < method_list->method_count; ++i) { Method_t method = &method_list->method_list[i]; if (method->method_name) if (!strcmp (method->method_name, name)) return method; } /* The method wasn't found. Follow the link to the next list of methods. */ method_list = method_list->method_next; } return NULL;}/* * This function adds a method list to a class. * * This function is typically called by another function specific to the * run-time. As such this function does not worry about thread safe issued. */void addMethodsToClass (Class_t class, MethodList_t list){ int i; /* Passing of a linked list is not allowed. Do multiple calls. */ assert (!list->method_next); /* Check for duplicates. */ for (i = 0; i < list->method_count; ++i) { Method_t method = &list->method_list[i]; if (method->method_name) /* Sometimes these are NULL */ if (searchForMethodInList (class->methods, method->method_name)) { /* * Duplication. Print a error message an change the * method name to NULL. */ fprintf (stderr, "attempt to add a existing method: %s\n", method->method_name); method->method_name = NULL; } } /* Add the methods to the class's method list. */ list->method_next = class->methods; class->methods = list;}/* * This function removes the instance and factory methods in the passed list * from a class. * * Methods are removed from a class by replacing the method's name with NULL. * * * This function is typically called by another function specific to the * run-time. As such this function does not worry about thread safe issued. */void class_removeMethods (Class_t class, MethodList_t method_list){ int i; /* Passing of a linked list is not allowed. Do multiple calls. */ assert (!method_list->method_next); /* * For each method in the list search the method lists erasing any * entries found.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -