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

Subversion Repositories scarts

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

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

Line No. Rev Author Line
1 14 jlechner
/* GNU Objective C Runtime message lookup
2
   Copyright (C) 1993, 1995, 1996, 1997, 1998,
3
   2001, 2002, 2004 Free Software Foundation, Inc.
4
   Contributed by Kresten Krab Thorup
5
 
6
This file is part of GCC.
7
 
8
GCC is free software; you can redistribute it and/or modify it under the
9
terms of the GNU General Public License as published by the Free Software
10
Foundation; either version 2, or (at your option) any later version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15
details.
16
 
17
You should have received a copy of the GNU General Public License along with
18
GCC; see the file COPYING.  If not, write to the Free Software
19
Foundation, 51 Franklin Street, Fifth Floor,
20
Boston, MA 02110-1301, USA.  */
21
 
22
/* As a special exception, if you link this library with files compiled with
23
   GCC to produce an executable, this does not cause the resulting executable
24
   to be covered by the GNU General Public License. This exception does not
25
   however invalidate any other reasons why the executable file might be
26
   covered by the GNU General Public License.  */
27
 
28
/* FIXME: This file has no business including tm.h.  */
29
/* FIXME: This should be using libffi instead of __builtin_apply
30
   and friends.  */
31
 
32
#include "tconfig.h"
33
#include "coretypes.h"
34
#include "tm.h"
35
#include "objc/runtime.h"
36
#include "objc/sarray.h"
37
#include "objc/encoding.h"
38
#include "runtime-info.h"
39
 
40
/* This is how we hack STRUCT_VALUE to be 1 or 0.   */
41
#define gen_rtx(args...) 1
42
#define gen_rtx_MEM(args...) 1
43
#define gen_rtx_REG(args...) 1
44
#define rtx int
45
 
46
#if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
47
#define INVISIBLE_STRUCT_RETURN 1
48
#else
49
#define INVISIBLE_STRUCT_RETURN 0
50
#endif
51
 
52
/* The uninstalled dispatch table */
53
struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
54
 
55
/* Hook for method forwarding. If it is set, is invoked to return a
56
   function that performs the real forwarding. Otherwise the libgcc
57
   based functions (__builtin_apply and friends) are used. */
58
IMP (*__objc_msg_forward) (SEL) = NULL;
59
 
60
/* Send +initialize to class */
61
static void __objc_send_initialize (Class);
62
 
63
static void __objc_install_dispatch_table_for_class (Class);
64
 
65
/* Forward declare some functions */
66
static void __objc_init_install_dtable (id, SEL);
67
 
68
/* Various forwarding functions that are used based upon the
69
   return type for the selector.
70
   __objc_block_forward for structures.
71
   __objc_double_forward for floats/doubles.
72
   __objc_word_forward for pointers or types that fit in registers.
73
   */
74
static double __objc_double_forward (id, SEL, ...);
75
static id __objc_word_forward (id, SEL, ...);
76
typedef struct { id many[8]; } __big;
77
#if INVISIBLE_STRUCT_RETURN 
78
static __big
79
#else
80
static id
81
#endif
82
__objc_block_forward (id, SEL, ...);
83
static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
84
Method_t search_for_method_in_list (MethodList_t list, SEL op);
85
id nil_method (id, SEL);
86
 
87
/* Given a selector, return the proper forwarding implementation. */
88
inline
89
IMP
90
__objc_get_forward_imp (SEL sel)
91
{
92
  /* If a custom forwarding hook was registered, try getting a forwarding
93
   * function from it.  */
94
  if (__objc_msg_forward)
95
    {
96
      IMP result;
97
      if ((result = __objc_msg_forward (sel)) != NULL)
98
        return result;
99
    }
100
 
101
  /* In all other cases, use the default forwarding functions built using
102
   * __builtin_apply and friends.  */
103
    {
104
      const char *t = sel->sel_types;
105
 
106
      if (t && (*t == '[' || *t == '(' || *t == '{')
107
#ifdef OBJC_MAX_STRUCT_BY_VALUE
108
          && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
109
#endif
110
          )
111
        return (IMP)__objc_block_forward;
112
      else if (t && (*t == 'f' || *t == 'd'))
113
        return (IMP)__objc_double_forward;
114
      else
115
        return (IMP)__objc_word_forward;
116
    }
117
}
118
 
