| OLD | NEW |
| 1 // Copyright 2007-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2007-2008 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 ObjectGroup() : objects_(4) {} | 50 ObjectGroup() : objects_(4) {} |
| 51 explicit ObjectGroup(size_t capacity) : objects_(capacity) {} | 51 explicit ObjectGroup(size_t capacity) : objects_(capacity) {} |
| 52 | 52 |
| 53 List<Object**> objects_; | 53 List<Object**> objects_; |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 | 56 |
| 57 class GlobalHandles : public AllStatic { | 57 class GlobalHandles : public AllStatic { |
| 58 public: | 58 public: |
| 59 // Creates a new global handle that is alive until Destroy is called. | 59 // Creates a new global handle that is alive until Destroy is called. |
| 60 static Handle<Object> Create(Object* value); | 60 static Handle<Object> Create(Object* value) { |
| 61 Counters::global_handles.Increment(); |
| 62 Node* result; |
| 63 if (first_free()) { |
| 64 // Take the first node in the free list. |
| 65 result = first_free(); |
| 66 set_first_free(result->next_free()); |
| 67 } else if (first_deallocated()) { |
| 68 // Next try deallocated list |
| 69 result = first_deallocated(); |
| 70 set_first_deallocated(result->next_free()); |
| 71 set_head(result); |
| 72 } else { |
| 73 // Allocate a new node. |
| 74 result = pool_.Allocate(); |
| 75 result->set_next(head()); |
| 76 set_head(result); |
| 77 } |
| 78 result->Initialize(value); |
| 79 return result->handle(); |
| 80 } |
| 81 |
| 61 | 82 |
| 62 // Destroy a global handle. | 83 // Destroy a global handle. |
| 63 static void Destroy(Object** location); | 84 static void Destroy(Object** location); |
| 64 | 85 |
| 65 // Make the global handle weak and set the callback parameter for the | 86 // Make the global handle weak and set the callback parameter for the |
| 66 // handle. When the garbage collector recognizes that only weak global | 87 // handle. When the garbage collector recognizes that only weak global |
| 67 // handles point to an object the handles are cleared and the callback | 88 // handles point to an object the handles are cleared and the callback |
| 68 // function is invoked (for each handle) with the handle and corresponding | 89 // function is invoked (for each handle) with the handle and corresponding |
| 69 // parameter as arguments. Note: cleared means set to Smi::FromInt(0). The | 90 // parameter as arguments. Note: cleared means set to Smi::FromInt(0). The |
| 70 // reason is that Smi::FromInt(0) does not change during garage collection. | 91 // reason is that Smi::FromInt(0) does not change during garage collection. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 | 137 |
| 117 // Tear down the global handle structure. | 138 // Tear down the global handle structure. |
| 118 static void TearDown(); | 139 static void TearDown(); |
| 119 | 140 |
| 120 #ifdef DEBUG | 141 #ifdef DEBUG |
| 121 static void PrintStats(); | 142 static void PrintStats(); |
| 122 static void Print(); | 143 static void Print(); |
| 123 #endif | 144 #endif |
| 124 private: | 145 private: |
| 125 // Internal node structure, one for each global handle. | 146 // Internal node structure, one for each global handle. |
| 126 class Node; | 147 class Node { |
| 148 public: |
| 149 // Transition diagram: |
| 150 // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED } |
| 151 enum State { |
| 152 NORMAL, // Normal global handle. |
| 153 WEAK, // Flagged as weak but not yet finalized. |
| 154 PENDING, // Has been recognized as only reachable by weak handles. |
| 155 NEAR_DEATH, // Callback has informed the handle is near death. |
| 156 DESTROYED |
| 157 }; |
| 158 |
| 159 Node() { state_ = DESTROYED; } |
| 160 |
| 161 explicit Node(Object* object) { |
| 162 Initialize(object); |
| 163 // Initialize link structure. |
| 164 next_ = NULL; |
| 165 } |
| 166 |
| 167 ~Node() { |
| 168 if (state_ != DESTROYED) Destroy(); |
| 169 #ifdef DEBUG |
| 170 // Zap the values for eager trapping. |
| 171 object_ = NULL; |
| 172 next_ = NULL; |
| 173 parameter_or_next_free_.next_free = NULL; |
| 174 #endif |
| 175 } |
| 176 |
| 177 void Initialize(Object* object) { |
| 178 // Set the initial value of the handle. |
| 179 object_ = object; |
| 180 state_ = NORMAL; |
| 181 parameter_or_next_free_.parameter = NULL; |
| 182 callback_ = NULL; |
| 183 } |
| 184 |
| 185 void Destroy(); |
| 186 |
| 187 // Accessors for next_. |
| 188 Node* next() { return next_; } |
| 189 void set_next(Node* value) { next_ = value; } |
| 190 Node** next_addr() { return &next_; } |
| 191 |
| 192 // Accessors for next free node in the free list. |
| 193 Node* next_free() { |
| 194 ASSERT(state_ == DESTROYED); |
| 195 return parameter_or_next_free_.next_free; |
| 196 } |
| 197 void set_next_free(Node* value) { |
| 198 ASSERT(state_ == DESTROYED); |
| 199 parameter_or_next_free_.next_free = value; |
| 200 } |
| 201 |
| 202 // Returns a link from the handle. |
| 203 static Node* FromLocation(Object** location) { |
| 204 ASSERT(OFFSET_OF(Node, object_) == 0); |
| 205 return reinterpret_cast<Node*>(location); |
| 206 } |
| 207 |
| 208 // Returns the handle. |
| 209 Handle<Object> handle() { return Handle<Object>(&object_); } |
| 210 |
| 211 // Make this handle weak. |
| 212 void MakeWeak(void* parameter, WeakReferenceCallback callback); |
| 213 void ClearWeakness(); |
| 214 |
| 215 bool IsNearDeath() { |
| 216 // Check for PENDING to ensure correct answer when processing callbacks. |
| 217 return state_ == PENDING || state_ == NEAR_DEATH; |
| 218 } |
| 219 |
| 220 bool IsWeak() { |
| 221 return state_ == WEAK; |
| 222 } |
| 223 |
| 224 // Returns the id for this weak handle. |
| 225 void set_parameter(void* parameter) { |
| 226 ASSERT(state_ != DESTROYED); |
| 227 parameter_or_next_free_.parameter = parameter; |
| 228 } |
| 229 void* parameter() { |
| 230 ASSERT(state_ != DESTROYED); |
| 231 return parameter_or_next_free_.parameter; |
| 232 } |
| 233 |
| 234 // Returns the callback for this weak handle. |
| 235 WeakReferenceCallback callback() { return callback_; } |
| 236 |
| 237 void PostGarbageCollectionProcessing(); |
| 238 |
| 239 // Place the handle address first to avoid offset computation. |
| 240 Object* object_; // Storage for object pointer. |
| 241 |
| 242 State state_; |
| 243 |
| 244 private: |
| 245 // Handle specific callback. |
| 246 WeakReferenceCallback callback_; |
| 247 // Provided data for callback. In DESTROYED state, this is used for |
| 248 // the free list link. |
| 249 union { |
| 250 void* parameter; |
| 251 Node* next_free; |
| 252 } parameter_or_next_free_; |
| 253 |
| 254 // Linkage for the list. |
| 255 Node* next_; |
| 256 |
| 257 public: |
| 258 TRACK_MEMORY("GlobalHandles::Node") |
| 259 }; |
| 260 |
| 261 |
| 262 class Pool BASE_EMBEDDED { |
| 263 public: |
| 264 Pool() { |
| 265 current_ = new Chunk(); |
| 266 current_->previous = NULL; |
| 267 next_ = current_->nodes; |
| 268 limit_ = current_->nodes + kNodesPerChunk; |
| 269 } |
| 270 |
| 271 Node* Allocate() { |
| 272 if (next_ < limit_) { |
| 273 return next_++; |
| 274 } |
| 275 return SlowAllocate(); |
| 276 } |
| 277 |
| 278 void Release(); |
| 279 |
| 280 private: |
| 281 static const int kNodesPerChunk = 8192; |
| 282 struct Chunk : public Malloced { |
| 283 Chunk* previous; |
| 284 Node nodes[kNodesPerChunk]; |
| 285 }; |
| 286 |
| 287 Node* SlowAllocate(); |
| 288 |
| 289 Chunk* current_; |
| 290 Node* next_; |
| 291 Node* limit_; |
| 292 }; |
| 293 |
| 294 static Pool pool_; |
| 295 |
| 127 | 296 |
| 128 // Field always containing the number of weak and near-death handles. | 297 // Field always containing the number of weak and near-death handles. |
| 129 static int number_of_weak_handles_; | 298 static int number_of_weak_handles_; |
| 130 | 299 |
| 131 // Field always containing the number of weak and near-death handles | 300 // Field always containing the number of weak and near-death handles |
| 132 // to global objects. These objects are also included in | 301 // to global objects. These objects are also included in |
| 133 // number_of_weak_handles_. | 302 // number_of_weak_handles_. |
| 134 static int number_of_global_object_weak_handles_; | 303 static int number_of_global_object_weak_handles_; |
| 135 | 304 |
| 136 // Global handles are kept in a single linked list pointed to by head_. | 305 // Global handles are kept in a single linked list pointed to by head_. |
| 137 static Node* head_; | 306 static Node* head_; |
| 138 static Node* head() { return head_; } | 307 static Node* head() { return head_; } |
| 139 static void set_head(Node* value) { head_ = value; } | 308 static void set_head(Node* value) { head_ = value; } |
| 140 | 309 |
| 141 // Free list for DESTROYED global handles not yet deallocated. | 310 // Free list for DESTROYED global handles not yet deallocated. |
| 142 static Node* first_free_; | 311 static Node* first_free_; |
| 143 static Node* first_free() { return first_free_; } | 312 static Node* first_free() { return first_free_; } |
| 144 static void set_first_free(Node* value) { first_free_ = value; } | 313 static void set_first_free(Node* value) { first_free_ = value; } |
| 314 |
| 315 // List of deallocated nodes. Even though they are deallocated, |
| 316 // they keep correct next pointers, so allocating it back is just a matter |
| 317 // of setting head to it (and ajusting |first_deallocated_|) |
| 318 static Node* first_deallocated_; |
| 319 static Node* first_deallocated() { return first_deallocated_; } |
| 320 static void set_first_deallocated(Node* value) { |
| 321 first_deallocated_ = value; |
| 322 } |
| 145 }; | 323 }; |
| 146 | 324 |
| 147 | 325 |
| 148 } } // namespace v8::internal | 326 } } // namespace v8::internal |
| 149 | 327 |
| 150 #endif // V8_GLOBAL_HANDLES_H_ | 328 #endif // V8_GLOBAL_HANDLES_H_ |
| OLD | NEW |