v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
literal-objects.cc
Go to the documentation of this file.
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
6
7#include "src/ast/ast.h"
8#include "src/base/logging.h"
10#include "src/common/globals.h"
12#include "src/heap/factory.h"
19#include "src/objects/smi.h"
21#include "src/sandbox/isolate.h"
22
23namespace v8 {
24namespace internal {
25
26namespace {
27
28// The enumeration order index in the property details is unused if they are
29// stored in a SwissNameDictionary or NumberDictionary (because they handle
30// property ordering differently). We then use this dummy value instead.
31constexpr int kDummyEnumerationIndex = 0;
32
33inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
34 unsigned key_index) {
35 using Flags = ClassBoilerplate::ComputedEntryFlags;
36 int flags = Flags::ValueKindBits::encode(value_kind) |
37 Flags::KeyIndexBits::encode(key_index);
38 return flags;
39}
40
41void SetAccessorPlaceholderIndices(Tagged<AccessorPair> pair,
43 Tagged<Smi> index) {
44 switch (value_kind) {
46 pair->set_getter(index);
47 break;
49 pair->set_setter(index);
50 break;
52 // Auto-accessor set the pair of consecutive indices in a single call.
53 pair->set_getter(index);
54 pair->set_setter(Smi::FromInt(Smi::ToInt(index) + 1));
55 break;
56 default:
58 }
59}
60
61void SetAccessorPlaceholderIndices(Tagged<AccessorPair> pair,
63 Tagged<Smi> index, ReleaseStoreTag tag) {
64 switch (value_kind) {
66 pair->set_getter(index, tag);
67 break;
69 pair->set_setter(index, tag);
70 break;
72 // Auto-accessor set the pair of consecutive indices in a single call.
73 pair->set_getter(index, tag);
74 pair->set_setter(Smi::FromInt(Smi::ToInt(index) + 1), tag);
75 break;
76 default:
78 }
79}
80
81template <typename IsolateT>
82void AddToDescriptorArrayTemplate(
83 IsolateT* isolate, DirectHandle<DescriptorArray> descriptor_array_template,
84 DirectHandle<Name> name, ClassBoilerplate::ValueKind value_kind,
85 DirectHandle<Object> value) {
86 InternalIndex entry = descriptor_array_template->Search(
87 *name, descriptor_array_template->number_of_descriptors());
88 // TODO(ishell): deduplicate properties at AST level, this will allow us to
89 // avoid creation of closures that will be overwritten anyway.
90 if (entry.is_not_found()) {
91 // Entry not found, add new one.
92 Descriptor d;
93 if (value_kind == ClassBoilerplate::kData) {
94 d = Descriptor::DataConstant(name, value, DONT_ENUM);
95 } else {
96 DCHECK(value_kind == ClassBoilerplate::kGetter ||
97 value_kind == ClassBoilerplate::kSetter ||
99 DirectHandle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
100 SetAccessorPlaceholderIndices(*pair, value_kind, Cast<Smi>(*value));
102 }
103 descriptor_array_template->Append(&d);
104
105 } else {
106 // Entry found, update it.
107 int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
108 if (value_kind == ClassBoilerplate::kData) {
109 Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
110 d.SetSortedKeyIndex(sorted_index);
111 descriptor_array_template->Set(entry, &d);
112 } else {
113 DCHECK(value_kind == ClassBoilerplate::kGetter ||
114 value_kind == ClassBoilerplate::kSetter ||
115 value_kind == ClassBoilerplate::kAutoAccessor);
116 Tagged<Object> raw_accessor =
117 descriptor_array_template->GetStrongValue(entry);
119 if (IsAccessorPair(raw_accessor)) {
120 pair = Cast<AccessorPair>(raw_accessor);
121 } else {
122 DirectHandle<AccessorPair> new_pair =
123 isolate->factory()->NewAccessorPair();
124 Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
125 d.SetSortedKeyIndex(sorted_index);
126 descriptor_array_template->Set(entry, &d);
127 pair = *new_pair;
128 }
129 SetAccessorPlaceholderIndices(pair, value_kind, Cast<Smi>(*value),
131 }
132 }
133}
134
135template <typename IsolateT>
136Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
137 IsolateT* isolate, Handle<NameDictionary> dictionary,
138 DirectHandle<Name> name, DirectHandle<Object> value,
139 PropertyDetails details, InternalIndex* entry_out = nullptr) {
140 return NameDictionary::AddNoUpdateNextEnumerationIndex(
141 isolate, dictionary, name, value, details, entry_out);
142}
143
144template <typename IsolateT>
145Handle<SwissNameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
146 IsolateT* isolate, Handle<SwissNameDictionary> dictionary,
147 DirectHandle<Name> name, DirectHandle<Object> value,
148 PropertyDetails details, InternalIndex* entry_out = nullptr) {
149 // SwissNameDictionary does not maintain the enumeration order in property
150 // details, so it's a normal Add().
151 return SwissNameDictionary::Add(isolate, dictionary, name, value, details);
152}
153
154template <typename IsolateT>
155DirectHandle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
156 IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t element,
157 DirectHandle<Object> value, PropertyDetails details,
158 InternalIndex* entry_out = nullptr) {
159 // NumberDictionary does not maintain the enumeration order, so it's
160 // a normal Add().
161 return NumberDictionary::Add(isolate, dictionary, element, value, details,
162 entry_out);
163}
164
165// TODO(42203211): The first parameter should be just DirectHandle<Dictionary>
166// but now it does not compile with implicit Handle to DirectHandle conversions.
167template <template <typename> typename HandleType, typename Dictionary>
168void DictionaryUpdateMaxNumberKey(HandleType<Dictionary> dictionary,
169 DirectHandle<Name> name)
170 requires(
171 std::is_convertible_v<HandleType<Dictionary>, DirectHandle<Dictionary>>)
172{
173 static_assert((std::is_same_v<Dictionary, SwissNameDictionary> ||
174 std::is_same_v<Dictionary, NameDictionary>));
175 // No-op for (ordered) name dictionaries.
176}
177
178void DictionaryUpdateMaxNumberKey(DirectHandle<NumberDictionary> dictionary,
179 uint32_t element) {
180 dictionary->UpdateMaxNumberKey(element, DirectHandle<JSObject>());
181 dictionary->set_requires_slow_elements();
182}
183
184constexpr int ComputeEnumerationIndex(int value_index) {
185 // We "shift" value indices to ensure that the enumeration index for the value
186 // will not overlap with minimum properties set for both class and prototype
187 // objects.
188 return value_index +
191}
192
193constexpr int kAccessorNotDefined = -1;
194
195inline int GetExistingValueIndex(Tagged<Object> value) {
196 return IsSmi(value) ? Smi::ToInt(value) : kAccessorNotDefined;
197}
198
199template <typename IsolateT, typename Dictionary, typename Key>
200void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary,
201 Key key, int key_index,
203 Tagged<Smi> value) {
204 InternalIndex entry = dictionary->FindEntry(isolate, key);
205
206 const bool is_elements_dictionary =
207 std::is_same_v<Dictionary, NumberDictionary>;
208 static_assert(is_elements_dictionary !=
209 (std::is_same_v<Dictionary, NameDictionary> ||
210 std::is_same_v<Dictionary, SwissNameDictionary>));
211
212 if (entry.is_not_found()) {
213 // Entry not found, add new one.
214 int enum_order =
215 Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
216 ? kDummyEnumerationIndex
217 : ComputeEnumerationIndex(key_index);
218 DirectHandle<Object> value_handle;
219 PropertyDetails details(
223 if (value_kind == ClassBoilerplate::kData) {
224 value_handle = direct_handle(value, isolate);
225 } else {
226 DCHECK(value_kind == ClassBoilerplate::kGetter ||
227 value_kind == ClassBoilerplate::kSetter ||
228 value_kind == ClassBoilerplate::kAutoAccessor);
229 DirectHandle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
230 SetAccessorPlaceholderIndices(*pair, value_kind, Cast<Smi>(value));
231 value_handle = pair;
232 }
233
234 // Add value to the dictionary without updating next enumeration index.
235 DirectHandle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
236 isolate, dictionary, key, value_handle, details, &entry);
237 // It is crucial to avoid dictionary reallocations because it may remove
238 // potential gaps in enumeration indices values that are necessary for
239 // inserting computed properties into right places in the enumeration order.
240 CHECK_EQ(*dict, *dictionary);
241
242 DictionaryUpdateMaxNumberKey(dictionary, key);
243
244 } else {
245 // Entry found, update it.
246 int enum_order_existing =
247 Dictionary::kIsOrderedDictionaryType
248 ? kDummyEnumerationIndex
249 : dictionary->DetailsAt(entry).dictionary_index();
250 int enum_order_computed =
251 Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
252 ? kDummyEnumerationIndex
253 : ComputeEnumerationIndex(key_index);
254
255 Tagged<Object> existing_value = dictionary->ValueAt(entry);
256 if (value_kind == ClassBoilerplate::kData) {
257 // Computed value is a normal method.
258 if (IsAccessorPair(existing_value)) {
259 Tagged<AccessorPair> current_pair = Cast<AccessorPair>(existing_value);
260
261 int existing_getter_index =
262 GetExistingValueIndex(current_pair->getter());
263 int existing_setter_index =
264 GetExistingValueIndex(current_pair->setter());
265 // At least one of the accessors must already be defined.
266 static_assert(kAccessorNotDefined < 0);
267 DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
268 if (existing_getter_index < key_index &&
269 existing_setter_index < key_index) {
270 // Either both getter and setter were defined before the computed
271 // method or just one of them was defined before while the other one
272 // was not defined yet, so overwrite property to kData.
273 PropertyDetails details(
276 enum_order_existing);
277 dictionary->DetailsAtPut(entry, details);
278 dictionary->ValueAtPut(entry, value);
279
280 } else if (existing_getter_index != kAccessorNotDefined &&
281 existing_getter_index < key_index) {
282 DCHECK_LT(key_index, existing_setter_index);
283 // Getter was defined and it was done before the computed method
284 // and then it was overwritten by the current computed method which
285 // in turn was later overwritten by the setter method. So we clear
286 // the getter.
287 current_pair->set_getter(*isolate->factory()->null_value());
288
289 } else if (existing_setter_index != kAccessorNotDefined &&
290 existing_setter_index < key_index) {
291 DCHECK_LT(key_index, existing_getter_index);
292 // Setter was defined and it was done before the computed method
293 // and then it was overwritten by the current computed method which
294 // in turn was later overwritten by the getter method. So we clear
295 // the setter.
296 current_pair->set_setter(*isolate->factory()->null_value());
297
298 } else {
299 // One of the following cases holds:
300 // The computed method was defined before ...
301 // 1.) the getter and setter, both of which are defined,
302 // 2.) the getter, and the setter isn't defined,
303 // 3.) the setter, and the getter isn't defined.
304 // Therefore, the computed value is overwritten, receiving the
305 // computed property's enum index.
306 DCHECK(key_index < existing_getter_index ||
307 existing_getter_index == kAccessorNotDefined);
308 DCHECK(key_index < existing_setter_index ||
309 existing_setter_index == kAccessorNotDefined);
310 DCHECK(existing_getter_index != kAccessorNotDefined ||
311 existing_setter_index != kAccessorNotDefined);
312 if (!is_elements_dictionary) {
313 // The enum index is unused by elements dictionaries,
314 // which is why we don't need to update the property details if
315 // |is_elements_dictionary| holds.
316 PropertyDetails details = dictionary->DetailsAt(entry);
317 details = details.set_index(enum_order_computed);
318 dictionary->DetailsAtPut(entry, details);
319 }
320 }
321 } else { // if (existing_value.IsAccessorPair()) ends here
322 DCHECK(value_kind == ClassBoilerplate::kData);
323
324 DCHECK_IMPLIES(!IsSmi(existing_value), IsAccessorInfo(existing_value));
325 DCHECK_IMPLIES(!IsSmi(existing_value),
326 Cast<AccessorInfo>(existing_value)->name() ==
327 *isolate->factory()->length_string() ||
328 Cast<AccessorInfo>(existing_value)->name() ==
329 *isolate->factory()->name_string());
330 if (!IsSmi(existing_value) || Smi::ToInt(existing_value) < key_index) {
331 // Overwrite existing value because it was defined before the computed
332 // one (AccessorInfo "length" and "name" properties are always defined
333 // before).
334 PropertyDetails details(
337 enum_order_existing);
338 dictionary->DetailsAtPut(entry, details);
339 dictionary->ValueAtPut(entry, value);
340 } else {
341 // The computed value appears before the existing one. Set the
342 // existing entry's enum index to that of the computed one.
343 if (!is_elements_dictionary) {
344 // The enum index is unused by elements dictionaries,
345 // which is why we don't need to update the property details if
346 // |is_elements_dictionary| holds.
347 PropertyDetails details(
350 enum_order_computed);
351
352 dictionary->DetailsAtPut(entry, details);
353 }
354 }
355 }
356 } else { // if (value_kind == ClassBoilerplate::kData) ends here
357 if (IsAccessorPair(existing_value)) {
358 // Update respective component of existing AccessorPair.
359 Tagged<AccessorPair> current_pair = Cast<AccessorPair>(existing_value);
360
361 bool updated = false;
362 switch (value_kind) {
364 int existing_get_component_index =
365 GetExistingValueIndex(current_pair->get(ACCESSOR_GETTER));
366 int existing_set_component_index =
367 GetExistingValueIndex(current_pair->get(ACCESSOR_SETTER));
368 if (existing_get_component_index < key_index &&
369 existing_set_component_index < key_index) {
370 SetAccessorPlaceholderIndices(current_pair, value_kind, value,
372 updated = true;
373 } else {
374 if (existing_get_component_index < key_index) {
375 SetAccessorPlaceholderIndices(current_pair,
378 updated = true;
379 } else if (existing_set_component_index < key_index) {
380 SetAccessorPlaceholderIndices(
381 current_pair, ClassBoilerplate::kSetter,
383 updated = true;
384 }
385 }
386 break;
387 }
390 AccessorComponent component =
393 int existing_component_index =
394 GetExistingValueIndex(current_pair->get(component));
395 if (existing_component_index < key_index) {
396 SetAccessorPlaceholderIndices(current_pair, value_kind, value,
398 updated = true;
399 }
400 break;
401 }
402 default:
403 UNREACHABLE();
404 }
405 if (!updated) {
406 // The existing accessor property overwrites the computed one, update
407 // its enumeration order accordingly.
408
409 if (!is_elements_dictionary) {
410 // The enum index is unused by elements dictionaries,
411 // which is why we don't need to update the property details if
412 // |is_elements_dictionary| holds.
413
414 PropertyDetails details(
417 enum_order_computed);
418 dictionary->DetailsAtPut(entry, details);
419 }
420 }
421
422 } else {
423 DCHECK(!IsAccessorPair(existing_value));
424 DCHECK(value_kind != ClassBoilerplate::kData);
425
426 if (!IsSmi(existing_value) || Smi::ToInt(existing_value) < key_index) {
427 // Overwrite the existing data property because it was defined before
428 // the computed accessor property.
429 DirectHandle<AccessorPair> pair(
430 isolate->factory()->NewAccessorPair());
431 SetAccessorPlaceholderIndices(*pair, value_kind, value);
432 PropertyDetails details(
435 enum_order_existing);
436 dictionary->DetailsAtPut(entry, details);
437 dictionary->ValueAtPut(entry, *pair);
438 } else {
439 // The computed accessor property appears before the existing data
440 // property. Set the existing entry's enum index to that of the
441 // computed one.
442
443 if (!is_elements_dictionary) {
444 // The enum index is unused by elements dictionaries,
445 // which is why we don't need to update the property details if
446 // |is_elements_dictionary| holds.
447 PropertyDetails details(
450 enum_order_computed);
451
452 dictionary->DetailsAtPut(entry, details);
453 }
454 }
455 }
456 }
457 }
458}
459
460} // namespace
461
462// Helper class that eases building of a properties, elements and computed
463// properties templates.
464template <typename IsolateT>
466 public:
470
471 explicit ObjectDescriptor(int property_slack)
472 : property_slack_(property_slack) {}
473
478
483
487
491
492 void CreateTemplates(IsolateT* isolate) {
493 auto* factory = isolate->factory();
494 descriptor_array_template_ = factory->empty_descriptor_array();
497 factory->empty_swiss_property_dictionary();
498 } else {
499 properties_dictionary_template_ = factory->empty_property_dictionary();
500 }
503 int need_space_for =
507 isolate->factory()->NewSwissNameDictionary(need_space_for,
509
510 } else {
512 isolate, need_space_for, AllocationType::kOld);
513 }
514 } else {
516 isolate, 0, property_count_ + property_slack_,
518 }
519 }
522 ? NumberDictionary::New(isolate, element_count_ + computed_count_,
524 : factory->empty_slow_element_dictionary();
525
528 ? factory->NewFixedArray(computed_count_, AllocationType::kOld)
529 : factory->empty_fixed_array();
530
531 temp_handle_ = handle(Smi::zero(), isolate);
532 }
533
534 void AddConstant(IsolateT* isolate, DirectHandle<Name> name,
536 bool is_accessor = IsAccessorInfo(*value);
537 DCHECK(!IsAccessorPair(*value));
540 is_accessor ? i::PropertyKind::kAccessor : i::PropertyKind::kData;
542 ? kDummyEnumerationIndex
545 enum_order);
548 DictionaryAddNoUpdateNextEnumerationIndex(
549 isolate, properties_ordered_dictionary_template(), name, value,
550 details);
551 } else {
553 DictionaryAddNoUpdateNextEnumerationIndex(
554 isolate, properties_dictionary_template(), name, value,
555 details);
556 }
557 } else {
558 Descriptor d = is_accessor
559 ? Descriptor::AccessorConstant(name, value, attribs)
560 : Descriptor::DataConstant(name, value, attribs);
561 descriptor_array_template_->Append(&d);
562 }
563 }
564
565 void AddNamedProperty(IsolateT* isolate, Handle<Name> name,
567 int value_index) {
568 Tagged<Smi> value = Smi::FromInt(value_index);
570 UpdateNextEnumerationIndex(value_index);
572 AddToDictionaryTemplate(isolate,
574 value_index, value_kind, value);
575 } else {
576 AddToDictionaryTemplate(isolate, properties_dictionary_template(), name,
577 value_index, value_kind, value);
578 }
579 } else {
581 AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
582 value_kind, temp_handle_);
583 }
584 }
585
586 void AddIndexedProperty(IsolateT* isolate, uint32_t element,
588 int value_index) {
589 Tagged<Smi> value = Smi::FromInt(value_index);
590 AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
591 value_index, value_kind, value);
592 }
593
594 void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) {
595 int value_index = key_index + 1;
596 UpdateNextEnumerationIndex(value_index);
597
598 int flags = EncodeComputedEntry(value_kind, key_index);
600 }
601
602 void UpdateNextEnumerationIndex(int value_index) {
603 int current_index = ComputeEnumerationIndex(value_index);
604 DCHECK_LE(next_enumeration_index_, current_index);
605 next_enumeration_index_ = current_index + 1;
606 }
607
608 void Finalize(IsolateT* isolate) {
612 properties_dictionary_template()->set_next_enumeration_index(
614 }
615 } else {
616 DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
617 }
618 }
619
620 private:
624
628
635
637
638 // Is either a NameDictionary or SwissNameDictionary.
640
643 // This temporary handle is used for storing to descriptor array.
645};
646
647template <typename IsolateT, typename PropertyDict>
649 IsolateT* isolate, Handle<PropertyDict> dictionary, Handle<Name> name,
650 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value) {
651 AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
652 value);
653}
655 Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
656 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
658 LocalIsolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
659 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
661 Isolate* isolate, Handle<SwissNameDictionary> dictionary, Handle<Name> name,
662 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
663
664template <typename IsolateT>
666 IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
667 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value) {
668 AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
669 value);
670}
672 Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
673 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
675 LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
676 int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
677
678// static
679template <typename IsolateT>
681 ClassLiteral* expr,
682 AllocationType allocation) {
683 // Create a non-caching handle scope to ensure that the temporary handle used
684 // by ObjectDescriptor for passing Smis around does not corrupt handle cache
685 // in CanonicalHandleScope.
686 typename IsolateT::HandleScopeType scope(isolate);
687 auto* factory = isolate->factory();
690
691 for (int i = 0; i < expr->public_members()->length(); i++) {
692 ClassLiteral::Property* property = expr->public_members()->at(i);
694 property->is_static() ? static_desc : instance_desc;
695 if (property->is_computed_name()) {
696 if (property->kind() != ClassLiteral::Property::FIELD) {
697 desc.IncComputedCount();
698 }
699 } else {
700 if (property->key()->AsLiteral()->IsPropertyName()) {
701 desc.IncPropertiesCount();
702 } else {
703 desc.IncElementsCount();
704 }
705 }
706 }
707
708 //
709 // Initialize class object template.
710 //
711 static_desc.CreateTemplates(isolate);
712 static_assert(JSFunction::kLengthDescriptorIndex == 0);
713 {
714 // Add length_accessor.
715 PropertyAttributes attribs =
716 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
717 static_desc.AddConstant(isolate, factory->length_string(),
718 factory->function_length_accessor(), attribs);
719 }
720 {
721 // Add name_accessor.
722 // All classes, even anonymous ones, have a name accessor.
723 PropertyAttributes attribs =
724 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
725 static_desc.AddConstant(isolate, factory->name_string(),
726 factory->function_name_accessor(), attribs);
727 }
728 {
729 // Add prototype_accessor.
730 PropertyAttributes attribs =
732 static_desc.AddConstant(isolate, factory->prototype_string(),
733 factory->function_prototype_accessor(), attribs);
734 }
735 {
736 DirectHandle<ClassPositions> class_positions = factory->NewClassPositions(
737 expr->start_position(), expr->end_position());
738 static_desc.AddConstant(isolate, factory->class_positions_symbol(),
739 class_positions, DONT_ENUM);
740 }
741
742 //
743 // Initialize prototype object template.
744 //
745 instance_desc.CreateTemplates(isolate);
746 {
749 instance_desc.AddConstant(isolate, factory->constructor_string(), value,
750 DONT_ENUM);
751 }
752
753 //
754 // Fill in class boilerplate.
755 //
756 int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
757
758 for (int i = 0; i < expr->public_members()->length(); i++) {
759 ClassLiteral::Property* property = expr->public_members()->at(i);
761 int value_index = dynamic_argument_index;
762 switch (property->kind()) {
764 value_kind = ClassBoilerplate::kData;
765 break;
767 value_kind = ClassBoilerplate::kGetter;
768 break;
770 value_kind = ClassBoilerplate::kSetter;
771 break;
773 DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
774 if (property->is_computed_name()) {
775 ++dynamic_argument_index;
776 }
777 continue;
780 // Auto-accessors have two arguments (getter and setter).
781 ++dynamic_argument_index;
782 }
783
785 property->is_static() ? static_desc : instance_desc;
786 if (property->is_computed_name()) {
787 int computed_name_index = value_index;
788 dynamic_argument_index += 2; // Computed name and value indices.
789 desc.AddComputed(value_kind, computed_name_index);
790 continue;
791 }
792 dynamic_argument_index++;
793
794 Literal* key_literal = property->key()->AsLiteral();
795 uint32_t index;
796 if (key_literal->AsArrayIndex(&index)) {
797 desc.AddIndexedProperty(isolate, index, value_kind, value_index);
798
799 } else {
800 Handle<String> name = key_literal->AsRawPropertyName()->string();
801 DCHECK(IsInternalizedString(*name));
802 desc.AddNamedProperty(isolate, name, value_kind, value_index);
803 }
804 }
805
806 static_desc.Finalize(isolate);
807 instance_desc.Finalize(isolate);
808
810 factory->NewStruct(CLASS_BOILERPLATE_TYPE, allocation));
811
812 result->set_arguments_count(dynamic_argument_index);
813
814 result->set_static_properties_template(*static_desc.properties_template());
815 result->set_static_elements_template(*static_desc.elements_template());
816 result->set_static_computed_properties(*static_desc.computed_properties());
817
818 result->set_instance_properties_template(
819 *instance_desc.properties_template());
820 result->set_instance_elements_template(*instance_desc.elements_template());
821 result->set_instance_computed_properties(
822 *instance_desc.computed_properties());
823
824 return scope.CloseAndEscape(result);
825}
826
828 Isolate* isolate, ClassLiteral* expr, AllocationType allocation);
830 LocalIsolate* isolate, ClassLiteral* expr, AllocationType allocation);
831
833 os << " " << ElementsKindToString(elements_kind()) << ", "
834 << Brief(constant_elements());
835}
836
838 // Note: keep boilerplate layout synced with JSRegExp layout.
839 static_assert(JSRegExp::kDataOffset == JSObject::kHeaderSize);
840 static_assert(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
841 static_assert(JSRegExp::kFlagsOffset ==
842 JSRegExp::kSourceOffset + kTaggedSize);
843 static_assert(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
845 os << " " << Brief(data(isolate)) << ", " << Brief(source()) << ", "
846 << flags();
847}
848
849} // namespace internal
850} // namespace v8
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
Builtins::Kind kind
Definition builtins.cc:40
static const int kMinimumPrototypePropertiesCount
static void AddToPropertiesTemplate(IsolateT *isolate, Handle< Dictionary > dictionary, Handle< Name > name, int key_index, ValueKind value_kind, Tagged< Smi > value)
static const int kMinimumClassPropertiesCount
static void AddToElementsTemplate(IsolateT *isolate, Handle< NumberDictionary > dictionary, uint32_t key, int key_index, ValueKind value_kind, Tagged< Smi > value)
static Handle< ClassBoilerplate > New(IsolateT *isolate, ClassLiteral *expr, AllocationType allocation=AllocationType::kYoung)
int end_position() const
Definition ast.h:2712
int start_position() const
Definition ast.h:2711
ZonePtrList< Property > * public_members() const
Definition ast.h:2709
static V8_EXPORT_PRIVATE Handle< DescriptorArray > Allocate(IsolateT *isolate, int nof_descriptors, int slack, AllocationType allocation=AllocationType::kYoung)
static Descriptor AccessorConstant(DirectHandle< Name > key, DirectHandle< Object > foreign, PropertyAttributes attributes)
Definition property.cc:118
static Descriptor DataConstant(DirectHandle< Name > key, DirectHandle< Object > value, PropertyAttributes attributes)
Definition property.cc:100
void PatchValue(Tagged< T > new_value)
Definition handles.h:213
bool AsArrayIndex(uint32_t *index) const
Definition ast.cc:1046
const AstRawString * AsRawPropertyName()
Definition ast.h:980
static V8_WARN_UNUSED_RESULT Handle< NameDictionary > New(IsolateT *isolate, int at_least_space_for, AllocationType allocation=AllocationType::kYoung, MinimumCapacity capacity_option=USE_DEFAULT_MINIMUM_CAPACITY)
Handle< Object > properties_template() const
void UpdateNextEnumerationIndex(int value_index)
Handle< NumberDictionary > elements_dictionary_template_
Handle< FixedArray > computed_properties() const
Handle< SwissNameDictionary > properties_ordered_dictionary_template() const
void CreateTemplates(IsolateT *isolate)
void AddConstant(IsolateT *isolate, DirectHandle< Name > name, DirectHandle< Object > value, PropertyAttributes attribs)
Handle< FixedArray > computed_properties_
Handle< HeapObject > properties_dictionary_template_
Handle< DescriptorArray > descriptor_array_template_
void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index)
void Finalize(IsolateT *isolate)
Handle< NameDictionary > properties_dictionary_template() const
ObjectDescriptor(int property_slack)
void AddIndexedProperty(IsolateT *isolate, uint32_t element, ClassBoilerplate::ValueKind value_kind, int value_index)
void AddNamedProperty(IsolateT *isolate, Handle< Name > name, ClassBoilerplate::ValueKind value_kind, int value_index)
Handle< NumberDictionary > elements_template() const
static constexpr PropertyConstness kConstIfDictConstnessTracking
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static HandleType< SwissNameDictionary > Add(IsolateT *isolate, HandleType< SwissNameDictionary > table, DirectHandle< Name > key, DirectHandle< Object > value, PropertyDetails details, InternalIndex *entry_out=nullptr)
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
ZoneVector< RpoNumber > & result
InstructionOperand source
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
V8_EXPORT_PRIVATE base::Vector< Flag > Flags()
Definition flags.cc:300
constexpr int kTaggedSize
Definition globals.h:542
Tagged(T object) -> Tagged< T >
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
Flag flags[]
Definition flags.cc:3797
const char * ElementsKindToString(ElementsKind kind)
V8_INLINE IsolateForSandbox GetIsolateForSandbox(Tagged< HeapObject >)
Definition isolate.h:75
static const int kMaxNumberOfDescriptors
return value
Definition map-inl.h:893
@ ACCESSOR_GETTER
Definition objects.h:879
@ ACCESSOR_SETTER
Definition objects.h:879
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
Local< T > Handle
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485