Chromium Code Reviews| 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 23 matching lines...) Expand all Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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(¤t->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(¤t->object_); | 312 v->VisitPointer(¤t->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(¤t->object_)) { | 331 if (f(¤t->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(¤t->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(), ¤t->object_)) { | 363 if (f(isolate_->heap(), ¤t->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(¤t->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(¤t->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(¤t->object_); | 499 v->VisitPointer(¤t->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(¤t->object_); | 508 v->VisitPointer(¤t->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(¤t->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(¤t->object_, current->class_id_); | 518 v->VisitEmbedderReference(¤t->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 Loading... | |
| 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 |
| OLD | NEW |