OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libobjc/] [class.c] - Blame information for rev 20

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* GNU Objective C Runtime class related functions
2
   Copyright (C) 1993, 1995, 1996, 1997, 2001, 2002
3
     Free Software Foundation, Inc.
4
   Contributed by Kresten Krab Thorup and Dennis Glatting.
5
 
6
   Lock-free class table code designed and written from scratch by
7
   Nicola Pero, 2001.
8
 
9
This file is part of GCC.
10
 
11
GCC is free software; you can redistribute it and/or modify it under the
12
terms of the GNU General Public License as published by the Free Software
13
Foundation; either version 2, or (at your option) any later version.
14
 
15
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18
details.
19
 
20
You should have received a copy of the GNU General Public License along with
21
GCC; see the file COPYING.  If not, write to the Free Software
22
Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
23
 
24
/* As a special exception, if you link this library with files compiled with
25
   GCC to produce an executable, this does not cause the resulting executable
26
   to be covered by the GNU General Public License. This exception does not
27
   however invalidate any other reasons why the executable file might be
28
   covered by the GNU General Public License.  */
29
 
30
/*
31
  The code in this file critically affects class method invocation
32
  speed.  This long preamble comment explains why, and the issues
33
  involved.
34
 
35
 
36
  One of the traditional weaknesses of the GNU Objective-C runtime is
37
  that class method invocations are slow.  The reason is that when you
38
  write
39
 
40
  array = [NSArray new];
41
 
42
  this gets basically compiled into the equivalent of
43
 
44
  array = [(objc_get_class ("NSArray")) new];
45
 
46
  objc_get_class returns the class pointer corresponding to the string
47
  `NSArray'; and because of the lookup, the operation is more
48
  complicated and slow than a simple instance method invocation.
49
 
50
  Most high performance Objective-C code (using the GNU Objc runtime)
51
  I had the opportunity to read (or write) work around this problem by
52
  caching the class pointer:
53
 
54
  Class arrayClass = [NSArray class];
55
 
56
  ... later on ...
57
 
58
  array = [arrayClass new];
59
  array = [arrayClass new];
60
  array = [arrayClass new];
61
 
62
  In this case, you always perform a class lookup (the first one), but
63
  then all the [arrayClass new] methods run exactly as fast as an
64
  instance method invocation.  It helps if you have many class method
65
  invocations to the same class.
66
 
67
  The long-term solution to this problem would be to modify the
68
  compiler to output tables of class pointers corresponding to all the
69
  class method invocations, and to add code to the runtime to update
70
  these tables - that should in the end allow class method invocations
71
  to perform precisely as fast as instance method invocations, because
72
  no class lookup would be involved.  I think the Apple Objective-C
73
  runtime uses this technique.  Doing this involves synchronized
74
  modifications in the runtime and in the compiler.
75
 
76
  As a first medicine to the problem, I [NP] have redesigned and
77
  rewritten the way the runtime is performing class lookup.  This
78
  doesn't give as much speed as the other (definitive) approach, but
79
  at least a class method invocation now takes approximately 4.5 times
80
  an instance method invocation on my machine (it would take approx 12
81
  times before the rewriting), which is a lot better.
82
 
83
  One of the main reason the new class lookup is so faster is because
84
  I implemented it in a way that can safely run multithreaded without
85
  using locks - a so-called `lock-free' data structure.  The atomic
86
  operation is pointer assignment.  The reason why in this problem
87
  lock-free data structures work so well is that you never remove
88
  classes from the table - and the difficult thing with lock-free data
89
  structures is freeing data when is removed from the structures.  */
90
 
91
#include "objc/runtime.h"            /* the kitchen sink */
92
#include "objc/sarray.h"
93
 
94
#include "objc/objc.h"
95
#include "objc/objc-api.h"
96
#include "objc/thr.h"
97
 
98
/* We use a table which maps a class name to the corresponding class
99
 * pointer.  The first part of this file defines this table, and
100
 * functions to do basic operations on the table.  The second part of
101
 * the file implements some higher level Objective-C functionality for
102
 * classes by using the functions provided in the first part to manage
103
 * the table. */
104
 
105
/**
106
 ** Class Table Internals
107
 **/
108
 
109
/* A node holding a class */
110
typedef struct class_node
111
{
112
  struct class_node *next;      /* Pointer to next entry on the list.
113
                                   NULL indicates end of list. */
114
 
115
  const char *name;             /* The class name string */
116
  int length;                   /* The class name string length */
117
  Class pointer;                /* The Class pointer */
118
 
119
} *class_node_ptr;
120
 
