blob: b601e999002319e47694ffddd73ec7e5423e9bb1 [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() {
danno@chromium.orgca29dd82013-04-26 11:59:48 +000040 if (info != NULL) info->Dispose();
41 delete[] objects;
42}
43
44
45ImplicitRefGroup::~ImplicitRefGroup() {
46 delete[] children;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000047}
48
49
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000050class GlobalHandles::Node {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051 public:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000052 // State transition diagram:
53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
54 enum State {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000055 FREE = 0,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000056 NORMAL, // Normal global handle.
57 WEAK, // Flagged as weak but not yet finalized.
58 PENDING, // Has been recognized as only reachable by weak handles.
59 NEAR_DEATH // Callback has informed the handle is near death.
60 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000062 // Maps handle location (slot) to the containing node.
63 static Node* FromLocation(Object** location) {
64 ASSERT(OFFSET_OF(Node, object_) == 0);
65 return reinterpret_cast<Node*>(location);
66 }
67
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000068 Node() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000069 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000070 ASSERT(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
71 STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
72 Internals::kNodeStateMask);
73 STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
74 STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
75 STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
76 Internals::kNodeIsIndependentShift);
77 STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
78 Internals::kNodeIsPartiallyDependentShift);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000079 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000080
danno@chromium.orgc99cd482013-03-21 15:26:42 +000081#ifdef ENABLE_EXTRA_CHECKS
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000082 ~Node() {
83 // TODO(1428): if it's a weak handle we should have invoked its callback.
84 // Zap the values for eager trapping.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000085 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000086 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
87 index_ = 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000088 set_independent(false);
89 set_partially_dependent(false);
90 set_in_new_space_list(false);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000091 parameter_or_next_free_.next_free = NULL;
rossberg@chromium.org79e79022013-06-03 15:43:46 +000092 weak_reference_callback_ = NULL;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000093 }
94#endif
95
96 void Initialize(int index, Node** first_free) {
97 index_ = static_cast<uint8_t>(index);
98 ASSERT(static_cast<int>(index_) == index);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000099 set_state(FREE);
100 set_in_new_space_list(false);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000101 parameter_or_next_free_.next_free = *first_free;
102 *first_free = this;
103 }
104
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000105 void Acquire(Object* object) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000106 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107 object_ = object;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000108 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000109 set_independent(false);
110 set_partially_dependent(false);
111 set_state(NORMAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 parameter_or_next_free_.parameter = NULL;
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000113 weak_reference_callback_ = NULL;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000114 IncreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 }
116
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000117 void Release() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000118 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000119 set_state(FREE);
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000120#ifdef ENABLE_EXTRA_CHECKS
ulan@chromium.org750145a2013-03-07 15:14:13 +0000121 // Zap the values for eager trapping.
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000122 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000123 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
124 set_independent(false);
125 set_partially_dependent(false);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000126 weak_reference_callback_ = NULL;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000127#endif
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000128 DecreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129 }
130
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000131 // Object slot accessors.
132 Object* object() const { return object_; }
133 Object** location() { return &object_; }
134 Handle<Object> handle() { return Handle<Object>(location()); }
135
136 // Wrapper class ID accessors.
137 bool has_wrapper_class_id() const {
138 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
139 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000140
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000141 uint16_t wrapper_class_id() const { return class_id_; }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000142
143 // State and flag accessors.
144
145 State state() const {
146 return NodeState::decode(flags_);
147 }
148 void set_state(State state) {
149 flags_ = NodeState::update(flags_, state);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000150 }
151
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000152 bool is_independent() {
153 return IsIndependent::decode(flags_);
154 }
155 void set_independent(bool v) {
156 flags_ = IsIndependent::update(flags_, v);
157 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000158
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000159 bool is_partially_dependent() {
160 return IsPartiallyDependent::decode(flags_);
161 }
162 void set_partially_dependent(bool v) {
163 flags_ = IsPartiallyDependent::update(flags_, v);
164 }
165
166 bool is_in_new_space_list() {
167 return IsInNewSpaceList::decode(flags_);
168 }
169 void set_in_new_space_list(bool v) {
170 flags_ = IsInNewSpaceList::update(flags_, v);
171 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000172
173 bool IsNearDeath() const {
174 // Check for PENDING to ensure correct answer when processing callbacks.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000175 return state() == PENDING || state() == NEAR_DEATH;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000176 }
177
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000178 bool IsWeak() const { return state() == WEAK; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000179
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000180 bool IsRetainer() const { return state() != FREE; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000181
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000182 bool IsStrongRetainer() const { return state() == NORMAL; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000183
184 bool IsWeakRetainer() const {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000185 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000186 }
187
188 void MarkPending() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000189 ASSERT(state() == WEAK);
190 set_state(PENDING);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000191 }
192
193 // Independent flag accessors.
194 void MarkIndependent() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000195 ASSERT(state() != FREE);
196 set_independent(true);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000197 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000198
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000199 void MarkPartiallyDependent() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000200 ASSERT(state() != FREE);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000201 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000202 set_partially_dependent(true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000203 }
204 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000205 void clear_partially_dependent() { set_partially_dependent(false); }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000206
207 // Callback accessor.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000208 // TODO(svenpanne) Re-enable or nuke later.
209 // WeakReferenceCallback callback() { return callback_; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000210
211 // Callback parameter accessors.
212 void set_parameter(void* parameter) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000213 ASSERT(state() != FREE);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000214 parameter_or_next_free_.parameter = parameter;
215 }
216 void* parameter() const {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000217 ASSERT(state() != FREE);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000218 return parameter_or_next_free_.parameter;
219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220
221 // Accessors for next free node in the free list.
222 Node* next_free() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000223 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 return parameter_or_next_free_.next_free;
225 }
226 void set_next_free(Node* value) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000227 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228 parameter_or_next_free_.next_free = value;
229 }
230
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000231 void MakeWeak(void* parameter,
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000232 RevivableCallback weak_reference_callback) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000233 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000234 set_state(WEAK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 set_parameter(parameter);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000236 weak_reference_callback_ = weak_reference_callback;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 }
238
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000239 void ClearWeakness() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000240 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000241 set_state(NORMAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 set_parameter(NULL);
243 }
244
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000245 bool PostGarbageCollectionProcessing(Isolate* isolate) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000246 if (state() != Node::PENDING) return false;
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000247 if (weak_reference_callback_ == NULL) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000248 Release();
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000249 return false;
250 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251 void* par = parameter();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000252 set_state(NEAR_DEATH);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253 set_parameter(NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000254
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000255 Object** object = location();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000256 {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000257 // Check that we are not passing a finalized external string to
258 // the callback.
259 ASSERT(!object_->IsExternalAsciiString() ||
260 ExternalAsciiString::cast(object_)->resource() != NULL);
261 ASSERT(!object_->IsExternalTwoByteString() ||
262 ExternalTwoByteString::cast(object_)->resource() != NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000263 // Leaving V8.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000264 VMState<EXTERNAL> state(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000265 weak_reference_callback_(reinterpret_cast<v8::Isolate*>(isolate),
266 reinterpret_cast<Persistent<Value>*>(&object),
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000267 par);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000269 // Absence of explicit cleanup or revival of weak handle
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000270 // in most of the cases would lead to memory leak.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000271 ASSERT(state() != NEAR_DEATH);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000272 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 }
274
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000275 private:
276 inline NodeBlock* FindBlock();
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000277 inline GlobalHandles* GetGlobalHandles();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000278 inline void IncreaseBlockUses();
279 inline void DecreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000281 // Storage for object pointer.
282 // Placed first to avoid offset computation.
283 Object* object_;
284
285 // Next word stores class_id, index, state, and independent.
286 // Note: the most aligned fields should go first.
287
288 // Wrapper class ID.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000289 uint16_t class_id_;
290
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000291 // Index in the containing handle block.
292 uint8_t index_;
293
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000294 // This stores three flags (independent, partially_dependent and
295 // in_new_space_list) and a State.
296 class NodeState: public BitField<State, 0, 4> {};
297 class IsIndependent: public BitField<bool, 4, 1> {};
298 class IsPartiallyDependent: public BitField<bool, 5, 1> {};
299 class IsInNewSpaceList: public BitField<bool, 6, 1> {};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000301 uint8_t flags_;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000302
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000303 // Handle specific callback - might be a weak reference in disguise.
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000304 RevivableCallback weak_reference_callback_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000305
306 // Provided data for callback. In FREE state, this is used for
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307 // the free list link.
308 union {
309 void* parameter;
310 Node* next_free;
311 } parameter_or_next_free_;
312
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000313 DISALLOW_COPY_AND_ASSIGN(Node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314};
315
316
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000317class GlobalHandles::NodeBlock {
318 public:
319 static const int kSize = 256;
ager@chromium.org3811b432009-10-28 14:53:37 +0000320
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000321 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
322 : next_(next),
323 used_nodes_(0),
324 next_used_(NULL),
325 prev_used_(NULL),
326 global_handles_(global_handles) {}
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000327
328 void PutNodesOnFreeList(Node** first_free) {
329 for (int i = kSize - 1; i >= 0; --i) {
330 nodes_[i].Initialize(i, first_free);
331 }
332 }
333
334 Node* node_at(int index) {
335 ASSERT(0 <= index && index < kSize);
336 return &nodes_[index];
337 }
338
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000339 void IncreaseUses() {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000340 ASSERT(used_nodes_ < kSize);
341 if (used_nodes_++ == 0) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000342 NodeBlock* old_first = global_handles_->first_used_block_;
343 global_handles_->first_used_block_ = this;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000344 next_used_ = old_first;
345 prev_used_ = NULL;
346 if (old_first == NULL) return;
347 old_first->prev_used_ = this;
348 }
349 }
350
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000351 void DecreaseUses() {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000352 ASSERT(used_nodes_ > 0);
353 if (--used_nodes_ == 0) {
354 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
355 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000356 if (this == global_handles_->first_used_block_) {
357 global_handles_->first_used_block_ = next_used_;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000358 }
359 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000360 }
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000361
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000362 GlobalHandles* global_handles() { return global_handles_; }
363
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000364 // Next block in the list of all blocks.
365 NodeBlock* next() const { return next_; }
ager@chromium.org3811b432009-10-28 14:53:37 +0000366
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000367 // Next/previous block in the list of blocks with used nodes.
368 NodeBlock* next_used() const { return next_used_; }
369 NodeBlock* prev_used() const { return prev_used_; }
ager@chromium.org3811b432009-10-28 14:53:37 +0000370
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000371 private:
372 Node nodes_[kSize];
373 NodeBlock* const next_;
374 int used_nodes_;
375 NodeBlock* next_used_;
376 NodeBlock* prev_used_;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000377 GlobalHandles* global_handles_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000378};
ager@chromium.org3811b432009-10-28 14:53:37 +0000379
ager@chromium.org3811b432009-10-28 14:53:37 +0000380
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000381GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
382 return FindBlock()->global_handles();
383}
384
385
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000386GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
387 intptr_t ptr = reinterpret_cast<intptr_t>(this);
388 ptr = ptr - index_ * sizeof(Node);
389 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
390 ASSERT(block->node_at(index_) == this);
391 return block;
392}
ager@chromium.org3811b432009-10-28 14:53:37 +0000393
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000394
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000395void GlobalHandles::Node::IncreaseBlockUses() {
396 NodeBlock* node_block = FindBlock();
397 node_block->IncreaseUses();
398 GlobalHandles* global_handles = node_block->global_handles();
399 global_handles->isolate()->counters()->global_handles()->Increment();
400 global_handles->number_of_global_handles_++;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000401}
402
403
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000404void GlobalHandles::Node::DecreaseBlockUses() {
405 NodeBlock* node_block = FindBlock();
406 GlobalHandles* global_handles = node_block->global_handles();
407 parameter_or_next_free_.next_free = global_handles->first_free_;
408 global_handles->first_free_ = this;
409 node_block->DecreaseUses();
410 global_handles->isolate()->counters()->global_handles()->Decrement();
411 global_handles->number_of_global_handles_--;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000412}
413
414
415class GlobalHandles::NodeIterator {
416 public:
417 explicit NodeIterator(GlobalHandles* global_handles)
418 : block_(global_handles->first_used_block_),
419 index_(0) {}
420
421 bool done() const { return block_ == NULL; }
422
423 Node* node() const {
424 ASSERT(!done());
425 return block_->node_at(index_);
426 }
427
428 void Advance() {
429 ASSERT(!done());
430 if (++index_ < NodeBlock::kSize) return;
431 index_ = 0;
432 block_ = block_->next_used();
433 }
434
435 private:
436 NodeBlock* block_;
437 int index_;
438
439 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
ager@chromium.org3811b432009-10-28 14:53:37 +0000440};
441
442
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000443GlobalHandles::GlobalHandles(Isolate* isolate)
444 : isolate_(isolate),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000445 number_of_global_handles_(0),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000446 first_block_(NULL),
447 first_used_block_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 first_free_(NULL),
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000449 post_gc_processing_count_(0),
450 object_group_connections_(kObjectGroupConnectionsCapacity) {}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451
452
453GlobalHandles::~GlobalHandles() {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000454 NodeBlock* block = first_block_;
455 while (block != NULL) {
456 NodeBlock* tmp = block->next();
457 delete block;
458 block = tmp;
459 }
460 first_block_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461}
ager@chromium.org3811b432009-10-28 14:53:37 +0000462
463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464Handle<Object> GlobalHandles::Create(Object* value) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000465 if (first_free_ == NULL) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000466 first_block_ = new NodeBlock(this, first_block_);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000467 first_block_->PutNodesOnFreeList(&first_free_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000469 ASSERT(first_free_ != NULL);
470 // Take the first node in the free list.
471 Node* result = first_free_;
472 first_free_ = result->next_free();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000473 result->Acquire(value);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000474 if (isolate_->heap()->InNewSpace(value) &&
475 !result->is_in_new_space_list()) {
476 new_space_nodes_.Add(result);
477 result->set_in_new_space_list(true);
478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 return result->handle();
480}
481
482
483void GlobalHandles::Destroy(Object** location) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000484 if (location != NULL) Node::FromLocation(location)->Release();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485}
486
487
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000488void GlobalHandles::MakeWeak(Object** location,
489 void* parameter,
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000490 RevivableCallback weak_reference_callback) {
491 ASSERT(weak_reference_callback != NULL);
492 Node::FromLocation(location)->MakeWeak(parameter, weak_reference_callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
496void GlobalHandles::ClearWeakness(Object** location) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000497 Node::FromLocation(location)->ClearWeakness();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498}
499
500
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000501void GlobalHandles::MarkIndependent(Object** location) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000502 Node::FromLocation(location)->MarkIndependent();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000503}
504
505
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000506void GlobalHandles::MarkPartiallyDependent(Object** location) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000507 Node::FromLocation(location)->MarkPartiallyDependent();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000508}
509
510
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000511bool GlobalHandles::IsIndependent(Object** location) {
512 return Node::FromLocation(location)->is_independent();
513}
514
515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516bool GlobalHandles::IsNearDeath(Object** location) {
517 return Node::FromLocation(location)->IsNearDeath();
518}
519
520
521bool GlobalHandles::IsWeak(Object** location) {
522 return Node::FromLocation(location)->IsWeak();
523}
524
525
526void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000527 for (NodeIterator it(this); !it.done(); it.Advance()) {
528 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000529 }
530}
531
532
ager@chromium.org9085a012009-05-11 19:22:57 +0000533void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000534 for (NodeIterator it(this); !it.done(); it.Advance()) {
535 if (it.node()->IsWeak() && f(it.node()->location())) {
536 it.node()->MarkPending();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 }
538 }
539}
540
541
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000542void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
543 for (int i = 0; i < new_space_nodes_.length(); ++i) {
544 Node* node = new_space_nodes_[i];
545 if (node->IsStrongRetainer() ||
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000546 (node->IsWeakRetainer() && !node->is_independent() &&
547 !node->is_partially_dependent())) {
548 v->VisitPointer(node->location());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000549 }
550 }
551}
552
553
554void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
555 WeakSlotCallbackWithHeap f) {
556 for (int i = 0; i < new_space_nodes_.length(); ++i) {
557 Node* node = new_space_nodes_[i];
558 ASSERT(node->is_in_new_space_list());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000559 if ((node->is_independent() || node->is_partially_dependent()) &&
560 node->IsWeak() && f(isolate_->heap(), node->location())) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000561 node->MarkPending();
562 }
563 }
564}
565
566
567void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
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());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000571 if ((node->is_independent() || node->is_partially_dependent()) &&
572 node->IsWeakRetainer()) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000573 v->VisitPointer(node->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000574 }
575 }
576}
577
578
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000579bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
580 WeakSlotCallbackWithHeap can_skip) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000581 ComputeObjectGroupsAndImplicitReferences();
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000582 int last = 0;
583 bool any_group_was_visited = false;
584 for (int i = 0; i < object_groups_.length(); i++) {
585 ObjectGroup* entry = object_groups_.at(i);
586 ASSERT(entry != NULL);
587
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000588 Object*** objects = entry->objects;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000589 bool group_should_be_visited = false;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000590 for (size_t j = 0; j < entry->length; j++) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000591 Object* object = *objects[j];
592 if (object->IsHeapObject()) {
593 if (!can_skip(isolate_->heap(), &object)) {
594 group_should_be_visited = true;
595 break;
596 }
597 }
598 }
599
600 if (!group_should_be_visited) {
601 object_groups_[last++] = entry;
602 continue;
603 }
604
605 // An object in the group requires visiting, so iterate over all
606 // objects in the group.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000607 for (size_t j = 0; j < entry->length; ++j) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000608 Object* object = *objects[j];
609 if (object->IsHeapObject()) {
610 v->VisitPointer(&object);
611 any_group_was_visited = true;
612 }
613 }
614
615 // Once the entire group has been iterated over, set the object
616 // group to NULL so it won't be processed again.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000617 delete entry;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000618 object_groups_.at(i) = NULL;
619 }
620 object_groups_.Rewind(last);
621 return any_group_was_visited;
622}
623
624
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000625bool GlobalHandles::PostGarbageCollectionProcessing(
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000626 GarbageCollector collector, GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 // Process weak global handle callbacks. This must be done after the
628 // GC is completely done, because the callbacks may invoke arbitrary
629 // API functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
631 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000632 bool next_gc_likely_to_collect_more = false;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000633 if (collector == SCAVENGER) {
634 for (int i = 0; i < new_space_nodes_.length(); ++i) {
635 Node* node = new_space_nodes_[i];
636 ASSERT(node->is_in_new_space_list());
637 // Skip dependent handles. Their weak callbacks might expect to be
638 // called between two global garbage collection callbacks which
639 // are not called for minor collections.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000640 if (!node->is_independent() && !node->is_partially_dependent()) {
641 continue;
642 }
643 node->clear_partially_dependent();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000644 if (node->PostGarbageCollectionProcessing(isolate_)) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000645 if (initial_post_gc_processing_count != post_gc_processing_count_) {
646 // Weak callback triggered another GC and another round of
647 // PostGarbageCollection processing. The current node might
648 // have been deleted in that round, so we need to bail out (or
649 // restart the processing).
650 return next_gc_likely_to_collect_more;
651 }
652 }
653 if (!node->IsRetainer()) {
654 next_gc_likely_to_collect_more = true;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000655 }
656 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000657 } else {
658 for (NodeIterator it(this); !it.done(); it.Advance()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000659 it.node()->clear_partially_dependent();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000660 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000661 if (initial_post_gc_processing_count != post_gc_processing_count_) {
662 // See the comment above.
663 return next_gc_likely_to_collect_more;
664 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000665 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000666 if (!it.node()->IsRetainer()) {
667 next_gc_likely_to_collect_more = true;
668 }
669 }
670 }
671 // Update the list of new space nodes.
672 int last = 0;
673 for (int i = 0; i < new_space_nodes_.length(); ++i) {
674 Node* node = new_space_nodes_[i];
675 ASSERT(node->is_in_new_space_list());
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000676 if (node->IsRetainer()) {
677 if (isolate_->heap()->InNewSpace(node->object())) {
678 new_space_nodes_[last++] = node;
679 tracer->increment_nodes_copied_in_new_space();
680 } else {
681 node->set_in_new_space_list(false);
682 tracer->increment_nodes_promoted();
683 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684 } else {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000685 node->set_in_new_space_list(false);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000686 tracer->increment_nodes_died_in_new_space();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687 }
688 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000689 new_space_nodes_.Rewind(last);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000690 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691}
692
693
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000694void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000695 for (NodeIterator it(this); !it.done(); it.Advance()) {
696 if (it.node()->IsStrongRetainer()) {
697 v->VisitPointer(it.node()->location());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 }
699 }
700}
701
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000702
703void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000704 for (NodeIterator it(this); !it.done(); it.Advance()) {
705 if (it.node()->IsRetainer()) {
706 v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000707 }
708 }
709}
710
711
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000712void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000713 for (NodeIterator it(this); !it.done(); it.Advance()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000714 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000715 v->VisitEmbedderReference(it.node()->location(),
716 it.node()->wrapper_class_id());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000717 }
718 }
719}
720
721
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000722void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
723 for (int i = 0; i < new_space_nodes_.length(); ++i) {
724 Node* node = new_space_nodes_[i];
725 if (node->IsRetainer() && node->has_wrapper_class_id()) {
726 v->VisitEmbedderReference(node->location(),
727 node->wrapper_class_id());
728 }
729 }
730}
731
732
yangguo@chromium.org28381b42013-01-21 14:39:38 +0000733int GlobalHandles::NumberOfWeakHandles() {
734 int count = 0;
735 for (NodeIterator it(this); !it.done(); it.Advance()) {
736 if (it.node()->IsWeakRetainer()) {
737 count++;
738 }
739 }
740 return count;
741}
742
743
744int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
745 int count = 0;
746 for (NodeIterator it(this); !it.done(); it.Advance()) {
747 if (it.node()->IsWeakRetainer() &&
748 it.node()->object()->IsJSGlobalObject()) {
749 count++;
750 }
751 }
752 return count;
753}
754
755
ager@chromium.org60121232009-12-03 11:25:37 +0000756void GlobalHandles::RecordStats(HeapStats* stats) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000757 *stats->global_handle_count = 0;
758 *stats->weak_global_handle_count = 0;
759 *stats->pending_global_handle_count = 0;
760 *stats->near_death_global_handle_count = 0;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000761 *stats->free_global_handle_count = 0;
762 for (NodeIterator it(this); !it.done(); it.Advance()) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000763 *stats->global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000764 if (it.node()->state() == Node::WEAK) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000765 *stats->weak_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000766 } else if (it.node()->state() == Node::PENDING) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000767 *stats->pending_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000768 } else if (it.node()->state() == Node::NEAR_DEATH) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000769 *stats->near_death_global_handle_count += 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000770 } else if (it.node()->state() == Node::FREE) {
771 *stats->free_global_handle_count += 1;
ager@chromium.org60121232009-12-03 11:25:37 +0000772 }
773 }
774}
775
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776#ifdef DEBUG
777
778void GlobalHandles::PrintStats() {
779 int total = 0;
780 int weak = 0;
781 int pending = 0;
782 int near_death = 0;
783 int destroyed = 0;
784
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000785 for (NodeIterator it(this); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000786 total++;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000787 if (it.node()->state() == Node::WEAK) weak++;
788 if (it.node()->state() == Node::PENDING) pending++;
789 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
790 if (it.node()->state() == Node::FREE) destroyed++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 }
792
793 PrintF("Global Handle Statistics:\n");
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000794 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795 PrintF(" # weak = %d\n", weak);
796 PrintF(" # pending = %d\n", pending);
797 PrintF(" # near_death = %d\n", near_death);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000798 PrintF(" # free = %d\n", destroyed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 PrintF(" # total = %d\n", total);
800}
801
802void GlobalHandles::Print() {
803 PrintF("Global handles:\n");
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000804 for (NodeIterator it(this); !it.done(); it.Advance()) {
805 PrintF(" handle %p to %p%s\n",
806 reinterpret_cast<void*>(it.node()->location()),
807 reinterpret_cast<void*>(it.node()->object()),
808 it.node()->IsWeak() ? " (weak)" : "");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809 }
810}
811
812#endif
813
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000815
816void GlobalHandles::AddObjectGroup(Object*** handles,
817 size_t length,
818 v8::RetainedObjectInfo* info) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000819#ifdef DEBUG
820 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000821 ASSERT(!Node::FromLocation(handles[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000822 }
823#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000824 if (length == 0) {
825 if (info != NULL) info->Dispose();
826 return;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000827 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000828 ObjectGroup* group = new ObjectGroup(length);
829 for (size_t i = 0; i < length; ++i)
830 group->objects[i] = handles[i];
831 group->info = info;
832 object_groups_.Add(group);
833}
834
835
836void GlobalHandles::SetObjectGroupId(Object** handle,
837 UniqueId id) {
838 object_group_connections_.Add(ObjectGroupConnection(id, handle));
839}
840
841
842void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
843 RetainedObjectInfo* info) {
844 retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000845}
846
847
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000848void GlobalHandles::AddImplicitReferences(HeapObject** parent,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000849 Object*** children,
850 size_t length) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000851#ifdef DEBUG
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000852 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000853 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000854 ASSERT(!Node::FromLocation(children[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000855 }
856#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000857 if (length == 0) return;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000858 ImplicitRefGroup* group = new ImplicitRefGroup(parent, length);
859 for (size_t i = 0; i < length; ++i)
860 group->children[i] = children[i];
861 implicit_ref_groups_.Add(group);
862}
863
864
865void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
866 ASSERT(!Node::FromLocation(child)->is_independent());
867 implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
868}
869
870
871void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
872 ASSERT(!Node::FromLocation(child)->is_independent());
873 ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
874 group->children[0] = child;
875 implicit_ref_groups_.Add(group);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000876}
877
878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879void GlobalHandles::RemoveObjectGroups() {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000880 for (int i = 0; i < object_groups_.length(); i++)
881 delete object_groups_.at(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000882 object_groups_.Clear();
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000883 for (int i = 0; i < retainer_infos_.length(); ++i)
884 retainer_infos_[i].info->Dispose();
885 retainer_infos_.Clear();
886 object_group_connections_.Clear();
887 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888}
889
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000890
891void GlobalHandles::RemoveImplicitRefGroups() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000892 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000893 delete implicit_ref_groups_.at(i);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000894 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 implicit_ref_groups_.Clear();
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000896 implicit_ref_connections_.Clear();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000897}
898
899
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000900void GlobalHandles::TearDown() {
901 // TODO(1428): invoke weak callbacks.
902}
903
904
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000905void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
906 if (object_group_connections_.length() == 0) {
907 for (int i = 0; i < retainer_infos_.length(); ++i)
908 retainer_infos_[i].info->Dispose();
909 retainer_infos_.Clear();
910 implicit_ref_connections_.Clear();
911 return;
912 }
913
914 object_group_connections_.Sort();
915 retainer_infos_.Sort();
916 implicit_ref_connections_.Sort();
917
918 int info_index = 0; // For iterating retainer_infos_.
919 UniqueId current_group_id(0);
920 int current_group_start = 0;
921
922 int current_implicit_refs_start = 0;
923 int current_implicit_refs_end = 0;
924 for (int i = 0; i <= object_group_connections_.length(); ++i) {
925 if (i == 0)
926 current_group_id = object_group_connections_[i].id;
927 if (i == object_group_connections_.length() ||
928 current_group_id != object_group_connections_[i].id) {
929 // Group detected: objects in indices [current_group_start, i[.
930
931 // Find out which implicit references are related to this group. (We want
932 // to ignore object groups which only have 1 object, but that object is
933 // needed as a representative object for the implicit refrerence group.)
934 while (current_implicit_refs_start < implicit_ref_connections_.length() &&
935 implicit_ref_connections_[current_implicit_refs_start].id <
936 current_group_id)
937 ++current_implicit_refs_start;
938 current_implicit_refs_end = current_implicit_refs_start;
939 while (current_implicit_refs_end < implicit_ref_connections_.length() &&
940 implicit_ref_connections_[current_implicit_refs_end].id ==
941 current_group_id)
942 ++current_implicit_refs_end;
943
944 if (current_implicit_refs_end > current_implicit_refs_start) {
945 // Find a representative object for the implicit references.
946 HeapObject** representative = NULL;
947 for (int j = current_group_start; j < i; ++j) {
948 Object** object = object_group_connections_[j].object;
949 if ((*object)->IsHeapObject()) {
950 representative = reinterpret_cast<HeapObject**>(object);
951 break;
952 }
953 }
954 if (representative) {
955 ImplicitRefGroup* group = new ImplicitRefGroup(
956 representative,
957 current_implicit_refs_end - current_implicit_refs_start);
958 for (int j = current_implicit_refs_start;
959 j < current_implicit_refs_end;
960 ++j) {
961 group->children[j - current_implicit_refs_start] =
962 implicit_ref_connections_[j].object;
963 }
964 implicit_ref_groups_.Add(group);
965 }
966 current_implicit_refs_start = current_implicit_refs_end;
967 }
968
969 // Find a RetainedObjectInfo for the group.
970 RetainedObjectInfo* info = NULL;
971 while (info_index < retainer_infos_.length() &&
972 retainer_infos_[info_index].id < current_group_id) {
973 retainer_infos_[info_index].info->Dispose();
974 ++info_index;
975 }
976 if (info_index < retainer_infos_.length() &&
977 retainer_infos_[info_index].id == current_group_id) {
978 // This object group has an associated ObjectGroupRetainerInfo.
979 info = retainer_infos_[info_index].info;
980 ++info_index;
981 }
982
983 // Ignore groups which only contain one object.
984 if (i > current_group_start + 1) {
985 ObjectGroup* group = new ObjectGroup(i - current_group_start);
986 for (int j = current_group_start; j < i; ++j) {
987 group->objects[j - current_group_start] =
988 object_group_connections_[j].object;
989 }
990 group->info = info;
991 object_groups_.Add(group);
992 } else if (info) {
993 info->Dispose();
994 }
995
996 if (i < object_group_connections_.length()) {
997 current_group_id = object_group_connections_[i].id;
998 current_group_start = i;
999 }
1000 }
1001 }
1002 object_group_connections_.Clear();
1003 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1004 retainer_infos_.Clear();
1005 implicit_ref_connections_.Clear();
1006}
1007
1008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009} } // namespace v8::internal