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

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

Issue 6992025: WIP: Blocks for global handles. Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/global-handles.h ('k') | src/utils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 23 matching lines...) Expand all
34 34
35 namespace v8 { 35 namespace v8 {
36 namespace internal { 36 namespace internal {
37 37
38 38
39 ObjectGroup::~ObjectGroup() { 39 ObjectGroup::~ObjectGroup() {
40 if (info_ != NULL) info_->Dispose(); 40 if (info_ != NULL) info_->Dispose();
41 } 41 }
42 42
43 43
44 class GlobalHandles::Node : public Malloced { 44 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(&current->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(&current->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(&current->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(), &current->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(&current->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(&current->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(&current->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(&current->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
OLDNEW
« no previous file with comments | « src/global-handles.h ('k') | src/utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698