Home | History | Annotate | Download | only in src
      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:
     44   static int IndexFromValue(Object* value) {
     45     return Smi::cast(value)->value();
     46   }
     47 
     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 
     59   String* GetKey() { return key_; }
     60   Object* GetValue() { return value_; }
     61   PropertyDetails GetDetails() { return details_; }
     62 
     63 #ifdef OBJECT_PRINT
     64   void Print(FILE* out);
     65 #endif
     66 
     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:
     78   Descriptor() : details_(Smi::FromInt(0)) {}
     79 
     80   void Init(String* key, Object* value, PropertyDetails details) {
     81     key_ = key;
     82     value_ = value;
     83     details_ = details;
     84   }
     85 
     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)
     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:
    109   MapTransitionDescriptor(String* key, Map* map, PropertyAttributes attributes)
    110       : Descriptor(key, map, attributes, MAP_TRANSITION) { }
    111 };
    112 
    113 class ExternalArrayTransitionDescriptor: public Descriptor {
    114  public:
    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:
    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)
    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)
    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)
    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 
    176   LookupResult()
    177       : lookup_type_(NOT_FOUND),
    178         cacheable_(true),
    179         details_(NONE, NORMAL) {}
    180 
    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 
    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 
    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 
    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 
    212   void InterceptorResult(JSObject* holder) {
    213     lookup_type_ = INTERCEPTOR_TYPE;
    214     holder_ = holder;
    215     details_ = PropertyDetails(NONE, INTERCEPTOR);
    216   }
    217 
    218   void NotFound() {
    219     lookup_type_ = NOT_FOUND;
    220   }
    221 
    222   JSObject* holder() {
    223     ASSERT(IsFound());
    224     return holder_;
    225   }
    226 
    227   PropertyType type() {
    228     ASSERT(IsFound());
    229     return details_.type();
    230   }
    231 
    232   PropertyAttributes GetAttributes() {
    233     ASSERT(IsFound());
    234     return details_.attributes();
    235   }
    236 
    237   PropertyDetails GetPropertyDetails() {
    238     return details_;
    239   }
    240 
    241   bool IsReadOnly() { return details_.IsReadOnly(); }
    242   bool IsDontDelete() { return details_.IsDontDelete(); }
    243   bool IsDontEnum() { return details_.IsDontEnum(); }
    244   bool IsDeleted() { return details_.IsDeleted(); }
    245   bool IsFound() { return lookup_type_ != NOT_FOUND; }
    246 
    247   // Is the result is a property excluding transitions and the null
    248   // descriptor?
    249   bool IsProperty() {
    250     return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE);
    251   }
    252 
    253   // Is the result a property or a transition?
    254   bool IsPropertyOrTransition() {
    255     return IsFound() && (type() != NULL_DESCRIPTOR);
    256   }
    257 
    258   bool IsCacheable() { return cacheable_; }
    259   void DisallowCaching() { cacheable_ = false; }
    260 
    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 
    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 
    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 
    293   int GetFieldIndex() {
    294     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
    295     ASSERT(type() == FIELD);
    296     return Descriptor::IndexFromValue(GetValue());
    297   }
    298 
    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 
    307   int GetDictionaryEntry() {
    308     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    309     return number_;
    310   }
    311 
    312   JSFunction* GetConstantFunction() {
    313     ASSERT(type() == CONSTANT_FUNCTION);
    314     return JSFunction::cast(GetValue());
    315   }
    316 
    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 
    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 
    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