121
/* A table containing classes is a class_node_ptr (pointing to the
122
   first entry in the table - if it is NULL, then the table is
123
   empty). */
124
 
125
/* We have 1024 tables.  Each table contains all class names which
126
   have the same hash (which is a number between 0 and 1023).  To look
127
   up a class_name, we compute its hash, and get the corresponding
128
   table.  Once we have the table, we simply compare strings directly
129
   till we find the one which we want (using the length first).  The
130
   number of tables is quite big on purpose (a normal big application
131
   has less than 1000 classes), so that you shouldn't normally get any
132
   collisions, and get away with a single comparison (which we can't
133
   avoid since we need to know that you have got the right thing).  */
134
#define CLASS_TABLE_SIZE 1024
135
#define CLASS_TABLE_MASK 1023
136
 
137
static class_node_ptr class_table_array[CLASS_TABLE_SIZE];
138
 
139
/* The table writing mutex - we lock on writing to avoid conflicts
140
   between different writers, but we read without locks.  That is
141
   possible because we assume pointer assignment to be an atomic
142
   operation.  */
143
static objc_mutex_t __class_table_lock = NULL;
144
 
145
/* CLASS_TABLE_HASH is how we compute the hash of a class name.  It is
146
   a macro - *not* a function - arguments *are* modified directly.
147
 
148
   INDEX should be a variable holding an int;
149
   HASH should be a variable holding an int;
150
   CLASS_NAME should be a variable holding a (char *) to the class_name.
151
 
152
   After the macro is executed, INDEX contains the length of the
153
   string, and HASH the computed hash of the string; CLASS_NAME is
154
   untouched.  */
155
 
156
#define CLASS_TABLE_HASH(INDEX, HASH, CLASS_NAME)          \
157
  HASH = 0;                                                  \
158
  for (INDEX = 0; CLASS_NAME[INDEX] != '\0'; INDEX++)        \
159
    {                                                        \
160
      HASH = (HASH << 4) ^ (HASH >> 28) ^ CLASS_NAME[INDEX]; \
161
    }                                                        \
162
                                                             \
163
  HASH = (HASH ^ (HASH >> 10) ^ (HASH >> 20)) & CLASS_TABLE_MASK;
164
 
165
/* Setup the table.  */
166
static void
167
class_table_setup (void)
168
{
169
  /* Start - nothing in the table.  */
170
  memset (class_table_array, 0, sizeof (class_node_ptr) * CLASS_TABLE_SIZE);
171
 
172
  /* The table writing mutex.  */
173
  __class_table_lock = objc_mutex_allocate ();
174
}
175
 
176
 
177
/* Insert a class in the table (used when a new class is registered).  */
178
static void
179
class_table_insert (const char *class_name, Class class_pointer)
180
{
181
  int hash, length;
182
  class_node_ptr new_node;
183
 
184
  /* Find out the class name's hash and length.  */
185
  CLASS_TABLE_HASH (length, hash, class_name);
186
 
187
  /* Prepare the new node holding the class.  */
188
  new_node = objc_malloc (sizeof (struct class_node));
189
  new_node->name = class_name;
190
  new_node->length = length;
191
  new_node->pointer = class_pointer;
192
 
193
  /* Lock the table for modifications.  */
194
  objc_mutex_lock (__class_table_lock);
195
 
196
  /* Insert the new node in the table at the beginning of the table at
197
     class_table_array[hash].  */
198
  new_node->next = class_table_array[hash];
199
  class_table_array[hash] = new_node;
200
 
201
  objc_mutex_unlock (__class_table_lock);
202
}
203
 
204
/* Replace a class in the table (used only by poseAs:).  */
205
static void
206
class_table_replace (Class old_class_pointer, Class new_class_pointer)
207
{
208
  int hash;
209
  class_node_ptr node;
210
 
211
  objc_mutex_lock (__class_table_lock);
212
 
213
  hash = 0;
214
  node = class_table_array[hash];
215
 
216
  while (hash < CLASS_TABLE_SIZE)
217
    {
218
      if (node == NULL)
219
        {
220
          hash++;
221
          if (hash < CLASS_TABLE_SIZE)
222
            {
223
              node = class_table_array[hash];
224
            }
225
        }
226
      else
227
        {
228
          Class class1 = node->pointer;
229
 
230
          if (class1 == old_class_pointer)
231
            {
232
              node->pointer = new_class_pointer;
233
            }
234
          node = node->next;
235
        }
236
    }
237
 
238
  objc_mutex_unlock (__class_table_lock);
239
}
240
 
241
 
242
/* Get a class from the table.  This does not need mutex protection.
243
   Currently, this function is called each time you call a static
244
   method, this is why it must be very fast.  */
