blob: 8c7dc8e5574cc096d2917c23cdcb035fbd9e171c [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2007-2008 Google Inc. All Rights Reserved.
2// 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()));
99 if (state_ != WEAK && !IsNearDeath()) {
100 GlobalHandles::number_of_weak_handles_++;
101 if (object_->IsJSGlobalObject()) {
102 GlobalHandles::number_of_global_object_weak_handles_++;
103 }
104 }
105 state_ = WEAK;
106 set_parameter(parameter);
107 callback_ = callback;
108 }
109
110 void ClearWeakness() {
111 LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
112 if (state_ == WEAK || IsNearDeath()) {
113 GlobalHandles::number_of_weak_handles_--;
114 if (object_->IsJSGlobalObject()) {
115 GlobalHandles::number_of_global_object_weak_handles_--;
116 }
117 }
118 state_ = NORMAL;
119 set_parameter(NULL);
120 }
121
122 bool IsNearDeath() {
123 // Check for PENDING to ensure correct answer when processing callbacks.
124 return state_ == PENDING || state_ == NEAR_DEATH;
125 }
126
127 bool IsWeak() {
128 return state_ == WEAK;
129 }
130
131 // Returns the id for this weak handle.
132 void set_parameter(void* parameter) {
133 ASSERT(state_ != DESTROYED);
134 parameter_or_next_free_.parameter = parameter;
135 }
136 void* parameter() {
137 ASSERT(state_ != DESTROYED);
138 return parameter_or_next_free_.parameter;
139 }
140
141 // Returns the callback for this weak handle.
142 WeakReferenceCallback callback() { return callback_; }
143
144 void PostGarbageCollectionProcessing() {
145 if (state_ != Node::PENDING) return;
146 LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
147 void* par = parameter();
148 state_ = NEAR_DEATH;
149 set_parameter(NULL);
150 // The callback function is resolved as late as possible to preserve old
151 // behavior.
152 WeakReferenceCallback func = callback();
153 if (func != NULL) {
154 func(v8::Persistent<v8::Object>(ToApi<v8::Object>(handle())), par);
155 }
156 }
157
158 // Place the handle address first to avoid offset computation.
159 Object* object_; // Storage for object pointer.
160
161 // Transition diagram:
162 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
163 enum State {
164 NORMAL, // Normal global handle.
165 WEAK, // Flagged as weak but not yet finalized.
166 PENDING, // Has been recognized as only reachable by weak handles.
167 NEAR_DEATH, // Callback has informed the handle is near death.
168 DESTROYED
169 };
170 State state_;
171
172 private:
173 // Handle specific callback.
174 WeakReferenceCallback callback_;
175 // Provided data for callback. In DESTROYED state, this is used for
176 // the free list link.
177 union {
178 void* parameter;
179 Node* next_free;
180 } parameter_or_next_free_;
181
182 // Linkage for the list.
183 Node* next_;
184
185 public:
186 TRACK_MEMORY("GlobalHandles::Node")
187};
188
189
190Handle<Object> GlobalHandles::Create(Object* value) {
191 Counters::global_handles.Increment();
192 Node* result;
193 if (first_free() == NULL) {
194 // Allocate a new node.
195 result = new Node(value);
196 result->set_next(head());
197 set_head(result);
198 } else {
199 // Take the first node in the free list.
200 result = first_free();
201 set_first_free(result->next_free());
202 result->Initialize(value);
203 }
204 return result->handle();
205}
206
207
208void GlobalHandles::Destroy(Object** location) {
209 Counters::global_handles.Decrement();
210 if (location == NULL) return;
211 Node* node = Node::FromLocation(location);
212 node->Destroy();
213 // Link the destroyed.
214 node->set_next_free(first_free());
215 set_first_free(node);
216}
217
218
219void GlobalHandles::MakeWeak(Object** location, void* parameter,
220 WeakReferenceCallback callback) {
221 ASSERT(callback != NULL);
222 Node::FromLocation(location)->MakeWeak(parameter, callback);
223}
224
225
226void GlobalHandles::ClearWeakness(Object** location) {
227 Node::FromLocation(location)->ClearWeakness();
228}
229
230
231bool GlobalHandles::IsNearDeath(Object** location) {
232 return Node::FromLocation(location)->IsNearDeath();
233}
234
235
236bool GlobalHandles::IsWeak(Object** location) {
237 return Node::FromLocation(location)->IsWeak();
238}
239
240
241void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
242 // Traversal of GC roots in the global handle list that are marked as
243 // WEAK or PENDING.
244 for (Node* current = head_; current != NULL; current = current->next()) {
245 if (current->state_ == Node::WEAK
246 || current->state_ == Node::PENDING
247 || current->state_ == Node::NEAR_DEATH) {
248 v->VisitPointer(&current->object_);
249 }
250 }
251}
252
253
254void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) {
255 for (Node* current = head_; current != NULL; current = current->next()) {
256 if (current->state_ == Node::WEAK) {
257 if (f(&current->object_)) {
258 current->state_ = Node::PENDING;
259 LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
260 }
261 }
262 }
263}
264
265
266void GlobalHandles::PostGarbageCollectionProcessing() {
267 // Process weak global handle callbacks. This must be done after the
268 // GC is completely done, because the callbacks may invoke arbitrary
269 // API functions.
270 // At the same time deallocate all DESTORYED nodes
271 ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
272 Node** p = &head_;
273 while (*p != NULL) {
274 (*p)->PostGarbageCollectionProcessing();
275 if ((*p)->state_ == Node::DESTROYED) {
276 // Delete the link.
277 Node* node = *p;
278 *p = node->next(); // Update the link.
279 delete node;
280 } else {
281 p = (*p)->next_addr();
282 }
283 }
284 set_first_free(NULL);
285}
286
287
288void GlobalHandles::IterateRoots(ObjectVisitor* v) {
289 // Traversal of global handles marked as NORMAL or NEAR_DEATH.
290 for (Node* current = head_; current != NULL; current = current->next()) {
291 if (current->state_ == Node::NORMAL) {
292 v->VisitPointer(&current->object_);
293 }
294 }
295}
296
297void GlobalHandles::TearDown() {
298 // Delete all the nodes in the linked list.
299 Node* current = head_;
300 while (current != NULL) {
301 Node* n = current;
302 current = current->next();
303 delete n;
304 }
305 // Reset the head and free_list.
306 set_head(NULL);
307 set_first_free(NULL);
308}
309
310
311int GlobalHandles::number_of_weak_handles_ = 0;
312int GlobalHandles::number_of_global_object_weak_handles_ = 0;
313
314GlobalHandles::Node* GlobalHandles::head_ = NULL;
315GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
316
317#ifdef DEBUG
318
319void GlobalHandles::PrintStats() {
320 int total = 0;
321 int weak = 0;
322 int pending = 0;
323 int near_death = 0;
324 int destroyed = 0;
325
326 for (Node* current = head_; current != NULL; current = current->next()) {
327 total++;
328 if (current->state_ == Node::WEAK) weak++;
329 if (current->state_ == Node::PENDING) pending++;
330 if (current->state_ == Node::NEAR_DEATH) near_death++;
331 if (current->state_ == Node::DESTROYED) destroyed++;
332 }
333
334 PrintF("Global Handle Statistics:\n");
335 PrintF(" allocated memory = %dB\n", sizeof(Node) * total);
336 PrintF(" # weak = %d\n", weak);
337 PrintF(" # pending = %d\n", pending);
338 PrintF(" # near_death = %d\n", near_death);
339 PrintF(" # destroyed = %d\n", destroyed);
340 PrintF(" # total = %d\n", total);
341}
342
343void GlobalHandles::Print() {
344 PrintF("Global handles:\n");
345 for (Node* current = head_; current != NULL; current = current->next()) {
346 PrintF(" handle %p to %p (weak=%d)\n", current->handle().location(),
347 *current->handle(), current->state_ == Node::WEAK);
348 }
349}
350
351#endif
352
353List<ObjectGroup*> GlobalHandles::object_groups_(4);
354
355void GlobalHandles::AddToGroup(void* id, Object** handle) {
356 for (int i = 0; i < object_groups_.length(); i++) {
357 ObjectGroup* entry = object_groups_[i];
358 if (entry->id_ == id) {
359 entry->objects_.Add(handle);
360 return;
361 }
362 }
363
364 // not found
365 ObjectGroup* new_entry = new ObjectGroup(id);
366 new_entry->objects_.Add(handle);
367 object_groups_.Add(new_entry);
368}
369
370
371void GlobalHandles::RemoveObjectGroups() {
372 for (int i = 0; i< object_groups_.length(); i++) {
373 delete object_groups_[i];
374 }
375 object_groups_.Clear();
376}
377
378
379} } // namespace v8::internal