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