245
static inline Class
246
class_table_get_safe (const char *class_name)
247
{
248
  class_node_ptr node;
249
  int length, hash;
250
 
251
  /* Compute length and hash.  */
252
  CLASS_TABLE_HASH (length, hash, class_name);
253
 
254
  node = class_table_array[hash];
255
 
256
  if (node != NULL)
257
    {
258
      do
259
        {
260
          if (node->length == length)
261
            {
262
              /* Compare the class names.  */
263
              int i;
264
 
265
              for (i = 0; i < length; i++)
266
                {
267
                  if ((node->name)[i] != class_name[i])
268
                    {
269
                      break;
270
                    }
271
                }
272
 
273
              if (i == length)
274
                {
275
                  /* They are equal!  */
276
                  return node->pointer;
277
                }
278
            }
279
        }
280
      while ((node = node->next) != NULL);
281
    }
282
 
283
  return Nil;
284
}
285
 
286
/* Enumerate over the class table.  */
287
struct class_table_enumerator
288
{
289
  int hash;
290
  class_node_ptr node;
291
};
292
 
293
 
294
static Class
295
class_table_next (struct class_table_enumerator **e)
296
{
297
  struct class_table_enumerator *enumerator = *e;
298
  class_node_ptr next;
299
 
300
  if (enumerator == NULL)
301
    {
302
       *e = objc_malloc (sizeof (struct class_table_enumerator));
303
      enumerator = *e;
304
      enumerator->hash = 0;
305
      enumerator->node = NULL;
306
 
307
      next = class_table_array[enumerator->hash];
308
    }
309
  else
310
    {
311
      next = enumerator->node->next;
312
    }
313
 
314
  if (next != NULL)
315
    {
316
      enumerator->node = next;
317
      return enumerator->node->pointer;
318
    }
319
  else
320
    {
321
      enumerator->hash++;
322
 
323
      while (enumerator->hash < CLASS_TABLE_SIZE)
324
        {
325
          next = class_table_array[enumerator->hash];
326
          if (next != NULL)
327
            {
328
              enumerator->node = next;
329
              return enumerator->node->pointer;
330
            }
331
          enumerator->hash++;
332
        }
333
 
334
      /* Ok - table finished - done.  */
335
      objc_free (enumerator);
336
      return Nil;
337
    }
338
}
339
 
340
#if 0 /* DEBUGGING FUNCTIONS */
341
/* Debugging function - print the class table.  */
342
void
343
class_table_print (void)
344
{
345
  int i;
346
 
347
  for (i = 0; i < CLASS_TABLE_SIZE; i++)
348
    {
349
      class_node_ptr node;
350
 
351
      printf ("%d:\n", i);
352
      node = class_table_array[i];
353
 
354
      while (node != NULL)
355
        {
356
          printf ("\t%s\n", node->name);
357
          node = node->next;
358
        }
359
    }
360
}
361
 
362
/* Debugging function - print an histogram of number of classes in
363
   function of hash key values.  Useful to evaluate the hash function
364
   in real cases.  */
365
void
366
class_table_print_histogram (void)
367
{
368
  int i, j;
369
  int counter = 0;
370
 
371
  for (i = 0; i < CLASS_TABLE_SIZE; i++)
372
    {
373
      class_node_ptr node;
374
 
375
      node = class_table_array[i];
376
 
377
      while (node != NULL)
378
        {
379
          counter++;
380
          node = node->next;
381
        }
382
      if (((i + 1) % 50) == 0)
383
        {
384
          printf ("%4d:", i + 1);
385
          for (j = 0; j < counter; j++)
386
            {
387
              printf ("X");
388
            }
389
          printf ("\n");
390
          counter = 0;
391
        }
392
    }
393
  printf ("%4d:", i + 1);
394
  for (j = 0; j < counter; j++)
395
    {
396
      printf ("X");
397
    }
398
  printf ("\n");
399
}
400
#endif /* DEBUGGING FUNCTIONS */
401
 
402
/**
403
 ** Objective-C runtime functions
404
 **/
405
 
406
/* From now on, the only access to the class table data structure
407
   should be via the class_table_* functions.  */
408
 
409
/* This is a hook which is called by objc_get_class and
410
   objc_lookup_class if the runtime is not able to find the class.
411
   This may e.g. try to load in the class using dynamic loading.  */
412
Class (*_objc_lookup_class) (const char *name) = 0;      /* !T:SAFE */
413
 
414
 
415
/* True when class links has been resolved.  */
416
BOOL __objc_class_links_resolved = NO;                  /* !T:UNUSED */
417
 
418
 
