Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / property.h
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_PROPERTY_H_
6 #define V8_PROPERTY_H_
7
8 #include "src/factory.h"
9 #include "src/field-index.h"
10 #include "src/field-index-inl.h"
11 #include "src/isolate.h"
12 #include "src/types.h"
13
14 namespace v8 {
15 namespace internal {
16
17 class OStream;
18
19 // Abstraction for elements in instance-descriptor arrays.
20 //
21 // Each descriptor has a key, property attributes, property type,
22 // property index (in the actual instance-descriptor array) and
23 // optionally a piece of data.
24 class Descriptor BASE_EMBEDDED {
25  public:
26   void KeyToUniqueName() {
27     if (!key_->IsUniqueName()) {
28       key_ = key_->GetIsolate()->factory()->InternalizeString(
29           Handle<String>::cast(key_));
30     }
31   }
32
33   Handle<Name> GetKey() const { return key_; }
34   Handle<Object> GetValue() const { return value_; }
35   PropertyDetails GetDetails() const { return details_; }
36
37   void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
38
39  private:
40   Handle<Name> key_;
41   Handle<Object> value_;
42   PropertyDetails details_;
43
44  protected:
45   Descriptor() : details_(Smi::FromInt(0)) {}
46
47   void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
48     key_ = key;
49     value_ = value;
50     details_ = details;
51   }
52
53   Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
54       : key_(key),
55         value_(value),
56         details_(details) { }
57
58   Descriptor(Handle<Name> key,
59              Handle<Object> value,
60              PropertyAttributes attributes,
61              PropertyType type,
62              Representation representation,
63              int field_index = 0)
64       : key_(key),
65         value_(value),
66         details_(attributes, type, representation, field_index) { }
67
68   friend class DescriptorArray;
69   friend class Map;
70 };
71
72
73 OStream& operator<<(OStream& os, const Descriptor& d);
74
75
76 class FieldDescriptor V8_FINAL : public Descriptor {
77  public:
78   FieldDescriptor(Handle<Name> key,
79                   int field_index,
80                   PropertyAttributes attributes,
81                   Representation representation)
82       : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
83                    FIELD, representation, field_index) {}
84   FieldDescriptor(Handle<Name> key,
85                   int field_index,
86                   Handle<HeapType> field_type,
87                   PropertyAttributes attributes,
88                   Representation representation)
89       : Descriptor(key, field_type, attributes, FIELD,
90                    representation, field_index) { }
91 };
92
93
94 class ConstantDescriptor V8_FINAL : public Descriptor {
95  public:
96   ConstantDescriptor(Handle<Name> key,
97                      Handle<Object> value,
98                      PropertyAttributes attributes)
99       : Descriptor(key, value, attributes, CONSTANT,
100                    value->OptimalRepresentation()) {}
101 };
102
103
104 class CallbacksDescriptor V8_FINAL : public Descriptor {
105  public:
106   CallbacksDescriptor(Handle<Name> key,
107                       Handle<Object> foreign,
108                       PropertyAttributes attributes)
109       : Descriptor(key, foreign, attributes, CALLBACKS,
110                    Representation::Tagged()) {}
111 };
112
113
114 class LookupResult V8_FINAL BASE_EMBEDDED {
115  public:
116   explicit LookupResult(Isolate* isolate)
117       : isolate_(isolate),
118         next_(isolate->top_lookup_result()),
119         lookup_type_(NOT_FOUND),
120         holder_(NULL),
121         transition_(NULL),
122         cacheable_(true),
123         details_(NONE, NONEXISTENT, Representation::None()) {
124     isolate->set_top_lookup_result(this);
125   }
126
127   ~LookupResult() {
128     DCHECK(isolate()->top_lookup_result() == this);
129     isolate()->set_top_lookup_result(next_);
130   }
131
132   Isolate* isolate() const { return isolate_; }
133
134   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
135     lookup_type_ = DESCRIPTOR_TYPE;
136     holder_ = holder;
137     transition_ = NULL;
138     details_ = details;
139     number_ = number;
140   }
141
142   bool CanHoldValue(Handle<Object> value) const {
143     switch (type()) {
144       case NORMAL:
145         return true;
146       case FIELD:
147         return value->FitsRepresentation(representation()) &&
148             GetFieldType()->NowContains(value);
149       case CONSTANT:
150         DCHECK(GetConstant() != *value ||
151                value->FitsRepresentation(representation()));
152         return GetConstant() == *value;
153       case CALLBACKS:
154       case HANDLER:
155       case INTERCEPTOR:
156         return true;
157       case NONEXISTENT:
158         UNREACHABLE();
159     }
160     UNREACHABLE();
161     return true;
162   }
163
164   void TransitionResult(JSObject* holder, Map* target) {
165     lookup_type_ = TRANSITION_TYPE;
166     number_ = target->LastAdded();
167     details_ = target->instance_descriptors()->GetDetails(number_);
168     holder_ = holder;
169     transition_ = target;
170   }
171
172   void DictionaryResult(JSObject* holder, int entry) {
173     lookup_type_ = DICTIONARY_TYPE;
174     holder_ = holder;
175     transition_ = NULL;
176     details_ = holder->property_dictionary()->DetailsAt(entry);
177     number_ = entry;
178   }
179
180   void HandlerResult(JSProxy* proxy) {
181     lookup_type_ = HANDLER_TYPE;
182     holder_ = proxy;
183     transition_ = NULL;
184     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
185     cacheable_ = false;
186   }
187
188   void InterceptorResult(JSObject* holder) {
189     lookup_type_ = INTERCEPTOR_TYPE;
190     holder_ = holder;
191     transition_ = NULL;
192     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
193   }
194
195   void NotFound() {
196     lookup_type_ = NOT_FOUND;
197     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
198     holder_ = NULL;
199     transition_ = NULL;
200   }
201
202   JSObject* holder() const {
203     DCHECK(IsFound());
204     return JSObject::cast(holder_);
205   }
206
207   JSProxy* proxy() const {
208     DCHECK(IsHandler());
209     return JSProxy::cast(holder_);
210   }
211
212   PropertyType type() const {
213     DCHECK(IsFound());
214     return details_.type();
215   }
216
217   Representation representation() const {
218     DCHECK(IsFound());
219     DCHECK(details_.type() != NONEXISTENT);
220     return details_.representation();
221   }
222
223   PropertyAttributes GetAttributes() const {
224     DCHECK(IsFound());
225     DCHECK(details_.type() != NONEXISTENT);
226     return details_.attributes();
227   }
228
229   PropertyDetails GetPropertyDetails() const {
230     return details_;
231   }
232
233   bool IsFastPropertyType() const {
234     DCHECK(IsFound());
235     return IsTransition() || type() != NORMAL;
236   }
237
238   // Property callbacks does not include transitions to callbacks.
239   bool IsPropertyCallbacks() const {
240     DCHECK(!(details_.type() == CALLBACKS && !IsFound()));
241     return !IsTransition() && details_.type() == CALLBACKS;
242   }
243
244   bool IsReadOnly() const {
245     DCHECK(IsFound());
246     DCHECK(details_.type() != NONEXISTENT);
247     return details_.IsReadOnly();
248   }
249
250   bool IsField() const {
251     DCHECK(!(details_.type() == FIELD && !IsFound()));
252     return IsDescriptorOrDictionary() && type() == FIELD;
253   }
254
255   bool IsNormal() const {
256     DCHECK(!(details_.type() == NORMAL && !IsFound()));
257     return IsDescriptorOrDictionary() && type() == NORMAL;
258   }
259
260   bool IsConstant() const {
261     DCHECK(!(details_.type() == CONSTANT && !IsFound()));
262     return IsDescriptorOrDictionary() && type() == CONSTANT;
263   }
264
265   bool IsConstantFunction() const {
266     return IsConstant() && GetConstant()->IsJSFunction();
267   }
268
269   bool IsDontDelete() const { return details_.IsDontDelete(); }
270   bool IsDontEnum() const { return details_.IsDontEnum(); }
271   bool IsFound() const { return lookup_type_ != NOT_FOUND; }
272   bool IsDescriptorOrDictionary() const {
273     return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
274   }
275   bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
276   bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
277   bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
278
279   // Is the result is a property excluding transitions and the null descriptor?
280   bool IsProperty() const {
281     return IsFound() && !IsTransition();
282   }
283
284   bool IsDataProperty() const {
285     switch (lookup_type_) {
286       case NOT_FOUND:
287       case TRANSITION_TYPE:
288       case HANDLER_TYPE:
289       case INTERCEPTOR_TYPE:
290         return false;
291
292       case DESCRIPTOR_TYPE:
293       case DICTIONARY_TYPE:
294         switch (type()) {
295           case FIELD:
296           case NORMAL:
297           case CONSTANT:
298             return true;
299           case CALLBACKS: {
300             Object* callback = GetCallbackObject();
301             DCHECK(!callback->IsForeign());
302             return callback->IsAccessorInfo();
303           }
304           case HANDLER:
305           case INTERCEPTOR:
306           case NONEXISTENT:
307             UNREACHABLE();
308             return false;
309         }
310     }
311     UNREACHABLE();
312     return false;
313   }
314
315   bool IsCacheable() const { return cacheable_; }
316   void DisallowCaching() { cacheable_ = false; }
317
318   Object* GetLazyValue() const {
319     switch (lookup_type_) {
320       case NOT_FOUND:
321       case TRANSITION_TYPE:
322       case HANDLER_TYPE:
323       case INTERCEPTOR_TYPE:
324         return isolate()->heap()->the_hole_value();
325
326       case DESCRIPTOR_TYPE:
327       case DICTIONARY_TYPE:
328         switch (type()) {
329           case FIELD:
330             return holder()->RawFastPropertyAt(GetFieldIndex());
331           case NORMAL: {
332             Object* value = holder()->property_dictionary()->ValueAt(
333                 GetDictionaryEntry());
334             if (holder()->IsGlobalObject()) {
335               value = PropertyCell::cast(value)->value();
336             }
337             return value;
338           }
339           case CONSTANT:
340             return GetConstant();
341           case CALLBACKS:
342             return isolate()->heap()->the_hole_value();
343           case HANDLER:
344           case INTERCEPTOR:
345           case NONEXISTENT:
346             UNREACHABLE();
347             return NULL;
348         }
349     }
350     UNREACHABLE();
351     return NULL;
352   }
353
354   Map* GetTransitionTarget() const {
355     DCHECK(IsTransition());
356     return transition_;
357   }
358
359   bool IsTransitionToField() const {
360     return IsTransition() && details_.type() == FIELD;
361   }
362
363   bool IsTransitionToConstant() const {
364     return IsTransition() && details_.type() == CONSTANT;
365   }
366
367   int GetDescriptorIndex() const {
368     DCHECK(lookup_type_ == DESCRIPTOR_TYPE);
369     return number_;
370   }
371
372   FieldIndex GetFieldIndex() const {
373     DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
374            lookup_type_ == TRANSITION_TYPE);
375     return FieldIndex::ForLookupResult(this);
376   }
377
378   int GetLocalFieldIndexFromMap(Map* map) const {
379     return GetFieldIndexFromMap(map) - map->inobject_properties();
380   }
381
382   int GetDictionaryEntry() const {
383     DCHECK(lookup_type_ == DICTIONARY_TYPE);
384     return number_;
385   }
386
387   JSFunction* GetConstantFunction() const {
388     DCHECK(type() == CONSTANT);
389     return JSFunction::cast(GetValue());
390   }
391
392   Object* GetConstantFromMap(Map* map) const {
393     DCHECK(type() == CONSTANT);
394     return GetValueFromMap(map);
395   }
396
397   JSFunction* GetConstantFunctionFromMap(Map* map) const {
398     return JSFunction::cast(GetConstantFromMap(map));
399   }
400
401   Object* GetConstant() const {
402     DCHECK(type() == CONSTANT);
403     return GetValue();
404   }
405
406   Object* GetCallbackObject() const {
407     DCHECK(!IsTransition());
408     DCHECK(type() == CALLBACKS);
409     return GetValue();
410   }
411
412   Object* GetValue() const {
413     if (lookup_type_ == DESCRIPTOR_TYPE) {
414       return GetValueFromMap(holder()->map());
415     } else if (lookup_type_ == TRANSITION_TYPE) {
416       return GetValueFromMap(transition_);
417     }
418     // In the dictionary case, the data is held in the value field.
419     DCHECK(lookup_type_ == DICTIONARY_TYPE);
420     return holder()->GetNormalizedProperty(this);
421   }
422
423   Object* GetValueFromMap(Map* map) const {
424     DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
425            lookup_type_ == TRANSITION_TYPE);
426     DCHECK(number_ < map->NumberOfOwnDescriptors());
427     return map->instance_descriptors()->GetValue(number_);
428   }
429
430   int GetFieldIndexFromMap(Map* map) const {
431     DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
432            lookup_type_ == TRANSITION_TYPE);
433     DCHECK(number_ < map->NumberOfOwnDescriptors());
434     return map->instance_descriptors()->GetFieldIndex(number_);
435   }
436
437   HeapType* GetFieldType() const {
438     DCHECK(type() == FIELD);
439     if (lookup_type_ == DESCRIPTOR_TYPE) {
440       return GetFieldTypeFromMap(holder()->map());
441     }
442     DCHECK(lookup_type_ == TRANSITION_TYPE);
443     return GetFieldTypeFromMap(transition_);
444   }
445
446   HeapType* GetFieldTypeFromMap(Map* map) const {
447     DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
448            lookup_type_ == TRANSITION_TYPE);
449     DCHECK(number_ < map->NumberOfOwnDescriptors());
450     return map->instance_descriptors()->GetFieldType(number_);
451   }
452
453   Map* GetFieldOwner() const {
454     return GetFieldOwnerFromMap(holder()->map());
455   }
456
457   Map* GetFieldOwnerFromMap(Map* map) const {
458     DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
459            lookup_type_ == TRANSITION_TYPE);
460     DCHECK(number_ < map->NumberOfOwnDescriptors());
461     return map->FindFieldOwner(number_);
462   }
463
464   bool ReceiverIsHolder(Handle<Object> receiver) {
465     if (*receiver == holder()) return true;
466     if (lookup_type_ == TRANSITION_TYPE) return true;
467     return false;
468   }
469
470   void Iterate(ObjectVisitor* visitor);
471
472  private:
473   Isolate* isolate_;
474   LookupResult* next_;
475
476   // Where did we find the result;
477   enum {
478     NOT_FOUND,
479     DESCRIPTOR_TYPE,
480     TRANSITION_TYPE,
481     DICTIONARY_TYPE,
482     HANDLER_TYPE,
483     INTERCEPTOR_TYPE
484   } lookup_type_;
485
486   JSReceiver* holder_;
487   Map* transition_;
488   int number_;
489   bool cacheable_;
490   PropertyDetails details_;
491 };
492
493
494 OStream& operator<<(OStream& os, const LookupResult& r);
495 } }  // namespace v8::internal
496
497 #endif  // V8_PROPERTY_H_