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