1 1.1 mrg /* GNU Objective C Runtime message lookup 2 1.12 mrg Copyright (C) 1993-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Kresten Krab Thorup 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under the 8 1.1 mrg terms of the GNU General Public License as published by the Free Software 9 1.1 mrg Foundation; either version 3, or (at your option) any later version. 10 1.1 mrg 11 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 1.1 mrg details. 15 1.1 mrg 16 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 17 1.1 mrg permissions described in the GCC Runtime Library Exception, version 18 1.1 mrg 3.1, as published by the Free Software Foundation. 19 1.1 mrg 20 1.1 mrg You should have received a copy of the GNU General Public License and 21 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 22 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 1.1 mrg <http://www.gnu.org/licenses/>. */ 24 1.1 mrg 25 1.3 mrg /* Uncommented the following line to enable debug logging. Use this 26 1.3 mrg only while debugging the runtime. */ 27 1.3 mrg /* #define DEBUG 1 */ 28 1.1 mrg 29 1.1 mrg /* FIXME: This should be using libffi instead of __builtin_apply 30 1.1 mrg and friends. */ 31 1.1 mrg 32 1.3 mrg #include "objc-private/common.h" 33 1.3 mrg #include "objc-private/error.h" 34 1.1 mrg #include "tconfig.h" 35 1.1 mrg #include "coretypes.h" 36 1.1 mrg #include "objc/runtime.h" 37 1.3 mrg #include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */ 38 1.3 mrg #include "objc/thr.h" 39 1.3 mrg #include "objc-private/module-abi-8.h" 40 1.3 mrg #include "objc-private/runtime.h" 41 1.3 mrg #include "objc-private/hash.h" 42 1.3 mrg #include "objc-private/sarray.h" 43 1.3 mrg #include "objc-private/selector.h" /* For sel_is_mapped() */ 44 1.1 mrg #include "runtime-info.h" 45 1.3 mrg #include <assert.h> /* For assert */ 46 1.3 mrg #include <string.h> /* For strlen */ 47 1.1 mrg 48 1.1 mrg #define INVISIBLE_STRUCT_RETURN 1 49 1.1 mrg 50 1.3 mrg /* The uninstalled dispatch table. If a class' dispatch table points 51 1.3 mrg to __objc_uninstalled_dtable then that means it needs its dispatch 52 1.3 mrg table to be installed. */ 53 1.1 mrg struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */ 54 1.1 mrg 55 1.3 mrg /* Two hooks for method forwarding. If either is set, it is invoked to 56 1.3 mrg * return a function that performs the real forwarding. If both are 57 1.3 mrg * set, the result of __objc_msg_forward2 will be preferred over that 58 1.3 mrg * of __objc_msg_forward. If both return NULL or are unset, the 59 1.3 mrg * libgcc based functions (__builtin_apply and friends) are used. */ 60 1.1 mrg IMP (*__objc_msg_forward) (SEL) = NULL; 61 1.1 mrg IMP (*__objc_msg_forward2) (id, SEL) = NULL; 62 1.1 mrg 63 1.3 mrg /* Send +initialize to class. */ 64 1.1 mrg static void __objc_send_initialize (Class); 65 1.1 mrg 66 1.3 mrg /* Forward declare some functions */ 67 1.3 mrg static void __objc_install_dtable_for_class (Class cls); 68 1.3 mrg static void __objc_prepare_dtable_for_class (Class cls); 69 1.3 mrg static void __objc_install_prepared_dtable_for_class (Class cls); 70 1.1 mrg 71 1.3 mrg static struct sarray *__objc_prepared_dtable_for_class (Class cls); 72 1.3 mrg static IMP __objc_get_prepared_imp (Class cls,SEL sel); 73 1.3 mrg 74 1.1 mrg 75 1.1 mrg /* Various forwarding functions that are used based upon the 76 1.1 mrg return type for the selector. 77 1.1 mrg __objc_block_forward for structures. 78 1.1 mrg __objc_double_forward for floats/doubles. 79 1.3 mrg __objc_word_forward for pointers or types that fit in registers. */ 80 1.1 mrg static double __objc_double_forward (id, SEL, ...); 81 1.1 mrg static id __objc_word_forward (id, SEL, ...); 82 1.1 mrg typedef struct { id many[8]; } __big; 83 1.1 mrg #if INVISIBLE_STRUCT_RETURN 84 1.1 mrg static __big 85 1.1 mrg #else 86 1.1 mrg static id 87 1.1 mrg #endif 88 1.1 mrg __objc_block_forward (id, SEL, ...); 89 1.3 mrg static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel); 90 1.3 mrg struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op); 91 1.1 mrg id nil_method (id, SEL); 92 1.1 mrg 93 1.5 mrg /* Make sure this inline function is exported regardless of GNU89 or C99 94 1.5 mrg inlining semantics as it is part of the libobjc ABI. */ 95 1.5 mrg extern IMP __objc_get_forward_imp (id, SEL); 96 1.5 mrg 97 1.3 mrg /* Given a selector, return the proper forwarding implementation. */ 98 1.1 mrg IMP 99 1.1 mrg __objc_get_forward_imp (id rcv, SEL sel) 100 1.1 mrg { 101 1.3 mrg /* If a custom forwarding hook was registered, try getting a 102 1.3 mrg forwarding function from it. There are two forward routine hooks, 103 1.3 mrg one that takes the receiver as an argument and one that does 104 1.3 mrg not. */ 105 1.1 mrg if (__objc_msg_forward2) 106 1.1 mrg { 107 1.1 mrg IMP result; 108 1.1 mrg if ((result = __objc_msg_forward2 (rcv, sel)) != NULL) 109 1.1 mrg return result; 110 1.1 mrg } 111 1.1 mrg if (__objc_msg_forward) 112 1.1 mrg { 113 1.1 mrg IMP result; 114 1.1 mrg if ((result = __objc_msg_forward (sel)) != NULL) 115 1.3 mrg return result; 116 1.1 mrg } 117 1.1 mrg 118 1.3 mrg /* In all other cases, use the default forwarding functions built 119 1.3 mrg using __builtin_apply and friends. */ 120 1.1 mrg { 121 1.1 mrg const char *t = sel->sel_types; 122 1.3 mrg 123 1.1 mrg if (t && (*t == '[' || *t == '(' || *t == '{') 124 1.1 mrg #ifdef OBJC_MAX_STRUCT_BY_VALUE 125 1.1 mrg && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE 126 1.1 mrg #endif 127 1.1 mrg ) 128 1.1 mrg return (IMP)__objc_block_forward; 129 1.1 mrg else if (t && (*t == 'f' || *t == 'd')) 130 1.1 mrg return (IMP)__objc_double_forward; 131 1.1 mrg else 132 1.1 mrg return (IMP)__objc_word_forward; 133 1.1 mrg } 134 1.1 mrg } 135 1.1 mrg 136 1.3 mrg /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:. 137 1.3 mrg These are set up at startup. */ 138 1.3 mrg static SEL selector_resolveClassMethod = NULL; 139 1.3 mrg static SEL selector_resolveInstanceMethod = NULL; 140 1.3 mrg 141 1.3 mrg /* Internal routines use to resolve a class method using 142 1.3 mrg +resolveClassMethod:. 'class' is always a non-Nil class (*not* a 143 1.3 mrg meta-class), and 'sel' is the selector that we are trying to 144 1.3 mrg resolve. This must be called when class is not Nil, and the 145 1.3 mrg dispatch table for class methods has already been installed. 146 1.3 mrg 147 1.3 mrg This routine tries to call +resolveClassMethod: to give an 148 1.3 mrg opportunity to resolve the method. If +resolveClassMethod: returns 149 1.3 mrg YES, it tries looking up the method again, and if found, it returns 150 1.3 mrg it. Else, it returns NULL. */ 151 1.3 mrg static inline 152 1.3 mrg IMP 153 1.3 mrg __objc_resolve_class_method (Class class, SEL sel) 154 1.3 mrg { 155 1.3 mrg /* We need to lookup +resolveClassMethod:. */ 156 1.3 mrg BOOL (*resolveMethodIMP) (id, SEL, SEL); 157 1.3 mrg 158 1.3 mrg /* The dispatch table for class methods is already installed and we 159 1.3 mrg don't want any forwarding to happen when looking up this method, 160 1.3 mrg so we just look it up directly. Note that if 'sel' is precisely 161 1.3 mrg +resolveClassMethod:, this would look it up yet again and find 162 1.3 mrg nothing. That's no problem and there's no recursion. */ 163 1.3 mrg resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe 164 1.3 mrg (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id); 165 1.3 mrg 166 1.3 mrg if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel)) 167 1.3 mrg { 168 1.3 mrg /* +resolveClassMethod: returned YES. Look the method up again. 169 1.3 mrg We already know the dtable is installed. */ 170 1.3 mrg 171 1.3 mrg /* TODO: There is the case where +resolveClassMethod: is buggy 172 1.3 mrg and returned YES without actually adding the method. We 173 1.3 mrg could maybe print an error message. */ 174 1.3 mrg return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id); 175 1.3 mrg } 176 1.3 mrg 177 1.3 mrg return NULL; 178 1.3 mrg } 179 1.3 mrg 180 1.3 mrg /* Internal routines use to resolve a instance method using 181 1.3 mrg +resolveInstanceMethod:. 'class' is always a non-Nil class, and 182 1.3 mrg 'sel' is the selector that we are trying to resolve. This must be 183 1.3 mrg called when class is not Nil, and the dispatch table for instance 184 1.3 mrg methods has already been installed. 185 1.3 mrg 186 1.3 mrg This routine tries to call +resolveInstanceMethod: to give an 187 1.3 mrg opportunity to resolve the method. If +resolveInstanceMethod: 188 1.3 mrg returns YES, it tries looking up the method again, and if found, it 189 1.3 mrg returns it. Else, it returns NULL. */ 190 1.3 mrg static inline 191 1.3 mrg IMP 192 1.3 mrg __objc_resolve_instance_method (Class class, SEL sel) 193 1.3 mrg { 194 1.3 mrg /* We need to lookup +resolveInstanceMethod:. */ 195 1.3 mrg BOOL (*resolveMethodIMP) (id, SEL, SEL); 196 1.3 mrg 197 1.3 mrg /* The dispatch table for class methods may not be already installed 198 1.3 mrg so we have to install it if needed. */ 199 1.3 mrg resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable, 200 1.3 mrg (size_t) selector_resolveInstanceMethod->sel_id); 201 1.3 mrg if (resolveMethodIMP == 0) 202 1.3 mrg { 203 1.3 mrg /* Try again after installing the dtable. */ 204 1.3 mrg if (class->class_pointer->dtable == __objc_uninstalled_dtable) 205 1.3 mrg { 206 1.3 mrg objc_mutex_lock (__objc_runtime_mutex); 207 1.3 mrg if (class->class_pointer->dtable == __objc_uninstalled_dtable) 208 1.3 mrg __objc_install_dtable_for_class (class->class_pointer); 209 1.3 mrg objc_mutex_unlock (__objc_runtime_mutex); 210 1.3 mrg } 211 1.3 mrg resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable, 212 1.3 mrg (size_t) selector_resolveInstanceMethod->sel_id); 213 1.3 mrg } 214 1.3 mrg 215 1.3 mrg if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel)) 216 1.3 mrg { 217 1.3 mrg /* +resolveInstanceMethod: returned YES. Look the method up 218 1.3 mrg again. We already know the dtable is installed. */ 219 1.3 mrg 220 1.3 mrg /* TODO: There is the case where +resolveInstanceMethod: is 221 1.3 mrg buggy and returned YES without actually adding the method. 222 1.3 mrg We could maybe print an error message. */ 223 1.3 mrg return sarray_get_safe (class->dtable, (size_t) sel->sel_id); 224 1.3 mrg } 225 1.3 mrg 226 1.3 mrg return NULL; 227 1.3 mrg } 228 1.3 mrg 229 1.3 mrg /* Given a CLASS and selector, return the implementation corresponding 230 1.3 mrg to the method of the selector. 231 1.3 mrg 232 1.3 mrg If CLASS is a class, the instance method is returned. 233 1.3 mrg If CLASS is a meta class, the class method is returned. 234 1.3 mrg 235 1.3 mrg Since this requires the dispatch table to be installed, this function 236 1.3 mrg will implicitly invoke +initialize for CLASS if it hasn't been 237 1.3 mrg invoked yet. This also insures that +initialize has been invoked 238 1.3 mrg when the returned implementation is called directly. 239 1.3 mrg 240 1.3 mrg The forwarding hooks require the receiver as an argument (if they are to 241 1.3 mrg perform dynamic lookup in proxy objects etc), so this function has a 242 1.3 mrg receiver argument to be used with those hooks. */ 243 1.3 mrg static inline 244 1.3 mrg IMP 245 1.3 mrg get_implementation (id receiver, Class class, SEL sel) 246 1.3 mrg { 247 1.3 mrg void *res; 248 1.3 mrg 249 1.3 mrg if (class->dtable == __objc_uninstalled_dtable) 250 1.3 mrg { 251 1.3 mrg /* The dispatch table needs to be installed. */ 252 1.3 mrg objc_mutex_lock (__objc_runtime_mutex); 253 1.3 mrg 254 1.3 mrg /* Double-checked locking pattern: Check 255 1.3 mrg __objc_uninstalled_dtable again in case another thread 256 1.3 mrg installed the dtable while we were waiting for the lock to be 257 1.3 mrg released. */ 258 1.3 mrg if (class->dtable == __objc_uninstalled_dtable) 259 1.3 mrg __objc_install_dtable_for_class (class); 260 1.3 mrg 261 1.3 mrg /* If the dispatch table is not yet installed, we are still in 262 1.3 mrg the process of executing +initialize. But the implementation 263 1.3 mrg pointer should be available in the prepared ispatch table if 264 1.3 mrg it exists at all. */ 265 1.3 mrg if (class->dtable == __objc_uninstalled_dtable) 266 1.3 mrg { 267 1.3 mrg assert (__objc_prepared_dtable_for_class (class) != 0); 268 1.3 mrg res = __objc_get_prepared_imp (class, sel); 269 1.3 mrg } 270 1.3 mrg else 271 1.3 mrg res = 0; 272 1.3 mrg 273 1.3 mrg objc_mutex_unlock (__objc_runtime_mutex); 274 1.3 mrg /* Call ourselves with the installed dispatch table and get the 275 1.3 mrg real method. */ 276 1.3 mrg if (!res) 277 1.3 mrg res = get_implementation (receiver, class, sel); 278 1.3 mrg } 279 1.3 mrg else 280 1.3 mrg { 281 1.3 mrg /* The dispatch table has been installed. */ 282 1.3 mrg res = sarray_get_safe (class->dtable, (size_t) sel->sel_id); 283 1.3 mrg if (res == 0) 284 1.3 mrg { 285 1.3 mrg /* The dispatch table has been installed, and the method is 286 1.3 mrg not in the dispatch table. So the method just doesn't 287 1.3 mrg exist for the class. */ 288 1.3 mrg 289 1.3 mrg /* Try going through the +resolveClassMethod: or 290 1.3 mrg +resolveInstanceMethod: process. */ 291 1.3 mrg if (CLS_ISMETA (class)) 292 1.3 mrg { 293 1.3 mrg /* We have the meta class, but we need to invoke the 294 1.3 mrg +resolveClassMethod: method on the class. So, we 295 1.3 mrg need to obtain the class from the meta class, which 296 1.3 mrg we do using the fact that both the class and the 297 1.3 mrg meta-class have the same name. */ 298 1.3 mrg Class realClass = objc_lookUpClass (class->name); 299 1.3 mrg if (realClass) 300 1.3 mrg res = __objc_resolve_class_method (realClass, sel); 301 1.3 mrg } 302 1.3 mrg else 303 1.3 mrg res = __objc_resolve_instance_method (class, sel); 304 1.3 mrg 305 1.3 mrg if (res == 0) 306 1.3 mrg res = __objc_get_forward_imp (receiver, sel); 307 1.3 mrg } 308 1.3 mrg } 309 1.3 mrg return res; 310 1.3 mrg } 311 1.3 mrg 312 1.5 mrg /* Make sure this inline function is exported regardless of GNU89 or C99 313 1.5 mrg inlining semantics as it is part of the libobjc ABI. */ 314 1.5 mrg extern IMP get_imp (Class, SEL); 315 1.5 mrg 316 1.5 mrg inline 317 1.1 mrg IMP 318 1.1 mrg get_imp (Class class, SEL sel) 319 1.1 mrg { 320 1.1 mrg /* In a vanilla implementation we would first check if the dispatch 321 1.1 mrg table is installed. Here instead, to get more speed in the 322 1.1 mrg standard case (that the dispatch table is installed) we first try 323 1.1 mrg to get the imp using brute force. Only if that fails, we do what 324 1.1 mrg we should have been doing from the very beginning, that is, check 325 1.1 mrg if the dispatch table needs to be installed, install it if it's 326 1.1 mrg not installed, and retrieve the imp from the table if it's 327 1.1 mrg installed. */ 328 1.1 mrg void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id); 329 1.1 mrg if (res == 0) 330 1.1 mrg { 331 1.3 mrg res = get_implementation(nil, class, sel); 332 1.3 mrg } 333 1.3 mrg return res; 334 1.3 mrg } 335 1.1 mrg 336 1.3 mrg /* The new name of get_imp(). */ 337 1.3 mrg IMP 338 1.3 mrg class_getMethodImplementation (Class class_, SEL selector) 339 1.3 mrg { 340 1.3 mrg if (class_ == Nil || selector == NULL) 341 1.3 mrg return NULL; 342 1.1 mrg 343 1.3 mrg /* get_imp is inlined, so we're good. */ 344 1.3 mrg return get_imp (class_, selector); 345 1.3 mrg } 346 1.1 mrg 347 1.3 mrg /* Given a method, return its implementation. This has been replaced 348 1.3 mrg by method_getImplementation() in the modern API. */ 349 1.3 mrg IMP 350 1.3 mrg method_get_imp (struct objc_method * method) 351 1.3 mrg { 352 1.3 mrg return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0; 353 1.1 mrg } 354 1.1 mrg 355 1.1 mrg /* Query if an object can respond to a selector, returns YES if the 356 1.3 mrg object implements the selector otherwise NO. Does not check if the 357 1.3 mrg method can be forwarded. Since this requires the dispatch table to 358 1.3 mrg installed, this function will implicitly invoke +initialize for the 359 1.3 mrg class of OBJECT if it hasn't been invoked yet. */ 360 1.1 mrg BOOL 361 1.1 mrg __objc_responds_to (id object, SEL sel) 362 1.1 mrg { 363 1.1 mrg void *res; 364 1.3 mrg struct sarray *dtable; 365 1.1 mrg 366 1.1 mrg /* Install dispatch table if need be */ 367 1.3 mrg dtable = object->class_pointer->dtable; 368 1.3 mrg if (dtable == __objc_uninstalled_dtable) 369 1.1 mrg { 370 1.1 mrg objc_mutex_lock (__objc_runtime_mutex); 371 1.1 mrg if (object->class_pointer->dtable == __objc_uninstalled_dtable) 372 1.3 mrg __objc_install_dtable_for_class (object->class_pointer); 373 1.3 mrg 374 1.3 mrg /* If the dispatch table is not yet installed, we are still in 375 1.3 mrg the process of executing +initialize. Yet the dispatch table 376 1.3 mrg should be available. */ 377 1.3 mrg if (object->class_pointer->dtable == __objc_uninstalled_dtable) 378 1.3 mrg { 379 1.3 mrg dtable = __objc_prepared_dtable_for_class (object->class_pointer); 380 1.3 mrg assert (dtable); 381 1.3 mrg } 382 1.3 mrg else 383 1.3 mrg dtable = object->class_pointer->dtable; 384 1.3 mrg 385 1.3 mrg objc_mutex_unlock (__objc_runtime_mutex); 386 1.3 mrg } 387 1.3 mrg 388 1.3 mrg /* Get the method from the dispatch table. */ 389 1.3 mrg res = sarray_get_safe (dtable, (size_t) sel->sel_id); 390 1.3 mrg return (res != 0) ? YES : NO; 391 1.3 mrg } 392 1.3 mrg 393 1.3 mrg BOOL 394 1.3 mrg class_respondsToSelector (Class class_, SEL selector) 395 1.3 mrg { 396 1.3 mrg struct sarray *dtable; 397 1.3 mrg void *res; 398 1.3 mrg 399 1.3 mrg if (class_ == Nil || selector == NULL) 400 1.3 mrg return NO; 401 1.3 mrg 402 1.3 mrg /* Install dispatch table if need be. */ 403 1.3 mrg dtable = class_->dtable; 404 1.3 mrg if (dtable == __objc_uninstalled_dtable) 405 1.3 mrg { 406 1.3 mrg objc_mutex_lock (__objc_runtime_mutex); 407 1.3 mrg if (class_->dtable == __objc_uninstalled_dtable) 408 1.3 mrg __objc_install_dtable_for_class (class_); 409 1.3 mrg 410 1.3 mrg /* If the dispatch table is not yet installed, 411 1.3 mrg we are still in the process of executing +initialize. 412 1.3 mrg Yet the dispatch table should be available. */ 413 1.3 mrg if (class_->dtable == __objc_uninstalled_dtable) 414 1.3 mrg { 415 1.3 mrg dtable = __objc_prepared_dtable_for_class (class_); 416 1.3 mrg assert (dtable); 417 1.3 mrg } 418 1.3 mrg else 419 1.3 mrg dtable = class_->dtable; 420 1.3 mrg 421 1.1 mrg objc_mutex_unlock (__objc_runtime_mutex); 422 1.1 mrg } 423 1.1 mrg 424 1.3 mrg /* Get the method from the dispatch table. */ 425 1.3 mrg res = sarray_get_safe (dtable, (size_t) selector->sel_id); 426 1.3 mrg return (res != 0) ? YES : NO; 427 1.1 mrg } 428 1.1 mrg 429 1.3 mrg /* This is the lookup function. All entries in the table are either a 430 1.1 mrg valid method *or* zero. If zero then either the dispatch table 431 1.3 mrg needs to be installed or it doesn't exist and forwarding is 432 1.3 mrg attempted. */ 433 1.1 mrg IMP 434 1.1 mrg objc_msg_lookup (id receiver, SEL op) 435 1.1 mrg { 436 1.1 mrg IMP result; 437 1.1 mrg if (receiver) 438 1.1 mrg { 439 1.3 mrg /* First try a quick lookup assuming the dispatch table exists. */ 440 1.1 mrg result = sarray_get_safe (receiver->class_pointer->dtable, 441 1.1 mrg (sidx)op->sel_id); 442 1.1 mrg if (result == 0) 443 1.1 mrg { 444 1.3 mrg /* Not found ... call get_implementation () to install the 445 1.3 mrg dispatch table and call +initialize as required, 446 1.3 mrg providing the method implementation or a forwarding 447 1.3 mrg function. */ 448 1.3 mrg result = get_implementation (receiver, receiver->class_pointer, op); 449 1.1 mrg } 450 1.1 mrg return result; 451 1.1 mrg } 452 1.1 mrg else 453 1.1 mrg return (IMP)nil_method; 454 1.1 mrg } 455 1.1 mrg 456 1.1 mrg IMP 457 1.3 mrg objc_msg_lookup_super (struct objc_super *super, SEL sel) 458 1.1 mrg { 459 1.1 mrg if (super->self) 460 1.3 mrg return get_imp (super->super_class, sel); 461 1.1 mrg else 462 1.1 mrg return (IMP)nil_method; 463 1.1 mrg } 464 1.1 mrg 465 1.1 mrg void 466 1.1 mrg __objc_init_dispatch_tables () 467 1.1 mrg { 468 1.1 mrg __objc_uninstalled_dtable = sarray_new (200, 0); 469 1.3 mrg 470 1.3 mrg /* TODO: It would be cool to register typed selectors here. */ 471 1.3 mrg selector_resolveClassMethod = sel_registerName ("resolveClassMethod:"); 472 1.3 mrg selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:"); 473 1.1 mrg } 474 1.1 mrg 475 1.1 mrg 476 1.1 mrg /* Install dummy table for class which causes the first message to 477 1.3 mrg that class (or instances hereof) to be initialized properly. */ 478 1.1 mrg void 479 1.1 mrg __objc_install_premature_dtable (Class class) 480 1.1 mrg { 481 1.1 mrg assert (__objc_uninstalled_dtable); 482 1.1 mrg class->dtable = __objc_uninstalled_dtable; 483 1.1 mrg } 484 1.1 mrg 485 1.3 mrg /* Send +initialize to class if not already done. */ 486 1.1 mrg static void 487 1.1 mrg __objc_send_initialize (Class class) 488 1.1 mrg { 489 1.3 mrg /* This *must* be a class object. */ 490 1.1 mrg assert (CLS_ISCLASS (class)); 491 1.1 mrg assert (! CLS_ISMETA (class)); 492 1.1 mrg 493 1.3 mrg /* class_add_method_list/__objc_update_dispatch_table_for_class may 494 1.3 mrg have reset the dispatch table. The canonical way to insure that 495 1.3 mrg we send +initialize just once, is this flag. */ 496 1.1 mrg if (! CLS_ISINITIALIZED (class)) 497 1.1 mrg { 498 1.3 mrg DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name); 499 1.1 mrg CLS_SETINITIALIZED (class); 500 1.1 mrg CLS_SETINITIALIZED (class->class_pointer); 501 1.1 mrg 502 1.3 mrg /* Create the garbage collector type memory description. */ 503 1.1 mrg __objc_generate_gc_type_description (class); 504 1.1 mrg 505 1.1 mrg if (class->super_class) 506 1.1 mrg __objc_send_initialize (class->super_class); 507 1.1 mrg 508 1.1 mrg { 509 1.3 mrg SEL op = sel_registerName ("initialize"); 510 1.3 mrg struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer, 511 1.3 mrg op); 512 1.3 mrg 513 1.3 mrg if (method) 514 1.3 mrg { 515 1.3 mrg DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name); 516 1.3 mrg (*method->method_imp) ((id)class, op); 517 1.3 mrg DEBUG_PRINTF (" end of [%s +initialize]\n", class->name); 518 1.3 mrg } 519 1.3 mrg #ifdef DEBUG 520 1.3 mrg else 521 1.3 mrg { 522 1.3 mrg DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name); 523 1.3 mrg } 524 1.3 mrg #endif 525 1.1 mrg } 526 1.1 mrg } 527 1.1 mrg } 528 1.1 mrg 529 1.3 mrg /* Walk on the methods list of class and install the methods in the 530 1.3 mrg reverse order of the lists. Since methods added by categories are 531 1.3 mrg before the methods of class in the methods list, this allows 532 1.3 mrg categories to substitute methods declared in class. However if 533 1.3 mrg more than one category replaces the same method nothing is 534 1.3 mrg guaranteed about what method will be used. Assumes that 535 1.3 mrg __objc_runtime_mutex is locked down. */ 536 1.1 mrg static void 537 1.3 mrg __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list) 538 1.1 mrg { 539 1.1 mrg int i; 540 1.3 mrg 541 1.1 mrg if (! method_list) 542 1.1 mrg return; 543 1.3 mrg 544 1.1 mrg if (method_list->method_next) 545 1.3 mrg __objc_install_methods_in_dtable (dtable, method_list->method_next); 546 1.3 mrg 547 1.1 mrg for (i = 0; i < method_list->method_count; i++) 548 1.1 mrg { 549 1.3 mrg struct objc_method * method = &(method_list->method_list[i]); 550 1.3 mrg sarray_at_put_safe (dtable, 551 1.1 mrg (sidx) method->method_name->sel_id, 552 1.1 mrg method->method_imp); 553 1.1 mrg } 554 1.1 mrg } 555 1.1 mrg 556 1.1 mrg void 557 1.1 mrg __objc_update_dispatch_table_for_class (Class class) 558 1.1 mrg { 559 1.1 mrg Class next; 560 1.1 mrg struct sarray *arr; 561 1.1 mrg 562 1.3 mrg DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name); 563 1.1 mrg 564 1.1 mrg objc_mutex_lock (__objc_runtime_mutex); 565 1.1 mrg 566 1.3 mrg /* Not yet installed -- skip it unless in +initialize. */ 567 1.3 mrg if (class->dtable == __objc_uninstalled_dtable) 568 1.3 mrg { 569 1.3 mrg if (__objc_prepared_dtable_for_class (class)) 570 1.3 mrg { 571 1.3 mrg /* There is a prepared table so we must be initialising this 572 1.3 mrg class ... we must re-do the table preparation. */ 573 1.3 mrg __objc_prepare_dtable_for_class (class); 574 1.3 mrg } 575 1.3 mrg objc_mutex_unlock (__objc_runtime_mutex); 576 1.3 mrg return; 577 1.3 mrg } 578 1.3 mrg 579 1.1 mrg arr = class->dtable; 580 1.1 mrg __objc_install_premature_dtable (class); /* someone might require it... */ 581 1.1 mrg sarray_free (arr); /* release memory */ 582 1.3 mrg 583 1.3 mrg /* Could have been lazy... */ 584 1.3 mrg __objc_install_dtable_for_class (class); 585 1.1 mrg 586 1.3 mrg if (class->subclass_list) /* Traverse subclasses. */ 587 1.1 mrg for (next = class->subclass_list; next; next = next->sibling_class) 588 1.1 mrg __objc_update_dispatch_table_for_class (next); 589 1.1 mrg 590 1.1 mrg objc_mutex_unlock (__objc_runtime_mutex); 591 1.1 mrg } 592 1.1 mrg 593 1.1 mrg /* This function adds a method list to a class. This function is 594 1.1 mrg typically called by another function specific to the run-time. As 595 1.1 mrg such this function does not worry about thread safe issues. 596 1.1 mrg 597 1.1 mrg This one is only called for categories. Class objects have their 598 1.1 mrg methods installed right away, and their selectors are made into 599 1.3 mrg SEL's by the function __objc_register_selectors_from_class. */ 600 1.1 mrg void 601 1.3 mrg class_add_method_list (Class class, struct objc_method_list * list) 602 1.1 mrg { 603 1.1 mrg /* Passing of a linked list is not allowed. Do multiple calls. */ 604 1.1 mrg assert (! list->method_next); 605 1.1 mrg 606 1.1 mrg __objc_register_selectors_from_list(list); 607 1.1 mrg 608 1.1 mrg /* Add the methods to the class's method list. */ 609 1.1 mrg list->method_next = class->methods; 610 1.1 mrg class->methods = list; 611 1.1 mrg 612 1.3 mrg /* Update the dispatch table of class. */ 613 1.1 mrg __objc_update_dispatch_table_for_class (class); 614 1.1 mrg } 615 1.1 mrg 616 1.3 mrg struct objc_method * 617 1.3 mrg class_getInstanceMethod (Class class_, SEL selector) 618 1.1 mrg { 619 1.3 mrg struct objc_method *m; 620 1.3 mrg 621 1.3 mrg if (class_ == Nil || selector == NULL) 622 1.3 mrg return NULL; 623 1.3 mrg 624 1.3 mrg m = search_for_method_in_hierarchy (class_, selector); 625 1.3 mrg if (m) 626 1.3 mrg return m; 627 1.3 mrg 628 1.3 mrg /* Try going through +resolveInstanceMethod:, and do the search 629 1.3 mrg again if successful. */ 630 1.3 mrg if (__objc_resolve_instance_method (class_, selector)) 631 1.3 mrg return search_for_method_in_hierarchy (class_, selector); 632 1.3 mrg 633 1.3 mrg return NULL; 634 1.1 mrg } 635 1.1 mrg 636 1.3 mrg struct objc_method * 637 1.3 mrg class_getClassMethod (Class class_, SEL selector) 638 1.1 mrg { 639 1.3 mrg struct objc_method *m; 640 1.3 mrg 641 1.3 mrg if (class_ == Nil || selector == NULL) 642 1.3 mrg return NULL; 643 1.3 mrg 644 1.3 mrg m = search_for_method_in_hierarchy (class_->class_pointer, 645 1.3 mrg selector); 646 1.3 mrg if (m) 647 1.3 mrg return m; 648 1.3 mrg 649 1.3 mrg /* Try going through +resolveClassMethod:, and do the search again 650 1.3 mrg if successful. */ 651 1.3 mrg if (__objc_resolve_class_method (class_, selector)) 652 1.3 mrg return search_for_method_in_hierarchy (class_->class_pointer, 653 1.3 mrg selector); 654 1.3 mrg 655 1.3 mrg return NULL; 656 1.3 mrg } 657 1.3 mrg 658 1.3 mrg BOOL 659 1.3 mrg class_addMethod (Class class_, SEL selector, IMP implementation, 660 1.3 mrg const char *method_types) 661 1.3 mrg { 662 1.3 mrg struct objc_method_list *method_list; 663 1.3 mrg struct objc_method *method; 664 1.3 mrg const char *method_name; 665 1.3 mrg 666 1.3 mrg if (class_ == Nil || selector == NULL || implementation == NULL 667 1.3 mrg || method_types == NULL || (strcmp (method_types, "") == 0)) 668 1.3 mrg return NO; 669 1.3 mrg 670 1.3 mrg method_name = sel_getName (selector); 671 1.3 mrg if (method_name == NULL) 672 1.3 mrg return NO; 673 1.3 mrg 674 1.3 mrg /* If the method already exists in the class, return NO. It is fine 675 1.3 mrg if the method already exists in the superclass; in that case, we 676 1.3 mrg are overriding it. */ 677 1.3 mrg if (CLS_IS_IN_CONSTRUCTION (class_)) 678 1.3 mrg { 679 1.3 mrg /* The class only contains a list of methods; they have not been 680 1.3 mrg registered yet, ie, the method_name of each of them is still 681 1.3 mrg a string, not a selector. Iterate manually over them to 682 1.3 mrg check if we have already added the method. */ 683 1.3 mrg struct objc_method_list * method_list = class_->methods; 684 1.3 mrg while (method_list) 685 1.3 mrg { 686 1.3 mrg int i; 687 1.3 mrg 688 1.3 mrg /* Search the method list. */ 689 1.3 mrg for (i = 0; i < method_list->method_count; ++i) 690 1.3 mrg { 691 1.3 mrg struct objc_method * method = &method_list->method_list[i]; 692 1.3 mrg 693 1.3 mrg if (method->method_name 694 1.3 mrg && strcmp ((char *)method->method_name, method_name) == 0) 695 1.3 mrg return NO; 696 1.3 mrg } 697 1.3 mrg 698 1.3 mrg /* The method wasn't found. Follow the link to the next list of 699 1.3 mrg methods. */ 700 1.3 mrg method_list = method_list->method_next; 701 1.3 mrg } 702 1.3 mrg /* The method wasn't found. It's a new one. Go ahead and add 703 1.3 mrg it. */ 704 1.3 mrg } 705 1.3 mrg else 706 1.3 mrg { 707 1.3 mrg /* Do the standard lookup. This assumes the selectors are 708 1.3 mrg mapped. */ 709 1.3 mrg if (search_for_method_in_list (class_->methods, selector)) 710 1.3 mrg return NO; 711 1.3 mrg } 712 1.3 mrg 713 1.3 mrg method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list)); 714 1.3 mrg method_list->method_count = 1; 715 1.3 mrg 716 1.3 mrg method = &(method_list->method_list[0]); 717 1.3 mrg method->method_name = objc_malloc (strlen (method_name) + 1); 718 1.3 mrg strcpy ((char *)method->method_name, method_name); 719 1.3 mrg 720 1.3 mrg method->method_types = objc_malloc (strlen (method_types) + 1); 721 1.3 mrg strcpy ((char *)method->method_types, method_types); 722 1.3 mrg 723 1.3 mrg method->method_imp = implementation; 724 1.3 mrg 725 1.3 mrg if (CLS_IS_IN_CONSTRUCTION (class_)) 726 1.3 mrg { 727 1.3 mrg /* We only need to add the method to the list. It will be 728 1.3 mrg registered with the runtime when the class pair is registered 729 1.3 mrg (if ever). */ 730 1.3 mrg method_list->method_next = class_->methods; 731 1.3 mrg class_->methods = method_list; 732 1.3 mrg } 733 1.3 mrg else 734 1.3 mrg { 735 1.3 mrg /* Add the method to a live class. */ 736 1.3 mrg objc_mutex_lock (__objc_runtime_mutex); 737 1.3 mrg class_add_method_list (class_, method_list); 738 1.3 mrg objc_mutex_unlock (__objc_runtime_mutex); 739 1.3 mrg } 740 1.3 mrg 741 1.3 mrg return YES; 742 1.1 mrg } 743 1.1 mrg 744 1.3 mrg IMP 745 1.3 mrg class_replaceMethod (Class class_, SEL selector, IMP implementation, 746 1.3 mrg const char *method_types) 747 1.3 mrg { 748 1.3 mrg struct objc_method * method; 749 1.3 mrg 750 1.3 mrg if (class_ == Nil || selector == NULL || implementation == NULL 751 1.3 mrg || method_types == NULL) 752 1.3 mrg return NULL; 753 1.1 mrg 754 1.3 mrg method = search_for_method_in_hierarchy (class_, selector); 755 1.1 mrg 756 1.3 mrg if (method) 757 1.3 mrg { 758 1.3 mrg return method_setImplementation (method, implementation); 759 1.3 mrg } 760 1.3 mrg else 761 1.3 mrg { 762 1.3 mrg class_addMethod (class_, selector, implementation, method_types); 763 1.3 mrg return NULL; 764 1.3 mrg } 765 1.3 mrg } 766 1.3 mrg 767 1.3 mrg /* Search for a method starting from the current class up its 768 1.3 mrg hierarchy. Return a pointer to the method's method structure if 769 1.3 mrg found. NULL otherwise. */ 770 1.3 mrg static struct objc_method * 771 1.1 mrg search_for_method_in_hierarchy (Class cls, SEL sel) 772 1.1 mrg { 773 1.3 mrg struct objc_method * method = NULL; 774 1.1 mrg Class class; 775 1.1 mrg 776 1.1 mrg if (! sel_is_mapped (sel)) 777 1.1 mrg return NULL; 778 1.1 mrg 779 1.3 mrg /* Scan the method list of the class. If the method isn't found in 780 1.3 mrg the list then step to its super class. */ 781 1.1 mrg for (class = cls; ((! method) && class); class = class->super_class) 782 1.1 mrg method = search_for_method_in_list (class->methods, sel); 783 1.1 mrg 784 1.1 mrg return method; 785 1.1 mrg } 786 1.1 mrg 787 1.1 mrg 788 1.1 mrg 789 1.3 mrg /* Given a linked list of method and a method's name. Search for the 790 1.3 mrg named method's method structure. Return a pointer to the method's 791 1.3 mrg method structure if found. NULL otherwise. */ 792 1.3 mrg struct objc_method * 793 1.3 mrg search_for_method_in_list (struct objc_method_list * list, SEL op) 794 1.1 mrg { 795 1.3 mrg struct objc_method_list * method_list = list; 796 1.1 mrg 797 1.1 mrg if (! sel_is_mapped (op)) 798 1.1 mrg return NULL; 799 1.1 mrg 800 1.1 mrg /* If not found then we'll search the list. */ 801 1.1 mrg while (method_list) 802 1.1 mrg { 803 1.1 mrg int i; 804 1.1 mrg 805 1.1 mrg /* Search the method list. */ 806 1.1 mrg for (i = 0; i < method_list->method_count; ++i) 807 1.1 mrg { 808 1.3 mrg struct objc_method * method = &method_list->method_list[i]; 809 1.1 mrg 810 1.1 mrg if (method->method_name) 811 1.1 mrg if (method->method_name->sel_id == op->sel_id) 812 1.1 mrg return method; 813 1.1 mrg } 814 1.1 mrg 815 1.1 mrg /* The method wasn't found. Follow the link to the next list of 816 1.1 mrg methods. */ 817 1.1 mrg method_list = method_list->method_next; 818 1.1 mrg } 819 1.1 mrg 820 1.1 mrg return NULL; 821 1.1 mrg } 822 1.1 mrg 823 1.3 mrg typedef void * retval_t; 824 1.3 mrg typedef void * arglist_t; 825 1.3 mrg 826 1.1 mrg static retval_t __objc_forward (id object, SEL sel, arglist_t args); 827 1.1 mrg 828 1.3 mrg /* Forwarding pointers/integers through the normal registers. */ 829 1.1 mrg static id 830 1.1 mrg __objc_word_forward (id rcv, SEL op, ...) 831 1.1 mrg { 832 1.1 mrg void *args, *res; 833 1.1 mrg 834 1.1 mrg args = __builtin_apply_args (); 835 1.1 mrg res = __objc_forward (rcv, op, args); 836 1.1 mrg if (res) 837 1.1 mrg __builtin_return (res); 838 1.1 mrg else 839 1.1 mrg return res; 840 1.1 mrg } 841 1.1 mrg 842 1.1 mrg /* Specific routine for forwarding floats/double because of 843 1.3 mrg architectural differences on some processors. i386s for example 844 1.3 mrg which uses a floating point stack versus general registers for 845 1.3 mrg floating point numbers. This forward routine makes sure that GCC 846 1.3 mrg restores the proper return values. */ 847 1.1 mrg static double 848 1.1 mrg __objc_double_forward (id rcv, SEL op, ...) 849 1.1 mrg { 850 1.1 mrg void *args, *res; 851 1.1 mrg 852 1.1 mrg args = __builtin_apply_args (); 853 1.1 mrg res = __objc_forward (rcv, op, args); 854 1.1 mrg __builtin_return (res); 855 1.1 mrg } 856 1.1 mrg 857 1.1 mrg #if INVISIBLE_STRUCT_RETURN 858 1.1 mrg static __big 859 1.1 mrg #else 860 1.1 mrg static id 861 1.1 mrg #endif 862 1.1 mrg __objc_block_forward (id rcv, SEL op, ...) 863 1.1 mrg { 864 1.1 mrg void *args, *res; 865 1.1 mrg 866 1.1 mrg args = __builtin_apply_args (); 867 1.1 mrg res = __objc_forward (rcv, op, args); 868 1.1 mrg if (res) 869 1.1 mrg __builtin_return (res); 870 1.1 mrg else 871 1.1 mrg #if INVISIBLE_STRUCT_RETURN 872 1.1 mrg return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}}; 873 1.1 mrg #else 874 1.1 mrg return nil; 875 1.1 mrg #endif 876 1.1 mrg } 877 1.1 mrg 878 1.1 mrg 879 1.3 mrg /* This function is called for methods which are not implemented, 880 1.3 mrg unless a custom forwarding routine has been installed. Please note 881 1.3 mrg that most serious users of libobjc (eg, GNUstep base) do install 882 1.3 mrg their own forwarding routines, and hence this is never actually 883 1.3 mrg used. But, if no custom forwarding routine is installed, this is 884 1.3 mrg called when a selector is not recognized. */ 885 1.1 mrg static retval_t 886 1.1 mrg __objc_forward (id object, SEL sel, arglist_t args) 887 1.1 mrg { 888 1.1 mrg IMP imp; 889 1.1 mrg static SEL frwd_sel = 0; /* !T:SAFE2 */ 890 1.1 mrg SEL err_sel; 891 1.1 mrg 892 1.3 mrg /* First try if the object understands forward::. */ 893 1.1 mrg if (! frwd_sel) 894 1.1 mrg frwd_sel = sel_get_any_uid ("forward::"); 895 1.1 mrg 896 1.1 mrg if (__objc_responds_to (object, frwd_sel)) 897 1.1 mrg { 898 1.3 mrg imp = get_implementation (object, object->class_pointer, frwd_sel); 899 1.1 mrg return (*imp) (object, frwd_sel, sel, args); 900 1.1 mrg } 901 1.1 mrg 902 1.3 mrg /* If the object recognizes the doesNotRecognize: method then we're 903 1.3 mrg going to send it. */ 904 1.1 mrg err_sel = sel_get_any_uid ("doesNotRecognize:"); 905 1.1 mrg if (__objc_responds_to (object, err_sel)) 906 1.1 mrg { 907 1.3 mrg imp = get_implementation (object, object->class_pointer, err_sel); 908 1.1 mrg return (*imp) (object, err_sel, sel); 909 1.1 mrg } 910 1.1 mrg 911 1.1 mrg /* The object doesn't recognize the method. Check for responding to 912 1.3 mrg error:. If it does then sent it. */ 913 1.1 mrg { 914 1.3 mrg char msg[256 + strlen ((const char *) sel_getName (sel)) 915 1.1 mrg + strlen ((const char *) object->class_pointer->name)]; 916 1.1 mrg 917 1.1 mrg sprintf (msg, "(%s) %s does not recognize %s", 918 1.1 mrg (CLS_ISMETA (object->class_pointer) 919 1.1 mrg ? "class" 920 1.1 mrg : "instance" ), 921 1.3 mrg object->class_pointer->name, sel_getName (sel)); 922 1.1 mrg 923 1.3 mrg /* The object doesn't respond to doesNotRecognize:. Therefore, a 924 1.3 mrg default action is taken. */ 925 1.3 mrg _objc_abort ("%s\n", msg); 926 1.1 mrg 927 1.1 mrg return 0; 928 1.1 mrg } 929 1.1 mrg } 930 1.1 mrg 931 1.1 mrg void 932 1.3 mrg __objc_print_dtable_stats (void) 933 1.1 mrg { 934 1.1 mrg int total = 0; 935 1.1 mrg 936 1.1 mrg objc_mutex_lock (__objc_runtime_mutex); 937 1.1 mrg 938 1.1 mrg #ifdef OBJC_SPARSE2 939 1.1 mrg printf ("memory usage: (%s)\n", "2-level sparse arrays"); 940 1.1 mrg #else 941 1.1 mrg printf ("memory usage: (%s)\n", "3-level sparse arrays"); 942 1.1 mrg #endif 943 1.1 mrg 944 1.1 mrg printf ("arrays: %d = %ld bytes\n", narrays, 945 1.1 mrg (long) ((size_t) narrays * sizeof (struct sarray))); 946 1.1 mrg total += narrays * sizeof (struct sarray); 947 1.1 mrg printf ("buckets: %d = %ld bytes\n", nbuckets, 948 1.1 mrg (long) ((size_t) nbuckets * sizeof (struct sbucket))); 949 1.1 mrg total += nbuckets * sizeof (struct sbucket); 950 1.1 mrg 951 1.1 mrg printf ("idxtables: %d = %ld bytes\n", 952 1.1 mrg idxsize, (long) ((size_t) idxsize * sizeof (void *))); 953 1.1 mrg total += idxsize * sizeof (void *); 954 1.1 mrg printf ("-----------------------------------\n"); 955 1.1 mrg printf ("total: %d bytes\n", total); 956 1.1 mrg printf ("===================================\n"); 957 1.1 mrg 958 1.1 mrg objc_mutex_unlock (__objc_runtime_mutex); 959 1.1 mrg } 960 1.1 mrg 961 1.3 mrg static cache_ptr prepared_dtable_table = 0; 962 1.3 mrg 963 1.3 mrg /* This function is called by: objc_msg_lookup, get_imp and 964 1.3 mrg __objc_responds_to (and the dispatch table installation functions 965 1.3 mrg themselves) to install a dispatch table for a class. 966 1.3 mrg 967 1.3 mrg If CLS is a class, it installs instance methods. 968 1.3 mrg If CLS is a meta class, it installs class methods. 969 1.3 mrg 970 1.3 mrg In either case +initialize is invoked for the corresponding class. 971 1.3 mrg 972 1.3 mrg The implementation must insure that the dispatch table is not 973 1.3 mrg installed until +initialize completes. Otherwise it opens a 974 1.3 mrg potential race since the installation of the dispatch table is used 975 1.3 mrg as gate in regular method dispatch and we need to guarantee that 976 1.3 mrg +initialize is the first method invoked an that no other thread my 977 1.3 mrg dispatch messages to the class before +initialize completes. */ 978 1.3 mrg static void 979 1.3 mrg __objc_install_dtable_for_class (Class cls) 980 1.3 mrg { 981 1.3 mrg /* If the class has not yet had its class links resolved, we must 982 1.3 mrg re-compute all class links. */ 983 1.3 mrg if (! CLS_ISRESOLV (cls)) 984 1.3 mrg __objc_resolve_class_links (); 985 1.3 mrg 986 1.3 mrg /* Make sure the super class has its dispatch table installed or is 987 1.3 mrg at least preparing. We do not need to send initialize for the 988 1.3 mrg super class since __objc_send_initialize will insure that. */ 989 1.3 mrg if (cls->super_class 990 1.3 mrg && cls->super_class->dtable == __objc_uninstalled_dtable 991 1.3 mrg && !__objc_prepared_dtable_for_class (cls->super_class)) 992 1.3 mrg { 993 1.3 mrg __objc_install_dtable_for_class (cls->super_class); 994 1.3 mrg /* The superclass initialisation may have also initialised the 995 1.3 mrg current class, in which case there is no more to do. */ 996 1.3 mrg if (cls->dtable != __objc_uninstalled_dtable) 997 1.3 mrg return; 998 1.3 mrg } 999 1.3 mrg 1000 1.3 mrg /* We have already been prepared but +initialize hasn't completed. 1001 1.3 mrg The +initialize implementation is probably sending 'self' 1002 1.3 mrg messages. We rely on _objc_get_prepared_imp to retrieve the 1003 1.3 mrg implementation pointers. */ 1004 1.3 mrg if (__objc_prepared_dtable_for_class (cls)) 1005 1.3 mrg return; 1006 1.3 mrg 1007 1.3 mrg /* We have this function cache the implementation pointers for 1008 1.3 mrg _objc_get_prepared_imp but the dispatch table won't be initilized 1009 1.3 mrg until __objc_send_initialize completes. */ 1010 1.3 mrg __objc_prepare_dtable_for_class (cls); 1011 1.3 mrg 1012 1.3 mrg /* We may have already invoked +initialize but 1013 1.3 mrg __objc_update_dispatch_table_for_class invoked by 1014 1.3 mrg class_add_method_list may have reset dispatch table. */ 1015 1.3 mrg 1016 1.3 mrg /* Call +initialize. If we are a real class, we are installing 1017 1.3 mrg instance methods. If we are a meta class, we are installing 1018 1.3 mrg class methods. The __objc_send_initialize itself will insure 1019 1.3 mrg that the message is called only once per class. */ 1020 1.3 mrg if (CLS_ISCLASS (cls)) 1021 1.3 mrg __objc_send_initialize (cls); 1022 1.3 mrg else 1023 1.3 mrg { 1024 1.3 mrg /* Retrieve the class from the meta class. */ 1025 1.3 mrg Class c = objc_getClass (cls->name); 1026 1.3 mrg assert (CLS_ISMETA (cls)); 1027 1.3 mrg assert (c); 1028 1.3 mrg __objc_send_initialize (c); 1029 1.3 mrg } 1030 1.3 mrg 1031 1.3 mrg /* We install the dispatch table correctly when +initialize completed. */ 1032 1.3 mrg __objc_install_prepared_dtable_for_class (cls); 1033 1.3 mrg } 1034 1.3 mrg 1035 1.3 mrg /* Builds the dispatch table for the class CLS and stores it in a 1036 1.3 mrg place where it can be retrieved by __objc_get_prepared_imp until 1037 1.3 mrg __objc_install_prepared_dtable_for_class installs it into the 1038 1.3 mrg class. The dispatch table should not be installed into the class 1039 1.3 mrg until +initialize has completed. */ 1040 1.3 mrg static void 1041 1.3 mrg __objc_prepare_dtable_for_class (Class cls) 1042 1.3 mrg { 1043 1.3 mrg struct sarray *dtable; 1044 1.3 mrg struct sarray *super_dtable; 1045 1.3 mrg 1046 1.9 mrg /* This table could be initialized in init.c. We cannot use the 1047 1.3 mrg class name since the class maintains the instance methods and the 1048 1.12 mrg meta class maintains the class methods yet both share the 1049 1.3 mrg same name. Classes should be unique in any program. */ 1050 1.3 mrg if (! prepared_dtable_table) 1051 1.3 mrg prepared_dtable_table 1052 1.3 mrg = objc_hash_new (32, 1053 1.3 mrg (hash_func_type) objc_hash_ptr, 1054 1.3 mrg (compare_func_type) objc_compare_ptrs); 1055 1.3 mrg 1056 1.3 mrg /* If the class has not yet had its class links resolved, we must 1057 1.3 mrg re-compute all class links. */ 1058 1.3 mrg if (! CLS_ISRESOLV (cls)) 1059 1.3 mrg __objc_resolve_class_links (); 1060 1.3 mrg 1061 1.3 mrg assert (cls); 1062 1.3 mrg assert (cls->dtable == __objc_uninstalled_dtable); 1063 1.3 mrg 1064 1.3 mrg /* If there is already a prepared dtable for this class, we must 1065 1.3 mrg replace it with a new version (since there must have been methods 1066 1.3 mrg added to or otherwise modified in the class while executing 1067 1.3 mrg +initialize, and the table needs to be recomputed. */ 1068 1.3 mrg dtable = __objc_prepared_dtable_for_class (cls); 1069 1.3 mrg if (dtable != 0) 1070 1.3 mrg { 1071 1.3 mrg objc_hash_remove (prepared_dtable_table, cls); 1072 1.3 mrg sarray_free (dtable); 1073 1.3 mrg } 1074 1.3 mrg 1075 1.3 mrg /* Now prepare the dtable for population. */ 1076 1.3 mrg assert (cls != cls->super_class); 1077 1.3 mrg if (cls->super_class) 1078 1.3 mrg { 1079 1.3 mrg /* Inherit the method list from the super class. Yet the super 1080 1.3 mrg class may still be initializing in the case when a class 1081 1.3 mrg cluster sub class initializes its super classes. */ 1082 1.3 mrg if (cls->super_class->dtable == __objc_uninstalled_dtable) 1083 1.3 mrg __objc_install_dtable_for_class (cls->super_class); 1084 1.3 mrg 1085 1.3 mrg super_dtable = cls->super_class->dtable; 1086 1.3 mrg /* If the dispatch table is not yet installed, we are still in 1087 1.3 mrg the process of executing +initialize. Yet the dispatch table 1088 1.3 mrg should be available. */ 1089 1.3 mrg if (super_dtable == __objc_uninstalled_dtable) 1090 1.3 mrg super_dtable = __objc_prepared_dtable_for_class (cls->super_class); 1091 1.3 mrg 1092 1.3 mrg assert (super_dtable); 1093 1.3 mrg dtable = sarray_lazy_copy (super_dtable); 1094 1.3 mrg } 1095 1.3 mrg else 1096 1.3 mrg dtable = sarray_new (__objc_selector_max_index, 0); 1097 1.3 mrg 1098 1.3 mrg __objc_install_methods_in_dtable (dtable, cls->methods); 1099 1.3 mrg 1100 1.3 mrg objc_hash_add (&prepared_dtable_table, 1101 1.3 mrg cls, 1102 1.3 mrg dtable); 1103 1.3 mrg } 1104 1.3 mrg 1105 1.3 mrg /* This wrapper only exists to allow an easy replacement of the lookup 1106 1.3 mrg implementation and it is expected that the compiler will optimize 1107 1.3 mrg it away. */ 1108 1.3 mrg static struct sarray * 1109 1.3 mrg __objc_prepared_dtable_for_class (Class cls) 1110 1.3 mrg { 1111 1.3 mrg struct sarray *dtable = 0; 1112 1.3 mrg assert (cls); 1113 1.3 mrg if (prepared_dtable_table) 1114 1.3 mrg dtable = objc_hash_value_for_key (prepared_dtable_table, cls); 1115 1.3 mrg /* dtable my be nil, since we call this to check whether we are 1116 1.3 mrg currently preparing before we start preparing. */ 1117 1.3 mrg return dtable; 1118 1.3 mrg } 1119 1.3 mrg 1120 1.3 mrg /* Helper function for messages sent to CLS or implementation pointers 1121 1.3 mrg retrieved from CLS during +initialize before the dtable is 1122 1.3 mrg installed. When a class implicitly initializes another class which 1123 1.3 mrg in turn implicitly invokes methods in this class, before the 1124 1.3 mrg implementation of +initialize of CLS completes, this returns the 1125 1.3 mrg expected implementation. Forwarding remains the responsibility of 1126 1.3 mrg objc_msg_lookup. This function should only be called under the 1127 1.3 mrg global lock. */ 1128 1.3 mrg static IMP 1129 1.3 mrg __objc_get_prepared_imp (Class cls,SEL sel) 1130 1.3 mrg { 1131 1.3 mrg struct sarray *dtable; 1132 1.3 mrg IMP imp; 1133 1.3 mrg 1134 1.3 mrg assert (cls); 1135 1.3 mrg assert (sel); 1136 1.3 mrg assert (cls->dtable == __objc_uninstalled_dtable); 1137 1.3 mrg dtable = __objc_prepared_dtable_for_class (cls); 1138 1.3 mrg 1139 1.3 mrg assert (dtable); 1140 1.3 mrg assert (dtable != __objc_uninstalled_dtable); 1141 1.3 mrg imp = sarray_get_safe (dtable, (size_t) sel->sel_id); 1142 1.3 mrg 1143 1.3 mrg /* imp may be Nil if the method does not exist and we may fallback 1144 1.3 mrg to the forwarding implementation later. */ 1145 1.3 mrg return imp; 1146 1.3 mrg } 1147 1.3 mrg 1148 1.3 mrg /* When this function is called +initialize should be completed. So 1149 1.3 mrg now we are safe to install the dispatch table for the class so that 1150 1.3 mrg they become available for other threads that may be waiting in the 1151 1.3 mrg lock. */ 1152 1.3 mrg static void 1153 1.3 mrg __objc_install_prepared_dtable_for_class (Class cls) 1154 1.1 mrg { 1155 1.3 mrg assert (cls); 1156 1.3 mrg assert (cls->dtable == __objc_uninstalled_dtable); 1157 1.3 mrg cls->dtable = __objc_prepared_dtable_for_class (cls); 1158 1.3 mrg 1159 1.3 mrg assert (cls->dtable); 1160 1.3 mrg assert (cls->dtable != __objc_uninstalled_dtable); 1161 1.3 mrg objc_hash_remove (prepared_dtable_table, cls); 1162 1.1 mrg } 1163