119
/* Given a class and selector, return the selector's implementation.  */
120
inline
121
IMP
122
get_imp (Class class, SEL sel)
123
{
124
  /* In a vanilla implementation we would first check if the dispatch
125
     table is installed.  Here instead, to get more speed in the
126
     standard case (that the dispatch table is installed) we first try
127
     to get the imp using brute force.  Only if that fails, we do what
128
     we should have been doing from the very beginning, that is, check
129
     if the dispatch table needs to be installed, install it if it's
130
     not installed, and retrieve the imp from the table if it's
131
     installed.  */
132
  void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
133
  if (res == 0)
134
    {
135
      /* Not a valid method */
136
      if (class->dtable == __objc_uninstalled_dtable)
137
        {
138
          /* The dispatch table needs to be installed. */
139
          objc_mutex_lock (__objc_runtime_mutex);
140
 
141
           /* Double-checked locking pattern: Check
142
              __objc_uninstalled_dtable again in case another thread
143
              installed the dtable while we were waiting for the lock
144
              to be released.  */
145
         if (class->dtable == __objc_uninstalled_dtable)
146
           {
147
             __objc_install_dispatch_table_for_class (class);
148
           }
149
 
150
          objc_mutex_unlock (__objc_runtime_mutex);
151
          /* Call ourselves with the installed dispatch table
152
             and get the real method */
153
          res = get_imp (class, sel);
154
        }
155
      else
156
        {
157
          /* The dispatch table has been installed.  */
158
 
159
         /* Get the method from the dispatch table (we try to get it
160
            again in case another thread has installed the dtable just
161
            after we invoked sarray_get_safe, but before we checked
162
            class->dtable == __objc_uninstalled_dtable).
163
         */
164
          res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
165
          if (res == 0)
166
            {
167
              /* The dispatch table has been installed, and the method
168
                 is not in the dispatch table.  So the method just
169
                 doesn't exist for the class.  Return the forwarding
170
                 implementation. */
171
              res = __objc_get_forward_imp (sel);
172
            }
173
        }
174
    }
175
  return res;
176
}
177
 
178
/* Query if an object can respond to a selector, returns YES if the
179
object implements the selector otherwise NO.  Does not check if the
180
method can be forwarded. */
181
inline
182
BOOL
183
__objc_responds_to (id object, SEL sel)
184
{
185
  void *res;
186
 
187
  /* Install dispatch table if need be */
188
  if (object->class_pointer->dtable == __objc_uninstalled_dtable)
189
    {
190
      objc_mutex_lock (__objc_runtime_mutex);
191
      if (object->class_pointer->dtable == __objc_uninstalled_dtable)
192
        {
193
          __objc_install_dispatch_table_for_class (object->class_pointer);
194
        }
195
      objc_mutex_unlock (__objc_runtime_mutex);
196
    }
197
 
198
  /* Get the method from the dispatch table */
199
  res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
200
  return (res != 0);
201
}
202
 
203
/* This is the lookup function.  All entries in the table are either a
204
   valid method *or* zero.  If zero then either the dispatch table
205
   needs to be installed or it doesn't exist and forwarding is attempted. */
