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