Upstream version 7.36.149.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 "isolate.h"
9 #include "factory.h"
10 #include "types.h"
11
12 namespace v8 {
13 namespace internal {
14
15 // Abstraction for elements in instance-descriptor arrays.
16 //
17 // Each descriptor has a key, property attributes, property type,
18 // property index (in the actual instance-descriptor array) and
19 // optionally a piece of data.
20 class Descriptor BASE_EMBEDDED {
21  public:
22   void KeyToUniqueName() {
23     if (!key_->IsUniqueName()) {
24       key_ = key_->GetIsolate()->factory()->InternalizeString(
25           Handle<String>::cast(key_));
26     }
27   }
28
29   Handle<Name> GetKey() { return key_; }
30   Handle<Object> GetValue() { return value_; }
31   PropertyDetails GetDetails() { return details_; }
32
33 #ifdef OBJECT_PRINT
34   void Print(FILE* out);
35 #endif
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 class FieldDescriptor V8_FINAL : public Descriptor {
74  public:
75   FieldDescriptor(Handle<Name> key,
76                   int field_index,
77                   PropertyAttributes attributes,
78                   Representation representation)
79       : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
80                    FIELD, representation, field_index) {}
81   FieldDescriptor(Handle<Name> key,
82                   int field_index,
83                   Handle<HeapType> field_type,
84                   PropertyAttributes attributes,
85                   Representation representation)
86       : Descriptor(key, field_type, attributes, FIELD,
87                    representation, field_index) { }
88 };
89
90
91 class ConstantDescriptor V8_FINAL : public Descriptor {
92  public:
93   ConstantDescriptor(Handle<Name> key,
94                      Handle<Object> value,
95                      PropertyAttributes attributes)
96       : Descriptor(key, value, attributes, CONSTANT,
97                    value->OptimalRepresentation()) {}
98 };
99
100
101 class CallbacksDescriptor V8_FINAL : public Descriptor {
102  public:
103   CallbacksDescriptor(Handle<Name> key,
104                       Handle<Object> foreign,
105                       PropertyAttributes attributes)
106       : Descriptor(key, foreign, attributes, CALLBACKS,
107                    Representation::Tagged()) {}
108 };
109
110
111 // Holds a property index value distinguishing if it is a field index or an
112 // index inside the object header.
113 class PropertyIndex V8_FINAL {
114  public:
115   static PropertyIndex NewFieldIndex(int index) {
116     return PropertyIndex(index, false);
117   }
118   static PropertyIndex NewHeaderIndex(int index) {
119     return PropertyIndex(index, true);
120   }
121
122   bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
123   bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
124
125   int field_index() {
126     ASSERT(is_field_index());
127     return value();
128   }
129   int header_index() {
130     ASSERT(is_header_index());
131     return value();
132   }
133
134   bool is_inobject(Handle<JSObject> holder) {
135     if (is_header_index()) return true;
136     return field_index() < holder->map()->inobject_properties();
137   }
138
139   int translate(Handle<JSObject> holder) {
140     if (is_header_index()) return header_index();
141     int index = field_index() - holder->map()->inobject_properties();
142     if (index >= 0) return index;
143     return index + holder->map()->instance_size() / kPointerSize;
144   }
145
146  private:
147   static const int kHeaderIndexBit = 1 << 31;
148   static const int kIndexMask = ~kHeaderIndexBit;
149
150   int value() { return index_ & kIndexMask; }
151
152   PropertyIndex(int index, bool is_header_based)
153       : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
154     ASSERT(index <= kIndexMask);
155   }
156
157   int index_;
158 };
159
160
161 class LookupResult V8_FINAL BASE_EMBEDDED {
162  public:
163   explicit LookupResult(Isolate* isolate)
164       : isolate_(isolate),
165         next_(isolate->top_lookup_result()),
166         lookup_type_(NOT_FOUND),
167         holder_(NULL),
168         transition_(NULL),
169         cacheable_(true),
170         details_(NONE, NONEXISTENT, Representation::None()) {
171     isolate->set_top_lookup_result(this);
172   }
173
174   ~LookupResult() {
175     ASSERT(isolate()->top_lookup_result() == this);
176     isolate()->set_top_lookup_result(next_);
177   }
178
179   Isolate* isolate() const { return isolate_; }
180
181   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
182     lookup_type_ = DESCRIPTOR_TYPE;
183     holder_ = holder;
184     transition_ = NULL;
185     details_ = details;
186     number_ = number;
187   }
188
189   bool CanHoldValue(Handle<Object> value) const {
190     switch (type()) {
191       case NORMAL:
192         return true;
193       case FIELD:
194         return value->FitsRepresentation(representation()) &&
195             GetFieldType()->NowContains(value);
196       case CONSTANT:
197         ASSERT(GetConstant() != *value ||
198                value->FitsRepresentation(representation()));
199         return GetConstant() == *value;
200       case CALLBACKS:
201       case HANDLER:
202       case INTERCEPTOR:
203         return true;
204       case NONEXISTENT:
205         UNREACHABLE();
206     }
207     UNREACHABLE();
208     return true;
209   }
210
211   void TransitionResult(JSObject* holder, Map* target) {
212     lookup_type_ = TRANSITION_TYPE;
213     number_ = target->LastAdded();
214     details_ = target->instance_descriptors()->GetDetails(number_);
215     holder_ = holder;
216     transition_ = target;
217   }
218
219   void DictionaryResult(JSObject* holder, int entry) {
220     lookup_type_ = DICTIONARY_TYPE;
221     holder_ = holder;
222     transition_ = NULL;
223     details_ = holder->property_dictionary()->DetailsAt(entry);
224     number_ = entry;
225   }
226
227   void HandlerResult(JSProxy* proxy) {
228     lookup_type_ = HANDLER_TYPE;
229     holder_ = proxy;
230     transition_ = NULL;
231     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
232     cacheable_ = false;
233   }
234
235   void InterceptorResult(JSObject* holder) {
236     lookup_type_ = INTERCEPTOR_TYPE;
237     holder_ = holder;
238     transition_ = NULL;
239     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
240   }
241
242   void NotFound() {
243     lookup_type_ = NOT_FOUND;
244     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
245     holder_ = NULL;
246     transition_ = NULL;
247   }
248
249   JSObject* holder() const {
250     ASSERT(IsFound());
251     return JSObject::cast(holder_);
252   }
253
254   JSProxy* proxy() const {
255     ASSERT(IsHandler());
256     return JSProxy::cast(holder_);
257   }
258
259   PropertyType type() const {
260     ASSERT(IsFound());
261     return details_.type();
262   }
263
264   Representation representation() const {
265     ASSERT(IsFound());
266     ASSERT(details_.type() != NONEXISTENT);
267     return details_.representation();
268   }
269
270   PropertyAttributes GetAttributes() const {
271     ASSERT(IsFound());
272     ASSERT(details_.type() != NONEXISTENT);
273     return details_.attributes();
274   }
275
276   PropertyDetails GetPropertyDetails() const {
277     return details_;
278   }
279
280   bool IsFastPropertyType() const {
281     ASSERT(IsFound());
282     return IsTransition() || type() != NORMAL;
283   }
284
285   // Property callbacks does not include transitions to callbacks.
286   bool IsPropertyCallbacks() const {
287     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
288     return !IsTransition() && details_.type() == CALLBACKS;
289   }
290
291   bool IsReadOnly() const {
292     ASSERT(IsFound());
293     ASSERT(details_.type() != NONEXISTENT);
294     return details_.IsReadOnly();
295   }
296
297   bool IsField() const {
298     ASSERT(!(details_.type() == FIELD && !IsFound()));
299     return IsDescriptorOrDictionary() && type() == FIELD;
300   }
301
302   bool IsNormal() const {
303     ASSERT(!(details_.type() == NORMAL && !IsFound()));
304     return IsDescriptorOrDictionary() && type() == NORMAL;
305   }
306
307   bool IsConstant() const {
308     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
309     return IsDescriptorOrDictionary() && type() == CONSTANT;
310   }
311
312   bool IsConstantFunction() const {
313     return IsConstant() && GetConstant()->IsJSFunction();
314   }
315
316   bool IsDontDelete() const { return details_.IsDontDelete(); }
317   bool IsDontEnum() const { return details_.IsDontEnum(); }
318   bool IsFound() const { return lookup_type_ != NOT_FOUND; }
319   bool IsDescriptorOrDictionary() const {
320     return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
321   }
322   bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
323   bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
324   bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
325
326   // Is the result is a property excluding transitions and the null descriptor?
327   bool IsProperty() const {
328     return IsFound() && !IsTransition();
329   }
330
331   bool IsDataProperty() const {
332     switch (lookup_type_) {
333       case NOT_FOUND:
334       case TRANSITION_TYPE:
335       case HANDLER_TYPE:
336       case INTERCEPTOR_TYPE:
337         return false;
338
339       case DESCRIPTOR_TYPE:
340       case DICTIONARY_TYPE:
341         switch (type()) {
342           case FIELD:
343           case NORMAL:
344           case CONSTANT:
345             return true;
346           case CALLBACKS: {
347             Object* callback = GetCallbackObject();
348             ASSERT(!callback->IsForeign());
349             return callback->IsAccessorInfo();
350           }
351           case HANDLER:
352           case INTERCEPTOR:
353           case NONEXISTENT:
354             UNREACHABLE();
355             return false;
356         }
357     }
358     UNREACHABLE();
359     return false;
360   }
361
362   bool IsCacheable() const { return cacheable_; }
363   void DisallowCaching() { cacheable_ = false; }
364
365   Object* GetLazyValue() const {
366     switch (lookup_type_) {
367       case NOT_FOUND:
368       case TRANSITION_TYPE:
369       case HANDLER_TYPE:
370       case INTERCEPTOR_TYPE:
371         return isolate()->heap()->the_hole_value();
372
373       case DESCRIPTOR_TYPE:
374       case DICTIONARY_TYPE:
375         switch (type()) {
376           case FIELD:
377             return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
378           case NORMAL: {
379             Object* value = holder()->property_dictionary()->ValueAt(
380                 GetDictionaryEntry());
381             if (holder()->IsGlobalObject()) {
382               value = PropertyCell::cast(value)->value();
383             }
384             return value;
385           }
386           case CONSTANT:
387             return GetConstant();
388           case CALLBACKS:
389             return isolate()->heap()->the_hole_value();
390           case HANDLER:
391           case INTERCEPTOR:
392           case NONEXISTENT:
393             UNREACHABLE();
394             return NULL;
395         }
396     }
397     UNREACHABLE();
398     return NULL;
399   }
400
401   Map* GetTransitionTarget() const {
402     ASSERT(IsTransition());
403     return transition_;
404   }
405
406   bool IsTransitionToField() const {
407     return IsTransition() && details_.type() == FIELD;
408   }
409
410   bool IsTransitionToConstant() const {
411     return IsTransition() && details_.type() == CONSTANT;
412   }
413
414   int GetDescriptorIndex() const {
415     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
416     return number_;
417   }
418
419   PropertyIndex GetFieldIndex() const {
420     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
421            lookup_type_ == TRANSITION_TYPE);
422     return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
423   }
424
425   int GetLocalFieldIndexFromMap(Map* map) const {
426     return GetFieldIndexFromMap(map) - map->inobject_properties();
427   }
428
429   int GetDictionaryEntry() const {
430     ASSERT(lookup_type_ == DICTIONARY_TYPE);
431     return number_;
432   }
433
434   JSFunction* GetConstantFunction() const {
435     ASSERT(type() == CONSTANT);
436     return JSFunction::cast(GetValue());
437   }
438
439   Object* GetConstantFromMap(Map* map) const {
440     ASSERT(type() == CONSTANT);
441     return GetValueFromMap(map);
442   }
443
444   JSFunction* GetConstantFunctionFromMap(Map* map) const {
445     return JSFunction::cast(GetConstantFromMap(map));
446   }
447
448   Object* GetConstant() const {
449     ASSERT(type() == CONSTANT);
450     return GetValue();
451   }
452
453   Object* GetCallbackObject() const {
454     ASSERT(!IsTransition());
455     ASSERT(type() == CALLBACKS);
456     return GetValue();
457   }
458
459 #ifdef OBJECT_PRINT
460   void Print(FILE* out);
461 #endif
462
463   Object* GetValue() const {
464     if (lookup_type_ == DESCRIPTOR_TYPE) {
465       return GetValueFromMap(holder()->map());
466     } else if (lookup_type_ == TRANSITION_TYPE) {
467       return GetValueFromMap(transition_);
468     }
469     // In the dictionary case, the data is held in the value field.
470     ASSERT(lookup_type_ == DICTIONARY_TYPE);
471     return holder()->GetNormalizedProperty(this);
472   }
473
474   Object* GetValueFromMap(Map* map) const {
475     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
476            lookup_type_ == TRANSITION_TYPE);
477     ASSERT(number_ < map->NumberOfOwnDescriptors());
478     return map->instance_descriptors()->GetValue(number_);
479   }
480
481   int GetFieldIndexFromMap(Map* map) const {
482     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
483            lookup_type_ == TRANSITION_TYPE);
484     ASSERT(number_ < map->NumberOfOwnDescriptors());
485     return map->instance_descriptors()->GetFieldIndex(number_);
486   }
487
488   HeapType* GetFieldType() const {
489     ASSERT(type() == FIELD);
490     if (lookup_type_ == DESCRIPTOR_TYPE) {
491       return GetFieldTypeFromMap(holder()->map());
492     }
493     ASSERT(lookup_type_ == TRANSITION_TYPE);
494     return GetFieldTypeFromMap(transition_);
495   }
496
497   HeapType* GetFieldTypeFromMap(Map* map) const {
498     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
499            lookup_type_ == TRANSITION_TYPE);
500     ASSERT(number_ < map->NumberOfOwnDescriptors());
501     return map->instance_descriptors()->GetFieldType(number_);
502   }
503
504   Map* GetFieldOwner() const {
505     return GetFieldOwnerFromMap(holder()->map());
506   }
507
508   Map* GetFieldOwnerFromMap(Map* map) const {
509     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
510            lookup_type_ == TRANSITION_TYPE);
511     ASSERT(number_ < map->NumberOfOwnDescriptors());
512     return map->FindFieldOwner(number_);
513   }
514
515   void Iterate(ObjectVisitor* visitor);
516
517  private:
518   Isolate* isolate_;
519   LookupResult* next_;
520
521   // Where did we find the result;
522   enum {
523     NOT_FOUND,
524     DESCRIPTOR_TYPE,
525     TRANSITION_TYPE,
526     DICTIONARY_TYPE,
527     HANDLER_TYPE,
528     INTERCEPTOR_TYPE
529   } lookup_type_;
530
531   JSReceiver* holder_;
532   Map* transition_;
533   int number_;
534   bool cacheable_;
535   PropertyDetails details_;
536 };
537
538 } }  // namespace v8::internal
539
540 #endif  // V8_PROPERTY_H_