xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/methods.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* GNU Objective C Runtime method related functions.
2*8feb0f0bSmrg    Copyright (C) 2010-2020 Free Software Foundation, Inc.
336ac495dSmrg    Contributed by Nicola Pero
436ac495dSmrg 
536ac495dSmrg This file is part of GCC.
636ac495dSmrg 
736ac495dSmrg GCC is free software; you can redistribute it and/or modify it under the
836ac495dSmrg terms of the GNU General Public License as published by the Free Software
936ac495dSmrg Foundation; either version 3, or (at your option) any later version.
1036ac495dSmrg 
1136ac495dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1236ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1336ac495dSmrg FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
1436ac495dSmrg details.
1536ac495dSmrg 
1636ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg 3.1, as published by the Free Software Foundation.
1936ac495dSmrg 
2036ac495dSmrg You should have received a copy of the GNU General Public License and
2136ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2336ac495dSmrg <http://www.gnu.org/licenses/>.  */
2436ac495dSmrg 
2536ac495dSmrg #include "objc-private/common.h"
2636ac495dSmrg #include "objc/runtime.h"
2736ac495dSmrg #include "objc-private/module-abi-8.h" /* For runtime structures.   */
2836ac495dSmrg #include "objc/thr.h"
2936ac495dSmrg #include "objc-private/runtime.h"      /* For __objc_runtime_mutex.  */
3036ac495dSmrg #include <stdlib.h>                    /* For malloc.  */
3136ac495dSmrg 
3236ac495dSmrg SEL
method_getName(struct objc_method * method)3336ac495dSmrg method_getName (struct objc_method * method)
3436ac495dSmrg {
3536ac495dSmrg   if (method == NULL)
3636ac495dSmrg     return NULL;
3736ac495dSmrg 
3836ac495dSmrg   return method->method_name;
3936ac495dSmrg }
4036ac495dSmrg 
4136ac495dSmrg const char *
method_getTypeEncoding(struct objc_method * method)4236ac495dSmrg method_getTypeEncoding (struct objc_method * method)
4336ac495dSmrg {
4436ac495dSmrg   if (method == NULL)
4536ac495dSmrg     return NULL;
4636ac495dSmrg 
4736ac495dSmrg   return method->method_types;
4836ac495dSmrg }
4936ac495dSmrg 
5036ac495dSmrg IMP
method_getImplementation(struct objc_method * method)5136ac495dSmrg method_getImplementation (struct objc_method * method)
5236ac495dSmrg {
5336ac495dSmrg   if (method == NULL)
5436ac495dSmrg     return NULL;
5536ac495dSmrg 
5636ac495dSmrg   return method->method_imp;
5736ac495dSmrg }
5836ac495dSmrg 
5936ac495dSmrg struct objc_method_description *
method_getDescription(struct objc_method * method)6036ac495dSmrg method_getDescription (struct objc_method * method)
6136ac495dSmrg {
6236ac495dSmrg   /* Note that the following returns NULL if method is NULL, which is
6336ac495dSmrg      fine.  */
6436ac495dSmrg   return (struct objc_method_description *)method;
6536ac495dSmrg }
6636ac495dSmrg 
6736ac495dSmrg struct objc_method **
class_copyMethodList(Class class_,unsigned int * numberOfReturnedMethods)6836ac495dSmrg class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods)
6936ac495dSmrg {
7036ac495dSmrg   unsigned int count = 0;
7136ac495dSmrg   struct objc_method **returnValue = NULL;
7236ac495dSmrg   struct objc_method_list* method_list;
7336ac495dSmrg 
7436ac495dSmrg   if (class_ == Nil)
7536ac495dSmrg     {
7636ac495dSmrg       if (numberOfReturnedMethods)
7736ac495dSmrg 	*numberOfReturnedMethods = 0;
7836ac495dSmrg       return NULL;
7936ac495dSmrg     }
8036ac495dSmrg 
8136ac495dSmrg   /* Lock the runtime mutex because the class methods may be
8236ac495dSmrg      concurrently modified.  */
8336ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
8436ac495dSmrg 
8536ac495dSmrg   /* Count how many methods we have.  */
8636ac495dSmrg   method_list = class_->methods;
8736ac495dSmrg 
8836ac495dSmrg   while (method_list)
8936ac495dSmrg     {
9036ac495dSmrg       count = count + method_list->method_count;
9136ac495dSmrg       method_list = method_list->method_next;
9236ac495dSmrg     }
9336ac495dSmrg 
9436ac495dSmrg   if (count != 0)
9536ac495dSmrg     {
9636ac495dSmrg       unsigned int i = 0;
9736ac495dSmrg 
9836ac495dSmrg       /* Allocate enough memory to hold them.  */
9936ac495dSmrg       returnValue
10036ac495dSmrg 	= (struct objc_method **)(malloc (sizeof (struct objc_method *)
10136ac495dSmrg 					  * (count + 1)));
10236ac495dSmrg 
10336ac495dSmrg       /* Copy the methods.  */
10436ac495dSmrg       method_list = class_->methods;
10536ac495dSmrg 
10636ac495dSmrg       while (method_list)
10736ac495dSmrg 	{
10836ac495dSmrg 	  int j;
10936ac495dSmrg 	  for (j = 0; j < method_list->method_count; j++)
11036ac495dSmrg 	    {
11136ac495dSmrg 	      returnValue[i] = &(method_list->method_list[j]);
11236ac495dSmrg 	      i++;
11336ac495dSmrg 	    }
11436ac495dSmrg 	  method_list = method_list->method_next;
11536ac495dSmrg 	}
11636ac495dSmrg 
11736ac495dSmrg       returnValue[i] = NULL;
11836ac495dSmrg     }
11936ac495dSmrg 
12036ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
12136ac495dSmrg 
12236ac495dSmrg   if (numberOfReturnedMethods)
12336ac495dSmrg     *numberOfReturnedMethods = count;
12436ac495dSmrg 
12536ac495dSmrg   return returnValue;
12636ac495dSmrg }
12736ac495dSmrg 
12836ac495dSmrg IMP
method_setImplementation(struct objc_method * method,IMP implementation)12936ac495dSmrg method_setImplementation (struct objc_method * method, IMP implementation)
13036ac495dSmrg {
13136ac495dSmrg   IMP old_implementation;
13236ac495dSmrg 
13336ac495dSmrg   if (method == NULL  ||  implementation == NULL)
13436ac495dSmrg     return NULL;
13536ac495dSmrg 
13636ac495dSmrg   /* We lock the runtime mutex so that concurrent calls to change the
13736ac495dSmrg      same method won't conflict with each other.  */
13836ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
13936ac495dSmrg 
14036ac495dSmrg   old_implementation = method->method_imp;
14136ac495dSmrg   method->method_imp = implementation;
14236ac495dSmrg 
14336ac495dSmrg   /* That was easy :-).  But now we need to find all classes that use
14436ac495dSmrg      this method, and update the IMP in the dispatch tables.  */
14536ac495dSmrg   __objc_update_classes_with_methods (method, NULL);
14636ac495dSmrg 
14736ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
14836ac495dSmrg 
14936ac495dSmrg   return old_implementation;
15036ac495dSmrg }
15136ac495dSmrg 
15236ac495dSmrg void
method_exchangeImplementations(struct objc_method * method_a,struct objc_method * method_b)15336ac495dSmrg method_exchangeImplementations (struct objc_method * method_a, struct objc_method * method_b)
15436ac495dSmrg {
15536ac495dSmrg   IMP old_implementation_a;
15636ac495dSmrg   IMP old_implementation_b;
15736ac495dSmrg 
15836ac495dSmrg   if (method_a == NULL  ||  method_b == NULL)
15936ac495dSmrg     return;
16036ac495dSmrg 
16136ac495dSmrg   /* We lock the runtime mutex so that concurrent calls to exchange
16236ac495dSmrg      similar methods won't conflict with each other.  Each of them
16336ac495dSmrg      should be atomic.  */
16436ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
16536ac495dSmrg 
16636ac495dSmrg   old_implementation_a = method_a->method_imp;
16736ac495dSmrg   old_implementation_b = method_b->method_imp;
16836ac495dSmrg 
16936ac495dSmrg   method_a->method_imp = old_implementation_b;
17036ac495dSmrg   method_b->method_imp = old_implementation_a;
17136ac495dSmrg 
17236ac495dSmrg   /* That was easy :-).  But now we need to find all classes that use
17336ac495dSmrg      these methods, and update the IMP in the dispatch tables.  */
17436ac495dSmrg   __objc_update_classes_with_methods (method_a, method_b);
17536ac495dSmrg 
17636ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
17736ac495dSmrg }
178