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