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