blob: 87066faeaf64950a8349da385e36cd206b23bea6 [file] [log] [blame]
ager@chromium.org71daaf62009-04-01 07:22:49 +00001// Copyright 2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "global-handles.h"
32
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "vm-state-inl.h"
34
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035namespace v8 {
36namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000038
39ObjectGroup::~ObjectGroup() {
40 if (info_ != NULL) info_->Dispose();
41}
42
43
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000044class GlobalHandles::Node {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045 public:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000046 // 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 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000056 // 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 // TODO(1428): if it's a weak handle we should have invoked its callback.
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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089 object_ = object;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000090 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000091 independent_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 state_ = NORMAL;
93 parameter_or_next_free_.parameter = NULL;
94 callback_ = NULL;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000095 IncreaseBlockUses(global_handles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 }
97
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000098 void Release(GlobalHandles* global_handles) {
99 ASSERT(state_ != FREE);
100 if (IsWeakRetainer()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000101 global_handles->number_of_weak_handles_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102 if (object_->IsJSGlobalObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 global_handles->number_of_global_object_weak_handles_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 }
105 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000106 state_ = FREE;
107 parameter_or_next_free_.next_free = global_handles->first_free_;
108 global_handles->first_free_ = this;
109 DecreaseBlockUses(global_handles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 }
111
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000112 // Object slot accessors.
113 Object* object() const { return object_; }
114 Object** location() { return &object_; }
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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173
174 // Accessors for next free node in the free list.
175 Node* next_free() {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000176 ASSERT(state_ == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 return parameter_or_next_free_.next_free;
178 }
179 void set_next_free(Node* value) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000180 ASSERT(state_ == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 parameter_or_next_free_.next_free = value;
182 }
183
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000184 void MakeWeak(GlobalHandles* global_handles,
185 void* parameter,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 WeakReferenceCallback callback) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000187 ASSERT(state_ != FREE);
188 if (!IsWeakRetainer()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000189 global_handles->number_of_weak_handles_++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190 if (object_->IsJSGlobalObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 global_handles->number_of_global_object_weak_handles_++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 }
193 }
194 state_ = WEAK;
195 set_parameter(parameter);
196 callback_ = callback;
197 }
198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 void ClearWeakness(GlobalHandles* global_handles) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000200 ASSERT(state_ != FREE);
201 if (IsWeakRetainer()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000202 global_handles->number_of_weak_handles_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 if (object_->IsJSGlobalObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000204 global_handles->number_of_global_object_weak_handles_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205 }
206 }
207 state_ = NORMAL;
208 set_parameter(NULL);
209 }
210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 bool PostGarbageCollectionProcessing(Isolate* isolate,
212 GlobalHandles* global_handles) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000213 if (state_ != Node::PENDING) return false;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000214 WeakReferenceCallback func = callback();
215 if (func == NULL) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000216 Release(global_handles);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000217 return false;
218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 void* par = parameter();
220 state_ = NEAR_DEATH;
221 set_parameter(NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000222
223 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
224 {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000225 // Check that we are not passing a finalized external string to
226 // the callback.
227 ASSERT(!object_->IsExternalAsciiString() ||
228 ExternalAsciiString::cast(object_)->resource() != NULL);
229 ASSERT(!object_->IsExternalTwoByteString() ||
230 ExternalTwoByteString::cast(object_)->resource() != NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000231 // Leaving V8.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 VMState state(isolate, EXTERNAL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000233 func(object, par);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 }
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000235 // Absense of explicit cleanup or revival of weak handle
236 // in most of the cases would lead to memory leak.
237 ASSERT(state_ != NEAR_DEATH);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000238 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 }
240
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000241 private:
242 inline NodeBlock* FindBlock();
243 inline void IncreaseBlockUses(GlobalHandles* global_handles);
244 inline void DecreaseBlockUses(GlobalHandles* global_handles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000246 // 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.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000254 uint16_t class_id_;
255
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000256 // Index in the containing handle block.
257 uint8_t index_;
258
259 // Need one more bit for MSVC as it treats enums as signed.
260 State state_ : 4;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000262 bool independent_ : 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000263 bool in_new_space_list_ : 1;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 // Handle specific callback.
266 WeakReferenceCallback callback_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000267
268 // Provided data for callback. In FREE state, this is used for
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269 // the free list link.
270 union {
271 void* parameter;
272 Node* next_free;
273 } parameter_or_next_free_;
274
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000275 DISALLOW_COPY_AND_ASSIGN(Node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276};
277
278
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000279class GlobalHandles::NodeBlock {
280 public:
281 static const int kSize = 256;
ager@chromium.org3811b432009-10-28 14:53:37 +0000282
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000283 explicit NodeBlock(NodeBlock* next)
284 : next_(next), used_nodes_(0), next_used_(NULL), prev_used_(NULL) {}
285
286 void PutNodesOnFreeList(Node** first_free) {
287 for (int i = kSize - 1; i >= 0; --i) {
288 nodes_[i].Initialize(i, first_free);
289 }
290 }
291
292 Node* node_at(int index) {
293 ASSERT(0 <= index && index < kSize);
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_;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000316 }
317 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000318 }
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000319
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000320 // Next block in the list of all blocks.
321 NodeBlock* next() const { return next_; }
ager@chromium.org3811b432009-10-28 14:53:37 +0000322
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000323 // Next/previous block in the list of blocks with used nodes.
324 NodeBlock* next_used() const { return next_used_; }
325 NodeBlock* prev_used() const { return prev_used_; }
ager@chromium.org3811b432009-10-28 14:53:37 +0000326
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000327 private:
328 Node nodes_[kSize];
329 NodeBlock* const next_;
330 int used_nodes_;
331 NodeBlock* next_used_;
332 NodeBlock* prev_used_;
333};
ager@chromium.org3811b432009-10-28 14:53:37 +0000334
ager@chromium.org3811b432009-10-28 14:53:37 +0000335
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000336GlobalHandles::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}
ager@chromium.org3811b432009-10-28 14:53:37 +0000343
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000344
345void GlobalHandles::Node::IncreaseBlockUses(GlobalHandles* global_handles) {
346 FindBlock()->IncreaseUses(global_handles);
347}
348
349
350void GlobalHandles::Node::DecreaseBlockUses(GlobalHandles* global_handles) {
351 FindBlock()->DecreaseUses(global_handles);
352}
353
354
355class 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);
ager@chromium.org3811b432009-10-28 14:53:37 +0000380};
381
382
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383GlobalHandles::GlobalHandles(Isolate* isolate)
384 : isolate_(isolate),
385 number_of_weak_handles_(0),
386 number_of_global_object_weak_handles_(0),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000387 first_block_(NULL),
388 first_used_block_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000389 first_free_(NULL),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000390 post_gc_processing_count_(0) {}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391
392
393GlobalHandles::~GlobalHandles() {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000394 NodeBlock* block = first_block_;
395 while (block != NULL) {
396 NodeBlock* tmp = block->next();
397 delete block;
398 block = tmp;
399 }
400 first_block_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401}
ager@chromium.org3811b432009-10-28 14:53:37 +0000402
403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404Handle<Object> GlobalHandles::Create(Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 isolate_->counters()->global_handles()->Increment();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000406 if (first_free_ == NULL) {
407 first_block_ = new NodeBlock(first_block_);
408 first_block_->PutNodesOnFreeList(&first_free_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000410 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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 return result->handle();
421}
422
423
424void GlobalHandles::Destroy(Object** location) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000425 isolate_->counters()->global_handles()->Decrement();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426 if (location == NULL) return;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000427 Node::FromLocation(location)->Release(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428}
429
430
431void GlobalHandles::MakeWeak(Object** location, void* parameter,
432 WeakReferenceCallback callback) {
433 ASSERT(callback != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 Node::FromLocation(location)->MakeWeak(this, parameter, callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435}
436
437
438void GlobalHandles::ClearWeakness(Object** location) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Node::FromLocation(location)->ClearWeakness(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440}
441
442
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000443void GlobalHandles::MarkIndependent(Object** location) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000444 Node::FromLocation(location)->MarkIndependent();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000445}
446
447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448bool GlobalHandles::IsNearDeath(Object** location) {
449 return Node::FromLocation(location)->IsNearDeath();
450}
451
452
453bool GlobalHandles::IsWeak(Object** location) {
454 return Node::FromLocation(location)->IsWeak();
455}
456
457
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000458void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000459 Node::FromLocation(location)->set_wrapper_class_id(class_id);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000460}
461
462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000464 for (NodeIterator it(this); !it.done(); it.Advance()) {
465 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000466 }
467}
468
469
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000470void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
471 WeakReferenceCallback callback) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000472 for (NodeIterator it(this); !it.done(); it.Advance()) {
473 if (it.node()->IsWeak() && it.node()->callback() == callback) {
474 f(it.node()->object(), it.node()->parameter());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000475 }
476 }
477}
478
479
ager@chromium.org9085a012009-05-11 19:22:57 +0000480void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000481 for (NodeIterator it(this); !it.done(); it.Advance()) {
482 if (it.node()->IsWeak() && f(it.node()->location())) {
483 it.node()->MarkPending();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 }
485 }
486}
487
488
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000489void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
490 for (int i = 0; i < new_space_nodes_.length(); ++i) {
491 Node* node = new_space_nodes_[i];
492 if (node->IsStrongRetainer() ||
493 (node->IsWeakRetainer() && !node->is_independent())) {
494 v->VisitPointer(node->location());
495 }
496 }
497}
498
499
500void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
501 WeakSlotCallbackWithHeap f) {
502 for (int i = 0; i < new_space_nodes_.length(); ++i) {
503 Node* node = new_space_nodes_[i];
504 ASSERT(node->is_in_new_space_list());
505 if (node->is_independent() && node->IsWeak() &&
506 f(isolate_->heap(), node->location())) {
507 node->MarkPending();
508 }
509 }
510}
511
512
513void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
514 for (int i = 0; i < new_space_nodes_.length(); ++i) {
515 Node* node = new_space_nodes_[i];
516 ASSERT(node->is_in_new_space_list());
517 if (node->is_independent() && node->IsWeakRetainer()) {
518 v->VisitPointer(node->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000519 }
520 }
521}
522
523
524bool GlobalHandles::PostGarbageCollectionProcessing(
525 GarbageCollector collector) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 // Process weak global handle callbacks. This must be done after the
527 // GC is completely done, because the callbacks may invoke arbitrary
528 // API functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
530 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000531 bool next_gc_likely_to_collect_more = false;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000532 if (collector == SCAVENGER) {
533 for (int i = 0; i < new_space_nodes_.length(); ++i) {
534 Node* node = new_space_nodes_[i];
535 ASSERT(node->is_in_new_space_list());
536 // Skip dependent handles. Their weak callbacks might expect to be
537 // called between two global garbage collection callbacks which
538 // are not called for minor collections.
539 if (!node->is_independent()) continue;
540 if (node->PostGarbageCollectionProcessing(isolate_, this)) {
541 if (initial_post_gc_processing_count != post_gc_processing_count_) {
542 // Weak callback triggered another GC and another round of
543 // PostGarbageCollection processing. The current node might
544 // have been deleted in that round, so we need to bail out (or
545 // restart the processing).
546 return next_gc_likely_to_collect_more;
547 }
548 }
549 if (!node->IsRetainer()) {
550 next_gc_likely_to_collect_more = true;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000551 }
552 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000553 } else {
554 for (NodeIterator it(this); !it.done(); it.Advance()) {
555 if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) {
556 if (initial_post_gc_processing_count != post_gc_processing_count_) {
557 // See the comment above.
558 return next_gc_likely_to_collect_more;
559 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000560 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000561 if (!it.node()->IsRetainer()) {
562 next_gc_likely_to_collect_more = true;
563 }
564 }
565 }
566 // Update the list of new space nodes.
567 int last = 0;
568 for (int i = 0; i < new_space_nodes_.length(); ++i) {
569 Node* node = new_space_nodes_[i];
570 ASSERT(node->is_in_new_space_list());
571 if (node->IsRetainer() && isolate_->heap()->InNewSpace(node->object())) {
572 new_space_nodes_[last++] = node;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 } else {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000574 node->set_in_new_space_list(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 }
576 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000577 new_space_nodes_.Rewind(last);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000578 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579}
580
581
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000582void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000583 for (NodeIterator it(this); !it.done(); it.Advance()) {
584 if (it.node()->IsStrongRetainer()) {
585 v->VisitPointer(it.node()->location());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586 }
587 }
588}
589
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000590
591void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000592 for (NodeIterator it(this); !it.done(); it.Advance()) {
593 if (it.node()->IsRetainer()) {
594 v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000595 }
596 }
597}
598
599
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000600void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000601 for (NodeIterator it(this); !it.done(); it.Advance()) {
602 if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) {
603 v->VisitEmbedderReference(it.node()->location(),
604 it.node()->wrapper_class_id());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000605 }
606 }
607}
608
609
ager@chromium.org60121232009-12-03 11:25:37 +0000610void GlobalHandles::RecordStats(HeapStats* stats) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000611 *stats->global_handle_count = 0;
612 *stats->weak_global_handle_count = 0;
613 *stats->pending_global_handle_count = 0;
614 *stats->near_death_global_handle_count = 0;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000615 *stats->free_global_handle_count = 0;
616 for (NodeIterator it(this); !it.done(); it.Advance()) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000617 *stats->global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000618 if (it.node()->state() == Node::WEAK) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 *stats->weak_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000620 } else if (it.node()->state() == Node::PENDING) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 *stats->pending_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000622 } else if (it.node()->state() == Node::NEAR_DEATH) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 *stats->near_death_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000624 } else if (it.node()->state() == Node::FREE) {
625 *stats->free_global_handle_count += 1;
ager@chromium.org60121232009-12-03 11:25:37 +0000626 }
627 }
628}
629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630#ifdef DEBUG
631
632void GlobalHandles::PrintStats() {
633 int total = 0;
634 int weak = 0;
635 int pending = 0;
636 int near_death = 0;
637 int destroyed = 0;
638
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000639 for (NodeIterator it(this); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 total++;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000641 if (it.node()->state() == Node::WEAK) weak++;
642 if (it.node()->state() == Node::PENDING) pending++;
643 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
644 if (it.node()->state() == Node::FREE) destroyed++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 }
646
647 PrintF("Global Handle Statistics:\n");
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000648 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 PrintF(" # weak = %d\n", weak);
650 PrintF(" # pending = %d\n", pending);
651 PrintF(" # near_death = %d\n", near_death);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000652 PrintF(" # free = %d\n", destroyed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 PrintF(" # total = %d\n", total);
654}
655
656void GlobalHandles::Print() {
657 PrintF("Global handles:\n");
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000658 for (NodeIterator it(this); !it.done(); it.Advance()) {
659 PrintF(" handle %p to %p%s\n",
660 reinterpret_cast<void*>(it.node()->location()),
661 reinterpret_cast<void*>(it.node()->object()),
662 it.node()->IsWeak() ? " (weak)" : "");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663 }
664}
665
666#endif
667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000669
670void GlobalHandles::AddObjectGroup(Object*** handles,
671 size_t length,
672 v8::RetainedObjectInfo* info) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000673#ifdef DEBUG
674 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000675 ASSERT(!Node::FromLocation(handles[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000676 }
677#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000678 if (length == 0) {
679 if (info != NULL) info->Dispose();
680 return;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000681 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000682 object_groups_.Add(ObjectGroup::New(handles, length, info));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000683}
684
685
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000686void GlobalHandles::AddImplicitReferences(HeapObject** parent,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000687 Object*** children,
688 size_t length) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000689#ifdef DEBUG
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000690 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000691 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000692 ASSERT(!Node::FromLocation(children[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000693 }
694#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000695 if (length == 0) return;
696 implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000697}
698
699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700void GlobalHandles::RemoveObjectGroups() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 for (int i = 0; i < object_groups_.length(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000702 object_groups_.at(i)->Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000704 object_groups_.Clear();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705}
706
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000707
708void GlobalHandles::RemoveImplicitRefGroups() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000710 implicit_ref_groups_.at(i)->Dispose();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 implicit_ref_groups_.Clear();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000713}
714
715
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000716void GlobalHandles::TearDown() {
717 // TODO(1428): invoke weak callbacks.
718}
719
720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721} } // namespace v8::internal