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   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 
     57   String* GetKey() { return key_; }
     58   Object* GetValue() { return value_; }
     59   PropertyDetails GetDetails() { return details_; }
     60 
     61 #ifdef DEBUG
     62   void Print();
     63 #endif
     64 
     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:
     76   Descriptor() : details_(Smi::FromInt(0)) {}
     77 
     78   void Init(String* key, Object* value, PropertyDetails details) {
     79     key_ = key;
     80     value_ = value;
     81     details_ = details;
     82   }
     83 
     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)
     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:
    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:
    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)
    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)
    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)
    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 
    164   LookupResult()
    165       : lookup_type_(NOT_FOUND),
    166         cacheable_(true),
    167         details_(NONE, NORMAL) {}
    168 
    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 
    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 
    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 
    193   void InterceptorResult(JSObject* holder) {
    194     lookup_type_ = INTERCEPTOR_TYPE;
    195     holder_ = holder;
    196     details_ = PropertyDetails(NONE, INTERCEPTOR);
    197   }
    198 
    199   void NotFound() {
    200     lookup_type_ = NOT_FOUND;
    201   }
    202 
    203   JSObject* holder() {
    204     ASSERT(IsFound());
    205     return holder_;
    206   }
    207 
    208   PropertyType type() {
    209     ASSERT(IsFound());
    210     return details_.type();
    211   }
    212 
    213   PropertyAttributes GetAttributes() {
    214     ASSERT(IsFound());
    215     return details_.attributes();
    216   }
    217 
    218   PropertyDetails GetPropertyDetails() {
    219     return details_;
    220   }
    221 
    222   bool IsReadOnly() { return details_.IsReadOnly(); }
    223   bool IsDontDelete() { return details_.IsDontDelete(); }
    224   bool IsDontEnum() { return details_.IsDontEnum(); }
    225   bool IsDeleted() { return details_.IsDeleted(); }
    226   bool IsFound() { return lookup_type_ != NOT_FOUND; }
    227 
    228   // Is the result is a property excluding transitions and the null
    229   // descriptor?
    230   bool IsProperty() {
    231     return IsFound() && (type() < FIRST_PHANTOM_PROPERTY_TYPE);
    232   }
    233 
    234   // Is the result a property or a transition?
    235   bool IsPropertyOrTransition() {
    236     return IsFound() && (type() != NULL_DESCRIPTOR);
    237   }
    238 
    239   bool IsCacheable() { return cacheable_; }
    240   void DisallowCaching() { cacheable_ = false; }
    241 
    242   Object* GetLazyValue() {
    243     switch (type()) {
    244       case FIELD:
    245         return holder()->FastPropertyAt(GetFieldIndex());
    246       case NORMAL: {
    247         Object* value;
    248         value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
    249         if (holder()->IsGlobalObject()) {
    250           value = JSGlobalPropertyCell::cast(value)->value();
    251         }
    252         return value;
    253       }
    254       case CONSTANT_FUNCTION:
    255         return GetConstantFunction();
    256       default:
    257         return Smi::FromInt(0);
    258     }
    259   }
    260 
    261   Map* GetTransitionMap() {
    262     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
    263     ASSERT(type() == MAP_TRANSITION);
    264     return Map::cast(GetValue());
    265   }
    266 
    267   int GetFieldIndex() {
    268     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
    269     ASSERT(type() == FIELD);
    270     return Descriptor::IndexFromValue(GetValue());
    271   }
    272 
    273   int GetDictionaryEntry() {
    274     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    275     return number_;
    276   }
    277 
    278   JSFunction* GetConstantFunction() {
    279     ASSERT(type() == CONSTANT_FUNCTION);
    280     return JSFunction::cast(GetValue());
    281   }
    282 
    283   Object* GetCallbackObject() {
    284     if (lookup_type_ == CONSTANT_TYPE) {
    285       // For now we only have the __proto__ as constant type.
    286       return Heap::prototype_accessors();
    287     }
    288     return GetValue();
    289   }
    290 
    291 #ifdef DEBUG
    292   void Print();
    293 #endif
    294 
    295   Object* GetValue() {
    296     if (lookup_type_ == DESCRIPTOR_TYPE) {
    297       DescriptorArray* descriptors = holder()->map()->instance_descriptors();
    298       return descriptors->GetValue(number_);
    299     }
    300     // In the dictionary case, the data is held in the value field.
    301     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    302     return holder()->GetNormalizedProperty(this);
    303   }
    304 
    305  private:
    306   JSObject* holder_;
    307   int number_;
    308   bool cacheable_;
    309   PropertyDetails details_;
    310 };
    311 
    312 
    313 } }  // namespace v8::internal
    314 
    315 #endif  // V8_PROPERTY_H_
    316