Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: src/global-handles.cc

Issue 155540: Fasten global handles allocation. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/global-handles.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 15 matching lines...) Expand all
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h" 28 #include "v8.h"
29 29
30 #include "api.h" 30 #include "api.h"
31 #include "global-handles.h" 31 #include "global-handles.h"
32 32
33 namespace v8 { 33 namespace v8 {
34 namespace internal { 34 namespace internal {
35 35
36 class GlobalHandles::Node : public Malloced {
37 public:
38
39 void Initialize(Object* object) {
40 // Set the initial value of the handle.
41 object_ = object;
42 state_ = NORMAL;
43 parameter_or_next_free_.parameter = NULL;
44 callback_ = NULL;
45 }
46
47 explicit Node(Object* object) {
48 Initialize(object);
49 // Initialize link structure.
50 next_ = NULL;
51 }
52
53 ~Node() {
54 if (state_ != DESTROYED) Destroy();
55 #ifdef DEBUG
56 // Zap the values for eager trapping.
57 object_ = NULL;
58 next_ = NULL;
59 parameter_or_next_free_.next_free = NULL;
60 #endif
61 }
62
63 void Destroy() {
64 if (state_ == WEAK || IsNearDeath()) {
65 GlobalHandles::number_of_weak_handles_--;
66 if (object_->IsJSGlobalObject()) {
67 GlobalHandles::number_of_global_object_weak_handles_--;
68 }
69 }
70 state_ = DESTROYED;
71 }
72
73 // Accessors for next_.
74 Node* next() { return next_; }
75 void set_next(Node* value) { next_ = value; }
76 Node** next_addr() { return &next_; }
77
78 // Accessors for next free node in the free list.
79 Node* next_free() {
80 ASSERT(state_ == DESTROYED);
81 return parameter_or_next_free_.next_free;
82 }
83 void set_next_free(Node* value) {
84 ASSERT(state_ == DESTROYED);
85 parameter_or_next_free_.next_free = value;
86 }
87
88 // Returns a link from the handle.
89 static Node* FromLocation(Object** location) {
90 ASSERT(OFFSET_OF(Node, object_) == 0);
91 return reinterpret_cast<Node*>(location);
92 }
93
94 // Returns the handle.
95 Handle<Object> handle() { return Handle<Object>(&object_); }
96
97 // Make this handle weak.
98 void MakeWeak(void* parameter, WeakReferenceCallback callback) {
99 LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
100 ASSERT(state_ != DESTROYED);
101 if (state_ != WEAK && !IsNearDeath()) {
102 GlobalHandles::number_of_weak_handles_++;
103 if (object_->IsJSGlobalObject()) {
104 GlobalHandles::number_of_global_object_weak_handles_++;
105 }
106 }
107 state_ = WEAK;
108 set_parameter(parameter);
109 callback_ = callback;
110 }
111
112 void ClearWeakness() {
113 LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
114 ASSERT(state_ != DESTROYED);
115 if (state_ == WEAK || IsNearDeath()) {
116 GlobalHandles::number_of_weak_handles_--;
117 if (object_->IsJSGlobalObject()) {
118 GlobalHandles::number_of_global_object_weak_handles_--;
119 }
120 }
121 state_ = NORMAL;
122 set_parameter(NULL);
123 }
124
125 bool IsNearDeath() {
126 // Check for PENDING to ensure correct answer when processing callbacks.
127 return state_ == PENDING || state_ == NEAR_DEATH;
128 }
129
130 bool IsWeak() {
131 return state_ == WEAK;
132 }
133
134 // Returns the id for this weak handle.
135 void set_parameter(void* parameter) {
136 ASSERT(state_ != DESTROYED);
137 parameter_or_next_free_.parameter = parameter;
138 }
139 void* parameter() {
140 ASSERT(state_ != DESTROYED);
141 return parameter_or_next_free_.parameter;
142 }
143
144 // Returns the callback for this weak handle.
145 WeakReferenceCallback callback() { return callback_; }
146
147 void PostGarbageCollectionProcessing() {
148 if (state_ != Node::PENDING) return;
149 LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
150 void* par = parameter();
151 state_ = NEAR_DEATH;
152 set_parameter(NULL);
153 // The callback function is resolved as late as possible to preserve old
154 // behavior.
155 WeakReferenceCallback func = callback();
156 if (func != NULL) {
157 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
158 {
159 // Leaving V8.
160 VMState state(EXTERNAL);
161 func(object, par);
162 }
163 }
164 }
165
166 // Place the handle address first to avoid offset computation.
167 Object* object_; // Storage for object pointer.
168
169 // Transition diagram:
170 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
171 enum State {
172 NORMAL, // Normal global handle.
173 WEAK, // Flagged as weak but not yet finalized.
174 PENDING, // Has been recognized as only reachable by weak handles.
175 NEAR_DEATH, // Callback has informed the handle is near death.
176 DESTROYED
177 };
178 State state_;
179
180 private:
181 // Handle specific callback.
182 WeakReferenceCallback callback_;
183 // Provided data for callback. In DESTROYED state, this is used for
184 // the free list link.
185 union {
186 void* parameter;
187 Node* next_free;
188 } parameter_or_next_free_;
189
190 // Linkage for the list.
191 Node* next_;
192
193 public:
194 TRACK_MEMORY("GlobalHandles::Node")
195 };
196
197
198 Handle<Object> GlobalHandles::Create(Object* value) {
199 Counters::global_handles.Increment();
200 Node* result;
201 if (first_free() == NULL) {
202 // Allocate a new node.
203 result = new Node(value);
204 result->set_next(head());
205 set_head(result);
206 } else {
207 // Take the first node in the free list.
208 result = first_free();
209 set_first_free(result->next_free());
210 result->Initialize(value);
211 }
212 return result->handle();
213 }
214
215
216 void GlobalHandles::Destroy(Object** location) { 36 void GlobalHandles::Destroy(Object** location) {
217 Counters::global_handles.Decrement(); 37 Counters::global_handles.Decrement();
218 if (location == NULL) return; 38 if (location == NULL) return;
219 Node* node = Node::FromLocation(location); 39 Node* node = Node::FromLocation(location);
220 node->Destroy(); 40 node->Destroy();
221 // Link the destroyed. 41 // Link the destroyed.
222 node->set_next_free(first_free()); 42 node->set_next_free(first_free());
223 set_first_free(node); 43 set_first_free(node);
224 } 44 }
225 45
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 88 }
269 } 89 }
270 } 90 }
271 } 91 }
272 92
273 93
274 void GlobalHandles::PostGarbageCollectionProcessing() { 94 void GlobalHandles::PostGarbageCollectionProcessing() {
275 // Process weak global handle callbacks. This must be done after the 95 // Process weak global handle callbacks. This must be done after the
276 // GC is completely done, because the callbacks may invoke arbitrary 96 // GC is completely done, because the callbacks may invoke arbitrary
277 // API functions. 97 // API functions.
278 // At the same time deallocate all DESTROYED nodes 98 // At the same time deallocate all DESTROYED nodes.
279 ASSERT(Heap::gc_state() == Heap::NOT_IN_GC); 99 ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
280 Node** p = &head_; 100 Node** p = &head_;
281 while (*p != NULL) { 101 while (*p != NULL) {
282 (*p)->PostGarbageCollectionProcessing(); 102 (*p)->PostGarbageCollectionProcessing();
283 if ((*p)->state_ == Node::DESTROYED) { 103 if ((*p)->state_ == Node::DESTROYED) {
284 // Delete the link. 104 // Delete the link.
285 Node* node = *p; 105 Node* node = *p;
286 *p = node->next(); // Update the link. 106 *p = node->next(); // Update the link.
287 delete node; 107 if (first_deallocated()) {
108 first_deallocated()->set_next(node);
109 }
110 node->set_next_free(first_deallocated());
111 set_first_deallocated(node);
288 } else { 112 } else {
289 p = (*p)->next_addr(); 113 p = (*p)->next_addr();
290 } 114 }
291 } 115 }
292 set_first_free(NULL); 116 set_first_free(NULL);
117 if (first_deallocated()) {
118 first_deallocated()->set_next(head());
119 }
293 } 120 }
294 121
295 122
296 void GlobalHandles::IterateRoots(ObjectVisitor* v) { 123 void GlobalHandles::IterateRoots(ObjectVisitor* v) {
297 // Traversal of global handles marked as NORMAL or NEAR_DEATH. 124 // Traversal of global handles marked as NORMAL or NEAR_DEATH.
298 for (Node* current = head_; current != NULL; current = current->next()) { 125 for (Node* current = head_; current != NULL; current = current->next()) {
299 if (current->state_ == Node::NORMAL) { 126 if (current->state_ == Node::NORMAL) {
300 v->VisitPointer(&current->object_); 127 v->VisitPointer(&current->object_);
301 } 128 }
302 } 129 }
303 } 130 }
304 131
305 void GlobalHandles::TearDown() { 132 void GlobalHandles::TearDown() {
306 // Delete all the nodes in the linked list. 133 // Reset all the lists.
307 Node* current = head_;
308 while (current != NULL) {
309 Node* n = current;
310 current = current->next();
311 delete n;
312 }
313 // Reset the head and free_list.
314 set_head(NULL); 134 set_head(NULL);
315 set_first_free(NULL); 135 set_first_free(NULL);
136 set_first_deallocated(NULL);
137 pool_.Release();
316 } 138 }
317 139
318 140
319 int GlobalHandles::number_of_weak_handles_ = 0; 141 int GlobalHandles::number_of_weak_handles_ = 0;
320 int GlobalHandles::number_of_global_object_weak_handles_ = 0; 142 int GlobalHandles::number_of_global_object_weak_handles_ = 0;
321 143
322 GlobalHandles::Node* GlobalHandles::head_ = NULL; 144 GlobalHandles::Node* GlobalHandles::head_ = NULL;
323 GlobalHandles::Node* GlobalHandles::first_free_ = NULL; 145 GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
146 GlobalHandles::Node* GlobalHandles::first_deallocated_ = NULL;
147
148 GlobalHandles::Pool GlobalHandles::pool_;
324 149
325 #ifdef DEBUG 150 #ifdef DEBUG
326 151
327 void GlobalHandles::PrintStats() { 152 void GlobalHandles::PrintStats() {
328 int total = 0; 153 int total = 0;
329 int weak = 0; 154 int weak = 0;
330 int pending = 0; 155 int pending = 0;
331 int near_death = 0; 156 int near_death = 0;
332 int destroyed = 0; 157 int destroyed = 0;
333 158
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 199
375 void GlobalHandles::RemoveObjectGroups() { 200 void GlobalHandles::RemoveObjectGroups() {
376 List<ObjectGroup*>* object_groups = ObjectGroups(); 201 List<ObjectGroup*>* object_groups = ObjectGroups();
377 for (int i = 0; i< object_groups->length(); i++) { 202 for (int i = 0; i< object_groups->length(); i++) {
378 delete object_groups->at(i); 203 delete object_groups->at(i);
379 } 204 }
380 object_groups->Clear(); 205 object_groups->Clear();
381 } 206 }
382 207
383 208
209 void GlobalHandles::Node::Destroy() {
210 if (state_ == WEAK || IsNearDeath()) {
211 GlobalHandles::number_of_weak_handles_--;
212 if (object_->IsJSGlobalObject()) {
213 GlobalHandles::number_of_global_object_weak_handles_--;
214 }
215 }
216 state_ = DESTROYED;
217 }
218
219
220 void GlobalHandles::Node::MakeWeak(void* parameter,
221 WeakReferenceCallback callback) {
222 LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
223 ASSERT(state_ != DESTROYED);
224 if (state_ != WEAK && !IsNearDeath()) {
225 GlobalHandles::number_of_weak_handles_++;
226 if (object_->IsJSGlobalObject()) {
227 GlobalHandles::number_of_global_object_weak_handles_++;
228 }
229 }
230 state_ = WEAK;
231 set_parameter(parameter);
232 callback_ = callback;
233 }
234
235
236 void GlobalHandles::Node::ClearWeakness() {
237 LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
238 ASSERT(state_ != DESTROYED);
239 if (state_ == WEAK || IsNearDeath()) {
240 GlobalHandles::number_of_weak_handles_--;
241 if (object_->IsJSGlobalObject()) {
242 GlobalHandles::number_of_global_object_weak_handles_--;
243 }
244 }
245 state_ = NORMAL;
246 set_parameter(NULL);
247 }
248
249
250 void GlobalHandles::Node::PostGarbageCollectionProcessing() {
251 if (state_ != Node::PENDING) return;
252 LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
253 void* par = parameter();
254 state_ = NEAR_DEATH;
255 set_parameter(NULL);
256 // The callback function is resolved as late as possible to preserve old
257 // behavior.
258 WeakReferenceCallback func = callback();
259 if (func != NULL) {
260 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
261 {
262 // Leaving V8.
263 VMState state(EXTERNAL);
264 func(object, par);
265 }
266 }
267 }
268
269
270 GlobalHandles::Node* GlobalHandles::Pool::SlowAllocate() {
271 Chunk* chunk = new Chunk();
272 chunk->previous = current_;
273 current_ = chunk;
274
275 Node* new_nodes = current_->nodes;
276 next_ = new_nodes + 1;
277 limit_ = new_nodes + kNodesPerChunk;
278 return new_nodes;
279 }
280
281
282 void GlobalHandles::Pool::Release() {
283 Chunk* current = current_;
284 ASSERT(current != NULL); // At least a single block must be allocated
285 do {
286 Chunk* previous = current->previous;
287 delete current;
288 current = previous;
289 } while (current != NULL);
290 current_ = NULL;
291 next_ = limit_ = NULL;
292 }
293
294
384 } } // namespace v8::internal 295 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/global-handles.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698