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