206
inline
207
IMP
208
objc_msg_lookup (id receiver, SEL op)
209
{
210
  IMP result;
211
  if (receiver)
212
    {
213
      result = sarray_get_safe (receiver->class_pointer->dtable,
214
                                (sidx)op->sel_id);
215
      if (result == 0)
216
        {
217
          /* Not a valid method */
218
          if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
219
            {
220
              /* The dispatch table needs to be installed.
221
                 This happens on the very first method call to the class. */
222
              __objc_init_install_dtable (receiver, op);
223
 
224
              /* Get real method for this in newly installed dtable */
225
              result = get_imp (receiver->class_pointer, op);
226
            }
227
          else
228
            {
229
              /* The dispatch table has been installed.  Check again
230
                 if the method exists (just in case the dispatch table
231
                 has been installed by another thread after we did the
232
                 previous check that the method exists).
233
              */
234
              result = sarray_get_safe (receiver->class_pointer->dtable,
235
                                        (sidx)op->sel_id);
236
              if (result == 0)
237
                {
238
                  /* If the method still just doesn't exist for the
239
                     class, attempt to forward the method. */
240
                  result = __objc_get_forward_imp (op);
241
                }
242
            }
243
        }
244
      return result;
245
    }
246
  else
247
    return (IMP)nil_method;
248
}
249
 
250
IMP
251
objc_msg_lookup_super (Super_t super, SEL sel)
252
{
253
  if (super->self)
254
    return get_imp (super->class, sel);
255
  else
256
    return (IMP)nil_method;
257
}
258
 
259
int method_get_sizeof_arguments (Method *);
260
 
261
retval_t
262
objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
263
{
264
  Method *m = class_get_instance_method (object->class_pointer, op);
265
  const char *type;
266
  *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
267
  *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
268
  return __builtin_apply ((apply_t) m->method_imp,
269
                          arg_frame,
270
                          method_get_sizeof_arguments (m));
271
}
272
 
273
void
274
__objc_init_dispatch_tables ()
275
{
276
  __objc_uninstalled_dtable = sarray_new (200, 0);
277
}
278
 
279
/* This function is called by objc_msg_lookup when the
280
   dispatch table needs to be installed; thus it is called once
281
   for each class, namely when the very first message is sent to it. */
282
static void
283
__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
284
{
285
  objc_mutex_lock (__objc_runtime_mutex);
286
 
287
  /* This may happen, if the programmer has taken the address of a
288
     method before the dtable was initialized... too bad for him! */
289
  if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
290
    {
291
      objc_mutex_unlock (__objc_runtime_mutex);
292
      return;
293
    }
294
 
295
  if (CLS_ISCLASS (receiver->class_pointer))
296
    {
297
      /* receiver is an ordinary object */
298
      assert (CLS_ISCLASS (receiver->class_pointer));
299
 
300
      /* install instance methods table */
301
      __objc_install_dispatch_table_for_class (receiver->class_pointer);
302
 
303
      /* call +initialize -- this will in turn install the factory
304
         dispatch table if not already done :-) */
305
      __objc_send_initialize (receiver->class_pointer);
306
    }
307
  else
308
    {
309
      /* receiver is a class object */
310
      assert (CLS_ISCLASS ((Class)receiver));
311
      assert (CLS_ISMETA (receiver->class_pointer));
312
 
313
      /* Install real dtable for factory methods */
314
      __objc_install_dispatch_table_for_class (receiver->class_pointer);
315
 
316
      __objc_send_initialize ((Class)receiver);
317
    }
318
  objc_mutex_unlock (__objc_runtime_mutex);
319
}
320
 
321
/* Install dummy table for class which causes the first message to
322
   that class (or instances hereof) to be initialized properly */
323
void
324
__objc_install_premature_dtable (Class class)
325
{
326
  assert (__objc_uninstalled_dtable);
327
  class->dtable = __objc_uninstalled_dtable;
328
}
329
 
