OSDN Git Service

Changes to support ObjC as a front-end language.
[pf3gnuchains/gcc-fork.git] / gcc / objc / init.c
index 902d224..fe64bf4 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU Objective C Runtime initialization 
-   Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
    Contributed by Kresten Krab Thorup
 
 This file is part of GNU CC.
@@ -27,7 +27,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* The version number of this runtime.  This must match the number 
    defined in gcc (objc-act.c) */
-#define OBJC_VERSION 7
+#define OBJC_VERSION 8
 #define PROTOCOL_VERSION 2
 
 /* This list contains all modules currently loaded into the runtime */
@@ -40,7 +40,7 @@ static struct objc_list* unclaimed_proto_list = 0;    /* !T:MUTEX */
 static struct objc_list *uninitialized_statics = 0;    /* !T:MUTEX */
 
 /* Global runtime "write" mutex. */
-_objc_mutex_t __objc_runtime_mutex;
+objc_mutex_t __objc_runtime_mutex;
 
 /* Number of threads that are alive. */
 int __objc_runtime_threads_alive = 1;                  /* !T:MUTEX */
@@ -67,6 +67,25 @@ extern SEL
 __sel_register_typed_name (const char *name, const char *types, 
                           struct objc_selector *orig, BOOL is_const);
 
+/* Send +load to all classes and categories from a module that implement
+   this method */
+static void __objc_send_load(Module_t module);
+
+/* This list contains all the classes in the runtime system for whom their
+   superclasses are not yet know to the runtime. */
+static struct objc_list* unresolved_classes = 0;
+
+/* Static function used to references the Object and NXConstantString classes. */
+static void
+__objc_force_linking (void)
+{
+  extern void __objc_linking (void);
+  __objc_linking ();
+
+  /* Call the function to avoid compiler warning */
+  __objc_force_linking ();
+}
+
 /* Run through the statics list, removing modules as soon as all its statics
    have been initialized.  */
 static void
@@ -143,6 +162,10 @@ __objc_exec_class (Module_t module)
   /* The symbol table (defined in objc-api.h) generated by gcc */
   Symtab_t symtab = module->symtab;
 
+  /* The statics in this module */
+  struct objc_static_instances **statics
+    = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt];
+
   /* Entry used to traverse hash lists */
   struct objc_list** cell;
 
@@ -196,6 +219,7 @@ __objc_exec_class (Module_t module)
   for (i = 0; i < symtab->cls_def_cnt; ++i)
     {
       Class class = (Class) symtab->defs[i];
+      const char* superclass = (char*)class->super_class;
 
       /* Make sure we have what we think.  */
       assert (CLS_ISCLASS(class));
@@ -216,8 +240,10 @@ __objc_exec_class (Module_t module)
       if (class->protocols)
        __objc_init_protocols (class->protocols);
 
-      if (_objc_load_callback)
-       _objc_load_callback(class, 0);
+      /* Check to see if the superclass is known in this point. If it's not
+        add the class to the unresolved_classes list. */
+      if (superclass && !objc_lookup_class (superclass))
+       unresolved_classes = list_cons (class, unresolved_classes);
    }
 
   /* Process category information from the module.  */
@@ -260,8 +286,8 @@ __objc_exec_class (Module_t module)
        }
     }
 
-  if (module->statics)
-    uninitialized_statics = list_cons (module->statics, uninitialized_statics);
+  if (statics)
+    uninitialized_statics = list_cons (statics, uninitialized_statics);
   if (uninitialized_statics)
     objc_init_statics ();
 
@@ -306,23 +332,134 @@ __objc_exec_class (Module_t module)
       unclaimed_proto_list = 0;
     }
 
+  objc_send_load ();
+
   objc_mutex_unlock(__objc_runtime_mutex);
 }
 
