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

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

Issue 7054072: Refactor storage of global handles. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 6 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
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 // 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(&current->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(&current->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(&current->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(), &current->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(&current->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(&current->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(&current->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(&current->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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698