• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 namespace v8 {
34 namespace internal {
35 
36 
37 // Abstraction for elements in instance-descriptor arrays.
38 //
39 // Each descriptor has a key, property attributes, property type,
40 // property index (in the actual instance-descriptor array) and
41 // optionally a piece of data.
42 //
43 
44 class Descriptor BASE_EMBEDDED {
45  public:
IndexFromValue(Object * value)46   static int IndexFromValue(Object* value) {
47     return Smi::cast(value)->value();
48   }
49 
KeyToSymbol()50   MUST_USE_RESULT MaybeObject* KeyToSymbol() {
51     if (!StringShape(key_).IsSymbol()) {
52       MaybeObject* maybe_result = HEAP->LookupSymbol(key_);
53       if (!maybe_result->To(&key_)) return maybe_result;
54     }
55     return key_;
56   }
57 
GetKey()58   String* GetKey() { return key_; }
GetValue()59   Object* GetValue() { return value_; }
GetDetails()60   PropertyDetails GetDetails() { return details_; }
61 
62 #ifdef OBJECT_PRINT
63   void Print(FILE* out);
64 #endif
65 
SetEnumerationIndex(int index)66   void SetEnumerationIndex(int index) {
67     ASSERT(PropertyDetails::IsValidIndex(index));
68     details_ = PropertyDetails(details_.attributes(), details_.type(), index);
69   }
70 
71   bool ContainsTransition();
72 
73  private:
74   String* key_;
75   Object* value_;
76   PropertyDetails details_;
77 
78  protected:
Descriptor()79   Descriptor() : details_(Smi::FromInt(0)) {}
80 
Init(String * key,Object * value,PropertyDetails details)81   void Init(String* key, Object* value, PropertyDetails details) {
82     key_ = key;
83     value_ = value;
84     details_ = details;
85   }
86 
Descriptor(String * key,Object * value,PropertyDetails details)87   Descriptor(String* key, Object* value, PropertyDetails details)
88       : key_(key),
89         value_(value),
90         details_(details) { }
91 
92   Descriptor(String* key,
93              Object* value,
94              PropertyAttributes attributes,
95              PropertyType type,
96              int index = 0)
key_(key)97       : key_(key),
98         value_(value),
99         details_(attributes, type, index) { }
100 
101   friend class DescriptorArray;
102 };
103 
104 // A pointer from a map to the new map that is created by adding
105 // a named property.  These are key to the speed and functioning of V8.
106 // The two maps should always have the same prototype, since
107 // MapSpace::CreateBackPointers depends on this.
108 class MapTransitionDescriptor: public Descriptor {
109  public:
MapTransitionDescriptor(String * key,Map * map,PropertyAttributes attributes)110   MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
111       : Descriptor(key, map, attributes, MAP_TRANSITION) { }
112 };
113 
114 class ElementsTransitionDescriptor: public Descriptor {
115  public:
ElementsTransitionDescriptor(String * key,Object * map_or_array)116   ElementsTransitionDescriptor(String* key,
117                                Object* map_or_array)
118       : Descriptor(key, map_or_array, PropertyDetails(NONE,
119                                                       ELEMENTS_TRANSITION)) { }
120 };
121 
122 // Marks a field name in a map so that adding the field is guaranteed
123 // to create a FIELD descriptor in the new map.  Used after adding
124 // a constant function the first time, creating a CONSTANT_FUNCTION
125 // descriptor in the new map.  This avoids creating multiple maps with
126 // the same CONSTANT_FUNCTION field.
127 class ConstTransitionDescriptor: public Descriptor {
128  public:
ConstTransitionDescriptor(String * key,Map * map)129   explicit ConstTransitionDescriptor(String* key, Map* map)
130       : Descriptor(key, map, NONE, CONSTANT_TRANSITION) { }
131 };
132 
133 
134 class FieldDescriptor: public Descriptor {
135  public:
136   FieldDescriptor(String* key,
137                   int field_index,
138                   PropertyAttributes attributes,
139                   int index = 0)
Descriptor(key,Smi::FromInt (field_index),attributes,FIELD,index)140       : Descriptor(key, Smi::FromInt(field_index), attributes, FIELD, index) {}
141 };
142 
143 
144 class ConstantFunctionDescriptor: public Descriptor {
145  public:
146   ConstantFunctionDescriptor(String* key,
147                              JSFunction* function,
148                              PropertyAttributes attributes,
149                              int index = 0)
Descriptor(key,function,attributes,CONSTANT_FUNCTION,index)150       : Descriptor(key, function, attributes, CONSTANT_FUNCTION, index) {}
151 };
152 
153 
154 class CallbacksDescriptor:  public Descriptor {
155  public:
156   CallbacksDescriptor(String* key,
157                       Object* foreign,
158                       PropertyAttributes attributes,
159                       int index = 0)
Descriptor(key,foreign,attributes,CALLBACKS,index)160       : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
161 };
162 
163 
164 template <class T>
IsPropertyDescriptor(T * desc)165 bool IsPropertyDescriptor(T* desc) {
166   switch (desc->type()) {
167     case NORMAL:
168     case FIELD:
169     case CONSTANT_FUNCTION:
170     case HANDLER:
171     case INTERCEPTOR:
172       return true;
173     case CALLBACKS: {
174       Object* callback_object = desc->GetCallbackObject();
175       // Non-JavaScript (i.e. native) accessors are always a property, otherwise
176       // either the getter or the setter must be an accessor. Put another way:
177       // If we only see map transitions and holes in a pair, this is not a
178       // property.
179       return (!callback_object->IsAccessorPair() ||
180               AccessorPair::cast(callback_object)->ContainsAccessor());
181     }
182     case MAP_TRANSITION:
183     case ELEMENTS_TRANSITION:
184     case CONSTANT_TRANSITION:
185     case NULL_DESCRIPTOR:
186       return false;
187   }
188   UNREACHABLE();  // keep the compiler happy
189   return false;
190 }
191 
192 
193 class LookupResult BASE_EMBEDDED {
194  public:
LookupResult(Isolate * isolate)195   explicit LookupResult(Isolate* isolate)
196       : isolate_(isolate),
197         next_(isolate->top_lookup_result()),
198         lookup_type_(NOT_FOUND),
199         holder_(NULL),
200         cacheable_(true),
201         details_(NONE, NORMAL) {
202     isolate->SetTopLookupResult(this);
203   }
204 
~LookupResult()205   ~LookupResult() {
206     ASSERT(isolate_->top_lookup_result() == this);
207     isolate_->SetTopLookupResult(next_);
208   }
209 
DescriptorResult(JSObject * holder,PropertyDetails details,int number)210   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
211     lookup_type_ = DESCRIPTOR_TYPE;
212     holder_ = holder;
213     details_ = details;
214     number_ = number;
215   }
216 
DescriptorResult(JSObject * holder,Smi * details,int number)217   void DescriptorResult(JSObject* holder, Smi* details, int number) {
218     lookup_type_ = DESCRIPTOR_TYPE;
219     holder_ = holder;
220     details_ = PropertyDetails(details);
221     number_ = number;
222   }
223 
ConstantResult(JSObject * holder)224   void ConstantResult(JSObject* holder) {
225     lookup_type_ = CONSTANT_TYPE;
226     holder_ = holder;
227     details_ =
228         PropertyDetails(static_cast<PropertyAttributes>(DONT_ENUM |
229                                                         DONT_DELETE),
230                         CALLBACKS);
231     number_ = -1;
232   }
233 
DictionaryResult(JSObject * holder,int entry)234   void DictionaryResult(JSObject* holder, int entry) {
235     lookup_type_ = DICTIONARY_TYPE;
236     holder_ = holder;
237     details_ = holder->property_dictionary()->DetailsAt(entry);
238     number_ = entry;
239   }
240 
HandlerResult(JSProxy * proxy)241   void HandlerResult(JSProxy* proxy) {
242     lookup_type_ = HANDLER_TYPE;
243     holder_ = proxy;
244     details_ = PropertyDetails(NONE, HANDLER);
245     cacheable_ = false;
246   }
247 
InterceptorResult(JSObject * holder)248   void InterceptorResult(JSObject* holder) {
249     lookup_type_ = INTERCEPTOR_TYPE;
250     holder_ = holder;
251     details_ = PropertyDetails(NONE, INTERCEPTOR);
252   }
253 
NotFound()254   void NotFound() {
255     lookup_type_ = NOT_FOUND;
256     holder_ = NULL;
257   }
258 
holder()259   JSObject* holder() {
260     ASSERT(IsFound());
261     return JSObject::cast(holder_);
262   }
263 
proxy()264   JSProxy* proxy() {
265     ASSERT(IsFound());
266     return JSProxy::cast(holder_);
267   }
268 
type()269   PropertyType type() {
270     ASSERT(IsFound());
271     return details_.type();
272   }
273 
GetAttributes()274   PropertyAttributes GetAttributes() {
275     ASSERT(IsFound());
276     return details_.attributes();
277   }
278 
GetPropertyDetails()279   PropertyDetails GetPropertyDetails() {
280     return details_;
281   }
282 
IsReadOnly()283   bool IsReadOnly() { return details_.IsReadOnly(); }
IsDontDelete()284   bool IsDontDelete() { return details_.IsDontDelete(); }
IsDontEnum()285   bool IsDontEnum() { return details_.IsDontEnum(); }
IsDeleted()286   bool IsDeleted() { return details_.IsDeleted(); }
IsFound()287   bool IsFound() { return lookup_type_ != NOT_FOUND; }
IsHandler()288   bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
289 
290   // Is the result is a property excluding transitions and the null descriptor?
IsProperty()291   bool IsProperty() {
292     return IsFound() && IsPropertyDescriptor(this);
293   }
294 
IsCacheable()295   bool IsCacheable() { return cacheable_; }
DisallowCaching()296   void DisallowCaching() { cacheable_ = false; }
297 
GetLazyValue()298   Object* GetLazyValue() {
299     switch (type()) {
300       case FIELD:
301         return holder()->FastPropertyAt(GetFieldIndex());
302       case NORMAL: {
303         Object* value;
304         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
305         if (holder()->IsGlobalObject()) {
306           value = JSGlobalPropertyCell::cast(value)->value();
307         }
308         return value;
309       }
310       case CONSTANT_FUNCTION:
311         return GetConstantFunction();
312       default:
313         return Smi::FromInt(0);
314     }
315   }
316 
317 
GetTransitionMap()318   Map* GetTransitionMap() {
319     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
320     ASSERT(type() == MAP_TRANSITION ||
321            type() == ELEMENTS_TRANSITION ||
322            type() == CONSTANT_TRANSITION);
323     return Map::cast(GetValue());
324   }
325 
GetTransitionMapFromMap(Map * map)326   Map* GetTransitionMapFromMap(Map* map) {
327     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
328     ASSERT(type() == MAP_TRANSITION);
329     return Map::cast(map->instance_descriptors()->GetValue(number_));
330   }
331 
GetFieldIndex()332   int GetFieldIndex() {
333     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
334     ASSERT(type() == FIELD);
335     return Descriptor::IndexFromValue(GetValue());
336   }
337 
GetLocalFieldIndexFromMap(Map * map)338   int GetLocalFieldIndexFromMap(Map* map) {
339     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
340     ASSERT(type() == FIELD);
341     return Descriptor::IndexFromValue(
342         map->instance_descriptors()->GetValue(number_)) -
343         map->inobject_properties();
344   }
345 
GetDictionaryEntry()346   int GetDictionaryEntry() {
347     ASSERT(lookup_type_ == DICTIONARY_TYPE);
348     return number_;
349   }
350 
GetConstantFunction()351   JSFunction* GetConstantFunction() {
352     ASSERT(type() == CONSTANT_FUNCTION);
353     return JSFunction::cast(GetValue());
354   }
355 
GetConstantFunctionFromMap(Map * map)356   JSFunction* GetConstantFunctionFromMap(Map* map) {
357     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
358     ASSERT(type() == CONSTANT_FUNCTION);
359     return JSFunction::cast(map->instance_descriptors()->GetValue(number_));
360   }
361 
GetCallbackObject()362   Object* GetCallbackObject() {
363     if (lookup_type_ == CONSTANT_TYPE) {
364       // For now we only have the __proto__ as constant type.
365       return HEAP->prototype_accessors();
366     }
367     return GetValue();
368   }
369 
370 #ifdef OBJECT_PRINT
371   void Print(FILE* out);
372 #endif
373 
GetValue()374   Object* GetValue() {
375     if (lookup_type_ == DESCRIPTOR_TYPE) {
376       DescriptorArray* descriptors = holder()->map()->instance_descriptors();
377       return descriptors->GetValue(number_);
378     }
379     // In the dictionary case, the data is held in the value field.
380     ASSERT(lookup_type_ == DICTIONARY_TYPE);
381     return holder()->GetNormalizedProperty(this);
382   }
383 
384   void Iterate(ObjectVisitor* visitor);
385 
386  private:
387   Isolate* isolate_;
388   LookupResult* next_;
389 
390   // Where did we find the result;
391   enum {
392     NOT_FOUND,
393     DESCRIPTOR_TYPE,
394     DICTIONARY_TYPE,
395     HANDLER_TYPE,
396     INTERCEPTOR_TYPE,
397     CONSTANT_TYPE
398   } lookup_type_;
399 
400   JSReceiver* holder_;
401   int number_;
402   bool cacheable_;
403   PropertyDetails details_;
404 };
405 
406 
407 } }  // namespace v8::internal
408 
409 #endif  // V8_PROPERTY_H_
410