blob: c2194fc89bf1182b6101b463a532cac618cdeb65 [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
33namespace v8 { namespace internal {
34
35class GlobalHandles::Node : public Malloced {
36 public:
37
38 void Initialize(Object* object) {
39 // Set the initial value of the handle.
40 object_ = object;
41 state_ = NORMAL;
42 parameter_or_next_free_.parameter = NULL;
43 callback_ = NULL;
44 }
45
46 explicit Node(Object* object) {
47 Initialize(object);
48 // Initialize link structure.
49 next_ = NULL;
50 }
51
52 ~Node() {
53 if (state_ != DESTROYED) Destroy();
54#ifdef DEBUG
55 // Zap the values for eager trapping.
56 object_ = NULL;
57 next_ = NULL;
58 parameter_or_next_free_.next_free = NULL;
59#endif
60 }
61
62 void Destroy() {
63 if (state_ == WEAK || IsNearDeath()) {
64 GlobalHandles::number_of_weak_handles_--;
65 if (object_->IsJSGlobalObject()) {
66 GlobalHandles::number_of_global_object_weak_handles_--;
67 }
68 }
69 state_ = DESTROYED;
70 }
71
72 // Accessors for next_.
73 Node* next() { return next_; }
74 void set_next(Node* value) { next_ = value; }
75 Node** next_addr() { return &next_; }
76
77 // Accessors for next free node in the free list.
78 Node* next_free() {
79 ASSERT(state_ == DESTROYED);
80 return parameter_or_next_free_.next_free;
81 }
82 void set_next_free(Node* value) {
83 ASSERT(state_ == DESTROYED);
84 parameter_or_next_free_.next_free = value;
85 }
86
87 // Returns a link from the handle.
88 static Node* FromLocation(Object** location) {
89 ASSERT(OFFSET_OF(Node, object_) == 0);
90 return reinterpret_cast<Node*>(location);
91 }
92
93 // Returns the handle.
94 Handle<Object> handle() { return Handle<Object>(&object_); }
95
96 // Make this handle weak.
97 void MakeWeak(void* parameter, WeakReferenceCallback callback) {
98 LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
ager@chromium.org3bf7b912008-11-17 09:09:45 +000099 ASSERT(state_ != DESTROYED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100 if (state_ != WEAK && !IsNearDeath()) {
101 GlobalHandles::number_of_weak_handles_++;
102 if (object_->IsJSGlobalObject()) {
103 GlobalHandles::number_of_global_object_weak_handles_++;
104 }
105 }
106 state_ = WEAK;
107 set_parameter(parameter);
108 callback_ = callback;
109 }
110
111 void ClearWeakness() {
112 LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000113 ASSERT(state_ != DESTROYED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 if (state_ == WEAK || IsNearDeath()) {
115 GlobalHandles::number_of_weak_handles_--;
116 if (object_->IsJSGlobalObject()) {
117 GlobalHandles::number_of_global_object_weak_handles_--;
118 }
119 }
120 state_ = NORMAL;
121 set_parameter(NULL);
122 }
123
124 bool IsNearDeath() {
125 // Check for PENDING to ensure correct answer when processing callbacks.
126 return state_ == PENDING || state_ == NEAR_DEATH;
127 }
128
129 bool IsWeak() {
130 return state_ == WEAK;
131 }
132
133 // Returns the id for this weak handle.
134 void set_parameter(void* parameter) {
135 ASSERT(state_ != DESTROYED);
136 parameter_or_next_free_.parameter = parameter;
137 }
138 void* parameter() {
139 ASSERT(state_ != DESTROYED);
140 return parameter_or_next_free_.parameter;
141 }
142
143 // Returns the callback for this weak handle.
144 WeakReferenceCallback callback() { return callback_; }
145
146 void PostGarbageCollectionProcessing() {
147 if (state_ != Node::PENDING) return;
148 LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
149 void* par = parameter();
150 state_ = NEAR_DEATH;
151 set_parameter(NULL);
152 // The callback function is resolved as late as possible to preserve old
153 // behavior.
154 WeakReferenceCallback func = callback();
155 if (func != NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +0000156 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
157 {
158 // Leaving V8.
159 VMState state(EXTERNAL);
160 func(object, par);
161 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 }
163 }
164
165 // Place the handle address first to avoid offset computation.
166 Object* object_; // Storage for object pointer.
167
168 // Transition diagram:
169 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
170 enum State {
171 NORMAL, // Normal global handle.
172 WEAK, // Flagged as weak but not yet finalized.
173 PENDING, // Has been recognized as only reachable by weak handles.
174 NEAR_DEATH, // Callback has informed the handle is near death.
175 DESTROYED
176 };
177 State state_;
178
179 private:
180 // Handle specific callback.
181 WeakReferenceCallback callback_;
182 // Provided data for callback. In DESTROYED state, this is used for
183 // the free list link.
184 union {
185 void* parameter;
186 Node* next_free;
187 } parameter_or_next_free_;
188
189 // Linkage for the list.
190 Node* next_;
191
192 public:
193 TRACK_MEMORY("GlobalHandles::Node")
194};
195
196
197Handle<Object> GlobalHandles::Create(Object* value) {
198 Counters::global_handles.Increment();
199 Node* result;
200 if (first_free() == NULL) {
201 // Allocate a new node.
202 result = new Node(value);
203 result->set_next(head());
204 set_head(result);
205 } else {
206 // Take the first node in the free list.
207 result = first_free();
208 set_first_free(result->next_free());
209 result->Initialize(value);
210 }
211 return result->handle();
212}
213
214
215void GlobalHandles::Destroy(Object** location) {
216 Counters::global_handles.Decrement();
217 if (location == NULL) return;
218 Node* node = Node::FromLocation(location);
219 node->Destroy();
220 // Link the destroyed.
221 node->set_next_free(first_free());
222 set_first_free(node);
223}
224
225
226void GlobalHandles::MakeWeak(Object** location, void* parameter,
227 WeakReferenceCallback callback) {
228 ASSERT(callback != NULL);
229 Node::FromLocation(location)->MakeWeak(parameter, callback);
230}
231
232
233void GlobalHandles::ClearWeakness(Object** location) {
234 Node::FromLocation(location)->ClearWeakness();
235}
236
237
238bool GlobalHandles::IsNearDeath(Object** location) {
239 return Node::FromLocation(location)->IsNearDeath();
240}
241
242
243bool GlobalHandles::IsWeak(Object** location) {
244 return Node::FromLocation(location)->IsWeak();
245}
246
247
248void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
249 // Traversal of GC roots in the global handle list that are marked as
250 // WEAK or PENDING.
251 for (Node* current = head_; current != NULL; current = current->next()) {
252 if (current->state_ == Node::WEAK
253 || current->state_ == Node::PENDING
254 || current->state_ == Node::NEAR_DEATH) {
255 v->VisitPointer(&current->object_);
256 }
257 }
258}
259
260
261void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) {
262 for (Node* current = head_; current != NULL; current = current->next()) {
263 if (current->state_ == Node::WEAK) {
264 if (f(&current->object_)) {
265 current->state_ = Node::PENDING;
266 LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
267 }
268 }
269 }
270}
271
272
273void GlobalHandles::PostGarbageCollectionProcessing() {
274 // Process weak global handle callbacks. This must be done after the
275 // GC is completely done, because the callbacks may invoke arbitrary
276 // API functions.
v8.team.kasperl727e9952008-09-02 14:56:44 +0000277 // At the same time deallocate all DESTROYED nodes
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278 ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
279 Node** p = &head_;
280 while (*p != NULL) {
281 (*p)->PostGarbageCollectionProcessing();
282 if ((*p)->state_ == Node::DESTROYED) {
283 // Delete the link.
284 Node* node = *p;
285 *p = node->next(); // Update the link.
286 delete node;
287 } else {
288 p = (*p)->next_addr();
289 }
290 }
291 set_first_free(NULL);
292}
293
294
295void GlobalHandles::IterateRoots(ObjectVisitor* v) {
296 // Traversal of global handles marked as NORMAL or NEAR_DEATH.
297 for (Node* current = head_; current != NULL; current = current->next()) {
298 if (current->state_ == Node::NORMAL) {
299 v->VisitPointer(&current->object_);
300 }
301 }
302}
303
304void GlobalHandles::TearDown() {
305 // Delete all the nodes in the linked list.
306 Node* current = head_;
307 while (current != NULL) {
308 Node* n = current;
309 current = current->next();
310 delete n;
311 }
312 // Reset the head and free_list.
313 set_head(NULL);
314 set_first_free(NULL);
315}
316
317
318int GlobalHandles::number_of_weak_handles_ = 0;
319int GlobalHandles::number_of_global_object_weak_handles_ = 0;
320
321GlobalHandles::Node* GlobalHandles::head_ = NULL;
322GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
323
324#ifdef DEBUG
325
326void GlobalHandles::PrintStats() {
327 int total = 0;
328 int weak = 0;
329 int pending = 0;
330 int near_death = 0;
331 int destroyed = 0;
332
333 for (Node* current = head_; current != NULL; current = current->next()) {
334 total++;
335 if (current->state_ == Node::WEAK) weak++;
336 if (current->state_ == Node::PENDING) pending++;
337 if (current->state_ == Node::NEAR_DEATH) near_death++;
338 if (current->state_ == Node::DESTROYED) destroyed++;
339 }
340
341 PrintF("Global Handle Statistics:\n");
342 PrintF(" allocated memory = %dB\n", sizeof(Node) * total);
343 PrintF(" # weak = %d\n", weak);
344 PrintF(" # pending = %d\n", pending);
345 PrintF(" # near_death = %d\n", near_death);
346 PrintF(" # destroyed = %d\n", destroyed);
347 PrintF(" # total = %d\n", total);
348}
349
350void GlobalHandles::Print() {
351 PrintF("Global handles:\n");
352 for (Node* current = head_; current != NULL; current = current->next()) {
353 PrintF(" handle %p to %p (weak=%d)\n", current->handle().location(),
354 *current->handle(), current->state_ == Node::WEAK);
355 }
356}
357
358#endif
359
ager@chromium.org8bb60582008-12-11 12:02:20 +0000360List<ObjectGroup*>* GlobalHandles::ObjectGroups() {
361 // Lazily initialize the list to avoid startup time static constructors.
362 static List<ObjectGroup*> groups(4);
363 return &groups;
364}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365
ager@chromium.org8bb60582008-12-11 12:02:20 +0000366void GlobalHandles::AddGroup(Object*** handles, size_t length) {
367 ObjectGroup* new_entry = new ObjectGroup(length);
368 for (size_t i = 0; i < length; ++i)
369 new_entry->objects_.Add(handles[i]);
370 ObjectGroups()->Add(new_entry);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371}
372
373
374void GlobalHandles::RemoveObjectGroups() {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000375 List<ObjectGroup*>* object_groups = ObjectGroups();
376 for (int i = 0; i< object_groups->length(); i++) {
377 delete object_groups->at(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000379 object_groups->Clear();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380}
381
382
383} } // namespace v8::internal