xref: /netbsd-src/external/gpl3/gcc/dist/libobjc/methods.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
148fb7bfaSmrg /* GNU Objective C Runtime method related functions.
2*b1e83836Smrg    Copyright (C) 2010-2022 Free Software Foundation, Inc.
348fb7bfaSmrg    Contributed by Nicola Pero
448fb7bfaSmrg 
548fb7bfaSmrg This file is part of GCC.
648fb7bfaSmrg 
748fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under the
848fb7bfaSmrg terms of the GNU General Public License as published by the Free Software
948fb7bfaSmrg Foundation; either version 3, or (at your option) any later version.
1048fb7bfaSmrg 
1148fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1248fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1348fb7bfaSmrg FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
1448fb7bfaSmrg details.
1548fb7bfaSmrg 
1648fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1748fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1848fb7bfaSmrg 3.1, as published by the Free Software Foundation.
1948fb7bfaSmrg 
2048fb7bfaSmrg You should have received a copy of the GNU General Public License and
2148fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2248fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2348fb7bfaSmrg <http://www.gnu.org/licenses/>.  */
2448fb7bfaSmrg 
2548fb7bfaSmrg #include "objc-private/common.h"
2648fb7bfaSmrg #include "objc/runtime.h"
2748fb7bfaSmrg #include "objc-private/module-abi-8.h" /* For runtime structures.   */
2848fb7bfaSmrg #include "objc/thr.h"
2948fb7bfaSmrg #include "objc-private/runtime.h"      /* For __objc_runtime_mutex.  */
3048fb7bfaSmrg #include <stdlib.h>                    /* For malloc.  */
3148fb7bfaSmrg 
3248fb7bfaSmrg SEL
method_getName(struct objc_method * method)3348fb7bfaSmrg method_getName (struct objc_method * method)
3448fb7bfaSmrg {
3548fb7bfaSmrg   if (method == NULL)
3648fb7bfaSmrg     return NULL;
3748fb7bfaSmrg 
3848fb7bfaSmrg   return method->method_name;
3948fb7bfaSmrg }
4048fb7bfaSmrg 
4148fb7bfaSmrg const char *
method_getTypeEncoding(struct objc_method * method)4248fb7bfaSmrg method_getTypeEncoding (struct objc_method * method)
4348fb7bfaSmrg {
4448fb7bfaSmrg   if (method == NULL)
4548fb7bfaSmrg     return NULL;
4648fb7bfaSmrg 
4748fb7bfaSmrg   return method->method_types;
4848fb7bfaSmrg }
4948fb7bfaSmrg 
5048fb7bfaSmrg IMP
method_getImplementation(struct objc_method * method)5148fb7bfaSmrg method_getImplementation (struct objc_method * method)
5248fb7bfaSmrg {
5348fb7bfaSmrg   if (method == NULL)
5448fb7bfaSmrg     return NULL;
5548fb7bfaSmrg 
5648fb7bfaSmrg   return method->method_imp;
5748fb7bfaSmrg }
5848fb7bfaSmrg 
5948fb7bfaSmrg struct objc_method_description *
method_getDescription(struct objc_method * method)6048fb7bfaSmrg method_getDescription (struct objc_method * method)
6148fb7bfaSmrg {
6248fb7bfaSmrg   /* Note that the following returns NULL if method is NULL, which is
6348fb7bfaSmrg      fine.  */
6448fb7bfaSmrg   return (struct objc_method_description *)method;
6548fb7bfaSmrg }
6648fb7bfaSmrg 
6748fb7bfaSmrg struct objc_method **
class_copyMethodList(Class class_,unsigned int * numberOfReturnedMethods)6848fb7bfaSmrg class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods)
6948fb7bfaSmrg {
7048fb7bfaSmrg   unsigned int count = 0;
7148fb7bfaSmrg   struct objc_method **returnValue = NULL;
7248fb7bfaSmrg   struct objc_method_list* method_list;
7348fb7bfaSmrg 
7448fb7bfaSmrg   if (class_ == Nil)
7548fb7bfaSmrg     {
7648fb7bfaSmrg       if (numberOfReturnedMethods)
7748fb7bfaSmrg 	*numberOfReturnedMethods = 0;
7848fb7bfaSmrg       return NULL;
7948fb7bfaSmrg     }
8048fb7bfaSmrg 
8148fb7bfaSmrg   /* Lock the runtime mutex because the class methods may be
8248fb7bfaSmrg      concurrently modified.  */
8348fb7bfaSmrg   objc_mutex_lock (__objc_runtime_mutex);
8448fb7bfaSmrg 
8548fb7bfaSmrg   /* Count how many methods we have.  */
8648fb7bfaSmrg   method_list = class_->methods;
8748fb7bfaSmrg 
8848fb7bfaSmrg   while (method_list)
8948fb7bfaSmrg     {
9048fb7bfaSmrg       count = count + method_list->method_count;
9148fb7bfaSmrg       method_list = method_list->method_next;
9248fb7bfaSmrg     }
9348fb7bfaSmrg 
9448fb7bfaSmrg   if (count != 0)
9548fb7bfaSmrg     {
9648fb7bfaSmrg       unsigned int i = 0;
9748fb7bfaSmrg 
9848fb7bfaSmrg       /* Allocate enough memory to hold them.  */
9948fb7bfaSmrg       returnValue
10048fb7bfaSmrg 	= (struct objc_method **)(malloc (sizeof (struct objc_method *)
10148fb7bfaSmrg 					  * (count + 1)));
10248fb7bfaSmrg 
10348fb7bfaSmrg       /* Copy the methods.  */
10448fb7bfaSmrg       method_list = class_->methods;
10548fb7bfaSmrg 
10648fb7bfaSmrg       while (method_list)
10748fb7bfaSmrg 	{
10848fb7bfaSmrg 	  int j;
10948fb7bfaSmrg 	  for (j = 0; j < method_list->method_count; j++)
11048fb7bfaSmrg 	    {
11148fb7bfaSmrg 	      returnValue[i] = &(method_list->method_list[j]);
11248fb7bfaSmrg 	      i++;
11348fb7bfaSmrg 	    }
11448fb7bfaSmrg 	  method_list = method_list->method_next;
11548fb7bfaSmrg 	}
11648fb7bfaSmrg 
11748fb7bfaSmrg       returnValue[i] = NULL;
11848fb7bfaSmrg     }
11948fb7bfaSmrg 
12048fb7bfaSmrg   objc_mutex_unlock (__objc_runtime_mutex);
12148fb7bfaSmrg 
12248fb7bfaSmrg   if (numberOfReturnedMethods)
12348fb7bfaSmrg     *numberOfReturnedMethods = count;
12448fb7bfaSmrg 
12548fb7bfaSmrg   return returnValue;
12648fb7bfaSmrg }
12748fb7bfaSmrg 
12848fb7bfaSmrg IMP
method_setImplementation(struct objc_method * method,IMP implementation)12948fb7bfaSmrg method_setImplementation (struct objc_method * method, IMP implementation)
13048fb7bfaSmrg {
13148fb7bfaSmrg   IMP old_implementation;
13248fb7bfaSmrg 
13348fb7bfaSmrg   if (method == NULL  ||  implementation == NULL)
13448fb7bfaSmrg     return NULL;
13548fb7bfaSmrg 
13648fb7bfaSmrg   /* We lock the runtime mutex so that concurrent calls to change the
13748fb7bfaSmrg      same method won't conflict with each other.  */
13848fb7bfaSmrg   objc_mutex_lock (__objc_runtime_mutex);
13948fb7bfaSmrg 
14048fb7bfaSmrg   old_implementation = method->method_imp;
14148fb7bfaSmrg   method->method_imp = implementation;
14248fb7bfaSmrg 
14348fb7bfaSmrg   /* That was easy :-).  But now we need to find all classes that use
14448fb7bfaSmrg      this method, and update the IMP in the dispatch tables.  */
14548fb7bfaSmrg   __objc_update_classes_with_methods (method, NULL);
14648fb7bfaSmrg 
14748fb7bfaSmrg   objc_mutex_unlock (__objc_runtime_mutex);
14848fb7bfaSmrg 
14948fb7bfaSmrg   return old_implementation;
15048fb7bfaSmrg }
15148fb7bfaSmrg 
15248fb7bfaSmrg void
method_exchangeImplementations(struct objc_method * method_a,struct objc_method * method_b)15348fb7bfaSmrg method_exchangeImplementations (struct objc_method * method_a, struct objc_method * method_b)
15448fb7bfaSmrg {
15548fb7bfaSmrg   IMP old_implementation_a;
15648fb7bfaSmrg   IMP old_implementation_b;
15748fb7bfaSmrg 
15848fb7bfaSmrg   if (method_a == NULL  ||  method_b == NULL)
15948fb7bfaSmrg     return;
16048fb7bfaSmrg 
16148fb7bfaSmrg   /* We lock the runtime mutex so that concurrent calls to exchange
16248fb7bfaSmrg      similar methods won't conflict with each other.  Each of them
16348fb7bfaSmrg      should be atomic.  */
16448fb7bfaSmrg   objc_mutex_lock (__objc_runtime_mutex);
16548fb7bfaSmrg 
16648fb7bfaSmrg   old_implementation_a = method_a->method_imp;
16748fb7bfaSmrg   old_implementation_b = method_b->method_imp;
16848fb7bfaSmrg 
16948fb7bfaSmrg   method_a->method_imp = old_implementation_b;
17048fb7bfaSmrg   method_b->method_imp = old_implementation_a;
17148fb7bfaSmrg 
17248fb7bfaSmrg   /* That was easy :-).  But now we need to find all classes that use
17348fb7bfaSmrg      these methods, and update the IMP in the dispatch tables.  */
17448fb7bfaSmrg   __objc_update_classes_with_methods (method_a, method_b);
17548fb7bfaSmrg 
17648fb7bfaSmrg   objc_mutex_unlock (__objc_runtime_mutex);
17748fb7bfaSmrg }
178