330
/* Send +initialize to class if not already done */
331
static void
332
__objc_send_initialize (Class class)
333
{
334
  /* This *must* be a class object */
335
  assert (CLS_ISCLASS (class));
336
  assert (! CLS_ISMETA (class));
337
 
338
  if (! CLS_ISINITIALIZED (class))
339
    {
340
      CLS_SETINITIALIZED (class);
341
      CLS_SETINITIALIZED (class->class_pointer);
342
 
343
      /* Create the garbage collector type memory description */
344
      __objc_generate_gc_type_description (class);
345
 
346
      if (class->super_class)
347
        __objc_send_initialize (class->super_class);
348
 
349
      {
350
        SEL          op = sel_register_name ("initialize");
351
        IMP          imp = 0;
352
        MethodList_t method_list = class->class_pointer->methods;
353
 
354
        while (method_list) {
355
          int i;
356
          Method_t method;
357
 
358
          for (i = 0; i < method_list->method_count; i++) {
359
            method = &(method_list->method_list[i]);
360
            if (method->method_name
361
                && method->method_name->sel_id == op->sel_id) {
362
              imp = method->method_imp;
363
              break;
364
            }
365
          }
366
 
367
          if (imp)
368
            break;
369
 
370
          method_list = method_list->method_next;
371
 
372
        }
373
        if (imp)
374
            (*imp) ((id) class, op);
375
 
376
      }
377
    }
378
}
379
 
380
/* Walk on the methods list of class and install the methods in the reverse
381
   order of the lists. Since methods added by categories are before the methods
382
   of class in the methods list, this allows categories to substitute methods
383
   declared in class. However if more than one category replaces the same
384
   method nothing is guaranteed about what method will be used.
385
   Assumes that __objc_runtime_mutex is locked down. */
386
static void
387
__objc_install_methods_in_dtable (Class class, MethodList_t method_list)
388
{
389
  int i;
390
 
391
  if (! method_list)
392
    return;
393
 
394
  if (method_list->method_next)
395
    __objc_install_methods_in_dtable (class, method_list->method_next);
396
 
397
  for (i = 0; i < method_list->method_count; i++)
398
    {
399
      Method_t method = &(method_list->method_list[i]);
400
      sarray_at_put_safe (class->dtable,
401
                          (sidx) method->method_name->sel_id,
402
                          method->method_imp);
403
    }
404
}
405
 
406
/* Assumes that __objc_runtime_mutex is locked down. */
407
static void
408
__objc_install_dispatch_table_for_class (Class class)
409
{
410
  Class super;
411
 
412
  /* If the class has not yet had its class links resolved, we must
413
     re-compute all class links */
414
  if (! CLS_ISRESOLV (class))
415
    __objc_resolve_class_links ();
416
 
417
  super = class->super_class;
418
 
419
  if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
420
    __objc_install_dispatch_table_for_class (super);
421
 
422
  /* Allocate dtable if necessary */
423
  if (super == 0)
424
    {
425
      objc_mutex_lock (__objc_runtime_mutex);
426
      class->dtable = sarray_new (__objc_selector_max_index, 0);
427
      objc_mutex_unlock (__objc_runtime_mutex);
428
    }
429
  else
430
    class->dtable = sarray_lazy_copy (super->dtable);
431
 
432
  __objc_install_methods_in_dtable (class, class->methods);
433
}
434
 
435
void
436
__objc_update_dispatch_table_for_class (Class class)
437
{
438
  Class next;
439
  struct sarray *arr;
440
 
441
  /* not yet installed -- skip it */
442
  if (class->dtable == __objc_uninstalled_dtable)
443
    return;
444
 
445
  objc_mutex_lock (__objc_runtime_mutex);
446
 
447
  arr = class->dtable;
448
  __objc_install_premature_dtable (class); /* someone might require it... */
449
  sarray_free (arr);                       /* release memory */
450
 
451
  /* could have been lazy... */
452
  __objc_install_dispatch_table_for_class (class);
453
 
454
  if (class->subclass_list)     /* Traverse subclasses */
455
    for (next = class->subclass_list; next; next = next->sibling_class)
456
      __objc_update_dispatch_table_for_class (next);
457
 
458
  objc_mutex_unlock (__objc_runtime_mutex);
459
}
460
 
461
 
