1/* GNU Objective C Runtime class related functions
2   Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3   Contributed by Kresten Krab Thorup and Dennis Glatting.
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 2, or (at your option) any later version.
10
11GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14details.
15
16You should have received a copy of the GNU General Public License along with
17GNU CC; see the file COPYING.  If not, write to the Free Software
18Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20/* As a special exception, if you link this library with files compiled with
21   GCC to produce an executable, this does not cause the resulting executable
22   to be covered by the GNU General Public License. This exception does not
23   however invalidate any other reasons why the executable file might be
24   covered by the GNU General Public License.  */
25
26#include "runtime.h"		/* the kitchen sink */
27#include "sarray.h"
28
29/* The table of classname->class.  Used for objc_lookup_class and friends */
30static cache_ptr __objc_class_hash = 0;                 /* !T:MUTEX */
31
32/* This is a hook which is called by objc_get_class and
33   objc_lookup_class if the runtime is not able to find the class.
34   This may e.g. try to load in the class using dynamic loading */
35Class (*_objc_lookup_class)(const char* name) = 0;      /* !T:SAFE */
36
37
38/* True when class links has been resolved */
39BOOL __objc_class_links_resolved = NO;                  /* !T:UNUSED */
40
41
42/* Initial number of buckets size of class hash table. */
43#define CLASS_HASH_SIZE 32
44
45void __objc_init_class_tables()
46{
47  /* Allocate the class hash table */
48
49  if(__objc_class_hash)
50    return;
51
52  objc_mutex_lock(__objc_runtime_mutex);
53
54  __objc_class_hash
55    =  hash_new (CLASS_HASH_SIZE,
56		 (hash_func_type) hash_string,
57		 (compare_func_type) compare_strings);
58
59  objc_mutex_unlock(__objc_runtime_mutex);
60}
61
62/* This function adds a class to the class hash table, and assigns the
63   class a number, unless it's already known */
64void
65__objc_add_class_to_hash(Class class)
66{
67  Class h_class;
68
69  objc_mutex_lock(__objc_runtime_mutex);
70
71  /* make sure the table is there */
72  assert(__objc_class_hash);
73
74  /* make sure it's not a meta class */
75  assert(CLS_ISCLASS(class));
76
77  /* Check to see if the class is already in the hash table.  */
78  h_class = hash_value_for_key (__objc_class_hash, class->name);
79  if (!h_class)
80    {
81      /* The class isn't in the hash table.  Add the class and assign a class
82         number.  */
83      static unsigned int class_number = 1;
84
85      CLS_SETNUMBER(class, class_number);
86      CLS_SETNUMBER(class->class_pointer, class_number);
87
88      ++class_number;
89      hash_add (&__objc_class_hash, class->name, class);
90    }
91
92  objc_mutex_unlock(__objc_runtime_mutex);
93}
94
95/* Get the class object for the class named NAME.  If NAME does not
96   identify a known class, the hook _objc_lookup_class is called.  If
97   this fails, nil is returned */
98Class objc_lookup_class (const char* name)
99{
100  Class class;
101
102  objc_mutex_lock(__objc_runtime_mutex);
103
104  /* Make sure the class hash table exists.  */
105  assert (__objc_class_hash);
106
107  class = hash_value_for_key (__objc_class_hash, name);
108
109  objc_mutex_unlock(__objc_runtime_mutex);
110
111  if (class)
112    return class;
113
114  if (_objc_lookup_class)
115    return (*_objc_lookup_class)(name);
116  else
117    return 0;
118}
119
120/* Get the class object for the class named NAME.  If NAME does not
121   identify a known class, the hook _objc_lookup_class is called.  If
122   this fails,  an error message is issued and the system aborts */
123Class
124objc_get_class (const char *name)
125{
126  Class class;
127
128  objc_mutex_lock(__objc_runtime_mutex);
129
130  /* Make sure the class hash table exists.  */
131  assert (__objc_class_hash);
132
133  class = hash_value_for_key (__objc_class_hash, name);
134
135  objc_mutex_unlock(__objc_runtime_mutex);
136
137  if (class)
138    return class;
139
140  if (_objc_lookup_class)
141    class = (*_objc_lookup_class)(name);
142
143  if(class)
144    return class;
145
146  objc_error(nil, OBJC_ERR_BAD_CLASS,
147	     "objc runtime: cannot find class %s\n", name);
148  return 0;
149}
150
151MetaClass
152objc_get_meta_class(const char *name)
153{
154  return objc_get_class(name)->class_pointer;
155}
156
157/* This function provides a way to enumerate all the classes in the
158   executable.  Pass *ENUM_STATE == NULL to start the enumeration.  The
159   function will return 0 when there are no more classes.
160   For example:
161       id class;
162       void *es = NULL;
163       while ((class = objc_next_class(&es)))
164         ... do something with class;
165*/
166Class
167objc_next_class(void **enum_state)
168{
169  objc_mutex_lock(__objc_runtime_mutex);
170
171  /* make sure the table is there */
172  assert(__objc_class_hash);
173
174  *(node_ptr*)enum_state =
175    hash_next(__objc_class_hash, *(node_ptr*)enum_state);
176
177  objc_mutex_unlock(__objc_runtime_mutex);
178
179  if (*(node_ptr*)enum_state)
180    return (*(node_ptr*)enum_state)->value;
181  return (Class)0;
182}
183
184/* Resolve super/subclass links for all classes.  The only thing we
185   can be sure of is that the class_pointer for class objects point
186   to the right meta class objects */
187void __objc_resolve_class_links()
188{
189  node_ptr node;
190  Class object_class = objc_get_class ("Object");
191
192  assert(object_class);
193
194  objc_mutex_lock(__objc_runtime_mutex);
195
196  /* Assign subclass links */
197  for (node = hash_next (__objc_class_hash, NULL); node;
198       node = hash_next (__objc_class_hash, node))
199    {
200      Class class1 = node->value;
201
202      /* Make sure we have what we think we have.  */
203      assert (CLS_ISCLASS(class1));
204      assert (CLS_ISMETA(class1->class_pointer));
205
206      /* The class_pointer of all meta classes point to Object's meta class. */
207      class1->class_pointer->class_pointer = object_class->class_pointer;
208
209      if (!(CLS_ISRESOLV(class1)))
210        {
211          CLS_SETRESOLV(class1);
212          CLS_SETRESOLV(class1->class_pointer);
213
214          if(class1->super_class)
215            {
216              Class a_super_class
217                = objc_get_class ((char *) class1->super_class);
218
219              assert (a_super_class);
220
221              DEBUG_PRINTF ("making class connections for: %s\n",
222                            class1->name);
223
224              /* assign subclass links for superclass */
225              class1->sibling_class = a_super_class->subclass_list;
226              a_super_class->subclass_list = class1;
227
228              /* Assign subclass links for meta class of superclass */
229              if (a_super_class->class_pointer)
230                {
231                  class1->class_pointer->sibling_class
232                    = a_super_class->class_pointer->subclass_list;
233                  a_super_class->class_pointer->subclass_list
234                    = class1->class_pointer;
235                }
236            }
237          else                  /* a root class, make its meta object */
238                                /* be a subclass of Object */
239            {
240              class1->class_pointer->sibling_class
241                = object_class->subclass_list;
242              object_class->subclass_list = class1->class_pointer;
243            }
244        }
245    }
246
247  /* Assign superclass links */
248  for (node = hash_next (__objc_class_hash, NULL); node;
249       node = hash_next (__objc_class_hash, node))
250    {
251      Class class1 = node->value;
252      Class sub_class;
253      for (sub_class = class1->subclass_list; sub_class;
254           sub_class = sub_class->sibling_class)
255        {
256          sub_class->super_class = class1;
257          if(CLS_ISCLASS(sub_class))
258            sub_class->class_pointer->super_class = class1->class_pointer;
259        }
260    }
261
262  objc_mutex_unlock(__objc_runtime_mutex);
263}
264
265
266
267#define CLASSOF(c) ((c)->class_pointer)
268
269Class
270class_pose_as (Class impostor, Class super_class)
271{
272  node_ptr node;
273  Class class1;
274
275  if (!CLS_ISRESOLV (impostor))
276    __objc_resolve_class_links ();
277
278  /* preconditions */
279  assert (impostor);
280  assert (super_class);
281  assert (impostor->super_class == super_class);
282  assert (CLS_ISCLASS (impostor));
283  assert (CLS_ISCLASS (super_class));
284  assert (impostor->instance_size == super_class->instance_size);
285
286  {
287    Class *subclass = &(super_class->subclass_list);
288
289    /* move subclasses of super_class to impostor */
290    while (*subclass)
291      {
292	Class nextSub = (*subclass)->sibling_class;
293
294	if (*subclass != impostor)
295	  {
296	    Class sub = *subclass;
297
298	    /* classes */
299	    sub->sibling_class = impostor->subclass_list;
300	    sub->super_class = impostor;
301	    impostor->subclass_list = sub;
302
303	    /* It will happen that SUB is not a class object if it is
304	       the top of the meta class hierarchy chain.  (root
305	       meta-class objects inherit their class object)  If that is
306	       the case... don't mess with the meta-meta class. */
307	    if (CLS_ISCLASS (sub))
308	      {
309		/* meta classes */
310		CLASSOF (sub)->sibling_class =
311		  CLASSOF (impostor)->subclass_list;
312		CLASSOF (sub)->super_class = CLASSOF (impostor);
313		CLASSOF (impostor)->subclass_list = CLASSOF (sub);
314	      }
315	  }
316
317	*subclass = nextSub;
318      }
319
320    /* set subclasses of superclass to be impostor only */
321    super_class->subclass_list = impostor;
322    CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
323
324    /* set impostor to have no sibling classes */
325    impostor->sibling_class = 0;
326    CLASSOF (impostor)->sibling_class = 0;
327  }
328
329  /* check relationship of impostor and super_class is kept. */
330  assert (impostor->super_class == super_class);
331  assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
332
333  /* This is how to update the lookup table. Regardless of
334     what the keys of the hashtable is, change all values that are
335     superclass into impostor. */
336
337  objc_mutex_lock(__objc_runtime_mutex);
338
339  for (node = hash_next (__objc_class_hash, NULL); node;
340       node = hash_next (__objc_class_hash, node))
341    {
342      class1 = (Class)node->value;
343      if (class1 == super_class)
344	{
345	  node->value = impostor; /* change hash table value */
346	}
347    }
348
349  objc_mutex_unlock(__objc_runtime_mutex);
350
351  /* next, we update the dispatch tables... */
352  __objc_update_dispatch_table_for_class (CLASSOF (impostor));
353  __objc_update_dispatch_table_for_class (impostor);
354
355  return impostor;
356}
357
358
359