]> git.saurik.com Git - apple/objc4.git/blame - runtime/Accessors.subproj/objc-accessors.mm
objc4-646.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
cd5f04f5 59id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
8070259c
A
60 if (offset == 0) {
61 return object_getClass(self);
62 }
63
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
b3962a83 78
cd5f04f5 79static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));
b3962a83 80
cd5f04f5
A
81static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
82{
8070259c
A
83 if (offset == 0) {
84 object_setClass(self, newValue);
85 return;
86 }
87
cd5f04f5
A
88 id oldValue;
89 id *slot = (id*) ((char*)self + offset);
90
91 if (copy) {
92 newValue = [newValue copyWithZone:NULL];
93 } else if (mutableCopy) {
94 newValue = [newValue mutableCopyWithZone:NULL];
7af964d1 95 } else {
cd5f04f5 96 if (*slot == newValue) return;
8972963c 97 newValue = objc_retain(newValue);
7af964d1 98 }
b3962a83
A
99
100 if (!atomic) {
101 oldValue = *slot;
102 *slot = newValue;
103 } else {
104 spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
105 _spin_lock(slotlock);
106 oldValue = *slot;
107 *slot = newValue;
cd5f04f5 108 _spin_unlock(slotlock);
b3962a83
A
109 }
110
8972963c
A
111 objc_release(oldValue);
112}
113
cd5f04f5
A
114void objc_setProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
115{
116 bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
117 bool mutableCopy = (shouldCopy == MUTABLE_COPY);
118 reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
119}
120
121void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
122{
123 reallySetProperty(self, _cmd, newValue, offset, true, false, false);
124}
125
126void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
127{
128 reallySetProperty(self, _cmd, newValue, offset, false, false, false);
129}
130
131
132void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
133{
134 reallySetProperty(self, _cmd, newValue, offset, true, true, false);
135}
136
137void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
138{
139 reallySetProperty(self, _cmd, newValue, offset, false, true, false);
140}
141
142
8972963c 143#if SUPPORT_GC
7257e56c
A
144
145id objc_getProperty_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
146 return *(id*) ((char*)self + offset);
147}
148
149void objc_setProperty_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) {
150 if (shouldCopy) {
151 newValue = (shouldCopy == MUTABLE_COPY ? [newValue mutableCopyWithZone:NULL] : [newValue copyWithZone:NULL]);
152 }
153 objc_assign_ivar(newValue, self, offset);
154}
155
156// objc_getProperty and objc_setProperty are resolver functions in objc-auto.mm
157
8972963c 158#else
7257e56c
A
159
160id
161objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
162{
163 return objc_getProperty_non_gc(self, _cmd, offset, atomic);
b3962a83
A
164}
165
7257e56c
A
166void
167objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue,
168 BOOL atomic, signed char shouldCopy)
169{
170 objc_setProperty_non_gc(self, _cmd, offset, newValue, atomic, shouldCopy);
171}
172
173#endif
174
b3962a83 175
b3962a83
A
176// This entry point was designed wrong. When used as a getter, src needs to be locked so that
177// if simultaneously used for a setter then there would be contention on src.
178// So we need two locks - one of which will be contended.
179void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong) {
180 static spin_lock_t StructLocks[1 << GOODPOWER] = { 0 };
181 spin_lock_t *lockfirst = NULL;
182 spin_lock_t *locksecond = NULL;
183 if (atomic) {
184 lockfirst = &StructLocks[GOODHASH(src)];
185 locksecond = &StructLocks[GOODHASH(dest)];
186 // order the locks by address so that we don't deadlock
187 if (lockfirst > locksecond) {
188 lockfirst = locksecond;
189 locksecond = &StructLocks[GOODHASH(src)];
190 }
191 else if (lockfirst == locksecond) {
192 // lucky - we only need one lock
193 locksecond = NULL;
194 }
195 _spin_lock(lockfirst);
196 if (locksecond) _spin_lock(locksecond);
197 }
8972963c 198#if SUPPORT_GC
b3962a83
A
199 if (UseGC && hasStrong) {
200 auto_zone_write_barrier_memmove(gc_zone, dest, src, size);
8972963c
A
201 } else
202#endif
203 {
b3962a83
A
204 memmove(dest, src, size);
205 }
206 if (atomic) {
207 _spin_unlock(lockfirst);
208 if (locksecond) _spin_unlock(locksecond);
209 }
210}
211
cd5f04f5
A
212void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {
213 static spin_lock_t CppObjectLocks[1 << GOODPOWER] = { 0 };
214 spin_lock_t *lockfirst = &CppObjectLocks[GOODHASH(src)], *locksecond = &CppObjectLocks[GOODHASH(dest)];
215 // order the locks by address so that we don't deadlock
216 if (lockfirst > locksecond) {
217 spin_lock_t *temp = lockfirst;
218 lockfirst = locksecond;
219 locksecond = temp;
220 } else if (lockfirst == locksecond) {
221 // lucky - we only need one lock
222 locksecond = NULL;
223 }
224 _spin_lock(lockfirst);
225 if (locksecond) _spin_lock(locksecond);
226
227 // let C++ code perform the actual copy.
228 copyHelper(dest, src);
229
230 _spin_unlock(lockfirst);
231 if (locksecond) _spin_unlock(locksecond);
232}