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