419
void
420
__objc_init_class_tables (void)
421
{
422
  /* Allocate the class hash table.  */
423
 
424
  if (__class_table_lock)
425
    return;
426
 
427
  objc_mutex_lock (__objc_runtime_mutex);
428
 
429
  class_table_setup ();
430
 
431
  objc_mutex_unlock (__objc_runtime_mutex);
432
}
433
 
434
/* This function adds a class to the class hash table, and assigns the
435
   class a number, unless it's already known.  */
436
void
437
__objc_add_class_to_hash (Class class)
438
{
439
  Class h_class;
440
 
441
  objc_mutex_lock (__objc_runtime_mutex);
442
 
443
  /* Make sure the table is there.  */
444
  assert (__class_table_lock);
445
 
446
  /* Make sure it's not a meta class.  */
447
  assert (CLS_ISCLASS (class));
448
 
449
  /* Check to see if the class is already in the hash table.  */
450
  h_class = class_table_get_safe (class->name);
451
  if (! h_class)
452
    {
453
      /* The class isn't in the hash table.  Add the class and assign a class
454
         number.  */
455
      static unsigned int class_number = 1;
456
 
457
      CLS_SETNUMBER (class, class_number);
458
      CLS_SETNUMBER (class->class_pointer, class_number);
459
 
460
      ++class_number;
461
      class_table_insert (class->name, class);
462
    }
463
 
464
  objc_mutex_unlock (__objc_runtime_mutex);
465
}
466
 
467
/* Get the class object for the class named NAME.  If NAME does not
468
   identify a known class, the hook _objc_lookup_class is called.  If
469
   this fails, nil is returned.  */
470
Class
471
objc_lookup_class (const char *name)
472
{
473
  Class class;
474
 
475
  class = class_table_get_safe (name);
476
 
477
  if (class)
478
    return class;
479
 
480
  if (_objc_lookup_class)
481
    return (*_objc_lookup_class) (name);
482
  else
483
    return 0;
484
}
485
 
486
/* Get the class object for the class named NAME.  If NAME does not
487
   identify a known class, the hook _objc_lookup_class is called.  If
488
   this fails, an error message is issued and the system aborts.  */
489
Class
490
objc_get_class (const char *name)
491
{
492
  Class class;
493
 
494
  class = class_table_get_safe (name);
495
 
496
  if (class)
497
    return class;
498
 
499
  if (_objc_lookup_class)
500
    class = (*_objc_lookup_class) (name);
501
 
502
  if (class)
503
    return class;
504
 
505
  objc_error (nil, OBJC_ERR_BAD_CLASS,
506
              "objc runtime: cannot find class %s\n", name);
507
  return 0;
508
}
509
 
510
MetaClass
511
objc_get_meta_class (const char *name)
512
{
513
  return objc_get_class (name)->class_pointer;
514
}
515
 
516
/* This function provides a way to enumerate all the classes in the
517
   executable.  Pass *ENUM_STATE == NULL to start the enumeration.  The
518
   function will return 0 when there are no more classes.
519
   For example:
520
       id class;
521
       void *es = NULL;
522
       while ((class = objc_next_class (&es)))
523
         ... do something with class;
524
*/
525
Class
526
objc_next_class (void **enum_state)
527
{
528
  Class class;
529
 
530
  objc_mutex_lock (__objc_runtime_mutex);
531
 
532
  /* Make sure the table is there.  */
533
  assert (__class_table_lock);
534
 
535
  class = class_table_next ((struct class_table_enumerator **) enum_state);
536
 
537
  objc_mutex_unlock (__objc_runtime_mutex);
538
 
539
  return class;
540
}
541
 
542
/* Resolve super/subclass links for all classes.  The only thing we
543
   can be sure of is that the class_pointer for class objects point to
544
   the right meta class objects.  */