462
/* This function adds a method list to a class.  This function is
463
   typically called by another function specific to the run-time.  As
464
   such this function does not worry about thread safe issues.
465
 
466
   This one is only called for categories. Class objects have their
467
   methods installed right away, and their selectors are made into
468
   SEL's by the function __objc_register_selectors_from_class. */
469
void
470
class_add_method_list (Class class, MethodList_t list)
471
{
472
  /* Passing of a linked list is not allowed.  Do multiple calls.  */
473
  assert (! list->method_next);
474
 
475
  __objc_register_selectors_from_list(list);
476
 
477
  /* Add the methods to the class's method list.  */
478
  list->method_next = class->methods;
479
  class->methods = list;
480
 
481
  /* Update the dispatch table of class */
482
  __objc_update_dispatch_table_for_class (class);
483
}
484
 
485
Method_t
486
class_get_instance_method (Class class, SEL op)
487
{
488
  return search_for_method_in_hierarchy (class, op);
489
}
490
 
491
Method_t
492
class_get_class_method (MetaClass class, SEL op)
493
{
494
  return search_for_method_in_hierarchy (class, op);
495
}
496
 
497
 
498
/* Search for a method starting from the current class up its hierarchy.
499
   Return a pointer to the method's method structure if found.  NULL
500
   otherwise. */
501
 
502
static Method_t
503
search_for_method_in_hierarchy (Class cls, SEL sel)
504
{
505
  Method_t method = NULL;
506
  Class class;
507
 
508
  if (! sel_is_mapped (sel))
509
    return NULL;
510
 
511
  /* Scan the method list of the class.  If the method isn't found in the
512
     list then step to its super class. */
513
  for (class = cls; ((! method) && class); class = class->super_class)
514
    method = search_for_method_in_list (class->methods, sel);
515
 
516
  return method;
517
}
518
 
519
 
520
 
521
/* Given a linked list of method and a method's name.  Search for the named
522
   method's method structure.  Return a pointer to the method's method
523
   structure if found.  NULL otherwise. */
524
Method_t
525
search_for_method_in_list (MethodList_t list, SEL op)
526
{
527
  MethodList_t method_list = list;
528
 
529
  if (! sel_is_mapped (op))
530
    return NULL;
531
 
532
  /* If not found then we'll search the list.  */
533
  while (method_list)
534
    {
535
      int i;
536
 
537
      /* Search the method list.  */
538
      for (i = 0; i < method_list->method_count; ++i)
539
        {
540
          Method_t method = &method_list->method_list[i];
541
 
542
          if (method->method_name)
543
            if (method->method_name->sel_id == op->sel_id)
544
              return method;
545
        }
546
 
547
      /* The method wasn't found.  Follow the link to the next list of
548
         methods.  */
549
      method_list = method_list->method_next;
550
    }
551
 
552
  return NULL;
553
}
554
 
555
static retval_t __objc_forward (id object, SEL sel, arglist_t args);
556
 
557
/* Forwarding pointers/integers through the normal registers */
558
static id
559
__objc_word_forward (id rcv, SEL op, ...)
560
{
561
  void *args, *res;
562
 
563
  args = __builtin_apply_args ();
564
  res = __objc_forward (rcv, op, args);
565
  if (res)
566
    __builtin_return (res);
567
  else
568
    return res;
569
}
570
 
571
/* Specific routine for forwarding floats/double because of
572
   architectural differences on some processors.  i386s for
573
   example which uses a floating point stack versus general
574
   registers for floating point numbers.  This forward routine
575
   makes sure that GCC restores the proper return values */
576
static double
577
__objc_double_forward (id rcv, SEL op, ...)
578
{
579
  void *args, *res;
580
 
581
  args = __builtin_apply_args ();
582
  res = __objc_forward (rcv, op, args);
583
  __builtin_return (res);
584
}
585
 
