Home | History | Annotate | Download | only in src
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_PROPERTY_H_
      6 #define V8_PROPERTY_H_
      7 
      8 #include "src/isolate.h"
      9 #include "src/factory.h"
     10 #include "src/field-index.h"
     11 #include "src/field-index-inl.h"
     12 #include "src/types.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 // Abstraction for elements in instance-descriptor arrays.
     18 //
     19 // Each descriptor has a key, property attributes, property type,
     20 // property index (in the actual instance-descriptor array) and
     21 // optionally a piece of data.
     22 class Descriptor BASE_EMBEDDED {
     23  public:
     24   void KeyToUniqueName() {
     25     if (!key_->IsUniqueName()) {
     26       key_ = key_->GetIsolate()->factory()->InternalizeString(
     27           Handle<String>::cast(key_));
     28     }
     29   }
     30 
     31   Handle<Name> GetKey() { return key_; }
     32   Handle<Object> GetValue() { return value_; }
     33   PropertyDetails GetDetails() { return details_; }
     34 
     35 #ifdef OBJECT_PRINT
     36   void Print(FILE* out);
     37 #endif
     38 
     39   void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
     40 
     41  private:
     42   Handle<Name> key_;
     43   Handle<Object> value_;
     44   PropertyDetails details_;
     45 
     46  protected:
     47   Descriptor() : details_(Smi::FromInt(0)) {}
     48 
     49   void Init(Handle<Name> key, Handle<Object> value, PropertyDetails details) {
     50     key_ = key;
     51     value_ = value;
     52     details_ = details;
     53   }
     54 
     55   Descriptor(Handle<Name> key, Handle<Object> value, PropertyDetails details)
     56       : key_(key),
     57         value_(value),
     58         details_(details) { }
     59 
     60   Descriptor(Handle<Name> key,
     61              Handle<Object> value,
     62              PropertyAttributes attributes,
     63              PropertyType type,
     64              Representation representation,
     65              int field_index = 0)
     66       : key_(key),
     67         value_(value),
     68         details_(attributes, type, representation, field_index) { }
     69 
     70   friend class DescriptorArray;
     71   friend class Map;
     72 };
     73 
     74 
     75 class FieldDescriptor V8_FINAL : public Descriptor {
     76  public:
     77   FieldDescriptor(Handle<Name> key,
     78                   int field_index,
     79                   PropertyAttributes attributes,
     80                   Representation representation)
     81       : Descriptor(key, HeapType::Any(key->GetIsolate()), attributes,
     82                    FIELD, representation, field_index) {}
     83   FieldDescriptor(Handle<Name> key,
     84                   int field_index,
     85                   Handle<HeapType> field_type,
     86                   PropertyAttributes attributes,
     87                   Representation representation)
     88       : Descriptor(key, field_type, attributes, FIELD,
     89                    representation, field_index) { }
     90 };
     91 
     92 
     93 class ConstantDescriptor V8_FINAL : public Descriptor {
     94  public:
     95   ConstantDescriptor(Handle<Name> key,
     96                      Handle<Object> value,
     97                      PropertyAttributes attributes)
     98       : Descriptor(key, value, attributes, CONSTANT,
     99                    value->OptimalRepresentation()) {}
    100 };
    101 
    102 
    103 class CallbacksDescriptor V8_FINAL : public Descriptor {
    104  public:
    105   CallbacksDescriptor(Handle<Name> key,
    106                       Handle<Object> foreign,
    107                       PropertyAttributes attributes)
    108       : Descriptor(key, foreign, attributes, CALLBACKS,
    109                    Representation::Tagged()) {}
    110 };
    111 
    112 
    113 class LookupResult V8_FINAL BASE_EMBEDDED {
    114  public:
    115   explicit LookupResult(Isolate* isolate)
    116       : isolate_(isolate),
    117         next_(isolate->top_lookup_result()),
    118         lookup_type_(NOT_FOUND),
    119         holder_(NULL),
    120         transition_(NULL),
    121         cacheable_(true),
    122         details_(NONE, NONEXISTENT, Representation::None()) {
    123     isolate->set_top_lookup_result(this);
    124   }
    125 
    126   ~LookupResult() {
    127     ASSERT(isolate()->top_lookup_result() == this);
    128     isolate()->set_top_lookup_result(next_);
    129   }
    130 
    131   Isolate* isolate() const { return isolate_; }
    132 
    133   void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
    134     lookup_type_ = DESCRIPTOR_TYPE;
    135     holder_ = holder;
    136     transition_ = NULL;
    137     details_ = details;
    138     number_ = number;
    139   }
    140 
    141   bool CanHoldValue(Handle<Object> value) const {
    142     switch (type()) {
    143       case NORMAL:
    144         return true;
    145       case FIELD:
    146         return value->FitsRepresentation(representation()) &&
    147             GetFieldType()->NowContains(value);
    148       case CONSTANT:
    149         ASSERT(GetConstant() != *value ||
    150                value->FitsRepresentation(representation()));
    151         return GetConstant() == *value;
    152       case CALLBACKS:
    153       case HANDLER:
    154       case INTERCEPTOR:
    155         return true;
    156       case NONEXISTENT:
    157         UNREACHABLE();
    158     }
    159     UNREACHABLE();
    160     return true;
    161   }
    162 
    163   void TransitionResult(JSObject* holder, Map* target) {
    164     lookup_type_ = TRANSITION_TYPE;
    165     number_ = target->LastAdded();
    166     details_ = target->instance_descriptors()->GetDetails(number_);
    167     holder_ = holder;
    168     transition_ = target;
    169   }
    170 
    171   void DictionaryResult(JSObject* holder, int entry) {
    172     lookup_type_ = DICTIONARY_TYPE;
    173     holder_ = holder;
    174     transition_ = NULL;
    175     details_ = holder->property_dictionary()->DetailsAt(entry);
    176     number_ = entry;
    177   }
    178 
    179   void HandlerResult(JSProxy* proxy) {
    180     lookup_type_ = HANDLER_TYPE;
    181     holder_ = proxy;
    182     transition_ = NULL;
    183     details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
    184     cacheable_ = false;
    185   }
    186 
    187   void InterceptorResult(JSObject* holder) {
    188     lookup_type_ = INTERCEPTOR_TYPE;
    189     holder_ = holder;
    190     transition_ = NULL;
    191     details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
    192   }
    193 
    194   void NotFound() {
    195     lookup_type_ = NOT_FOUND;
    196     details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
    197     holder_ = NULL;
    198     transition_ = NULL;
    199   }
    200 
    201   JSObject* holder() const {
    202     ASSERT(IsFound());
    203     return JSObject::cast(holder_);
    204   }
    205 
    206   JSProxy* proxy() const {
    207     ASSERT(IsHandler());
    208     return JSProxy::cast(holder_);
    209   }
    210 
    211   PropertyType type() const {
    212     ASSERT(IsFound());
    213     return details_.type();
    214   }
    215 
    216   Representation representation() const {
    217     ASSERT(IsFound());
    218     ASSERT(details_.type() != NONEXISTENT);
    219     return details_.representation();
    220   }
    221 
    222   PropertyAttributes GetAttributes() const {
    223     ASSERT(IsFound());
    224     ASSERT(details_.type() != NONEXISTENT);
    225     return details_.attributes();
    226   }
    227 
    228   PropertyDetails GetPropertyDetails() const {
    229     return details_;
    230   }
    231 
    232   bool IsFastPropertyType() const {
    233     ASSERT(IsFound());
    234     return IsTransition() || type() != NORMAL;
    235   }
    236 
    237   // Property callbacks does not include transitions to callbacks.
    238   bool IsPropertyCallbacks() const {
    239     ASSERT(!(details_.type() == CALLBACKS && !IsFound()));
    240     return !IsTransition() && details_.type() == CALLBACKS;
    241   }
    242 
    243   bool IsReadOnly() const {
    244     ASSERT(IsFound());
    245     ASSERT(details_.type() != NONEXISTENT);
    246     return details_.IsReadOnly();
    247   }
    248 
    249   bool IsField() const {
    250     ASSERT(!(details_.type() == FIELD && !IsFound()));
    251     return IsDescriptorOrDictionary() && type() == FIELD;
    252   }
    253 
    254   bool IsNormal() const {
    255     ASSERT(!(details_.type() == NORMAL && !IsFound()));
    256     return IsDescriptorOrDictionary() && type() == NORMAL;
    257   }
    258 
    259   bool IsConstant() const {
    260     ASSERT(!(details_.type() == CONSTANT && !IsFound()));
    261     return IsDescriptorOrDictionary() && type() == CONSTANT;
    262   }
    263 
    264   bool IsConstantFunction() const {
    265     return IsConstant() && GetConstant()->IsJSFunction();
    266   }
    267 
    268   bool IsDontDelete() const { return details_.IsDontDelete(); }
    269   bool IsDontEnum() const { return details_.IsDontEnum(); }
    270   bool IsFound() const { return lookup_type_ != NOT_FOUND; }
    271   bool IsDescriptorOrDictionary() const {
    272     return lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE;
    273   }
    274   bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
    275   bool IsHandler() const { return lookup_type_ == HANDLER_TYPE; }
    276   bool IsInterceptor() const { return lookup_type_ == INTERCEPTOR_TYPE; }
    277 
    278   // Is the result is a property excluding transitions and the null descriptor?
    279   bool IsProperty() const {
    280     return IsFound() && !IsTransition();
    281   }
    282 
    283   bool IsDataProperty() const {
    284     switch (lookup_type_) {
    285       case NOT_FOUND:
    286       case TRANSITION_TYPE:
    287       case HANDLER_TYPE:
    288       case INTERCEPTOR_TYPE:
    289         return false;
    290 
    291       case DESCRIPTOR_TYPE:
    292       case DICTIONARY_TYPE:
    293         switch (type()) {
    294           case FIELD:
    295           case NORMAL:
    296           case CONSTANT:
    297             return true;
    298           case CALLBACKS: {
    299             Object* callback = GetCallbackObject();
    300             ASSERT(!callback->IsForeign());
    301             return callback->IsAccessorInfo();
    302           }
    303           case HANDLER:
    304           case INTERCEPTOR:
    305           case NONEXISTENT:
    306             UNREACHABLE();
    307             return false;
    308         }
    309     }
    310     UNREACHABLE();
    311     return false;
    312   }
    313 
    314   bool IsCacheable() const { return cacheable_; }
    315   void DisallowCaching() { cacheable_ = false; }
    316 
    317   Object* GetLazyValue() const {
    318     switch (lookup_type_) {
    319       case NOT_FOUND:
    320       case TRANSITION_TYPE:
    321       case HANDLER_TYPE:
    322       case INTERCEPTOR_TYPE:
    323         return isolate()->heap()->the_hole_value();
    324 
    325       case DESCRIPTOR_TYPE:
    326       case DICTIONARY_TYPE:
    327         switch (type()) {
    328           case FIELD:
    329             return holder()->RawFastPropertyAt(GetFieldIndex());
    330           case NORMAL: {
    331             Object* value = holder()->property_dictionary()->ValueAt(
    332                 GetDictionaryEntry());
    333             if (holder()->IsGlobalObject()) {
    334               value = PropertyCell::cast(value)->value();
    335             }
    336             return value;
    337           }
    338           case CONSTANT:
    339             return GetConstant();
    340           case CALLBACKS:
    341             return isolate()->heap()->the_hole_value();
    342           case HANDLER:
    343           case INTERCEPTOR:
    344           case NONEXISTENT:
    345             UNREACHABLE();
    346             return NULL;
    347         }
    348     }
    349     UNREACHABLE();
    350     return NULL;
    351   }
    352 
    353   Map* GetTransitionTarget() const {
    354     ASSERT(IsTransition());
    355     return transition_;
    356   }
    357 
    358   bool IsTransitionToField() const {
    359     return IsTransition() && details_.type() == FIELD;
    360   }
    361 
    362   bool IsTransitionToConstant() const {
    363     return IsTransition() && details_.type() == CONSTANT;
    364   }
    365 
    366   int GetDescriptorIndex() const {
    367     ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
    368     return number_;
    369   }
    370 
    371   FieldIndex GetFieldIndex() const {
    372     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
    373            lookup_type_ == TRANSITION_TYPE);
    374     return FieldIndex::ForLookupResult(this);
    375   }
    376 
    377   int GetLocalFieldIndexFromMap(Map* map) const {
    378     return GetFieldIndexFromMap(map) - map->inobject_properties();
    379   }
    380 
    381   int GetDictionaryEntry() const {
    382     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    383     return number_;
    384   }
    385 
    386   JSFunction* GetConstantFunction() const {
    387     ASSERT(type() == CONSTANT);
    388     return JSFunction::cast(GetValue());
    389   }
    390 
    391   Object* GetConstantFromMap(Map* map) const {
    392     ASSERT(type() == CONSTANT);
    393     return GetValueFromMap(map);
    394   }
    395 
    396   JSFunction* GetConstantFunctionFromMap(Map* map) const {
    397     return JSFunction::cast(GetConstantFromMap(map));
    398   }
    399 
    400   Object* GetConstant() const {
    401     ASSERT(type() == CONSTANT);
    402     return GetValue();
    403   }
    404 
    405   Object* GetCallbackObject() const {
    406     ASSERT(!IsTransition());
    407     ASSERT(type() == CALLBACKS);
    408     return GetValue();
    409   }
    410 
    411 #ifdef OBJECT_PRINT
    412   void Print(FILE* out);
    413 #endif
    414 
    415   Object* GetValue() const {
    416     if (lookup_type_ == DESCRIPTOR_TYPE) {
    417       return GetValueFromMap(holder()->map());
    418     } else if (lookup_type_ == TRANSITION_TYPE) {
    419       return GetValueFromMap(transition_);
    420     }
    421     // In the dictionary case, the data is held in the value field.
    422     ASSERT(lookup_type_ == DICTIONARY_TYPE);
    423     return holder()->GetNormalizedProperty(this);
    424   }
    425 
    426   Object* GetValueFromMap(Map* map) const {
    427     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
    428            lookup_type_ == TRANSITION_TYPE);
    429     ASSERT(number_ < map->NumberOfOwnDescriptors());
    430     return map->instance_descriptors()->GetValue(number_);
    431   }
    432 
    433   int GetFieldIndexFromMap(Map* map) const {
    434     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
    435            lookup_type_ == TRANSITION_TYPE);
    436     ASSERT(number_ < map->NumberOfOwnDescriptors());
    437     return map->instance_descriptors()->GetFieldIndex(number_);
    438   }
    439 
    440   HeapType* GetFieldType() const {
    441     ASSERT(type() == FIELD);
    442     if (lookup_type_ == DESCRIPTOR_TYPE) {
    443       return GetFieldTypeFromMap(holder()->map());
    444     }
    445     ASSERT(lookup_type_ == TRANSITION_TYPE);
    446     return GetFieldTypeFromMap(transition_);
    447   }
    448 
    449   HeapType* GetFieldTypeFromMap(Map* map) const {
    450     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
    451            lookup_type_ == TRANSITION_TYPE);
    452     ASSERT(number_ < map->NumberOfOwnDescriptors());
    453     return map->instance_descriptors()->GetFieldType(number_);
    454   }
    455 
    456   Map* GetFieldOwner() const {
    457     return GetFieldOwnerFromMap(holder()->map());
    458   }
    459 
    460   Map* GetFieldOwnerFromMap(Map* map) const {
    461     ASSERT(lookup_type_ == DESCRIPTOR_TYPE ||
    462            lookup_type_ == TRANSITION_TYPE);
    463     ASSERT(number_ < map->NumberOfOwnDescriptors());
    464     return map->FindFieldOwner(number_);
    465   }
    466 
    467   void Iterate(ObjectVisitor* visitor);
    468 
    469  private:
    470   Isolate* isolate_;
    471   LookupResult* next_;
    472 
    473   // Where did we find the result;
    474   enum {
    475     NOT_FOUND,
    476     DESCRIPTOR_TYPE,
    477     TRANSITION_TYPE,
    478     DICTIONARY_TYPE,
    479     HANDLER_TYPE,
    480     INTERCEPTOR_TYPE
    481   } lookup_type_;
    482 
    483   JSReceiver* holder_;
    484   Map* transition_;
    485   int number_;
    486   bool cacheable_;
    487   PropertyDetails details_;
    488 };
    489 
    490 } }  // namespace v8::internal
    491 
    492 #endif  // V8_PROPERTY_H_
    493