LCOV - code coverage report
Current view: top level - src/objects - literal-objects.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 203 206 98.5 %
Date: 2019-03-21 Functions: 19 20 95.0 %

          Line data    Source code
       1             : // Copyright 2017 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             : #include "src/objects/literal-objects.h"
       6             : 
       7             : #include "src/accessors.h"
       8             : #include "src/ast/ast.h"
       9             : #include "src/heap/factory.h"
      10             : #include "src/isolate.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/hash-table-inl.h"
      13             : #include "src/objects/literal-objects-inl.h"
      14             : #include "src/objects/smi.h"
      15             : #include "src/objects/struct-inl.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20     4650826 : Object ObjectBoilerplateDescription::name(int index) const {
      21             :   // get() already checks for out of bounds access, but we do not want to allow
      22             :   // access to the last element, if it is the number of properties.
      23             :   DCHECK_NE(size(), index);
      24     9301652 :   return get(2 * index + kDescriptionStartIndex);
      25             : }
      26             : 
      27     4650829 : Object ObjectBoilerplateDescription::value(int index) const {
      28     9301657 :   return get(2 * index + 1 + kDescriptionStartIndex);
      29             : }
      30             : 
      31     1960429 : void ObjectBoilerplateDescription::set_key_value(int index, Object key,
      32             :                                                  Object value) {
      33             :   DCHECK_LT(index, size());
      34             :   DCHECK_GE(index, 0);
      35     1960429 :   set(2 * index + kDescriptionStartIndex, key);
      36     1960429 :   set(2 * index + 1 + kDescriptionStartIndex, value);
      37     1960429 : }
      38             : 
      39      376001 : int ObjectBoilerplateDescription::size() const {
      40             :   DCHECK_EQ(0, (length() - kDescriptionStartIndex -
      41             :                 (this->has_number_of_properties() ? 1 : 0)) %
      42             :                    2);
      43             :   // Rounding is intended.
      44      732421 :   return (length() - kDescriptionStartIndex) / 2;
      45             : }
      46             : 
      47      361391 : int ObjectBoilerplateDescription::backing_store_size() const {
      48      361391 :   if (has_number_of_properties()) {
      49             :     // If present, the last entry contains the number of properties.
      50        4971 :     return Smi::ToInt(this->get(length() - 1));
      51             :   }
      52             :   // If the number is not given explicitly, we assume there are no
      53             :   // properties with computed names.
      54      356420 :   return size();
      55             : }
      56             : 
      57        2751 : void ObjectBoilerplateDescription::set_backing_store_size(
      58             :     Isolate* isolate, int backing_store_size) {
      59             :   DCHECK(has_number_of_properties());
      60             :   DCHECK_NE(size(), backing_store_size);
      61             :   Handle<Object> backing_store_size_obj =
      62        2751 :       isolate->factory()->NewNumberFromInt(backing_store_size);
      63        2751 :   set(length() - 1, *backing_store_size_obj);
      64        2751 : }
      65             : 
      66           0 : bool ObjectBoilerplateDescription::has_number_of_properties() const {
      67      361391 :   return (length() - kDescriptionStartIndex) % 2 != 0;
      68             : }
      69             : 
      70             : namespace {
      71             : 
      72             : inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
      73             :                                unsigned key_index) {
      74             :   typedef ClassBoilerplate::ComputedEntryFlags Flags;
      75        5528 :   int flags = Flags::ValueKindBits::encode(value_kind) |
      76        5528 :               Flags::KeyIndexBits::encode(key_index);
      77             :   return flags;
      78             : }
      79             : 
      80      254394 : void AddToDescriptorArrayTemplate(
      81             :     Isolate* isolate, Handle<DescriptorArray> descriptor_array_template,
      82             :     Handle<Name> name, ClassBoilerplate::ValueKind value_kind,
      83             :     Handle<Object> value) {
      84      763182 :   int entry = descriptor_array_template->Search(
      85             :       *name, descriptor_array_template->number_of_descriptors());
      86             :   // TODO(ishell): deduplicate properties at AST level, this will allow us to
      87             :   // avoid creation of closures that will be overwritten anyway.
      88      254394 :   if (entry == DescriptorArray::kNotFound) {
      89             :     // Entry not found, add new one.
      90      254216 :     Descriptor d;
      91      254216 :     if (value_kind == ClassBoilerplate::kData) {
      92      250976 :       d = Descriptor::DataConstant(name, value, DONT_ENUM);
      93             :     } else {
      94             :       DCHECK(value_kind == ClassBoilerplate::kGetter ||
      95             :              value_kind == ClassBoilerplate::kSetter);
      96        3240 :       Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
      97        9720 :       pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
      98             :                                                         : ACCESSOR_SETTER,
      99        3240 :                 *value);
     100        3240 :       d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
     101             :     }
     102      254216 :     descriptor_array_template->Append(&d);
     103             : 
     104             :   } else {
     105             :     // Entry found, update it.
     106         356 :     int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
     107         178 :     if (value_kind == ClassBoilerplate::kData) {
     108          36 :       Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
     109             :       d.SetSortedKeyIndex(sorted_index);
     110          36 :       descriptor_array_template->Set(entry, &d);
     111             :     } else {
     112             :       DCHECK(value_kind == ClassBoilerplate::kGetter ||
     113             :              value_kind == ClassBoilerplate::kSetter);
     114         142 :       Object raw_accessor = descriptor_array_template->GetStrongValue(entry);
     115         142 :       AccessorPair pair;
     116         142 :       if (raw_accessor->IsAccessorPair()) {
     117         118 :         pair = AccessorPair::cast(raw_accessor);
     118             :       } else {
     119          24 :         Handle<AccessorPair> new_pair = isolate->factory()->NewAccessorPair();
     120          24 :         Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
     121             :         d.SetSortedKeyIndex(sorted_index);
     122          24 :         descriptor_array_template->Set(entry, &d);
     123          24 :         pair = *new_pair;
     124             :       }
     125         142 :       pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
     126             :                                                         : ACCESSOR_SETTER,
     127         142 :                 *value);
     128             :     }
     129             :   }
     130      254394 : }
     131             : 
     132             : Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
     133             :     Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
     134             :     Handle<Object> value, PropertyDetails details, int* entry_out = nullptr) {
     135             :   return NameDictionary::AddNoUpdateNextEnumerationIndex(
     136       35727 :       isolate, dictionary, name, value, details, entry_out);
     137             : }
     138             : 
     139             : Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
     140             :     Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t element,
     141             :     Handle<Object> value, PropertyDetails details, int* entry_out = nullptr) {
     142             :   // NumberDictionary does not maintain the enumeration order, so it's
     143             :   // a normal Add().
     144             :   return NumberDictionary::Add(isolate, dictionary, element, value, details,
     145         446 :                                entry_out);
     146             : }
     147             : 
     148             : void DictionaryUpdateMaxNumberKey(Handle<NameDictionary> dictionary,
     149             :                                   Handle<Name> name) {
     150             :   // No-op for name dictionaries.
     151             : }
     152             : 
     153         446 : void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary,
     154             :                                   uint32_t element) {
     155         446 :   dictionary->UpdateMaxNumberKey(element, Handle<JSObject>());
     156             :   dictionary->set_requires_slow_elements();
     157         446 : }
     158             : 
     159             : constexpr int ComputeEnumerationIndex(int value_index) {
     160             :   // We "shift" value indices to ensure that the enumeration index for the value
     161             :   // will not overlap with minimum properties set for both class and prototype
     162             :   // objects.
     163             :   return value_index + Max(ClassBoilerplate::kMinimumClassPropertiesCount,
     164       56753 :                            ClassBoilerplate::kMinimumPrototypePropertiesCount);
     165             : }
     166             : 
     167             : inline int GetExistingValueIndex(Object value) {
     168         255 :   return value->IsSmi() ? Smi::ToInt(value) : -1;
     169             : }
     170             : 
     171             : template <typename Dictionary, typename Key>
     172       27682 : void AddToDictionaryTemplate(Isolate* isolate, Handle<Dictionary> dictionary,
     173             :                              Key key, int key_index,
     174             :                              ClassBoilerplate::ValueKind value_kind,
     175             :                              Object value) {
     176       27682 :   int entry = dictionary->FindEntry(isolate, key);
     177             : 
     178       27682 :   if (entry == kNotFound) {
     179             :     // Entry not found, add new one.
     180             :     const bool is_elements_dictionary =
     181             :         std::is_same<Dictionary, NumberDictionary>::value;
     182             :     STATIC_ASSERT(is_elements_dictionary !=
     183             :                   (std::is_same<Dictionary, NameDictionary>::value));
     184             :     int enum_order =
     185             :         is_elements_dictionary ? 0 : ComputeEnumerationIndex(key_index);
     186             :     Handle<Object> value_handle;
     187             :     PropertyDetails details(
     188             :         value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
     189       27449 :         PropertyCellType::kNoCell, enum_order);
     190             : 
     191       27449 :     if (value_kind == ClassBoilerplate::kData) {
     192             :       value_handle = handle(value, isolate);
     193             :     } else {
     194             :       AccessorComponent component = value_kind == ClassBoilerplate::kGetter
     195             :                                         ? ACCESSOR_GETTER
     196        2800 :                                         : ACCESSOR_SETTER;
     197        2800 :       Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
     198        2800 :       pair->set(component, value);
     199             :       value_handle = pair;
     200             :     }
     201             : 
     202             :     // Add value to the dictionary without updating next enumeration index.
     203             :     Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
     204             :         isolate, dictionary, key, value_handle, details, &entry);
     205             :     // It is crucial to avoid dictionary reallocations because it may remove
     206             :     // potential gaps in enumeration indices values that are necessary for
     207             :     // inserting computed properties into right places in the enumeration order.
     208       27449 :     CHECK_EQ(*dict, *dictionary);
     209             : 
     210         446 :     DictionaryUpdateMaxNumberKey(dictionary, key);
     211             : 
     212             :   } else {
     213             :     // Entry found, update it.
     214             :     int enum_order = dictionary->DetailsAt(entry).dictionary_index();
     215         466 :     Object existing_value = dictionary->ValueAt(entry);
     216         233 :     if (value_kind == ClassBoilerplate::kData) {
     217             :       // Computed value is a normal method.
     218          90 :       if (existing_value->IsAccessorPair()) {
     219          72 :         AccessorPair current_pair = AccessorPair::cast(existing_value);
     220             : 
     221             :         int existing_getter_index =
     222             :             GetExistingValueIndex(current_pair->getter());
     223             :         int existing_setter_index =
     224             :             GetExistingValueIndex(current_pair->setter());
     225             :         // At least one of the accessors must already be defined.
     226             :         DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
     227          72 :         if (existing_getter_index < key_index &&
     228             :             existing_setter_index < key_index) {
     229             :           // Either both getter and setter were defined before the computed
     230             :           // method or just one of them was defined before while the other one
     231             :           // was not defined yet, so overwrite property to kData.
     232             :           PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
     233             :                                   enum_order);
     234           0 :           dictionary->DetailsAtPut(isolate, entry, details);
     235           0 :           dictionary->ValueAtPut(entry, value);
     236             : 
     237             :         } else {
     238             :           // The data property was defined "between" accessors so the one that
     239             :           // was overwritten has to be cleared.
     240          72 :           if (existing_getter_index < key_index) {
     241             :             DCHECK_LT(key_index, existing_setter_index);
     242             :             // Getter was defined and it was done before the computed method
     243             :             // and then it was overwritten by the current computed method which
     244             :             // in turn was later overwritten by the setter method. So we clear
     245             :             // the getter.
     246          36 :             current_pair->set_getter(*isolate->factory()->null_value());
     247             : 
     248          36 :           } else if (existing_setter_index < key_index) {
     249             :             DCHECK_LT(key_index, existing_getter_index);
     250             :             // Setter was defined and it was done before the computed method
     251             :             // and then it was overwritten by the current computed method which
     252             :             // in turn was later overwritten by the getter method. So we clear
     253             :             // the setter.
     254          36 :             current_pair->set_setter(*isolate->factory()->null_value());
     255             :           }
     256             :         }
     257             :       } else {
     258             :         // Overwrite existing value if it was defined before the computed one.
     259             :         int existing_value_index = Smi::ToInt(existing_value);
     260          18 :         if (existing_value_index < key_index) {
     261             :           PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
     262             :                                   enum_order);
     263          18 :           dictionary->DetailsAtPut(isolate, entry, details);
     264          54 :           dictionary->ValueAtPut(entry, value);
     265             :         }
     266             :       }
     267             :     } else {
     268             :       AccessorComponent component = value_kind == ClassBoilerplate::kGetter
     269             :                                         ? ACCESSOR_GETTER
     270         143 :                                         : ACCESSOR_SETTER;
     271         143 :       if (existing_value->IsAccessorPair()) {
     272         111 :         AccessorPair current_pair = AccessorPair::cast(existing_value);
     273             : 
     274             :         int existing_component_index =
     275         111 :             GetExistingValueIndex(current_pair->get(component));
     276         111 :         if (existing_component_index < key_index) {
     277          93 :           current_pair->set(component, value);
     278             :         }
     279             : 
     280             :       } else {
     281          32 :         Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
     282          32 :         pair->set(component, value);
     283             :         PropertyDetails details(kAccessor, DONT_ENUM, PropertyCellType::kNoCell,
     284             :                                 enum_order);
     285          32 :         dictionary->DetailsAtPut(isolate, entry, details);
     286          96 :         dictionary->ValueAtPut(entry, *pair);
     287             :       }
     288             :     }
     289             :   }
     290       27682 : }
     291             : 
     292             : }  // namespace
     293             : 
     294             : // Helper class that eases building of a properties, elements and computed
     295             : // properties templates.
     296       80192 : class ObjectDescriptor {
     297             :  public:
     298        5908 :   void IncComputedCount() { ++computed_count_; }
     299      279223 :   void IncPropertiesCount() { ++property_count_; }
     300         155 :   void IncElementsCount() { ++element_count_; }
     301             : 
     302             :   bool HasDictionaryProperties() const {
     303      812132 :     return computed_count_ > 0 || property_count_ > kMaxNumberOfDescriptors;
     304             :   }
     305             : 
     306             :   Handle<Object> properties_template() const {
     307             :     return HasDictionaryProperties()
     308             :                ? Handle<Object>::cast(properties_dictionary_template_)
     309       80192 :                : Handle<Object>::cast(descriptor_array_template_);
     310             :   }
     311             : 
     312             :   Handle<NumberDictionary> elements_template() const {
     313             :     return elements_dictionary_template_;
     314             :   }
     315             : 
     316             :   Handle<FixedArray> computed_properties() const {
     317             :     return computed_properties_;
     318             :   }
     319             : 
     320       80192 :   void CreateTemplates(Isolate* isolate, int slack) {
     321             :     Factory* factory = isolate->factory();
     322       80192 :     descriptor_array_template_ = factory->empty_descriptor_array();
     323       80192 :     properties_dictionary_template_ = factory->empty_property_dictionary();
     324      140477 :     if (property_count_ || HasDictionaryProperties() || slack) {
     325       80192 :       if (HasDictionaryProperties()) {
     326             :         properties_dictionary_template_ = NameDictionary::New(
     327        5596 :             isolate, property_count_ + computed_count_ + slack);
     328             :       } else {
     329             :         descriptor_array_template_ =
     330       74596 :             DescriptorArray::Allocate(isolate, 0, property_count_ + slack);
     331             :       }
     332             :     }
     333             :     elements_dictionary_template_ =
     334       80192 :         element_count_ || computed_count_
     335        5624 :             ? NumberDictionary::New(isolate, element_count_ + computed_count_)
     336      160384 :             : factory->empty_slow_element_dictionary();
     337             : 
     338             :     computed_properties_ =
     339       80192 :         computed_count_
     340             :             ? factory->NewFixedArray(computed_count_ *
     341        5584 :                                      ClassBoilerplate::kFullComputedEntrySize)
     342      160384 :             : factory->empty_fixed_array();
     343             : 
     344       80192 :     temp_handle_ = handle(Smi::kZero, isolate);
     345       80192 :   }
     346             : 
     347      196159 :   void AddConstant(Isolate* isolate, Handle<Name> name, Handle<Object> value,
     348             :                    PropertyAttributes attribs) {
     349             :     bool is_accessor = value->IsAccessorInfo();
     350             :     DCHECK(!value->IsAccessorPair());
     351      196159 :     if (HasDictionaryProperties()) {
     352        8724 :       PropertyKind kind = is_accessor ? i::kAccessor : i::kData;
     353             :       PropertyDetails details(kind, attribs, PropertyCellType::kNoCell,
     354        8724 :                               next_enumeration_index_++);
     355             :       properties_dictionary_template_ =
     356             :           DictionaryAddNoUpdateNextEnumerationIndex(
     357        8724 :               isolate, properties_dictionary_template_, name, value, details);
     358             :     } else {
     359             :       Descriptor d = is_accessor
     360             :                          ? Descriptor::AccessorConstant(name, value, attribs)
     361      187435 :                          : Descriptor::DataConstant(name, value, attribs);
     362      187435 :       descriptor_array_template_->Append(&d);
     363             :     }
     364      196159 :   }
     365             : 
     366      278616 :   void AddNamedProperty(Isolate* isolate, Handle<Name> name,
     367             :                         ClassBoilerplate::ValueKind value_kind,
     368             :                         int value_index) {
     369             :     Smi value = Smi::FromInt(value_index);
     370      278616 :     if (HasDictionaryProperties()) {
     371             :       UpdateNextEnumerationIndex(value_index);
     372             :       AddToDictionaryTemplate(isolate, properties_dictionary_template_, name,
     373       24222 :                               value_index, value_kind, value);
     374             :     } else {
     375      254394 :       *temp_handle_.location() = value->ptr();
     376             :       AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
     377      254394 :                                    value_kind, temp_handle_);
     378             :     }
     379      278616 :   }
     380             : 
     381             :   void AddIndexedProperty(Isolate* isolate, uint32_t element,
     382             :                           ClassBoilerplate::ValueKind value_kind,
     383             :                           int value_index) {
     384         155 :     Smi value = Smi::FromInt(value_index);
     385             :     AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
     386         155 :                             value_index, value_kind, value);
     387             :   }
     388             : 
     389        5528 :   void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) {
     390             :     int value_index = key_index + 1;
     391             :     UpdateNextEnumerationIndex(value_index);
     392             : 
     393        5528 :     int flags = EncodeComputedEntry(value_kind, key_index);
     394        5528 :     computed_properties_->set(current_computed_index_++, Smi::FromInt(flags));
     395        5528 :   }
     396             : 
     397             :   void UpdateNextEnumerationIndex(int value_index) {
     398             :     int next_index = ComputeEnumerationIndex(value_index);
     399             :     DCHECK_LT(next_enumeration_index_, next_index);
     400       29750 :     next_enumeration_index_ = next_index;
     401             :   }
     402             : 
     403       80192 :   void Finalize(Isolate* isolate) {
     404       80192 :     if (HasDictionaryProperties()) {
     405        5596 :       properties_dictionary_template_->SetNextEnumerationIndex(
     406             :           next_enumeration_index_);
     407             :       computed_properties_ = FixedArray::ShrinkOrEmpty(
     408        5596 :           isolate, computed_properties_, current_computed_index_);
     409             :     } else {
     410             :       DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
     411             :     }
     412       80192 :   }
     413             : 
     414             :  private:
     415             :   int property_count_ = 0;
     416             :   int next_enumeration_index_ = PropertyDetails::kInitialIndex;
     417             :   int element_count_ = 0;
     418             :   int computed_count_ = 0;
     419             :   int current_computed_index_ = 0;
     420             : 
     421             :   Handle<DescriptorArray> descriptor_array_template_;
     422             :   Handle<NameDictionary> properties_dictionary_template_;
     423             :   Handle<NumberDictionary> elements_dictionary_template_;
     424             :   Handle<FixedArray> computed_properties_;
     425             :   // This temporary handle is used for storing to descriptor array.
     426             :   Handle<Object> temp_handle_;
     427             : };
     428             : 
     429        2999 : void ClassBoilerplate::AddToPropertiesTemplate(
     430             :     Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
     431             :     int key_index, ClassBoilerplate::ValueKind value_kind, Object value) {
     432             :   AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
     433        2999 :                           value);
     434        2999 : }
     435             : 
     436         306 : void ClassBoilerplate::AddToElementsTemplate(
     437             :     Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
     438             :     int key_index, ClassBoilerplate::ValueKind value_kind, Object value) {
     439             :   AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
     440         306 :                           value);
     441         306 : }
     442             : 
     443       40096 : Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
     444             :     Isolate* isolate, ClassLiteral* expr) {
     445             :   // Create a non-caching handle scope to ensure that the temporary handle used
     446             :   // by ObjectDescriptor for passing Smis around does not corrupt handle cache
     447             :   // in CanonicalHandleScope.
     448             :   HandleScope scope(isolate);
     449             :   Factory* factory = isolate->factory();
     450             :   ObjectDescriptor static_desc;
     451             :   ObjectDescriptor instance_desc;
     452             : 
     453      610668 :   for (int i = 0; i < expr->properties()->length(); i++) {
     454      285286 :     ClassLiteral::Property* property = expr->properties()->at(i);
     455             :     ObjectDescriptor& desc =
     456      285286 :         property->is_static() ? static_desc : instance_desc;
     457      285286 :     if (property->is_computed_name()) {
     458             :       desc.IncComputedCount();
     459             :     } else {
     460      558756 :       if (property->key()->AsLiteral()->IsPropertyName()) {
     461             :         desc.IncPropertiesCount();
     462             :       } else {
     463             :         desc.IncElementsCount();
     464             :       }
     465             :     }
     466             :   }
     467             : 
     468             :   //
     469             :   // Initialize class object template.
     470             :   //
     471       40096 :   static_desc.CreateTemplates(isolate, kMinimumClassPropertiesCount);
     472             :   STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
     473             :   {
     474             :     // Add length_accessor.
     475             :     PropertyAttributes attribs =
     476             :         static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
     477       40096 :     static_desc.AddConstant(isolate, factory->length_string(),
     478       40096 :                             factory->function_length_accessor(), attribs);
     479             :   }
     480             :   {
     481             :     // Add prototype_accessor.
     482             :     PropertyAttributes attribs =
     483             :         static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
     484       40096 :     static_desc.AddConstant(isolate, factory->prototype_string(),
     485       40096 :                             factory->function_prototype_accessor(), attribs);
     486             :   }
     487       40096 :   if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
     488             :     PropertyAttributes attribs =
     489             :         static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
     490             :     Handle<Object> value(
     491             :         Smi::FromInt(ClassBoilerplate::kPrototypeArgumentIndex), isolate);
     492         828 :     static_desc.AddConstant(isolate, factory->home_object_symbol(), value,
     493         828 :                             attribs);
     494             :   }
     495             :   {
     496             :     Handle<ClassPositions> class_positions = factory->NewClassPositions(
     497       40096 :         expr->start_position(), expr->end_position());
     498       40096 :     static_desc.AddConstant(isolate, factory->class_positions_symbol(),
     499       40096 :                             class_positions, DONT_ENUM);
     500             :   }
     501             : 
     502             :   //
     503             :   // Initialize prototype object template.
     504             :   //
     505       40096 :   instance_desc.CreateTemplates(isolate, kMinimumPrototypePropertiesCount);
     506             :   {
     507             :     Handle<Object> value(
     508             :         Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
     509       40096 :     instance_desc.AddConstant(isolate, factory->constructor_string(), value,
     510       40096 :                               DONT_ENUM);
     511             :   }
     512             : 
     513             :   //
     514             :   // Fill in class boilerplate.
     515             :   //
     516             :   int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
     517             : 
     518      610668 :   for (int i = 0; i < expr->properties()->length(); i++) {
     519      285286 :     ClassLiteral::Property* property = expr->properties()->at(i);
     520             : 
     521             :     ClassBoilerplate::ValueKind value_kind;
     522      285286 :     switch (property->kind()) {
     523             :       case ClassLiteral::Property::METHOD:
     524             :         value_kind = ClassBoilerplate::kData;
     525      277950 :         break;
     526             :       case ClassLiteral::Property::GETTER:
     527             :         value_kind = ClassBoilerplate::kGetter;
     528        3388 :         break;
     529             :       case ClassLiteral::Property::SETTER:
     530             :         value_kind = ClassBoilerplate::kSetter;
     531        2961 :         break;
     532             :       case ClassLiteral::Property::FIELD:
     533             :         DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
     534         987 :         if (property->is_computed_name()) {
     535         380 :           ++dynamic_argument_index;
     536             :         }
     537        6515 :         continue;
     538             :     }
     539             : 
     540             :     ObjectDescriptor& desc =
     541      284299 :         property->is_static() ? static_desc : instance_desc;
     542      284299 :     if (property->is_computed_name()) {
     543             :       int computed_name_index = dynamic_argument_index;
     544        5528 :       dynamic_argument_index += 2;  // Computed name and value indices.
     545        5528 :       desc.AddComputed(value_kind, computed_name_index);
     546        5528 :       continue;
     547             :     }
     548      278771 :     int value_index = dynamic_argument_index++;
     549             : 
     550      278771 :     Literal* key_literal = property->key()->AsLiteral();
     551             :     uint32_t index;
     552      278771 :     if (key_literal->AsArrayIndex(&index)) {
     553         155 :       desc.AddIndexedProperty(isolate, index, value_kind, value_index);
     554             : 
     555             :     } else {
     556             :       Handle<String> name = key_literal->AsRawPropertyName()->string();
     557             :       DCHECK(name->IsInternalizedString());
     558      278616 :       desc.AddNamedProperty(isolate, name, value_kind, value_index);
     559             :     }
     560             :   }
     561             : 
     562             :   // Add name accessor to the class object if necessary.
     563             :   bool install_class_name_accessor = false;
     564       40096 :   if (!expr->has_name_static_property() &&
     565             :       expr->constructor()->has_shared_name()) {
     566       36496 :     if (static_desc.HasDictionaryProperties()) {
     567             :       // Install class name accessor if necessary during class literal
     568             :       // instantiation.
     569             :       install_class_name_accessor = true;
     570             :     } else {
     571             :       // Set class name accessor if the "name" method was not added yet.
     572             :       PropertyAttributes attribs =
     573             :           static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
     574       34947 :       static_desc.AddConstant(isolate, factory->name_string(),
     575       34947 :                               factory->function_name_accessor(), attribs);
     576             :     }
     577             :   }
     578             : 
     579       40096 :   static_desc.Finalize(isolate);
     580       40096 :   instance_desc.Finalize(isolate);
     581             : 
     582             :   Handle<ClassBoilerplate> class_boilerplate =
     583       40096 :       Handle<ClassBoilerplate>::cast(factory->NewFixedArray(kBoileplateLength));
     584             : 
     585             :   class_boilerplate->set_flags(0);
     586      120288 :   class_boilerplate->set_install_class_name_accessor(
     587       40096 :       install_class_name_accessor);
     588       40096 :   class_boilerplate->set_arguments_count(dynamic_argument_index);
     589             : 
     590       80192 :   class_boilerplate->set_static_properties_template(
     591       40096 :       *static_desc.properties_template());
     592      120288 :   class_boilerplate->set_static_elements_template(
     593       40096 :       *static_desc.elements_template());
     594       80192 :   class_boilerplate->set_static_computed_properties(
     595       40096 :       *static_desc.computed_properties());
     596             : 
     597       80192 :   class_boilerplate->set_instance_properties_template(
     598       40096 :       *instance_desc.properties_template());
     599      120288 :   class_boilerplate->set_instance_elements_template(
     600       40096 :       *instance_desc.elements_template());
     601       80192 :   class_boilerplate->set_instance_computed_properties(
     602       40096 :       *instance_desc.computed_properties());
     603             : 
     604       80192 :   return scope.CloseAndEscape(class_boilerplate);
     605             : }
     606             : 
     607             : }  // namespace internal
     608      120216 : }  // namespace v8

Generated by: LCOV version 1.10