]>
Commit | Line | Data |
---|---|---|
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 | enum WeakRegisterDeallocatingOptions { | |
127 | ReturnNilIfDeallocating, | |
128 | CrashIfDeallocating, | |
129 | DontCheckDeallocating | |
130 | }; | |
131 | ||
132 | /// Adds an (object, weak pointer) pair to the weak table. | |
133 | id weak_register_no_lock(weak_table_t *weak_table, id referent, | |
134 | id *referrer, WeakRegisterDeallocatingOptions deallocatingOptions); | |
135 | ||
136 | /// Removes an (object, weak pointer) pair from the weak table. | |
137 | void weak_unregister_no_lock(weak_table_t *weak_table, id referent, id *referrer); | |
138 | ||
139 | #if DEBUG | |
140 | /// Returns true if an object is weakly referenced somewhere. | |
141 | bool weak_is_registered_no_lock(weak_table_t *weak_table, id referent); | |
142 | #endif | |
143 | ||
144 | /// Called on object destruction. Sets all remaining weak pointers to nil. | |
145 | void weak_clear_no_lock(weak_table_t *weak_table, id referent); | |
146 | ||
147 | __END_DECLS | |
148 | ||
149 | #endif /* _OBJC_WEAK_H_ */ |