545
void
546
__objc_resolve_class_links (void)
547
{
548
  struct class_table_enumerator *es = NULL;
549
  Class object_class = objc_get_class ("Object");
550
  Class class1;
551
 
552
  assert (object_class);
553
 
554
  objc_mutex_lock (__objc_runtime_mutex);
555
 
556
  /* Assign subclass links.  */
557
  while ((class1 = class_table_next (&es)))
558
    {
559
      /* Make sure we have what we think we have.  */
560
      assert (CLS_ISCLASS (class1));
561
      assert (CLS_ISMETA (class1->class_pointer));
562
 
563
      /* The class_pointer of all meta classes point to Object's meta
564
         class.  */
565
      class1->class_pointer->class_pointer = object_class->class_pointer;
566
 
567
      if (! CLS_ISRESOLV (class1))
568
        {
569
          CLS_SETRESOLV (class1);
570
          CLS_SETRESOLV (class1->class_pointer);
571
 
572
          if (class1->super_class)
573
            {
574
              Class a_super_class
575
                = objc_get_class ((char *) class1->super_class);
576
 
577
              assert (a_super_class);
578
 
579
              DEBUG_PRINTF ("making class connections for: %s\n",
580
                            class1->name);
581
 
582
              /* Assign subclass links for superclass.  */
583
              class1->sibling_class = a_super_class->subclass_list;
584
              a_super_class->subclass_list = class1;
585
 
586
              /* Assign subclass links for meta class of superclass.  */
587
              if (a_super_class->class_pointer)
588
                {
589
                  class1->class_pointer->sibling_class
590
                    = a_super_class->class_pointer->subclass_list;
591
                  a_super_class->class_pointer->subclass_list
592
                    = class1->class_pointer;
593
                }
594
            }
595
          else /* A root class, make its meta object be a subclass of
596
                  Object.  */
597
            {
598
              class1->class_pointer->sibling_class
599
                = object_class->subclass_list;
600
              object_class->subclass_list = class1->class_pointer;
601
            }
602
        }
603
    }
604
 
605
  /* Assign superclass links.  */
606
   es = NULL;
607
   while ((class1 = class_table_next (&es)))
608
    {
609
      Class sub_class;
610
      for (sub_class = class1->subclass_list; sub_class;
611
           sub_class = sub_class->sibling_class)
612
        {
613
          sub_class->super_class = class1;
614
          if (CLS_ISCLASS (sub_class))
615
            sub_class->class_pointer->super_class = class1->class_pointer;
616
        }
617
    }
618
 
619
  objc_mutex_unlock (__objc_runtime_mutex);
620
}
621
 
622
 
623
 
624
#define CLASSOF(c) ((c)->class_pointer)
625
 
626
Class
627
class_pose_as (Class impostor, Class super_class)
628
{
629
  if (! CLS_ISRESOLV (impostor))
630
    __objc_resolve_class_links ();
631
 
632
  /* Preconditions */
633
  assert (impostor);
634
  assert (super_class);
635
  assert (impostor->super_class == super_class);
636
  assert (CLS_ISCLASS (impostor));
637
  assert (CLS_ISCLASS (super_class));
638
  assert (impostor->instance_size == super_class->instance_size);
639
 
640
  {
641
    Class *subclass = &(super_class->subclass_list);
642
 
643
    /* Move subclasses of super_class to impostor.  */
644
    while (*subclass)
645
      {
646
        Class nextSub = (*subclass)->sibling_class;
647
 
648
        if (*subclass != impostor)
649
          {
650
            Class sub = *subclass;
651
 
652
            /* Classes */
653
            sub->sibling_class = impostor->subclass_list;
654
            sub->super_class = impostor;
655
            impostor->subclass_list = sub;
656
 
657
            /* It will happen that SUB is not a class object if it is
658
               the top of the meta class hierarchy chain (root
659
               meta-class objects inherit their class object).  If
660
               that is the case... don't mess with the meta-meta
661
               class.  */
662
            if (CLS_ISCLASS (sub))
663
              {
664
                /* Meta classes */
665
                CLASSOF (sub)->sibling_class =
666
                  CLASSOF (impostor)->subclass_list;
667
                CLASSOF (sub)->super_class = CLASSOF (impostor);
668
                CLASSOF (impostor)->subclass_list = CLASSOF (sub);
669
              }
670
          }
671
 
672
        *subclass = nextSub;
673
      }
674
 
675
    /* Set subclasses of superclass to be impostor only.  */
676
    super_class->subclass_list = impostor;
677
    CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
678
 
679
    /* Set impostor to have no sibling classes.  */
680
    impostor->sibling_class = 0;
681
    CLASSOF (impostor)->sibling_class = 0;
682
  }
683
 
684
  /* Check relationship of impostor and super_class is kept.  */
685
  assert (impostor->super_class == super_class);
686
  assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
687
 
688
  /* This is how to update the lookup table.  Regardless of what the
689
     keys of the hashtable is, change all values that are superclass
690
     into impostor.  */
691
 
692
  objc_mutex_lock (__objc_runtime_mutex);
693
 
694
  class_table_replace (super_class, impostor);
695
 
696
  objc_mutex_unlock (__objc_runtime_mutex);
697
 
698
  /* Next, we update the dispatch tables...  */
699
  __objc_update_dispatch_table_for_class (CLASSOF (impostor));
700
  __objc_update_dispatch_table_for_class (impostor);
701
 
702
  return impostor;
703
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.