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/js-regexp.h" 17#include "src/objects/literal-objects-inl.h" 18#include "src/objects/objects-inl.h" 19#include "src/objects/smi.h" 20#include "src/objects/struct-inl.h" 21 22namespace v8 { 23namespace internal { 24 25namespace { 26 27// The enumeration order index in the property details is unused if they are 28// stored in a SwissNameDictionary or NumberDictionary (because they handle 29// propery ordering differently). We then use this dummy value instead. 30constexpr int kDummyEnumerationIndex = 0; 31 32inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind, 33 unsigned key_index) { 34 using Flags = ClassBoilerplate::ComputedEntryFlags; 35 int flags = Flags::ValueKindBits::encode(value_kind) | 36 Flags::KeyIndexBits::encode(key_index); 37 return flags; 38} 39 40constexpr AccessorComponent ToAccessorComponent( 41 ClassBoilerplate::ValueKind value_kind) { 42 return value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER 43 : ACCESSOR_SETTER; 44} 45 46template <typename IsolateT> 47void AddToDescriptorArrayTemplate( 48 IsolateT* isolate, Handle<DescriptorArray> descriptor_array_template, 49 Handle<Name> name, ClassBoilerplate::ValueKind value_kind, 50 Handle<Object> value) { 51 InternalIndex entry = descriptor_array_template->Search( 52 *name, descriptor_array_template->number_of_descriptors()); 53 // TODO(ishell): deduplicate properties at AST level, this will allow us to 54 // avoid creation of closures that will be overwritten anyway. 55 if (entry.is_not_found()) { 56 // Entry not found, add new one. 57 Descriptor d; 58 if (value_kind == ClassBoilerplate::kData) { 59 d = Descriptor::DataConstant(name, value, DONT_ENUM); 60 } else { 61 DCHECK(value_kind == ClassBoilerplate::kGetter || 62 value_kind == ClassBoilerplate::kSetter); 63 Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair(); 64 pair->set(ToAccessorComponent(value_kind), *value); 65 d = Descriptor::AccessorConstant(name, pair, DONT_ENUM); 66 } 67 descriptor_array_template->Append(&d); 68 69 } else { 70 // Entry found, update it. 71 int sorted_index = descriptor_array_template->GetDetails(entry).pointer(); 72 if (value_kind == ClassBoilerplate::kData) { 73 Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM); 74 d.SetSortedKeyIndex(sorted_index); 75 descriptor_array_template->Set(entry, &d); 76 } else { 77 DCHECK(value_kind == ClassBoilerplate::kGetter || 78 value_kind == ClassBoilerplate::kSetter); 79 Object raw_accessor = descriptor_array_template->GetStrongValue(entry); 80 AccessorPair pair; 81 if (raw_accessor.IsAccessorPair()) { 82 pair = AccessorPair::cast(raw_accessor); 83 } else { 84 Handle<AccessorPair> new_pair = isolate->factory()->NewAccessorPair(); 85 Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM); 86 d.SetSortedKeyIndex(sorted_index); 87 descriptor_array_template->Set(entry, &d); 88 pair = *new_pair; 89 } 90 pair.set(ToAccessorComponent(value_kind), *value, kReleaseStore); 91 } 92 } 93} 94 95template <typename IsolateT> 96Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex( 97 IsolateT* isolate, Handle<NameDictionary> dictionary, Handle<Name> name, 98 Handle<Object> value, PropertyDetails details, 99 InternalIndex* entry_out = nullptr) { 100 return NameDictionary::AddNoUpdateNextEnumerationIndex( 101 isolate, dictionary, name, value, details, entry_out); 102} 103 104template <typename IsolateT> 105Handle<SwissNameDictionary> DictionaryAddNoUpdateNextEnumerationIndex( 106 IsolateT* isolate, Handle<SwissNameDictionary> dictionary, 107 Handle<Name> name, Handle<Object> value, PropertyDetails details, 108 InternalIndex* entry_out = nullptr) { 109 // SwissNameDictionary does not maintain the enumeration order in property 110 // details, so it's a normal Add(). 111 return SwissNameDictionary::Add(isolate, dictionary, name, value, details); 112} 113 114template <typename IsolateT> 115Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex( 116 IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t element, 117 Handle<Object> value, PropertyDetails details, 118 InternalIndex* entry_out = nullptr) { 119 // NumberDictionary does not maintain the enumeration order, so it's 120 // a normal Add(). 121 return NumberDictionary::Add(isolate, dictionary, element, value, details, 122 entry_out); 123} 124 125template <typename Dictionary> 126void DictionaryUpdateMaxNumberKey(Handle<Dictionary> dictionary, 127 Handle<Name> name) { 128 STATIC_ASSERT((std::is_same<Dictionary, SwissNameDictionary>::value || 129 std::is_same<Dictionary, NameDictionary>::value)); 130 // No-op for (ordered) name dictionaries. 131} 132 133void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary, 134 uint32_t element) { 135 dictionary->UpdateMaxNumberKey(element, Handle<JSObject>()); 136 dictionary->set_requires_slow_elements(); 137} 138 139constexpr int ComputeEnumerationIndex(int value_index) { 140 // We "shift" value indices to ensure that the enumeration index for the value 141 // will not overlap with minimum properties set for both class and prototype 142 // objects. 143 return value_index + 144 std::max({ClassBoilerplate::kMinimumClassPropertiesCount, 145 ClassBoilerplate::kMinimumPrototypePropertiesCount}); 146} 147 148constexpr int kAccessorNotDefined = -1; 149 150inline int GetExistingValueIndex(Object value) { 151 return value.IsSmi() ? Smi::ToInt(value) : kAccessorNotDefined; 152} 153 154template <typename IsolateT, typename Dictionary, typename Key> 155void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary, 156 Key key, int key_index, 157 ClassBoilerplate::ValueKind value_kind, 158 Smi value) { 159 InternalIndex entry = dictionary->FindEntry(isolate, key); 160 161 const bool is_elements_dictionary = 162 std::is_same<Dictionary, NumberDictionary>::value; 163 STATIC_ASSERT(is_elements_dictionary != 164 (std::is_same<Dictionary, NameDictionary>::value || 165 std::is_same<Dictionary, SwissNameDictionary>::value)); 166 167 if (entry.is_not_found()) { 168 // Entry not found, add new one. 169 int enum_order = 170 Dictionary::kIsOrderedDictionaryType || is_elements_dictionary 171 ? kDummyEnumerationIndex 172 : ComputeEnumerationIndex(key_index); 173 Handle<Object> value_handle; 174 PropertyDetails details( 175 value_kind != ClassBoilerplate::kData ? PropertyKind::kAccessor 176 : PropertyKind::kData, 177 DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking, enum_order); 178 if (value_kind == ClassBoilerplate::kData) { 179 value_handle = handle(value, isolate); 180 } else { 181 Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair()); 182 pair->set(ToAccessorComponent(value_kind), value); 183 value_handle = pair; 184 } 185 186 // Add value to the dictionary without updating next enumeration index. 187 Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex( 188 isolate, dictionary, key, value_handle, details, &entry); 189 // It is crucial to avoid dictionary reallocations because it may remove 190 // potential gaps in enumeration indices values that are necessary for 191 // inserting computed properties into right places in the enumeration order. 192 CHECK_EQ(*dict, *dictionary); 193 194 DictionaryUpdateMaxNumberKey(dictionary, key); 195 196 } else { 197 // Entry found, update it. 198 int enum_order_existing = 199 Dictionary::kIsOrderedDictionaryType 200 ? kDummyEnumerationIndex 201 : dictionary->DetailsAt(entry).dictionary_index(); 202 int enum_order_computed = 203 Dictionary::kIsOrderedDictionaryType || is_elements_dictionary 204 ? kDummyEnumerationIndex 205 : ComputeEnumerationIndex(key_index); 206 207 Object existing_value = dictionary->ValueAt(entry); 208 if (value_kind == ClassBoilerplate::kData) { 209 // Computed value is a normal method. 210 if (existing_value.IsAccessorPair()) { 211 AccessorPair current_pair = AccessorPair::cast(existing_value); 212 213 int existing_getter_index = 214 GetExistingValueIndex(current_pair.getter()); 215 int existing_setter_index = 216 GetExistingValueIndex(current_pair.setter()); 217 // At least one of the accessors must already be defined. 218 STATIC_ASSERT(kAccessorNotDefined < 0); 219 DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0); 220 if (existing_getter_index < key_index && 221 existing_setter_index < key_index) { 222 // Either both getter and setter were defined before the computed 223 // method or just one of them was defined before while the other one 224 // was not defined yet, so overwrite property to kData. 225 PropertyDetails details( 226 PropertyKind::kData, DONT_ENUM, 227 PropertyDetails::kConstIfDictConstnessTracking, 228 enum_order_existing); 229 dictionary->DetailsAtPut(entry, details); 230 dictionary->ValueAtPut(entry, value); 231 232 } else if (existing_getter_index != kAccessorNotDefined && 233 existing_getter_index < key_index) { 234 DCHECK_LT(key_index, existing_setter_index); 235 // Getter was defined and it was done before the computed method 236 // and then it was overwritten by the current computed method which 237 // in turn was later overwritten by the setter method. So we clear 238 // the getter. 239 current_pair.set_getter(*isolate->factory()->null_value()); 240 241 } else if (existing_setter_index != kAccessorNotDefined && 242 existing_setter_index < key_index) { 243 DCHECK_LT(key_index, existing_getter_index); 244 // Setter was defined and it was done before the computed method 245 // and then it was overwritten by the current computed method which 246 // in turn was later overwritten by the getter method. So we clear 247 // the setter. 248 current_pair.set_setter(*isolate->factory()->null_value()); 249 250 } else { 251 // One of the following cases holds: 252 // The computed method was defined before ... 253 // 1.) the getter and setter, both of which are defined, 254 // 2.) the getter, and the setter isn't defined, 255 // 3.) the setter, and the getter isn't defined. 256 // Therefore, the computed value is overwritten, receiving the 257 // computed property's enum index. 258 DCHECK(key_index < existing_getter_index || 259 existing_getter_index == kAccessorNotDefined); 260 DCHECK(key_index < existing_setter_index || 261 existing_setter_index == kAccessorNotDefined); 262 DCHECK(existing_getter_index != kAccessorNotDefined || 263 existing_setter_index != kAccessorNotDefined); 264 if (!is_elements_dictionary) { 265 // The enum index is unused by elements dictionaries, 266 // which is why we don't need to update the property details if 267 // |is_elements_dictionary| holds. 268 PropertyDetails details = dictionary->DetailsAt(entry); 269 details = details.set_index(enum_order_computed); 270 dictionary->DetailsAtPut(entry, details); 271 } 272 } 273 } else { // if (existing_value.IsAccessorPair()) ends here 274 DCHECK(value_kind == ClassBoilerplate::kData); 275 276 DCHECK_IMPLIES(!existing_value.IsSmi(), 277 existing_value.IsAccessorInfo()); 278 DCHECK_IMPLIES(!existing_value.IsSmi(), 279 AccessorInfo::cast(existing_value).name() == 280 *isolate->factory()->length_string() || 281 AccessorInfo::cast(existing_value).name() == 282 *isolate->factory()->name_string()); 283 if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) { 284 // Overwrite existing value because it was defined before the computed 285 // one (AccessorInfo "length" and "name" properties are always defined 286 // before). 287 PropertyDetails details( 288 PropertyKind::kData, DONT_ENUM, 289 PropertyDetails::kConstIfDictConstnessTracking, 290 enum_order_existing); 291 dictionary->DetailsAtPut(entry, details); 292 dictionary->ValueAtPut(entry, value); 293 } else { 294 // The computed value appears before the existing one. Set the 295 // existing entry's enum index to that of the computed one. 296 if (!is_elements_dictionary) { 297 // The enum index is unused by elements dictionaries, 298 // which is why we don't need to update the property details if 299 // |is_elements_dictionary| holds. 300 PropertyDetails details( 301 PropertyKind::kData, DONT_ENUM, 302 PropertyDetails::kConstIfDictConstnessTracking, 303 enum_order_computed); 304 305 dictionary->DetailsAtPut(entry, details); 306 } 307 } 308 } 309 } else { // if (value_kind == ClassBoilerplate::kData) ends here 310 AccessorComponent component = ToAccessorComponent(value_kind); 311 if (existing_value.IsAccessorPair()) { 312 // Update respective component of existing AccessorPair. 313 AccessorPair current_pair = AccessorPair::cast(existing_value); 314 315 int existing_component_index = 316 GetExistingValueIndex(current_pair.get(component)); 317 if (existing_component_index < key_index) { 318 current_pair.set(component, value, kReleaseStore); 319 } else { 320 // The existing accessor property overwrites the computed one, update 321 // its enumeration order accordingly. 322 323 if (!is_elements_dictionary) { 324 // The enum index is unused by elements dictionaries, 325 // which is why we don't need to update the property details if 326 // |is_elements_dictionary| holds. 327 328 PropertyDetails details( 329 PropertyKind::kAccessor, DONT_ENUM, 330 PropertyDetails::kConstIfDictConstnessTracking, 331 enum_order_computed); 332 dictionary->DetailsAtPut(entry, details); 333 } 334 } 335 336 } else { 337 DCHECK(!existing_value.IsAccessorPair()); 338 DCHECK(value_kind != ClassBoilerplate::kData); 339 340 if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) { 341 // Overwrite the existing data property because it was defined before 342 // the computed accessor property. 343 Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair()); 344 pair->set(component, value); 345 PropertyDetails details( 346 PropertyKind::kAccessor, DONT_ENUM, 347 PropertyDetails::kConstIfDictConstnessTracking, 348 enum_order_existing); 349 dictionary->DetailsAtPut(entry, details); 350 dictionary->ValueAtPut(entry, *pair); 351 } else { 352 // The computed accessor property appears before the existing data 353 // property. Set the existing entry's enum index to that of the 354 // computed one. 355 356 if (!is_elements_dictionary) { 357 // The enum index is unused by elements dictionaries, 358 // which is why we don't need to update the property details if 359 // |is_elements_dictionary| holds. 360 PropertyDetails details( 361 PropertyKind::kData, DONT_ENUM, 362 PropertyDetails::kConstIfDictConstnessTracking, 363 enum_order_computed); 364 365 dictionary->DetailsAtPut(entry, details); 366 } 367 } 368 } 369 } 370 } 371} 372 373} // namespace 374 375// Helper class that eases building of a properties, elements and computed 376// properties templates. 377template <typename IsolateT> 378class ObjectDescriptor { 379 public: 380 void IncComputedCount() { ++computed_count_; } 381 void IncPropertiesCount() { ++property_count_; } 382 void IncElementsCount() { ++element_count_; } 383 384 explicit ObjectDescriptor(int property_slack) 385 : property_slack_(property_slack) {} 386 387 bool HasDictionaryProperties() const { 388 return computed_count_ > 0 || 389 (property_count_ + property_slack_) > kMaxNumberOfDescriptors; 390 } 391 392 Handle<Object> properties_template() const { 393 return HasDictionaryProperties() 394 ? properties_dictionary_template_ 395 : Handle<Object>::cast(descriptor_array_template_); 396 } 397 398 Handle<NumberDictionary> elements_template() const { 399 return elements_dictionary_template_; 400 } 401 402 Handle<FixedArray> computed_properties() const { 403 return computed_properties_; 404 } 405 406 void CreateTemplates(IsolateT* isolate) { 407 auto* factory = isolate->factory(); 408 descriptor_array_template_ = factory->empty_descriptor_array(); 409 if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 410 properties_dictionary_template_ = 411 factory->empty_swiss_property_dictionary(); 412 } else { 413 properties_dictionary_template_ = factory->empty_property_dictionary(); 414 } 415 if (property_count_ || computed_count_ || property_slack_) { 416 if (HasDictionaryProperties()) { 417 int need_space_for = 418 property_count_ + computed_count_ + property_slack_; 419 if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 420 properties_dictionary_template_ = 421 isolate->factory()->NewSwissNameDictionary(need_space_for, 422 AllocationType::kOld); 423 424 } else { 425 properties_dictionary_template_ = NameDictionary::New( 426 isolate, need_space_for, AllocationType::kOld); 427 } 428 } else { 429 descriptor_array_template_ = DescriptorArray::Allocate( 430 isolate, 0, property_count_ + property_slack_, 431 AllocationType::kOld); 432 } 433 } 434 elements_dictionary_template_ = 435 element_count_ || computed_count_ 436 ? NumberDictionary::New(isolate, element_count_ + computed_count_, 437 AllocationType::kOld) 438 : factory->empty_slow_element_dictionary(); 439 440 computed_properties_ = 441 computed_count_ 442 ? factory->NewFixedArray(computed_count_, AllocationType::kOld) 443 : factory->empty_fixed_array(); 444 445 temp_handle_ = handle(Smi::zero(), isolate); 446 } 447 448 void AddConstant(IsolateT* isolate, Handle<Name> name, Handle<Object> value, 449 PropertyAttributes attribs) { 450 bool is_accessor = value->IsAccessorInfo(); 451 DCHECK(!value->IsAccessorPair()); 452 if (HasDictionaryProperties()) { 453 PropertyKind kind = 454 is_accessor ? i::PropertyKind::kAccessor : i::PropertyKind::kData; 455 int enum_order = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL 456 ? kDummyEnumerationIndex 457 : next_enumeration_index_++; 458 PropertyDetails details(kind, attribs, PropertyCellType::kNoCell, 459 enum_order); 460 if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 461 properties_dictionary_template_ = 462 DictionaryAddNoUpdateNextEnumerationIndex( 463 isolate, properties_ordered_dictionary_template(), name, value, 464 details); 465 } else { 466 properties_dictionary_template_ = 467 DictionaryAddNoUpdateNextEnumerationIndex( 468 isolate, properties_dictionary_template(), name, value, 469 details); 470 } 471 } else { 472 Descriptor d = is_accessor 473 ? Descriptor::AccessorConstant(name, value, attribs) 474 : Descriptor::DataConstant(name, value, attribs); 475 descriptor_array_template_->Append(&d); 476 } 477 } 478 479 void AddNamedProperty(IsolateT* isolate, Handle<Name> name, 480 ClassBoilerplate::ValueKind value_kind, 481 int value_index) { 482 Smi value = Smi::FromInt(value_index); 483 if (HasDictionaryProperties()) { 484 UpdateNextEnumerationIndex(value_index); 485 if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 486 AddToDictionaryTemplate(isolate, 487 properties_ordered_dictionary_template(), name, 488 value_index, value_kind, value); 489 } else { 490 AddToDictionaryTemplate(isolate, properties_dictionary_template(), name, 491 value_index, value_kind, value); 492 } 493 } else { 494 temp_handle_.PatchValue(value); 495 AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name, 496 value_kind, temp_handle_); 497 } 498 } 499 500 void AddIndexedProperty(IsolateT* isolate, uint32_t element, 501 ClassBoilerplate::ValueKind value_kind, 502 int value_index) { 503 Smi value = Smi::FromInt(value_index); 504 AddToDictionaryTemplate(isolate, elements_dictionary_template_, element, 505 value_index, value_kind, value); 506 } 507 508 void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) { 509 int value_index = key_index + 1; 510 UpdateNextEnumerationIndex(value_index); 511 512 int flags = EncodeComputedEntry(value_kind, key_index); 513 computed_properties_->set(current_computed_index_++, Smi::FromInt(flags)); 514 } 515 516 void UpdateNextEnumerationIndex(int value_index) { 517 int current_index = ComputeEnumerationIndex(value_index); 518 DCHECK_LE(next_enumeration_index_, current_index); 519 next_enumeration_index_ = current_index + 1; 520 } 521 522 void Finalize(IsolateT* isolate) { 523 if (HasDictionaryProperties()) { 524 DCHECK_EQ(current_computed_index_, computed_properties_->length()); 525 if (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { 526 properties_dictionary_template()->set_next_enumeration_index( 527 next_enumeration_index_); 528 } 529 } else { 530 DCHECK(descriptor_array_template_->IsSortedNoDuplicates()); 531 } 532 } 533 534 private: 535 Handle<NameDictionary> properties_dictionary_template() const { 536 return Handle<NameDictionary>::cast(properties_dictionary_template_); 537 } 538 539 Handle<SwissNameDictionary> properties_ordered_dictionary_template() const { 540 return Handle<SwissNameDictionary>::cast(properties_dictionary_template_); 541 } 542 543 const int property_slack_; 544 int property_count_ = 0; 545 int next_enumeration_index_ = PropertyDetails::kInitialIndex; 546 int element_count_ = 0; 547 int computed_count_ = 0; 548 int current_computed_index_ = 0; 549 550 Handle<DescriptorArray> descriptor_array_template_; 551 552 // Is either a NameDictionary or SwissNameDictionary. 553 Handle<HeapObject> properties_dictionary_template_; 554 555 Handle<NumberDictionary> elements_dictionary_template_; 556 Handle<FixedArray> computed_properties_; 557 // This temporary handle is used for storing to descriptor array. 558 Handle<Object> temp_handle_; 559}; 560 561template <typename IsolateT, typename PropertyDict> 562void ClassBoilerplate::AddToPropertiesTemplate( 563 IsolateT* isolate, Handle<PropertyDict> dictionary, Handle<Name> name, 564 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) { 565 AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind, 566 value); 567} 568template void ClassBoilerplate::AddToPropertiesTemplate( 569 Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name, 570 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value); 571template void ClassBoilerplate::AddToPropertiesTemplate( 572 LocalIsolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name, 573 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value); 574template void ClassBoilerplate::AddToPropertiesTemplate( 575 Isolate* isolate, Handle<SwissNameDictionary> dictionary, Handle<Name> name, 576 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value); 577 578template <typename IsolateT> 579void ClassBoilerplate::AddToElementsTemplate( 580 IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t key, 581 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) { 582 AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind, 583 value); 584} 585template void ClassBoilerplate::AddToElementsTemplate( 586 Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key, 587 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value); 588template void ClassBoilerplate::AddToElementsTemplate( 589 LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key, 590 int key_index, ClassBoilerplate::ValueKind value_kind, Smi value); 591 592template <typename IsolateT> 593Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( 594 IsolateT* isolate, ClassLiteral* expr) { 595 // Create a non-caching handle scope to ensure that the temporary handle used 596 // by ObjectDescriptor for passing Smis around does not corrupt handle cache 597 // in CanonicalHandleScope. 598 typename IsolateT::HandleScopeType scope(isolate); 599 auto* factory = isolate->factory(); 600 ObjectDescriptor<IsolateT> static_desc(kMinimumClassPropertiesCount); 601 ObjectDescriptor<IsolateT> instance_desc(kMinimumPrototypePropertiesCount); 602 603 for (int i = 0; i < expr->public_members()->length(); i++) { 604 ClassLiteral::Property* property = expr->public_members()->at(i); 605 ObjectDescriptor<IsolateT>& desc = 606 property->is_static() ? static_desc : instance_desc; 607 if (property->is_computed_name()) { 608 if (property->kind() != ClassLiteral::Property::FIELD) { 609 desc.IncComputedCount(); 610 } 611 } else { 612 if (property->key()->AsLiteral()->IsPropertyName()) { 613 desc.IncPropertiesCount(); 614 } else { 615 desc.IncElementsCount(); 616 } 617 } 618 } 619 620 // 621 // Initialize class object template. 622 // 623 static_desc.CreateTemplates(isolate); 624 STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0); 625 { 626 // Add length_accessor. 627 PropertyAttributes attribs = 628 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY); 629 static_desc.AddConstant(isolate, factory->length_string(), 630 factory->function_length_accessor(), attribs); 631 } 632 { 633 // Add name_accessor. 634 // All classes, even anonymous ones, have a name accessor. 635 PropertyAttributes attribs = 636 static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY); 637 static_desc.AddConstant(isolate, factory->name_string(), 638 factory->function_name_accessor(), attribs); 639 } 640 { 641 // Add prototype_accessor. 642 PropertyAttributes attribs = 643 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); 644 static_desc.AddConstant(isolate, factory->prototype_string(), 645 factory->function_prototype_accessor(), attribs); 646 } 647 { 648 Handle<ClassPositions> class_positions = factory->NewClassPositions( 649 expr->start_position(), expr->end_position()); 650 static_desc.AddConstant(isolate, factory->class_positions_symbol(), 651 class_positions, DONT_ENUM); 652 } 653 654 // 655 // Initialize prototype object template. 656 // 657 instance_desc.CreateTemplates(isolate); 658 { 659 Handle<Object> value( 660 Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate); 661 instance_desc.AddConstant(isolate, factory->constructor_string(), value, 662 DONT_ENUM); 663 } 664 665 // 666 // Fill in class boilerplate. 667 // 668 int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex; 669 670 for (int i = 0; i < expr->public_members()->length(); i++) { 671 ClassLiteral::Property* property = expr->public_members()->at(i); 672 ClassBoilerplate::ValueKind value_kind; 673 switch (property->kind()) { 674 case ClassLiteral::Property::METHOD: 675 value_kind = ClassBoilerplate::kData; 676 break; 677 case ClassLiteral::Property::GETTER: 678 value_kind = ClassBoilerplate::kGetter; 679 break; 680 case ClassLiteral::Property::SETTER: 681 value_kind = ClassBoilerplate::kSetter; 682 break; 683 case ClassLiteral::Property::FIELD: 684 DCHECK_IMPLIES(property->is_computed_name(), !property->is_private()); 685 if (property->is_computed_name()) { 686 ++dynamic_argument_index; 687 } 688 continue; 689 } 690 691 ObjectDescriptor<IsolateT>& desc = 692 property->is_static() ? static_desc : instance_desc; 693 if (property->is_computed_name()) { 694 int computed_name_index = dynamic_argument_index; 695 dynamic_argument_index += 2; // Computed name and value indices. 696 desc.AddComputed(value_kind, computed_name_index); 697 continue; 698 } 699 int value_index = dynamic_argument_index++; 700 701 Literal* key_literal = property->key()->AsLiteral(); 702 uint32_t index; 703 if (key_literal->AsArrayIndex(&index)) { 704 desc.AddIndexedProperty(isolate, index, value_kind, value_index); 705 706 } else { 707 Handle<String> name = key_literal->AsRawPropertyName()->string(); 708 DCHECK(name->IsInternalizedString()); 709 desc.AddNamedProperty(isolate, name, value_kind, value_index); 710 } 711 } 712 713 static_desc.Finalize(isolate); 714 instance_desc.Finalize(isolate); 715 716 Handle<ClassBoilerplate> class_boilerplate = Handle<ClassBoilerplate>::cast( 717 factory->NewFixedArray(kBoilerplateLength, AllocationType::kOld)); 718 719 class_boilerplate->set_arguments_count(dynamic_argument_index); 720 721 class_boilerplate->set_static_properties_template( 722 *static_desc.properties_template()); 723 class_boilerplate->set_static_elements_template( 724 *static_desc.elements_template()); 725 class_boilerplate->set_static_computed_properties( 726 *static_desc.computed_properties()); 727 728 class_boilerplate->set_instance_properties_template( 729 *instance_desc.properties_template()); 730 class_boilerplate->set_instance_elements_template( 731 *instance_desc.elements_template()); 732 class_boilerplate->set_instance_computed_properties( 733 *instance_desc.computed_properties()); 734 735 return scope.CloseAndEscape(class_boilerplate); 736} 737 738template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( 739 Isolate* isolate, ClassLiteral* expr); 740template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( 741 LocalIsolate* isolate, ClassLiteral* expr); 742 743void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) { 744 os << " " << ElementsKindToString(elements_kind()) << ", " 745 << Brief(constant_elements()); 746} 747 748void RegExpBoilerplateDescription::BriefPrintDetails(std::ostream& os) { 749 // Note: keep boilerplate layout synced with JSRegExp layout. 750 STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize); 751 STATIC_ASSERT(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize); 752 STATIC_ASSERT(JSRegExp::kFlagsOffset == 753 JSRegExp::kSourceOffset + kTaggedSize); 754 STATIC_ASSERT(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize); 755 os << " " << Brief(data()) << ", " << Brief(source()) << ", " << flags(); 756} 757 758} // namespace internal 759} // namespace v8 760