blob: 4f744d6dfbd28096c6c6985bdb53de4fa4c2acfc [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/api.h"
8#include "src/global-handles.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00009
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/vm-state-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010011
Steve Blocka7e24c12009-10-30 11:49:00 +000012namespace v8 {
13namespace internal {
14
Steve Block44f0eee2011-05-26 01:26:41 +010015
16ObjectGroup::~ObjectGroup() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017 if (info != NULL) info->Dispose();
18 delete[] objects;
19}
20
21
22ImplicitRefGroup::~ImplicitRefGroup() {
23 delete[] children;
Steve Block44f0eee2011-05-26 01:26:41 +010024}
25
26
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000027class GlobalHandles::Node {
Steve Blocka7e24c12009-10-30 11:49:00 +000028 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000029 // State transition diagram:
30 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
31 enum State {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 FREE = 0,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040033 NORMAL, // Normal global handle.
34 WEAK, // Flagged as weak but not yet finalized.
35 PENDING, // Has been recognized as only reachable by weak handles.
36 NEAR_DEATH, // Callback has informed the handle is near death.
37 NUMBER_OF_NODE_STATES
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000038 };
Steve Blocka7e24c12009-10-30 11:49:00 +000039
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000040 // Maps handle location (slot) to the containing node.
41 static Node* FromLocation(Object** location) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 DCHECK(OFFSET_OF(Node, object_) == 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000043 return reinterpret_cast<Node*>(location);
44 }
45
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 Node() {
47 DCHECK(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
48 DCHECK(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
49 STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
50 Internals::kNodeStateMask);
51 STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
52 STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
53 STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
54 STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
55 Internals::kNodeIsIndependentShift);
56 STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
57 Internals::kNodeIsPartiallyDependentShift);
58 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060#ifdef ENABLE_HANDLE_ZAPPING
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000061 ~Node() {
62 // TODO(1428): if it's a weak handle we should have invoked its callback.
63 // Zap the values for eager trapping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000065 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
66 index_ = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067 set_independent(false);
68 set_partially_dependent(false);
69 set_in_new_space_list(false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000070 parameter_or_next_free_.next_free = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 weak_callback_ = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000072 }
73#endif
74
75 void Initialize(int index, Node** first_free) {
76 index_ = static_cast<uint8_t>(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 DCHECK(static_cast<int>(index_) == index);
78 set_state(FREE);
79 set_in_new_space_list(false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000080 parameter_or_next_free_.next_free = *first_free;
81 *first_free = this;
82 }
83
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 void Acquire(Object* object) {
85 DCHECK(state() == FREE);
Steve Blocka7e24c12009-10-30 11:49:00 +000086 object_ = object;
Steve Block44f0eee2011-05-26 01:26:41 +010087 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 set_independent(false);
89 set_partially_dependent(false);
90 set_state(NORMAL);
Steve Blocka7e24c12009-10-30 11:49:00 +000091 parameter_or_next_free_.parameter = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092 weak_callback_ = NULL;
93 IncreaseBlockUses();
Steve Blocka7e24c12009-10-30 11:49:00 +000094 }
95
Emily Bernierd0a1eb72015-03-24 16:35:39 -040096 void Zap() {
97 DCHECK(IsInUse());
98 // Zap the values for eager trapping.
99 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
100 }
101
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 void Release() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400103 DCHECK(IsInUse());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 set_state(FREE);
105 // Zap the values for eager trapping.
106 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
107 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
108 set_independent(false);
109 set_partially_dependent(false);
110 weak_callback_ = NULL;
111 DecreaseBlockUses();
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 }
113
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000114 // Object slot accessors.
115 Object* object() const { return object_; }
116 Object** location() { return &object_; }
117 Handle<Object> handle() { return Handle<Object>(location()); }
118
119 // Wrapper class ID accessors.
120 bool has_wrapper_class_id() const {
121 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
122 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000124 uint16_t wrapper_class_id() const { return class_id_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125
126 // State and flag accessors.
127
128 State state() const {
129 return NodeState::decode(flags_);
130 }
131 void set_state(State state) {
132 flags_ = NodeState::update(flags_, state);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000133 }
134
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 bool is_independent() {
136 return IsIndependent::decode(flags_);
137 }
138 void set_independent(bool v) {
139 flags_ = IsIndependent::update(flags_, v);
140 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142 bool is_partially_dependent() {
143 return IsPartiallyDependent::decode(flags_);
144 }
145 void set_partially_dependent(bool v) {
146 flags_ = IsPartiallyDependent::update(flags_, v);
147 }
148
149 bool is_in_new_space_list() {
150 return IsInNewSpaceList::decode(flags_);
151 }
152 void set_in_new_space_list(bool v) {
153 flags_ = IsInNewSpaceList::update(flags_, v);
154 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000155
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400156 WeaknessType weakness_type() const {
157 return NodeWeaknessType::decode(flags_);
158 }
159 void set_weakness_type(WeaknessType weakness_type) {
160 flags_ = NodeWeaknessType::update(flags_, weakness_type);
161 }
162
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000163 bool IsNearDeath() const {
164 // Check for PENDING to ensure correct answer when processing callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 return state() == PENDING || state() == NEAR_DEATH;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000166 }
167
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 bool IsWeak() const { return state() == WEAK; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000169
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 bool IsInUse() const { return state() != FREE; }
171
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 bool IsRetainer() const { return state() != FREE; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000173
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 bool IsStrongRetainer() const { return state() == NORMAL; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000175
176 bool IsWeakRetainer() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000178 }
179
180 void MarkPending() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181 DCHECK(state() == WEAK);
182 set_state(PENDING);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000183 }
184
185 // Independent flag accessors.
186 void MarkIndependent() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400187 DCHECK(IsInUse());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 set_independent(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000189 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000190
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 void MarkPartiallyDependent() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400192 DCHECK(IsInUse());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
194 set_partially_dependent(true);
195 }
196 }
197 void clear_partially_dependent() { set_partially_dependent(false); }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000198
199 // Callback accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 // TODO(svenpanne) Re-enable or nuke later.
201 // WeakReferenceCallback callback() { return callback_; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000202
203 // Callback parameter accessors.
204 void set_parameter(void* parameter) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400205 DCHECK(IsInUse());
206 DCHECK(weakness_type() == NORMAL_WEAK || weakness_type() == PHANTOM_WEAK);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000207 parameter_or_next_free_.parameter = parameter;
208 }
209 void* parameter() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 DCHECK(IsInUse());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000211 return parameter_or_next_free_.parameter;
212 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000213
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214 void set_internal_fields(int internal_field_index1,
215 int internal_field_index2) {
216 DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
217 // These are stored in an int16_t.
218 DCHECK(internal_field_index1 < 1 << 16);
219 DCHECK(internal_field_index1 >= -(1 << 16));
220 DCHECK(internal_field_index2 < 1 << 16);
221 DCHECK(internal_field_index2 >= -(1 << 16));
222 parameter_or_next_free_.internal_field_indeces.internal_field1 =
223 static_cast<int16_t>(internal_field_index1);
224 parameter_or_next_free_.internal_field_indeces.internal_field2 =
225 static_cast<int16_t>(internal_field_index2);
226 }
227
228 int internal_field1() const {
229 DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
230 return parameter_or_next_free_.internal_field_indeces.internal_field1;
231 }
232
233 int internal_field2() const {
234 DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
235 return parameter_or_next_free_.internal_field_indeces.internal_field2;
236 }
237
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 // Accessors for next free node in the free list.
239 Node* next_free() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 DCHECK(state() == FREE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 return parameter_or_next_free_.next_free;
242 }
243 void set_next_free(Node* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 DCHECK(state() == FREE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 parameter_or_next_free_.next_free = value;
246 }
247
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 void MakeWeak(void* parameter, WeakCallback weak_callback) {
249 DCHECK(weak_callback != NULL);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400250 DCHECK(IsInUse());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 CHECK(object_ != NULL);
252 set_state(WEAK);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253 set_weakness_type(NORMAL_WEAK);
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 set_parameter(parameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 weak_callback_ = weak_callback;
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 }
257
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400258 void MakePhantom(void* parameter,
259 PhantomCallbackData<void>::Callback phantom_callback,
260 int16_t internal_field_index1,
261 int16_t internal_field_index2) {
262 DCHECK(phantom_callback != NULL);
263 DCHECK(IsInUse());
264 CHECK(object_ != NULL);
265 set_state(WEAK);
266 if (parameter == NULL) {
267 set_weakness_type(INTERNAL_FIELDS_WEAK);
268 set_internal_fields(internal_field_index1, internal_field_index2);
269 } else {
270 DCHECK(internal_field_index1 == v8::Object::kNoInternalFieldIndex);
271 DCHECK(internal_field_index2 == v8::Object::kNoInternalFieldIndex);
272 set_weakness_type(PHANTOM_WEAK);
273 set_parameter(parameter);
274 }
275 weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
276 }
277
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 void* ClearWeakness() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400279 DCHECK(IsInUse());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280 void* p = parameter();
281 set_state(NORMAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 set_parameter(NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 return p;
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 }
285
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400286 void CollectPhantomCallbackData(
287 Isolate* isolate, List<PendingPhantomCallback>* pending_phantom_callbacks,
288 List<PendingInternalFieldsCallback>* pending_internal_fields_callbacks) {
289 if (state() != Node::PENDING) return;
290 bool do_release = true;
291 if (weak_callback_ != NULL) {
292 if (weakness_type() == NORMAL_WEAK) return;
293
294 v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
295
296 if (weakness_type() == PHANTOM_WEAK) {
297 // Phantom weak pointer case. Zap with harmless value.
298 DCHECK(*location() == Smi::FromInt(0));
299 typedef PhantomCallbackData<void> Data;
300
301 Data data(api_isolate, parameter());
302 Data::Callback callback =
303 reinterpret_cast<Data::Callback>(weak_callback_);
304
305 pending_phantom_callbacks->Add(
306 PendingPhantomCallback(this, data, callback));
307
308 // Postpone the release of the handle. The embedder can't use the
309 // handle (it's zapped), but it may be using the location, and we
310 // don't want to confuse things by reusing that.
311 do_release = false;
312 } else {
313 DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
314 typedef InternalFieldsCallbackData<void, void> Data;
315
316 // Phantom weak pointer case, passing internal fields instead of
317 // parameter. Don't use a handle here during GC, because it will
318 // create a handle pointing to a dying object, which can confuse
319 // the next GC.
320 JSObject* jsobject = reinterpret_cast<JSObject*>(object());
321 DCHECK(jsobject->IsJSObject());
322 Data data(api_isolate, jsobject->GetInternalField(internal_field1()),
323 jsobject->GetInternalField(internal_field2()));
324 Data::Callback callback =
325 reinterpret_cast<Data::Callback>(weak_callback_);
326
327 // In the future, we want to delay the callback. In that case we will
328 // zap when we queue up, to stop the C++ side accessing the dead V8
329 // object, but we will call Release only after the callback (allowing
330 // the node to be reused).
331 pending_internal_fields_callbacks->Add(
332 PendingInternalFieldsCallback(data, callback));
333 }
334 }
335 // TODO(erikcorry): At the moment the callbacks are not postponed much,
336 // but if we really postpone them until after the mutator has run, we
337 // need to divide things up, so that an early callback clears the handle,
338 // while a later one destroys the objects involved, possibley triggering
339 // some work when decremented ref counts hit zero.
340 if (do_release) Release();
341 }
342
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000343 bool PostGarbageCollectionProcessing(Isolate* isolate) {
344 if (state() != Node::PENDING) return false;
345 if (weak_callback_ == NULL) {
346 Release();
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100347 return false;
348 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 set_state(NEAR_DEATH);
Steve Blocka7e24c12009-10-30 11:49:00 +0000350
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351 // Check that we are not passing a finalized external string to
352 // the callback.
353 DCHECK(!object_->IsExternalOneByteString() ||
354 ExternalOneByteString::cast(object_)->resource() != NULL);
355 DCHECK(!object_->IsExternalTwoByteString() ||
356 ExternalTwoByteString::cast(object_)->resource() != NULL);
357 // Leaving V8.
358 VMState<EXTERNAL> vmstate(isolate);
359 HandleScope handle_scope(isolate);
360 if (weakness_type() == PHANTOM_WEAK) return false;
361 DCHECK(weakness_type() == NORMAL_WEAK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000362 Object** object = location();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400363 Handle<Object> handle(*object, isolate);
364 v8::WeakCallbackData<v8::Value, void> data(
365 reinterpret_cast<v8::Isolate*>(isolate), parameter(),
366 v8::Utils::ToLocal(handle));
367 set_parameter(NULL);
368 weak_callback_(data);
369
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100370 // Absence of explicit cleanup or revival of weak handle
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100371 // in most of the cases would lead to memory leak.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 CHECK(state() != NEAR_DEATH);
Steve Blocka7e24c12009-10-30 11:49:00 +0000373 return true;
374 }
375
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 inline GlobalHandles* GetGlobalHandles();
377
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000378 private:
379 inline NodeBlock* FindBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 inline void IncreaseBlockUses();
381 inline void DecreaseBlockUses();
Steve Blocka7e24c12009-10-30 11:49:00 +0000382
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000383 // Storage for object pointer.
384 // Placed first to avoid offset computation.
385 Object* object_;
386
387 // Next word stores class_id, index, state, and independent.
388 // Note: the most aligned fields should go first.
389
390 // Wrapper class ID.
Steve Block44f0eee2011-05-26 01:26:41 +0100391 uint16_t class_id_;
392
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000393 // Index in the containing handle block.
394 uint8_t index_;
395
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000396 // This stores three flags (independent, partially_dependent and
397 // in_new_space_list) and a State.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400398 class NodeState : public BitField<State, 0, 3> {};
399 class IsIndependent : public BitField<bool, 3, 1> {};
400 class IsPartiallyDependent : public BitField<bool, 4, 1> {};
401 class IsInNewSpaceList : public BitField<bool, 5, 1> {};
402 class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
Steve Blocka7e24c12009-10-30 11:49:00 +0000403
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 uint8_t flags_;
Ben Murdoch257744e2011-11-30 15:57:28 +0000405
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406 // Handle specific callback - might be a weak reference in disguise.
407 WeakCallback weak_callback_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000408
409 // Provided data for callback. In FREE state, this is used for
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 // the free list link.
411 union {
412 void* parameter;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400413 struct {
414 int16_t internal_field1;
415 int16_t internal_field2;
416 } internal_field_indeces;
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 Node* next_free;
418 } parameter_or_next_free_;
419
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000420 DISALLOW_COPY_AND_ASSIGN(Node);
Steve Blocka7e24c12009-10-30 11:49:00 +0000421};
422
423
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000424class GlobalHandles::NodeBlock {
425 public:
426 static const int kSize = 256;
Steve Blockd0582a62009-12-15 09:54:21 +0000427
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
429 : next_(next),
430 used_nodes_(0),
431 next_used_(NULL),
432 prev_used_(NULL),
433 global_handles_(global_handles) {}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000434
435 void PutNodesOnFreeList(Node** first_free) {
436 for (int i = kSize - 1; i >= 0; --i) {
437 nodes_[i].Initialize(i, first_free);
438 }
439 }
440
441 Node* node_at(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 DCHECK(0 <= index && index < kSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000443 return &nodes_[index];
444 }
445
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 void IncreaseUses() {
447 DCHECK(used_nodes_ < kSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000448 if (used_nodes_++ == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 NodeBlock* old_first = global_handles_->first_used_block_;
450 global_handles_->first_used_block_ = this;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000451 next_used_ = old_first;
452 prev_used_ = NULL;
453 if (old_first == NULL) return;
454 old_first->prev_used_ = this;
455 }
456 }
457
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 void DecreaseUses() {
459 DCHECK(used_nodes_ > 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000460 if (--used_nodes_ == 0) {
461 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
462 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 if (this == global_handles_->first_used_block_) {
464 global_handles_->first_used_block_ = next_used_;
Ben Murdochbb769b22010-08-11 14:56:33 +0100465 }
466 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000467 }
Ben Murdochbb769b22010-08-11 14:56:33 +0100468
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000469 GlobalHandles* global_handles() { return global_handles_; }
470
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000471 // Next block in the list of all blocks.
472 NodeBlock* next() const { return next_; }
Steve Blockd0582a62009-12-15 09:54:21 +0000473
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000474 // Next/previous block in the list of blocks with used nodes.
475 NodeBlock* next_used() const { return next_used_; }
476 NodeBlock* prev_used() const { return prev_used_; }
Steve Blockd0582a62009-12-15 09:54:21 +0000477
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000478 private:
479 Node nodes_[kSize];
480 NodeBlock* const next_;
481 int used_nodes_;
482 NodeBlock* next_used_;
483 NodeBlock* prev_used_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 GlobalHandles* global_handles_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000485};
Steve Blockd0582a62009-12-15 09:54:21 +0000486
Steve Blockd0582a62009-12-15 09:54:21 +0000487
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
489 return FindBlock()->global_handles();
490}
491
492
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000493GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
494 intptr_t ptr = reinterpret_cast<intptr_t>(this);
495 ptr = ptr - index_ * sizeof(Node);
496 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 DCHECK(block->node_at(index_) == this);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000498 return block;
499}
Steve Blockd0582a62009-12-15 09:54:21 +0000500
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000501
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502void GlobalHandles::Node::IncreaseBlockUses() {
503 NodeBlock* node_block = FindBlock();
504 node_block->IncreaseUses();
505 GlobalHandles* global_handles = node_block->global_handles();
506 global_handles->isolate()->counters()->global_handles()->Increment();
507 global_handles->number_of_global_handles_++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000508}
509
510
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511void GlobalHandles::Node::DecreaseBlockUses() {
512 NodeBlock* node_block = FindBlock();
513 GlobalHandles* global_handles = node_block->global_handles();
514 parameter_or_next_free_.next_free = global_handles->first_free_;
515 global_handles->first_free_ = this;
516 node_block->DecreaseUses();
517 global_handles->isolate()->counters()->global_handles()->Decrement();
518 global_handles->number_of_global_handles_--;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000519}
520
521
522class GlobalHandles::NodeIterator {
523 public:
524 explicit NodeIterator(GlobalHandles* global_handles)
525 : block_(global_handles->first_used_block_),
526 index_(0) {}
527
528 bool done() const { return block_ == NULL; }
529
530 Node* node() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 DCHECK(!done());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000532 return block_->node_at(index_);
533 }
534
535 void Advance() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 DCHECK(!done());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000537 if (++index_ < NodeBlock::kSize) return;
538 index_ = 0;
539 block_ = block_->next_used();
540 }
541
542 private:
543 NodeBlock* block_;
544 int index_;
545
546 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
Steve Blockd0582a62009-12-15 09:54:21 +0000547};
548
549
Steve Block44f0eee2011-05-26 01:26:41 +0100550GlobalHandles::GlobalHandles(Isolate* isolate)
551 : isolate_(isolate),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100552 number_of_global_handles_(0),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000553 first_block_(NULL),
554 first_used_block_(NULL),
Steve Block44f0eee2011-05-26 01:26:41 +0100555 first_free_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 post_gc_processing_count_(0),
557 object_group_connections_(kObjectGroupConnectionsCapacity) {}
Steve Block44f0eee2011-05-26 01:26:41 +0100558
559
560GlobalHandles::~GlobalHandles() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000561 NodeBlock* block = first_block_;
562 while (block != NULL) {
563 NodeBlock* tmp = block->next();
564 delete block;
565 block = tmp;
566 }
567 first_block_ = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100568}
Steve Blockd0582a62009-12-15 09:54:21 +0000569
570
Steve Blocka7e24c12009-10-30 11:49:00 +0000571Handle<Object> GlobalHandles::Create(Object* value) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000572 if (first_free_ == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 first_block_ = new NodeBlock(this, first_block_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000574 first_block_->PutNodesOnFreeList(&first_free_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576 DCHECK(first_free_ != NULL);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000577 // Take the first node in the free list.
578 Node* result = first_free_;
579 first_free_ = result->next_free();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 result->Acquire(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000581 if (isolate_->heap()->InNewSpace(value) &&
582 !result->is_in_new_space_list()) {
583 new_space_nodes_.Add(result);
584 result->set_in_new_space_list(true);
585 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000586 return result->handle();
587}
588
589
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
591 DCHECK(location != NULL);
592 return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
593}
594
595
Steve Blocka7e24c12009-10-30 11:49:00 +0000596void GlobalHandles::Destroy(Object** location) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 if (location != NULL) Node::FromLocation(location)->Release();
Steve Blocka7e24c12009-10-30 11:49:00 +0000598}
599
600
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400601void GlobalHandles::MakeWeak(Object** location, void* parameter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 WeakCallback weak_callback) {
603 Node::FromLocation(location)->MakeWeak(parameter, weak_callback);
Steve Blocka7e24c12009-10-30 11:49:00 +0000604}
605
606
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400607typedef PhantomCallbackData<void>::Callback GenericCallback;
608
609
610void GlobalHandles::MakePhantom(
611 Object** location,
612 v8::InternalFieldsCallbackData<void, void>::Callback phantom_callback,
613 int16_t internal_field_index1, int16_t internal_field_index2) {
614 Node::FromLocation(location)
615 ->MakePhantom(NULL, reinterpret_cast<GenericCallback>(phantom_callback),
616 internal_field_index1, internal_field_index2);
617}
618
619
620void GlobalHandles::MakePhantom(Object** location, void* parameter,
621 GenericCallback phantom_callback) {
622 Node::FromLocation(location)->MakePhantom(parameter, phantom_callback,
623 v8::Object::kNoInternalFieldIndex,
624 v8::Object::kNoInternalFieldIndex);
625}
626
627
628void GlobalHandles::CollectPhantomCallbackData() {
629 for (NodeIterator it(this); !it.done(); it.Advance()) {
630 Node* node = it.node();
631 node->CollectPhantomCallbackData(isolate(), &pending_phantom_callbacks_,
632 &pending_internal_fields_callbacks_);
633 }
634}
635
636
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637void* GlobalHandles::ClearWeakness(Object** location) {
638 return Node::FromLocation(location)->ClearWeakness();
Steve Blocka7e24c12009-10-30 11:49:00 +0000639}
640
641
Ben Murdoch257744e2011-11-30 15:57:28 +0000642void GlobalHandles::MarkIndependent(Object** location) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000643 Node::FromLocation(location)->MarkIndependent();
Ben Murdoch257744e2011-11-30 15:57:28 +0000644}
645
646
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647void GlobalHandles::MarkPartiallyDependent(Object** location) {
648 Node::FromLocation(location)->MarkPartiallyDependent();
649}
650
651
652bool GlobalHandles::IsIndependent(Object** location) {
653 return Node::FromLocation(location)->is_independent();
654}
655
656
Steve Blocka7e24c12009-10-30 11:49:00 +0000657bool GlobalHandles::IsNearDeath(Object** location) {
658 return Node::FromLocation(location)->IsNearDeath();
659}
660
661
662bool GlobalHandles::IsWeak(Object** location) {
663 return Node::FromLocation(location)->IsWeak();
664}
665
666
667void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000668 for (NodeIterator it(this); !it.done(); it.Advance()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400669 Node* node = it.node();
670 if (node->IsWeakRetainer()) {
671 // Weakness type can be normal, phantom or internal fields.
672 // For normal weakness we mark through the handle so that
673 // the object and things reachable from it are available
674 // to the callback.
675 // In the case of phantom we can zap the object handle now
676 // and we won't need it, so we don't need to mark through it.
677 // In the internal fields case we will need the internal
678 // fields, so we can't zap the handle, but we don't need to
679 // mark through it, because it will die in this GC round.
680 if (node->state() == Node::PENDING) {
681 if (node->weakness_type() == PHANTOM_WEAK) {
682 *(node->location()) = Smi::FromInt(0);
683 } else if (node->weakness_type() == NORMAL_WEAK) {
684 v->VisitPointer(node->location());
685 } else {
686 DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
687 }
688 } else {
689 // Node is not pending, so that means the object survived. We still
690 // need to visit the pointer in case the object moved, eg. because of
691 // compaction.
692 v->VisitPointer(node->location());
693 }
694 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000695 }
696}
697
698
Steve Blocka7e24c12009-10-30 11:49:00 +0000699void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000700 for (NodeIterator it(this); !it.done(); it.Advance()) {
701 if (it.node()->IsWeak() && f(it.node()->location())) {
702 it.node()->MarkPending();
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 }
704 }
705}
706
707
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000708void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v) {
709 for (int i = 0; i < new_space_nodes_.length(); ++i) {
710 Node* node = new_space_nodes_[i];
711 if (node->IsStrongRetainer() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 (node->IsWeakRetainer() && !node->is_independent() &&
713 !node->is_partially_dependent())) {
714 v->VisitPointer(node->location());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000715 }
716 }
717}
718
719
720void GlobalHandles::IdentifyNewSpaceWeakIndependentHandles(
721 WeakSlotCallbackWithHeap f) {
722 for (int i = 0; i < new_space_nodes_.length(); ++i) {
723 Node* node = new_space_nodes_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 DCHECK(node->is_in_new_space_list());
725 if ((node->is_independent() || node->is_partially_dependent()) &&
726 node->IsWeak() && f(isolate_->heap(), node->location())) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000727 node->MarkPending();
728 }
729 }
730}
731
732
733void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
734 for (int i = 0; i < new_space_nodes_.length(); ++i) {
735 Node* node = new_space_nodes_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 DCHECK(node->is_in_new_space_list());
737 if ((node->is_independent() || node->is_partially_dependent()) &&
738 node->IsWeakRetainer()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400739 if (node->weakness_type() == PHANTOM_WEAK) {
740 *(node->location()) = Smi::FromInt(0);
741 } else if (node->weakness_type() == NORMAL_WEAK) {
742 v->VisitPointer(node->location());
743 } else {
744 DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
745 // For this case we only need to trace if it's alive: The tracing of
746 // something that is already alive is just to get the pointer updated
747 // to the new location of the object).
748 DCHECK(node->state() != Node::NEAR_DEATH);
749 if (node->state() != Node::PENDING) {
750 v->VisitPointer(node->location());
751 }
752 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000753 }
754 }
755}
756
757
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
759 WeakSlotCallbackWithHeap can_skip) {
760 ComputeObjectGroupsAndImplicitReferences();
761 int last = 0;
762 bool any_group_was_visited = false;
763 for (int i = 0; i < object_groups_.length(); i++) {
764 ObjectGroup* entry = object_groups_.at(i);
765 DCHECK(entry != NULL);
766
767 Object*** objects = entry->objects;
768 bool group_should_be_visited = false;
769 for (size_t j = 0; j < entry->length; j++) {
770 Object* object = *objects[j];
771 if (object->IsHeapObject()) {
772 if (!can_skip(isolate_->heap(), &object)) {
773 group_should_be_visited = true;
774 break;
775 }
776 }
777 }
778
779 if (!group_should_be_visited) {
780 object_groups_[last++] = entry;
781 continue;
782 }
783
784 // An object in the group requires visiting, so iterate over all
785 // objects in the group.
786 for (size_t j = 0; j < entry->length; ++j) {
787 Object* object = *objects[j];
788 if (object->IsHeapObject()) {
789 v->VisitPointer(&object);
790 any_group_was_visited = true;
791 }
792 }
793
794 // Once the entire group has been iterated over, set the object
795 // group to NULL so it won't be processed again.
796 delete entry;
797 object_groups_.at(i) = NULL;
798 }
799 object_groups_.Rewind(last);
800 return any_group_was_visited;
801}
802
803
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400804int GlobalHandles::PostScavengeProcessing(
805 const int initial_post_gc_processing_count) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 int freed_nodes = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400807 for (int i = 0; i < new_space_nodes_.length(); ++i) {
808 Node* node = new_space_nodes_[i];
809 DCHECK(node->is_in_new_space_list());
810 if (!node->IsRetainer()) {
811 // Free nodes do not have weak callbacks. Do not use them to compute
812 // the freed_nodes.
813 continue;
814 }
815 // Skip dependent handles. Their weak callbacks might expect to be
816 // called between two global garbage collection callbacks which
817 // are not called for minor collections.
818 if (!node->is_independent() && !node->is_partially_dependent()) {
819 continue;
820 }
821 node->clear_partially_dependent();
822 if (node->PostGarbageCollectionProcessing(isolate_)) {
823 if (initial_post_gc_processing_count != post_gc_processing_count_) {
824 // Weak callback triggered another GC and another round of
825 // PostGarbageCollection processing. The current node might
826 // have been deleted in that round, so we need to bail out (or
827 // restart the processing).
828 return freed_nodes;
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 }
830 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400831 if (!node->IsRetainer()) {
832 freed_nodes++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000833 }
834 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400835 return freed_nodes;
836}
837
838
839int GlobalHandles::PostMarkSweepProcessing(
840 const int initial_post_gc_processing_count) {
841 int freed_nodes = 0;
842 for (NodeIterator it(this); !it.done(); it.Advance()) {
843 if (!it.node()->IsRetainer()) {
844 // Free nodes do not have weak callbacks. Do not use them to compute
845 // the freed_nodes.
846 continue;
847 }
848 it.node()->clear_partially_dependent();
849 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
850 if (initial_post_gc_processing_count != post_gc_processing_count_) {
851 // See the comment above.
852 return freed_nodes;
853 }
854 }
855 if (!it.node()->IsRetainer()) {
856 freed_nodes++;
857 }
858 }
859 return freed_nodes;
860}
861
862
863void GlobalHandles::UpdateListOfNewSpaceNodes() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000864 int last = 0;
865 for (int i = 0; i < new_space_nodes_.length(); ++i) {
866 Node* node = new_space_nodes_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867 DCHECK(node->is_in_new_space_list());
868 if (node->IsRetainer()) {
869 if (isolate_->heap()->InNewSpace(node->object())) {
870 new_space_nodes_[last++] = node;
871 isolate_->heap()->IncrementNodesCopiedInNewSpace();
872 } else {
873 node->set_in_new_space_list(false);
874 isolate_->heap()->IncrementNodesPromoted();
875 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000877 node->set_in_new_space_list(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 isolate_->heap()->IncrementNodesDiedInNewSpace();
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 }
880 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000881 new_space_nodes_.Rewind(last);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400882}
883
884
885int GlobalHandles::DispatchPendingPhantomCallbacks() {
886 int freed_nodes = 0;
887 while (pending_phantom_callbacks_.length() != 0) {
888 PendingPhantomCallback callback = pending_phantom_callbacks_.RemoveLast();
889 callback.invoke();
890 freed_nodes++;
891 }
892 while (pending_internal_fields_callbacks_.length() != 0) {
893 PendingInternalFieldsCallback callback =
894 pending_internal_fields_callbacks_.RemoveLast();
895 callback.invoke();
896 freed_nodes++;
897 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898 return freed_nodes;
Steve Blocka7e24c12009-10-30 11:49:00 +0000899}
900
901
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400902int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
903 // Process weak global handle callbacks. This must be done after the
904 // GC is completely done, because the callbacks may invoke arbitrary
905 // API functions.
906 DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
907 const int initial_post_gc_processing_count = ++post_gc_processing_count_;
908 int freed_nodes = 0;
909 if (collector == SCAVENGER) {
910 freed_nodes = PostScavengeProcessing(initial_post_gc_processing_count);
911 } else {
912 freed_nodes = PostMarkSweepProcessing(initial_post_gc_processing_count);
913 }
914 if (initial_post_gc_processing_count != post_gc_processing_count_) {
915 // If the callbacks caused a nested GC, then return. See comment in
916 // PostScavengeProcessing.
917 return freed_nodes;
918 }
919 freed_nodes += DispatchPendingPhantomCallbacks();
920 if (initial_post_gc_processing_count == post_gc_processing_count_) {
921 UpdateListOfNewSpaceNodes();
922 }
923 return freed_nodes;
924}
925
926
927void GlobalHandles::PendingPhantomCallback::invoke() {
928 if (node_->state() == Node::FREE) return;
929 DCHECK(node_->state() == Node::NEAR_DEATH);
930 callback_(data_);
931 if (node_->state() != Node::FREE) node_->Release();
932}
933
934
Steve Blockd0582a62009-12-15 09:54:21 +0000935void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000936 for (NodeIterator it(this); !it.done(); it.Advance()) {
937 if (it.node()->IsStrongRetainer()) {
938 v->VisitPointer(it.node()->location());
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 }
940 }
941}
942
Steve Blockd0582a62009-12-15 09:54:21 +0000943
944void GlobalHandles::IterateAllRoots(ObjectVisitor* v) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000945 for (NodeIterator it(this); !it.done(); it.Advance()) {
946 if (it.node()->IsRetainer()) {
947 v->VisitPointer(it.node()->location());
Ben Murdoch257744e2011-11-30 15:57:28 +0000948 }
949 }
950}
951
952
Steve Block44f0eee2011-05-26 01:26:41 +0100953void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000954 for (NodeIterator it(this); !it.done(); it.Advance()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000956 v->VisitEmbedderReference(it.node()->location(),
957 it.node()->wrapper_class_id());
Steve Block44f0eee2011-05-26 01:26:41 +0100958 }
959 }
960}
961
962
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
964 for (int i = 0; i < new_space_nodes_.length(); ++i) {
965 Node* node = new_space_nodes_[i];
966 if (node->IsRetainer() && node->has_wrapper_class_id()) {
967 v->VisitEmbedderReference(node->location(),
968 node->wrapper_class_id());
969 }
970 }
971}
972
973
974int GlobalHandles::NumberOfWeakHandles() {
975 int count = 0;
976 for (NodeIterator it(this); !it.done(); it.Advance()) {
977 if (it.node()->IsWeakRetainer()) {
978 count++;
979 }
980 }
981 return count;
982}
983
984
985int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
986 int count = 0;
987 for (NodeIterator it(this); !it.done(); it.Advance()) {
988 if (it.node()->IsWeakRetainer() &&
989 it.node()->object()->IsJSGlobalObject()) {
990 count++;
991 }
992 }
993 return count;
994}
995
996
Steve Blockd0582a62009-12-15 09:54:21 +0000997void GlobalHandles::RecordStats(HeapStats* stats) {
998 *stats->global_handle_count = 0;
999 *stats->weak_global_handle_count = 0;
1000 *stats->pending_global_handle_count = 0;
1001 *stats->near_death_global_handle_count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001002 *stats->free_global_handle_count = 0;
1003 for (NodeIterator it(this); !it.done(); it.Advance()) {
Steve Blockd0582a62009-12-15 09:54:21 +00001004 *stats->global_handle_count += 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001005 if (it.node()->state() == Node::WEAK) {
Steve Blockd0582a62009-12-15 09:54:21 +00001006 *stats->weak_global_handle_count += 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001007 } else if (it.node()->state() == Node::PENDING) {
Steve Blockd0582a62009-12-15 09:54:21 +00001008 *stats->pending_global_handle_count += 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001009 } else if (it.node()->state() == Node::NEAR_DEATH) {
Steve Blockd0582a62009-12-15 09:54:21 +00001010 *stats->near_death_global_handle_count += 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001011 } else if (it.node()->state() == Node::FREE) {
1012 *stats->free_global_handle_count += 1;
Steve Blockd0582a62009-12-15 09:54:21 +00001013 }
1014 }
1015}
Steve Blocka7e24c12009-10-30 11:49:00 +00001016
1017#ifdef DEBUG
1018
1019void GlobalHandles::PrintStats() {
1020 int total = 0;
1021 int weak = 0;
1022 int pending = 0;
1023 int near_death = 0;
1024 int destroyed = 0;
1025
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001026 for (NodeIterator it(this); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001027 total++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001028 if (it.node()->state() == Node::WEAK) weak++;
1029 if (it.node()->state() == Node::PENDING) pending++;
1030 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
1031 if (it.node()->state() == Node::FREE) destroyed++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 }
1033
1034 PrintF("Global Handle Statistics:\n");
Ben Murdochf87a2032010-10-22 12:50:53 +01001035 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 PrintF(" # weak = %d\n", weak);
1037 PrintF(" # pending = %d\n", pending);
1038 PrintF(" # near_death = %d\n", near_death);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001039 PrintF(" # free = %d\n", destroyed);
Steve Blocka7e24c12009-10-30 11:49:00 +00001040 PrintF(" # total = %d\n", total);
1041}
1042
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001043
Steve Blocka7e24c12009-10-30 11:49:00 +00001044void GlobalHandles::Print() {
1045 PrintF("Global handles:\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001046 for (NodeIterator it(this); !it.done(); it.Advance()) {
1047 PrintF(" handle %p to %p%s\n",
1048 reinterpret_cast<void*>(it.node()->location()),
1049 reinterpret_cast<void*>(it.node()->object()),
1050 it.node()->IsWeak() ? " (weak)" : "");
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 }
1052}
1053
1054#endif
1055
Steve Block44f0eee2011-05-26 01:26:41 +01001056
1057
1058void GlobalHandles::AddObjectGroup(Object*** handles,
1059 size_t length,
1060 v8::RetainedObjectInfo* info) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001061#ifdef DEBUG
1062 for (size_t i = 0; i < length; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 DCHECK(!Node::FromLocation(handles[i])->is_independent());
Ben Murdoch257744e2011-11-30 15:57:28 +00001064 }
1065#endif
Ben Murdoch8b112d22011-06-08 16:22:53 +01001066 if (length == 0) {
1067 if (info != NULL) info->Dispose();
1068 return;
Steve Block44f0eee2011-05-26 01:26:41 +01001069 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 ObjectGroup* group = new ObjectGroup(length);
1071 for (size_t i = 0; i < length; ++i)
1072 group->objects[i] = handles[i];
1073 group->info = info;
1074 object_groups_.Add(group);
Steve Blocka7e24c12009-10-30 11:49:00 +00001075}
1076
Steve Block44f0eee2011-05-26 01:26:41 +01001077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001078void GlobalHandles::SetObjectGroupId(Object** handle,
1079 UniqueId id) {
1080 object_group_connections_.Add(ObjectGroupConnection(id, handle));
1081}
1082
1083
1084void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
1085 RetainedObjectInfo* info) {
1086 retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
1087}
1088
1089
1090void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
1091 DCHECK(!Node::FromLocation(child)->is_independent());
1092 implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
1093}
1094
1095
1096void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
1097 DCHECK(!Node::FromLocation(child)->is_independent());
1098 ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
1099 group->children[0] = child;
1100 implicit_ref_groups_.Add(group);
Steve Blocka7e24c12009-10-30 11:49:00 +00001101}
1102
1103
1104void GlobalHandles::RemoveObjectGroups() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 for (int i = 0; i < object_groups_.length(); i++)
1106 delete object_groups_.at(i);
Steve Block44f0eee2011-05-26 01:26:41 +01001107 object_groups_.Clear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001108 for (int i = 0; i < retainer_infos_.length(); ++i)
1109 retainer_infos_[i].info->Dispose();
1110 retainer_infos_.Clear();
1111 object_group_connections_.Clear();
1112 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00001113}
1114
Steve Block44f0eee2011-05-26 01:26:41 +01001115
1116void GlobalHandles::RemoveImplicitRefGroups() {
1117 for (int i = 0; i < implicit_ref_groups_.length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 delete implicit_ref_groups_.at(i);
Steve Block44f0eee2011-05-26 01:26:41 +01001119 }
1120 implicit_ref_groups_.Clear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001121 implicit_ref_connections_.Clear();
Steve Block44f0eee2011-05-26 01:26:41 +01001122}
1123
1124
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001125void GlobalHandles::TearDown() {
1126 // TODO(1428): invoke weak callbacks.
1127}
1128
1129
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001130void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
1131 if (object_group_connections_.length() == 0) {
1132 for (int i = 0; i < retainer_infos_.length(); ++i)
1133 retainer_infos_[i].info->Dispose();
1134 retainer_infos_.Clear();
1135 implicit_ref_connections_.Clear();
1136 return;
1137 }
1138
1139 object_group_connections_.Sort();
1140 retainer_infos_.Sort();
1141 implicit_ref_connections_.Sort();
1142
1143 int info_index = 0; // For iterating retainer_infos_.
1144 UniqueId current_group_id(0);
1145 int current_group_start = 0;
1146
1147 int current_implicit_refs_start = 0;
1148 int current_implicit_refs_end = 0;
1149 for (int i = 0; i <= object_group_connections_.length(); ++i) {
1150 if (i == 0)
1151 current_group_id = object_group_connections_[i].id;
1152 if (i == object_group_connections_.length() ||
1153 current_group_id != object_group_connections_[i].id) {
1154 // Group detected: objects in indices [current_group_start, i[.
1155
1156 // Find out which implicit references are related to this group. (We want
1157 // to ignore object groups which only have 1 object, but that object is
1158 // needed as a representative object for the implicit refrerence group.)
1159 while (current_implicit_refs_start < implicit_ref_connections_.length() &&
1160 implicit_ref_connections_[current_implicit_refs_start].id <
1161 current_group_id)
1162 ++current_implicit_refs_start;
1163 current_implicit_refs_end = current_implicit_refs_start;
1164 while (current_implicit_refs_end < implicit_ref_connections_.length() &&
1165 implicit_ref_connections_[current_implicit_refs_end].id ==
1166 current_group_id)
1167 ++current_implicit_refs_end;
1168
1169 if (current_implicit_refs_end > current_implicit_refs_start) {
1170 // Find a representative object for the implicit references.
1171 HeapObject** representative = NULL;
1172 for (int j = current_group_start; j < i; ++j) {
1173 Object** object = object_group_connections_[j].object;
1174 if ((*object)->IsHeapObject()) {
1175 representative = reinterpret_cast<HeapObject**>(object);
1176 break;
1177 }
1178 }
1179 if (representative) {
1180 ImplicitRefGroup* group = new ImplicitRefGroup(
1181 representative,
1182 current_implicit_refs_end - current_implicit_refs_start);
1183 for (int j = current_implicit_refs_start;
1184 j < current_implicit_refs_end;
1185 ++j) {
1186 group->children[j - current_implicit_refs_start] =
1187 implicit_ref_connections_[j].object;
1188 }
1189 implicit_ref_groups_.Add(group);
1190 }
1191 current_implicit_refs_start = current_implicit_refs_end;
1192 }
1193
1194 // Find a RetainedObjectInfo for the group.
1195 RetainedObjectInfo* info = NULL;
1196 while (info_index < retainer_infos_.length() &&
1197 retainer_infos_[info_index].id < current_group_id) {
1198 retainer_infos_[info_index].info->Dispose();
1199 ++info_index;
1200 }
1201 if (info_index < retainer_infos_.length() &&
1202 retainer_infos_[info_index].id == current_group_id) {
1203 // This object group has an associated ObjectGroupRetainerInfo.
1204 info = retainer_infos_[info_index].info;
1205 ++info_index;
1206 }
1207
1208 // Ignore groups which only contain one object.
1209 if (i > current_group_start + 1) {
1210 ObjectGroup* group = new ObjectGroup(i - current_group_start);
1211 for (int j = current_group_start; j < i; ++j) {
1212 group->objects[j - current_group_start] =
1213 object_group_connections_[j].object;
1214 }
1215 group->info = info;
1216 object_groups_.Add(group);
1217 } else if (info) {
1218 info->Dispose();
1219 }
1220
1221 if (i < object_group_connections_.length()) {
1222 current_group_id = object_group_connections_[i].id;
1223 current_group_start = i;
1224 }
1225 }
1226 }
1227 object_group_connections_.Clear();
1228 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1229 retainer_infos_.Clear();
1230 implicit_ref_connections_.Clear();
1231}
1232
1233
1234EternalHandles::EternalHandles() : size_(0) {
1235 for (unsigned i = 0; i < arraysize(singleton_handles_); i++) {
1236 singleton_handles_[i] = kInvalidIndex;
1237 }
1238}
1239
1240
1241EternalHandles::~EternalHandles() {
1242 for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i];
1243}
1244
1245
1246void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) {
1247 int limit = size_;
1248 for (int i = 0; i < blocks_.length(); i++) {
1249 DCHECK(limit > 0);
1250 Object** block = blocks_[i];
1251 visitor->VisitPointers(block, block + Min(limit, kSize));
1252 limit -= kSize;
1253 }
1254}
1255
1256
1257void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) {
1258 for (int i = 0; i < new_space_indices_.length(); i++) {
1259 visitor->VisitPointer(GetLocation(new_space_indices_[i]));
1260 }
1261}
1262
1263
1264void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
1265 int last = 0;
1266 for (int i = 0; i < new_space_indices_.length(); i++) {
1267 int index = new_space_indices_[i];
1268 if (heap->InNewSpace(*GetLocation(index))) {
1269 new_space_indices_[last++] = index;
1270 }
1271 }
1272 new_space_indices_.Rewind(last);
1273}
1274
1275
1276void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
1277 DCHECK_EQ(kInvalidIndex, *index);
1278 if (object == NULL) return;
1279 DCHECK_NE(isolate->heap()->the_hole_value(), object);
1280 int block = size_ >> kShift;
1281 int offset = size_ & kMask;
1282 // need to resize
1283 if (offset == 0) {
1284 Object** next_block = new Object*[kSize];
1285 Object* the_hole = isolate->heap()->the_hole_value();
1286 MemsetPointer(next_block, the_hole, kSize);
1287 blocks_.Add(next_block);
1288 }
1289 DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
1290 blocks_[block][offset] = object;
1291 if (isolate->heap()->InNewSpace(object)) {
1292 new_space_indices_.Add(size_);
1293 }
1294 *index = size_++;
1295}
1296
1297
Steve Blocka7e24c12009-10-30 11:49:00 +00001298} } // namespace v8::internal