Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / src / property.h
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28 #ifndef V8_PROPERTY_H_
29 #define V8_PROPERTY_H_
30
31 #include "allocation.h"
32 #include "transitions.h"
33
34 namespace v8 {
35 namespace internal {
36
37
38 // Abstraction for elements in instance-descriptor arrays.
39 //
40 // Each descriptor has a key, property attributes, property type,
41 // property index (in the actual instance-descriptor array) and
42 // optionally a piece of data.
43 //
44
45 class Descriptor BASE_EMBEDDED {
46  public:
47   MUST_USE_RESULT MaybeObject* KeyToUniqueName() {
48     if (!key_->IsUniqueName()) {
49       MaybeObject* maybe_result =
50           key_->GetIsolate()->heap()->InternalizeString(String::cast(key_));
51       if (!maybe_result->To(&key_)) return maybe_result;
52     }
53     return key_;
54   }
55
56   Name* GetKey() { return key_; }
57   Object* GetValue() { return value_; }
58   PropertyDetails GetDetails() { return details_; }
59
60 #ifdef OBJECT_PRINT
61   void Print(FILE* out);
62 #endif
63
64   void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
65
66  private:
67   Name* key_;
68   Object* value_;
69   PropertyDetails details_;
70
71  protected:
72   Descriptor() : details_(Smi::FromInt(0)) {}
73
74   void Init(Name* key, Object* value, PropertyDetails details) {
75     key_ = key;
76     value_ = value;
77     details_ = details;
78   }
79
80   Descriptor(Name* key, Object* value, PropertyDetails details)
81       : key_(key),
82         value_(value),
83         details_(details) { }
84
85   Descriptor(Name* key,
86              Object* value,
87              PropertyAttributes attributes,
88              PropertyType type,
89              Representation representation,
90              int field_index = 0)
91       : key_(key),
92         value_(value),
93         details_(attributes, type, representation, field_index) { }
94
95   friend class DescriptorArray;
96 };
97
98
99 class FieldDescriptor: public Descriptor {
100  public:
101   FieldDescriptor(Name* key,
102                   int field_index,
103                   PropertyAttributes attributes,
104                   Representation representation)
105       : Descriptor(key, Smi::FromInt(0), attributes,
106                    FIELD, representation, field_index) {}
107 };
108
109
110 class ConstantDescriptor: public Descriptor {
111  public:
112   ConstantDescriptor(Name* key,
113                      Object* value,
114                      PropertyAttributes attributes)
115       : Descriptor(key, value, attributes, CONSTANT,
116                    value->OptimalRepresentation()) {}
117 };
118
119
120 class CallbacksDescriptor:  public Descriptor {
121  public:
122   CallbacksDescriptor(Name* key,
123                       Object* foreign,
124                       PropertyAttributes attributes)
125       : Descriptor(key, foreign, attributes, CALLBACKS,
126                    Representation::Tagged()) {}
127 };
128
129
130 // Holds a property index value distinguishing if it is a field index or an
131 // index inside the object header.
132 class PropertyIndex {
133  public:
134   static PropertyIndex NewFieldIndex(int index) {
135     return PropertyIndex(index, false);
136   }
137   static PropertyIndex NewHeaderIndex(int index) {
138     return PropertyIndex(index, true);
139   }
140
141   bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
142   bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
143
144   int field_index() {
145     ASSERT(is_field_index());
146     return value();
147   }
148   int header_index() {
149     ASSERT(is_header_index());
150     return value();
151   }
152
153   bool is_inobject(Handle<JSObject> holder) {
154     if (is_header_index()) return true;
155     return field_index() < holder->map()->inobject_properties();
156   }
157
158   int translate(Handle<JSObject> holder) {
159     if (is_header_index()) return header_index();
160     int index = field_index() - holder->map()->inobject_properties();
161     if (index >= 0) return index;
162     return index + holder->map()->instance_size() / kPointerSize;
163   }
164
165  private:
166   static const int kHeaderIndexBit = 1 << 31;
167   static const int kIndexMask = ~kHeaderIndexBit;
168
169   int value() { return index_ & kIndexMask; }
170
171   PropertyIndex(int index, bool is_header_based)
172       : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
173     ASSERT(index <= kIndexMask);
174   }
175
176   int index_;
177 };
178
179
180 class LookupResult BASE_EMBEDDED {
181  public:
182   explicit LookupResult(Isolate* isolate)
183       : isolate_(isolate),
184         next_(isolate->top_lookup_result()),
185         lookup_type_(NOT_FOUND),
186         holder_(NULL),
187         transition_(NULL),
188         cacheable_(true),
189         details_(NONE, NONEXISTENT, Representation::None()) {
190     isolate->SetTopLookupResult(this);
191   }
192
193   ~LookupResult() {
194     ASSERT(isolate()->top_lookup_result() == this);
195     isolate()->SetTopLookupResult(next_);
196   }
197
198   Isolate* isolate() const { return isolate_; }
199
200   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
201     lookup_type_ = DESCRIPTOR_TYPE;
202     holder_ = holder;
203     details_ = details;
204     number_ = number;
205     transition_ = NULL;
206   }
207
208   bool CanHoldValue(Handle<Object> value) {
209     if (IsNormal()) return true;
210     ASSERT(!IsTransition());
211     return value->FitsRepresentation(details_.representation());
212   }
213
214   void TransitionResult(JSObject* holder, Map* target) {
215     lookup_type_ = TRANSITION_TYPE;
216     details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
217     holder_ = holder;
218     transition_ = target;
219     number_ = 0xAAAA;
220   }
221
222   void DictionaryResult(JSObject* holder, int entry) {
223     lookup_type_ = DICTIONARY_TYPE;
224     holder_ = holder;
225     transition_ = NULL;
226     details_ = holder->property_dictionary()->DetailsAt(entry);
227     number_ = entry;
228   }
229
230   void HandlerResult(JSProxy* proxy) {
231     lookup_type_ = HANDLER_TYPE;
232     holder_ = proxy;
233     transition_ = NULL;
234     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
235     cacheable_ = false;
236   }
237
238   void InterceptorResult(JSObject* holder) {
239     lookup_type_ = INTERCEPTOR_TYPE;
240     holder_ = holder;
241     transition_ = NULL;
242     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
243   }
244
245   void NotFound() {
246     lookup_type_ = NOT_FOUND;
247     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
248     holder_ = NULL;
249   }
250
251   JSObject* holder() {
252     ASSERT(IsFound());
253     return JSObject::cast(holder_);
254   }
255
256   JSProxy* proxy() {
257     ASSERT(IsHandler());
258     return JSProxy::cast(holder_);
259   }
260
261   PropertyType type() {
262     ASSERT(IsFound());
263     return details_.type();
264   }
265
266   Representation representation() {
267     ASSERT(IsFound());
268     ASSERT(!IsTransition());
269     ASSERT(details_.type() != NONEXISTENT);
270     return details_.representation();
271   }
272
273   PropertyAttributes GetAttributes() {
274     ASSERT(!IsTransition());
275     ASSERT(IsFound());
276     ASSERT(details_.type() != NONEXISTENT);
277     return details_.attributes();
278   }
279
280   PropertyDetails GetPropertyDetails() {
281     ASSERT(!IsTransition());
282     return details_;
283   }
284
285   bool IsFastPropertyType() {
286     ASSERT(IsFound());
287     return IsTransition() || type() != NORMAL;
288   }
289
290   // Property callbacks does not include transitions to callbacks.
291   bool IsPropertyCallbacks() {
292     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
293     return details_.type() == CALLBACKS;
294   }
295
296   bool IsReadOnly() {
297     ASSERT(IsFound());
298     ASSERT(!IsTransition());
299     ASSERT(details_.type() != NONEXISTENT);
300     return details_.IsReadOnly();
301   }
302
303   bool IsField() {
304     ASSERT(!(details_.type() == FIELD && !IsFound()));
305     return details_.type() == FIELD;
306   }
307
308   bool IsNormal() {
309     ASSERT(!(details_.type() == NORMAL && !IsFound()));
310     return details_.type() == NORMAL;
311   }
312
313   bool IsConstant() {
314     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
315     return details_.type() == CONSTANT;
316   }
317
318   bool IsConstantFunction() {
319     return IsConstant() && GetValue()->IsJSFunction();
320   }
321
322   bool IsDontDelete() { return details_.IsDontDelete(); }
323   bool IsDontEnum() { return details_.IsDontEnum(); }
324   bool IsFound() { return lookup_type_ != NOT_FOUND; }
325   bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
326   bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
327   bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
328
329   // Is the result is a property excluding transitions and the null descriptor?
330   bool IsProperty() {
331     return IsFound() && !IsTransition();
332   }
333
334   bool IsDataProperty() {
335     switch (type()) {
336       case FIELD:
337       case NORMAL:
338       case CONSTANT:
339         return true;
340       case CALLBACKS: {
341         Object* callback = GetCallbackObject();
342         return callback->IsAccessorInfo() || callback->IsForeign();
343       }
344       case HANDLER:
345       case INTERCEPTOR:
346       case TRANSITION:
347       case NONEXISTENT:
348         return false;
349     }
350     UNREACHABLE();
351     return false;
352   }
353
354   bool IsCacheable() { return cacheable_; }
355   void DisallowCaching() { cacheable_ = false; }
356
357   Object* GetLazyValue() {
358     switch (type()) {
359       case FIELD:
360         return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
361       case NORMAL: {
362         Object* value;
363         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
364         if (holder()->IsGlobalObject()) {
365           value = PropertyCell::cast(value)->value();
366         }
367         return value;
368       }
369       case CONSTANT:
370         return GetConstant();
371       case CALLBACKS:
372       case HANDLER:
373       case INTERCEPTOR:
374       case TRANSITION:
375       case NONEXISTENT:
376         return isolate()->heap()->the_hole_value();
377     }
378     UNREACHABLE();
379     return NULL;
380   }
381
382   Map* GetTransitionTarget() {
383     return transition_;
384   }
385
386   PropertyDetails GetTransitionDetails() {
387     return transition_->GetLastDescriptorDetails();
388   }
389
390   bool IsTransitionToField() {
391     return IsTransition() && GetTransitionDetails().type() == FIELD;
392   }
393
394   bool IsTransitionToConstant() {
395     return IsTransition() && GetTransitionDetails().type() == CONSTANT;
396   }
397
398   int GetTransitionIndex() {
399     ASSERT(IsTransition());
400     return number_;
401   }
402
403   int GetDescriptorIndex() {
404     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
405     return number_;
406   }
407
408   PropertyIndex GetFieldIndex() {
409     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
410     return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
411   }
412
413   int GetLocalFieldIndexFromMap(Map* map) {
414     return GetFieldIndexFromMap(map) - map->inobject_properties();
415   }
416
417   int GetDictionaryEntry() {
418     ASSERT(lookup_type_ == DICTIONARY_TYPE);
419     return number_;
420   }
421
422   JSFunction* GetConstantFunction() {
423     ASSERT(type() == CONSTANT);
424     return JSFunction::cast(GetValue());
425   }
426
427   Object* GetConstantFromMap(Map* map) {
428     ASSERT(type() == CONSTANT);
429     return GetValueFromMap(map);
430   }
431
432   JSFunction* GetConstantFunctionFromMap(Map* map) {
433     return JSFunction::cast(GetConstantFromMap(map));
434   }
435
436   Object* GetConstant() {
437     ASSERT(type() == CONSTANT);
438     return GetValue();
439   }
440
441   Object* GetCallbackObject() {
442     ASSERT(type() == CALLBACKS && !IsTransition());
443     return GetValue();
444   }
445
446 #ifdef OBJECT_PRINT
447   void Print(FILE* out);
448 #endif
449
450   Object* GetValue() {
451     if (lookup_type_ == DESCRIPTOR_TYPE) {
452       return GetValueFromMap(holder()->map());
453     }
454     // In the dictionary case, the data is held in the value field.
455     ASSERT(lookup_type_ == DICTIONARY_TYPE);
456     return holder()->GetNormalizedProperty(this);
457   }
458
459   Object* GetValueFromMap(Map* map) const {
460     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
461     ASSERT(number_ < map->NumberOfOwnDescriptors());
462     return map->instance_descriptors()->GetValue(number_);
463   }
464
465   int GetFieldIndexFromMap(Map* map) const {
466     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
467     ASSERT(number_ < map->NumberOfOwnDescriptors());
468     return map->instance_descriptors()->GetFieldIndex(number_);
469   }
470
471   void Iterate(ObjectVisitor* visitor);
472
473  private:
474   Isolate* isolate_;
475   LookupResult* next_;
476
477   // Where did we find the result;
478   enum {
479     NOT_FOUND,
480     DESCRIPTOR_TYPE,
481     TRANSITION_TYPE,
482     DICTIONARY_TYPE,
483     HANDLER_TYPE,
484     INTERCEPTOR_TYPE
485   } lookup_type_;
486
487   JSReceiver* holder_;
488   Map* transition_;
489   int number_;
490   bool cacheable_;
491   PropertyDetails details_;
492 };
493
494
495 } }  // namespace v8::internal
496
497 #endif  // V8_PROPERTY_H_