blob: 2ebe1c0088fb7d5b865460feb50549c0a0d18157 [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.
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +000059 NEAR_DEATH // Callback has informed the handle is near death.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000060 };
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);
danno@chromium.orgc16e8282013-08-12 16:17:40 +000074 STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000075 STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
76 STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
77 Internals::kNodeIsIndependentShift);
78 STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
79 Internals::kNodeIsPartiallyDependentShift);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000080 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000081
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +000082#ifdef ENABLE_HANDLE_ZAPPING
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000083 ~Node() {
84 // TODO(1428): if it's a weak handle we should have invoked its callback.
85 // Zap the values for eager trapping.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000086 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000087 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
88 index_ = 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000089 set_independent(false);
90 set_partially_dependent(false);
91 set_in_new_space_list(false);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000092 parameter_or_next_free_.next_free = NULL;
dslomov@chromium.org639bac02013-09-09 11:58:54 +000093 weak_callback_ = NULL;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000094 }
95#endif
96
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +000097 void Initialize(int index, Node** first_free) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000098 index_ = static_cast<uint8_t>(index);
99 ASSERT(static_cast<int>(index_) == index);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000100 set_state(FREE);
101 set_in_new_space_list(false);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000102 parameter_or_next_free_.next_free = *first_free;
103 *first_free = this;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000104 }
105
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000106 void Acquire(Object* object) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000107 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 object_ = object;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000109 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000110 set_independent(false);
111 set_partially_dependent(false);
112 set_state(NORMAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113 parameter_or_next_free_.parameter = NULL;
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000114 weak_callback_ = NULL;
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000115 IncreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 }
117
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000118 void Release() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000119 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000120 set_state(FREE);
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);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000126 weak_callback_ = NULL;
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000127 DecreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 }
129
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000130 // Object slot accessors.
131 Object* object() const { return object_; }
132 Object** location() { return &object_; }
133 Handle<Object> handle() { return Handle<Object>(location()); }
134
135 // Wrapper class ID accessors.
136 bool has_wrapper_class_id() const {
137 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
138 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000139
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000140 uint16_t wrapper_class_id() const { return class_id_; }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000141
142 // State and flag accessors.
143
144 State state() const {
145 return NodeState::decode(flags_);
146 }
147 void set_state(State state) {
148 flags_ = NodeState::update(flags_, state);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000149 }
150
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000151 bool is_independent() {
152 return IsIndependent::decode(flags_);
153 }
154 void set_independent(bool v) {
155 flags_ = IsIndependent::update(flags_, v);
156 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000157
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000158 bool is_partially_dependent() {
159 return IsPartiallyDependent::decode(flags_);
160 }
161 void set_partially_dependent(bool v) {
162 flags_ = IsPartiallyDependent::update(flags_, v);
163 }
164
165 bool is_in_new_space_list() {
166 return IsInNewSpaceList::decode(flags_);
167 }
168 void set_in_new_space_list(bool v) {
169 flags_ = IsInNewSpaceList::update(flags_, v);
170 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000171
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000172 bool is_revivable_callback() {
173 return IsRevivableCallback::decode(flags_);
174 }
175 void set_revivable_callback(bool v) {
176 flags_ = IsRevivableCallback::update(flags_, v);
177 }
178
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000179 bool IsNearDeath() const {
180 // Check for PENDING to ensure correct answer when processing callbacks.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000181 return state() == PENDING || state() == NEAR_DEATH;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000182 }
183
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000184 bool IsWeak() const { return state() == WEAK; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000185
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000186 bool IsRetainer() const { return state() != FREE; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000187
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000188 bool IsStrongRetainer() const { return state() == NORMAL; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000189
190 bool IsWeakRetainer() const {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000191 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000192 }
193
194 void MarkPending() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000195 ASSERT(state() == WEAK);
196 set_state(PENDING);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000197 }
198
199 // Independent flag accessors.
200 void MarkIndependent() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000201 ASSERT(state() != FREE);
202 set_independent(true);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000203 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000204
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000205 void MarkPartiallyDependent() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000206 ASSERT(state() != FREE);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000207 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000208 set_partially_dependent(true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000209 }
210 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000211 void clear_partially_dependent() { set_partially_dependent(false); }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000212
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000213 // Callback accessor.
214 // TODO(svenpanne) Re-enable or nuke later.
215 // WeakReferenceCallback callback() { return callback_; }
216
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000217 // Callback parameter accessors.
218 void set_parameter(void* parameter) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000219 ASSERT(state() != FREE);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000220 parameter_or_next_free_.parameter = parameter;
221 }
222 void* parameter() const {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000223 ASSERT(state() != FREE);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000224 return parameter_or_next_free_.parameter;
225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226
227 // Accessors for next free node in the free list.
228 Node* next_free() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000229 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 return parameter_or_next_free_.next_free;
231 }
232 void set_next_free(Node* value) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000233 ASSERT(state() == FREE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 parameter_or_next_free_.next_free = value;
235 }
236
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000237 void MakeWeak(void* parameter,
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000238 WeakCallback weak_callback,
239 RevivableCallback revivable_callback) {
240 ASSERT((weak_callback == NULL) != (revivable_callback == NULL));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000241 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000242 set_state(WEAK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243 set_parameter(parameter);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000244 if (weak_callback != NULL) {
245 weak_callback_ = weak_callback;
246 set_revivable_callback(false);
247 } else {
248 weak_callback_ =
249 reinterpret_cast<WeakCallback>(revivable_callback);
250 set_revivable_callback(true);
251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 }
253
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000254 void ClearWeakness() {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000255 ASSERT(state() != FREE);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000256 set_state(NORMAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 set_parameter(NULL);
258 }
259
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000260 bool PostGarbageCollectionProcessing(Isolate* isolate) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000261 if (state() != Node::PENDING) return false;
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000262 if (weak_callback_ == NULL) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000263 Release();
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000264 return false;
265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266 void* par = parameter();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000267 set_state(NEAR_DEATH);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 set_parameter(NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000269
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000270 Object** object = location();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000271 {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000272 // Check that we are not passing a finalized external string to
273 // the callback.
274 ASSERT(!object_->IsExternalAsciiString() ||
275 ExternalAsciiString::cast(object_)->resource() != NULL);
276 ASSERT(!object_->IsExternalTwoByteString() ||
277 ExternalTwoByteString::cast(object_)->resource() != NULL);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000278 // Leaving V8.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000279 VMState<EXTERNAL> state(isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000280 HandleScope handle_scope(isolate);
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000281 if (is_revivable_callback()) {
282 RevivableCallback revivable =
283 reinterpret_cast<RevivableCallback>(weak_callback_);
284 revivable(reinterpret_cast<v8::Isolate*>(isolate),
285 reinterpret_cast<Persistent<Value>*>(&object),
286 par);
287 } else {
288 Handle<Object> handle(*object, isolate);
289 v8::WeakCallbackData<v8::Value, void> data(
290 reinterpret_cast<v8::Isolate*>(isolate),
291 v8::Utils::ToLocal(handle),
292 par);
293 weak_callback_(data);
294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000296 // Absence of explicit cleanup or revival of weak handle
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000297 // in most of the cases would lead to memory leak.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000298 ASSERT(state() != NEAR_DEATH);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000299 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 }
301
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000302 inline GlobalHandles* GetGlobalHandles();
303
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000304 private:
305 inline NodeBlock* FindBlock();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000306 inline void IncreaseBlockUses();
307 inline void DecreaseBlockUses();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000309 // Storage for object pointer.
310 // Placed first to avoid offset computation.
311 Object* object_;
312
313 // Next word stores class_id, index, state, and independent.
314 // Note: the most aligned fields should go first.
315
316 // Wrapper class ID.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000317 uint16_t class_id_;
318
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000319 // Index in the containing handle block.
320 uint8_t index_;
321
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000322 // This stores three flags (independent, partially_dependent and
323 // in_new_space_list) and a State.
324 class NodeState: public BitField<State, 0, 4> {};
325 class IsIndependent: public BitField<bool, 4, 1> {};
326 class IsPartiallyDependent: public BitField<bool, 5, 1> {};
327 class IsInNewSpaceList: public BitField<bool, 6, 1> {};
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000328 class IsRevivableCallback: public BitField<bool, 7, 1> {};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000330 uint8_t flags_;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000331
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +0000332 // Handle specific callback - might be a weak reference in disguise.
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000333 WeakCallback weak_callback_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000334
335 // Provided data for callback. In FREE state, this is used for
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 // the free list link.
337 union {
338 void* parameter;
339 Node* next_free;
340 } parameter_or_next_free_;
341
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000342 DISALLOW_COPY_AND_ASSIGN(Node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343};
344
345
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000346class GlobalHandles::NodeBlock {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000347 public:
348 static const int kSize = 256;
ager@chromium.org3811b432009-10-28 14:53:37 +0000349
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000350 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
351 : next_(next),
352 used_nodes_(0),
353 next_used_(NULL),
354 prev_used_(NULL),
355 global_handles_(global_handles) {}
356
357 void PutNodesOnFreeList(Node** first_free) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000358 for (int i = kSize - 1; i >= 0; --i) {
359 nodes_[i].Initialize(i, first_free);
360 }
361 }
362
363 Node* node_at(int index) {
364 ASSERT(0 <= index && index < kSize);
365 return &nodes_[index];
366 }
367
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000368 void IncreaseUses() {
369 ASSERT(used_nodes_ < kSize);
370 if (used_nodes_++ == 0) {
371 NodeBlock* old_first = global_handles_->first_used_block_;
372 global_handles_->first_used_block_ = this;
373 next_used_ = old_first;
374 prev_used_ = NULL;
375 if (old_first == NULL) return;
376 old_first->prev_used_ = this;
danno@chromium.org59400602013-08-13 17:09:37 +0000377 }
danno@chromium.org59400602013-08-13 17:09:37 +0000378 }
danno@chromium.org59400602013-08-13 17:09:37 +0000379
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000380 void DecreaseUses() {
381 ASSERT(used_nodes_ > 0);
382 if (--used_nodes_ == 0) {
383 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
384 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
385 if (this == global_handles_->first_used_block_) {
386 global_handles_->first_used_block_ = next_used_;
danno@chromium.org59400602013-08-13 17:09:37 +0000387 }
388 }
389 }
danno@chromium.org59400602013-08-13 17:09:37 +0000390
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000391 GlobalHandles* global_handles() { return global_handles_; }
danno@chromium.org59400602013-08-13 17:09:37 +0000392
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000393 // Next block in the list of all blocks.
394 NodeBlock* next() const { return next_; }
395
396 // Next/previous block in the list of blocks with used nodes.
397 NodeBlock* next_used() const { return next_used_; }
398 NodeBlock* prev_used() const { return prev_used_; }
399
400 private:
401 Node nodes_[kSize];
402 NodeBlock* const next_;
403 int used_nodes_;
404 NodeBlock* next_used_;
405 NodeBlock* prev_used_;
406 GlobalHandles* global_handles_;
407};
danno@chromium.org59400602013-08-13 17:09:37 +0000408
409
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000410GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
411 return FindBlock()->global_handles();
412}
413
414
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000415GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000416 intptr_t ptr = reinterpret_cast<intptr_t>(this);
417 ptr = ptr - index_ * sizeof(Node);
418 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
419 ASSERT(block->node_at(index_) == this);
420 return block;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000421}
ager@chromium.org3811b432009-10-28 14:53:37 +0000422
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000423
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000424void GlobalHandles::Node::IncreaseBlockUses() {
425 NodeBlock* node_block = FindBlock();
426 node_block->IncreaseUses();
427 GlobalHandles* global_handles = node_block->global_handles();
428 global_handles->isolate()->counters()->global_handles()->Increment();
429 global_handles->number_of_global_handles_++;
430}
431
432
433void GlobalHandles::Node::DecreaseBlockUses() {
434 NodeBlock* node_block = FindBlock();
435 GlobalHandles* global_handles = node_block->global_handles();
436 parameter_or_next_free_.next_free = global_handles->first_free_;
437 global_handles->first_free_ = this;
438 node_block->DecreaseUses();
439 global_handles->isolate()->counters()->global_handles()->Decrement();
440 global_handles->number_of_global_handles_--;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000441}
442
443
444class GlobalHandles::NodeIterator {
445 public:
446 explicit NodeIterator(GlobalHandles* global_handles)
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000447 : block_(global_handles->first_used_block_),
448 index_(0) {}
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000449
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000450 bool done() const { return block_ == NULL; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000451
452 Node* node() const {
453 ASSERT(!done());
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000454 return block_->node_at(index_);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000455 }
456
457 void Advance() {
458 ASSERT(!done());
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000459 if (++index_ < NodeBlock::kSize) return;
460 index_ = 0;
461 block_ = block_->next_used();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000462 }
463
464 private:
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000465 NodeBlock* block_;
466 int index_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000467
468 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
ager@chromium.org3811b432009-10-28 14:53:37 +0000469};
470
471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000472GlobalHandles::GlobalHandles(Isolate* isolate)
473 : isolate_(isolate),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000474 number_of_global_handles_(0),
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000475 first_block_(NULL),
476 first_used_block_(NULL),
477 first_free_(NULL),
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000478 post_gc_processing_count_(0),
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000479 object_group_connections_(kObjectGroupConnectionsCapacity) {}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480
481
482GlobalHandles::~GlobalHandles() {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000483 NodeBlock* block = first_block_;
484 while (block != NULL) {
485 NodeBlock* tmp = block->next();
486 delete block;
487 block = tmp;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000488 }
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000489 first_block_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490}
ager@chromium.org3811b432009-10-28 14:53:37 +0000491
492
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493Handle<Object> GlobalHandles::Create(Object* value) {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000494 if (first_free_ == NULL) {
495 first_block_ = new NodeBlock(this, first_block_);
496 first_block_->PutNodesOnFreeList(&first_free_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 }
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000498 ASSERT(first_free_ != NULL);
499 // Take the first node in the free list.
500 Node* result = first_free_;
501 first_free_ = result->next_free();
502 result->Acquire(value);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000503 if (isolate_->heap()->InNewSpace(value) &&
504 !result->is_in_new_space_list()) {
505 new_space_nodes_.Add(result);
506 result->set_in_new_space_list(true);
507 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 return result->handle();
509}
510
511
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000512Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
513 ASSERT(location != NULL);
514 return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
515}
516
517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518void GlobalHandles::Destroy(Object** location) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000519 if (location != NULL) Node::FromLocation(location)->Release();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520}
521
522
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000523void GlobalHandles::MakeWeak(Object** location,
524 void* parameter,
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000525 WeakCallback weak_callback,
526 RevivableCallback revivable_callback) {
527 Node::FromLocation(location)->MakeWeak(
528 parameter, weak_callback, revivable_callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529}
530
531
532void GlobalHandles::ClearWeakness(Object** location) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000533 Node::FromLocation(location)->ClearWeakness();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534}
535
536
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000537void GlobalHandles::MarkIndependent(Object** location) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000538 Node::FromLocation(location)->MarkIndependent();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000539}
540
541
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000542void GlobalHandles::MarkPartiallyDependent(Object** location) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000543 Node::FromLocation(location)->MarkPartiallyDependent();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000544}
545
546
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000547bool GlobalHandles::IsIndependent(Object** location) {
548 return Node::FromLocation(location)->is_independent();
549}
550
551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552bool GlobalHandles::IsNearDeath(Object** location) {
553 return Node::FromLocation(location)->IsNearDeath();
554}
555
556
557bool GlobalHandles::IsWeak(Object** location) {
558 return Node::FromLocation(location)->IsWeak();
559}
560
561
562void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000563 for (NodeIterator it(this); !it.done(); it.Advance()) {
564 if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000565 }
566}
567
568
ager@chromium.org9085a012009-05-11 19:22:57 +0000569void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000570 for (NodeIterator it(this); !it.done(); it.Advance()) {
571 if (it.node()->IsWeak() && f(it.node()->location())) {
572 it.node()->MarkPending();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 }
574 }
575}
576
577
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000578void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
579 for (int i = 0; i < new_space_nodes_.length(); ++i) {
580 Node* node = new_space_nodes_[i];
581 if (node->IsStrongRetainer() ||
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000582 (node->IsWeakRetainer() && !node->is_independent() &&
583 !node->is_partially_dependent())) {
584 v->VisitPointer(node->location());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000585 }
586 }
587}
588
589
590void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
591 WeakSlotCallbackWithHeap f) {
592 for (int i = 0; i < new_space_nodes_.length(); ++i) {
593 Node* node = new_space_nodes_[i];
594 ASSERT(node->is_in_new_space_list());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000595 if ((node->is_independent() || node->is_partially_dependent()) &&
596 node->IsWeak() && f(isolate_->heap(), node->location())) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000597 node->MarkPending();
598 }
599 }
600}
601
602
603void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
604 for (int i = 0; i < new_space_nodes_.length(); ++i) {
605 Node* node = new_space_nodes_[i];
606 ASSERT(node->is_in_new_space_list());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000607 if ((node->is_independent() || node->is_partially_dependent()) &&
608 node->IsWeakRetainer()) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000609 v->VisitPointer(node->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000610 }
611 }
612}
613
614
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000615bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
616 WeakSlotCallbackWithHeap can_skip) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000617 ComputeObjectGroupsAndImplicitReferences();
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000618 int last = 0;
619 bool any_group_was_visited = false;
620 for (int i = 0; i < object_groups_.length(); i++) {
621 ObjectGroup* entry = object_groups_.at(i);
622 ASSERT(entry != NULL);
623
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000624 Object*** objects = entry->objects;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000625 bool group_should_be_visited = false;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000626 for (size_t j = 0; j < entry->length; j++) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000627 Object* object = *objects[j];
628 if (object->IsHeapObject()) {
629 if (!can_skip(isolate_->heap(), &object)) {
630 group_should_be_visited = true;
631 break;
632 }
633 }
634 }
635
636 if (!group_should_be_visited) {
637 object_groups_[last++] = entry;
638 continue;
639 }
640
641 // An object in the group requires visiting, so iterate over all
642 // objects in the group.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000643 for (size_t j = 0; j < entry->length; ++j) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000644 Object* object = *objects[j];
645 if (object->IsHeapObject()) {
646 v->VisitPointer(&object);
647 any_group_was_visited = true;
648 }
649 }
650
651 // Once the entire group has been iterated over, set the object
652 // group to NULL so it won't be processed again.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000653 delete entry;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000654 object_groups_.at(i) = NULL;
655 }
656 object_groups_.Rewind(last);
657 return any_group_was_visited;
658}
659
660
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000661bool GlobalHandles::PostGarbageCollectionProcessing(
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000662 GarbageCollector collector, GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663 // Process weak global handle callbacks. This must be done after the
664 // GC is completely done, because the callbacks may invoke arbitrary
665 // API functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000666 ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
667 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000668 bool next_gc_likely_to_collect_more = false;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000669 if (collector == SCAVENGER) {
670 for (int i = 0; i < new_space_nodes_.length(); ++i) {
671 Node* node = new_space_nodes_[i];
672 ASSERT(node->is_in_new_space_list());
danno@chromium.orgbee51992013-07-10 14:57:15 +0000673 if (!node->IsRetainer()) {
674 // Free nodes do not have weak callbacks. Do not use them to compute
675 // the next_gc_likely_to_collect_more.
676 continue;
677 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000678 // Skip dependent handles. Their weak callbacks might expect to be
679 // called between two global garbage collection callbacks which
680 // are not called for minor collections.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000681 if (!node->is_independent() && !node->is_partially_dependent()) {
682 continue;
683 }
684 node->clear_partially_dependent();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000685 if (node->PostGarbageCollectionProcessing(isolate_)) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000686 if (initial_post_gc_processing_count != post_gc_processing_count_) {
687 // Weak callback triggered another GC and another round of
688 // PostGarbageCollection processing. The current node might
689 // have been deleted in that round, so we need to bail out (or
690 // restart the processing).
691 return next_gc_likely_to_collect_more;
692 }
693 }
694 if (!node->IsRetainer()) {
695 next_gc_likely_to_collect_more = true;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000696 }
697 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000698 } else {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000699 for (NodeIterator it(this); !it.done(); it.Advance()) {
700 if (!it.node()->IsRetainer()) {
701 // Free nodes do not have weak callbacks. Do not use them to compute
702 // the next_gc_likely_to_collect_more.
703 continue;
danno@chromium.orgbee51992013-07-10 14:57:15 +0000704 }
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000705 it.node()->clear_partially_dependent();
706 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
707 if (initial_post_gc_processing_count != post_gc_processing_count_) {
708 // See the comment above.
709 return next_gc_likely_to_collect_more;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000710 }
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000711 }
712 if (!it.node()->IsRetainer()) {
713 next_gc_likely_to_collect_more = true;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000714 }
715 }
716 }
717 // Update the list of new space nodes.
718 int last = 0;
719 for (int i = 0; i < new_space_nodes_.length(); ++i) {
720 Node* node = new_space_nodes_[i];
721 ASSERT(node->is_in_new_space_list());
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000722 if (node->IsRetainer()) {
723 if (isolate_->heap()->InNewSpace(node->object())) {
724 new_space_nodes_[last++] = node;
725 tracer->increment_nodes_copied_in_new_space();
726 } else {
727 node->set_in_new_space_list(false);
728 tracer->increment_nodes_promoted();
729 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 } else {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000731 node->set_in_new_space_list(false);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000732 tracer->increment_nodes_died_in_new_space();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733 }
734 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000735 new_space_nodes_.Rewind(last);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000736 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737}
738
739
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000740void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000741 for (NodeIterator it(this); !it.done(); it.Advance()) {
742 if (it.node()->IsStrongRetainer()) {
743 v->VisitPointer(it.node()->location());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000744 }
745 }
746}
747
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000748
749void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000750 for (NodeIterator it(this); !it.done(); it.Advance()) {
751 if (it.node()->IsRetainer()) {
752 v->VisitPointer(it.node()->location());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000753 }
754 }
755}
756
757
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000758void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000759 for (NodeIterator it(this); !it.done(); it.Advance()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000760 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000761 v->VisitEmbedderReference(it.node()->location(),
762 it.node()->wrapper_class_id());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000763 }
764 }
765}
766
767
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000768void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
769 for (int i = 0; i < new_space_nodes_.length(); ++i) {
770 Node* node = new_space_nodes_[i];
771 if (node->IsRetainer() && node->has_wrapper_class_id()) {
772 v->VisitEmbedderReference(node->location(),
773 node->wrapper_class_id());
774 }
775 }
776}
777
778
yangguo@chromium.org28381b42013-01-21 14:39:38 +0000779int GlobalHandles::NumberOfWeakHandles() {
780 int count = 0;
781 for (NodeIterator it(this); !it.done(); it.Advance()) {
782 if (it.node()->IsWeakRetainer()) {
783 count++;
784 }
785 }
786 return count;
787}
788
789
790int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
791 int count = 0;
792 for (NodeIterator it(this); !it.done(); it.Advance()) {
793 if (it.node()->IsWeakRetainer() &&
794 it.node()->object()->IsJSGlobalObject()) {
795 count++;
796 }
797 }
798 return count;
799}
800
801
ager@chromium.org60121232009-12-03 11:25:37 +0000802void GlobalHandles::RecordStats(HeapStats* stats) {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000803 *stats->global_handle_count = 0;
804 *stats->weak_global_handle_count = 0;
805 *stats->pending_global_handle_count = 0;
806 *stats->near_death_global_handle_count = 0;
807 *stats->free_global_handle_count = 0;
808 for (NodeIterator it(this); !it.done(); it.Advance()) {
809 *stats->global_handle_count += 1;
810 if (it.node()->state() == Node::WEAK) {
811 *stats->weak_global_handle_count += 1;
812 } else if (it.node()->state() == Node::PENDING) {
813 *stats->pending_global_handle_count += 1;
814 } else if (it.node()->state() == Node::NEAR_DEATH) {
815 *stats->near_death_global_handle_count += 1;
816 } else if (it.node()->state() == Node::FREE) {
817 *stats->free_global_handle_count += 1;
818 }
819 }
ager@chromium.org60121232009-12-03 11:25:37 +0000820}
821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822#ifdef DEBUG
823
824void GlobalHandles::PrintStats() {
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000825 int total = 0;
826 int weak = 0;
827 int pending = 0;
828 int near_death = 0;
829 int destroyed = 0;
830
831 for (NodeIterator it(this); !it.done(); it.Advance()) {
832 total++;
833 if (it.node()->state() == Node::WEAK) weak++;
834 if (it.node()->state() == Node::PENDING) pending++;
835 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
836 if (it.node()->state() == Node::FREE) destroyed++;
837 }
838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 PrintF("Global Handle Statistics:\n");
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +0000840 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
841 PrintF(" # weak = %d\n", weak);
842 PrintF(" # pending = %d\n", pending);
843 PrintF(" # near_death = %d\n", near_death);
844 PrintF(" # free = %d\n", destroyed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 PrintF(" # total = %d\n", total);
846}
847
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849void GlobalHandles::Print() {
850 PrintF("Global handles:\n");
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000851 for (NodeIterator it(this); !it.done(); it.Advance()) {
852 PrintF(" handle %p to %p%s\n",
853 reinterpret_cast<void*>(it.node()->location()),
854 reinterpret_cast<void*>(it.node()->object()),
855 it.node()->IsWeak() ? " (weak)" : "");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 }
857}
858
859#endif
860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000862
863void GlobalHandles::AddObjectGroup(Object*** handles,
864 size_t length,
865 v8::RetainedObjectInfo* info) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000866#ifdef DEBUG
867 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000868 ASSERT(!Node::FromLocation(handles[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000869 }
870#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000871 if (length == 0) {
872 if (info != NULL) info->Dispose();
873 return;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000874 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000875 ObjectGroup* group = new ObjectGroup(length);
876 for (size_t i = 0; i < length; ++i)
877 group->objects[i] = handles[i];
878 group->info = info;
879 object_groups_.Add(group);
880}
881
882
883void GlobalHandles::SetObjectGroupId(Object** handle,
884 UniqueId id) {
885 object_group_connections_.Add(ObjectGroupConnection(id, handle));
886}
887
888
889void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
890 RetainedObjectInfo* info) {
891 retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000892}
893
894
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000895void GlobalHandles::AddImplicitReferences(HeapObject** parent,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000896 Object*** children,
897 size_t length) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000898#ifdef DEBUG
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000899 ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000900 for (size_t i = 0; i < length; ++i) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000901 ASSERT(!Node::FromLocation(children[i])->is_independent());
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000902 }
903#endif
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000904 if (length == 0) return;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000905 ImplicitRefGroup* group = new ImplicitRefGroup(parent, length);
906 for (size_t i = 0; i < length; ++i)
907 group->children[i] = children[i];
908 implicit_ref_groups_.Add(group);
909}
910
911
912void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
913 ASSERT(!Node::FromLocation(child)->is_independent());
914 implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
915}
916
917
918void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
919 ASSERT(!Node::FromLocation(child)->is_independent());
920 ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
921 group->children[0] = child;
922 implicit_ref_groups_.Add(group);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000923}
924
925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926void GlobalHandles::RemoveObjectGroups() {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000927 for (int i = 0; i < object_groups_.length(); i++)
928 delete object_groups_.at(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 object_groups_.Clear();
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000930 for (int i = 0; i < retainer_infos_.length(); ++i)
931 retainer_infos_[i].info->Dispose();
932 retainer_infos_.Clear();
933 object_group_connections_.Clear();
934 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935}
936
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000937
938void GlobalHandles::RemoveImplicitRefGroups() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000940 delete implicit_ref_groups_.at(i);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000941 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 implicit_ref_groups_.Clear();
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000943 implicit_ref_connections_.Clear();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000944}
945
946
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000947void GlobalHandles::TearDown() {
948 // TODO(1428): invoke weak callbacks.
949}
950
951
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000952void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
953 if (object_group_connections_.length() == 0) {
954 for (int i = 0; i < retainer_infos_.length(); ++i)
955 retainer_infos_[i].info->Dispose();
956 retainer_infos_.Clear();
957 implicit_ref_connections_.Clear();
958 return;
959 }
960
961 object_group_connections_.Sort();
962 retainer_infos_.Sort();
963 implicit_ref_connections_.Sort();
964
965 int info_index = 0; // For iterating retainer_infos_.
966 UniqueId current_group_id(0);
967 int current_group_start = 0;
968
969 int current_implicit_refs_start = 0;
970 int current_implicit_refs_end = 0;
971 for (int i = 0; i <= object_group_connections_.length(); ++i) {
972 if (i == 0)
973 current_group_id = object_group_connections_[i].id;
974 if (i == object_group_connections_.length() ||
975 current_group_id != object_group_connections_[i].id) {
976 // Group detected: objects in indices [current_group_start, i[.
977
978 // Find out which implicit references are related to this group. (We want
979 // to ignore object groups which only have 1 object, but that object is
980 // needed as a representative object for the implicit refrerence group.)
981 while (current_implicit_refs_start < implicit_ref_connections_.length() &&
982 implicit_ref_connections_[current_implicit_refs_start].id <
983 current_group_id)
984 ++current_implicit_refs_start;
985 current_implicit_refs_end = current_implicit_refs_start;
986 while (current_implicit_refs_end < implicit_ref_connections_.length() &&
987 implicit_ref_connections_[current_implicit_refs_end].id ==
988 current_group_id)
989 ++current_implicit_refs_end;
990
991 if (current_implicit_refs_end > current_implicit_refs_start) {
992 // Find a representative object for the implicit references.
993 HeapObject** representative = NULL;
994 for (int j = current_group_start; j < i; ++j) {
995 Object** object = object_group_connections_[j].object;
996 if ((*object)->IsHeapObject()) {
997 representative = reinterpret_cast<HeapObject**>(object);
998 break;
999 }
1000 }
1001 if (representative) {
1002 ImplicitRefGroup* group = new ImplicitRefGroup(
1003 representative,
1004 current_implicit_refs_end - current_implicit_refs_start);
1005 for (int j = current_implicit_refs_start;
1006 j < current_implicit_refs_end;
1007 ++j) {
1008 group->children[j - current_implicit_refs_start] =
1009 implicit_ref_connections_[j].object;
1010 }
1011 implicit_ref_groups_.Add(group);
1012 }
1013 current_implicit_refs_start = current_implicit_refs_end;
1014 }
1015
1016 // Find a RetainedObjectInfo for the group.
1017 RetainedObjectInfo* info = NULL;
1018 while (info_index < retainer_infos_.length() &&
1019 retainer_infos_[info_index].id < current_group_id) {
1020 retainer_infos_[info_index].info->Dispose();
1021 ++info_index;
1022 }
1023 if (info_index < retainer_infos_.length() &&
1024 retainer_infos_[info_index].id == current_group_id) {
1025 // This object group has an associated ObjectGroupRetainerInfo.
1026 info = retainer_infos_[info_index].info;
1027 ++info_index;
1028 }
1029
1030 // Ignore groups which only contain one object.
1031 if (i > current_group_start + 1) {
1032 ObjectGroup* group = new ObjectGroup(i - current_group_start);
1033 for (int j = current_group_start; j < i; ++j) {
1034 group->objects[j - current_group_start] =
1035 object_group_connections_[j].object;
1036 }
1037 group->info = info;
1038 object_groups_.Add(group);
1039 } else if (info) {
1040 info->Dispose();
1041 }
1042
1043 if (i < object_group_connections_.length()) {
1044 current_group_id = object_group_connections_[i].id;
1045 current_group_start = i;
1046 }
1047 }
1048 }
1049 object_group_connections_.Clear();
1050 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1051 retainer_infos_.Clear();
1052 implicit_ref_connections_.Clear();
1053}
1054
1055
danno@chromium.org59400602013-08-13 17:09:37 +00001056EternalHandles::EternalHandles() : size_(0) {
danno@chromium.org59400602013-08-13 17:09:37 +00001057 for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) {
1058 singleton_handles_[i] = kInvalidIndex;
1059 }
1060}
1061
1062
1063EternalHandles::~EternalHandles() {
1064 for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i];
1065}
1066
1067
1068void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) {
1069 int limit = size_;
1070 for (int i = 0; i < blocks_.length(); i++) {
1071 ASSERT(limit > 0);
1072 Object** block = blocks_[i];
1073 visitor->VisitPointers(block, block + Min(limit, kSize));
1074 limit -= kSize;
1075 }
1076}
1077
1078
1079void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) {
1080 for (int i = 0; i < new_space_indices_.length(); i++) {
1081 visitor->VisitPointer(GetLocation(new_space_indices_[i]));
1082 }
1083}
1084
1085
1086void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
1087 int last = 0;
1088 for (int i = 0; i < new_space_indices_.length(); i++) {
1089 int index = new_space_indices_[i];
1090 if (heap->InNewSpace(*GetLocation(index))) {
1091 new_space_indices_[last++] = index;
1092 }
1093 }
1094 new_space_indices_.Rewind(last);
1095}
1096
1097
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001098void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
1099 ASSERT_EQ(kInvalidIndex, *index);
1100 if (object == NULL) return;
danno@chromium.org59400602013-08-13 17:09:37 +00001101 ASSERT_NE(isolate->heap()->the_hole_value(), object);
1102 int block = size_ >> kShift;
1103 int offset = size_ & kMask;
1104 // need to resize
1105 if (offset == 0) {
1106 Object** next_block = new Object*[kSize];
1107 Object* the_hole = isolate->heap()->the_hole_value();
1108 MemsetPointer(next_block, the_hole, kSize);
1109 blocks_.Add(next_block);
1110 }
1111 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
1112 blocks_[block][offset] = object;
1113 if (isolate->heap()->InNewSpace(object)) {
1114 new_space_indices_.Add(size_);
1115 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001116 *index = size_++;
danno@chromium.org59400602013-08-13 17:09:37 +00001117}
1118
1119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120} } // namespace v8::internal