objc-references.mm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. #if _LIBCPP_VERSION
  30. # include <unordered_map>
  31. #else
  32. # include <tr1/unordered_map>
  33. using namespace tr1;
  34. #endif
  35. // wrap all the murky C++ details in a namespace to get them out of the way.
  36. namespace objc_references_support {
  37. struct DisguisedPointerEqual {
  38. bool operator()(uintptr_t p1, uintptr_t p2) const {
  39. return p1 == p2;
  40. }
  41. };
  42. struct DisguisedPointerHash {
  43. uintptr_t operator()(uintptr_t k) const {
  44. // borrowed from CFSet.c
  45. #if __LP64__
  46. uintptr_t a = 0x4368726973746F70ULL;
  47. uintptr_t b = 0x686572204B616E65ULL;
  48. #else
  49. uintptr_t a = 0x4B616E65UL;
  50. uintptr_t b = 0x4B616E65UL;
  51. #endif
  52. uintptr_t c = 1;
  53. a += k;
  54. #if __LP64__
  55. a -= b; a -= c; a ^= (c >> 43);
  56. b -= c; b -= a; b ^= (a << 9);
  57. c -= a; c -= b; c ^= (b >> 8);
  58. a -= b; a -= c; a ^= (c >> 38);
  59. b -= c; b -= a; b ^= (a << 23);
  60. c -= a; c -= b; c ^= (b >> 5);
  61. a -= b; a -= c; a ^= (c >> 35);
  62. b -= c; b -= a; b ^= (a << 49);
  63. c -= a; c -= b; c ^= (b >> 11);
  64. a -= b; a -= c; a ^= (c >> 12);
  65. b -= c; b -= a; b ^= (a << 18);
  66. c -= a; c -= b; c ^= (b >> 22);
  67. #else
  68. a -= b; a -= c; a ^= (c >> 13);
  69. b -= c; b -= a; b ^= (a << 8);
  70. c -= a; c -= b; c ^= (b >> 13);
  71. a -= b; a -= c; a ^= (c >> 12);
  72. b -= c; b -= a; b ^= (a << 16);
  73. c -= a; c -= b; c ^= (b >> 5);
  74. a -= b; a -= c; a ^= (c >> 3);
  75. b -= c; b -= a; b ^= (a << 10);
  76. c -= a; c -= b; c ^= (b >> 15);
  77. #endif
  78. return c;
  79. }
  80. };
  81. struct ObjectPointerLess {
  82. bool operator()(const void *p1, const void *p2) const {
  83. return p1 < p2;
  84. }
  85. };
  86. struct ObjcPointerHash {
  87. uintptr_t operator()(void *p) const {
  88. return DisguisedPointerHash()(uintptr_t(p));
  89. }
  90. };
  91. // STL allocator that uses the runtime's internal allocator.
  92. template <typename T> struct ObjcAllocator {
  93. typedef T value_type;
  94. typedef value_type* pointer;
  95. typedef const value_type *const_pointer;
  96. typedef value_type& reference;
  97. typedef const value_type& const_reference;
  98. typedef size_t size_type;
  99. typedef ptrdiff_t difference_type;
  100. template <typename U> struct rebind { typedef ObjcAllocator<U> other; };
  101. template <typename U> ObjcAllocator(const ObjcAllocator<U>&) {}
  102. ObjcAllocator() {}
  103. ObjcAllocator(const ObjcAllocator&) {}
  104. ~ObjcAllocator() {}
  105. pointer address(reference x) const { return &x; }
  106. const_pointer address(const_reference x) const {
  107. return x;
  108. }
  109. pointer allocate(size_type n, const_pointer = 0) {
  110. return static_cast<pointer>(::malloc(n * sizeof(T)));
  111. }
  112. void deallocate(pointer p, size_type) { ::free(p); }
  113. size_type max_size() const {
  114. return static_cast<size_type>(-1) / sizeof(T);
  115. }
  116. void construct(pointer p, const value_type& x) {
  117. new(p) value_type(x);
  118. }
  119. void destroy(pointer p) { p->~value_type(); }
  120. void operator=(const ObjcAllocator&);
  121. };
  122. template<> struct ObjcAllocator<void> {
  123. typedef void value_type;
  124. typedef void* pointer;
  125. typedef const void *const_pointer;
  126. template <typename U> struct rebind { typedef ObjcAllocator<U> other; };
  127. };
  128. typedef uintptr_t disguised_ptr_t;
  129. inline disguised_ptr_t DISGUISE(id value) { return ~uintptr_t(value); }
  130. inline id UNDISGUISE(disguised_ptr_t dptr) { return id(~dptr); }
  131. class ObjcAssociation {
  132. uintptr_t _policy;
  133. id _value;
  134. public:
  135. ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
  136. ObjcAssociation() : _policy(0), _value(nil) {}
  137. uintptr_t policy() const { return _policy; }
  138. id value() const { return _value; }
  139. bool hasValue() { return _value != nil; }
  140. };
  141. #if TARGET_OS_WIN32
  142. typedef hash_map<void *, ObjcAssociation> ObjectAssociationMap;
  143. typedef hash_map<disguised_ptr_t, ObjectAssociationMap *> AssociationsHashMap;
  144. #else
  145. typedef ObjcAllocator<std::pair<void * const, ObjcAssociation> > ObjectAssociationMapAllocator;
  146. class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {
  147. public:
  148. void *operator new(size_t n) { return ::malloc(n); }
  149. void operator delete(void *ptr) { ::free(ptr); }
  150. };
  151. typedef ObjcAllocator<std::pair<const disguised_ptr_t, ObjectAssociationMap*> > AssociationsHashMapAllocator;
  152. class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> {
  153. public:
  154. void *operator new(size_t n) { return ::malloc(n); }
  155. void operator delete(void *ptr) { ::free(ptr); }
  156. };
  157. #endif
  158. }
  159. using namespace objc_references_support;
  160. // class AssociationsManager manages a lock / hash table singleton pair.
  161. // Allocating an instance acquires the lock, and calling its assocations()
  162. // method lazily allocates the hash table.
  163. spinlock_t AssociationsManagerLock;
  164. class AssociationsManager {
  165. // associative references: object pointer -> PtrPtrHashMap.
  166. static AssociationsHashMap *_map;
  167. public:
  168. AssociationsManager() { AssociationsManagerLock.lock(); }
  169. ~AssociationsManager() { AssociationsManagerLock.unlock(); }
  170. AssociationsHashMap &associations() {
  171. if (_map == NULL)
  172. _map = new AssociationsHashMap();
  173. return *_map;
  174. }
  175. };
  176. AssociationsHashMap *AssociationsManager::_map = NULL;
  177. // expanded policy bits.
  178. enum {
  179. OBJC_ASSOCIATION_SETTER_ASSIGN = 0,
  180. OBJC_ASSOCIATION_SETTER_RETAIN = 1,
  181. OBJC_ASSOCIATION_SETTER_COPY = 3, // NOTE: both bits are set, so we can simply test 1 bit in releaseValue below.
  182. OBJC_ASSOCIATION_GETTER_READ = (0 << 8),
  183. OBJC_ASSOCIATION_GETTER_RETAIN = (1 << 8),
  184. OBJC_ASSOCIATION_GETTER_AUTORELEASE = (2 << 8)
  185. };
  186. id _object_get_associative_reference(id object, void *key) {
  187. id value = nil;
  188. uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
  189. {
  190. AssociationsManager manager;
  191. AssociationsHashMap &associations(manager.associations());
  192. disguised_ptr_t disguised_object = DISGUISE(object);
  193. AssociationsHashMap::iterator i = associations.find(disguised_object);
  194. if (i != associations.end()) {
  195. ObjectAssociationMap *refs = i->second;
  196. ObjectAssociationMap::iterator j = refs->find(key);
  197. if (j != refs->end()) {
  198. ObjcAssociation &entry = j->second;
  199. value = entry.value();
  200. policy = entry.policy();
  201. if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
  202. objc_retain(value);
  203. }
  204. }
  205. }
  206. }
  207. if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
  208. objc_autorelease(value);
  209. }
  210. return value;
  211. }
  212. static id acquireValue(id value, uintptr_t policy) {
  213. switch (policy & 0xFF) {
  214. case OBJC_ASSOCIATION_SETTER_RETAIN:
  215. return objc_retain(value);
  216. case OBJC_ASSOCIATION_SETTER_COPY:
  217. return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
  218. }
  219. return value;
  220. }
  221. static void releaseValue(id value, uintptr_t policy) {
  222. if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
  223. return objc_release(value);
  224. }
  225. }
  226. struct ReleaseValue {
  227. void operator() (ObjcAssociation &association) {
  228. releaseValue(association.value(), association.policy());
  229. }
  230. };
  231. void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
  232. // retain the new value (if any) outside the lock.
  233. ObjcAssociation old_association(0, nil);
  234. id new_value = value ? acquireValue(value, policy) : nil;
  235. {
  236. AssociationsManager manager;
  237. AssociationsHashMap &associations(manager.associations());
  238. disguised_ptr_t disguised_object = DISGUISE(object);
  239. if (new_value) {
  240. // break any existing association.
  241. AssociationsHashMap::iterator i = associations.find(disguised_object);
  242. if (i != associations.end()) {
  243. // secondary table exists
  244. ObjectAssociationMap *refs = i->second;
  245. ObjectAssociationMap::iterator j = refs->find(key);
  246. if (j != refs->end()) {
  247. old_association = j->second;
  248. j->second = ObjcAssociation(policy, new_value);
  249. } else {
  250. (*refs)[key] = ObjcAssociation(policy, new_value);
  251. }
  252. } else {
  253. // create the new association (first time).
  254. ObjectAssociationMap *refs = new ObjectAssociationMap;
  255. associations[disguised_object] = refs;
  256. (*refs)[key] = ObjcAssociation(policy, new_value);
  257. object->setHasAssociatedObjects();
  258. }
  259. } else {
  260. // setting the association to nil breaks the association.
  261. AssociationsHashMap::iterator i = associations.find(disguised_object);
  262. if (i != associations.end()) {
  263. ObjectAssociationMap *refs = i->second;
  264. ObjectAssociationMap::iterator j = refs->find(key);
  265. if (j != refs->end()) {
  266. old_association = j->second;
  267. refs->erase(j);
  268. }
  269. }
  270. }
  271. }
  272. // release the old value (outside of the lock).
  273. if (old_association.hasValue()) ReleaseValue()(old_association);
  274. }
  275. void _object_remove_assocations(id object) {
  276. vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
  277. {
  278. AssociationsManager manager;
  279. AssociationsHashMap &associations(manager.associations());
  280. if (associations.size() == 0) return;
  281. disguised_ptr_t disguised_object = DISGUISE(object);
  282. AssociationsHashMap::iterator i = associations.find(disguised_object);
  283. if (i != associations.end()) {
  284. // copy all of the associations that need to be removed.
  285. ObjectAssociationMap *refs = i->second;
  286. for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
  287. elements.push_back(j->second);
  288. }
  289. // remove the secondary table.
  290. delete refs;
  291. associations.erase(i);
  292. }
  293. }
  294. // the calls to releaseValue() happen outside of the lock.
  295. for_each(elements.begin(), elements.end(), ReleaseValue());
  296. }