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