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