|
|
1.1 root 1: /* Method dispatcher and class-object creator for Objective C.
2: Copyright (C) 1992 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 2, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20: /* As a special exception, if you link this library with files
21: compiled with GCC to produce an executable, this does not cause
22: the resulting executable to be covered by the GNU General Public License.
23: This exception does not however invalidate any other reasons why
24: the executable file might be covered by the GNU General Public License. */
25:
26: #include "tconfig.h"
27: #include "assert.h"
28: #include <ctype.h>
29: #include "gstdarg.h"
30: #include <stdio.h>
31: #include "gstddef.h"
32:
33: #include "hash.h"
34: #include "objc.h"
35: #include "objc-proto.h"
36:
37:
38: #define MODULE_HASH_SIZE 32 /* Initial module hash table size.
39: Value doesn't really matter. */
40:
41: #define CLASS_HASH_SIZE 32 /* Initial number of buckets size of
42: class hash table. Value doesn't
43: really matter. */
44:
45:
46: /* Forward declare some functions. */
47: id objc_object_create (Class_t),
48: objc_object_dispose (id),
49: objc_object_realloc (id, unsigned int),
50: objc_object_copy (id);
51: void objc_error (id object, const char *fmt, va_list ap);
52: static id nil_method (id, SEL, ...);
53: static id return_error_static (id, SEL, ...);
54: static IMP handle_runtime_error (id, SEL);
55: static void initialize_dispatch_tables (void);
56: static SEL record_selector (const char*);
57: static void record_methods_from_class (Class_t);
58: static void record_methods_from_list (MethodList_t);
59: static void initialize_class (const char*);
60: /*
61: * This is a hash table of Class_t structures.
62: *
63: * At initialization the executable is searched for all Class_t structures.
64: * Since these structures are created by the compiler they are therefore
65: * located in the TEXT segment.
66: *
67: * A identical structure is allocated from the free store and initialized from
68: * its TEXT counterpart and placed in the hash table using the TEXT part as
69: * its key.
70: *
71: * Since the free store structure is now writable, additional initialization
72: * takes place such as its "info" variable, method cache allocation, and
73: * linking of all of its method and ivar lists from multiple implementations.
74: */
75: cache_ptr class_hash_table = NULL;
76:
77: /*
78: * This variable is a flag used within the messaging routines. If a
79: * application sets it to !0 then the messager will print messages sent to
80: * objects.
81: */
82: BOOL objc_trace = NO;
83:
84: /* This mutex provides a course lock for method dispatch. */
85: MUTEX runtimeMutex;
86:
87: /*
88: * This hash table is used by the initialization routines. When the
89: * constructor function (__objc_execClass) is called it is passed a pointer
90: * to a module structure. That pointer is stored in this table and its
91: * contents are processed in __objcInit.
92: */
93: cache_ptr module_hash_table = NULL;
94:
95: /*
96: * This hash table is used in the constructor subroutine to hold pointers
97: * to categories that have not been attached to a class. Constructors are
98: * received in a random order. Files may contain category implementation
99: * of objects whose constructor hasn't been executed yet. Therefore,
100: * there is no object to attach the categories.
101: *
102: * This hash table holds pointers to categories that haven't been
103: * attached to objects. As objects are processed the category hash
104: * table is searched for attachments. If a category is found for the
105: * object it is attached to the object and deleted from the hash table.
106: */
107: cache_ptr unclaimed_category_hash_table = NULL;
108:
109: /*
110: * This flag is used by the messager routines to determine if the run-time
111: * has been initialized. If the run-time isn't initialized then a
112: * initialization clean up routine is called.
113: */
114: static int initialized = 0;
115:
116: /*
117: * Records that hold pointers to arrays of records. The terminal records are
118: * method implementations.
119: *
120: * The size of the first record is the number of unique classes in the
121: * executable. The second is the number of selectors.
122: *
123: * The second record conatins methods that are visible to the class -- that is,
124: * methods that are not overriden from the classt to the root object.
125: *
126: * The cache pointers of class and meta class structures point to one of these
127: * records.
128: */
129: static struct record *instance_method_record = NULL;
130: static struct record *factory_method_record = NULL;
131:
132: /*
133: * This structure is used to translate between selectors and their ASCII
134: * representation. A NULL terminated array of char*,
135: * OBJC_SELECTOR_REFERENCES, is passed to the constructor routine:
136: * __objc_execClass. That routine places entries from that array into this
137: * structure. The location within OBJC_SELECTOR_REFERENCES where the string
138: * was taken from is replaced with a small integer, the index into the array
139: * inside selectorTranslateTable. That integer then becomes the selector.
140: *
141: * Selectors begin at 1 to numEntries. A selector outside of that range is
142: * considered an error. The selector integers are used as the first index
143: * into the instance_method_record and factory_method_record arrays.
144: */
145: static struct record *selector_record = NULL;
146:
147: /*
148: * This data structure is used in the special case where usual fatal error
149: * functions are called but have been overridden in a class. The value
150: * returned by that function is returned to the calling object. error_static
151: * holds the returned value until it is retrieved by return_error_static
152: * which returns it to the calling function.
153: */
154: static id error_static;
155:
156:
157: /* Given a class and selector, return the selector's implementation. */
158: static inline IMP
159: get_imp (Class_t class, SEL sel)
160: {
161: IMP imp = NULL;
162: imp = record_get (getClassNumber (class),
163: record_get ((unsigned int)sel, *class->cache));
164:
165: return imp;
166: }
167:
168:
169: static void
170: error (msg, arg1, arg2)
171: char *msg, *arg1, *arg2;
172: {
173: #if 0 /* There is no portable way to get the program name. Too bad. */
174: fprintf (stderr, "%s: ", programname);
175: #endif
176: fprintf (stderr, msg, arg1, arg2);
177: fprintf (stderr, "\n");
178: }
179:
180: static void
181: fatal (msg, arg1, arg2)
182: char *msg, *arg1, *arg2;
183: {
184: error (msg, arg1, arg2);
185: exit (1);
186: }
187:
188: static void *
189: xmalloc (unsigned int size)
190: {
191: void *ptr = (void *) malloc (size);
192: if (ptr == 0)
193: fatal ("virtual memory exceeded");
194: return ptr;
195: }
196:
197: static void *
198: xcalloc (unsigned int size, unsigned int units)
199: {
200: void *ptr = (void *) calloc (size, units);
201: if (ptr == 0)
202: fatal ("virtual memory exceeded");
203: return ptr;
204: }
205:
206: void *
207: __objc_xmalloc (unsigned int size)
208: {
209: void *ptr = (void *) malloc (size);
210: if (ptr == 0)
211: fatal ("virtual memory exceeded");
212: return ptr;
213: }
214:
215: void *
216: __objc_xrealloc (void *optr, unsigned int size)
217: {
218: void *ptr = (void *) realloc (optr, size);
219: if (ptr == 0)
220: fatal ("virtual memory exceeded");
221: return ptr;
222: }
223:
224: void *
225: __objc_xcalloc (unsigned int size, unsigned int units)
226: {
227: void *ptr = (void *) calloc (size, units);
228: if (ptr == 0)
229: fatal ("virtual memory exceeded");
230: return ptr;
231: }
232:
233: static inline char *
234: my_strdup (const char *str)
235: {
236: char *new = (char *) xmalloc (strlen (str) + 1);
237: strcpy (new, str);
238:
239: return new;
240: }
241:
242:
243: /*
244: * This function is called by constructor functions generated for each module
245: * compiled.
246: *
247: * The purpose of this function is to gather the module pointers so that they
248: * may be processed by the initialization clean up routine.
249: */
250: void
251: __objc_execClass (Module_t module)
252: {
253: /* Has we processed any constructors previously?
254: Flag used to indicate that some global data structures
255: need to be built. */
256: static BOOL previous_constructors = 0;
257:
258: Symtab_t symtab = module->symtab;
259: Class_t object_class;
260: node_ptr node;
261: SEL *(*selectors)[] = (SEL *(*)[])symtab->refs;
262: int i;
263: BOOL incomplete = 0;
264:
265:
266: assert (module->size == sizeof (Module));
267: DEBUG_PRINTF ("received load module: %s\n",module->name);
268:
269: /* Header file data structure hack test. */
270: assert (sizeof (Class) == sizeof (MetaClass));
271:
272: /* On the first call of this routine, initialize
273: some data structures. */
274: if (!previous_constructors) {
275:
276: /* Enable malloc debugging. This'll slow'er down! */
277: #if defined (DEBUG) && defined (NeXT)
278: malloc_debug (62);
279: #endif
280:
281: /* Allocate and initialize the mutex. */
282: MUTEX_ALLOC (&runtimeMutex);
283: MUTEX_INIT (runtimeMutex);
284:
285: /* Allocate the module hash table. */
286: module_hash_table
287: = hash_new (MODULE_HASH_SIZE, (hash_func_type)hash_ptr,
288: (compare_func_type)compare_ptrs);
289:
290: /* Allocate a table for unclaimed categories. */
291: unclaimed_category_hash_table
292: = hash_new (16, (hash_func_type)hash_ptr,
293: (compare_func_type)compare_ptrs);
294:
295: /* Allocate a master selector table if it doesn't exist. */
296: selector_record = record_new ();
297:
298: previous_constructors = 1;
299: }
300:
301: /* Save the module pointer for later processing. */
302: hash_add (&module_hash_table, module, module);
303:
304: /* Parse the classes in the load module and gather selector information. */
305: DEBUG_PRINTF ("gathering selectors from module: %s\n",module->name);
306: for (i = 0; i < symtab->cls_def_cnt; ++i) {
307: Class_t class = (Class_t)symtab->defs[i];
308:
309: /* Make sure we have what we think. */
310: assert (class->info & CLS_CLASS);
311: assert (class->class_pointer->info & CLS_META);
312: DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
313:
314: /* Store the class in the class table and assign class numbers. */
315: addClassToHash (class);
316:
317: /* Store all of the selectors in the class and meta class. */
318: record_methods_from_class (class);
319: record_methods_from_class ((Class_t)class->class_pointer);
320:
321: /* Initialize the cache pointers. */
322: class->cache = &instance_method_record;
323: class->class_pointer->cache = &factory_method_record;
324: }
325:
326: /* Replace referenced selectors. */
327: for (i=0; i < symtab->sel_ref_cnt; ++i)
328: (*selectors)[i] = record_selector ((const char*)(*selectors)[i]);
329:
330: /* Try to build the class hierarchy and initialize the data structures. */
331: object_class = objc_getClass ("Object");
332: if (object_class) {
333:
334: /* Make sure we have what we think we have. */
335: assert (object_class->class_pointer->info & CLS_META);
336: assert (object_class->info & CLS_CLASS);
337:
338: /* Connect the classes together (at least as much as we can). */
339: for (node = hash_next (class_hash_table, NULL); node;
340: node = hash_next (class_hash_table, node)) {
341: Class_t class1 = node->value;
342:
343: /* Make sure we have what we think we have. */
344: assert (class1->info & CLS_CLASS);
345: assert (class1->class_pointer->info & CLS_META);
346:
347: /* The class_pointer of all meta classes point to Object's meta class. */
348: class1->class_pointer->class_pointer = object_class->class_pointer;
349:
350: /* Assign super class pointers */
351: if (class1->super_class) {
352: Class_t aSuperClass = objc_getClass ((char*)class1->super_class);
353:
354: if (aSuperClass) {
355:
356: DEBUG_PRINTF ("making class connections for: %s\n",
357: class1->name);
358:
359: class1->super_class = aSuperClass;
360: if (class1->class_pointer->super_class)
361: class1->class_pointer->super_class = class1->super_class->class_pointer;
362:
363: /* Mark the class as initialized. */
364: class1->info |= CLS_RTI;
365: } else
366: /* Couldn't find the class's super class. */
367: incomplete = 1;
368: }
369: }
370: } else
371: /* Couldn't find class Object. */
372: incomplete = 1;
373:
374: /* Process category information from the module. */
375: for (i = 0; i < symtab->cat_def_cnt; ++i) {
376: Category_t category = symtab->defs[i + symtab->cls_def_cnt];
377: Class_t class = objc_getClass (category->class_name);
378:
379: /* If the class for the category exists then append its
380: methods. */
381: if (class) {
382:
383: DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
384: module->name,
385: class_getClassName (class));
386:
387: /* Do instance methods. */
388: if (category->instance_methods)
389: addMethodsToClass (class, category->instance_methods);
390:
391: /* Do class methods. */
392: if (category->class_methods)
393: addMethodsToClass ((Class_t)class->class_pointer, category->class_methods);
394: } else {
395: /* The object to which the category methods belong can't
396: be found. Save the information. */
397: hash_add (&unclaimed_category_hash_table, category, category);
398:
399: incomplete = 1;
400: }
401: }
402:
403: /* Scan the unclaimed category hash.
404: Attempt to attach any unclaimed categories to objects. */
405: for (node = hash_next (unclaimed_category_hash_table, NULL); node;
406: node = hash_next (unclaimed_category_hash_table, node)) {
407: Category_t category = node->value;
408: Class_t class = objc_getClass (category->class_name);
409:
410: if (class) {
411:
412: DEBUG_PRINTF ("attaching stored categories to object: %s\n",
413: class_getClassName (class));
414:
415: /* Delete this class from the hash table. */
416: hash_remove (unclaimed_category_hash_table, category);
417: node = NULL;
418:
419: if (category->instance_methods)
420: addMethodsToClass (class, category->instance_methods);
421:
422: if (category->class_methods)
423: addMethodsToClass ((Class_t)class->class_pointer,
424: category->class_methods);
425: } else
426: incomplete = 1;
427: }
428:
429: /* Can we finish the run time initialization? */
430: if (!incomplete) {
431:
432: initialize_dispatch_tables ();
433:
434: /* Debug run time test.
435: We're initialized! */
436: initialized = 1;
437:
438: /* Print out class tables if debugging. */
439: DEBUG_PRINTF ("dump of class tables from objcInit\n");
440: debug_dump_classes ();
441: }
442:
443: }
444:
445:
446: IMP
447: objc_msgSend (id receiver, SEL sel)
448: {
449: /*
450: * A method is always called by the compiler. If a method wasn't
451: * found then supply a default.
452: */
453: IMP imp = nil_method;
454:
455:
456: /* The run time must be initialized at this point.
457: Otherwise we get a message sent to a object with a bogus selector. */
458: assert (initialized);
459:
460: /* Objective-C allows messages to be sent to a nil object. */
461: if (receiver) {
462:
463: /* Check for common programmer error. */
464: if (!receiver->class_pointer) {
465: fprintf (stderr, "method %s sent to deallocated object %#x\n",
466: sel_getName (sel), receiver);
467: abort ();
468: }
469:
470: /* Initialize the class if need be. */
471: if (!(receiver->class_pointer->info & CLS_INITIALIZED))
472: initialize_class (receiver->class_pointer->name);
473:
474: /*
475: * If we're passed a object then its class_pointer is a Class. If
476: * we're passed a Class then its class_pointer is a MetaClass.
477: * Therefore, searching for a instance or class method
478: * requires no special decision making here.
479: *
480: * Look for the method.
481: */
482: imp = get_imp (receiver->class_pointer, sel);
483:
484: /* If the method cannot be found then perform error handling. */
485: if (!imp)
486: imp = handle_runtime_error (receiver, sel);
487: }
488:
489: /* Nice debugging messages if enabled. */
490: if (objc_trace) {
491: printf ("trace: objc_msgSend , obj=%#x, class=%s, method=%s\n",
492: receiver,
493: receiver->class_pointer->name,
494: sel_getName (sel));
495: fflush (stdout);
496: }
497:
498: return imp;
499: }
500:
501:
502: IMP
503: objc_msgSendSuper (Super_t super, SEL sel)
504: {
505: IMP imp;
506:
507:
508: assert (initialized);
509:
510: if (!(super->class->info & CLS_INITIALIZED))
511: initialize_class (super->class->name);
512: if (!(super->receiver->class_pointer->info & CLS_INITIALIZED))
513: initialize_class (super->receiver->class_pointer->name);
514:
515: imp = get_imp (super->class, sel);
516:
517: if (!imp)
518: imp = handle_runtime_error (super->receiver, sel);
519:
520: if (objc_trace) {
521: printf ("trace: objc_msgSendSuper , obj=%#x, class=%s, method=%s\n",
522: super->receiver,
523: super->receiver->class_pointer->name,
524: sel_getName (sel));
525: fflush (stdout);
526: }
527:
528: return imp;
529: }
530:
531:
532: /*
533: * This function is called by objc_msgSend or objc_msgSendSuper when a
534: * message is sent to a object which it does not recognize.
535: */
536: static IMP
537: handle_runtime_error (id object, SEL sel)
538: {
539: IMP imp;
540:
541:
542: /*
543: * If the object recognizes the doesNotRecognize: method then we're
544: * going to send it.
545: */
546: imp = get_imp (object->class_pointer, sel_getUid ("doesNotRecognize:"));
547: if (imp)
548: error_static = (*imp)(object, sel_getUid ("doesNotRecognize:"), sel);
549: else {
550: /*
551: * The object doesn't recognize the method. Check for
552: * responding to error:. If it does then sent it.
553: */
554: char msg[256 + strlen (sel_getName (sel))
555: + strlen (object->class_pointer->name)];
556:
557: sprintf (msg, "%s does not recognize %s",
558: object->class_pointer->name, sel_getName (sel));
559:
560: imp = get_imp (object->class_pointer, sel_getUid ("error:"));
561: if (imp)
562: error_static = (*imp)(object, sel_getUid ("error:"), msg);
563: else {
564: /*
565: * The object doesn't respond to doesNotRecognize: or
566: * error:; Therefore, a default action is taken.
567: */
568: fprintf (stderr, "%s\n", msg);
569: abort ();
570: }
571: }
572:
573: /*
574: * Either doesNotRecognize: or error: has been overridden. We have
575: * to return that value as the default action.
576: */
577: return return_error_static;
578: }
579:
580:
581: /*
582: * This function is used by the run-time to provide a method where nil
583: * objects can receive messages.
584: *
585: * This method simply returns self.
586: */
587: static id
588: nil_method (id object, SEL sel, ...)
589: {
590: return object;
591: }
592:
593:
594: /*
595: * This function is used by the run-time to provide a method where nil
596: * objects can receive messages.
597: *
598: * This method simply returns self.
599: *
600: * Note: multiple thread problem area.
601: */
602: static id
603: return_error_static (id object, SEL sel, ...)
604: {
605: return error_static;
606: }
607:
608:
609: /*
610: * These variables provide a way for the defalut methods of object
611: * allocation, destruction, and reallocation to be overridden.
612: */
613: id (*_alloc)(Class_t) = objc_object_create;
614: id (*_dealloc)(id) = objc_object_dispose;
615: id (*_realloc)(id, unsigned int) = objc_object_realloc;
616: id (*_copy)(id) = objc_object_copy;
617: void (*_error)(id, const char*, va_list) = objc_error;
618:
619:
620: id
621: objc_object_create (Class_t class)
622: {
623: id object;
624:
625:
626: assert (class);
627:
628: /*
629: * Allocate memory for the object, initialize the memory to 0, and
630: * set the object's class_pointer.
631: *
632: * The object's class_pointer is the class's TEXT image. It is used by
633: * the messager as the key to the class hash for methods.
634: *
635: * No need to initialize the class. That was done in objcInit.
636: */
637: object = (id) xcalloc (1, class->instance_size);
638: object->class_pointer = class;
639:
640: return object;
641: }
642:
643:
644: id
645: objc_object_dispose (id object)
646: {
647: object->class_pointer = NULL;
648: free (object);
649:
650: return nil;
651: }
652:
653:
654: id
655: objc_object_realloc (id object, unsigned int length)
656: {
657: id obj;
658: /* Can't resize a object smaller than its instance size. */
659: /* Don't use assert here;
660: checks for user errors shouldn't depend on NDEBUG. */
661: if (length < object->class_pointer->instance_size)
662: abort ();
663:
664: obj = (id) realloc (object, length);
665: bzero ((char*)obj + object->class_pointer->instance_size,
666: length - object->class_pointer->instance_size);
667:
668: return obj;
669: }
670:
671:
672: id
673: objc_object_copy (id object)
674: {
675: id obj;
676: obj = class_createInstance (object->class_pointer);
677: bcopy (object, obj, objc_classSize (object));
678:
679: return obj;
680: }
681:
682:
683: void
684: objc_error (id object, const char *fmt, va_list ap)
685: {
686: vfprintf (stderr, fmt, ap);
687: abort ();
688: }
689:
690:
691: /* Silly function to skip past a sequence of digits in a string. */
692: static inline const char *
693: skip_digits (const char *str)
694: {
695: while (isdigit (*str))
696: ++str;
697:
698: return str;
699: }
700:
701:
702: unsigned int
703: method_getNumberOfArguments (Method_t method)
704: {
705: unsigned int num = 0;
706: const char *args = &method->method_types[1];
707:
708:
709: while (*args) {
710:
711: /* Skip past size info. */
712: args = skip_digits (args);
713:
714: /* Argument type next. */
715: assert (*args);
716: ++num;
717:
718: /* Step to next arg. */
719: ++args;
720: }
721:
722: assert (num >= 2);
723: return num;
724: }
725:
726:
727: unsigned int
728: method_getArgumentInfo (Method_t method, int indx, const char **type,
729: int *offset)
730: {
731: const char *args = skip_digits (&method->method_types[1]);
732: int i;
733:
734:
735: assert (method_getNumberOfArguments (method) >= indx);
736:
737: /* Step to arg. */
738: for (i = 0; i < indx; ++i) {
739: ++args;
740: args = skip_digits (args);
741: }
742:
743: /* Return arg data. */
744: *type = args++;
745: *offset = atoi (args);
746:
747: return indx;
748: }
749:
750:
751: /* This function is not thread safe. */
752: Ivar_t
753: object_getIvarAddress (id object, const char *name)
754: {
755: Class_t class = object->class_pointer; /* Here is the thread safe problem. */
756: Ivar_t ivar = NULL;
757:
758:
759: do {
760: IvarList_t ivars = class->ivars;
761: int i;
762:
763: /* Look at all of the ivar names. */
764: for (i = 0; i < ivars->ivar_count; ++i)
765: if (!strcmp (name, ivars->ivar_list[i].ivar_name))
766: ivar = &ivars->ivar_list[i];
767:
768: /*
769: * If the ivar wasn't found then lets look to the
770: * super class.
771: *
772: * If the class is Object then the super class is NULL
773: * and we're done.
774: */
775: class = class->super_class;
776:
777: } while (!ivar && class);
778:
779: return ivar;
780: }
781:
782:
783: /*
784: * Search for a method starting from the current class up its hierarchy.
785: *
786: * Return a pointer to the method's method structure if found. NULL otherwise.
787: */
788: Method_t
789: searchForMethodInHierarchy (Class_t class, SEL sel)
790: {
791: Method_t method = NULL;
792: const char* name;
793:
794: if (sel == 0)
795: return NULL;
796:
797: name = sel_getName (sel);
798:
799: if (name == 0)
800: return NULL;
801:
802: /*
803: * Scan the method list of the class. If the method isn't found in
804: * the list then step to its super class.
805: */
806: do {
807:
808: method = searchForMethodInList (class->methods, name);
809: class = class->super_class;
810:
811: } while (!method && class);
812:
813: return method;
814: }
815:
816:
817: /*
818: * Given a linked list of method and a method's name. Search for the named
819: * method's method structure.
820: *
821: * Return a pointer to the method's method structure if found. NULL otherwise.
822: */
823: Method_t
824: searchForMethodInList (MethodList_t list, const char *name)
825: {
826: MethodList_t method_list = list;
827:
828:
829: /* Check for bumbling. */
830: /* ??? Who generates the name? Is it the user, or part of this file?
831: If we crash here, whose fault is it? */
832: assert (name);
833:
834: /* If not found then we'll search the list. */
835: while (method_list) {
836: int i;
837:
838: /* Search the method list. */
839: for (i = 0; i < method_list->method_count; ++i) {
840: Method_t method = &method_list->method_list[i];
841:
842: if (method->method_name)
843: if (!strcmp (method->method_name, name))
844: return method;
845: }
846:
847: /* The method wasn't found. Follow the link to the next list of
848: methods. */
849: method_list = method_list->method_next;
850: }
851:
852: return NULL;
853: }
854:
855:
856: /*
857: * This function adds a method list to a class.
858: *
859: * This function is typically called by another function specific to the
860: * run-time. As such this function does not worry about thread safe issued.
861: */
862: void
863: addMethodsToClass (Class_t class, MethodList_t list)
864: {
865: int i;
866:
867:
868: /* Passing of a linked list is not allowed. Do multiple calls. */
869: assert (!list->method_next);
870:
871: /* Check for duplicates. */
872: for (i = 0; i < list->method_count; ++i) {
873: Method_t method = &list->method_list[i];
874:
875: if (method->method_name) /* Sometimes these are NULL */
876: if (searchForMethodInList (class->methods, method->method_name)) {
877: /*
878: * Duplication. Print a error message an change the
879: * method name to NULL.
880: */
881: fprintf (stderr, "attempt to add a existing method: %s\n",
882: method->method_name);
883: method->method_name = NULL;
884: }
885: }
886:
887: /* Add the methods to the class's method list. */
888: list->method_next = class->methods;
889: class->methods = list;
890: }
891:
892:
893: /*
894: * This function removes the instance and factory methods in the passed list
895: * from a class.
896: *
897: * Methods are removed from a class by replacing the method's name with NULL.
898: *
899: *
900: * This function is typically called by another function specific to the
901: * run-time. As such this function does not worry about thread safe issued.
902: */
903: void
904: class_removeMethods (Class_t class, MethodList_t method_list)
905: {
906: int i;
907:
908:
909: /* Passing of a linked list is not allowed. Do multiple calls. */
910: assert (!method_list->method_next);
911:
912: /*
913: * For each method in the list search the method lists erasing any
914: * entries found.
915: */
916: for (i = 0; i < method_list->method_count; ++i) {
917: Method_t kill_method = &method_list->method_list[i];
918: Method_t method;
919:
920: /* Remove any instance method found. */
921: method = searchForMethodInList (class->methods,
922: kill_method->method_name);
923: if (method)
924: method->method_name = NULL;
925:
926: /* Remove any factory method found. */
927: method = searchForMethodInList (class->class_pointer->methods,
928: kill_method->method_name);
929: if (method)
930: method->method_name = NULL;
931: }
932: }
933:
934:
935: /*
936: * This is a incomplete implementation of posing. This function does the
937: * bulk of the work but does not initialize the class method caches. That is
938: * a run-time specific operation.
939: *
940: * I implement posing by hiding SUPER_CLASS, creating new class and meta
941: * class structures, initializing it with IMPOSTOR, and changing it such
942: * that it is identified as SUPER_CLASS. SUPER_CLASS remains in the
943: * hierarchy but is inaccessible by the means. The class hierarchy is then re
944: * arranged such that all of the subclasses of SUPER_CLASS now inherit from
945: * the new class structures -- except the impostor itself. The only dramatic
946: * effect on the application is that subclasses of SUPER_CLASS cannot do a
947: * [ .... superClass ] and expect their real super class.
948: */
949: Class_t
950: class_poseAs (Class_t impostor, Class_t super_class)
951: {
952: Class_t new_class = (Class_t) calloc (1, sizeof (Class));
953: MetaClass_t new_meta_class = (MetaClass_t) calloc (1, sizeof (MetaClass));
954: node_ptr node;
955: char *new_name = (char *) malloc (strlen (super_class->name) + 12);
956:
957:
958: assert (new_class);
959: assert (new_meta_class);
960: assert (new_name);
961:
962: /* No dispatching while the the posing class is being built.
963: The dispatch tables will be hacked on. */
964: MUTEX_LOCK (runtimeMutex);
965:
966: assert (impostor->info & CLS_CLASS);
967: assert (super_class->info & CLS_CLASS);
968:
969: assert (impostor->instance_size == super_class->instance_size);
970:
971: /* Create the impostor class. */
972: new_class->class_pointer = new_meta_class;
973: new_class->super_class = super_class;
974: new_class->name = super_class->name;
975: new_class->version = super_class->version;
976: new_class->info = super_class->info;
977: new_class->instance_size = super_class->instance_size;
978: new_class->ivars = super_class->ivars;
979: new_class->methods = impostor->methods;
980: new_class->cache = &instance_method_record;
981:
982: /* Create the impostor meta class. */
983: new_meta_class->class_pointer = super_class->class_pointer->class_pointer;
984: new_meta_class->super_class = super_class->class_pointer->super_class;
985: new_meta_class->name = super_class->class_pointer->name;
986: new_meta_class->version = super_class->class_pointer->version;
987: new_meta_class->info = super_class->class_pointer->info;
988: new_meta_class->instance_size = super_class->class_pointer->instance_size;
989: new_meta_class->ivars = super_class->class_pointer->ivars;
990: new_meta_class->methods = impostor->class_pointer->methods;
991: new_meta_class->cache = &factory_method_record;
992:
993: /*
994: * Delete the class from the hash table, change its name so that it
995: * can no longer be found, then place it back into the hash table
996: * using its new name.
997: *
998: * Don't worry about the class number. It is already assigned.
999: *
1000: * Don't worry about dangling pointers. Life's a bitch. (A little bit
1001: * of memory is lost with the hash key.)
1002: */
1003: hash_remove (class_hash_table, super_class->name);
1004: sprintf (new_name, "%s*", super_class->name);
1005: super_class->name = new_name;
1006: super_class->class_pointer->name = new_name;
1007: hash_add (&class_hash_table, super_class->name, super_class);
1008:
1009: /*
1010: * Now change all of the classes derived from super_class to be
1011: * derived from a impostor (except the impostor's impostor.
1012: */
1013: for (node = hash_next (class_hash_table, NULL); node;
1014: node = hash_next (class_hash_table, node)) {
1015:
1016: Class_t class1 = node->value;
1017:
1018: if (class1->super_class == super_class)
1019: if (class1 != impostor)
1020: class1->super_class = new_class;
1021: }
1022:
1023: /* Place the impostor class in class hash table
1024: and assign it a class number. */
1025: addClassToHash (new_class);
1026:
1027: /* Reinitialize the dispatch tables. */
1028: initialize_dispatch_tables ();
1029:
1030: MUTEX_UNLOCK (runtimeMutex);
1031:
1032: /* Print out class tables if debugging. */
1033: DEBUG_PRINTF ("dump of class tables class_poseAs\n");
1034: debug_dump_classes ();
1035:
1036: return new_class;
1037: }
1038:
1039:
1040: /*
1041: * This routine is given a class and records all of the methods in its class
1042: * structure in the record table.
1043: */
1044: static void
1045: record_methods_from_class (Class_t class)
1046: {
1047: MethodList_t method_list;
1048:
1049:
1050: method_list = class->methods;
1051: while (method_list) {
1052: record_methods_from_list (method_list);
1053: method_list = method_list->method_next;
1054: }
1055: }
1056:
1057:
1058: /*
1059: * This routine is given a list of methods and records each of the methods in
1060: * the record table. This is the routine that does the actual recording
1061: * work.
1062: */
1063: static void
1064: record_methods_from_list (MethodList_t method_list)
1065: {
1066: int i;
1067:
1068:
1069: for (i = 0; i < method_list->method_count; ++i) {
1070: Method_t method = &method_list->method_list[i];
1071:
1072: record_selector (method->method_name);
1073: }
1074: }
1075:
1076:
1077: SEL
1078: sel_getUid (const STR name)
1079: {
1080: int i;
1081:
1082:
1083: for (i = 1; i <= record_entries (selector_record); ++i)
1084: if (!strcmp (name, record_get (i, selector_record)))
1085: return (SEL)i;
1086:
1087: /* Unable to locate selector. Return error value. */
1088: return (SEL)0;
1089: }
1090:
1091:
1092: STR
1093: sel_getName (SEL selector)
1094: {
1095: return record_get ((unsigned int)selector, selector_record);
1096: }
1097:
1098:
1099: /*
1100: * Store the passed selector name in the selector record and return its
1101: * selector value (value returned by sel_getUid).
1102: */
1103: static SEL
1104: record_selector (const char *sel)
1105: {
1106: int j;
1107:
1108:
1109: /* Find either the selector in the table or an empty slot. */
1110: for (j = 1; j <= record_entries (selector_record); ++j)
1111: if (!strcmp (sel, record_get (j, selector_record)))
1112: return (SEL)j;
1113:
1114: /* Save the selector name. */
1115: record_store (my_strdup (sel), selector_record);
1116: DEBUG_PRINTF ("Record: %s as: %#x\n", sel, j);
1117:
1118: return (SEL)j;
1119: }
1120:
1121:
1122: /*
1123: * Initialize the dispatch tables. This requires the initialization of the
1124: * instance_method_record and factory_method_record arrays and the arrays they
1125: * point to.
1126: *
1127: * The first array is indexed by a class number. Therefore its size is the
1128: * number of classes in the executable. The second array is indexed by a
1129: * selector id. Therefore its size is the number of unique selectors in the
1130: * application.
1131: *
1132: * When a method is sent to a object its class number is extracted from the
1133: * class structure and used in the first array. The selector id is used in
1134: * the second. The result value is a method implementation.
1135: */
1136: static void
1137: initialize_dispatch_tables (void)
1138: {
1139: int i;
1140:
1141:
1142: /* Check to make sure things are in place. */
1143: assert (selector_record);
1144:
1145: /* Blow away the instance and factory method records. */
1146: if (factory_method_record) {
1147: for (i = 1; i <= record_entries (factory_method_record); ++i)
1148: record_delete (record_get (i, factory_method_record));
1149: record_delete (factory_method_record);
1150: }
1151: if (instance_method_record) {
1152: for (i = 1; i <= record_entries (instance_method_record); ++i)
1153: record_delete (record_get (i, instance_method_record));
1154: record_delete (instance_method_record);
1155: }
1156:
1157: /* Reallocate the instance and factory method records. */
1158: factory_method_record = record_new ();
1159: instance_method_record = record_new ();
1160: for (i = 1; i <= record_entries (selector_record); ++i) {
1161: record_store (record_new (), factory_method_record);
1162: record_store (record_new (), instance_method_record);
1163: }
1164:
1165: /* Fool all of the secondary records into thinking they have data. */
1166: for (i = 1; i <= record_entries (selector_record); ++i) {
1167: struct record *record;
1168: node_ptr node;
1169:
1170: record = record_get (i, factory_method_record);
1171: for (node = hash_next (module_hash_table, NULL); node;
1172: node = hash_next (module_hash_table, node))
1173: record_store (NULL, record);
1174:
1175: record = record_get (i, instance_method_record);
1176: for (node = hash_next (module_hash_table, NULL); node;
1177: node = hash_next (module_hash_table, node))
1178: record_store (NULL, record);
1179: }
1180:
1181: /* For all classes fill in the methods implemented by the class and visiable
1182: from the class in the hierarchy. Those methods are assigned to the
1183: class. */
1184: for (i = 1; i <= record_entries (selector_record); ++i) { /* i is a sel */
1185: node_ptr node;
1186:
1187: for (node = hash_next (class_hash_table, NULL); node;
1188: node = hash_next (class_hash_table, node)) {
1189: Class_t class = node->value;
1190: MetaClass_t meta_class = class->class_pointer;
1191: int class_number = getClassNumber (class);
1192: Method_t method;
1193:
1194: /* DEBUG_PRINTF ("Assignment of sel=%s, class=%s (%#x, %#x)\n",
1195: sel_getName ((SEL)i), class->name,
1196: searchForMethodInHierarchy (class, (SEL)i),
1197: searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i)); */
1198:
1199: method = searchForMethodInHierarchy (class, (SEL)i);
1200: if (method)
1201: record_store_at (class_number, method->method_imp,
1202: record_get (i, instance_method_record));
1203:
1204: assert (class_number == getClassNumber ((Class_t)class->class_pointer));
1205: method = searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i);
1206: if (method)
1207: record_store_at (class_number, method->method_imp,
1208: record_get (i, factory_method_record));
1209: }
1210: }
1211: }
1212:
1213:
1214: /*
1215: * This method is called by the dispatch routines when a class has not been
1216: * initialized. This method is responsible for initializing the class. This
1217: * is accomplished by first testing the class itself for responding to the
1218: * +initialize method. If such a method is implemented then it is called.
1219: * Before exit, irregardless if the class implements +initialize, the class
1220: * is marked as initialized.
1221: */
1222: static void
1223: initialize_class (const char *name)
1224: {
1225: Method_t method = NULL;
1226: Class_t class = objc_getClass (name);
1227: SEL sel = sel_getUid ("initialize");
1228:
1229:
1230: /* The class should not be initialized at this point. */
1231: assert (!(class->info & CLS_INITIALIZED));
1232: assert (!(class->class_pointer->info & CLS_INITIALIZED));
1233:
1234: /* Search for the +initialize method.
1235: Call it if it exists. */
1236: if (sel)
1237: method = searchForMethodInList (class->class_pointer->methods,
1238: sel_getName (sel));
1239: if (method) {
1240: IMP imp;
1241:
1242: DEBUG_PRINTF ("Class: %s sending +%s\n",
1243: name, sel_getName (sel));
1244: imp = get_imp ((Class_t)class->class_pointer, sel);
1245: assert (imp);
1246: (*imp)((id)class, sel);
1247: }
1248:
1249: /* Mark the class as initialized. */
1250: class->info |= CLS_INITIALIZED;
1251: class->class_pointer->info |= CLS_INITIALIZED;
1252: }
1253:
1254:
1255: /*
1256: * Silly little function that checks to make sure the class hash table is
1257: * initialized. If it isn't initialized then do it.
1258: */
1259: static inline void
1260: class_hash_init (void)
1261: {
1262: static unsigned int init = 0;
1263:
1264:
1265: if (!init)
1266: class_hash_table = hash_new (CLASS_HASH_SIZE,
1267: (hash_func_type)hash_string,
1268: (compare_func_type)compare_strings);
1269: init = 1;
1270: }
1271:
1272:
1273: Class_t
1274: objc_getClass (const char *name)
1275: {
1276: Class_t class;
1277:
1278:
1279: /* Make sure the class hash table exists. */
1280: class_hash_init ();
1281:
1282: class = hash_value_for_key (class_hash_table, name);
1283:
1284: return class;
1285: }
1286:
1287:
1288: MetaClass_t
1289: objc_getMetaClass (const char *name)
1290: {
1291: /* Meta classes are pointed to by the class's class_pointer.
1292: Just get the class and return its class_pointer. */
1293: return (objc_getClass (name))->class_pointer;
1294: }
1295:
1296:
1297: void
1298: addClassToHash (Class_t class)
1299: {
1300: Class_t hClass;
1301:
1302:
1303: class_hash_init ();
1304:
1305: /* Check to see if the class is already in the hash table. */
1306: hClass = hash_value_for_key (class_hash_table, class->name);
1307: if (!hClass) {
1308:
1309: /* The class isn't in the hash table. Add the class and
1310: assign a class number. */
1311: static unsigned int class_number = 1;
1312:
1313: setClassNumber (class, class_number);
1314: setClassNumber ((Class_t)class->class_pointer, class_number);
1315: ++class_number;
1316:
1317: hash_add (&class_hash_table, class->name, class);
1318: }
1319: }
1320:
1321:
1322: void
1323: debug_dump_classes (void)
1324: {
1325: node_ptr node;
1326: int i;
1327:
1328:
1329: DEBUG_PRINTF ("class tables\n");
1330: i = 0;
1331: for (node = hash_next (class_hash_table, NULL); node;
1332: node = hash_next (class_hash_table, node)) {
1333:
1334: Class_t class = node->value;
1335:
1336: DEBUG_PRINTF ("Class { /*%#x*/\n", class);
1337: DEBUG_PRINTF (" MetaClass_t class_pointer = %#x\n", class->class_pointer);
1338: DEBUG_PRINTF (" Class_t super_class = %#x\n", class->super_class);
1339: DEBUG_PRINTF (" char *name = %s\n", class->name);
1340: DEBUG_PRINTF (" long version = %ld\n", class->version);
1341: DEBUG_PRINTF (" long info = %#x\n", class->info);
1342: DEBUG_PRINTF (" long instance_size = %ld\n", class->instance_size);
1343: DEBUG_PRINTF (" IvarList_t ivars = %#x\n", class->ivars);
1344: DEBUG_PRINTF (" MethodList_t methods = %#x\n", class->methods);
1345: DEBUG_PRINTF (" cache_ptr cache = %#x\n", class->cache);
1346: DEBUG_PRINTF ("}[%d];\n", i++);
1347: }
1348:
1349: i = 0;
1350: for (node = hash_next (class_hash_table, NULL); node;
1351: node = hash_next (class_hash_table, node)) {
1352:
1353: Class_t class = (Class_t)((Class_t)(node->value))->class_pointer;
1354:
1355: DEBUG_PRINTF ("MetaClass { /*%#x*/\n", class);
1356: DEBUG_PRINTF (" MetaClass_t class_pointer = %#x\n", class->class_pointer);
1357: DEBUG_PRINTF (" MetaClass_t super_class = %#x\n", class->super_class);
1358: DEBUG_PRINTF (" char *name = %s\n", class->name);
1359: DEBUG_PRINTF (" long version = %ld\n", class->version);
1360: DEBUG_PRINTF (" long info = %#x\n", class->info);
1361: DEBUG_PRINTF (" long instance_size = %ld\n", class->instance_size);
1362: DEBUG_PRINTF (" IvarList_t ivars = %#x\n", class->ivars);
1363: DEBUG_PRINTF (" MethodList_t methods = %#x\n", class->methods);
1364: DEBUG_PRINTF (" cache_ptr cache = %#x\n", class->cache);
1365: DEBUG_PRINTF ("}[%d];\n", i++);
1366: }
1367: }
1368:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.