OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 11 matching lines...) Loading... |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #ifndef V8_PROPERTY_H_ | 28 #ifndef V8_PROPERTY_H_ |
29 #define V8_PROPERTY_H_ | 29 #define V8_PROPERTY_H_ |
30 | 30 |
31 #include "allocation.h" | 31 #include "allocation.h" |
| 32 #include "transitions.h" |
32 | 33 |
33 namespace v8 { | 34 namespace v8 { |
34 namespace internal { | 35 namespace internal { |
35 | 36 |
36 | 37 |
37 // Abstraction for elements in instance-descriptor arrays. | 38 // Abstraction for elements in instance-descriptor arrays. |
38 // | 39 // |
39 // Each descriptor has a key, property attributes, property type, | 40 // Each descriptor has a key, property attributes, property type, |
40 // property index (in the actual instance-descriptor array) and | 41 // property index (in the actual instance-descriptor array) and |
41 // optionally a piece of data. | 42 // optionally a piece of data. |
(...skipping 19 matching lines...) Loading... |
61 | 62 |
62 #ifdef OBJECT_PRINT | 63 #ifdef OBJECT_PRINT |
63 void Print(FILE* out); | 64 void Print(FILE* out); |
64 #endif | 65 #endif |
65 | 66 |
66 void SetEnumerationIndex(int index) { | 67 void SetEnumerationIndex(int index) { |
67 ASSERT(PropertyDetails::IsValidIndex(index)); | 68 ASSERT(PropertyDetails::IsValidIndex(index)); |
68 details_ = PropertyDetails(details_.attributes(), details_.type(), index); | 69 details_ = PropertyDetails(details_.attributes(), details_.type(), index); |
69 } | 70 } |
70 | 71 |
71 bool ContainsTransition(); | |
72 | |
73 private: | 72 private: |
74 String* key_; | 73 String* key_; |
75 Object* value_; | 74 Object* value_; |
76 PropertyDetails details_; | 75 PropertyDetails details_; |
77 | 76 |
78 protected: | 77 protected: |
79 Descriptor() : details_(Smi::FromInt(0)) {} | 78 Descriptor() : details_(Smi::FromInt(0)) {} |
80 | 79 |
81 void Init(String* key, Object* value, PropertyDetails details) { | 80 void Init(String* key, Object* value, PropertyDetails details) { |
82 key_ = key; | 81 key_ = key; |
(...skipping 11 matching lines...) Loading... |
94 PropertyAttributes attributes, | 93 PropertyAttributes attributes, |
95 PropertyType type, | 94 PropertyType type, |
96 int index = 0) | 95 int index = 0) |
97 : key_(key), | 96 : key_(key), |
98 value_(value), | 97 value_(value), |
99 details_(attributes, type, index) { } | 98 details_(attributes, type, index) { } |
100 | 99 |
101 friend class DescriptorArray; | 100 friend class DescriptorArray; |
102 }; | 101 }; |
103 | 102 |
104 // A pointer from a map to the new map that is created by adding | |
105 // a named property. These are key to the speed and functioning of V8. | |
106 // The two maps should always have the same prototype, since | |
107 // MapSpace::CreateBackPointers depends on this. | |
108 class MapTransitionDescriptor: public Descriptor { | |
109 public: | |
110 MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes) | |
111 : Descriptor(key, map, attributes, MAP_TRANSITION) { } | |
112 }; | |
113 | |
114 // Marks a field name in a map so that adding the field is guaranteed | |
115 // to create a FIELD descriptor in the new map. Used after adding | |
116 // a constant function the first time, creating a CONSTANT_FUNCTION | |
117 // descriptor in the new map. This avoids creating multiple maps with | |
118 // the same CONSTANT_FUNCTION field. | |
119 class ConstTransitionDescriptor: public Descriptor { | |
120 public: | |
121 explicit ConstTransitionDescriptor(String* key, Map* map) | |
122 : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { } | |
123 }; | |
124 | |
125 | 103 |
126 class FieldDescriptor: public Descriptor { | 104 class FieldDescriptor: public Descriptor { |
127 public: | 105 public: |
128 FieldDescriptor(String* key, | 106 FieldDescriptor(String* key, |
129 int field_index, | 107 int field_index, |
130 PropertyAttributes attributes, | 108 PropertyAttributes attributes, |
131 int index = 0) | 109 int index = 0) |
132 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {} | 110 : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {} |
133 }; | 111 }; |
134 | 112 |
(...skipping 11 matching lines...) Loading... |
146 class CallbacksDescriptor: public Descriptor { | 124 class CallbacksDescriptor: public Descriptor { |
147 public: | 125 public: |
148 CallbacksDescriptor(String* key, | 126 CallbacksDescriptor(String* key, |
149 Object* foreign, | 127 Object* foreign, |
150 PropertyAttributes attributes, | 128 PropertyAttributes attributes, |
151 int index = 0) | 129 int index = 0) |
152 : Descriptor(key, foreign, attributes, CALLBACKS, index) {} | 130 : Descriptor(key, foreign, attributes, CALLBACKS, index) {} |
153 }; | 131 }; |
154 | 132 |
155 | 133 |
156 template <class T> | |
157 bool IsPropertyDescriptor(T* desc) { | |
158 switch (desc->type()) { | |
159 case NORMAL: | |
160 case FIELD: | |
161 case CONSTANT_FUNCTION: | |
162 case HANDLER: | |
163 case INTERCEPTOR: | |
164 return true; | |
165 case CALLBACKS: { | |
166 Object* callback_object = desc->GetCallbackObject(); | |
167 // Non-JavaScript (i.e. native) accessors are always a property, otherwise | |
168 // either the getter or the setter must be an accessor. Put another way: | |
169 // If we only see map transitions and holes in a pair, this is not a | |
170 // property. | |
171 return (!callback_object->IsAccessorPair() || | |
172 AccessorPair::cast(callback_object)->ContainsAccessor()); | |
173 } | |
174 case MAP_TRANSITION: | |
175 case CONSTANT_TRANSITION: | |
176 return false; | |
177 case NONEXISTENT: | |
178 UNREACHABLE(); | |
179 break; | |
180 } | |
181 UNREACHABLE(); // keep the compiler happy | |
182 return false; | |
183 } | |
184 | |
185 | |
186 class LookupResult BASE_EMBEDDED { | 134 class LookupResult BASE_EMBEDDED { |
187 public: | 135 public: |
188 explicit LookupResult(Isolate* isolate) | 136 explicit LookupResult(Isolate* isolate) |
189 : isolate_(isolate), | 137 : isolate_(isolate), |
190 next_(isolate->top_lookup_result()), | 138 next_(isolate->top_lookup_result()), |
191 lookup_type_(NOT_FOUND), | 139 lookup_type_(NOT_FOUND), |
192 holder_(NULL), | 140 holder_(NULL), |
193 cacheable_(true), | 141 cacheable_(true), |
194 details_(NONE, NONEXISTENT) { | 142 details_(NONE, NONEXISTENT) { |
195 isolate->SetTopLookupResult(this); | 143 isolate->SetTopLookupResult(this); |
196 } | 144 } |
197 | 145 |
198 ~LookupResult() { | 146 ~LookupResult() { |
199 ASSERT(isolate_->top_lookup_result() == this); | 147 ASSERT(isolate_->top_lookup_result() == this); |
200 isolate_->SetTopLookupResult(next_); | 148 isolate_->SetTopLookupResult(next_); |
201 } | 149 } |
202 | 150 |
203 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { | 151 void DescriptorResult(JSObject* holder, PropertyDetails details, int number) { |
204 lookup_type_ = DESCRIPTOR_TYPE; | 152 lookup_type_ = DESCRIPTOR_TYPE; |
205 holder_ = holder; | 153 holder_ = holder; |
206 details_ = details; | 154 details_ = details; |
207 number_ = number; | 155 number_ = number; |
208 } | 156 } |
209 | 157 |
| 158 void TransitionResult(JSObject* holder, int number) { |
| 159 lookup_type_ = TRANSITION_TYPE; |
| 160 details_ = PropertyDetails(NONE, TRANSITION); |
| 161 holder_ = holder; |
| 162 number_ = number; |
| 163 } |
| 164 |
210 void ConstantResult(JSObject* holder) { | 165 void ConstantResult(JSObject* holder) { |
211 lookup_type_ = CONSTANT_TYPE; | 166 lookup_type_ = CONSTANT_TYPE; |
212 holder_ = holder; | 167 holder_ = holder; |
213 details_ = | 168 details_ = |
214 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM | | 169 PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM | |
215 DONT_DELETE), | 170 DONT_DELETE), |
216 CALLBACKS); | 171 CALLBACKS); |
217 number_ = -1; | 172 number_ = -1; |
218 } | 173 } |
219 | 174 |
(...skipping 32 matching lines...) Loading... |
252 ASSERT(IsFound()); | 207 ASSERT(IsFound()); |
253 return JSProxy::cast(holder_); | 208 return JSProxy::cast(holder_); |
254 } | 209 } |
255 | 210 |
256 PropertyType type() { | 211 PropertyType type() { |
257 ASSERT(IsFound()); | 212 ASSERT(IsFound()); |
258 return details_.type(); | 213 return details_.type(); |
259 } | 214 } |
260 | 215 |
261 PropertyAttributes GetAttributes() { | 216 PropertyAttributes GetAttributes() { |
| 217 ASSERT(!IsTransition()); |
262 ASSERT(IsFound()); | 218 ASSERT(IsFound()); |
| 219 ASSERT(details_.type() != NONEXISTENT); |
263 return details_.attributes(); | 220 return details_.attributes(); |
264 } | 221 } |
265 | 222 |
266 PropertyDetails GetPropertyDetails() { | 223 PropertyDetails GetPropertyDetails() { |
| 224 ASSERT(!IsTransition()); |
267 return details_; | 225 return details_; |
268 } | 226 } |
269 | 227 |
270 bool IsFastPropertyType() { | 228 bool IsFastPropertyType() { |
271 ASSERT(IsFound()); | 229 ASSERT(IsFound()); |
272 return type() != NORMAL; | 230 return IsTransition() || type() != NORMAL; |
| 231 } |
| 232 |
| 233 // Property callbacks does not include transitions to callbacks. |
| 234 bool IsPropertyCallbacks() { |
| 235 ASSERT(!(details_.type() == CALLBACKS && !IsFound())); |
| 236 return details_.type() == CALLBACKS; |
| 237 } |
| 238 |
| 239 // Is callbacks contains both property callbacks and transitions to callbacks. |
| 240 bool IsCallbacks() { |
| 241 return IsPropertyCallbacks() || |
| 242 (IsTransition() && GetTransitionValue()->IsAccessorPair()); |
273 } | 243 } |
274 | 244 |
275 bool IsReadOnly() { | 245 bool IsReadOnly() { |
276 ASSERT(IsFound()); | 246 ASSERT(IsFound()); |
| 247 ASSERT(!IsTransition()); |
| 248 ASSERT(details_.type() != NONEXISTENT); |
277 return details_.IsReadOnly(); | 249 return details_.IsReadOnly(); |
278 } | 250 } |
279 | 251 |
280 bool IsCallbacks() { | |
281 ASSERT(!(details_.type() == CALLBACKS && !IsFound())); | |
282 return details_.type() == CALLBACKS; | |
283 } | |
284 | |
285 bool IsField() { | 252 bool IsField() { |
286 ASSERT(!(details_.type() == FIELD && !IsFound())); | 253 ASSERT(!(details_.type() == FIELD && !IsFound())); |
287 return details_.type() == FIELD; | 254 return details_.type() == FIELD; |
288 } | 255 } |
289 | 256 |
290 bool IsNormal() { | 257 bool IsNormal() { |
291 ASSERT(!(details_.type() == NORMAL && !IsFound())); | 258 ASSERT(!(details_.type() == NORMAL && !IsFound())); |
292 return details_.type() == NORMAL; | 259 return details_.type() == NORMAL; |
293 } | 260 } |
294 | 261 |
295 bool IsConstantFunction() { | 262 bool IsConstantFunction() { |
296 ASSERT(!(details_.type() == CONSTANT_FUNCTION && !IsFound())); | 263 ASSERT(!(details_.type() == CONSTANT_FUNCTION && !IsFound())); |
297 return details_.type() == CONSTANT_FUNCTION; | 264 return details_.type() == CONSTANT_FUNCTION; |
298 } | 265 } |
299 | 266 |
300 bool IsMapTransition() { | |
301 ASSERT(!(details_.type() == MAP_TRANSITION && !IsFound())); | |
302 return details_.type() == MAP_TRANSITION; | |
303 } | |
304 | |
305 bool IsDontDelete() { return details_.IsDontDelete(); } | 267 bool IsDontDelete() { return details_.IsDontDelete(); } |
306 bool IsDontEnum() { return details_.IsDontEnum(); } | 268 bool IsDontEnum() { return details_.IsDontEnum(); } |
307 bool IsDeleted() { return details_.IsDeleted(); } | 269 bool IsDeleted() { return details_.IsDeleted(); } |
308 bool IsFound() { return lookup_type_ != NOT_FOUND; } | 270 bool IsFound() { return lookup_type_ != NOT_FOUND; } |
| 271 bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; } |
309 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; } | 272 bool IsHandler() { return lookup_type_ == HANDLER_TYPE; } |
310 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; } | 273 bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; } |
311 | 274 |
312 // Is the result is a property excluding transitions and the null descriptor? | 275 // Is the result is a property excluding transitions and the null descriptor? |
313 bool IsProperty() { | 276 bool IsProperty() { |
314 return IsFound() && IsPropertyDescriptor(this); | 277 return IsFound() && !IsTransition(); |
315 } | 278 } |
316 | 279 |
317 bool IsCacheable() { return cacheable_; } | 280 bool IsCacheable() { return cacheable_; } |
318 void DisallowCaching() { cacheable_ = false; } | 281 void DisallowCaching() { cacheable_ = false; } |
319 | 282 |
320 Object* GetLazyValue() { | 283 Object* GetLazyValue() { |
321 switch (type()) { | 284 switch (type()) { |
322 case FIELD: | 285 case FIELD: |
323 return holder()->FastPropertyAt(GetFieldIndex()); | 286 return holder()->FastPropertyAt(GetFieldIndex()); |
324 case NORMAL: { | 287 case NORMAL: { |
325 Object* value; | 288 Object* value; |
326 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); | 289 value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry()); |
327 if (holder()->IsGlobalObject()) { | 290 if (holder()->IsGlobalObject()) { |
328 value = JSGlobalPropertyCell::cast(value)->value(); | 291 value = JSGlobalPropertyCell::cast(value)->value(); |
329 } | 292 } |
330 return value; | 293 return value; |
331 } | 294 } |
332 case CONSTANT_FUNCTION: | 295 case CONSTANT_FUNCTION: |
333 return GetConstantFunction(); | 296 return GetConstantFunction(); |
334 default: | 297 default: |
335 return Smi::FromInt(0); | 298 return Smi::FromInt(0); |
336 } | 299 } |
337 } | 300 } |
338 | 301 |
| 302 Object* GetTransitionValue() { |
| 303 ASSERT(IsTransition()); |
| 304 TransitionArray* transitions = holder()->map()->transitions(); |
| 305 Object* value = transitions->GetValue(number_); |
| 306 return value; |
| 307 } |
| 308 |
| 309 PropertyDetails GetTransitionDetails(Map* map) { |
| 310 ASSERT(IsTransition()); |
| 311 TransitionArray* transitions = map->transitions(); |
| 312 return transitions->GetTargetDetails(number_); |
| 313 } |
| 314 |
| 315 PropertyDetails GetTransitionDetails() { |
| 316 return GetTransitionDetails(holder()->map()); |
| 317 } |
| 318 |
| 319 bool IsTransitionToField(Map* map) { |
| 320 return IsTransition() && GetTransitionDetails(map).type() == FIELD; |
| 321 } |
| 322 |
339 Map* GetTransitionMap() { | 323 Map* GetTransitionMap() { |
340 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 324 ASSERT(IsTransition()); |
341 ASSERT(type() == MAP_TRANSITION || | |
342 type() == CONSTANT_TRANSITION); | |
343 return Map::cast(GetValue()); | 325 return Map::cast(GetValue()); |
344 } | 326 } |
345 | 327 |
346 Map* GetTransitionMapFromMap(Map* map) { | 328 Map* GetTransitionMapFromMap(Map* map) { |
347 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 329 ASSERT(IsTransition()); |
348 ASSERT(type() == MAP_TRANSITION); | 330 return Map::cast(map->transitions()->GetValue(number_)); |
349 return Map::cast(map->instance_descriptors()->GetValue(number_)); | |
350 } | 331 } |
351 | 332 |
352 int GetFieldIndex() { | 333 int GetFieldIndex() { |
353 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 334 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); |
354 ASSERT(IsField()); | 335 ASSERT(IsField()); |
355 return Descriptor::IndexFromValue(GetValue()); | 336 return Descriptor::IndexFromValue(GetValue()); |
356 } | 337 } |
357 | 338 |
358 int GetLocalFieldIndexFromMap(Map* map) { | 339 int GetLocalFieldIndexFromMap(Map* map) { |
359 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 340 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); |
(...skipping 13 matching lines...) Loading... |
373 return JSFunction::cast(GetValue()); | 354 return JSFunction::cast(GetValue()); |
374 } | 355 } |
375 | 356 |
376 JSFunction* GetConstantFunctionFromMap(Map* map) { | 357 JSFunction* GetConstantFunctionFromMap(Map* map) { |
377 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); | 358 ASSERT(lookup_type_ == DESCRIPTOR_TYPE); |
378 ASSERT(type() == CONSTANT_FUNCTION); | 359 ASSERT(type() == CONSTANT_FUNCTION); |
379 return JSFunction::cast(map->instance_descriptors()->GetValue(number_)); | 360 return JSFunction::cast(map->instance_descriptors()->GetValue(number_)); |
380 } | 361 } |
381 | 362 |
382 Object* GetCallbackObject() { | 363 Object* GetCallbackObject() { |
383 if (lookup_type_ == CONSTANT_TYPE) { | 364 switch (lookup_type_) { |
384 // For now we only have the __proto__ as constant type. | 365 case CONSTANT_TYPE: |
385 return HEAP->prototype_accessors(); | 366 return HEAP->prototype_accessors(); |
| 367 case TRANSITION_TYPE: |
| 368 return GetTransitionValue(); |
| 369 default: |
| 370 return GetValue(); |
386 } | 371 } |
387 return GetValue(); | |
388 } | 372 } |
389 | 373 |
390 #ifdef OBJECT_PRINT | 374 #ifdef OBJECT_PRINT |
391 void Print(FILE* out); | 375 void Print(FILE* out); |
392 #endif | 376 #endif |
393 | 377 |
394 Object* GetValue() { | 378 Object* GetValue() { |
395 if (lookup_type_ == DESCRIPTOR_TYPE) { | 379 if (lookup_type_ == DESCRIPTOR_TYPE) { |
396 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); | 380 DescriptorArray* descriptors = holder()->map()->instance_descriptors(); |
397 return descriptors->GetValue(number_); | 381 return descriptors->GetValue(number_); |
398 } | 382 } |
399 // In the dictionary case, the data is held in the value field. | 383 // In the dictionary case, the data is held in the value field. |
400 ASSERT(lookup_type_ == DICTIONARY_TYPE); | 384 ASSERT(lookup_type_ == DICTIONARY_TYPE); |
401 return holder()->GetNormalizedProperty(this); | 385 return holder()->GetNormalizedProperty(this); |
402 } | 386 } |
403 | 387 |
404 void Iterate(ObjectVisitor* visitor); | 388 void Iterate(ObjectVisitor* visitor); |
405 | 389 |
406 private: | 390 private: |
407 Isolate* isolate_; | 391 Isolate* isolate_; |
408 LookupResult* next_; | 392 LookupResult* next_; |
409 | 393 |
410 // Where did we find the result; | 394 // Where did we find the result; |
411 enum { | 395 enum { |
412 NOT_FOUND, | 396 NOT_FOUND, |
413 DESCRIPTOR_TYPE, | 397 DESCRIPTOR_TYPE, |
| 398 TRANSITION_TYPE, |
414 DICTIONARY_TYPE, | 399 DICTIONARY_TYPE, |
415 HANDLER_TYPE, | 400 HANDLER_TYPE, |
416 INTERCEPTOR_TYPE, | 401 INTERCEPTOR_TYPE, |
417 CONSTANT_TYPE | 402 CONSTANT_TYPE |
418 } lookup_type_; | 403 } lookup_type_; |
419 | 404 |
420 JSReceiver* holder_; | 405 JSReceiver* holder_; |
421 int number_; | 406 int number_; |
422 bool cacheable_; | 407 bool cacheable_; |
423 PropertyDetails details_; | 408 PropertyDetails details_; |
424 }; | 409 }; |
425 | 410 |
426 | 411 |
427 } } // namespace v8::internal | 412 } } // namespace v8::internal |
428 | 413 |
429 #endif // V8_PROPERTY_H_ | 414 #endif // V8_PROPERTY_H_ |
OLD | NEW |