• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006-2008 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 namespace v8 {
32 namespace internal {
33 
34 
35 // Abstraction for elements in instance-descriptor arrays.
36 //
37 // Each descriptor has a key, property attributes, property type,
38 // property index (in the actual instance-descriptor array) and
39 // optionally a piece of data.
40 //
41 
42 class Descriptor BASE_EMBEDDED {
43  public:
IndexFromValue(Object * value)44   static int IndexFromValue(Object* value) {
45     return Smi::cast(value)->value();
46   }
47 
KeyToSymbol()48   Object* KeyToSymbol() {
49     if (!StringShape(key_).IsSymbol()) {
50       Object* result = Heap::LookupSymbol(key_);
51       if (result->IsFailure()) return result;
52       key_ = String::cast(result);
53     }
54     return key_;
55   }
56 
GetKey()57   String* GetKey() { return key_; }
GetValue()58   Object* GetValue() { return value_; }
GetDetails()59   PropertyDetails GetDetails() { return details_; }
60 
61 #ifdef DEBUG
62   void Print();
63 #endif
64 
SetEnumerationIndex(int index)65   void SetEnumerationIndex(int index) {
66     ASSERT(PropertyDetails::IsValidIndex(index));
67     details_ = PropertyDetails(details_.attributes(), details_.type(), index);
68   }
69 
70  private:
71   String* key_;
72   Object* value_;
73   PropertyDetails details_;
74 
75  protected:
Descriptor()76   Descriptor() : details_(Smi::FromInt(0)) {}
77 
Init(String * key,Object * value,PropertyDetails details)78   void Init(String* key, Object* value, PropertyDetails details) {
79     key_ = key;
80     value_ = value;
81     details_ = details;
82   }
83 
Descriptor(String * key,Object * value,PropertyDetails details)84   Descriptor(String* key, Object* value, PropertyDetails details)
85       : key_(key),
86         value_(value),
87         details_(details) { }
88 
89   Descriptor(String* key,
90              Object* value,
91              PropertyAttributes attributes,
92              PropertyType type,
93              int index = 0)
key_(key)94       : key_(key),
95         value_(value),
96         details_(attributes, type, index) { }
97 
98   friend class DescriptorArray;
99 };
100 
101 // A pointer from a map to the new map that is created by adding
102 // a named property.  These are key to the speed and functioning of V8.
103 // The two maps should always have the same prototype, since
104 // MapSpace::CreateBackPointers depends on this.
105 class MapTransitionDescriptor: public Descriptor {
106  public:
MapTransitionDescriptor(String * key,Map * map,PropertyAttributes attributes)107   MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
108       : Descriptor(key, map, attributes, MAP_TRANSITION) { }
109 };
110 
111 // Marks a field name in a map so that adding the field is guaranteed
112 // to create a FIELD descriptor in the new map.  Used after adding
113 // a constant function the first time, creating a CONSTANT_FUNCTION
114 // descriptor in the new map.  This avoids creating multiple maps with
115 // the same CONSTANT_FUNCTION field.
116 class ConstTransitionDescriptor: public Descriptor {
117  public:
ConstTransitionDescriptor(String * key)118   explicit ConstTransitionDescriptor(String* key)
119       : Descriptor(key, Smi::FromInt(0), NONE, CONSTANT_TRANSITION) { }
120 };
121 
122 
123 class FieldDescriptor: public Descriptor {
124  public:
125   FieldDescriptor(String* key,
126                   int field_index,
127                   PropertyAttributes attributes,
128                   int index = 0)
Descriptor(key,Smi::FromInt (field_index),attributes,FIELD,index)129       : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
130 };
131 
132 
133 class ConstantFunctionDescriptor: public Descriptor {
134  public:
135   ConstantFunctionDescriptor(String* key,
136                              JSFunction* function,
137                              PropertyAttributes attributes,
138                              int index = 0)
Descriptor(key,function,attributes,CONSTANT_FUNCTION,index)139       : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
140 };
141 
142 
143 class CallbacksDescriptor:  public Descriptor {
144  public:
145   CallbacksDescriptor(String* key,
146                       Object* proxy,
147                       PropertyAttributes attributes,
148                       int index = 0)
Descriptor(key,proxy,attributes,CALLBACKS,index)149       : Descriptor(key, proxy, attributes, CALLBACKS, index) {}
150 };
151 
152 
153 class LookupResult BASE_EMBEDDED {
154  public:
155   // Where did we find the result;
156   enum {
157     NOT_FOUND,
158     DESCRIPTOR_TYPE,
159     DICTIONARY_TYPE,
160     INTERCEPTOR_TYPE,
161     CONSTANT_TYPE
162   } lookup_type_;
163 
LookupResult()164   LookupResult()
165       : lookup_type_(NOT_FOUND),
166         cacheable_(true),
167         details_(NONE, NORMAL) {}
168 
DescriptorResult(JSObject * holder,PropertyDetails details,int number)169   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
170     lookup_type_ = DESCRIPTOR_TYPE;
171     holder_ = holder;
172     details_ = details;
173     number_ = number;
174   }
175 
ConstantResult(JSObject * holder)176   void ConstantResult(JSObject* holder) {
177     lookup_type_ = CONSTANT_TYPE;
178     holder_ = holder;
179     details_ =
180         PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
181                                                         DONT_DELETE),
182                         CALLBACKS);
183     number_ = -1;
184   }
185 
DictionaryResult(JSObject * holder,int entry)186   void DictionaryResult(JSObject* holder, int entry) {
187     lookup_type_ = DICTIONARY_TYPE;
188     holder_ = holder;
189     details_ = holder->property_dictionary()->DetailsAt(entry);
190     number_ = entry;
191   }
192 
InterceptorResult(JSObject * holder)193   void InterceptorResult(JSObject* holder) {
194     lookup_type_ = INTERCEPTOR_TYPE;
195     holder_ = holder;
196     details_ = PropertyDetails(NONE, INTERCEPTOR);
197   }
198 
NotFound()199   void NotFound() {
200     lookup_type_ = NOT_FOUND;
201   }
202 
holder()203   JSObject* holder() {
204     ASSERT(IsValid());
205     return holder_;
206   }
207 
type()208   PropertyType type() {
209     ASSERT(IsValid());
210     return details_.type();
211   }
212 
IsTransitionType()213   bool IsTransitionType() {
214     PropertyType t = type();
215     if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
216     return false;
217   }
218 
GetAttributes()219   PropertyAttributes GetAttributes() {
220     ASSERT(IsValid());
221     return details_.attributes();
222   }
223 
GetPropertyDetails()224   PropertyDetails GetPropertyDetails() {
225     return details_;
226   }
227 
IsReadOnly()228   bool IsReadOnly() { return details_.IsReadOnly(); }
IsDontDelete()229   bool IsDontDelete() { return details_.IsDontDelete(); }
IsDontEnum()230   bool IsDontEnum() { return details_.IsDontEnum(); }
IsDeleted()231   bool IsDeleted() { return details_.IsDeleted(); }
232 
IsValid()233   bool IsValid() { return  lookup_type_ != NOT_FOUND; }
IsNotFound()234   bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
235 
236   // Tells whether the result is a property.
237   // Excluding transitions and the null descriptor.
IsProperty()238   bool IsProperty() {
239     return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE;
240   }
241 
IsCacheable()242   bool IsCacheable() { return cacheable_; }
DisallowCaching()243   void DisallowCaching() { cacheable_ = false; }
244 
245   // Tells whether the value needs to be loaded.
IsLoaded()246   bool IsLoaded() {
247     if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) {
248       Object* target = GetLazyValue();
249       return !target->IsJSObject() || JSObject::cast(target)->IsLoaded();
250     }
251     return true;
252   }
253 
GetLazyValue()254   Object* GetLazyValue() {
255     switch (type()) {
256       case FIELD:
257         return holder()->FastPropertyAt(GetFieldIndex());
258       case NORMAL: {
259         Object* value;
260         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
261         if (holder()->IsGlobalObject()) {
262           value = JSGlobalPropertyCell::cast(value)->value();
263         }
264         return value;
265       }
266       case CONSTANT_FUNCTION:
267         return GetConstantFunction();
268       default:
269         return Smi::FromInt(0);
270     }
271   }
272 
GetTransitionMap()273   Map* GetTransitionMap() {
274     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
275     ASSERT(type() == MAP_TRANSITION);
276     return Map::cast(GetValue());
277   }
278 
GetFieldIndex()279   int GetFieldIndex() {
280     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
281     ASSERT(type() == FIELD);
282     return Descriptor::IndexFromValue(GetValue());
283   }
284 
GetDictionaryEntry()285   int GetDictionaryEntry() {
286     ASSERT(lookup_type_ == DICTIONARY_TYPE);
287     return number_;
288   }
289 
GetConstantFunction()290   JSFunction* GetConstantFunction() {
291     ASSERT(type() == CONSTANT_FUNCTION);
292     return JSFunction::cast(GetValue());
293   }
294 
GetCallbackObject()295   Object* GetCallbackObject() {
296     if (lookup_type_ == CONSTANT_TYPE) {
297       // For now we only have the __proto__ as constant type.
298       return Heap::prototype_accessors();
299     }
300     return GetValue();
301   }
302 
303 #ifdef DEBUG
304   void Print();
305 #endif
306 
GetValue()307   Object* GetValue() {
308     if (lookup_type_ == DESCRIPTOR_TYPE) {
309       DescriptorArray* descriptors = holder()->map()->instance_descriptors();
310       return descriptors->GetValue(number_);
311     }
312     // In the dictionary case, the data is held in the value field.
313     ASSERT(lookup_type_ == DICTIONARY_TYPE);
314     return holder()->GetNormalizedProperty(this);
315   }
316 
317  private:
318   JSObject* holder_;
319   int number_;
320   bool cacheable_;
321   PropertyDetails details_;
322 };
323 
324 
325 } }  // namespace v8::internal
326 
327 #endif  // V8_PROPERTY_H_
328