586
#if INVISIBLE_STRUCT_RETURN
587
static __big
588
#else
589
static id
590
#endif
591
__objc_block_forward (id rcv, SEL op, ...)
592
{
593
  void *args, *res;
594
 
595
  args = __builtin_apply_args ();
596
  res = __objc_forward (rcv, op, args);
597
  if (res)
598
    __builtin_return (res);
599
  else
600
#if INVISIBLE_STRUCT_RETURN
601
    return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
602
#else
603
    return nil;
604
#endif
605
}
606
 
607
 
608
/* This function is installed in the dispatch table for all methods which are
609
   not implemented.  Thus, it is called when a selector is not recognized. */
610
static retval_t
611
__objc_forward (id object, SEL sel, arglist_t args)
612
{
613
  IMP imp;
614
  static SEL frwd_sel = 0;                      /* !T:SAFE2 */
615
  SEL err_sel;
616
 
617
  /* first try if the object understands forward:: */
618
  if (! frwd_sel)
619
    frwd_sel = sel_get_any_uid ("forward::");
620
 
621
  if (__objc_responds_to (object, frwd_sel))
622
    {
623
      imp = get_imp (object->class_pointer, frwd_sel);
624
      return (*imp) (object, frwd_sel, sel, args);
625
    }
626
 
627
  /* If the object recognizes the doesNotRecognize: method then we're going
628
     to send it. */
629
  err_sel = sel_get_any_uid ("doesNotRecognize:");
630
  if (__objc_responds_to (object, err_sel))
631
    {
632
      imp = get_imp (object->class_pointer, err_sel);
633
      return (*imp) (object, err_sel, sel);
634
    }
635
 
636
  /* The object doesn't recognize the method.  Check for responding to
637
     error:.  If it does then sent it. */
638
  {
639
    char msg[256 + strlen ((const char *) sel_get_name (sel))
640
             + strlen ((const char *) object->class_pointer->name)];
641
 
642
    sprintf (msg, "(%s) %s does not recognize %s",
643
             (CLS_ISMETA (object->class_pointer)
644
              ? "class"
645
              : "instance" ),
646
             object->class_pointer->name, sel_get_name (sel));
647
 
648
    err_sel = sel_get_any_uid ("error:");
649
    if (__objc_responds_to (object, err_sel))
650
      {
651
        imp = get_imp (object->class_pointer, err_sel);
652
        return (*imp) (object, sel_get_any_uid ("error:"), msg);
653
      }
654
 
655
    /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
656
       a default action is taken. */
657
    objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
658
 
659
    return 0;
660
  }
661
}
662
 
663
void
664
__objc_print_dtable_stats ()
665
{
666
  int total = 0;
667
 
668
  objc_mutex_lock (__objc_runtime_mutex);
669
 
670
#ifdef OBJC_SPARSE2
671
  printf ("memory usage: (%s)\n", "2-level sparse arrays");
672
#else
673
  printf ("memory usage: (%s)\n", "3-level sparse arrays");
674
#endif
675
 
676
  printf ("arrays: %d = %ld bytes\n", narrays,
677
          (long) narrays * sizeof (struct sarray));
678
  total += narrays * sizeof (struct sarray);
679
  printf ("buckets: %d = %ld bytes\n", nbuckets,
680
          (long) nbuckets * sizeof (struct sbucket));
681
  total += nbuckets * sizeof (struct sbucket);
682
 
683
  printf ("idxtables: %d = %ld bytes\n",
684
          idxsize, (long) idxsize * sizeof (void *));
685
  total += idxsize * sizeof (void *);
686
  printf ("-----------------------------------\n");
687
  printf ("total: %d bytes\n", total);
688
  printf ("===================================\n");
689
 
690
  objc_mutex_unlock (__objc_runtime_mutex);
691
}
692
 
693
/* Returns the uninstalled dispatch table indicator.
694
 If a class' dispatch table points to __objc_uninstalled_dtable
695
 then that means it needs its dispatch table to be installed. */
696
inline
697
struct sarray *
698
objc_get_uninstalled_dtable ()
699
{
700
  return __objc_uninstalled_dtable;
701
}

powered by: WebSVN 2.1.0

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