summaryrefslogtreecommitdiff
path: root/contrib/gcc/objc/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/objc/init.c')
-rw-r--r--contrib/gcc/objc/init.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/contrib/gcc/objc/init.c b/contrib/gcc/objc/init.c
new file mode 100644
index 000000000000..9560dc20234a
--- /dev/null
+++ b/contrib/gcc/objc/init.c
@@ -0,0 +1,363 @@
+/* GNU Objective C Runtime initialization
+ Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Contributed by Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2, or (at your option) any later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along with
+GNU CC; see the file COPYING. If not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h"
+
+/* The version number of this runtime. This must match the number
+ defined in gcc (objc-act.c) */
+#define OBJC_VERSION 7
+#define PROTOCOL_VERSION 2
+
+/* This list contains all modules currently loaded into the runtime */
+static struct objc_list* __objc_module_list = 0;
+
+/* This list contains all proto_list's not yet assigned class links */
+static struct objc_list* unclaimed_proto_list = 0;
+
+/* List of unresolved static instances. */
+static struct objc_list *uninitialized_statics;
+
+/* Check compiler vs runtime version */
+static void init_check_module_version (Module_t);
+
+/* Assign isa links to protos */
+static void __objc_init_protocols (struct objc_protocol_list* protos);
+
+/* Add protocol to class */
+static void __objc_class_add_protocols (Class, struct objc_protocol_list*);
+
+/* This is a hook which is called by __objc_exec_class every time a class
+ or a category is loaded into the runtime. This may e.g. help a
+ dynamic loader determine the classes that have been loaded when
+ an object file is dynamically linked in */
+void (*_objc_load_callback)(Class class, Category* category) = 0;
+
+/* Is all categories/classes resolved? */
+BOOL __objc_dangling_categories = NO;
+
+extern SEL
+__sel_register_typed_name (const char *name, const char *types,
+ struct objc_selector *orig);
+
+/* Run through the statics list, removing modules as soon as all its statics
+ have been initialized. */
+static void
+objc_init_statics ()
+{
+ struct objc_list **cell = &uninitialized_statics;
+ struct objc_static_instances **statics_in_module;
+
+ while (*cell)
+ {
+ int module_initialized = 1;
+
+ for (statics_in_module = (*cell)->head;
+ *statics_in_module; statics_in_module++)
+ {
+ struct objc_static_instances *statics = *statics_in_module;
+ Class class = objc_lookup_class (statics->class_name);
+
+ if (!class)
+ module_initialized = 0;
+ /* Actually, the static's class_pointer will be NULL when we
+ haven't been here before. However, the comparison is to be
+ reminded of taking into account class posing and to think about
+ possible semantics... */
+ else if (class != statics->instances[0]->class_pointer)
+ {
+ id *inst;
+
+ for (inst = &statics->instances[0]; *inst; inst++)
+ {
+ (*inst)->class_pointer = class;
+
+ /* ??? Make sure the object will not be freed. With
+ refcounting, invoke `-retain'. Without refcounting, do
+ nothing and hope that `-free' will never be invoked. */
+
+ /* ??? Send the object an `-initStatic' or something to
+ that effect now or later on? What are the semantics of
+ statically allocated instances, besides the trivial
+ NXConstantString, anyway? */
+ }
+ }
+ }
+ if (module_initialized)
+ {
+ /* Remove this module from the uninitialized list. */
+ struct objc_list *this = *cell;
+ *cell = this->tail;
+ free (this);
+ }
+ else
+ cell = &(*cell)->tail;
+ }
+} /* objc_init_statics */
+
+/* This function is called by constructor functions generated for each
+ module compiled. (_GLOBAL_$I$...) The purpose of this function is to
+ gather the module pointers so that they may be processed by the
+ initialization routines as soon as possible */
+
+void
+__objc_exec_class (Module_t module)
+{
+ /* Have we processed any constructors previously? This flag is used to
+ indicate that some global data structures need to be built. */
+ static BOOL previous_constructors = 0;
+
+ static struct objc_list* unclaimed_categories = 0;
+
+ /* The symbol table (defined in objc-api.h) generated by gcc */
+ Symtab_t symtab = module->symtab;
+
+ /* Entry used to traverse hash lists */
+ struct objc_list** cell;
+
+ /* The table of selector references for this module */
+ SEL selectors = symtab->refs;
+
+ /* dummy counter */
+ int i;
+
+ DEBUG_PRINTF ("received module: %s\n", module->name);
+
+ /* check gcc version */
+ init_check_module_version(module);
+
+ /* On the first call of this routine, initialize some data structures. */
+ if (!previous_constructors)
+ {
+ __objc_init_selector_tables();
+ __objc_init_class_tables();
+ __objc_init_dispatch_tables();
+ previous_constructors = 1;
+ }
+
+ /* Save the module pointer for later processing. (not currently used) */
+ __objc_module_list = list_cons(module, __objc_module_list);
+
+ /* Replace referenced selectors from names to SEL's. */
+ if (selectors)
+ {
+ for (i = 0; selectors[i].sel_id; ++i)
+ {
+ const char *name, *type;
+ name = (char*)selectors[i].sel_id;
+ type = (char*)selectors[i].sel_types;
+ __sel_register_typed_name (name, type,
+ (struct objc_selector*)&(selectors[i]));
+ }
+ }
+
+ /* Parse the classes in the load module and gather selector information. */
+ DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
+ for (i = 0; i < symtab->cls_def_cnt; ++i)
+ {
+ Class class = (Class) symtab->defs[i];
+
+ /* Make sure we have what we think. */
+ assert (CLS_ISCLASS(class));
+ assert (CLS_ISMETA(class->class_pointer));
+ DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
+
+ /* Store the class in the class table and assign class numbers. */
+ __objc_add_class_to_hash (class);
+
+ /* Register all of the selectors in the class and meta class. */
+ __objc_register_selectors_from_class (class);
+ __objc_register_selectors_from_class ((Class) class->class_pointer);
+
+ /* Install the fake dispatch tables */
+ __objc_install_premature_dtable(class);
+ __objc_install_premature_dtable(class->class_pointer);
+
+ if (class->protocols)
+ __objc_init_protocols (class->protocols);
+
+ if (_objc_load_callback)
+ _objc_load_callback(class, 0);
+ }
+
+ /* Process category information from the module. */
+ 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 the class for the category exists then append its methods. */
+ if (class)
+ {
+
+ DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
+ module->name,
+ class->name);
+
+ /* Do instance methods. */
+ if (category->instance_methods)
+ class_add_method_list (class, category->instance_methods);
+
+ /* Do class methods. */
+ if (category->class_methods)
+ class_add_method_list ((Class) class->class_pointer,
+ category->class_methods);
+
+ if (category->protocols)
+ {
+ __objc_init_protocols (category->protocols);
+ __objc_class_add_protocols (class, category->protocols);
+ }
+
+ if (_objc_load_callback)
+ _objc_load_callback(class, category);
+ }
+ else
+ {
+ /* The object to which the category methods belong can't be found.
+ Save the information. */
+ unclaimed_categories = list_cons(category, unclaimed_categories);
+ }
+ }
+
+ if (module->statics)
+ uninitialized_statics = list_cons (module->statics, uninitialized_statics);
+ if (uninitialized_statics)
+ objc_init_statics ();
+
+ /* Scan the unclaimed category hash. Attempt to attach any unclaimed
+ categories to objects. */
+ for (cell = &unclaimed_categories;
+ *cell;
+ ({ if (*cell) cell = &(*cell)->tail; }))
+ {
+ Category_t category = (*cell)->head;
+ Class class = objc_lookup_class (category->class_name);
+
+ if (class)
+ {
+ DEBUG_PRINTF ("attaching stored categories to object: %s\n",
+ class->name);
+
+ list_remove_head (cell);
+
+ if (category->instance_methods)
+ class_add_method_list (class, category->instance_methods);
+
+ if (category->class_methods)
+ class_add_method_list ((Class) class->class_pointer,
+ category->class_methods);
+
+ if (category->protocols)
+ {
+ __objc_init_protocols (category->protocols);
+ __objc_class_add_protocols (class, category->protocols);
+ }
+
+ if (_objc_load_callback)
+ _objc_load_callback(class, category);
+ }
+ }
+
+ if (unclaimed_proto_list && objc_lookup_class ("Protocol"))
+ {
+ list_mapcar (unclaimed_proto_list,(void(*)(void*))__objc_init_protocols);
+ list_free (unclaimed_proto_list);
+ unclaimed_proto_list = 0;
+ }
+
+}
+
+/* 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);
+ if(module->version > OBJC_VERSION)
+ fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
+ else if (module->version < OBJC_VERSION)
+ fprintf (stderr, "Compiler (gcc) is out of date\n");
+ else
+ fprintf (stderr, "Objective C internal error -- bad Module size\n");
+ abort ();
+ }
+}
+
+static void
+__objc_init_protocols (struct objc_protocol_list* protos)
+{
+ int i;
+ static Class proto_class = 0;
+
+ if (! protos)
+ return;
+
+ if (!proto_class)
+ proto_class = objc_lookup_class("Protocol");
+
+ if (!proto_class)
+ {
+ unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
+ return;
+ }
+
+#if 0
+ assert (protos->next == 0); /* only single ones allowed */
+#endif
+
+ for(i = 0; i < protos->count; i++)
+ {
+ struct objc_protocol* aProto = protos->list[i];
+ if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
+ {
+ /* assign class pointer */
+ aProto->class_pointer = proto_class;
+
+ /* init super protocols */
+ __objc_init_protocols (aProto->protocol_list);
+ }
+ 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 ();
+ }
+ }
+}
+
+static void __objc_class_add_protocols (Class class,
+ struct objc_protocol_list* protos)
+{
+ /* Well... */
+ if (! protos)
+ return;
+
+ /* Add it... */
+ protos->next = class->protocols;
+ class->protocols = protos;
+}