+void objc_send_load (void)
+{
+  if (!__objc_module_list)
+    return;
+  /* Try to find out if all the classes loaded so far also have their
+     superclasses known to the runtime. We suppose that the objects that are
+     allocated in the +load method are in general of a class declared in the
+     same module. */
+  if (unresolved_classes)
+    {
+      Class class = unresolved_classes->head;
+
+      while (objc_lookup_class ((char*)class->super_class))
+       {
+         list_remove_head (&unresolved_classes);
+         if (unresolved_classes)
+           class = unresolved_classes->head;
+         else
+           break;
+       }
+
+      /*
+       * If we still have classes for which we don't have yet their super
+       * classes known to the runtime we don't send the +load messages.
+       */
+      if (unresolved_classes)
+       return;
+    }
+
+  /* Special check to allow sending messages to constant strings in +load
+     methods. If the class is not yet known, even if all the classes are known,
+     delay sending of +load. */
+  if (!objc_lookup_class ("NXConstantString"))
+    return;
+
+  /* Iterate over all modules in the __objc_module_list and call on them the
+     __objc_send_load function that sends the +load message. */
+  list_mapcar (__objc_module_list, (void(*)(void*))__objc_send_load);
+  list_free (__objc_module_list);
+  __objc_module_list = NULL;
+}
+
+static void
+__objc_send_message_in_list (MethodList_t method_list, id object, SEL op)
+{
+  while (method_list)
+    {
+      int i;
+
+      /* Search the method list. */
+      for (i = 0; i < method_list->method_count; i++)
+       {
+         Method_t mth = &method_list->method_list[i];
+
+         if (mth->method_name && sel_eq (mth->method_name, op))
+           {
+             /* The method was found. */
+             (*mth->method_imp) (object, mth->method_name);
+             break;
+           }
+       }
+      method_list = method_list->method_next;
+    }
+}
+
+static void
+__objc_send_load(Module_t module)
+{
+  /* The runtime mutex is locked in this point */
+
+  Symtab_t symtab = module->symtab;
+  static SEL load_sel = 0;
+  int i;
+
+  if (!load_sel)
+    load_sel = sel_register_name ("load");
+
+  /* Iterate thru classes defined in this module and send them the +load
+     message if they implement it. At this point all methods defined in
+     categories were added to the corresponding class, so all the +load
+     methods of categories are in their corresponding classes. */
+  for (i = 0; i < symtab->cls_def_cnt; i++)
+    {
+      Class class = (Class) symtab->defs[i];
+      MethodList_t method_list = class->class_pointer->methods;
+
+      __objc_send_message_in_list (method_list, (id)class, load_sel);
+
+      /* Call the _objc_load_callback for this class. */
+      if (_objc_load_callback)
+       _objc_load_callback(class, 0);
+    }
+
+  /* Call the _objc_load_callback for categories. Don't register the instance
+     methods as class methods for categories to root classes since they were
+     already added in the class. */
+  for (i = 0; i < symtab->cat_def_cnt; i++)
+    {
+      Category_t category = symtab->defs[i + symtab->cls_def_cnt];
+      Class class = objc_lookup_class (category->class_name);
+      
+      if (_objc_load_callback)
+       _objc_load_callback(class, category);
+    }
+}
+
 /* Sanity check the version of gcc used to compile `module'*/
 static void init_check_module_version(Module_t module)
 {
   if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module)))
     {
-      fprintf (stderr, "Module %s version %d doesn't match runtime %d\n",
-              module->name, (int)module->version, OBJC_VERSION);
+      int code;
+
       if(module->version > OBJC_VERSION)
-       fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
+       code = OBJC_ERR_OBJC_VERSION;
       else if (module->version < OBJC_VERSION)
-       fprintf (stderr, "Compiler (gcc) is out of date\n");
+       code = OBJC_ERR_GCC_VERSION;
       else
-       fprintf (stderr, "Objective C internal error -- bad Module size\n");
-      abort ();
+       code = OBJC_ERR_MODULE_SIZE;
+
+      objc_error(nil, code, "Module %s version %d doesn't match runtime %d\n",
+              module->name, (int)module->version, OBJC_VERSION);
     }
 }
 
@@ -364,11 +501,10 @@ __objc_init_protocols (struct objc_protocol_list* protos)
        }
       else if (protos->list[i]->class_pointer != proto_class)
        {
-         fprintf (stderr,
-                  "Version %d doesn't match runtime protocol version %d\n",
-                  (int)((char*)protos->list[i]->class_pointer-(char*)0),
-                  PROTOCOL_VERSION);
-         abort ();
+         objc_error(nil, OBJC_ERR_PROTOCOL_VERSION,
+                    "Version %d doesn't match runtime protocol version %d\n",
+                    (int)((char*)protos->list[i]->class_pointer-(char*)0),
+                    PROTOCOL_VERSION);
        }
     }