OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 28 matching lines...) Expand all Loading... | |
39 ObjectGroup::~ObjectGroup() { | 39 ObjectGroup::~ObjectGroup() { |
40 if (info_ != NULL) info_->Dispose(); | 40 if (info_ != NULL) info_->Dispose(); |
41 } | 41 } |
42 | 42 |
43 | 43 |
44 class GlobalHandles::Node { | 44 class GlobalHandles::Node { |
45 public: | 45 public: |
46 // State transition diagram: | 46 // State transition diagram: |
47 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } | 47 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } |
48 enum State { | 48 enum State { |
49 FREE, | 49 FREE = 0, |
50 NORMAL, // Normal global handle. | 50 NORMAL, // Normal global handle. |
51 WEAK, // Flagged as weak but not yet finalized. | 51 WEAK, // Flagged as weak but not yet finalized. |
52 PENDING, // Has been recognized as only reachable by weak handles. | 52 PENDING, // Has been recognized as only reachable by weak handles. |
53 NEAR_DEATH // Callback has informed the handle is near death. | 53 NEAR_DEATH // Callback has informed the handle is near death. |
54 }; | 54 }; |
55 | 55 |
56 // Maps handle location (slot) to the containing node. | 56 // Maps handle location (slot) to the containing node. |
57 static Node* FromLocation(Object** location) { | 57 static Node* FromLocation(Object** location) { |
58 ASSERT(OFFSET_OF(Node, object_) == 0); | 58 ASSERT(OFFSET_OF(Node, object_) == 0); |
59 return reinterpret_cast<Node*>(location); | 59 return reinterpret_cast<Node*>(location); |
60 } | 60 } |
61 | 61 |
62 Node() {} | 62 Node() {} |
63 | 63 |
64 #ifdef DEBUG | 64 #ifdef DEBUG |
65 ~Node() { | 65 ~Node() { |
66 // TODO(1428): if it's a weak handle we should have invoked its callback. | 66 // TODO(1428): if it's a weak handle we should have invoked its callback. |
67 // Zap the values for eager trapping. | 67 // Zap the values for eager trapping. |
68 object_ = NULL; | 68 object_ = NULL; |
69 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 69 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
70 index_ = 0; | 70 index_ = 0; |
71 independent_ = false; | 71 set_independent(false); |
72 partially_dependent_ = false; | 72 set_partially_dependent_(false); |
73 in_new_space_list_ = false; | 73 set_in_new_space_list_(false); |
Michael Starzinger
2013/01/15 10:27:13
Two small typos at the trailing underscore. Fixed
| |
74 parameter_or_next_free_.next_free = NULL; | 74 parameter_or_next_free_.next_free = NULL; |
75 callback_ = NULL; | 75 callback_ = NULL; |
76 } | 76 } |
77 #endif | 77 #endif |
78 | 78 |
79 void Initialize(int index, Node** first_free) { | 79 void Initialize(int index, Node** first_free) { |
80 index_ = static_cast<uint8_t>(index); | 80 index_ = static_cast<uint8_t>(index); |
81 ASSERT(static_cast<int>(index_) == index); | 81 ASSERT(static_cast<int>(index_) == index); |
82 state_ = FREE; | 82 set_state(FREE); |
83 in_new_space_list_ = false; | 83 set_in_new_space_list(false); |
84 parameter_or_next_free_.next_free = *first_free; | 84 parameter_or_next_free_.next_free = *first_free; |
85 *first_free = this; | 85 *first_free = this; |
86 } | 86 } |
87 | 87 |
88 void Acquire(Object* object, GlobalHandles* global_handles) { | 88 void Acquire(Object* object, GlobalHandles* global_handles) { |
89 ASSERT(state_ == FREE); | 89 ASSERT(state() == FREE); |
90 object_ = object; | 90 object_ = object; |
91 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 91 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
92 independent_ = false; | 92 set_independent(false); |
93 partially_dependent_ = false; | 93 set_partially_dependent(false); |
94 state_ = NORMAL; | 94 set_state(NORMAL); |
95 parameter_or_next_free_.parameter = NULL; | 95 parameter_or_next_free_.parameter = NULL; |
96 callback_ = NULL; | 96 callback_ = NULL; |
97 IncreaseBlockUses(global_handles); | 97 IncreaseBlockUses(global_handles); |
98 } | 98 } |
99 | 99 |
100 void Release(GlobalHandles* global_handles) { | 100 void Release(GlobalHandles* global_handles) { |
101 ASSERT(state_ != FREE); | 101 ASSERT(state() != FREE); |
102 if (IsWeakRetainer()) { | 102 if (IsWeakRetainer()) { |
103 global_handles->number_of_weak_handles_--; | 103 global_handles->number_of_weak_handles_--; |
104 if (object_->IsJSGlobalObject()) { | 104 if (object_->IsJSGlobalObject()) { |
105 global_handles->number_of_global_object_weak_handles_--; | 105 global_handles->number_of_global_object_weak_handles_--; |
106 } | 106 } |
107 } | 107 } |
108 state_ = FREE; | 108 set_state(FREE); |
109 parameter_or_next_free_.next_free = global_handles->first_free_; | 109 parameter_or_next_free_.next_free = global_handles->first_free_; |
110 global_handles->first_free_ = this; | 110 global_handles->first_free_ = this; |
111 DecreaseBlockUses(global_handles); | 111 DecreaseBlockUses(global_handles); |
112 } | 112 } |
113 | 113 |
114 // Object slot accessors. | 114 // Object slot accessors. |
115 Object* object() const { return object_; } | 115 Object* object() const { return object_; } |
116 Object** location() { return &object_; } | 116 Object** location() { return &object_; } |
117 Handle<Object> handle() { return Handle<Object>(location()); } | 117 Handle<Object> handle() { return Handle<Object>(location()); } |
118 | 118 |
119 // Wrapper class ID accessors. | 119 // Wrapper class ID accessors. |
120 bool has_wrapper_class_id() const { | 120 bool has_wrapper_class_id() const { |
121 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; | 121 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; |
122 } | 122 } |
123 | |
123 uint16_t wrapper_class_id() const { return class_id_; } | 124 uint16_t wrapper_class_id() const { return class_id_; } |
124 void set_wrapper_class_id(uint16_t class_id) { | 125 void set_wrapper_class_id(uint16_t class_id) { class_id_ = class_id; } |
125 class_id_ = class_id; | 126 |
127 // State and flag accessors. | |
128 | |
129 State state() const { | |
130 return NodeState::decode(flags_); | |
131 } | |
132 void set_state(State state) { | |
133 flags_ = NodeState::update(flags_, state); | |
126 } | 134 } |
127 | 135 |
128 // State accessors. | 136 bool is_independent() { |
137 return IsIndependent::decode(flags_); | |
138 } | |
139 void set_independent(bool v) { | |
140 flags_ = IsIndependent::update(flags_, v); | |
141 } | |
129 | 142 |
130 State state() const { return state_; } | 143 bool is_partially_dependent() { |
144 return IsPartiallyDependent::decode(flags_); | |
145 } | |
146 void set_partially_dependent(bool v) { | |
147 flags_ = IsPartiallyDependent::update(flags_, v); | |
148 } | |
149 | |
150 bool is_in_new_space_list() { | |
151 return IsInNewSpaceList::decode(flags_); | |
152 } | |
153 void set_in_new_space_list(bool v) { | |
154 flags_ = IsInNewSpaceList::update(flags_, v); | |
155 } | |
131 | 156 |
132 bool IsNearDeath() const { | 157 bool IsNearDeath() const { |
133 // Check for PENDING to ensure correct answer when processing callbacks. | 158 // Check for PENDING to ensure correct answer when processing callbacks. |
134 return state_ == PENDING || state_ == NEAR_DEATH; | 159 return state() == PENDING || state() == NEAR_DEATH; |
135 } | 160 } |
136 | 161 |
137 bool IsWeak() const { return state_ == WEAK; } | 162 bool IsWeak() const { return state() == WEAK; } |
138 | 163 |
139 bool IsRetainer() const { return state_ != FREE; } | 164 bool IsRetainer() const { return state() != FREE; } |
140 | 165 |
141 bool IsStrongRetainer() const { return state_ == NORMAL; } | 166 bool IsStrongRetainer() const { return state() == NORMAL; } |
142 | 167 |
143 bool IsWeakRetainer() const { | 168 bool IsWeakRetainer() const { |
144 return state_ == WEAK || state_ == PENDING || state_ == NEAR_DEATH; | 169 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH; |
145 } | 170 } |
146 | 171 |
147 void MarkPending() { | 172 void MarkPending() { |
148 ASSERT(state_ == WEAK); | 173 ASSERT(state() == WEAK); |
149 state_ = PENDING; | 174 set_state(PENDING); |
150 } | 175 } |
151 | 176 |
152 // Independent flag accessors. | 177 // Independent flag accessors. |
153 void MarkIndependent() { | 178 void MarkIndependent() { |
154 ASSERT(state_ != FREE); | 179 ASSERT(state() != FREE); |
155 independent_ = true; | 180 set_independent(true); |
156 } | 181 } |
157 bool is_independent() const { return independent_; } | |
158 | 182 |
159 void MarkPartiallyDependent(GlobalHandles* global_handles) { | 183 void MarkPartiallyDependent(GlobalHandles* global_handles) { |
160 ASSERT(state_ != FREE); | 184 ASSERT(state() != FREE); |
161 if (global_handles->isolate()->heap()->InNewSpace(object_)) { | 185 if (global_handles->isolate()->heap()->InNewSpace(object_)) { |
162 partially_dependent_ = true; | 186 set_partially_dependent(true); |
163 } | 187 } |
164 } | 188 } |
165 bool is_partially_dependent() const { return partially_dependent_; } | 189 void clear_partially_dependent() { set_partially_dependent(false); } |
166 void clear_partially_dependent() { partially_dependent_ = false; } | |
167 | |
168 // In-new-space-list flag accessors. | |
169 void set_in_new_space_list(bool v) { in_new_space_list_ = v; } | |
170 bool is_in_new_space_list() const { return in_new_space_list_; } | |
171 | 190 |
172 // Callback accessor. | 191 // Callback accessor. |
173 WeakReferenceCallback callback() { return callback_; } | 192 WeakReferenceCallback callback() { return callback_; } |
174 | 193 |
175 // Callback parameter accessors. | 194 // Callback parameter accessors. |
176 void set_parameter(void* parameter) { | 195 void set_parameter(void* parameter) { |
177 ASSERT(state_ != FREE); | 196 ASSERT(state() != FREE); |
178 parameter_or_next_free_.parameter = parameter; | 197 parameter_or_next_free_.parameter = parameter; |
179 } | 198 } |
180 void* parameter() const { | 199 void* parameter() const { |
181 ASSERT(state_ != FREE); | 200 ASSERT(state() != FREE); |
182 return parameter_or_next_free_.parameter; | 201 return parameter_or_next_free_.parameter; |
183 } | 202 } |
184 | 203 |
185 // Accessors for next free node in the free list. | 204 // Accessors for next free node in the free list. |
186 Node* next_free() { | 205 Node* next_free() { |
187 ASSERT(state_ == FREE); | 206 ASSERT(state() == FREE); |
188 return parameter_or_next_free_.next_free; | 207 return parameter_or_next_free_.next_free; |
189 } | 208 } |
190 void set_next_free(Node* value) { | 209 void set_next_free(Node* value) { |
191 ASSERT(state_ == FREE); | 210 ASSERT(state() == FREE); |
192 parameter_or_next_free_.next_free = value; | 211 parameter_or_next_free_.next_free = value; |
193 } | 212 } |
194 | 213 |
195 void MakeWeak(GlobalHandles* global_handles, | 214 void MakeWeak(GlobalHandles* global_handles, |
196 void* parameter, | 215 void* parameter, |
197 WeakReferenceCallback callback) { | 216 WeakReferenceCallback callback) { |
198 ASSERT(state_ != FREE); | 217 ASSERT(state() != FREE); |
199 if (!IsWeakRetainer()) { | 218 if (!IsWeakRetainer()) { |
200 global_handles->number_of_weak_handles_++; | 219 global_handles->number_of_weak_handles_++; |
201 if (object_->IsJSGlobalObject()) { | 220 if (object_->IsJSGlobalObject()) { |
202 global_handles->number_of_global_object_weak_handles_++; | 221 global_handles->number_of_global_object_weak_handles_++; |
203 } | 222 } |
204 } | 223 } |
205 state_ = WEAK; | 224 set_state(WEAK); |
206 set_parameter(parameter); | 225 set_parameter(parameter); |
207 callback_ = callback; | 226 callback_ = callback; |
208 } | 227 } |
209 | 228 |
210 void ClearWeakness(GlobalHandles* global_handles) { | 229 void ClearWeakness(GlobalHandles* global_handles) { |
211 ASSERT(state_ != FREE); | 230 ASSERT(state() != FREE); |
212 if (IsWeakRetainer()) { | 231 if (IsWeakRetainer()) { |
213 global_handles->number_of_weak_handles_--; | 232 global_handles->number_of_weak_handles_--; |
214 if (object_->IsJSGlobalObject()) { | 233 if (object_->IsJSGlobalObject()) { |
215 global_handles->number_of_global_object_weak_handles_--; | 234 global_handles->number_of_global_object_weak_handles_--; |
216 } | 235 } |
217 } | 236 } |
218 state_ = NORMAL; | 237 set_state(NORMAL); |
219 set_parameter(NULL); | 238 set_parameter(NULL); |
220 } | 239 } |
221 | 240 |
222 bool PostGarbageCollectionProcessing(Isolate* isolate, | 241 bool PostGarbageCollectionProcessing(Isolate* isolate, |
223 GlobalHandles* global_handles) { | 242 GlobalHandles* global_handles) { |
224 if (state_ != Node::PENDING) return false; | 243 if (state() != Node::PENDING) return false; |
225 WeakReferenceCallback func = callback(); | 244 WeakReferenceCallback func = callback(); |
226 if (func == NULL) { | 245 if (func == NULL) { |
227 Release(global_handles); | 246 Release(global_handles); |
228 return false; | 247 return false; |
229 } | 248 } |
230 void* par = parameter(); | 249 void* par = parameter(); |
231 state_ = NEAR_DEATH; | 250 set_state(NEAR_DEATH); |
232 set_parameter(NULL); | 251 set_parameter(NULL); |
233 | 252 |
234 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); | 253 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); |
235 { | 254 { |
236 // Check that we are not passing a finalized external string to | 255 // Check that we are not passing a finalized external string to |
237 // the callback. | 256 // the callback. |
238 ASSERT(!object_->IsExternalAsciiString() || | 257 ASSERT(!object_->IsExternalAsciiString() || |
239 ExternalAsciiString::cast(object_)->resource() != NULL); | 258 ExternalAsciiString::cast(object_)->resource() != NULL); |
240 ASSERT(!object_->IsExternalTwoByteString() || | 259 ASSERT(!object_->IsExternalTwoByteString() || |
241 ExternalTwoByteString::cast(object_)->resource() != NULL); | 260 ExternalTwoByteString::cast(object_)->resource() != NULL); |
242 // Leaving V8. | 261 // Leaving V8. |
243 VMState state(isolate, EXTERNAL); | 262 VMState state(isolate, EXTERNAL); |
244 func(object, par); | 263 func(object, par); |
245 } | 264 } |
246 // Absence of explicit cleanup or revival of weak handle | 265 // Absence of explicit cleanup or revival of weak handle |
247 // in most of the cases would lead to memory leak. | 266 // in most of the cases would lead to memory leak. |
248 ASSERT(state_ != NEAR_DEATH); | 267 ASSERT(state() != NEAR_DEATH); |
249 return true; | 268 return true; |
250 } | 269 } |
251 | 270 |
252 private: | 271 private: |
253 inline NodeBlock* FindBlock(); | 272 inline NodeBlock* FindBlock(); |
254 inline void IncreaseBlockUses(GlobalHandles* global_handles); | 273 inline void IncreaseBlockUses(GlobalHandles* global_handles); |
255 inline void DecreaseBlockUses(GlobalHandles* global_handles); | 274 inline void DecreaseBlockUses(GlobalHandles* global_handles); |
256 | 275 |
257 // Storage for object pointer. | 276 // Storage for object pointer. |
258 // Placed first to avoid offset computation. | 277 // Placed first to avoid offset computation. |
259 Object* object_; | 278 Object* object_; |
260 | 279 |
261 // Next word stores class_id, index, state, and independent. | 280 // Next word stores class_id, index, state, and independent. |
262 // Note: the most aligned fields should go first. | 281 // Note: the most aligned fields should go first. |
263 | 282 |
264 // Wrapper class ID. | 283 // Wrapper class ID. |
265 uint16_t class_id_; | 284 uint16_t class_id_; |
266 | 285 |
267 // Index in the containing handle block. | 286 // Index in the containing handle block. |
268 uint8_t index_; | 287 uint8_t index_; |
269 | 288 |
270 // Need one more bit for MSVC as it treats enums as signed. | 289 // This stores three flags (independent, partially_dependent and |
271 State state_ : 4; | 290 // in_new_space_list) and a State. |
291 class NodeState: public BitField<State, 0, 4> {}; | |
292 class IsIndependent: public BitField<bool, 4, 1> {}; | |
293 class IsPartiallyDependent: public BitField<bool, 5, 1> {}; | |
294 class IsInNewSpaceList: public BitField<bool, 6, 1> {}; | |
272 | 295 |
273 bool independent_ : 1; | 296 uint8_t flags_; |
274 bool partially_dependent_ : 1; | |
275 bool in_new_space_list_ : 1; | |
276 | 297 |
277 // Handle specific callback. | 298 // Handle specific callback. |
278 WeakReferenceCallback callback_; | 299 WeakReferenceCallback callback_; |
279 | 300 |
280 // Provided data for callback. In FREE state, this is used for | 301 // Provided data for callback. In FREE state, this is used for |
281 // the free list link. | 302 // the free list link. |
282 union { | 303 union { |
283 void* parameter; | 304 void* parameter; |
284 Node* next_free; | 305 Node* next_free; |
285 } parameter_or_next_free_; | 306 } parameter_or_next_free_; |
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
798 implicit_ref_groups_.Clear(); | 819 implicit_ref_groups_.Clear(); |
799 } | 820 } |
800 | 821 |
801 | 822 |
802 void GlobalHandles::TearDown() { | 823 void GlobalHandles::TearDown() { |
803 // TODO(1428): invoke weak callbacks. | 824 // TODO(1428): invoke weak callbacks. |
804 } | 825 } |
805 | 826 |
806 | 827 |
807 } } // namespace v8::internal | 828 } } // namespace v8::internal |
OLD | NEW |