objc-accessors.mm 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
  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. #include <string.h>
  24. #include <stddef.h>
  25. #include <libkern/OSAtomic.h>
  26. #include "objc-private.h"
  27. #include "runtime.h"
  28. // stub interface declarations to make compiler happy.
  29. @interface __NSCopyable
  30. - (id)copyWithZone:(void *)zone;
  31. @end
  32. @interface __NSMutableCopyable
  33. - (id)mutableCopyWithZone:(void *)zone;
  34. @end
  35. StripedMap<spinlock_t> PropertyLocks;
  36. StripedMap<spinlock_t> StructLocks;
  37. StripedMap<spinlock_t> CppObjectLocks;
  38. #define MUTABLE_COPY 2
  39. id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
  40. if (offset == 0) {
  41. return object_getClass(self);
  42. }
  43. // Retain release world
  44. id *slot = (id*) ((char*)self + offset);
  45. if (!atomic) return *slot;
  46. // Atomic retain release world
  47. spinlock_t& slotlock = PropertyLocks[slot];
  48. slotlock.lock();
  49. id value = objc_retain(*slot);
  50. slotlock.unlock();
  51. // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
  52. return objc_autoreleaseReturnValue(value);
  53. }
  54. static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));
  55. static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
  56. {
  57. if (offset == 0) {
  58. object_setClass(self, newValue);
  59. return;
  60. }
  61. id oldValue;
  62. id *slot = (id*) ((char*)self + offset);
  63. if (copy) {
  64. newValue = [newValue copyWithZone:nil];
  65. } else if (mutableCopy) {
  66. newValue = [newValue mutableCopyWithZone:nil];
  67. } else {
  68. if (*slot == newValue) return;
  69. newValue = objc_retain(newValue);
  70. }
  71. if (!atomic) {
  72. oldValue = *slot;
  73. *slot = newValue;
  74. } else {
  75. spinlock_t& slotlock = PropertyLocks[slot];
  76. slotlock.lock();
  77. oldValue = *slot;
  78. *slot = newValue;
  79. slotlock.unlock();
  80. }
  81. objc_release(oldValue);
  82. }
  83. void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
  84. {
  85. bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
  86. bool mutableCopy = (shouldCopy == MUTABLE_COPY);
  87. reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
  88. }
  89. void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
  90. {
  91. reallySetProperty(self, _cmd, newValue, offset, true, false, false);
  92. }
  93. void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
  94. {
  95. reallySetProperty(self, _cmd, newValue, offset, false, false, false);
  96. }
  97. void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
  98. {
  99. reallySetProperty(self, _cmd, newValue, offset, true, true, false);
  100. }
  101. void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
  102. {
  103. reallySetProperty(self, _cmd, newValue, offset, false, true, false);
  104. }
  105. // This entry point was designed wrong. When used as a getter, src needs to be locked so that
  106. // if simultaneously used for a setter then there would be contention on src.
  107. // So we need two locks - one of which will be contended.
  108. void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong __unused) {
  109. spinlock_t *srcLock = nil;
  110. spinlock_t *dstLock = nil;
  111. if (atomic) {
  112. srcLock = &StructLocks[src];
  113. dstLock = &StructLocks[dest];
  114. spinlock_t::lockTwo(srcLock, dstLock);
  115. }
  116. memmove(dest, src, size);
  117. if (atomic) {
  118. spinlock_t::unlockTwo(srcLock, dstLock);
  119. }
  120. }
  121. void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {
  122. spinlock_t *srcLock = &CppObjectLocks[src];
  123. spinlock_t *dstLock = &CppObjectLocks[dest];
  124. spinlock_t::lockTwo(srcLock, dstLock);
  125. // let C++ code perform the actual copy.
  126. copyHelper(dest, src);
  127. spinlock_t::unlockTwo(srcLock, dstLock);
  128. }