]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-weak.h
objc4-706.tar.gz
[apple/objc4.git] / runtime / objc-weak.h
1 /*
2 * Copyright (c) 2010-2011 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 #ifndef _OBJC_WEAK_H_
25 #define _OBJC_WEAK_H_
26
27 #include <objc/objc.h>
28 #include "objc-config.h"
29
30 __BEGIN_DECLS
31
32 /*
33 The weak table is a hash table governed by a single spin lock.
34 An allocated blob of memory, most often an object, but under GC any such
35 allocation, may have its address stored in a __weak marked storage location
36 through use of compiler generated write-barriers or hand coded uses of the
37 register weak primitive. Associated with the registration can be a callback
38 block for the case when one of the allocated chunks of memory is reclaimed.
39 The table is hashed on the address of the allocated memory. When __weak
40 marked memory changes its reference, we count on the fact that we can still
41 see its previous reference.
42
43 So, in the hash table, indexed by the weakly referenced item, is a list of
44 all locations where this address is currently being stored.
45
46 For ARC, we also keep track of whether an arbitrary object is being
47 deallocated by briefly placing it in the table just prior to invoking
48 dealloc, and removing it via objc_clear_deallocating just prior to memory
49 reclamation.
50
51 */
52
53 // The address of a __weak variable.
54 // These pointers are stored disguised so memory analysis tools
55 // don't see lots of interior pointers from the weak table into objects.
56 typedef DisguisedPtr<objc_object *> weak_referrer_t;
57
58 #if __LP64__
59 #define PTR_MINUS_2 62
60 #else
61 #define PTR_MINUS_2 30
62 #endif
63
64 /**
65 * The internal structure stored in the weak references table.
66 * It maintains and stores
67 * a hash set of weak references pointing to an object.
68 * If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set
69 * is instead a small inline array.
70 */
71 #define WEAK_INLINE_COUNT 4
72
73 // out_of_line_ness field overlaps with the low two bits of inline_referrers[1].
74 // inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.
75 // The low two bits of a pointer-aligned DisguisedPtr will always be 0b00
76 // (disguised nil or 0x80..00) or 0b11 (any other address).
77 // Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.
78 #define REFERRERS_OUT_OF_LINE 2
79
80 struct weak_entry_t {
81 DisguisedPtr<objc_object> referent;
82 union {
83 struct {
84 weak_referrer_t *referrers;
85 uintptr_t out_of_line_ness : 2;
86 uintptr_t num_refs : PTR_MINUS_2;
87 uintptr_t mask;
88 uintptr_t max_hash_displacement;
89 };
90 struct {
91 // out_of_line_ness field is low bits of inline_referrers[1]
92 weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
93 };
94 };
95
96 bool out_of_line() {
97 return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
98 }
99
100 weak_entry_t& operator=(const weak_entry_t& other) {
101 memcpy(this, &other, sizeof(other));
102 return *this;
103 }
104
105 weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
106 : referent(newReferent)
107 {
108 inline_referrers[0] = newReferrer;
109 for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
110 inline_referrers[i] = nil;
111 }
112 }
113 };
114
115 /**
116 * The global weak references table. Stores object ids as keys,
117 * and weak_entry_t structs as their values.
118 */
119 struct weak_table_t {
120 weak_entry_t *weak_entries;
121 size_t num_entries;
122 uintptr_t mask;
123 uintptr_t max_hash_displacement;
124 };
125
126 /// Adds an (object, weak pointer) pair to the weak table.
127 id weak_register_no_lock(weak_table_t *weak_table, id referent,
128 id *referrer, bool crashIfDeallocating);
129
130 /// Removes an (object, weak pointer) pair from the weak table.
131 void weak_unregister_no_lock(weak_table_t *weak_table, id referent, id *referrer);
132
133 #if DEBUG
134 /// Returns true if an object is weakly referenced somewhere.
135 bool weak_is_registered_no_lock(weak_table_t *weak_table, id referent);
136 #endif
137
138 /// Called on object destruction. Sets all remaining weak pointers to nil.
139 void weak_clear_no_lock(weak_table_t *weak_table, id referent);
140
141 __END_DECLS
142
143 #endif /* _OBJC_WEAK_H_ */