Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/global-handles.cc

Issue 7062004: Move young independent handles to the end of the global handle's list. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« src/global-handles.h ('K') | « src/global-handles.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 23 matching lines...) Expand all
34 34
35 namespace v8 { 35 namespace v8 {
36 namespace internal { 36 namespace internal {
37 37
38 38
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 : public Malloced { 44 GlobalHandles::Node::~Node() {
45 public: 45 if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles());
46 #ifdef DEBUG
47 // Zap the values for eager trapping.
48 object_ = NULL;
49 next_ = NULL;
50 prev_ = NULL;
51 parameter_or_next_free_.next_free = NULL;
52 #endif
53 }
46 54
47 void Initialize(Object* object) { 55
48 // Set the initial value of the handle. 56
49 object_ = object; 57 bool GlobalHandles::Node::PostGarbageCollectionProcessing(
50 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 58 Isolate* isolate, GlobalHandles* global_handles) {
51 independent_ = false; 59 if (state_ != Node::PENDING) return false;
52 state_ = NORMAL; 60 LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location()));
53 parameter_or_next_free_.parameter = NULL; 61 WeakReferenceCallback func = callback();
54 callback_ = NULL; 62 if (func == NULL) {
63 Destroy(global_handles);
64 return false;
55 } 65 }
66 void* par = parameter();
67 state_ = NEAR_DEATH;
68 set_parameter(NULL);
56 69
57 Node() { 70 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
58 state_ = DESTROYED; 71 {
72 // Forbid reuse of destroyed nodes as they might be already deallocated.
73 // It's fine though to reuse nodes that were destroyed in weak callback
74 // as those cannot be deallocated until we are back from the callback.
75 global_handles->set_first_free(NULL);
76 if (global_handles->first_deallocated()) {
77 global_handles->first_deallocated()->set_next(global_handles->head());
78 }
79 // Check that we are not passing a finalized external string to
80 // the callback.
81 ASSERT(!object_->IsExternalAsciiString() ||
82 ExternalAsciiString::cast(object_)->resource() != NULL);
83 ASSERT(!object_->IsExternalTwoByteString() ||
84 ExternalTwoByteString::cast(object_)->resource() != NULL);
85 // Leaving V8.
86 VMState state(isolate, EXTERNAL);
87 func(object, par);
59 } 88 }
89 // Absense of explicit cleanup or revival of weak handle
90 // in most of the cases would lead to memory leak.
91 ASSERT(state_ != NEAR_DEATH);
92 return true;
93 }
60 94
61 explicit Node(Object* object) { 95
62 Initialize(object); 96 void GlobalHandles::Node::MakeWeak(GlobalHandles* global_handles,
63 // Initialize link structure. 97 void* parameter,
64 next_ = NULL; 98 WeakReferenceCallback callback) {
99 LOG(global_handles->isolate(),
100 HandleEvent("GlobalHandle::MakeWeak", handle().location()));
101 ASSERT(state_ != DESTROYED);
102 if (state_ != WEAK && !IsNearDeath()) {
103 global_handles->number_of_weak_handles_++;
104 if (object_->IsJSGlobalObject()) {
105 global_handles->number_of_global_object_weak_handles_++;
106 }
65 } 107 }
108 state_ = WEAK;
109 set_parameter(parameter);
110 callback_ = callback;
111 }
66 112
67 ~Node() { 113
68 if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles()); 114 void GlobalHandles::Node::ClearWeakness(GlobalHandles* global_handles) {
antonm 2011/05/23 19:44:19 do we want to persist independence related state a
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 I think independence is more a property of an obje
antonm 2011/05/24 10:58:38 I am more concerned with is_in_independent_tail_
69 #ifdef DEBUG 115 LOG(global_handles->isolate(),
70 // Zap the values for eager trapping. 116 HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
71 object_ = NULL; 117 ASSERT(state_ != DESTROYED);
72 next_ = NULL; 118 if (state_ == WEAK || IsNearDeath()) {
73 parameter_or_next_free_.next_free = NULL; 119 global_handles->number_of_weak_handles_--;
74 #endif 120 if (object_->IsJSGlobalObject()) {
121 global_handles->number_of_global_object_weak_handles_--;
122 }
75 } 123 }
124 state_ = NORMAL;
125 set_parameter(NULL);
126 }
76 127
77 void Destroy(GlobalHandles* global_handles) {
78 if (state_ == WEAK || IsNearDeath()) {
79 global_handles->number_of_weak_handles_--;
80 if (object_->IsJSGlobalObject()) {
81 global_handles->number_of_global_object_weak_handles_--;
82 }
83 }
84 state_ = DESTROYED;
85 }
86 128
87 // Accessors for next_. 129 void GlobalHandles::Node::MarkIndependent(GlobalHandles* global_handles) {
88 Node* next() { return next_; } 130 LOG(global_handles->isolate(),
89 void set_next(Node* value) { next_ = value; } 131 HandleEvent("GlobalHandle::MarkIndependent", handle().location()));
90 Node** next_addr() { return &next_; } 132 ASSERT(state_ != DESTROYED);
91 133 independent_ = true;
92 // Accessors for next free node in the free list. 134 }
93 Node* next_free() {
94 ASSERT(state_ == DESTROYED);
95 return parameter_or_next_free_.next_free;
96 }
97 void set_next_free(Node* value) {
98 ASSERT(state_ == DESTROYED);
99 parameter_or_next_free_.next_free = value;
100 }
101
102 // Returns a link from the handle.
103 static Node* FromLocation(Object** location) {
104 ASSERT(OFFSET_OF(Node, object_) == 0);
105 return reinterpret_cast<Node*>(location);
106 }
107
108 // Returns the handle.
109 Handle<Object> handle() { return Handle<Object>(&object_); }
110
111 // Make this handle weak.
112 void MakeWeak(GlobalHandles* global_handles, void* parameter,
113 WeakReferenceCallback callback) {
114 LOG(global_handles->isolate(),
115 HandleEvent("GlobalHandle::MakeWeak", handle().location()));
116 ASSERT(state_ != DESTROYED);
117 if (state_ != WEAK && !IsNearDeath()) {
118 global_handles->number_of_weak_handles_++;
119 if (object_->IsJSGlobalObject()) {
120 global_handles->number_of_global_object_weak_handles_++;
121 }
122 }
123 state_ = WEAK;
124 set_parameter(parameter);
125 callback_ = callback;
126 }
127
128 void ClearWeakness(GlobalHandles* global_handles) {
129 LOG(global_handles->isolate(),
130 HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
131 ASSERT(state_ != DESTROYED);
132 if (state_ == WEAK || IsNearDeath()) {
133 global_handles->number_of_weak_handles_--;
134 if (object_->IsJSGlobalObject()) {
135 global_handles->number_of_global_object_weak_handles_--;
136 }
137 }
138 state_ = NORMAL;
139 set_parameter(NULL);
140 }
141
142 void MarkIndependent(GlobalHandles* global_handles) {
143 LOG(global_handles->isolate(),
144 HandleEvent("GlobalHandle::MarkIndependent", handle().location()));
145 ASSERT(state_ != DESTROYED);
146 independent_ = true;
147 }
148
149 bool IsNearDeath() {
150 // Check for PENDING to ensure correct answer when processing callbacks.
151 return state_ == PENDING || state_ == NEAR_DEATH;
152 }
153
154 bool IsWeak() {
155 return state_ == WEAK;
156 }
157
158 bool CanBeRetainer() {
159 return state_ != DESTROYED && state_ != NEAR_DEATH;
160 }
161
162 void SetWrapperClassId(uint16_t class_id) {
163 class_id_ = class_id;
164 }
165
166 // Returns the id for this weak handle.
167 void set_parameter(void* parameter) {
168 ASSERT(state_ != DESTROYED);
169 parameter_or_next_free_.parameter = parameter;
170 }
171 void* parameter() {
172 ASSERT(state_ != DESTROYED);
173 return parameter_or_next_free_.parameter;
174 }
175
176 // Returns the callback for this weak handle.
177 WeakReferenceCallback callback() { return callback_; }
178
179 bool PostGarbageCollectionProcessing(Isolate* isolate,
180 GlobalHandles* global_handles) {
181 if (state_ != Node::PENDING) return false;
182 LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location()));
183 WeakReferenceCallback func = callback();
184 if (func == NULL) {
185 Destroy(global_handles);
186 return false;
187 }
188 void* par = parameter();
189 state_ = NEAR_DEATH;
190 set_parameter(NULL);
191
192 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
193 {
194 // Forbid reuse of destroyed nodes as they might be already deallocated.
195 // It's fine though to reuse nodes that were destroyed in weak callback
196 // as those cannot be deallocated until we are back from the callback.
197 global_handles->set_first_free(NULL);
198 if (global_handles->first_deallocated()) {
199 global_handles->first_deallocated()->set_next(global_handles->head());
200 }
201 // Check that we are not passing a finalized external string to
202 // the callback.
203 ASSERT(!object_->IsExternalAsciiString() ||
204 ExternalAsciiString::cast(object_)->resource() != NULL);
205 ASSERT(!object_->IsExternalTwoByteString() ||
206 ExternalTwoByteString::cast(object_)->resource() != NULL);
207 // Leaving V8.
208 VMState state(isolate, EXTERNAL);
209 func(object, par);
210 }
211 // Absense of explicit cleanup or revival of weak handle
212 // in most of the cases would lead to memory leak.
213 ASSERT(state_ != NEAR_DEATH);
214 return true;
215 }
216
217 // Place the handle address first to avoid offset computation.
218 Object* object_; // Storage for object pointer.
219
220 uint16_t class_id_;
221
222 // Transition diagram:
223 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
224 enum State {
225 NORMAL, // Normal global handle.
226 WEAK, // Flagged as weak but not yet finalized.
227 PENDING, // Has been recognized as only reachable by weak handles.
228 NEAR_DEATH, // Callback has informed the handle is near death.
229 DESTROYED
230 };
231 State state_ : 4; // Need one more bit for MSVC as it treats enums as signed.
232
233 bool independent_ : 1;
234
235 private:
236 // Handle specific callback.
237 WeakReferenceCallback callback_;
238 // Provided data for callback. In DESTROYED state, this is used for
239 // the free list link.
240 union {
241 void* parameter;
242 Node* next_free;
243 } parameter_or_next_free_;
244
245 // Linkage for the list.
246 Node* next_;
247
248 public:
249 TRACK_MEMORY("GlobalHandles::Node")
250 };
251 135
252 136
253 class GlobalHandles::Pool { 137 class GlobalHandles::Pool {
254 public: 138 public:
255 Pool() { 139 Pool() {
256 current_ = new Chunk(); 140 current_ = new Chunk();
257 current_->previous = NULL; 141 current_->previous = NULL;
258 next_ = current_->nodes; 142 next_ = current_->nodes;
259 limit_ = current_->nodes + kNodesPerChunk; 143 limit_ = current_->nodes + kNodesPerChunk;
260 } 144 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 Chunk* current_; 189 Chunk* current_;
306 Node* next_; 190 Node* next_;
307 Node* limit_; 191 Node* limit_;
308 }; 192 };
309 193
310 194
311 GlobalHandles::GlobalHandles(Isolate* isolate) 195 GlobalHandles::GlobalHandles(Isolate* isolate)
312 : isolate_(isolate), 196 : isolate_(isolate),
313 number_of_weak_handles_(0), 197 number_of_weak_handles_(0),
314 number_of_global_object_weak_handles_(0), 198 number_of_global_object_weak_handles_(0),
315 head_(NULL), 199 young_independent_anchor_(&anchor_node_),
316 first_free_(NULL), 200 first_free_(NULL),
317 first_deallocated_(NULL), 201 first_deallocated_(NULL),
318 pool_(new Pool()), 202 pool_(new Pool()),
319 post_gc_processing_count_(0), 203 post_gc_processing_count_(0),
320 object_groups_(4) { 204 object_groups_(4) {
321 } 205 }
322 206
323 207
324 GlobalHandles::~GlobalHandles() { 208 GlobalHandles::~GlobalHandles() {
325 delete pool_; 209 delete pool_;
326 pool_ = 0; 210 pool_ = 0;
327 } 211 }
328 212
329 213
330 Handle<Object> GlobalHandles::Create(Object* value) { 214 Handle<Object> GlobalHandles::Create(Object* value) {
331 isolate_->counters()->global_handles()->Increment(); 215 isolate_->counters()->global_handles()->Increment();
332 Node* result; 216 Node* result;
333 if (first_free()) { 217 if (first_free()) {
334 // Take the first node in the free list. 218 // Take the first node in the free list.
335 result = first_free(); 219 result = first_free();
336 set_first_free(result->next_free()); 220 set_first_free(result->next_free());
337 } else if (first_deallocated()) { 221 } else if (first_deallocated()) {
antonm 2011/05/23 19:44:19 just FYI: I recently thought about it, and chance
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 Well if we can remove "free" stuff than I don't ne
antonm 2011/05/24 10:58:38 Not free, but deallocated. On 2011/05/23 20:08:15
338 // Next try deallocated list 222 // Next try deallocated list
339 result = first_deallocated(); 223 result = first_deallocated();
340 set_first_deallocated(result->next_free()); 224 set_first_deallocated(result->next_free());
341 ASSERT(result->next() == head()); 225 ASSERT(result->next() == head());
226 if (head() != NULL) head()->set_prev(result);
antonm 2011/05/23 19:44:19 nit: mixed style: it's (first_free()) in old code
227 result->set_prev(NULL);
342 set_head(result); 228 set_head(result);
343 } else { 229 } else {
344 // Allocate a new node. 230 // Allocate a new node.
345 result = pool_->Allocate(); 231 result = pool_->Allocate();
232 if (head() != NULL) head()->set_prev(result);
346 result->set_next(head()); 233 result->set_next(head());
234 result->set_prev(NULL);
347 set_head(result); 235 set_head(result);
348 } 236 }
349 result->Initialize(value); 237 result->Initialize(value);
350 return result->handle(); 238 return result->handle();
351 } 239 }
352 240
353 241
354 void GlobalHandles::Destroy(Object** location) { 242 void GlobalHandles::Destroy(Object** location) {
355 isolate_->counters()->global_handles()->Decrement(); 243 isolate_->counters()->global_handles()->Decrement();
356 if (location == NULL) return; 244 if (location == NULL) return;
(...skipping 11 matching lines...) Expand all
368 Node::FromLocation(location)->MakeWeak(this, parameter, callback); 256 Node::FromLocation(location)->MakeWeak(this, parameter, callback);
369 } 257 }
370 258
371 259
372 void GlobalHandles::ClearWeakness(Object** location) { 260 void GlobalHandles::ClearWeakness(Object** location) {
373 Node::FromLocation(location)->ClearWeakness(this); 261 Node::FromLocation(location)->ClearWeakness(this);
374 } 262 }
375 263
376 264
377 void GlobalHandles::MarkIndependent(Object** location) { 265 void GlobalHandles::MarkIndependent(Object** location) {
378 Node::FromLocation(location)->MarkIndependent(this); 266 Node* node = Node::FromLocation(location);
267
268 if (node->independent_) return;
269
270 node->MarkIndependent(this);
271
272 if (node->is_in_independent_tail_) {
antonm 2011/05/23 19:44:19 is it possible for this to be true? if node wasn'
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 Yes it is. If the handle is destroyed and reused w
273 return;
274 }
275
276 if (isolate_->heap()->InNewSpace(node->object_)) {
277 if (node == young_independent_anchor_) {
278 ASSERT(node->prev() != NULL);
279 young_independent_anchor_ = node->prev();
280 } else {
281 UnlinkNode(node);
282 LinkAfter(young_independent_anchor_, node);
283 }
284 node->is_in_independent_tail_ = true;
285 ASSERT(FirstYoungIndependent() == node);
286 }
379 } 287 }
380 288
381 289
382 bool GlobalHandles::IsNearDeath(Object** location) { 290 bool GlobalHandles::IsNearDeath(Object** location) {
383 return Node::FromLocation(location)->IsNearDeath(); 291 return Node::FromLocation(location)->IsNearDeath();
384 } 292 }
385 293
386 294
387 bool GlobalHandles::IsWeak(Object** location) { 295 bool GlobalHandles::IsWeak(Object** location) {
388 return Node::FromLocation(location)->IsWeak(); 296 return Node::FromLocation(location)->IsWeak();
389 } 297 }
390 298
391 299
392 void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) { 300 void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
393 Node::FromLocation(location)->SetWrapperClassId(class_id); 301 Node::FromLocation(location)->SetWrapperClassId(class_id);
394 } 302 }
395 303
396 304
397 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { 305 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
398 // Traversal of GC roots in the global handle list that are marked as 306 // Traversal of GC roots in the global handle list that are marked as
399 // WEAK, PENDING or NEAR_DEATH. 307 // WEAK, PENDING or NEAR_DEATH.
400 for (Node* current = head_; current != NULL; current = current->next()) { 308 for (Node* current = head(); current != NULL; current = current->next()) {
401 if (current->state_ == Node::WEAK 309 if (current->state_ == Node::WEAK
402 || current->state_ == Node::PENDING 310 || current->state_ == Node::PENDING
403 || current->state_ == Node::NEAR_DEATH) { 311 || current->state_ == Node::NEAR_DEATH) {
404 v->VisitPointer(&current->object_);
405 }
406 }
407 }
408
409
410 void GlobalHandles::IterateWeakIndependentRoots(ObjectVisitor* v) {
411 // Traversal of GC roots in the global handle list that are independent
412 // and marked as WEAK, PENDING or NEAR_DEATH.
413 for (Node* current = head_; current != NULL; current = current->next()) {
414 if (!current->independent_) continue;
415 if (current->state_ == Node::WEAK
416 || current->state_ == Node::PENDING
417 || current->state_ == Node::NEAR_DEATH) {
418 v->VisitPointer(&current->object_); 312 v->VisitPointer(&current->object_);
419 } 313 }
420 } 314 }
421 } 315 }
422 316
423 317
424 void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f, 318 void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
425 WeakReferenceCallback callback) { 319 WeakReferenceCallback callback) {
426 for (Node* current = head_; current != NULL; current = current->next()) { 320 for (Node* current = head(); current != NULL; current = current->next()) {
427 if (current->IsWeak() && current->callback() == callback) { 321 if (current->IsWeak() && current->callback() == callback) {
428 f(current->object_, current->parameter()); 322 f(current->object_, current->parameter());
429 } 323 }
430 } 324 }
431 } 325 }
432 326
433 327
434 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { 328 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
435 for (Node* current = head_; current != NULL; current = current->next()) { 329 for (Node* current = head(); current != NULL; current = current->next()) {
436 if (current->state_ == Node::WEAK) { 330 if (current->state_ == Node::WEAK) {
437 if (f(&current->object_)) { 331 if (f(&current->object_)) {
438 current->state_ = Node::PENDING; 332 current->state_ = Node::PENDING;
439 LOG(isolate_, 333 LOG(isolate_,
440 HandleEvent("GlobalHandle::Pending", current->handle().location())); 334 HandleEvent("GlobalHandle::Pending", current->handle().location()));
441 } 335 }
442 } 336 }
443 } 337 }
444 } 338 }
445 339
446 340
341 void GlobalHandles::IterateWeakIndependentRoots(ObjectVisitor* v) {
342 // Traversal of GC roots in the global handle list that are independent
343 // and marked as WEAK, PENDING or NEAR_DEATH.
344 for (Node* current = FirstYoungIndependent();
345 current != NULL;
346 current = current->next()) {
347 if (!current->independent_) continue;
antonm 2011/05/23 19:44:19 shouldn't it always hold: ASSERT(current->independ
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 It was an assertion initially but... see above :-)
348 if (current->state_ == Node::WEAK
349 || current->state_ == Node::PENDING
350 || current->state_ == Node::NEAR_DEATH) {
351 v->VisitPointer(&current->object_);
352 }
353 }
354 }
355
356
447 void GlobalHandles::IdentifyWeakIndependentHandles(WeakSlotCallbackWithHeap f) { 357 void GlobalHandles::IdentifyWeakIndependentHandles(WeakSlotCallbackWithHeap f) {
448 for (Node* current = head_; current != NULL; current = current->next()) { 358 for (Node* current = FirstYoungIndependent();
449 if (current->state_ == Node::WEAK && current->independent_) { 359 current != NULL;
360 current = current->next()) {
361 if (!current->independent_) continue;
antonm 2011/05/23 19:44:19 ditto
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 ditto :-)
362 if (current->state_ == Node::WEAK) {
450 if (f(isolate_->heap(), &current->object_)) { 363 if (f(isolate_->heap(), &current->object_)) {
451 current->state_ = Node::PENDING; 364 current->state_ = Node::PENDING;
452 LOG(isolate_, 365 LOG(isolate_,
453 HandleEvent("GlobalHandle::Pending", current->handle().location())); 366 HandleEvent("GlobalHandle::Pending", current->handle().location()));
454 } 367 }
455 } 368 }
456 } 369 }
457 } 370 }
458 371
459 372
373 void GlobalHandles::IterateStrongAndDependentRoots(ObjectVisitor* v) {
374 Node* first_young_independent = FirstYoungIndependent();
375 for (Node* current = head();
376 current != first_young_independent;
377 current = current->next()) {
378 if (current->state_ != Node::DESTROYED) {
379 v->VisitPointer(&current->object_);
380 }
381 }
382
383 for (Node* current = first_young_independent;
384 current != NULL;
385 current = current->next()) {
386 if ((current->independent_ && current->state_ == Node::NORMAL) ||
387 (!current->independent_ && current->state_ != Node::DESTROYED)) {
388 v->VisitPointer(&current->object_);
389 }
390 }
391 }
392
393
394 void GlobalHandles::RemoveFromIndependentTail(Node* node) {
395 if (FirstYoungIndependent() != node) {
396 UnlinkNode(node);
397 LinkAfter(young_independent_anchor_, node);
398 }
399 young_independent_anchor_ = node;
400 node->is_in_independent_tail_ = false;
401 }
402
403
404 void GlobalHandles::UnlinkNode(Node* node) {
405 Node* next = node->next();
406 Node* prev = node->prev();
407
408 if (next != NULL) next->set_prev(prev);
409
410 prev->set_next(next);
411
412 if (prev == &anchor_node_) {
413 if (first_deallocated()) first_deallocated()->set_next(next);
414 }
415
416 if (young_independent_anchor_ == node) {
417 young_independent_anchor_ = prev;
418 }
419
420 node->is_in_independent_tail_ = false;
antonm 2011/05/23 19:44:19 is it mandatory here? apparently you overwrite it
Vyacheslav Egorov (Chromium) 2011/05/23 20:08:15 there is one callsite that calls UnlinkNode direct
antonm 2011/05/24 10:58:38 Maybe it should go to this callsite then, but it's
421 }
422
423
424 void GlobalHandles::LinkAfter(Node* prev, Node* node) {
425 ASSERT(prev != NULL);
426 Node* next = prev->next();
427 prev->set_next(node);
428 node->set_prev(prev);
429
430 node->set_next(next);
431 if (next != NULL) next->set_prev(node);
432
433 if (prev == &anchor_node_) {
434 if (first_deallocated()) first_deallocated()->set_next(node);
435 }
436 }
437
438
460 bool GlobalHandles::PostGarbageCollectionProcessing( 439 bool GlobalHandles::PostGarbageCollectionProcessing(
461 GarbageCollector collector) { 440 GarbageCollector collector) {
462 // Process weak global handle callbacks. This must be done after the 441 // Process weak global handle callbacks. This must be done after the
463 // GC is completely done, because the callbacks may invoke arbitrary 442 // GC is completely done, because the callbacks may invoke arbitrary
464 // API functions. 443 // API functions.
465 // At the same time deallocate all DESTROYED nodes. 444 // At the same time deallocate all DESTROYED nodes.
466 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC); 445 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
467 const int initial_post_gc_processing_count = ++post_gc_processing_count_; 446 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
468 bool next_gc_likely_to_collect_more = false; 447 bool next_gc_likely_to_collect_more = false;
469 Node** p = &head_; 448
470 while (*p != NULL) { 449 Node* next_node = NULL;
450 for (Node* node = (collector == SCAVENGER) ? FirstYoungIndependent() : head();
451 node != NULL;
452 node = next_node) {
453 next_node = node->next();
454 ASSERT(collector == MARK_COMPACTOR || node->is_in_independent_tail_);
455
471 // Skip dependent handles. Their weak callbacks might expect to be 456 // Skip dependent handles. Their weak callbacks might expect to be
472 // called between two global garbage collection callbacks which 457 // called between two global garbage collection callbacks which
473 // are not called for minor collections. 458 // are not called for minor collections.
474 if (collector == SCAVENGER && !(*p)->independent_) { 459 if (collector == SCAVENGER && !node->independent_) {
475 p = (*p)->next_addr(); 460 RemoveFromIndependentTail(node);
476 continue; 461 continue;
477 } 462 }
478 463
479 if ((*p)->PostGarbageCollectionProcessing(isolate_, this)) { 464 if (node->PostGarbageCollectionProcessing(isolate_, this)) {
480 if (initial_post_gc_processing_count != post_gc_processing_count_) { 465 if (initial_post_gc_processing_count != post_gc_processing_count_) {
481 // Weak callback triggered another GC and another round of 466 // Weak callback triggered another GC and another round of
482 // PostGarbageCollection processing. The current node might 467 // PostGarbageCollection processing. The current node might
483 // have been deleted in that round, so we need to bail out (or 468 // have been deleted in that round, so we need to bail out (or
484 // restart the processing). 469 // restart the processing).
485 break; 470 break;
486 } 471 }
487 } 472 }
488 if ((*p)->state_ == Node::DESTROYED) { 473
489 // Delete the link. 474 if (node->state_ == Node::DESTROYED) {
490 Node* node = *p; 475 UnlinkNode(node);
491 *p = node->next(); // Update the link. 476
492 if (first_deallocated()) { 477 if (first_deallocated()) first_deallocated()->set_next(node);
493 first_deallocated()->set_next(node);
494 }
495 node->set_next_free(first_deallocated()); 478 node->set_next_free(first_deallocated());
496 set_first_deallocated(node); 479 set_first_deallocated(node);
497 next_gc_likely_to_collect_more = true; 480 next_gc_likely_to_collect_more = true;
498 } else { 481 } else if (node->is_in_independent_tail_ &&
499 p = (*p)->next_addr(); 482 !isolate_->heap()->InNewSpace(node->object_)) {
483 RemoveFromIndependentTail(node);
500 } 484 }
501 } 485 }
502 set_first_free(NULL); 486 set_first_free(NULL);
503 if (first_deallocated()) { 487 if (first_deallocated()) {
504 first_deallocated()->set_next(head()); 488 first_deallocated()->set_next(head());
505 } 489 }
506 490
507 return next_gc_likely_to_collect_more; 491 return next_gc_likely_to_collect_more;
508 } 492 }
509 493
510 494
511 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { 495 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
512 // Traversal of global handles marked as NORMAL. 496 // Traversal of global handles marked as NORMAL.
513 for (Node* current = head_; current != NULL; current = current->next()) { 497 for (Node* current = head(); current != NULL; current = current->next()) {
514 if (current->state_ == Node::NORMAL) { 498 if (current->state_ == Node::NORMAL) {
515 v->VisitPointer(&current->object_); 499 v->VisitPointer(&current->object_);
516 } 500 }
517 } 501 }
518 } 502 }
519 503
520 504
521 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) { 505 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
522 for (Node* current = head_; current != NULL; current = current->next()) { 506 for (Node* current = head(); current != NULL; current = current->next()) {
523 if (current->state_ != Node::DESTROYED) { 507 if (current->state_ != Node::DESTROYED) {
524 v->VisitPointer(&current->object_); 508 v->VisitPointer(&current->object_);
525 } 509 }
526 } 510 }
527 } 511 }
528 512
529 513
530 void GlobalHandles::IterateStrongAndDependentRoots(ObjectVisitor* v) {
531 for (Node* current = head_; current != NULL; current = current->next()) {
532 if ((current->independent_ && current->state_ == Node::NORMAL) ||
533 (!current->independent_ && current->state_ != Node::DESTROYED)) {
534 v->VisitPointer(&current->object_);
535 }
536 }
537 }
538
539
540 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) { 514 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
541 for (Node* current = head_; current != NULL; current = current->next()) { 515 for (Node* current = head(); current != NULL; current = current->next()) {
542 if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId && 516 if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId &&
543 current->CanBeRetainer()) { 517 current->CanBeRetainer()) {
544 v->VisitEmbedderReference(&current->object_, current->class_id_); 518 v->VisitEmbedderReference(&current->object_, current->class_id_);
545 } 519 }
546 } 520 }
547 } 521 }
548 522
549 523
550 void GlobalHandles::TearDown() { 524 void GlobalHandles::TearDown() {
551 // Reset all the lists. 525 // Reset all the lists.
552 set_head(NULL); 526 set_head(NULL);
553 set_first_free(NULL); 527 set_first_free(NULL);
554 set_first_deallocated(NULL); 528 set_first_deallocated(NULL);
555 pool_->Release(); 529 pool_->Release();
556 } 530 }
557 531
558 532
559 void GlobalHandles::RecordStats(HeapStats* stats) { 533 void GlobalHandles::RecordStats(HeapStats* stats) {
560 *stats->global_handle_count = 0; 534 *stats->global_handle_count = 0;
561 *stats->weak_global_handle_count = 0; 535 *stats->weak_global_handle_count = 0;
562 *stats->pending_global_handle_count = 0; 536 *stats->pending_global_handle_count = 0;
563 *stats->near_death_global_handle_count = 0; 537 *stats->near_death_global_handle_count = 0;
564 *stats->destroyed_global_handle_count = 0; 538 *stats->destroyed_global_handle_count = 0;
565 for (Node* current = head_; current != NULL; current = current->next()) { 539 for (Node* current = head(); current != NULL; current = current->next()) {
566 *stats->global_handle_count += 1; 540 *stats->global_handle_count += 1;
567 if (current->state_ == Node::WEAK) { 541 if (current->state_ == Node::WEAK) {
568 *stats->weak_global_handle_count += 1; 542 *stats->weak_global_handle_count += 1;
569 } else if (current->state_ == Node::PENDING) { 543 } else if (current->state_ == Node::PENDING) {
570 *stats->pending_global_handle_count += 1; 544 *stats->pending_global_handle_count += 1;
571 } else if (current->state_ == Node::NEAR_DEATH) { 545 } else if (current->state_ == Node::NEAR_DEATH) {
572 *stats->near_death_global_handle_count += 1; 546 *stats->near_death_global_handle_count += 1;
573 } else if (current->state_ == Node::DESTROYED) { 547 } else if (current->state_ == Node::DESTROYED) {
574 *stats->destroyed_global_handle_count += 1; 548 *stats->destroyed_global_handle_count += 1;
575 } 549 }
576 } 550 }
577 } 551 }
578 552
579 #ifdef DEBUG 553 #ifdef DEBUG
580 554
581 void GlobalHandles::PrintStats() { 555 void GlobalHandles::PrintStats() {
582 int total = 0; 556 int total = 0;
583 int weak = 0; 557 int weak = 0;
584 int pending = 0; 558 int pending = 0;
585 int near_death = 0; 559 int near_death = 0;
586 int destroyed = 0; 560 int destroyed = 0;
587 561
588 for (Node* current = head_; current != NULL; current = current->next()) { 562 for (Node* current = head(); current != NULL; current = current->next()) {
589 total++; 563 total++;
590 if (current->state_ == Node::WEAK) weak++; 564 if (current->state_ == Node::WEAK) weak++;
591 if (current->state_ == Node::PENDING) pending++; 565 if (current->state_ == Node::PENDING) pending++;
592 if (current->state_ == Node::NEAR_DEATH) near_death++; 566 if (current->state_ == Node::NEAR_DEATH) near_death++;
593 if (current->state_ == Node::DESTROYED) destroyed++; 567 if (current->state_ == Node::DESTROYED) destroyed++;
594 } 568 }
595 569
596 PrintF("Global Handle Statistics:\n"); 570 PrintF("Global Handle Statistics:\n");
597 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); 571 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
598 PrintF(" # weak = %d\n", weak); 572 PrintF(" # weak = %d\n", weak);
599 PrintF(" # pending = %d\n", pending); 573 PrintF(" # pending = %d\n", pending);
600 PrintF(" # near_death = %d\n", near_death); 574 PrintF(" # near_death = %d\n", near_death);
601 PrintF(" # destroyed = %d\n", destroyed); 575 PrintF(" # destroyed = %d\n", destroyed);
602 PrintF(" # total = %d\n", total); 576 PrintF(" # total = %d\n", total);
603 } 577 }
604 578
605 void GlobalHandles::Print() { 579 void GlobalHandles::Print() {
606 PrintF("Global handles:\n"); 580 PrintF("Global handles:\n");
607 for (Node* current = head_; current != NULL; current = current->next()) { 581 for (Node* current = head(); current != NULL; current = current->next()) {
608 PrintF(" handle %p to %p (weak=%d)\n", 582 PrintF(" handle %p to %p (weak=%d)\n",
609 reinterpret_cast<void*>(current->handle().location()), 583 reinterpret_cast<void*>(current->handle().location()),
610 reinterpret_cast<void*>(*current->handle()), 584 reinterpret_cast<void*>(*current->handle()),
611 current->state_ == Node::WEAK); 585 current->state_ == Node::WEAK);
612 } 586 }
613 } 587 }
614 588
615 #endif 589 #endif
616 590
617 591
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 630
657 void GlobalHandles::RemoveImplicitRefGroups() { 631 void GlobalHandles::RemoveImplicitRefGroups() {
658 for (int i = 0; i < implicit_ref_groups_.length(); i++) { 632 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
659 implicit_ref_groups_.at(i)->Dispose(); 633 implicit_ref_groups_.at(i)->Dispose();
660 } 634 }
661 implicit_ref_groups_.Clear(); 635 implicit_ref_groups_.Clear();
662 } 636 }
663 637
664 638
665 } } // namespace v8::internal 639 } } // namespace v8::internal
OLDNEW
« src/global-handles.h ('K') | « src/global-handles.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698