136ac495dSmrg/* GNU Objective C Runtime accessors functions 2*8feb0f0bSmrg Copyright (C) 2010-2020 Free Software Foundation, Inc. 336ac495dSmrg Contributed by Nicola Pero 436ac495dSmrg 536ac495dSmrgThis file is part of GCC. 636ac495dSmrg 736ac495dSmrgGCC is free software; you can redistribute it and/or modify it under the 836ac495dSmrgterms of the GNU General Public License as published by the Free Software 936ac495dSmrgFoundation; either version 3, or (at your option) any later version. 1036ac495dSmrg 1136ac495dSmrgGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1236ac495dSmrgWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 1336ac495dSmrgFOR A PARTICULAR PURPOSE. See the GNU General Public License for more 1436ac495dSmrgdetails. 1536ac495dSmrg 1636ac495dSmrgUnder Section 7 of GPL version 3, you are granted additional 1736ac495dSmrgpermissions described in the GCC Runtime Library Exception, version 1836ac495dSmrg3.1, as published by the Free Software Foundation. 1936ac495dSmrg 2036ac495dSmrgYou should have received a copy of the GNU General Public License and 2136ac495dSmrga copy of the GCC Runtime Library Exception along with this program; 2236ac495dSmrgsee 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/objc.h" 2736ac495dSmrg#include "objc/thr.h" 2836ac495dSmrg#include <string.h> /* For memcpy */ 2936ac495dSmrg 3036ac495dSmrg/* This file contains functions that the compiler uses when 3136ac495dSmrg synthesizing accessors (getters/setters) for properties. The 3236ac495dSmrg functions are part of the ABI, but are meant to be used by the 3336ac495dSmrg compiler and not by users; for this reason, they are not declared 3436ac495dSmrg in public header files. The compiler automatically generates 3536ac495dSmrg declarations for these functions. */ 3636ac495dSmrg 3736ac495dSmrg/* Properties can be "atomic", which requires protecting them from 3836ac495dSmrg concurrency issues using a lock. Unfortunately, we can't have a 3936ac495dSmrg lock for each property, so we'll go with a small pool of locks. 4036ac495dSmrg Any time a property is accessed in an "atomic" way, we pick a 4136ac495dSmrg random lock from the pool (random, but always the same one for the 4236ac495dSmrg same property of the same object) and use it to protect access to 4336ac495dSmrg the property. 4436ac495dSmrg 4536ac495dSmrg The size of the pool is currently 16. A bigger pool can help 4636ac495dSmrg reduce contention, ie, reduce the chances that two threads, 4736ac495dSmrg operating on unrelated properties, will have to wait for each other 4836ac495dSmrg because the properties use the same lock. 16 seems big enough at 4936ac495dSmrg the moment. */ 5036ac495dSmrg#define ACCESSORS_NUMBER_OF_LOCKS 16 5136ac495dSmrg 5236ac495dSmrg#define ACCESSORS_HASH(POINTER) ((((size_t)POINTER >> 8) ^ (size_t)POINTER) & (ACCESSORS_NUMBER_OF_LOCKS - 1)) 5336ac495dSmrg 5436ac495dSmrgstatic objc_mutex_t accessors_locks[ACCESSORS_NUMBER_OF_LOCKS]; 5536ac495dSmrg 5636ac495dSmrg/* This is called at startup to setup the locks. */ 5736ac495dSmrgvoid 5836ac495dSmrg__objc_accessors_init (void) 5936ac495dSmrg{ 6036ac495dSmrg int i; 6136ac495dSmrg 6236ac495dSmrg for (i = 0; i < ACCESSORS_NUMBER_OF_LOCKS; i++) 6336ac495dSmrg accessors_locks[i] = objc_mutex_allocate (); 6436ac495dSmrg} 6536ac495dSmrg 6636ac495dSmrg/* The property accessors automatically call various methods from the 6736ac495dSmrg Foundation library (eg, GNUstep-base). These methods are not 6836ac495dSmrg implemented here, but we need to declare them so we can compile the 6936ac495dSmrg runtime. The Foundation library will need to provide 7036ac495dSmrg implementations of these methods (most likely in the root class, 7136ac495dSmrg eg, NSObject) as the accessors only work with objects of classes 7236ac495dSmrg that implement these methods. */ 7336ac495dSmrg@interface _libobjcNSObject 7436ac495dSmrg- (id) copyWithZone: (void *)zone; 7536ac495dSmrg- (id) mutableCopyWithZone: (void *)zone; 7636ac495dSmrg@end 7736ac495dSmrg#define COPY(X) [((_libobjcNSObject *)(X)) copyWithZone: NULL] 7836ac495dSmrg#define MUTABLE_COPY(X) [((_libobjcNSObject *)(X)) mutableCopyWithZone: NULL] 7936ac495dSmrg 8036ac495dSmrg 8136ac495dSmrg#if OBJC_WITH_GC 8236ac495dSmrg 8336ac495dSmrg# define AUTORELEASE(X) (X) 8436ac495dSmrg# define RELEASE(X) 8536ac495dSmrg# define RETAIN(X) (X) 8636ac495dSmrg 8736ac495dSmrg#else 8836ac495dSmrg 8936ac495dSmrg@interface _libobjcNSObject (RetainReleaseMethods) 9036ac495dSmrg- (id) autorelease; 9136ac495dSmrg- (oneway void) release; 9236ac495dSmrg- (id) retain; 9336ac495dSmrg@end 9436ac495dSmrg# define AUTORELEASE(X) [((_libobjcNSObject *)(X)) autorelease] 9536ac495dSmrg# define RELEASE(X) [((_libobjcNSObject *)(X)) release] 9636ac495dSmrg# define RETAIN(X) [((_libobjcNSObject *)(X)) retain] 9736ac495dSmrg 9836ac495dSmrg#endif 9936ac495dSmrg 10036ac495dSmrg/* The compiler uses this function when implementing some synthesized 10136ac495dSmrg getters for properties of type 'id'. */ 10236ac495dSmrgid 10336ac495dSmrgobjc_getProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, BOOL is_atomic) 10436ac495dSmrg{ 10536ac495dSmrg if (self != nil) 10636ac495dSmrg { 10736ac495dSmrg id *pointer_to_ivar = (id *)((char *)self + offset); 10836ac495dSmrg 10936ac495dSmrg 11036ac495dSmrg if (is_atomic == NO) 11136ac495dSmrg { 11236ac495dSmrg /* Note that in this case, we do not RETAIN/AUTORELEASE the 11336ac495dSmrg returned value. The programmer should do it if it is 11436ac495dSmrg needed. Since access is non-atomic, other threads can be 11536ac495dSmrg ignored and the caller has full control of what happens 11636ac495dSmrg to the object and whether it needs to be RETAINed or not, 11736ac495dSmrg so it makes sense to leave the decision to him/her. This 11836ac495dSmrg is also what the Apple/NeXT runtime does. */ 11936ac495dSmrg return *pointer_to_ivar; 12036ac495dSmrg } 12136ac495dSmrg else 12236ac495dSmrg { 12336ac495dSmrg objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)]; 12436ac495dSmrg id result; 12536ac495dSmrg 12636ac495dSmrg objc_mutex_lock (lock); 12736ac495dSmrg result = RETAIN (*(pointer_to_ivar)); 12836ac495dSmrg objc_mutex_unlock (lock); 12936ac495dSmrg 13036ac495dSmrg return AUTORELEASE (result); 13136ac495dSmrg } 13236ac495dSmrg } 13336ac495dSmrg 13436ac495dSmrg return nil; 13536ac495dSmrg} 13636ac495dSmrg 13736ac495dSmrg/* The compiler uses this function when implementing some synthesized 13836ac495dSmrg setters for properties of type 'id'. 13936ac495dSmrg 14036ac495dSmrg PS: Note how 'should_copy' is declared 'BOOL' but then actually 14136ac495dSmrg takes values from 0 to 2. This hack was introduced by Apple; we 14236ac495dSmrg do the same for compatibility reasons. */ 14336ac495dSmrgvoid 14436ac495dSmrgobjc_setProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, id new_value, BOOL is_atomic, BOOL should_copy) 14536ac495dSmrg{ 14636ac495dSmrg if (self != nil) 14736ac495dSmrg { 14836ac495dSmrg id *pointer_to_ivar = (id *)((char *)self + offset); 14936ac495dSmrg id retained_value; 15036ac495dSmrg#if !OBJC_WITH_GC 15136ac495dSmrg id old_value; 15236ac495dSmrg#endif 15336ac495dSmrg 15436ac495dSmrg switch (should_copy) 15536ac495dSmrg { 15636ac495dSmrg case 0: /* retain */ 15736ac495dSmrg { 15836ac495dSmrg if (*pointer_to_ivar == new_value) 15936ac495dSmrg return; 16036ac495dSmrg retained_value = RETAIN (new_value); 16136ac495dSmrg break; 16236ac495dSmrg } 16336ac495dSmrg case 2: /* mutable copy */ 16436ac495dSmrg { 16536ac495dSmrg retained_value = MUTABLE_COPY (new_value); 16636ac495dSmrg break; 16736ac495dSmrg } 16836ac495dSmrg case 1: /* copy */ 16936ac495dSmrg default: 17036ac495dSmrg { 17136ac495dSmrg retained_value = COPY (new_value); 17236ac495dSmrg break; 17336ac495dSmrg } 17436ac495dSmrg } 17536ac495dSmrg 17636ac495dSmrg if (is_atomic == NO) 17736ac495dSmrg { 17836ac495dSmrg#if !OBJC_WITH_GC 17936ac495dSmrg old_value = *pointer_to_ivar; 18036ac495dSmrg#endif 18136ac495dSmrg *pointer_to_ivar = retained_value; 18236ac495dSmrg } 18336ac495dSmrg else 18436ac495dSmrg { 18536ac495dSmrg objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)]; 18636ac495dSmrg 18736ac495dSmrg objc_mutex_lock (lock); 18836ac495dSmrg#if !OBJC_WITH_GC 18936ac495dSmrg old_value = *pointer_to_ivar; 19036ac495dSmrg#endif 19136ac495dSmrg *pointer_to_ivar = retained_value; 19236ac495dSmrg objc_mutex_unlock (lock); 19336ac495dSmrg } 19436ac495dSmrg#if !OBJC_WITH_GC 19536ac495dSmrg RELEASE (old_value); 19636ac495dSmrg#endif 19736ac495dSmrg } 19836ac495dSmrg} 19936ac495dSmrg 20036ac495dSmrg/* The compiler uses this function when implementing some synthesized 20136ac495dSmrg getters for properties of arbitrary C types. The data is just 20236ac495dSmrg copied. Compatibility Note: this function does not exist in the 20336ac495dSmrg Apple/NeXT runtime. */ 20436ac495dSmrgvoid 20536ac495dSmrgobjc_getPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) 20636ac495dSmrg{ 20736ac495dSmrg if (is_atomic == NO) 20836ac495dSmrg memcpy (destination, source, size); 20936ac495dSmrg else 21036ac495dSmrg { 21136ac495dSmrg objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (source)]; 21236ac495dSmrg 21336ac495dSmrg objc_mutex_lock (lock); 21436ac495dSmrg memcpy (destination, source, size); 21536ac495dSmrg objc_mutex_unlock (lock); 21636ac495dSmrg } 21736ac495dSmrg} 21836ac495dSmrg 21936ac495dSmrg/* The compiler uses this function when implementing some synthesized 22036ac495dSmrg setters for properties of arbitrary C types. The data is just 22136ac495dSmrg copied. Compatibility Note: this function does not exist in the 22236ac495dSmrg Apple/NeXT runtime. */ 22336ac495dSmrgvoid 22436ac495dSmrgobjc_setPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) 22536ac495dSmrg{ 22636ac495dSmrg if (is_atomic == NO) 22736ac495dSmrg memcpy (destination, source, size); 22836ac495dSmrg else 22936ac495dSmrg { 23036ac495dSmrg objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (destination)]; 23136ac495dSmrg 23236ac495dSmrg objc_mutex_lock (lock); 23336ac495dSmrg memcpy (destination, source, size); 23436ac495dSmrg objc_mutex_unlock (lock); 23536ac495dSmrg } 23636ac495dSmrg} 23736ac495dSmrg 23836ac495dSmrg/* This is the function that the Apple/NeXT runtime has instead of 23936ac495dSmrg objc_getPropertyStruct and objc_setPropertyStruct. We include it 24036ac495dSmrg for API compatibility (just for people who may have used 24136ac495dSmrg objc_copyStruct on the NeXT runtime thinking it was a public API); 24236ac495dSmrg the compiler never generates calls to it with the GNU runtime. 24336ac495dSmrg This function is clumsy because it requires two locks instead of 24436ac495dSmrg one. */ 24536ac495dSmrgvoid 24636ac495dSmrgobjc_copyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) 24736ac495dSmrg{ 24836ac495dSmrg if (is_atomic == NO) 24936ac495dSmrg memcpy (destination, source, size); 25036ac495dSmrg else 25136ac495dSmrg { 25236ac495dSmrg /* We don't know which one is the property, so we have to lock 25336ac495dSmrg both. One of them is most likely a temporary buffer in the 25436ac495dSmrg local stack and we really wouldn't want to lock it (our 25536ac495dSmrg objc_getPropertyStruct and objc_setPropertyStruct functions 25636ac495dSmrg don't lock it). Note that if we're locking more than one 25736ac495dSmrg accessor lock at once, we need to always lock them in the 25836ac495dSmrg same order to avoid deadlocks. */ 25936ac495dSmrg objc_mutex_t first_lock; 26036ac495dSmrg objc_mutex_t second_lock; 26136ac495dSmrg 26236ac495dSmrg if (ACCESSORS_HASH (source) == ACCESSORS_HASH (destination)) 26336ac495dSmrg { 26436ac495dSmrg /* A lucky collision. */ 26536ac495dSmrg first_lock = accessors_locks[ACCESSORS_HASH (source)]; 26636ac495dSmrg objc_mutex_lock (first_lock); 26736ac495dSmrg memcpy (destination, source, size); 26836ac495dSmrg objc_mutex_unlock (first_lock); 26936ac495dSmrg return; 27036ac495dSmrg } 27136ac495dSmrg 27236ac495dSmrg if (ACCESSORS_HASH (source) > ACCESSORS_HASH (destination)) 27336ac495dSmrg { 27436ac495dSmrg first_lock = accessors_locks[ACCESSORS_HASH (source)]; 27536ac495dSmrg second_lock = accessors_locks[ACCESSORS_HASH (destination)]; 27636ac495dSmrg } 27736ac495dSmrg else 27836ac495dSmrg { 27936ac495dSmrg first_lock = accessors_locks[ACCESSORS_HASH (destination)]; 28036ac495dSmrg second_lock = accessors_locks[ACCESSORS_HASH (source)]; 28136ac495dSmrg } 28236ac495dSmrg 28336ac495dSmrg objc_mutex_lock (first_lock); 28436ac495dSmrg objc_mutex_lock (second_lock); 28536ac495dSmrg memcpy (destination, source, size); 28636ac495dSmrg objc_mutex_unlock (second_lock); 28736ac495dSmrg objc_mutex_unlock (first_lock); 28836ac495dSmrg } 28936ac495dSmrg} 290