Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 23 matching lines...) Expand all Loading... | |
| 34 | 34 |
| 35 namespace v8 { | 35 namespace v8 { |
| 36 namespace internal { | 36 namespace internal { |
| 37 | 37 |
| 38 | 38 |
| 39 ObjectGroup::~ObjectGroup() { | 39 ObjectGroup::~ObjectGroup() { |
| 40 if (info_ != NULL) info_->Dispose(); | 40 if (info_ != NULL) info_->Dispose(); |
| 41 } | 41 } |
| 42 | 42 |
| 43 | 43 |
| 44 const uint8_t NodeIndependentFlag = 6; | |
| 45 const uint8_t NodePartiallyDependentFlag = 5; | |
| 46 const uint8_t NodeInNewSpaceListFlag = 4; | |
| 47 const uint8_t NodeIndependentFlagMask = 1 << NodeIndependentFlag; | |
| 48 const uint8_t NodePartiallyDependentFlagMask = 1 << NodePartiallyDependentFlag; | |
| 49 const uint8_t NodeInNewSpaceListFlagMask = 1 << NodeInNewSpaceListFlag; | |
| 50 const uint8_t NodeStateMask = 0xf; | |
| 51 | |
| 52 | |
| 44 class GlobalHandles::Node { | 53 class GlobalHandles::Node { |
| 45 public: | 54 public: |
| 46 // State transition diagram: | 55 // State transition diagram: |
| 47 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } | 56 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } |
| 48 enum State { | 57 enum State { |
| 49 FREE, | 58 FREE = 0, |
| 50 NORMAL, // Normal global handle. | 59 NORMAL, // Normal global handle. |
| 51 WEAK, // Flagged as weak but not yet finalized. | 60 WEAK, // Flagged as weak but not yet finalized. |
| 52 PENDING, // Has been recognized as only reachable by weak handles. | 61 PENDING, // Has been recognized as only reachable by weak handles. |
| 53 NEAR_DEATH // Callback has informed the handle is near death. | 62 NEAR_DEATH // Callback has informed the handle is near death. |
| 54 }; | 63 }; |
| 55 | 64 |
| 56 // Maps handle location (slot) to the containing node. | 65 // Maps handle location (slot) to the containing node. |
| 57 static Node* FromLocation(Object** location) { | 66 static Node* FromLocation(Object** location) { |
| 58 ASSERT(OFFSET_OF(Node, object_) == 0); | 67 ASSERT(OFFSET_OF(Node, object_) == 0); |
| 59 return reinterpret_cast<Node*>(location); | 68 return reinterpret_cast<Node*>(location); |
| 60 } | 69 } |
| 61 | 70 |
| 62 Node() {} | 71 Node() {} |
| 63 | 72 |
| 64 #ifdef DEBUG | 73 #ifdef DEBUG |
| 65 ~Node() { | 74 ~Node() { |
| 66 // TODO(1428): if it's a weak handle we should have invoked its callback. | 75 // TODO(1428): if it's a weak handle we should have invoked its callback. |
| 67 // Zap the values for eager trapping. | 76 // Zap the values for eager trapping. |
| 68 object_ = NULL; | 77 object_ = NULL; |
| 69 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 78 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
| 70 index_ = 0; | 79 index_ = 0; |
| 71 independent_ = false; | 80 set_independent(false); |
| 72 partially_dependent_ = false; | 81 set_partially_dependent_(false); |
| 73 in_new_space_list_ = false; | 82 set_in_new_space_list_(false); |
| 74 parameter_or_next_free_.next_free = NULL; | 83 parameter_or_next_free_.next_free = NULL; |
| 75 callback_ = NULL; | 84 callback_ = NULL; |
| 76 } | 85 } |
| 77 #endif | 86 #endif |
| 78 | 87 |
| 79 void Initialize(int index, Node** first_free) { | 88 void Initialize(int index, Node** first_free) { |
| 80 index_ = static_cast<uint8_t>(index); | 89 index_ = static_cast<uint8_t>(index); |
| 81 ASSERT(static_cast<int>(index_) == index); | 90 ASSERT(static_cast<int>(index_) == index); |
| 82 state_ = FREE; | 91 set_state(FREE); |
| 83 in_new_space_list_ = false; | 92 set_in_new_space_list(false); |
| 84 parameter_or_next_free_.next_free = *first_free; | 93 parameter_or_next_free_.next_free = *first_free; |
| 85 *first_free = this; | 94 *first_free = this; |
| 86 } | 95 } |
| 87 | 96 |
| 88 void Acquire(Object* object, GlobalHandles* global_handles) { | 97 void Acquire(Object* object, GlobalHandles* global_handles) { |
| 89 ASSERT(state_ == FREE); | 98 ASSERT(state() == FREE); |
| 90 object_ = object; | 99 object_ = object; |
| 91 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 100 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
| 92 independent_ = false; | 101 set_independent(false); |
| 93 partially_dependent_ = false; | 102 set_partially_dependent(false); |
| 94 state_ = NORMAL; | 103 set_state(NORMAL); |
| 95 parameter_or_next_free_.parameter = NULL; | 104 parameter_or_next_free_.parameter = NULL; |
| 96 callback_ = NULL; | 105 callback_ = NULL; |
| 97 IncreaseBlockUses(global_handles); | 106 IncreaseBlockUses(global_handles); |
| 98 } | 107 } |
| 99 | 108 |
| 100 void Release(GlobalHandles* global_handles) { | 109 void Release(GlobalHandles* global_handles) { |
| 101 ASSERT(state_ != FREE); | 110 ASSERT(state() != FREE); |
| 102 if (IsWeakRetainer()) { | 111 if (IsWeakRetainer()) { |
| 103 global_handles->number_of_weak_handles_--; | 112 global_handles->number_of_weak_handles_--; |
| 104 if (object_->IsJSGlobalObject()) { | 113 if (object_->IsJSGlobalObject()) { |
| 105 global_handles->number_of_global_object_weak_handles_--; | 114 global_handles->number_of_global_object_weak_handles_--; |
| 106 } | 115 } |
| 107 } | 116 } |
| 108 state_ = FREE; | 117 set_state(FREE); |
| 109 parameter_or_next_free_.next_free = global_handles->first_free_; | 118 parameter_or_next_free_.next_free = global_handles->first_free_; |
| 110 global_handles->first_free_ = this; | 119 global_handles->first_free_ = this; |
| 111 DecreaseBlockUses(global_handles); | 120 DecreaseBlockUses(global_handles); |
| 112 } | 121 } |
| 113 | 122 |
| 114 // Object slot accessors. | 123 // Object slot accessors. |
| 115 Object* object() const { return object_; } | 124 Object* object() const { return object_; } |
| 116 Object** location() { return &object_; } | 125 Object** location() { return &object_; } |
| 117 Handle<Object> handle() { return Handle<Object>(location()); } | 126 Handle<Object> handle() { return Handle<Object>(location()); } |
| 118 | 127 |
| 119 // Wrapper class ID accessors. | 128 // Wrapper class ID accessors. |
| 120 bool has_wrapper_class_id() const { | 129 bool has_wrapper_class_id() const { |
| 121 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; | 130 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; |
| 122 } | 131 } |
| 132 | |
| 123 uint16_t wrapper_class_id() const { return class_id_; } | 133 uint16_t wrapper_class_id() const { return class_id_; } |
| 124 void set_wrapper_class_id(uint16_t class_id) { | 134 void set_wrapper_class_id(uint16_t class_id) { |
| 125 class_id_ = class_id; | 135 class_id_ = static_cast<uint8_t>(class_id); |
|
Michael Starzinger
2013/01/15 09:06:41
The class_id is a full 16 bit, we can drop this ca
haraken
2013/01/15 09:40:39
Done.
| |
| 126 } | 136 } |
| 127 | 137 |
| 128 // State accessors. | 138 // State and flag accessors. |
| 129 | 139 |
| 130 State state() const { return state_; } | 140 State state() const { |
| 141 return static_cast<State>(flags_and_state_ & NodeStateMask); | |
|
Michael Starzinger
2013/01/15 09:06:41
Instead of using all of this hand-written magic, c
haraken
2013/01/15 09:40:39
Done.
| |
| 142 } | |
| 143 void set_state(State state) { | |
| 144 flags_and_state_ = | |
| 145 (flags_and_state_ & ~NodeStateMask) | state; | |
| 146 } | |
| 147 | |
| 148 bool is_independent() { | |
| 149 return flags_and_state_ & NodeIndependentFlagMask; | |
| 150 } | |
| 151 void set_independent(bool v) { | |
| 152 flags_and_state_ = | |
| 153 (flags_and_state_ & ~NodeIndependentFlagMask) | | |
| 154 (static_cast<uint8_t>(v) << NodeIndependentFlag); | |
| 155 } | |
| 156 | |
| 157 bool is_partially_dependent() { | |
| 158 return flags_and_state_ & NodePartiallyDependentFlagMask; | |
| 159 } | |
| 160 void set_partially_dependent(bool v) { | |
| 161 flags_and_state_ = | |
| 162 (flags_and_state_ & ~NodePartiallyDependentFlagMask) | | |
| 163 (static_cast<uint8_t>(v) << NodePartiallyDependentFlag); | |
| 164 } | |
| 165 | |
| 166 bool is_in_new_space_list() { | |
| 167 return flags_and_state_ & NodeInNewSpaceListFlagMask; | |
| 168 } | |
| 169 void set_in_new_space_list(bool v) { | |
| 170 flags_and_state_ = | |
| 171 (flags_and_state_ & ~NodeInNewSpaceListFlagMask) | | |
| 172 (static_cast<uint8_t>(v) << NodeInNewSpaceListFlag); | |
| 173 } | |
| 131 | 174 |
| 132 bool IsNearDeath() const { | 175 bool IsNearDeath() const { |
| 133 // Check for PENDING to ensure correct answer when processing callbacks. | 176 // Check for PENDING to ensure correct answer when processing callbacks. |
| 134 return state_ == PENDING || state_ == NEAR_DEATH; | 177 return state() == PENDING || state() == NEAR_DEATH; |
| 135 } | 178 } |
| 136 | 179 |
| 137 bool IsWeak() const { return state_ == WEAK; } | 180 bool IsWeak() const { return state() == WEAK; } |
| 138 | 181 |
| 139 bool IsRetainer() const { return state_ != FREE; } | 182 bool IsRetainer() const { return state() != FREE; } |
| 140 | 183 |
| 141 bool IsStrongRetainer() const { return state_ == NORMAL; } | 184 bool IsStrongRetainer() const { return state() == NORMAL; } |
| 142 | 185 |
| 143 bool IsWeakRetainer() const { | 186 bool IsWeakRetainer() const { |
| 144 return state_ == WEAK || state_ == PENDING || state_ == NEAR_DEATH; | 187 return state() == WEAK || state() == PENDING || state() == NEAR_DEATH; |
| 145 } | 188 } |
| 146 | 189 |
| 147 void MarkPending() { | 190 void MarkPending() { |
| 148 ASSERT(state_ == WEAK); | 191 ASSERT(state() == WEAK); |
| 149 state_ = PENDING; | 192 set_state(PENDING); |
| 150 } | 193 } |
| 151 | 194 |
| 152 // Independent flag accessors. | 195 // Independent flag accessors. |
| 153 void MarkIndependent() { | 196 void MarkIndependent() { |
| 154 ASSERT(state_ != FREE); | 197 ASSERT(state() != FREE); |
| 155 independent_ = true; | 198 set_independent(true); |
| 156 } | 199 } |
| 157 bool is_independent() const { return independent_; } | |
| 158 | 200 |
| 159 void MarkPartiallyDependent(GlobalHandles* global_handles) { | 201 void MarkPartiallyDependent(GlobalHandles* global_handles) { |
| 160 ASSERT(state_ != FREE); | 202 ASSERT(state() != FREE); |
| 161 if (global_handles->isolate()->heap()->InNewSpace(object_)) { | 203 if (global_handles->isolate()->heap()->InNewSpace(object_)) { |
| 162 partially_dependent_ = true; | 204 set_partially_dependent(true); |
| 163 } | 205 } |
| 164 } | 206 } |
| 165 bool is_partially_dependent() const { return partially_dependent_; } | 207 void clear_partially_dependent() { set_partially_dependent(false); } |
| 166 void clear_partially_dependent() { partially_dependent_ = false; } | |
| 167 | |
| 168 // In-new-space-list flag accessors. | |
| 169 void set_in_new_space_list(bool v) { in_new_space_list_ = v; } | |
| 170 bool is_in_new_space_list() const { return in_new_space_list_; } | |
| 171 | 208 |
| 172 // Callback accessor. | 209 // Callback accessor. |
| 173 WeakReferenceCallback callback() { return callback_; } | 210 WeakReferenceCallback callback() { return callback_; } |
| 174 | 211 |
| 175 // Callback parameter accessors. | 212 // Callback parameter accessors. |
| 176 void set_parameter(void* parameter) { | 213 void set_parameter(void* parameter) { |
| 177 ASSERT(state_ != FREE); | 214 ASSERT(state() != FREE); |
| 178 parameter_or_next_free_.parameter = parameter; | 215 parameter_or_next_free_.parameter = parameter; |
| 179 } | 216 } |
| 180 void* parameter() const { | 217 void* parameter() const { |
| 181 ASSERT(state_ != FREE); | 218 ASSERT(state() != FREE); |
| 182 return parameter_or_next_free_.parameter; | 219 return parameter_or_next_free_.parameter; |
| 183 } | 220 } |
| 184 | 221 |
| 185 // Accessors for next free node in the free list. | 222 // Accessors for next free node in the free list. |
| 186 Node* next_free() { | 223 Node* next_free() { |
| 187 ASSERT(state_ == FREE); | 224 ASSERT(state() == FREE); |
| 188 return parameter_or_next_free_.next_free; | 225 return parameter_or_next_free_.next_free; |
| 189 } | 226 } |
| 190 void set_next_free(Node* value) { | 227 void set_next_free(Node* value) { |
| 191 ASSERT(state_ == FREE); | 228 ASSERT(state() == FREE); |
| 192 parameter_or_next_free_.next_free = value; | 229 parameter_or_next_free_.next_free = value; |
| 193 } | 230 } |
| 194 | 231 |
| 195 void MakeWeak(GlobalHandles* global_handles, | 232 void MakeWeak(GlobalHandles* global_handles, |
| 196 void* parameter, | 233 void* parameter, |
| 197 WeakReferenceCallback callback) { | 234 WeakReferenceCallback callback) { |
| 198 ASSERT(state_ != FREE); | 235 ASSERT(state() != FREE); |
| 199 if (!IsWeakRetainer()) { | 236 if (!IsWeakRetainer()) { |
| 200 global_handles->number_of_weak_handles_++; | 237 global_handles->number_of_weak_handles_++; |
| 201 if (object_->IsJSGlobalObject()) { | 238 if (object_->IsJSGlobalObject()) { |
| 202 global_handles->number_of_global_object_weak_handles_++; | 239 global_handles->number_of_global_object_weak_handles_++; |
| 203 } | 240 } |
| 204 } | 241 } |
| 205 state_ = WEAK; | 242 set_state(WEAK); |
| 206 set_parameter(parameter); | 243 set_parameter(parameter); |
| 207 callback_ = callback; | 244 callback_ = callback; |
| 208 } | 245 } |
| 209 | 246 |
| 210 void ClearWeakness(GlobalHandles* global_handles) { | 247 void ClearWeakness(GlobalHandles* global_handles) { |
| 211 ASSERT(state_ != FREE); | 248 ASSERT(state() != FREE); |
| 212 if (IsWeakRetainer()) { | 249 if (IsWeakRetainer()) { |
| 213 global_handles->number_of_weak_handles_--; | 250 global_handles->number_of_weak_handles_--; |
| 214 if (object_->IsJSGlobalObject()) { | 251 if (object_->IsJSGlobalObject()) { |
| 215 global_handles->number_of_global_object_weak_handles_--; | 252 global_handles->number_of_global_object_weak_handles_--; |
| 216 } | 253 } |
| 217 } | 254 } |
| 218 state_ = NORMAL; | 255 set_state(NORMAL); |
| 219 set_parameter(NULL); | 256 set_parameter(NULL); |
| 220 } | 257 } |
| 221 | 258 |
| 222 bool PostGarbageCollectionProcessing(Isolate* isolate, | 259 bool PostGarbageCollectionProcessing(Isolate* isolate, |
| 223 GlobalHandles* global_handles) { | 260 GlobalHandles* global_handles) { |
| 224 if (state_ != Node::PENDING) return false; | 261 if (state() != Node::PENDING) return false; |
| 225 WeakReferenceCallback func = callback(); | 262 WeakReferenceCallback func = callback(); |
| 226 if (func == NULL) { | 263 if (func == NULL) { |
| 227 Release(global_handles); | 264 Release(global_handles); |
| 228 return false; | 265 return false; |
| 229 } | 266 } |
| 230 void* par = parameter(); | 267 void* par = parameter(); |
| 231 state_ = NEAR_DEATH; | 268 set_state(NEAR_DEATH); |
| 232 set_parameter(NULL); | 269 set_parameter(NULL); |
| 233 | 270 |
| 234 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); | 271 v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle()); |
| 235 { | 272 { |
| 236 // Check that we are not passing a finalized external string to | 273 // Check that we are not passing a finalized external string to |
| 237 // the callback. | 274 // the callback. |
| 238 ASSERT(!object_->IsExternalAsciiString() || | 275 ASSERT(!object_->IsExternalAsciiString() || |
| 239 ExternalAsciiString::cast(object_)->resource() != NULL); | 276 ExternalAsciiString::cast(object_)->resource() != NULL); |
| 240 ASSERT(!object_->IsExternalTwoByteString() || | 277 ASSERT(!object_->IsExternalTwoByteString() || |
| 241 ExternalTwoByteString::cast(object_)->resource() != NULL); | 278 ExternalTwoByteString::cast(object_)->resource() != NULL); |
| 242 // Leaving V8. | 279 // Leaving V8. |
| 243 VMState state(isolate, EXTERNAL); | 280 VMState state(isolate, EXTERNAL); |
| 244 func(object, par); | 281 func(object, par); |
| 245 } | 282 } |
| 246 // Absence of explicit cleanup or revival of weak handle | 283 // Absence of explicit cleanup or revival of weak handle |
| 247 // in most of the cases would lead to memory leak. | 284 // in most of the cases would lead to memory leak. |
| 248 ASSERT(state_ != NEAR_DEATH); | 285 ASSERT(state() != NEAR_DEATH); |
| 249 return true; | 286 return true; |
| 250 } | 287 } |
| 251 | 288 |
| 252 private: | 289 private: |
| 253 inline NodeBlock* FindBlock(); | 290 inline NodeBlock* FindBlock(); |
| 254 inline void IncreaseBlockUses(GlobalHandles* global_handles); | 291 inline void IncreaseBlockUses(GlobalHandles* global_handles); |
| 255 inline void DecreaseBlockUses(GlobalHandles* global_handles); | 292 inline void DecreaseBlockUses(GlobalHandles* global_handles); |
| 256 | 293 |
| 257 // Storage for object pointer. | 294 // Storage for object pointer. |
| 258 // Placed first to avoid offset computation. | 295 // Placed first to avoid offset computation. |
| 259 Object* object_; | 296 Object* object_; |
| 260 | 297 |
| 261 // Next word stores class_id, index, state, and independent. | 298 // Next word stores class_id, index, state, and independent. |
| 262 // Note: the most aligned fields should go first. | 299 // Note: the most aligned fields should go first. |
| 263 | 300 |
| 264 // Wrapper class ID. | 301 // Wrapper class ID. |
| 265 uint16_t class_id_; | 302 uint16_t class_id_; |
| 266 | 303 |
| 267 // Index in the containing handle block. | 304 // Index in the containing handle block. |
| 268 uint8_t index_; | 305 uint8_t index_; |
| 269 | 306 |
| 270 // Need one more bit for MSVC as it treats enums as signed. | 307 // This stores three flags (independent, partially_dependent and |
| 271 State state_ : 4; | 308 // in_new_space_list) and a State. |
| 272 | 309 uint8_t flags_and_state_; |
|
Michael Starzinger
2013/01/15 09:06:41
Let's just call this field "flags_".
haraken
2013/01/15 09:40:39
Done.
| |
| 273 bool independent_ : 1; | |
| 274 bool partially_dependent_ : 1; | |
| 275 bool in_new_space_list_ : 1; | |
| 276 | 310 |
| 277 // Handle specific callback. | 311 // Handle specific callback. |
| 278 WeakReferenceCallback callback_; | 312 WeakReferenceCallback callback_; |
| 279 | 313 |
| 280 // Provided data for callback. In FREE state, this is used for | 314 // Provided data for callback. In FREE state, this is used for |
| 281 // the free list link. | 315 // the free list link. |
| 282 union { | 316 union { |
| 283 void* parameter; | 317 void* parameter; |
| 284 Node* next_free; | 318 Node* next_free; |
| 285 } parameter_or_next_free_; | 319 } parameter_or_next_free_; |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 implicit_ref_groups_.Clear(); | 832 implicit_ref_groups_.Clear(); |
| 799 } | 833 } |
| 800 | 834 |
| 801 | 835 |
| 802 void GlobalHandles::TearDown() { | 836 void GlobalHandles::TearDown() { |
| 803 // TODO(1428): invoke weak callbacks. | 837 // TODO(1428): invoke weak callbacks. |
| 804 } | 838 } |
| 805 | 839 |
| 806 | 840 |
| 807 } } // namespace v8::internal | 841 } } // namespace v8::internal |
| OLD | NEW |