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