]> git.saurik.com Git - apple/objc4.git/blame - runtime/Accessors.subproj/objc-accessors.mm
objc4-532.2.tar.gz
[apple/objc4.git] / runtime / Accessors.subproj / objc-accessors.mm
CommitLineData
b3962a83 1/*
7af964d1 2 * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
b3962a83
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
cd5f04f5
A
24#include <string.h>
25#include <stddef.h>
b3962a83 26
cd5f04f5 27#include <libkern/OSAtomic.h>
b3962a83 28
cd5f04f5
A
29#include "objc-private.h"
30#include "objc-auto.h"
31#include "runtime.h"
32#include "objc-accessors.h"
b3962a83
A
33
34// stub interface declarations to make compiler happy.
35
36@interface __NSCopyable
37- (id)copyWithZone:(void *)zone;
38@end
39
7af964d1
A
40@interface __NSMutableCopyable
41- (id)mutableCopyWithZone:(void *)zone;
42@end
43
b3962a83
A
44
45typedef uintptr_t spin_lock_t;
cd5f04f5
A
46OBJC_EXTERN void _spin_lock(spin_lock_t *lockp);
47OBJC_EXTERN int _spin_lock_try(spin_lock_t *lockp);
48OBJC_EXTERN void _spin_unlock(spin_lock_t *lockp);
b3962a83
A
49
50/* need to consider cache line contention - space locks out XXX */
51
52#define GOODPOWER 7
53#define GOODMASK ((1<<GOODPOWER)-1)
54#define GOODHASH(x) (((long)x >> 5) & GOODMASK)
55static spin_lock_t PropertyLocks[1 << GOODPOWER] = { 0 };
56
cd5f04f5
A
57#define MUTABLE_COPY 2
58
59id objc_getProperty_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
8972963c
A
60 return *(id*) ((char*)self + offset);
61}
62
cd5f04f5 63id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
b3962a83
A
64 // Retain release world
65 id *slot = (id*) ((char*)self + offset);
66 if (!atomic) return *slot;
67
68 // Atomic retain release world
69 spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
70 _spin_lock(slotlock);
8972963c 71 id value = objc_retain(*slot);
b3962a83
A
72 _spin_unlock(slotlock);
73
74 // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
8972963c
A
75 return objc_autoreleaseReturnValue(value);
76}
77
78id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
79 return
80#if SUPPORT_GC
81 (UseGC ? objc_getProperty_gc : objc_getProperty_non_gc)
82#else
83 objc_getProperty_non_gc
84#endif
85 (self, _cmd, offset, atomic);
b3962a83
A
86}
87
8972963c 88#if SUPPORT_GC
cd5f04f5 89void objc_setProperty_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) {
8972963c 90 if (shouldCopy) {
cd5f04f5 91 newValue = (shouldCopy == MUTABLE_COPY ? [newValue mutableCopyWithZone:NULL] : [newValue copyWithZone:NULL]);
b3962a83 92 }
8972963c
A
93 objc_assign_ivar_gc(newValue, self, offset);
94}
95#endif
b3962a83 96
cd5f04f5 97static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));
b3962a83 98
cd5f04f5
A
99static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
100{
101 id oldValue;
102 id *slot = (id*) ((char*)self + offset);
103
104 if (copy) {
105 newValue = [newValue copyWithZone:NULL];
106 } else if (mutableCopy) {
107 newValue = [newValue mutableCopyWithZone:NULL];
7af964d1 108 } else {
cd5f04f5 109 if (*slot == newValue) return;
8972963c 110 newValue = objc_retain(newValue);
7af964d1 111 }
b3962a83
A
112
113 if (!atomic) {
114 oldValue = *slot;
115 *slot = newValue;
116 } else {
117 spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
118 _spin_lock(slotlock);
119 oldValue = *slot;
120 *slot = newValue;
cd5f04f5 121 _spin_unlock(slotlock);
b3962a83
A
122 }
123
8972963c
A
124 objc_release(oldValue);
125}
126
cd5f04f5
A
127void objc_setProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
128{
129 bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
130 bool mutableCopy = (shouldCopy == MUTABLE_COPY);
131 reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
132}
133
134void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
135{
136 reallySetProperty(self, _cmd, newValue, offset, true, false, false);
137}
138
139void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
140{
141 reallySetProperty(self, _cmd, newValue, offset, false, false, false);
142}
143
144
145void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
146{
147 reallySetProperty(self, _cmd, newValue, offset, true, true, false);
148}
149
150void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
151{
152 reallySetProperty(self, _cmd, newValue, offset, false, true, false);
153}
154
155
156void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) {
8972963c
A
157#if SUPPORT_GC
158 (UseGC ? objc_setProperty_gc : objc_setProperty_non_gc)
159#else
160 objc_setProperty_non_gc
161#endif
162 (self, _cmd, offset, newValue, atomic, shouldCopy);
b3962a83
A
163}
164
165
b3962a83
A
166// This entry point was designed wrong. When used as a getter, src needs to be locked so that
167// if simultaneously used for a setter then there would be contention on src.
168// So we need two locks - one of which will be contended.
169void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong) {
170 static spin_lock_t StructLocks[1 << GOODPOWER] = { 0 };
171 spin_lock_t *lockfirst = NULL;
172 spin_lock_t *locksecond = NULL;
173 if (atomic) {
174 lockfirst = &StructLocks[GOODHASH(src)];
175 locksecond = &StructLocks[GOODHASH(dest)];
176 // order the locks by address so that we don't deadlock
177 if (lockfirst > locksecond) {
178 lockfirst = locksecond;
179 locksecond = &StructLocks[GOODHASH(src)];
180 }
181 else if (lockfirst == locksecond) {
182 // lucky - we only need one lock
183 locksecond = NULL;
184 }
185 _spin_lock(lockfirst);
186 if (locksecond) _spin_lock(locksecond);
187 }
8972963c 188#if SUPPORT_GC
b3962a83
A
189 if (UseGC && hasStrong) {
190 auto_zone_write_barrier_memmove(gc_zone, dest, src, size);
8972963c
A
191 } else
192#endif
193 {
b3962a83
A
194 memmove(dest, src, size);
195 }
196 if (atomic) {
197 _spin_unlock(lockfirst);
198 if (locksecond) _spin_unlock(locksecond);
199 }
200}
201
cd5f04f5
A
202void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {
203 static spin_lock_t CppObjectLocks[1 << GOODPOWER] = { 0 };
204 spin_lock_t *lockfirst = &CppObjectLocks[GOODHASH(src)], *locksecond = &CppObjectLocks[GOODHASH(dest)];
205 // order the locks by address so that we don't deadlock
206 if (lockfirst > locksecond) {
207 spin_lock_t *temp = lockfirst;
208 lockfirst = locksecond;
209 locksecond = temp;
210 } else if (lockfirst == locksecond) {
211 // lucky - we only need one lock
212 locksecond = NULL;
213 }
214 _spin_lock(lockfirst);
215 if (locksecond) _spin_lock(locksecond);
216
217 // let C++ code perform the actual copy.
218 copyHelper(dest, src);
219
220 _spin_unlock(lockfirst);
221 if (locksecond) _spin_unlock(locksecond);
222}