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 class GlobalHandles::Node { |
| 45 public: | 45 public: |
| 46 // State transition diagram: | |
| 47 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED } | |
| 48 enum State { | |
| 49 DESTROYED, | |
| 50 NORMAL, // Normal global handle. | |
| 51 WEAK, // Flagged as weak but not yet finalized. | |
| 52 PENDING, // Has been recognized as only reachable by weak handles. | |
| 53 NEAR_DEATH // Callback has informed the handle is near death. | |
| 54 }; | |
| 46 | 55 |
| 47 void Initialize(Object* object) { | 56 // Maps handle location (slot) to the containing node. |
| 57 static Node* FromLocation(Object** location) { | |
| 58 ASSERT(OFFSET_OF(Node, object_) == 0); | |
| 59 return reinterpret_cast<Node*>(location); | |
| 60 } | |
| 61 | |
| 62 Node() {} | |
| 63 | |
| 64 #ifdef DEBUG | |
| 65 ~Node() { | |
| 66 // ASSERT(state_ == DESTROYED); | |
| 67 // Zap the values for eager trapping. | |
| 68 object_ = NULL; | |
| 69 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | |
| 70 index_ = 0; | |
| 71 independent_ = false; | |
| 72 parameter_or_next_free_.next_free = NULL; | |
| 73 callback_ = NULL; | |
| 74 } | |
| 75 #endif | |
| 76 | |
| 77 void PreInitialize(int index, GlobalHandles* global_handles) { | |
| 78 index_ = index; | |
| 79 state_ = DESTROYED; | |
| 80 parameter_or_next_free_.next_free = global_handles->first_free_; | |
| 81 global_handles->first_free_ = this; | |
| 82 } | |
| 83 | |
| 84 void Initialize(Object* object, GlobalHandles* global_handles) { | |
| 48 // Set the initial value of the handle. | 85 // Set the initial value of the handle. |
| 49 object_ = object; | 86 object_ = object; |
| 50 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 87 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
| 51 independent_ = false; | 88 independent_ = false; |
| 52 state_ = NORMAL; | 89 state_ = NORMAL; |
| 53 parameter_or_next_free_.parameter = NULL; | 90 parameter_or_next_free_.parameter = NULL; |
| 54 callback_ = NULL; | 91 callback_ = NULL; |
| 55 } | 92 IncreaseBlockUses(global_handles); |
| 56 | |
| 57 Node() { | |
| 58 state_ = DESTROYED; | |
| 59 } | |
| 60 | |
| 61 explicit Node(Object* object) { | |
| 62 Initialize(object); | |
| 63 // Initialize link structure. | |
| 64 next_ = NULL; | |
| 65 } | |
| 66 | |
| 67 ~Node() { | |
| 68 if (state_ != DESTROYED) Destroy(Isolate::Current()->global_handles()); | |
| 69 #ifdef DEBUG | |
| 70 // Zap the values for eager trapping. | |
| 71 object_ = NULL; | |
| 72 next_ = NULL; | |
| 73 parameter_or_next_free_.next_free = NULL; | |
| 74 #endif | |
| 75 } | 93 } |
| 76 | 94 |
| 77 void Destroy(GlobalHandles* global_handles) { | 95 void Destroy(GlobalHandles* global_handles) { |
| 78 if (state_ == WEAK || IsNearDeath()) { | 96 if (IsWeakRetainer()) { |
| 79 global_handles->number_of_weak_handles_--; | 97 global_handles->number_of_weak_handles_--; |
| 80 if (object_->IsJSGlobalObject()) { | 98 if (object_->IsJSGlobalObject()) { |
| 81 global_handles->number_of_global_object_weak_handles_--; | 99 global_handles->number_of_global_object_weak_handles_--; |
| 82 } | 100 } |
| 83 } | 101 } |
| 84 state_ = DESTROYED; | 102 state_ = DESTROYED; |
| 103 parameter_or_next_free_.next_free = global_handles->first_free_; | |
| 104 global_handles->first_free_ = this; | |
| 105 DecreaseBlockUses(global_handles); | |
| 85 } | 106 } |
| 86 | 107 |
| 87 // Accessors for next_. | 108 // Object slot accessors. |
| 88 Node* next() { return next_; } | 109 Object* object() const { return object_; } |
| 89 void set_next(Node* value) { next_ = value; } | 110 Object** location() { return &object_; } |
| 90 Node** next_addr() { return &next_; } | 111 Handle<Object> handle() { return Handle<Object>(location()); } |
| 112 | |
| 113 // Wrapper class ID accessors. | |
| 114 bool has_wrapper_class_id() const { | |
| 115 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; | |
| 116 } | |
| 117 uint16_t wrapper_class_id() const { return class_id_; } | |
| 118 void set_wrapper_class_id(uint16_t class_id) { | |
| 119 class_id_ = class_id; | |
| 120 } | |
| 121 | |
| 122 // State accessors. | |
| 123 | |
| 124 State state() const { return state_; } | |
| 125 | |
| 126 bool IsNearDeath() const { | |
| 127 // Check for PENDING to ensure correct answer when processing callbacks. | |
| 128 return state_ == PENDING || state_ == NEAR_DEATH; | |
| 129 } | |
| 130 | |
| 131 bool IsWeak() const { return state_ == WEAK; } | |
| 132 | |
| 133 bool IsRetainer() const { return state_ != DESTROYED; } | |
| 134 | |
| 135 bool IsWeakRetainer() const { | |
| 136 return state_ == WEAK || state_ == PENDING || state_ == NEAR_DEATH; | |
| 137 } | |
| 138 | |
| 139 void MarkPending() { | |
| 140 ASSERT(state_ == WEAK); | |
| 141 state_ = PENDING; | |
| 142 } | |
| 143 | |
| 144 // Independent flag accessors. | |
| 145 void MarkIndependent() { | |
| 146 ASSERT(state_ != DESTROYED); | |
| 147 independent_ = true; | |
| 148 } | |
| 149 bool is_independent() const { return independent_; } | |
| 150 | |
| 151 // Callback accessor. | |
| 152 WeakReferenceCallback callback() { return callback_; } | |
| 153 | |
| 154 // Callback parameter accessors. | |
| 155 void set_parameter(void* parameter) { | |
| 156 ASSERT(state_ != DESTROYED); | |
| 157 parameter_or_next_free_.parameter = parameter; | |
| 158 } | |
| 159 void* parameter() const { | |
| 160 ASSERT(state_ != DESTROYED); | |
| 161 return parameter_or_next_free_.parameter; | |
| 162 } | |
| 91 | 163 |
| 92 // Accessors for next free node in the free list. | 164 // Accessors for next free node in the free list. |
| 93 Node* next_free() { | 165 Node* next_free() { |
| 94 ASSERT(state_ == DESTROYED); | 166 ASSERT(state_ == DESTROYED); |
| 95 return parameter_or_next_free_.next_free; | 167 return parameter_or_next_free_.next_free; |
| 96 } | 168 } |
| 97 void set_next_free(Node* value) { | 169 void set_next_free(Node* value) { |
| 98 ASSERT(state_ == DESTROYED); | 170 ASSERT(state_ == DESTROYED); |
| 99 parameter_or_next_free_.next_free = value; | 171 parameter_or_next_free_.next_free = value; |
| 100 } | 172 } |
| 101 | 173 |
| 102 // Returns a link from the handle. | 174 void MakeWeak(GlobalHandles* global_handles, |
| 103 static Node* FromLocation(Object** location) { | 175 void* parameter, |
| 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) { | 176 WeakReferenceCallback callback) { |
| 114 LOG(global_handles->isolate(), | |
| 115 HandleEvent("GlobalHandle::MakeWeak", handle().location())); | |
| 116 ASSERT(state_ != DESTROYED); | 177 ASSERT(state_ != DESTROYED); |
| 117 if (state_ != WEAK && !IsNearDeath()) { | 178 if (!IsWeakRetainer()) { |
| 118 global_handles->number_of_weak_handles_++; | 179 global_handles->number_of_weak_handles_++; |
| 119 if (object_->IsJSGlobalObject()) { | 180 if (object_->IsJSGlobalObject()) { |
| 120 global_handles->number_of_global_object_weak_handles_++; | 181 global_handles->number_of_global_object_weak_handles_++; |
| 121 } | 182 } |
| 122 } | 183 } |
| 123 state_ = WEAK; | 184 state_ = WEAK; |
| 124 set_parameter(parameter); | 185 set_parameter(parameter); |
| 125 callback_ = callback; | 186 callback_ = callback; |
| 126 } | 187 } |
| 127 | 188 |
| 128 void ClearWeakness(GlobalHandles* global_handles) { | 189 void ClearWeakness(GlobalHandles* global_handles) { |
| 129 LOG(global_handles->isolate(), | |
| 130 HandleEvent("GlobalHandle::ClearWeakness", handle().location())); | |
| 131 ASSERT(state_ != DESTROYED); | 190 ASSERT(state_ != DESTROYED); |
| 132 if (state_ == WEAK || IsNearDeath()) { | 191 if (IsWeakRetainer()) { |
| 133 global_handles->number_of_weak_handles_--; | 192 global_handles->number_of_weak_handles_--; |
| 134 if (object_->IsJSGlobalObject()) { | 193 if (object_->IsJSGlobalObject()) { |
| 135 global_handles->number_of_global_object_weak_handles_--; | 194 global_handles->number_of_global_object_weak_handles_--; |
| 136 } | 195 } |
| 137 } | 196 } |
| 138 state_ = NORMAL; | 197 state_ = NORMAL; |
| 139 set_parameter(NULL); | 198 set_parameter(NULL); |
| 140 } | 199 } |
| 141 | 200 |
| 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, | 201 bool PostGarbageCollectionProcessing(Isolate* isolate, |
| 180 GlobalHandles* global_handles) { | 202 GlobalHandles* global_handles) { |
| 181 if (state_ != Node::PENDING) return false; | 203 if (state_ != Node::PENDING) return false; |
| 182 LOG(isolate, HandleEvent("GlobalHandle::Processing", handle().location())); | |
| 183 WeakReferenceCallback func = callback(); | 204 WeakReferenceCallback func = callback(); |
| 184 if (func == NULL) { | 205 if (func == NULL) { |
| 185 Destroy(global_handles); | 206 Destroy(global_handles); |
| 186 return false; | 207 return false; |
| 187 } | 208 } |
| 188 void* par = parameter(); | 209 void* par = parameter(); |
| 189 state_ = NEAR_DEATH; | 210 state_ = NEAR_DEATH; |
| 190 set_parameter(NULL); | 211 set_parameter(NULL); |
| 191 | 212 |
| 192 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); | 213 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); |
| 193 { | 214 { |
| 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 | 215 // Check that we are not passing a finalized external string to |
| 202 // the callback. | 216 // the callback. |
| 203 ASSERT(!object_->IsExternalAsciiString() || | 217 ASSERT(!object_->IsExternalAsciiString() || |
| 204 ExternalAsciiString::cast(object_)->resource() != NULL); | 218 ExternalAsciiString::cast(object_)->resource() != NULL); |
| 205 ASSERT(!object_->IsExternalTwoByteString() || | 219 ASSERT(!object_->IsExternalTwoByteString() || |
| 206 ExternalTwoByteString::cast(object_)->resource() != NULL); | 220 ExternalTwoByteString::cast(object_)->resource() != NULL); |
| 207 // Leaving V8. | 221 // Leaving V8. |
| 208 VMState state(isolate, EXTERNAL); | 222 VMState state(isolate, EXTERNAL); |
| 209 func(object, par); | 223 func(object, par); |
| 210 } | 224 } |
| 211 // Absense of explicit cleanup or revival of weak handle | 225 // Absense of explicit cleanup or revival of weak handle |
| 212 // in most of the cases would lead to memory leak. | 226 // in most of the cases would lead to memory leak. |
| 213 ASSERT(state_ != NEAR_DEATH); | 227 ASSERT(state_ != NEAR_DEATH); |
| 214 return true; | 228 return true; |
| 215 } | 229 } |
| 216 | 230 |
| 217 // Place the handle address first to avoid offset computation. | 231 private: |
| 218 Object* object_; // Storage for object pointer. | 232 inline NodeBlock* FindBlock(); |
| 233 inline void IncreaseBlockUses(GlobalHandles* global_handles); | |
| 234 inline void DecreaseBlockUses(GlobalHandles* global_handles); | |
| 219 | 235 |
| 236 // Storage for object pointer. | |
| 237 // Placed first to avoid offset computation. | |
| 238 Object* object_; | |
| 239 | |
| 240 // Next word stores class_id, index, state, and independent. | |
| 241 // Note: the most aligned fields should go first. | |
| 242 | |
| 243 // Wrapper class ID. | |
| 220 uint16_t class_id_; | 244 uint16_t class_id_; |
| 221 | 245 |
| 222 // Transition diagram: | 246 // Index in the containing handle block. |
| 223 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED } | 247 uint8_t index_; |
| 224 enum State { | 248 |
| 225 NORMAL, // Normal global handle. | 249 // Need one more bit for MSVC as it treats enums as signed. |
| 226 WEAK, // Flagged as weak but not yet finalized. | 250 State state_ : 4; |
| 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 | 251 |
| 233 bool independent_ : 1; | 252 bool independent_ : 1; |
| 234 | 253 |
| 235 private: | |
| 236 // Handle specific callback. | 254 // Handle specific callback. |
| 237 WeakReferenceCallback callback_; | 255 WeakReferenceCallback callback_; |
| 256 | |
| 238 // Provided data for callback. In DESTROYED state, this is used for | 257 // Provided data for callback. In DESTROYED state, this is used for |
| 239 // the free list link. | 258 // the free list link. |
| 240 union { | 259 union { |
| 241 void* parameter; | 260 void* parameter; |
| 242 Node* next_free; | 261 Node* next_free; |
| 243 } parameter_or_next_free_; | 262 } parameter_or_next_free_; |
| 244 | 263 |
| 245 // Linkage for the list. | 264 DISALLOW_COPY_AND_ASSIGN(Node); |
| 246 Node* next_; | |
| 247 | |
| 248 public: | |
| 249 TRACK_MEMORY("GlobalHandles::Node") | |
| 250 }; | 265 }; |
| 251 | 266 |
| 252 | 267 |
| 253 class GlobalHandles::Pool { | 268 class GlobalHandles::NodeBlock { |
| 254 public: | 269 public: |
| 255 Pool() { | 270 static const int kSize = 256; |
| 256 current_ = new Chunk(); | 271 |
| 257 current_->previous = NULL; | 272 explicit NodeBlock(GlobalHandles* global_handles) { |
| 258 next_ = current_->nodes; | 273 next_ = global_handles->first_block_; |
| 259 limit_ = current_->nodes + kNodesPerChunk; | 274 global_handles->first_block_ = this; |
| 275 next_used_ = prev_used_ = NULL; | |
| 276 used_nodes_ = 0; | |
| 277 for (int i = kSize - 1; i >= 0; --i) { | |
| 278 nodes_[i].PreInitialize(i, global_handles); | |
| 260 } | 279 } |
| 280 } | |
| 261 | 281 |
| 262 ~Pool() { | 282 Node* node_at(int index) { |
| 263 if (current_ != NULL) { | 283 ASSERT(0 <= index && index < kSize); |
| 264 Release(); | 284 return &nodes_[index]; |
| 285 } | |
| 286 | |
| 287 void IncreaseUses(GlobalHandles* global_handles) { | |
| 288 ASSERT(used_nodes_ < kSize); | |
| 289 if (used_nodes_++ == 0) { | |
| 290 NodeBlock* old_first = global_handles->first_used_block_; | |
| 291 global_handles->first_used_block_ = this; | |
| 292 next_used_ = old_first; | |
| 293 prev_used_ = NULL; | |
| 294 if (old_first == NULL) return; | |
| 295 old_first->prev_used_ = this; | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 void DecreaseUses(GlobalHandles* global_handles) { | |
| 300 ASSERT(used_nodes_ > 0); | |
| 301 if (--used_nodes_ == 0) { | |
| 302 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; | |
| 303 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; | |
| 304 if (this == global_handles->first_used_block_) { | |
| 305 global_handles->first_used_block_ = next_used_; | |
| 265 } | 306 } |
| 266 } | 307 } |
| 308 } | |
| 267 | 309 |
| 268 Node* Allocate() { | 310 // Next block in the list of all blocks. |
| 269 if (next_ < limit_) { | 311 NodeBlock* next() const { return next_; } |
| 270 return next_++; | |
| 271 } | |
| 272 return SlowAllocate(); | |
| 273 } | |
| 274 | 312 |
| 275 void Release() { | 313 // Next/previous block in the list of blocks with used nodes. |
| 276 Chunk* current = current_; | 314 NodeBlock* next_used() const { return next_used_; } |
| 277 ASSERT(current != NULL); // At least a single block must by allocated | 315 NodeBlock* prev_used() const { return prev_used_; } |
| 278 do { | |
| 279 Chunk* previous = current->previous; | |
| 280 delete current; | |
| 281 current = previous; | |
| 282 } while (current != NULL); | |
| 283 current_ = NULL; | |
| 284 next_ = limit_ = NULL; | |
| 285 } | |
| 286 | 316 |
| 287 private: | 317 private: |
| 288 static const int kNodesPerChunk = (1 << 12) - 1; | 318 Node nodes_[kSize]; |
| 289 struct Chunk : public Malloced { | 319 NodeBlock* next_; |
| 290 Chunk* previous; | 320 int used_nodes_; |
| 291 Node nodes[kNodesPerChunk]; | 321 NodeBlock* next_used_; |
| 292 }; | 322 NodeBlock* prev_used_; |
| 293 | |
| 294 Node* SlowAllocate() { | |
| 295 Chunk* chunk = new Chunk(); | |
| 296 chunk->previous = current_; | |
| 297 current_ = chunk; | |
| 298 | |
| 299 Node* new_nodes = current_->nodes; | |
| 300 next_ = new_nodes + 1; | |
| 301 limit_ = new_nodes + kNodesPerChunk; | |
| 302 return new_nodes; | |
| 303 } | |
| 304 | |
| 305 Chunk* current_; | |
| 306 Node* next_; | |
| 307 Node* limit_; | |
| 308 }; | 323 }; |
| 309 | 324 |
| 310 | 325 |
| 326 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { | |
| 327 intptr_t ptr = reinterpret_cast<intptr_t>(this); | |
| 328 ptr = ptr - index_ * sizeof(Node); | |
| 329 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); | |
| 330 ASSERT(block->node_at(index_) == this); | |
| 331 return block; | |
| 332 } | |
| 333 | |
| 334 | |
| 335 void GlobalHandles::Node::IncreaseBlockUses(GlobalHandles* global_handles) { | |
| 336 FindBlock()->IncreaseUses(global_handles); | |
| 337 } | |
| 338 | |
| 339 | |
| 340 void GlobalHandles::Node::DecreaseBlockUses(GlobalHandles* global_handles) { | |
| 341 FindBlock()->DecreaseUses(global_handles); | |
| 342 } | |
| 343 | |
| 344 | |
| 345 class GlobalHandles::NodeIterator { | |
| 346 public: | |
| 347 explicit NodeIterator(GlobalHandles* global_handles) | |
| 348 : block_(global_handles->first_used_block_), | |
| 349 index_(0) {} | |
| 350 | |
| 351 bool done() const { return block_ == NULL; } | |
| 352 | |
| 353 Node* node() const { | |
| 354 ASSERT(!done()); | |
| 355 return block_->node_at(index_); | |
| 356 } | |
| 357 | |
| 358 void Advance() { | |
| 359 ASSERT(!done()); | |
| 360 if (++index_ < NodeBlock::kSize) return; | |
| 361 index_ = 0; | |
| 362 block_ = block_->next_used(); | |
| 363 } | |
| 364 | |
| 365 private: | |
| 366 NodeBlock* block_; | |
| 367 int index_; | |
| 368 | |
| 369 DISALLOW_COPY_AND_ASSIGN(NodeIterator); | |
| 370 }; | |
| 371 | |
| 372 | |
| 311 GlobalHandles::GlobalHandles(Isolate* isolate) | 373 GlobalHandles::GlobalHandles(Isolate* isolate) |
| 312 : isolate_(isolate), | 374 : isolate_(isolate), |
| 313 number_of_weak_handles_(0), | 375 number_of_weak_handles_(0), |
| 314 number_of_global_object_weak_handles_(0), | 376 number_of_global_object_weak_handles_(0), |
| 315 head_(NULL), | 377 first_block_(NULL), |
| 378 first_used_block_(NULL), | |
| 316 first_free_(NULL), | 379 first_free_(NULL), |
| 317 first_deallocated_(NULL), | 380 post_gc_processing_count_(0) {} |
| 318 pool_(new Pool()), | |
| 319 post_gc_processing_count_(0), | |
| 320 object_groups_(4) { | |
| 321 } | |
| 322 | 381 |
| 323 | 382 |
| 324 GlobalHandles::~GlobalHandles() { | 383 GlobalHandles::~GlobalHandles() { |
| 325 delete pool_; | 384 NodeBlock* block = first_block_; |
| 326 pool_ = 0; | 385 while (block != NULL) { |
| 386 NodeBlock* tmp = block->next(); | |
| 387 delete block; | |
| 388 block = tmp; | |
| 389 } | |
| 390 first_block_ = NULL; | |
| 327 } | 391 } |
| 328 | 392 |
| 329 | 393 |
| 330 Handle<Object> GlobalHandles::Create(Object* value) { | 394 Handle<Object> GlobalHandles::Create(Object* value) { |
| 331 isolate_->counters()->global_handles()->Increment(); | 395 isolate_->counters()->global_handles()->Increment(); |
| 332 Node* result; | 396 if (first_free_ == NULL) { |
| 333 if (first_free()) { | 397 new NodeBlock(this); |
|
Vyacheslav Egorov (Chromium)
2011/05/24 16:45:12
Personally I don't like constructors with deep imp
| |
| 334 // Take the first node in the free list. | |
| 335 result = first_free(); | |
| 336 set_first_free(result->next_free()); | |
| 337 } else if (first_deallocated()) { | |
| 338 // Next try deallocated list | |
| 339 result = first_deallocated(); | |
| 340 set_first_deallocated(result->next_free()); | |
| 341 ASSERT(result->next() == head()); | |
| 342 set_head(result); | |
| 343 } else { | |
| 344 // Allocate a new node. | |
| 345 result = pool_->Allocate(); | |
| 346 result->set_next(head()); | |
| 347 set_head(result); | |
| 348 } | 398 } |
| 349 result->Initialize(value); | 399 ASSERT(first_free_ != NULL); |
| 400 // Take the first node in the free list. | |
| 401 Node* result = first_free_; | |
| 402 first_free_ = result->next_free(); | |
| 403 result->Initialize(value, this); | |
| 350 return result->handle(); | 404 return result->handle(); |
| 351 } | 405 } |
| 352 | 406 |
| 353 | 407 |
| 354 void GlobalHandles::Destroy(Object** location) { | 408 void GlobalHandles::Destroy(Object** location) { |
| 355 isolate_->counters()->global_handles()->Decrement(); | 409 isolate_->counters()->global_handles()->Decrement(); |
| 356 if (location == NULL) return; | 410 if (location == NULL) return; |
| 357 Node* node = Node::FromLocation(location); | 411 Node::FromLocation(location)->Destroy(this); |
| 358 node->Destroy(this); | |
| 359 // Link the destroyed. | |
| 360 node->set_next_free(first_free()); | |
| 361 set_first_free(node); | |
| 362 } | 412 } |
| 363 | 413 |
| 364 | 414 |
| 365 void GlobalHandles::MakeWeak(Object** location, void* parameter, | 415 void GlobalHandles::MakeWeak(Object** location, void* parameter, |
| 366 WeakReferenceCallback callback) { | 416 WeakReferenceCallback callback) { |
| 367 ASSERT(callback != NULL); | 417 ASSERT(callback != NULL); |
| 368 Node::FromLocation(location)->MakeWeak(this, parameter, callback); | 418 Node::FromLocation(location)->MakeWeak(this, parameter, callback); |
| 369 } | 419 } |
| 370 | 420 |
| 371 | 421 |
| 372 void GlobalHandles::ClearWeakness(Object** location) { | 422 void GlobalHandles::ClearWeakness(Object** location) { |
| 373 Node::FromLocation(location)->ClearWeakness(this); | 423 Node::FromLocation(location)->ClearWeakness(this); |
| 374 } | 424 } |
| 375 | 425 |
| 376 | 426 |
| 377 void GlobalHandles::MarkIndependent(Object** location) { | 427 void GlobalHandles::MarkIndependent(Object** location) { |
| 378 Node::FromLocation(location)->MarkIndependent(this); | 428 Node* node = Node::FromLocation(location); |
| 429 if (node->is_independent()) return; | |
| 430 node->MarkIndependent(); | |
| 431 if (isolate_->heap()->InNewSpace(*location)) { | |
| 432 new_space_independent_.Add(node); | |
| 433 } | |
| 379 } | 434 } |
| 380 | 435 |
| 381 | 436 |
| 382 bool GlobalHandles::IsNearDeath(Object** location) { | 437 bool GlobalHandles::IsNearDeath(Object** location) { |
| 383 return Node::FromLocation(location)->IsNearDeath(); | 438 return Node::FromLocation(location)->IsNearDeath(); |
| 384 } | 439 } |
| 385 | 440 |
| 386 | 441 |
| 387 bool GlobalHandles::IsWeak(Object** location) { | 442 bool GlobalHandles::IsWeak(Object** location) { |
| 388 return Node::FromLocation(location)->IsWeak(); | 443 return Node::FromLocation(location)->IsWeak(); |
| 389 } | 444 } |
| 390 | 445 |
| 391 | 446 |
| 392 void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) { | 447 void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) { |
| 393 Node::FromLocation(location)->SetWrapperClassId(class_id); | 448 Node::FromLocation(location)->set_wrapper_class_id(class_id); |
| 394 } | 449 } |
| 395 | 450 |
| 396 | 451 |
| 397 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { | 452 void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { |
| 398 // Traversal of GC roots in the global handle list that are marked as | 453 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 399 // WEAK, PENDING or NEAR_DEATH. | 454 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location()); |
| 400 for (Node* current = head_; current != NULL; current = current->next()) { | |
| 401 if (current->state_ == Node::WEAK | |
| 402 || current->state_ == Node::PENDING | |
| 403 || current->state_ == Node::NEAR_DEATH) { | |
| 404 v->VisitPointer(¤t->object_); | |
| 405 } | |
| 406 } | 455 } |
| 407 } | 456 } |
| 408 | 457 |
| 409 | 458 |
| 410 void GlobalHandles::IterateWeakIndependentRoots(ObjectVisitor* v) { | 459 void GlobalHandles::IterateWeakIndependentRoots(ObjectVisitor* v) { |
| 411 // Traversal of GC roots in the global handle list that are independent | 460 for (int i = 0; i < new_space_independent_.length(); ++i) { |
| 412 // and marked as WEAK, PENDING or NEAR_DEATH. | 461 Node* node = new_space_independent_[i]; |
| 413 for (Node* current = head_; current != NULL; current = current->next()) { | 462 ASSERT(node->is_independent()); |
| 414 if (!current->independent_) continue; | 463 if (node->IsWeakRetainer()) v->VisitPointer(node->location()); |
| 415 if (current->state_ == Node::WEAK | |
| 416 || current->state_ == Node::PENDING | |
| 417 || current->state_ == Node::NEAR_DEATH) { | |
| 418 v->VisitPointer(¤t->object_); | |
| 419 } | |
| 420 } | 464 } |
| 421 } | 465 } |
| 422 | 466 |
| 423 | 467 |
| 424 void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f, | 468 void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f, |
| 425 WeakReferenceCallback callback) { | 469 WeakReferenceCallback callback) { |
| 426 for (Node* current = head_; current != NULL; current = current->next()) { | 470 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 427 if (current->IsWeak() && current->callback() == callback) { | 471 if (it.node()->IsWeak() && it.node()->callback() == callback) { |
| 428 f(current->object_, current->parameter()); | 472 f(it.node()->object(), it.node()->parameter()); |
| 429 } | 473 } |
| 430 } | 474 } |
| 431 } | 475 } |
| 432 | 476 |
| 433 | 477 |
| 434 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { | 478 void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) { |
| 435 for (Node* current = head_; current != NULL; current = current->next()) { | 479 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 436 if (current->state_ == Node::WEAK) { | 480 if (it.node()->IsWeak() && f(it.node()->location())) { |
| 437 if (f(¤t->object_)) { | 481 it.node()->MarkPending(); |
| 438 current->state_ = Node::PENDING; | |
| 439 LOG(isolate_, | |
| 440 HandleEvent("GlobalHandle::Pending", current->handle().location())); | |
| 441 } | |
| 442 } | 482 } |
| 443 } | 483 } |
| 444 } | 484 } |
| 445 | 485 |
| 446 | 486 |
| 447 void GlobalHandles::IdentifyWeakIndependentHandles(WeakSlotCallbackWithHeap f) { | 487 void GlobalHandles::IdentifyWeakIndependentHandles(WeakSlotCallbackWithHeap f) { |
| 448 for (Node* current = head_; current != NULL; current = current->next()) { | 488 for (int i = 0; i < new_space_independent_.length(); ++i) { |
| 449 if (current->state_ == Node::WEAK && current->independent_) { | 489 Node* node = new_space_independent_[i]; |
| 450 if (f(isolate_->heap(), ¤t->object_)) { | 490 ASSERT(node->is_independent()); |
| 451 current->state_ = Node::PENDING; | 491 if (node->IsWeak() && f(isolate_->heap(), node->location())) { |
| 452 LOG(isolate_, | 492 node->MarkPending(); |
| 453 HandleEvent("GlobalHandle::Pending", current->handle().location())); | |
| 454 } | |
| 455 } | 493 } |
| 456 } | 494 } |
| 457 } | 495 } |
| 458 | 496 |
| 459 | 497 |
| 460 bool GlobalHandles::PostGarbageCollectionProcessing( | 498 bool GlobalHandles::PostGarbageCollectionProcessing( |
| 461 GarbageCollector collector) { | 499 GarbageCollector collector) { |
| 462 // Process weak global handle callbacks. This must be done after the | 500 // Process weak global handle callbacks. This must be done after the |
| 463 // GC is completely done, because the callbacks may invoke arbitrary | 501 // GC is completely done, because the callbacks may invoke arbitrary |
| 464 // API functions. | 502 // API functions. |
| 465 // At the same time deallocate all DESTROYED nodes. | |
| 466 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC); | 503 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC); |
| 467 const int initial_post_gc_processing_count = ++post_gc_processing_count_; | 504 const int initial_post_gc_processing_count = ++post_gc_processing_count_; |
| 468 bool next_gc_likely_to_collect_more = false; | 505 bool next_gc_likely_to_collect_more = false; |
| 469 Node** p = &head_; | 506 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 470 while (*p != NULL) { | |
| 471 // Skip dependent handles. Their weak callbacks might expect to be | 507 // Skip dependent handles. Their weak callbacks might expect to be |
| 472 // called between two global garbage collection callbacks which | 508 // called between two global garbage collection callbacks which |
| 473 // are not called for minor collections. | 509 // are not called for minor collections. |
| 474 if (collector == SCAVENGER && !(*p)->independent_) { | 510 if (collector == SCAVENGER && !it.node()->is_independent()) continue; |
|
Vyacheslav Egorov (Chromium)
2011/05/24 16:45:12
Interesting: so skipping blocks with no young inde
| |
| 475 p = (*p)->next_addr(); | |
| 476 continue; | |
| 477 } | |
| 478 | 511 |
| 479 if ((*p)->PostGarbageCollectionProcessing(isolate_, this)) { | 512 if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) { |
| 480 if (initial_post_gc_processing_count != post_gc_processing_count_) { | 513 if (initial_post_gc_processing_count != post_gc_processing_count_) { |
| 481 // Weak callback triggered another GC and another round of | 514 // Weak callback triggered another GC and another round of |
| 482 // PostGarbageCollection processing. The current node might | 515 // PostGarbageCollection processing. The current node might |
| 483 // have been deleted in that round, so we need to bail out (or | 516 // have been deleted in that round, so we need to bail out (or |
| 484 // restart the processing). | 517 // restart the processing). |
| 485 break; | 518 return next_gc_likely_to_collect_more; |
| 486 } | 519 } |
| 487 } | 520 } |
| 488 if ((*p)->state_ == Node::DESTROYED) { | 521 if (!it.node()->IsRetainer()) { |
| 489 // Delete the link. | |
| 490 Node* node = *p; | |
| 491 *p = node->next(); // Update the link. | |
| 492 if (first_deallocated()) { | |
| 493 first_deallocated()->set_next(node); | |
| 494 } | |
| 495 node->set_next_free(first_deallocated()); | |
| 496 set_first_deallocated(node); | |
| 497 next_gc_likely_to_collect_more = true; | 522 next_gc_likely_to_collect_more = true; |
| 498 } else { | |
| 499 p = (*p)->next_addr(); | |
| 500 } | 523 } |
| 501 } | 524 } |
| 502 set_first_free(NULL); | 525 int last = 0; |
| 503 if (first_deallocated()) { | 526 for (int i = 0; i < new_space_independent_.length(); ++i) { |
| 504 first_deallocated()->set_next(head()); | 527 Node* node = new_space_independent_[i]; |
| 528 if (node->IsRetainer() && isolate_->heap()->InNewSpace(node->object())) { | |
| 529 new_space_independent_[last++] = node; | |
| 530 } | |
| 505 } | 531 } |
| 506 | 532 new_space_independent_.Rewind(last); |
| 507 return next_gc_likely_to_collect_more; | 533 return next_gc_likely_to_collect_more; |
| 508 } | 534 } |
| 509 | 535 |
| 510 | 536 |
| 511 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { | 537 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { |
| 512 // Traversal of global handles marked as NORMAL. | 538 // Traversal of global handles marked as NORMAL. |
| 513 for (Node* current = head_; current != NULL; current = current->next()) { | 539 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 514 if (current->state_ == Node::NORMAL) { | 540 if (it.node()->state() == Node::NORMAL) { |
| 515 v->VisitPointer(¤t->object_); | 541 v->VisitPointer(it.node()->location()); |
| 516 } | 542 } |
| 517 } | 543 } |
| 518 } | 544 } |
| 519 | 545 |
| 520 | 546 |
| 521 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) { | 547 void GlobalHandles::IterateAllRoots(ObjectVisitor* v) { |
| 522 for (Node* current = head_; current != NULL; current = current->next()) { | 548 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 523 if (current->state_ != Node::DESTROYED) { | 549 if (it.node()->IsRetainer()) { |
| 524 v->VisitPointer(¤t->object_); | 550 v->VisitPointer(it.node()->location()); |
| 525 } | 551 } |
| 526 } | 552 } |
| 527 } | 553 } |
| 528 | 554 |
| 529 | 555 |
| 530 void GlobalHandles::IterateStrongAndDependentRoots(ObjectVisitor* v) { | 556 void GlobalHandles::IterateStrongAndDependentRoots(ObjectVisitor* v) { |
| 531 for (Node* current = head_; current != NULL; current = current->next()) { | 557 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 532 if ((current->independent_ && current->state_ == Node::NORMAL) || | 558 if ((it.node()->is_independent() && it.node()->state() == Node::NORMAL) || |
| 533 (!current->independent_ && current->state_ != Node::DESTROYED)) { | 559 (!it.node()->is_independent() && it.node()->IsRetainer())) { |
| 534 v->VisitPointer(¤t->object_); | 560 v->VisitPointer(it.node()->location()); |
| 535 } | 561 } |
| 536 } | 562 } |
| 537 } | 563 } |
| 538 | 564 |
| 539 | 565 |
| 540 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) { | 566 void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) { |
| 541 for (Node* current = head_; current != NULL; current = current->next()) { | 567 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 542 if (current->class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId && | 568 if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) { |
| 543 current->CanBeRetainer()) { | 569 v->VisitEmbedderReference(it.node()->location(), |
| 544 v->VisitEmbedderReference(¤t->object_, current->class_id_); | 570 it.node()->wrapper_class_id()); |
| 545 } | 571 } |
| 546 } | 572 } |
| 547 } | 573 } |
| 548 | 574 |
| 549 | 575 |
| 550 void GlobalHandles::TearDown() { | 576 void GlobalHandles::TearDown() { |
| 551 // Reset all the lists. | 577 // TODO(vitalyr): dispose stuff? |
| 552 set_head(NULL); | |
| 553 set_first_free(NULL); | |
| 554 set_first_deallocated(NULL); | |
| 555 pool_->Release(); | |
| 556 } | 578 } |
| 557 | 579 |
| 558 | 580 |
| 559 void GlobalHandles::RecordStats(HeapStats* stats) { | 581 void GlobalHandles::RecordStats(HeapStats* stats) { |
| 560 *stats->global_handle_count = 0; | 582 *stats->global_handle_count = 0; |
| 561 *stats->weak_global_handle_count = 0; | 583 *stats->weak_global_handle_count = 0; |
| 562 *stats->pending_global_handle_count = 0; | 584 *stats->pending_global_handle_count = 0; |
| 563 *stats->near_death_global_handle_count = 0; | 585 *stats->near_death_global_handle_count = 0; |
| 564 *stats->destroyed_global_handle_count = 0; | 586 *stats->destroyed_global_handle_count = 0; |
| 565 for (Node* current = head_; current != NULL; current = current->next()) { | 587 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 566 *stats->global_handle_count += 1; | 588 *stats->global_handle_count += 1; |
| 567 if (current->state_ == Node::WEAK) { | 589 if (it.node()->state() == Node::WEAK) { |
| 568 *stats->weak_global_handle_count += 1; | 590 *stats->weak_global_handle_count += 1; |
| 569 } else if (current->state_ == Node::PENDING) { | 591 } else if (it.node()->state() == Node::PENDING) { |
| 570 *stats->pending_global_handle_count += 1; | 592 *stats->pending_global_handle_count += 1; |
| 571 } else if (current->state_ == Node::NEAR_DEATH) { | 593 } else if (it.node()->state() == Node::NEAR_DEATH) { |
| 572 *stats->near_death_global_handle_count += 1; | 594 *stats->near_death_global_handle_count += 1; |
| 573 } else if (current->state_ == Node::DESTROYED) { | 595 } else if (it.node()->state() == Node::DESTROYED) { |
| 574 *stats->destroyed_global_handle_count += 1; | 596 *stats->destroyed_global_handle_count += 1; |
| 575 } | 597 } |
| 576 } | 598 } |
| 577 } | 599 } |
| 578 | 600 |
| 579 #ifdef DEBUG | 601 #ifdef DEBUG |
| 580 | 602 |
| 581 void GlobalHandles::PrintStats() { | 603 void GlobalHandles::PrintStats() { |
| 582 int total = 0; | 604 int total = 0; |
| 583 int weak = 0; | 605 int weak = 0; |
| 584 int pending = 0; | 606 int pending = 0; |
| 585 int near_death = 0; | 607 int near_death = 0; |
| 586 int destroyed = 0; | 608 int destroyed = 0; |
| 587 | 609 |
| 588 for (Node* current = head_; current != NULL; current = current->next()) { | 610 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 589 total++; | 611 total++; |
| 590 if (current->state_ == Node::WEAK) weak++; | 612 if (it.node()->state() == Node::WEAK) weak++; |
| 591 if (current->state_ == Node::PENDING) pending++; | 613 if (it.node()->state() == Node::PENDING) pending++; |
| 592 if (current->state_ == Node::NEAR_DEATH) near_death++; | 614 if (it.node()->state() == Node::NEAR_DEATH) near_death++; |
| 593 if (current->state_ == Node::DESTROYED) destroyed++; | 615 if (it.node()->state() == Node::DESTROYED) destroyed++; |
| 594 } | 616 } |
| 595 | 617 |
| 596 PrintF("Global Handle Statistics:\n"); | 618 PrintF("Global Handle Statistics:\n"); |
| 597 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); | 619 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); |
| 598 PrintF(" # weak = %d\n", weak); | 620 PrintF(" # weak = %d\n", weak); |
| 599 PrintF(" # pending = %d\n", pending); | 621 PrintF(" # pending = %d\n", pending); |
| 600 PrintF(" # near_death = %d\n", near_death); | 622 PrintF(" # near_death = %d\n", near_death); |
| 601 PrintF(" # destroyed = %d\n", destroyed); | 623 PrintF(" # destroyed = %d\n", destroyed); |
| 602 PrintF(" # total = %d\n", total); | 624 PrintF(" # total = %d\n", total); |
| 603 } | 625 } |
| 604 | 626 |
| 605 void GlobalHandles::Print() { | 627 void GlobalHandles::Print() { |
| 606 PrintF("Global handles:\n"); | 628 PrintF("Global handles:\n"); |
| 607 for (Node* current = head_; current != NULL; current = current->next()) { | 629 for (NodeIterator it(this); !it.done(); it.Advance()) { |
| 608 PrintF(" handle %p to %p (weak=%d)\n", | 630 PrintF(" handle %p to %p%s\n", |
| 609 reinterpret_cast<void*>(current->handle().location()), | 631 reinterpret_cast<void*>(it.node()->location()), |
| 610 reinterpret_cast<void*>(*current->handle()), | 632 reinterpret_cast<void*>(it.node()->object()), |
| 611 current->state_ == Node::WEAK); | 633 it.node()->IsWeak() ? " (weak)" : ""); |
| 612 } | 634 } |
| 613 } | 635 } |
| 614 | 636 |
| 615 #endif | 637 #endif |
| 616 | 638 |
| 617 | 639 |
| 618 | 640 |
| 619 void GlobalHandles::AddObjectGroup(Object*** handles, | 641 void GlobalHandles::AddObjectGroup(Object*** handles, |
| 620 size_t length, | 642 size_t length, |
| 621 v8::RetainedObjectInfo* info) { | 643 v8::RetainedObjectInfo* info) { |
| 622 #ifdef DEBUG | 644 #ifdef DEBUG |
| 623 for (size_t i = 0; i < length; ++i) { | 645 for (size_t i = 0; i < length; ++i) { |
| 624 ASSERT(!Node::FromLocation(handles[i])->independent_); | 646 ASSERT(!Node::FromLocation(handles[i])->is_independent()); |
| 625 } | 647 } |
| 626 #endif | 648 #endif |
| 627 if (length == 0) { | 649 if (length == 0) { |
| 628 if (info != NULL) info->Dispose(); | 650 if (info != NULL) info->Dispose(); |
| 629 return; | 651 return; |
| 630 } | 652 } |
| 631 object_groups_.Add(ObjectGroup::New(handles, length, info)); | 653 object_groups_.Add(ObjectGroup::New(handles, length, info)); |
| 632 } | 654 } |
| 633 | 655 |
| 634 | 656 |
| 635 void GlobalHandles::AddImplicitReferences(HeapObject** parent, | 657 void GlobalHandles::AddImplicitReferences(HeapObject** parent, |
| 636 Object*** children, | 658 Object*** children, |
| 637 size_t length) { | 659 size_t length) { |
| 638 #ifdef DEBUG | 660 #ifdef DEBUG |
| 639 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->independent_); | 661 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent()); |
| 640 for (size_t i = 0; i < length; ++i) { | 662 for (size_t i = 0; i < length; ++i) { |
| 641 ASSERT(!Node::FromLocation(children[i])->independent_); | 663 ASSERT(!Node::FromLocation(children[i])->is_independent()); |
| 642 } | 664 } |
| 643 #endif | 665 #endif |
| 644 if (length == 0) return; | 666 if (length == 0) return; |
| 645 implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length)); | 667 implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length)); |
| 646 } | 668 } |
| 647 | 669 |
| 648 | 670 |
| 649 void GlobalHandles::RemoveObjectGroups() { | 671 void GlobalHandles::RemoveObjectGroups() { |
| 650 for (int i = 0; i < object_groups_.length(); i++) { | 672 for (int i = 0; i < object_groups_.length(); i++) { |
| 651 object_groups_.at(i)->Dispose(); | 673 object_groups_.at(i)->Dispose(); |
| 652 } | 674 } |
| 653 object_groups_.Clear(); | 675 object_groups_.Clear(); |
| 654 } | 676 } |
| 655 | 677 |
| 656 | 678 |
| 657 void GlobalHandles::RemoveImplicitRefGroups() { | 679 void GlobalHandles::RemoveImplicitRefGroups() { |
| 658 for (int i = 0; i < implicit_ref_groups_.length(); i++) { | 680 for (int i = 0; i < implicit_ref_groups_.length(); i++) { |
| 659 implicit_ref_groups_.at(i)->Dispose(); | 681 implicit_ref_groups_.at(i)->Dispose(); |
| 660 } | 682 } |
| 661 implicit_ref_groups_.Clear(); | 683 implicit_ref_groups_.Clear(); |
| 662 } | 684 } |
| 663 | 685 |
| 664 | 686 |
| 665 } } // namespace v8::internal | 687 } } // namespace v8::internal |
| OLD | NEW |