diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libobjc/accessors.m | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libobjc/accessors.m')
-rw-r--r-- | libobjc/accessors.m | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/libobjc/accessors.m b/libobjc/accessors.m new file mode 100644 index 000000000..a47903a6c --- /dev/null +++ b/libobjc/accessors.m @@ -0,0 +1,289 @@ +/* GNU Objective C Runtime accessors functions + Copyright (C) 2010 Free Software Foundation, Inc. + Contributed by Nicola Pero + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3, or (at your option) any later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#include "objc-private/common.h" +#include "objc/objc.h" +#include "objc/thr.h" +#include <string.h> /* For memcpy */ + +/* This file contains functions that the compiler uses when + synthesizing accessors (getters/setters) for properties. The + functions are part of the ABI, but are meant to be used by the + compiler and not by users; for this reason, they are not declared + in public header files. The compiler automatically generates + declarations for these functions. */ + +/* Properties can be "atomic", which requires protecting them from + concurrency issues using a lock. Unfortunately, we can't have a + lock for each property, so we'll go with a small pool of locks. + Any time a property is accessed in an "atomic" way, we pick a + random lock from the pool (random, but always the same one for the + same property of the same object) and use it to protect access to + the property. + + The size of the pool is currently 16. A bigger pool can help + reduce contention, ie, reduce the chances that two threads, + operating on unrelated properties, will have to wait for each other + because the properties use the same lock. 16 seems big enough at + the moment. */ +#define ACCESSORS_NUMBER_OF_LOCKS 16 + +#define ACCESSORS_HASH(POINTER) ((((size_t)POINTER >> 8) ^ (size_t)POINTER) & (ACCESSORS_NUMBER_OF_LOCKS - 1)) + +static objc_mutex_t accessors_locks[ACCESSORS_NUMBER_OF_LOCKS]; + +/* This is called at startup to setup the locks. */ +void +__objc_accessors_init (void) +{ + int i; + + for (i = 0; i < ACCESSORS_NUMBER_OF_LOCKS; i++) + accessors_locks[i] = objc_mutex_allocate (); +} + +/* The property accessors automatically call various methods from the + Foundation library (eg, GNUstep-base). These methods are not + implemented here, but we need to declare them so we can compile the + runtime. The Foundation library will need to provide + implementations of these methods (most likely in the root class, + eg, NSObject) as the accessors only work with objects of classes + that implement these methods. */ +@interface _libobjcNSObject +- (id) copyWithZone: (void *)zone; +- (id) mutableCopyWithZone: (void *)zone; +@end +#define COPY(X) [((_libobjcNSObject *)(X)) copyWithZone: NULL] +#define MUTABLE_COPY(X) [((_libobjcNSObject *)(X)) mutableCopyWithZone: NULL] + + +#if OBJC_WITH_GC + +# define AUTORELEASE(X) (X) +# define RELEASE(X) +# define RETAIN(X) (X) + +#else + +@interface _libobjcNSObject (RetainReleaseMethods) +- (id) autorelease; +- (oneway void) release; +- (id) retain; +@end +# define AUTORELEASE(X) [((_libobjcNSObject *)(X)) autorelease] +# define RELEASE(X) [((_libobjcNSObject *)(X)) release] +# define RETAIN(X) [((_libobjcNSObject *)(X)) retain] + +#endif + +/* The compiler uses this function when implementing some synthesized + getters for properties of type 'id'. */ +id +objc_getProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, BOOL is_atomic) +{ + if (self != nil) + { + id *pointer_to_ivar = (id *)((char *)self + offset); + + + if (is_atomic == NO) + { + /* Note that in this case, we do not RETAIN/AUTORELEASE the + returned value. The programmer should do it if it is + needed. Since access is non-atomic, other threads can be + ignored and the caller has full control of what happens + to the object and whether it needs to be RETAINed or not, + so it makes sense to leave the decision to him/her. This + is also what the Apple/NeXT runtime does. */ + return *pointer_to_ivar; + } + else + { + objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)]; + id result; + + objc_mutex_lock (lock); + result = RETAIN (*(pointer_to_ivar)); + objc_mutex_unlock (lock); + + return AUTORELEASE (result); + } + } + + return nil; +} + +/* The compiler uses this function when implementing some synthesized + setters for properties of type 'id'. + + PS: Note how 'should_copy' is declared 'BOOL' but then actually + takes values from 0 to 2. This hack was introduced by Apple; we + do the same for compatibility reasons. */ +void +objc_setProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, id new_value, BOOL is_atomic, BOOL should_copy) +{ + if (self != nil) + { + id *pointer_to_ivar = (id *)((char *)self + offset); + id retained_value; +#if !OBJC_WITH_GC + id old_value; +#endif + + switch (should_copy) + { + case 0: /* retain */ + { + if (*pointer_to_ivar == new_value) + return; + retained_value = RETAIN (new_value); + break; + } + case 2: /* mutable copy */ + { + retained_value = MUTABLE_COPY (new_value); + break; + } + case 1: /* copy */ + default: + { + retained_value = COPY (new_value); + break; + } + } + + if (is_atomic == NO) + { +#if !OBJC_WITH_GC + old_value = *pointer_to_ivar; +#endif + *pointer_to_ivar = retained_value; + } + else + { + objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)]; + + objc_mutex_lock (lock); +#if !OBJC_WITH_GC + old_value = *pointer_to_ivar; +#endif + *pointer_to_ivar = retained_value; + objc_mutex_unlock (lock); + } +#if !OBJC_WITH_GC + RELEASE (old_value); +#endif + } +} + +/* The compiler uses this function when implementing some synthesized + getters for properties of arbitrary C types. The data is just + copied. Compatibility Note: this function does not exist in the + Apple/NeXT runtime. */ +void +objc_getPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) +{ + if (is_atomic == NO) + memcpy (destination, source, size); + else + { + objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (source)]; + + objc_mutex_lock (lock); + memcpy (destination, source, size); + objc_mutex_unlock (lock); + } +} + +/* The compiler uses this function when implementing some synthesized + setters for properties of arbitrary C types. The data is just + copied. Compatibility Note: this function does not exist in the + Apple/NeXT runtime. */ +void +objc_setPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) +{ + if (is_atomic == NO) + memcpy (destination, source, size); + else + { + objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (destination)]; + + objc_mutex_lock (lock); + memcpy (destination, source, size); + objc_mutex_unlock (lock); + } +} + +/* This is the function that the Apple/NeXT runtime has instead of + objc_getPropertyStruct and objc_setPropertyStruct. We include it + for API compatibility (just for people who may have used + objc_copyStruct on the NeXT runtime thinking it was a public API); + the compiler never generates calls to it with the GNU runtime. + This function is clumsy because it requires two locks instead of + one. */ +void +objc_copyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong) +{ + if (is_atomic == NO) + memcpy (destination, source, size); + else + { + /* We don't know which one is the property, so we have to lock + both. One of them is most likely a temporary buffer in the + local stack and we really wouldn't want to lock it (our + objc_getPropertyStruct and objc_setPropertyStruct functions + don't lock it). Note that if we're locking more than one + accessor lock at once, we need to always lock them in the + same order to avoid deadlocks. */ + objc_mutex_t first_lock; + objc_mutex_t second_lock; + + if (ACCESSORS_HASH (source) == ACCESSORS_HASH (destination)) + { + /* A lucky collision. */ + first_lock = accessors_locks[ACCESSORS_HASH (source)]; + objc_mutex_lock (first_lock); + memcpy (destination, source, size); + objc_mutex_unlock (first_lock); + return; + } + + if (ACCESSORS_HASH (source) > ACCESSORS_HASH (destination)) + { + first_lock = accessors_locks[ACCESSORS_HASH (source)]; + second_lock = accessors_locks[ACCESSORS_HASH (destination)]; + } + else + { + first_lock = accessors_locks[ACCESSORS_HASH (destination)]; + second_lock = accessors_locks[ACCESSORS_HASH (source)]; + } + + objc_mutex_lock (first_lock); + objc_mutex_lock (second_lock); + memcpy (destination, source, size); + objc_mutex_unlock (second_lock); + objc_mutex_unlock (first_lock); + } +} |