objc-references.mm 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Copyright (c) 2004-2007 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. /*
  24. Implementation of the weak / associative references for non-GC mode.
  25. */
  26. #include "objc-private.h"
  27. #include <objc/message.h>
  28. #include <map>
  29. #include "DenseMapExtras.h"
  30. // expanded policy bits.
  31. enum {
  32. OBJC_ASSOCIATION_SETTER_ASSIGN = 0,
  33. OBJC_ASSOCIATION_SETTER_RETAIN = 1,
  34. OBJC_ASSOCIATION_SETTER_COPY = 3, // NOTE: both bits are set, so we can simply test 1 bit in releaseValue below.
  35. OBJC_ASSOCIATION_GETTER_READ = (0 << 8),
  36. OBJC_ASSOCIATION_GETTER_RETAIN = (1 << 8),
  37. OBJC_ASSOCIATION_GETTER_AUTORELEASE = (2 << 8)
  38. };
  39. spinlock_t AssociationsManagerLock;
  40. namespace objc {
  41. class ObjcAssociation {
  42. uintptr_t _policy;
  43. id _value;
  44. public:
  45. ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
  46. ObjcAssociation() : _policy(0), _value(nil) {}
  47. ObjcAssociation(const ObjcAssociation &other) = default;
  48. ObjcAssociation &operator=(const ObjcAssociation &other) = default;
  49. ObjcAssociation(ObjcAssociation &&other) : ObjcAssociation() {
  50. swap(other);
  51. }
  52. inline void swap(ObjcAssociation &other) {
  53. std::swap(_policy, other._policy);
  54. std::swap(_value, other._value);
  55. }
  56. inline uintptr_t policy() const { return _policy; }
  57. inline id value() const { return _value; }
  58. inline void acquireValue() {
  59. if (_value) {
  60. switch (_policy & 0xFF) {
  61. case OBJC_ASSOCIATION_SETTER_RETAIN:
  62. _value = objc_retain(_value);
  63. break;
  64. case OBJC_ASSOCIATION_SETTER_COPY:
  65. _value = ((id(*)(id, SEL))objc_msgSend)(_value, @selector(copy));
  66. break;
  67. }
  68. }
  69. }
  70. inline void releaseHeldValue() {
  71. if (_value && (_policy & OBJC_ASSOCIATION_SETTER_RETAIN)) {
  72. objc_release(_value);
  73. }
  74. }
  75. inline void retainReturnedValue() {
  76. if (_value && (_policy & OBJC_ASSOCIATION_GETTER_RETAIN)) {
  77. objc_retain(_value);
  78. }
  79. }
  80. inline id autoreleaseReturnedValue() {
  81. if (slowpath(_value && (_policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE))) {
  82. return objc_autorelease(_value);
  83. }
  84. return _value;
  85. }
  86. };
  87. typedef DenseMap<const void *, ObjcAssociation> ObjectAssociationMap;
  88. typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;
  89. // class AssociationsManager manages a lock / hash table singleton pair.
  90. // Allocating an instance acquires the lock
  91. class AssociationsManager {
  92. using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>;
  93. static Storage _mapStorage;
  94. public:
  95. AssociationsManager() { AssociationsManagerLock.lock(); }
  96. ~AssociationsManager() { AssociationsManagerLock.unlock(); }
  97. AssociationsHashMap &get() {
  98. return _mapStorage.get();
  99. }
  100. static void init() {
  101. _mapStorage.init();
  102. }
  103. };
  104. AssociationsManager::Storage AssociationsManager::_mapStorage;
  105. } // namespace objc
  106. using namespace objc;
  107. void
  108. _objc_associations_init()
  109. {
  110. AssociationsManager::init();
  111. }
  112. id
  113. _object_get_associative_reference(id object, const void *key)
  114. {
  115. ObjcAssociation association{};
  116. {
  117. AssociationsManager manager;
  118. AssociationsHashMap &associations(manager.get());
  119. AssociationsHashMap::iterator i = associations.find((objc_object *)object);
  120. if (i != associations.end()) {
  121. ObjectAssociationMap &refs = i->second;
  122. ObjectAssociationMap::iterator j = refs.find(key);
  123. if (j != refs.end()) {
  124. association = j->second;
  125. association.retainReturnedValue();
  126. }
  127. }
  128. }
  129. return association.autoreleaseReturnedValue();
  130. }
  131. void
  132. _object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
  133. {
  134. // This code used to work when nil was passed for object and key. Some code
  135. // probably relies on that to not crash. Check and handle it explicitly.
  136. // rdar://problem/44094390
  137. if (!object && !value) return;
  138. if (object->getIsa()->forbidsAssociatedObjects())
  139. _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object));
  140. DisguisedPtr<objc_object> disguised{(objc_object *)object};
  141. ObjcAssociation association{policy, value};
  142. // retain the new value (if any) outside the lock.
  143. association.acquireValue();
  144. {
  145. AssociationsManager manager;
  146. AssociationsHashMap &associations(manager.get());
  147. if (value) {
  148. auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
  149. if (refs_result.second) {
  150. /* it's the first association we make */
  151. object->setHasAssociatedObjects();
  152. }
  153. /* establish or replace the association */
  154. auto &refs = refs_result.first->second;
  155. auto result = refs.try_emplace(key, std::move(association));
  156. if (!result.second) {
  157. association.swap(result.first->second);
  158. }
  159. } else {
  160. auto refs_it = associations.find(disguised);
  161. if (refs_it != associations.end()) {
  162. auto &refs = refs_it->second;
  163. auto it = refs.find(key);
  164. if (it != refs.end()) {
  165. association.swap(it->second);
  166. refs.erase(it);
  167. if (refs.size() == 0) {
  168. associations.erase(refs_it);
  169. }
  170. }
  171. }
  172. }
  173. }
  174. // release the old value (outside of the lock).
  175. association.releaseHeldValue();
  176. }
  177. // Unlike setting/getting an associated reference,
  178. // this function is performance sensitive because of
  179. // raw isa objects (such as OS Objects) that can't track
  180. // whether they have associated objects.
  181. void
  182. _object_remove_assocations(id object)
  183. {
  184. ObjectAssociationMap refs{};
  185. {
  186. AssociationsManager manager;
  187. AssociationsHashMap &associations(manager.get());
  188. AssociationsHashMap::iterator i = associations.find((objc_object *)object);
  189. if (i != associations.end()) {
  190. refs.swap(i->second);
  191. associations.erase(i);
  192. }
  193. }
  194. // release everything (outside of the lock).
  195. for (auto &i: refs) {
  196. i.second.releaseHeldValue();
  197. }
  198. }