Home | History | Annotate | Download | only in src
      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:
     46   static int IndexFromValue(Object* value) {
     47     return Smi::cast(value)->value();
     48   }
     49 
     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 
     58   String* GetKey() { return key_; }
     59   Object* GetValue() { return value_; }
     60   PropertyDetails GetDetails() { return details_; }
     61 
     62 #ifdef OBJECT_PRINT
     63   void Print(FILE* out);
     64 #endif
     65 
     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:
     79   Descriptor() : details_(Smi::FromInt(0)) {}
     80 
     81   void Init(String* key, Object* value, PropertyDetails details) {
     82     key_ = key;
     83     value_ = value;
     84     details_ = details;
     85   }
     86 
     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)
     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:
    110   MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
    111       : Descriptor(key, map, attributes, MAP_TRANSITION) { }
    112 };
    113 
    114 class ElementsTransitionDescriptor: public Descriptor {
    115  public:
    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:
    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)
    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)
    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)
    160       : Descriptor(key, foreign, attributes, CALLBACKS, index) {}
    161 };
    162 
    163 
    164 template <class T>
    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:
    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 
    205   ~LookupResult() {
    206     ASSERT(isolate_->top_lookup_result() == this);
    207     isolate_->SetTopLookupResult(next_);
    208   }
    209 
    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 
    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 
    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 
    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 
    241   void HandlerResult(JSProxy* proxy) {
    242     lookup_type_ = HANDLER_TYPE;
    243     holder_ = proxy;
    244     details_ = PropertyDetails(NONE, HANDLER);
    245     cacheable_ = false;
    246   }
    247 
    248   void InterceptorResult(JSObject* holder) {
    249     lookup_type_ = INTERCEPTOR_TYPE;
    250     holder_ = holder;
    251     details_ = PropertyDetails(NONE, INTERCEPTOR);
    252   }
    253 
    254   void NotFound() {
    255     lookup_type_ = NOT_FOUND;
    256     holder_ = NULL;
    257   }
    258 
    259   JSObject* holder() {
    260     ASSERT(IsFound());
    261     return JSObject::cast(holder_);
    262   }
    263 
    264   JSProxy* proxy() {
    265     ASSERT(IsFound());
    266     return JSProxy::cast(holder_);
    267   }
    268 
    269   PropertyType type() {
    270     ASSERT(IsFound());
    271     return details_.type();
    272   }
    273 
    274   PropertyAttributes GetAttributes() {
    275     ASSERT(IsFound());
    276     return details_.attributes();
    277   }
    278 
    279   PropertyDetails GetPropertyDetails() {
    280     return details_;
    281   }
    282 
    283   bool IsReadOnly() { return details_.IsReadOnly(); }
    284   bool IsDontDelete() { return details_.IsDontDelete(); }
    285   bool IsDontEnum() { return details_.IsDontEnum(); }
    286   bool IsDeleted() { return details_.IsDeleted(); }
    287   bool IsFound() { return lookup_type_ != NOT_FOUND; }
    288   bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
    289 
    290   // Is the result is a property excluding transitions and the null descriptor?
    291   bool IsProperty() {
    292     return IsFound() && IsPropertyDescriptor(this);
    293   }
    294 
    295   bool IsCacheable() { return cacheable_; }
    296   void DisallowCaching() { cacheable_ = false; }
    297 
    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 
    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 
    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 
    332   int GetFieldIndex() {
    333     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
    334     ASSERT(type() == FIELD);
    335     return Descriptor::IndexFromValue(GetValue());
    336   }
    337 
    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 
    346   int GetDictionaryEntry() {
    347     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    348     return number_;
    349   }
    350 
    351   JSFunction* GetConstantFunction() {
    352     ASSERT(type() == CONSTANT_FUNCTION);
    353     return JSFunction::cast(GetValue());
    354   }
    355 
    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 
    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 
    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