5 #include "src/objects/literal-objects.h" 7 #include "src/accessors.h" 8 #include "src/ast/ast.h" 9 #include "src/heap/factory.h" 10 #include "src/isolate.h" 11 #include "src/objects-inl.h" 12 #include "src/objects/hash-table-inl.h" 13 #include "src/objects/literal-objects-inl.h" 14 #include "src/objects/smi.h" 19 Object* ObjectBoilerplateDescription::name(
int index)
const {
22 DCHECK_NE(size(), index);
23 return get(2 * index + kDescriptionStartIndex);
26 Object* ObjectBoilerplateDescription::value(
int index)
const {
27 return get(2 * index + 1 + kDescriptionStartIndex);
30 void ObjectBoilerplateDescription::set_key_value(
int index, Object* key,
32 DCHECK_LT(index, size());
34 set(2 * index + kDescriptionStartIndex, key);
35 set(2 * index + 1 + kDescriptionStartIndex, value);
38 int ObjectBoilerplateDescription::size()
const {
39 DCHECK_EQ(0, (length() - kDescriptionStartIndex -
40 (this->has_number_of_properties() ? 1 : 0)) %
43 return (length() - kDescriptionStartIndex) / 2;
46 int ObjectBoilerplateDescription::backing_store_size()
const {
47 if (has_number_of_properties()) {
49 return Smi::ToInt(this->
get(length() - 1));
56 void ObjectBoilerplateDescription::set_backing_store_size(
57 Isolate* isolate,
int backing_store_size) {
58 DCHECK(has_number_of_properties());
59 DCHECK_NE(size(), backing_store_size);
60 Handle<Object> backing_store_size_obj =
61 isolate->factory()->NewNumberFromInt(backing_store_size);
62 set(length() - 1, *backing_store_size_obj);
65 bool ObjectBoilerplateDescription::has_number_of_properties()
const {
66 return (length() - kDescriptionStartIndex) % 2 != 0;
71 inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
73 typedef ClassBoilerplate::ComputedEntryFlags Flags;
74 int flags = Flags::ValueKindBits::encode(value_kind) |
75 Flags::KeyIndexBits::encode(key_index);
79 void AddToDescriptorArrayTemplate(
80 Isolate* isolate, Handle<DescriptorArray> descriptor_array_template,
81 Handle<Name> name, ClassBoilerplate::ValueKind value_kind,
82 Handle<Object> value) {
83 int entry = descriptor_array_template->Search(
84 *name, descriptor_array_template->number_of_descriptors());
87 if (entry == DescriptorArray::kNotFound) {
90 if (value_kind == ClassBoilerplate::kData) {
91 d = Descriptor::DataConstant(name, value, DONT_ENUM);
93 DCHECK(value_kind == ClassBoilerplate::kGetter ||
94 value_kind == ClassBoilerplate::kSetter);
95 Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
96 pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
99 d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
101 descriptor_array_template->Append(&d);
105 int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
106 if (value_kind == ClassBoilerplate::kData) {
107 Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
108 d.SetSortedKeyIndex(sorted_index);
109 descriptor_array_template->Set(entry, &d);
111 DCHECK(value_kind == ClassBoilerplate::kGetter ||
112 value_kind == ClassBoilerplate::kSetter);
113 Object* raw_accessor = descriptor_array_template->GetStrongValue(entry);
115 if (raw_accessor->IsAccessorPair()) {
116 pair = AccessorPair::cast(raw_accessor);
118 Handle<AccessorPair> new_pair = isolate->factory()->NewAccessorPair();
119 Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
120 d.SetSortedKeyIndex(sorted_index);
121 descriptor_array_template->Set(entry, &d);
124 pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
131 Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
132 Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
133 Handle<Object> value, PropertyDetails details,
int* entry_out =
nullptr) {
134 return NameDictionary::AddNoUpdateNextEnumerationIndex(
135 isolate, dictionary, name, value, details, entry_out);
138 Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
139 Isolate* isolate, Handle<NumberDictionary> dictionary,
uint32_t element,
140 Handle<Object> value, PropertyDetails details,
int* entry_out =
nullptr) {
143 return NumberDictionary::Add(isolate, dictionary, element, value, details,
147 void DictionaryUpdateMaxNumberKey(Handle<NameDictionary> dictionary,
152 void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary,
154 dictionary->UpdateMaxNumberKey(element, Handle<JSObject>());
155 dictionary->set_requires_slow_elements();
158 constexpr
int ComputeEnumerationIndex(
int value_index) {
162 return value_index + Max(ClassBoilerplate::kMinimumClassPropertiesCount,
163 ClassBoilerplate::kMinimumPrototypePropertiesCount);
166 inline int GetExistingValueIndex(Object* value) {
167 return value->IsSmi() ? Smi::ToInt(value) : -1;
170 template <
typename Dictionary,
typename Key>
171 void AddToDictionaryTemplate(Isolate* isolate, Handle<Dictionary> dictionary,
172 Key key,
int key_index,
173 ClassBoilerplate::ValueKind value_kind,
175 int entry = dictionary->FindEntry(isolate, key);
177 if (entry == kNotFound) {
179 const bool is_elements_dictionary =
180 std::is_same<Dictionary, NumberDictionary>::value;
181 STATIC_ASSERT(is_elements_dictionary !=
182 (std::is_same<Dictionary, NameDictionary>::value));
184 is_elements_dictionary ? 0 : ComputeEnumerationIndex(key_index);
185 Handle<Object> value_handle;
186 PropertyDetails details(
187 value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
188 PropertyCellType::kNoCell, enum_order);
190 if (value_kind == ClassBoilerplate::kData) {
191 value_handle = handle(value, isolate);
193 AccessorComponent component = value_kind == ClassBoilerplate::kGetter
196 Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
197 pair->set(component, value);
202 Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
203 isolate, dictionary, key, value_handle, details, &entry);
207 CHECK_EQ(*dict, *dictionary);
209 DictionaryUpdateMaxNumberKey(dictionary, key);
213 int enum_order = dictionary->DetailsAt(entry).dictionary_index();
214 Object* existing_value = dictionary->ValueAt(entry);
215 if (value_kind == ClassBoilerplate::kData) {
217 if (existing_value->IsAccessorPair()) {
218 AccessorPair* current_pair = AccessorPair::cast(existing_value);
220 int existing_getter_index =
221 GetExistingValueIndex(current_pair->getter());
222 int existing_setter_index =
223 GetExistingValueIndex(current_pair->setter());
225 DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
226 if (existing_getter_index < key_index &&
227 existing_setter_index < key_index) {
231 PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
233 dictionary->DetailsAtPut(isolate, entry, details);
234 dictionary->ValueAtPut(entry, value);
239 if (existing_getter_index < key_index) {
240 DCHECK_LT(key_index, existing_setter_index);
245 current_pair->set_getter(*isolate->factory()->null_value());
247 }
else if (existing_setter_index < key_index) {
248 DCHECK_LT(key_index, existing_getter_index);
253 current_pair->set_setter(*isolate->factory()->null_value());
258 int existing_value_index = Smi::ToInt(existing_value);
259 if (existing_value_index < key_index) {
260 PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
262 dictionary->DetailsAtPut(isolate, entry, details);
263 dictionary->ValueAtPut(entry, value);
267 AccessorComponent component = value_kind == ClassBoilerplate::kGetter
270 if (existing_value->IsAccessorPair()) {
271 AccessorPair* current_pair = AccessorPair::cast(existing_value);
273 int existing_component_index =
274 GetExistingValueIndex(current_pair->get(component));
275 if (existing_component_index < key_index) {
276 current_pair->set(component, value);
280 Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
281 pair->set(component, value);
282 PropertyDetails details(kAccessor, DONT_ENUM, PropertyCellType::kNoCell,
284 dictionary->DetailsAtPut(isolate, entry, details);
285 dictionary->ValueAtPut(entry, *pair);
297 void IncComputedCount() { ++computed_count_; }
298 void IncPropertiesCount() { ++property_count_; }
299 void IncElementsCount() { ++element_count_; }
301 bool HasDictionaryProperties()
const {
302 return computed_count_ > 0 || property_count_ > kMaxNumberOfDescriptors;
306 return HasDictionaryProperties()
312 return elements_dictionary_template_;
316 return computed_properties_;
319 void CreateTemplates(
Isolate* isolate,
int slack) {
320 Factory* factory = isolate->factory();
321 descriptor_array_template_ = factory->empty_descriptor_array();
322 properties_dictionary_template_ = factory->empty_property_dictionary();
323 if (property_count_ || HasDictionaryProperties() || slack) {
324 if (HasDictionaryProperties()) {
325 properties_dictionary_template_ = NameDictionary::New(
326 isolate, property_count_ + computed_count_ + slack);
328 descriptor_array_template_ =
329 DescriptorArray::Allocate(isolate, 0, property_count_ + slack);
332 elements_dictionary_template_ =
333 element_count_ || computed_count_
334 ? NumberDictionary::New(isolate, element_count_ + computed_count_)
335 : factory->empty_slow_element_dictionary();
337 computed_properties_ =
339 ? factory->NewFixedArray(computed_count_ *
340 ClassBoilerplate::kFullComputedEntrySize)
341 : factory->empty_fixed_array();
343 temp_handle_ = handle(Smi::kZero, isolate);
347 PropertyAttributes attribs) {
348 bool is_accessor = value->IsAccessorInfo();
349 DCHECK(!value->IsAccessorPair());
350 if (HasDictionaryProperties()) {
351 PropertyKind kind = is_accessor ? i::kAccessor : i::kData;
353 next_enumeration_index_++);
354 properties_dictionary_template_ =
355 DictionaryAddNoUpdateNextEnumerationIndex(
356 isolate, properties_dictionary_template_, name, value, details);
359 ? Descriptor::AccessorConstant(name, value, attribs)
360 : Descriptor::DataConstant(name, value, attribs);
361 descriptor_array_template_->Append(&d);
366 ClassBoilerplate::ValueKind value_kind,
368 Smi value = Smi::FromInt(value_index);
369 if (HasDictionaryProperties()) {
370 UpdateNextEnumerationIndex(value_index);
371 AddToDictionaryTemplate(isolate, properties_dictionary_template_, name,
372 value_index, value_kind, value);
374 *temp_handle_.location() = value->ptr();
375 AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
376 value_kind, temp_handle_);
381 ClassBoilerplate::ValueKind value_kind,
383 Smi value = Smi::FromInt(value_index);
384 AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
385 value_index, value_kind, value);
388 void AddComputed(ClassBoilerplate::ValueKind value_kind,
int key_index) {
389 int value_index = key_index + 1;
390 UpdateNextEnumerationIndex(value_index);
392 int flags = EncodeComputedEntry(value_kind, key_index);
393 computed_properties_->set(current_computed_index_++, Smi::FromInt(flags));
396 void UpdateNextEnumerationIndex(
int value_index) {
397 int next_index = ComputeEnumerationIndex(value_index);
398 DCHECK_LT(next_enumeration_index_, next_index);
399 next_enumeration_index_ = next_index;
402 void Finalize(
Isolate* isolate) {
403 if (HasDictionaryProperties()) {
404 properties_dictionary_template_->SetNextEnumerationIndex(
405 next_enumeration_index_);
406 computed_properties_ = FixedArray::ShrinkOrEmpty(
407 isolate, computed_properties_, current_computed_index_);
409 DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
414 int property_count_ = 0;
415 int next_enumeration_index_ = PropertyDetails::kInitialIndex;
416 int element_count_ = 0;
417 int computed_count_ = 0;
418 int current_computed_index_ = 0;
428 void ClassBoilerplate::AddToPropertiesTemplate(
430 int key_index, ClassBoilerplate::ValueKind value_kind,
Object* value) {
431 AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
435 void ClassBoilerplate::AddToElementsTemplate(
437 int key_index, ClassBoilerplate::ValueKind value_kind,
Object* value) {
438 AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
442 Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
443 Isolate* isolate, ClassLiteral* expr) {
447 HandleScope scope(isolate);
448 Factory* factory = isolate->factory();
449 ObjectDescriptor static_desc;
450 ObjectDescriptor instance_desc;
452 for (
int i = 0;
i < expr->properties()->length();
i++) {
453 ClassLiteral::Property*
property = expr->properties()->at(
i);
454 ObjectDescriptor& desc =
455 property->is_static() ? static_desc : instance_desc;
456 if (property->is_computed_name()) {
457 desc.IncComputedCount();
459 if (property->key()->AsLiteral()->IsPropertyName()) {
460 desc.IncPropertiesCount();
462 desc.IncElementsCount();
470 static_desc.CreateTemplates(isolate, kMinimumClassPropertiesCount);
471 STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
474 PropertyAttributes attribs =
475 static_cast<PropertyAttributes
>(DONT_ENUM | READ_ONLY);
476 static_desc.AddConstant(isolate, factory->length_string(),
477 factory->function_length_accessor(), attribs);
481 PropertyAttributes attribs =
482 static_cast<PropertyAttributes
>(DONT_ENUM | DONT_DELETE | READ_ONLY);
483 static_desc.AddConstant(isolate, factory->prototype_string(),
484 factory->function_prototype_accessor(), attribs);
486 if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
487 PropertyAttributes attribs =
488 static_cast<PropertyAttributes
>(DONT_ENUM | DONT_DELETE | READ_ONLY);
489 Handle<Object> value(
490 Smi::FromInt(ClassBoilerplate::kPrototypeArgumentIndex), isolate);
491 static_desc.AddConstant(isolate, factory->home_object_symbol(), value,
495 Handle<Smi> start_position(Smi::FromInt(expr->start_position()), isolate);
496 Handle<Smi> end_position(Smi::FromInt(expr->end_position()), isolate);
497 Handle<Tuple2> class_positions =
498 factory->NewTuple2(start_position, end_position, NOT_TENURED);
499 static_desc.AddConstant(isolate, factory->class_positions_symbol(),
500 class_positions, DONT_ENUM);
506 instance_desc.CreateTemplates(isolate, kMinimumPrototypePropertiesCount);
508 Handle<Object> value(
509 Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
510 instance_desc.AddConstant(isolate, factory->constructor_string(), value,
517 int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
519 for (
int i = 0;
i < expr->properties()->length();
i++) {
520 ClassLiteral::Property*
property = expr->properties()->at(
i);
522 ClassBoilerplate::ValueKind value_kind;
523 switch (property->kind()) {
524 case ClassLiteral::Property::METHOD:
525 value_kind = ClassBoilerplate::kData;
527 case ClassLiteral::Property::GETTER:
528 value_kind = ClassBoilerplate::kGetter;
530 case ClassLiteral::Property::SETTER:
531 value_kind = ClassBoilerplate::kSetter;
533 case ClassLiteral::Property::FIELD:
534 DCHECK_IMPLIES(property->is_computed_name(), !
property->is_private());
535 if (property->is_computed_name()) {
536 ++dynamic_argument_index;
541 ObjectDescriptor& desc =
542 property->is_static() ? static_desc : instance_desc;
543 if (property->is_computed_name()) {
544 int computed_name_index = dynamic_argument_index;
545 dynamic_argument_index += 2;
546 desc.AddComputed(value_kind, computed_name_index);
549 int value_index = dynamic_argument_index++;
551 Literal* key_literal =
property->key()->AsLiteral();
553 if (key_literal->AsArrayIndex(&index)) {
554 desc.AddIndexedProperty(isolate, index, value_kind, value_index);
557 Handle<String> name = key_literal->AsRawPropertyName()->string();
558 DCHECK(name->IsInternalizedString());
559 desc.AddNamedProperty(isolate, name, value_kind, value_index);
564 bool install_class_name_accessor =
false;
565 if (!expr->has_name_static_property() &&
566 expr->constructor()->has_shared_name()) {
567 if (static_desc.HasDictionaryProperties()) {
570 install_class_name_accessor =
true;
573 PropertyAttributes attribs =
574 static_cast<PropertyAttributes
>(DONT_ENUM | READ_ONLY);
575 static_desc.AddConstant(isolate, factory->name_string(),
576 factory->function_name_accessor(), attribs);
580 static_desc.Finalize(isolate);
581 instance_desc.Finalize(isolate);
583 Handle<ClassBoilerplate> class_boilerplate =
584 Handle<ClassBoilerplate>::cast(factory->NewFixedArray(kBoileplateLength));
586 class_boilerplate->set_flags(0);
587 class_boilerplate->set_install_class_name_accessor(
588 install_class_name_accessor);
589 class_boilerplate->set_arguments_count(dynamic_argument_index);
591 class_boilerplate->set_static_properties_template(
592 *static_desc.properties_template());
593 class_boilerplate->set_static_elements_template(
594 *static_desc.elements_template());
595 class_boilerplate->set_static_computed_properties(
596 *static_desc.computed_properties());
598 class_boilerplate->set_instance_properties_template(
599 *instance_desc.properties_template());
600 class_boilerplate->set_instance_elements_template(
601 *instance_desc.elements_template());
602 class_boilerplate->set_instance_computed_properties(
603 *instance_desc.computed_properties());
605 return scope.CloseAndEscape(class_boilerplate);