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