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