0f78ba478ec8512e8d94fd57a502a42a470c582a
[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         cacheable_(true),
188         details_(NONE, NONEXISTENT, Representation::None()) {
189     isolate->SetTopLookupResult(this);
190   }
191
192   ~LookupResult() {
193     ASSERT(isolate()->top_lookup_result() == this);
194     isolate()->SetTopLookupResult(next_);
195   }
196
197   Isolate* isolate() const { return isolate_; }
198
199   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
200     lookup_type_ = DESCRIPTOR_TYPE;
201     holder_ = holder;
202     details_ = details;
203     number_ = number;
204   }
205
206   bool CanHoldValue(Handle<Object> value) {
207     if (IsNormal()) return true;
208     ASSERT(!IsTransition());
209     return value->FitsRepresentation(details_.representation());
210   }
211
212   void TransitionResult(JSObject* holder, int number) {
213     lookup_type_ = TRANSITION_TYPE;
214     details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
215     holder_ = holder;
216     number_ = number;
217   }
218
219   void DictionaryResult(JSObject* holder, int entry) {
220     lookup_type_ = DICTIONARY_TYPE;
221     holder_ = holder;
222     details_ = holder->property_dictionary()->DetailsAt(entry);
223     number_ = entry;
224   }
225
226   void HandlerResult(JSProxy* proxy) {
227     lookup_type_ = HANDLER_TYPE;
228     holder_ = proxy;
229     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
230     cacheable_ = false;
231   }
232
233   void InterceptorResult(JSObject* holder) {
234     lookup_type_ = INTERCEPTOR_TYPE;
235     holder_ = holder;
236     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
237   }
238
239   void NotFound() {
240     lookup_type_ = NOT_FOUND;
241     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
242     holder_ = NULL;
243   }
244
245   JSObject* holder() {
246     ASSERT(IsFound());
247     return JSObject::cast(holder_);
248   }
249
250   JSProxy* proxy() {
251     ASSERT(IsFound());
252     return JSProxy::cast(holder_);
253   }
254
255   PropertyType type() {
256     ASSERT(IsFound());
257     return details_.type();
258   }
259
260   Representation representation() {
261     ASSERT(IsFound());
262     ASSERT(!IsTransition());
263     ASSERT(details_.type() != NONEXISTENT);
264     return details_.representation();
265   }
266
267   PropertyAttributes GetAttributes() {
268     ASSERT(!IsTransition());
269     ASSERT(IsFound());
270     ASSERT(details_.type() != NONEXISTENT);
271     return details_.attributes();
272   }
273
274   PropertyDetails GetPropertyDetails() {
275     ASSERT(!IsTransition());
276     return details_;
277   }
278
279   bool IsFastPropertyType() {
280     ASSERT(IsFound());
281     return IsTransition() || type() != NORMAL;
282   }
283
284   // Property callbacks does not include transitions to callbacks.
285   bool IsPropertyCallbacks() {
286     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
287     return details_.type() == CALLBACKS;
288   }
289
290   bool IsReadOnly() {
291     ASSERT(IsFound());
292     ASSERT(!IsTransition());
293     ASSERT(details_.type() != NONEXISTENT);
294     return details_.IsReadOnly();
295   }
296
297   bool IsField() {
298     ASSERT(!(details_.type() == FIELD && !IsFound()));
299     return details_.type() == FIELD;
300   }
301
302   bool IsNormal() {
303     ASSERT(!(details_.type() == NORMAL && !IsFound()));
304     return details_.type() == NORMAL;
305   }
306
307   bool IsConstant() {
308     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
309     return details_.type() == CONSTANT;
310   }
311
312   bool IsConstantFunction() {
313     return IsConstant() && GetValue()->IsJSFunction();
314   }
315
316   bool IsDontDelete() { return details_.IsDontDelete(); }
317   bool IsDontEnum() { return details_.IsDontEnum(); }
318   bool IsFound() { return lookup_type_ != NOT_FOUND; }
319   bool IsTransition() { return lookup_type_ == TRANSITION_TYPE; }
320   bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
321   bool IsInterceptor() { return lookup_type_ == INTERCEPTOR_TYPE; }
322
323   // Is the result is a property excluding transitions and the null descriptor?
324   bool IsProperty() {
325     return IsFound() && !IsTransition();
326   }
327
328   bool IsDataProperty() {
329     switch (type()) {
330       case FIELD:
331       case NORMAL:
332       case CONSTANT:
333         return true;
334       case CALLBACKS: {
335         Object* callback = GetCallbackObject();
336         return callback->IsAccessorInfo() || callback->IsForeign();
337       }
338       case HANDLER:
339       case INTERCEPTOR:
340       case TRANSITION:
341       case NONEXISTENT:
342         return false;
343     }
344     UNREACHABLE();
345     return false;
346   }
347
348   bool IsCacheable() { return cacheable_; }
349   void DisallowCaching() { cacheable_ = false; }
350
351   Object* GetLazyValue() {
352     switch (type()) {
353       case FIELD:
354         return holder()->RawFastPropertyAt(GetFieldIndex().field_index());
355       case NORMAL: {
356         Object* value;
357         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
358         if (holder()->IsGlobalObject()) {
359           value = PropertyCell::cast(value)->value();
360         }
361         return value;
362       }
363       case CONSTANT:
364         return GetConstant();
365       case CALLBACKS:
366       case HANDLER:
367       case INTERCEPTOR:
368       case TRANSITION:
369       case NONEXISTENT:
370         return isolate()->heap()->the_hole_value();
371     }
372     UNREACHABLE();
373     return NULL;
374   }
375
376   Map* GetTransitionTarget(Map* map) {
377     ASSERT(IsTransition());
378     TransitionArray* transitions = map->transitions();
379     return transitions->GetTarget(number_);
380   }
381
382   Map* GetTransitionTarget() {
383     return GetTransitionTarget(holder()->map());
384   }
385
386   PropertyDetails GetTransitionDetails(Map* map) {
387     ASSERT(IsTransition());
388     TransitionArray* transitions = map->transitions();
389     return transitions->GetTargetDetails(number_);
390   }
391
392   PropertyDetails GetTransitionDetails() {
393     return GetTransitionDetails(holder()->map());
394   }
395
396   bool IsTransitionToField(Map* map) {
397     return IsTransition() && GetTransitionDetails(map).type() == FIELD;
398   }
399
400   bool IsTransitionToConstant(Map* map) {
401     return IsTransition() && GetTransitionDetails(map).type() == CONSTANT;
402   }
403
404   Map* GetTransitionMap() {
405     ASSERT(IsTransition());
406     return Map::cast(GetValue());
407   }
408
409   Map* GetTransitionMapFromMap(Map* map) {
410     ASSERT(IsTransition());
411     return map->transitions()->GetTarget(number_);
412   }
413
414   int GetTransitionIndex() {
415     ASSERT(IsTransition());
416     return number_;
417   }
418
419   int GetDescriptorIndex() {
420     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
421     return number_;
422   }
423
424   PropertyIndex GetFieldIndex() {
425     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
426     return PropertyIndex::NewFieldIndex(GetFieldIndexFromMap(holder()->map()));
427   }
428
429   int GetLocalFieldIndexFromMap(Map* map) {
430     return GetFieldIndexFromMap(map) - map->inobject_properties();
431   }
432
433   int GetDictionaryEntry() {
434     ASSERT(lookup_type_ == DICTIONARY_TYPE);
435     return number_;
436   }
437
438   JSFunction* GetConstantFunction() {
439     ASSERT(type() == CONSTANT);
440     return JSFunction::cast(GetValue());
441   }
442
443   Object* GetConstantFromMap(Map* map) {
444     ASSERT(type() == CONSTANT);
445     return GetValueFromMap(map);
446   }
447
448   JSFunction* GetConstantFunctionFromMap(Map* map) {
449     return JSFunction::cast(GetConstantFromMap(map));
450   }
451
452   Object* GetConstant() {
453     ASSERT(type() == CONSTANT);
454     return GetValue();
455   }
456
457   Object* GetCallbackObject() {
458     ASSERT(type() == CALLBACKS && !IsTransition());
459     return GetValue();
460   }
461
462 #ifdef OBJECT_PRINT
463   void Print(FILE* out);
464 #endif
465
466   Object* GetValue() {
467     if (lookup_type_ == DESCRIPTOR_TYPE) {
468       return GetValueFromMap(holder()->map());
469     }
470     // In the dictionary case, the data is held in the value field.
471     ASSERT(lookup_type_ == DICTIONARY_TYPE);
472     return holder()->GetNormalizedProperty(this);
473   }
474
475   Object* GetValueFromMap(Map* map) const {
476     ASSERT(lookup_type_ == DESCRIPTOR_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     ASSERT(number_ < map->NumberOfOwnDescriptors());
484     return map->instance_descriptors()->GetFieldIndex(number_);
485   }
486
487   void Iterate(ObjectVisitor* visitor);
488
489  private:
490   Isolate* isolate_;
491   LookupResult* next_;
492
493   // Where did we find the result;
494   enum {
495     NOT_FOUND,
496     DESCRIPTOR_TYPE,
497     TRANSITION_TYPE,
498     DICTIONARY_TYPE,
499     HANDLER_TYPE,
500     INTERCEPTOR_TYPE
501   } lookup_type_;
502
503   JSReceiver* holder_;
504   int number_;
505   bool cacheable_;
506   PropertyDetails details_;
507 };
508
509
510 } }  // namespace v8::internal
511
512 #endif  // V8_PROPERTY_H_