literal-objects.cc 30.9 KB
Newer Older
1 2 3 4 5 6
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/objects/literal-objects.h"

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 22 23 24

namespace v8 {
namespace internal {

25 26
namespace {

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 30 31
// propery ordering differently). We then use this dummy value instead.
constexpr int kDummyEnumerationIndex = 0;

32 33
inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
                               unsigned key_index) {
34
  using Flags = ClassBoilerplate::ComputedEntryFlags;
35 36 37 38 39
  int flags = Flags::ValueKindBits::encode(value_kind) |
              Flags::KeyIndexBits::encode(key_index);
  return flags;
}

40
template <typename IsolateT>
41
void AddToDescriptorArrayTemplate(
42
    IsolateT* isolate, Handle<DescriptorArray> descriptor_array_template,
43 44
    Handle<Name> name, ClassBoilerplate::ValueKind value_kind,
    Handle<Object> value) {
45
  InternalIndex entry = descriptor_array_template->Search(
46 47 48
      *name, descriptor_array_template->number_of_descriptors());
  // TODO(ishell): deduplicate properties at AST level, this will allow us to
  // avoid creation of closures that will be overwritten anyway.
49
  if (entry.is_not_found()) {
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    // Entry not found, add new one.
    Descriptor d;
    if (value_kind == ClassBoilerplate::kData) {
      d = Descriptor::DataConstant(name, value, DONT_ENUM);
    } else {
      DCHECK(value_kind == ClassBoilerplate::kGetter ||
             value_kind == ClassBoilerplate::kSetter);
      Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
      pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
                                                        : ACCESSOR_SETTER,
                *value);
      d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
    }
    descriptor_array_template->Append(&d);

  } else {
    // Entry found, update it.
    int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
    if (value_kind == ClassBoilerplate::kData) {
      Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
      d.SetSortedKeyIndex(sorted_index);
      descriptor_array_template->Set(entry, &d);
    } else {
      DCHECK(value_kind == ClassBoilerplate::kGetter ||
             value_kind == ClassBoilerplate::kSetter);
75
      Object raw_accessor = descriptor_array_template->GetStrongValue(entry);
76
      AccessorPair pair;
77
      if (raw_accessor.IsAccessorPair()) {
78 79 80 81 82 83 84 85
        pair = AccessorPair::cast(raw_accessor);
      } else {
        Handle<AccessorPair> new_pair = isolate->factory()->NewAccessorPair();
        Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
        d.SetSortedKeyIndex(sorted_index);
        descriptor_array_template->Set(entry, &d);
        pair = *new_pair;
      }
86 87 88
      pair.set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
                                                       : ACCESSOR_SETTER,
               *value);
89 90 91 92
    }
  }
}

93
template <typename IsolateT>
94
Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
95
    IsolateT* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
96 97
    Handle<Object> value, PropertyDetails details,
    InternalIndex* entry_out = nullptr) {
98
  return NameDictionary::AddNoUpdateNextEnumerationIndex(
99
      isolate, dictionary, name, value, details, entry_out);
100 101
}

102
template <typename IsolateT>
103
Handle<SwissNameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
104
    IsolateT* isolate, Handle<SwissNameDictionary> dictionary,
105 106
    Handle<Name> name, Handle<Object> value, PropertyDetails details,
    InternalIndex* entry_out = nullptr) {
107
  // SwissNameDictionary does not maintain the enumeration order in property
108
  // details, so it's a normal Add().
109
  return SwissNameDictionary::Add(isolate, dictionary, name, value, details);
110 111
}

112
template <typename IsolateT>
113
Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
114 115
    IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t element,
    Handle<Object> value, PropertyDetails details,
116
    InternalIndex* entry_out = nullptr) {
117 118
  // NumberDictionary does not maintain the enumeration order, so it's
  // a normal Add().
119 120
  return NumberDictionary::Add(isolate, dictionary, element, value, details,
                               entry_out);
121 122
}

123 124
template <typename Dictionary>
void DictionaryUpdateMaxNumberKey(Handle<Dictionary> dictionary,
125
                                  Handle<Name> name) {
126
  STATIC_ASSERT((std::is_same<Dictionary, SwissNameDictionary>::value ||
127 128
                 std::is_same<Dictionary, NameDictionary>::value));
  // No-op for (ordered) name dictionaries.
129 130 131 132 133 134 135 136 137 138 139 140
}

void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary,
                                  uint32_t element) {
  dictionary->UpdateMaxNumberKey(element, Handle<JSObject>());
  dictionary->set_requires_slow_elements();
}

constexpr int ComputeEnumerationIndex(int value_index) {
  // We "shift" value indices to ensure that the enumeration index for the value
  // will not overlap with minimum properties set for both class and prototype
  // objects.
141 142 143
  return value_index +
         std::max({ClassBoilerplate::kMinimumClassPropertiesCount,
                   ClassBoilerplate::kMinimumPrototypePropertiesCount});
144 145
}

146 147
constexpr int kAccessorNotDefined = -1;

148
inline int GetExistingValueIndex(Object value) {
149
  return value.IsSmi() ? Smi::ToInt(value) : kAccessorNotDefined;
150 151
}

152 153 154
template <typename IsolateT, typename Dictionary, typename Key>
void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary,
                             Key key, int key_index,
155
                             ClassBoilerplate::ValueKind value_kind,
156
                             Smi value) {
157
  InternalIndex entry = dictionary->FindEntry(isolate, key);
158

159 160 161 162
  const bool is_elements_dictionary =
      std::is_same<Dictionary, NumberDictionary>::value;
  STATIC_ASSERT(is_elements_dictionary !=
                (std::is_same<Dictionary, NameDictionary>::value ||
163
                 std::is_same<Dictionary, SwissNameDictionary>::value));
164

165
  if (entry.is_not_found()) {
166 167
    // Entry not found, add new one.
    int enum_order =
168 169 170
        Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
            ? kDummyEnumerationIndex
            : ComputeEnumerationIndex(key_index);
171 172 173
    Handle<Object> value_handle;
    PropertyDetails details(
        value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
174
        PropertyDetails::kConstIfDictConstnessTracking, enum_order);
175 176 177 178 179 180 181 182 183 184 185 186 187
    if (value_kind == ClassBoilerplate::kData) {
      value_handle = handle(value, isolate);
    } else {
      AccessorComponent component = value_kind == ClassBoilerplate::kGetter
                                        ? ACCESSOR_GETTER
                                        : ACCESSOR_SETTER;
      Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
      pair->set(component, value);
      value_handle = pair;
    }

    // Add value to the dictionary without updating next enumeration index.
    Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
188
        isolate, dictionary, key, value_handle, details, &entry);
189 190 191 192 193 194 195 196 197
    // It is crucial to avoid dictionary reallocations because it may remove
    // potential gaps in enumeration indices values that are necessary for
    // inserting computed properties into right places in the enumeration order.
    CHECK_EQ(*dict, *dictionary);

    DictionaryUpdateMaxNumberKey(dictionary, key);

  } else {
    // Entry found, update it.
198 199 200 201 202 203 204 205 206
    int enum_order_existing =
        Dictionary::kIsOrderedDictionaryType
            ? kDummyEnumerationIndex
            : dictionary->DetailsAt(entry).dictionary_index();
    int enum_order_computed =
        Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
            ? kDummyEnumerationIndex
            : ComputeEnumerationIndex(key_index);

207
    Object existing_value = dictionary->ValueAt(entry);
208 209
    if (value_kind == ClassBoilerplate::kData) {
      // 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 221
        if (existing_getter_index < key_index &&
            existing_setter_index < key_index) {
222 223 224
          // Either both getter and setter were defined before the computed
          // method or just one of them was defined before while the other one
          // was not defined yet, so overwrite property to kData.
225 226 227
          PropertyDetails details(
              kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
228
          dictionary->DetailsAtPut(entry, details);
229 230
          dictionary->ValueAtPut(entry, value);

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        } else if (existing_getter_index != kAccessorNotDefined &&
                   existing_getter_index < key_index) {
          DCHECK_LT(key_index, existing_setter_index);
          // Getter was defined and it was done before the computed method
          // and then it was overwritten by the current computed method which
          // in turn was later overwritten by the setter method. So we clear
          // the getter.
          current_pair.set_getter(*isolate->factory()->null_value());

        } else if (existing_setter_index != kAccessorNotDefined &&
                   existing_setter_index < key_index) {
          DCHECK_LT(key_index, existing_getter_index);
          // Setter was defined and it was done before the computed method
          // and then it was overwritten by the current computed method which
          // in turn was later overwritten by the getter method. So we clear
          // the setter.
          current_pair.set_setter(*isolate->factory()->null_value());

249
        } else {
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
          // One of the following cases holds:
          // The computed method was defined before ...
          // 1.) the getter and setter, both of which are defined,
          // 2.) the getter, and the setter isn't defined,
          // 3.) the setter, and the getter isn't defined.
          // Therefore, the computed value is overwritten, receiving the
          // computed property's enum index.
          DCHECK(key_index < existing_getter_index ||
                 existing_getter_index == kAccessorNotDefined);
          DCHECK(key_index < existing_setter_index ||
                 existing_setter_index == kAccessorNotDefined);
          DCHECK(existing_getter_index != kAccessorNotDefined ||
                 existing_setter_index != kAccessorNotDefined);
          if (!is_elements_dictionary) {
            // The enum index is unused by elements dictionaries,
            // which is why we don't need to update the property details if
            // |is_elements_dictionary| holds.
            PropertyDetails details = dictionary->DetailsAt(entry);
            details = details.set_index(enum_order_computed);
            dictionary->DetailsAtPut(entry, details);
270 271
          }
        }
272 273 274
      } else {  // if (existing_value.IsAccessorPair()) ends here
        DCHECK(value_kind == ClassBoilerplate::kData);

275 276 277 278
        DCHECK_IMPLIES(!existing_value.IsSmi(),
                       existing_value.IsAccessorInfo());
        DCHECK_IMPLIES(!existing_value.IsSmi(),
                       AccessorInfo::cast(existing_value).name() ==
279
                           *isolate->factory()->length_string());
280
        if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) {
281 282
          // Overwrite existing value because it was defined before the computed
          // one (AccessorInfo "length" property is always defined before).
283 284 285
          PropertyDetails details(
              kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
286
          dictionary->DetailsAtPut(entry, details);
287
          dictionary->ValueAtPut(entry, value);
288 289 290 291 292 293 294
        } else {
          // The computed value appears before the existing one. Set the
          // existing entry's enum index to that of the computed one.
          if (!is_elements_dictionary) {
            // The enum index is unused by elements dictionaries,
            // which is why we don't need to update the property details if
            // |is_elements_dictionary| holds.
295 296 297 298
            PropertyDetails details(
                kData, DONT_ENUM,
                PropertyDetails::kConstIfDictConstnessTracking,
                enum_order_computed);
299 300 301

            dictionary->DetailsAtPut(entry, details);
          }
302 303
        }
      }
304
    } else {  // if (value_kind == ClassBoilerplate::kData) ends here
305 306 307
      AccessorComponent component = value_kind == ClassBoilerplate::kGetter
                                        ? ACCESSOR_GETTER
                                        : ACCESSOR_SETTER;
308
      if (existing_value.IsAccessorPair()) {
309
        // Update respective component of existing AccessorPair.
310
        AccessorPair current_pair = AccessorPair::cast(existing_value);
311 312

        int existing_component_index =
313
            GetExistingValueIndex(current_pair.get(component));
314
        if (existing_component_index < key_index) {
315
          current_pair.set(component, value);
316 317 318 319 320 321 322 323 324
        } else {
          // The existing accessor property overwrites the computed one, update
          // its enumeration order accordingly.

          if (!is_elements_dictionary) {
            // The enum index is unused by elements dictionaries,
            // which is why we don't need to update the property details if
            // |is_elements_dictionary| holds.

325 326 327 328
            PropertyDetails details(
                kAccessor, DONT_ENUM,
                PropertyDetails::kConstIfDictConstnessTracking,
                enum_order_computed);
329 330
            dictionary->DetailsAtPut(entry, details);
          }
331 332 333
        }

      } else {
334 335 336 337 338 339 340 341
        DCHECK(!existing_value.IsAccessorPair());
        DCHECK(value_kind != ClassBoilerplate::kData);

        if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) {
          // Overwrite the existing data property because it was defined before
          // the computed accessor property.
          Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
          pair->set(component, value);
342 343 344 345
          PropertyDetails details(
              kAccessor, DONT_ENUM,
              PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
346 347 348 349 350 351 352 353 354 355 356
          dictionary->DetailsAtPut(entry, details);
          dictionary->ValueAtPut(entry, *pair);
        } else {
          // The computed accessor property appears before the existing data
          // property. Set the existing entry's enum index to that of the
          // computed one.

          if (!is_elements_dictionary) {
            // The enum index is unused by elements dictionaries,
            // which is why we don't need to update the property details if
            // |is_elements_dictionary| holds.
357 358 359 360
            PropertyDetails details(
                kData, DONT_ENUM,
                PropertyDetails::kConstIfDictConstnessTracking,
                enum_order_computed);
361 362 363 364

            dictionary->DetailsAtPut(entry, details);
          }
        }
365 366 367 368 369 370 371 372 373
      }
    }
  }
}

}  // namespace

// Helper class that eases building of a properties, elements and computed
// properties templates.
374
template <typename IsolateT>
375 376 377 378 379 380
class ObjectDescriptor {
 public:
  void IncComputedCount() { ++computed_count_; }
  void IncPropertiesCount() { ++property_count_; }
  void IncElementsCount() { ++element_count_; }

381 382 383
  explicit ObjectDescriptor(int property_slack)
      : property_slack_(property_slack) {}

384
  bool HasDictionaryProperties() const {
385 386
    return computed_count_ > 0 ||
           (property_count_ + property_slack_) > kMaxNumberOfDescriptors;
387
  }
388 389

  Handle<Object> properties_template() const {
390
    return HasDictionaryProperties()
391
               ? properties_dictionary_template_
392 393 394 395 396 397 398 399 400 401 402
               : Handle<Object>::cast(descriptor_array_template_);
  }

  Handle<NumberDictionary> elements_template() const {
    return elements_dictionary_template_;
  }

  Handle<FixedArray> computed_properties() const {
    return computed_properties_;
  }

403
  void CreateTemplates(IsolateT* isolate) {
404
    auto* factory = isolate->factory();
405
    descriptor_array_template_ = factory->empty_descriptor_array();
406
    if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
407
      properties_dictionary_template_ =
408
          factory->empty_swiss_property_dictionary();
409 410 411
    } else {
      properties_dictionary_template_ = factory->empty_property_dictionary();
    }
412
    if (property_count_ || computed_count_ || property_slack_) {
413
      if (HasDictionaryProperties()) {
414 415
        int need_space_for =
            property_count_ + computed_count_ + property_slack_;
416
        if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
417
          properties_dictionary_template_ =
418 419 420
              isolate->factory()->NewSwissNameDictionary(need_space_for,
                                                         AllocationType::kOld);

421 422 423 424
        } else {
          properties_dictionary_template_ = NameDictionary::New(
              isolate, need_space_for, AllocationType::kOld);
        }
425
      } else {
426
        descriptor_array_template_ = DescriptorArray::Allocate(
427 428
            isolate, 0, property_count_ + property_slack_,
            AllocationType::kOld);
429 430 431 432
      }
    }
    elements_dictionary_template_ =
        element_count_ || computed_count_
433 434
            ? NumberDictionary::New(isolate, element_count_ + computed_count_,
                                    AllocationType::kOld)
435 436
            : factory->empty_slow_element_dictionary();

437 438 439 440
    computed_properties_ =
        computed_count_
            ? factory->NewFixedArray(computed_count_, AllocationType::kOld)
            : factory->empty_fixed_array();
441

442
    temp_handle_ = handle(Smi::zero(), isolate);
443 444
  }

445 446
  void AddConstant(IsolateT* isolate, Handle<Name> name, Handle<Object> value,
                   PropertyAttributes attribs) {
447 448
    bool is_accessor = value->IsAccessorInfo();
    DCHECK(!value->IsAccessorPair());
449
    if (HasDictionaryProperties()) {
450
      PropertyKind kind = is_accessor ? i::kAccessor : i::kData;
451 452 453
      int enum_order = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
                           ? kDummyEnumerationIndex
                           : next_enumeration_index_++;
454
      PropertyDetails details(kind, attribs, PropertyCellType::kNoCell,
455
                              enum_order);
456
      if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
457 458 459 460 461 462 463 464 465 466
        properties_dictionary_template_ =
            DictionaryAddNoUpdateNextEnumerationIndex(
                isolate, properties_ordered_dictionary_template(), name, value,
                details);
      } else {
        properties_dictionary_template_ =
            DictionaryAddNoUpdateNextEnumerationIndex(
                isolate, properties_dictionary_template(), name, value,
                details);
      }
467 468 469 470 471 472 473 474
    } else {
      Descriptor d = is_accessor
                         ? Descriptor::AccessorConstant(name, value, attribs)
                         : Descriptor::DataConstant(name, value, attribs);
      descriptor_array_template_->Append(&d);
    }
  }

475
  void AddNamedProperty(IsolateT* isolate, Handle<Name> name,
476 477
                        ClassBoilerplate::ValueKind value_kind,
                        int value_index) {
478
    Smi value = Smi::FromInt(value_index);
479
    if (HasDictionaryProperties()) {
480
      UpdateNextEnumerationIndex(value_index);
481
      if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
482 483 484 485 486 487 488
        AddToDictionaryTemplate(isolate,
                                properties_ordered_dictionary_template(), name,
                                value_index, value_kind, value);
      } else {
        AddToDictionaryTemplate(isolate, properties_dictionary_template(), name,
                                value_index, value_kind, value);
      }
489
    } else {
490
      temp_handle_.PatchValue(value);
491 492 493 494 495
      AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
                                   value_kind, temp_handle_);
    }
  }

496
  void AddIndexedProperty(IsolateT* isolate, uint32_t element,
497 498
                          ClassBoilerplate::ValueKind value_kind,
                          int value_index) {
499
    Smi value = Smi::FromInt(value_index);
500 501 502 503 504 505 506 507 508 509 510 511 512
    AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
                            value_index, value_kind, value);
  }

  void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) {
    int value_index = key_index + 1;
    UpdateNextEnumerationIndex(value_index);

    int flags = EncodeComputedEntry(value_kind, key_index);
    computed_properties_->set(current_computed_index_++, Smi::FromInt(flags));
  }

  void UpdateNextEnumerationIndex(int value_index) {
513 514 515
    int current_index = ComputeEnumerationIndex(value_index);
    DCHECK_LE(next_enumeration_index_, current_index);
    next_enumeration_index_ = current_index + 1;
516 517
  }

518
  void Finalize(IsolateT* isolate) {
519
    if (HasDictionaryProperties()) {
520
      DCHECK_EQ(current_computed_index_, computed_properties_->length());
521
      if (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
522 523 524
        properties_dictionary_template()->set_next_enumeration_index(
            next_enumeration_index_);
      }
525
    } else {
526
      DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
527 528 529 530
    }
  }

 private:
531 532 533 534
  Handle<NameDictionary> properties_dictionary_template() const {
    return Handle<NameDictionary>::cast(properties_dictionary_template_);
  }

535 536
  Handle<SwissNameDictionary> properties_ordered_dictionary_template() const {
    return Handle<SwissNameDictionary>::cast(properties_dictionary_template_);
537 538
  }

539
  const int property_slack_;
540 541 542 543 544 545 546
  int property_count_ = 0;
  int next_enumeration_index_ = PropertyDetails::kInitialIndex;
  int element_count_ = 0;
  int computed_count_ = 0;
  int current_computed_index_ = 0;

  Handle<DescriptorArray> descriptor_array_template_;
547

548
  // Is either a NameDictionary or SwissNameDictionary.
549 550
  Handle<HeapObject> properties_dictionary_template_;

551 552 553 554 555 556
  Handle<NumberDictionary> elements_dictionary_template_;
  Handle<FixedArray> computed_properties_;
  // This temporary handle is used for storing to descriptor array.
  Handle<Object> temp_handle_;
};

557
template <typename IsolateT, typename PropertyDict>
558
void ClassBoilerplate::AddToPropertiesTemplate(
559
    IsolateT* isolate, Handle<PropertyDict> dictionary, Handle<Name> name,
560
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) {
561 562 563
  AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
                          value);
}
564 565 566 567
template void ClassBoilerplate::AddToPropertiesTemplate(
    Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
template void ClassBoilerplate::AddToPropertiesTemplate(
568 569
    LocalIsolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
570
template void ClassBoilerplate::AddToPropertiesTemplate(
571
    Isolate* isolate, Handle<SwissNameDictionary> dictionary, Handle<Name> name,
572
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
573

574
template <typename IsolateT>
575
void ClassBoilerplate::AddToElementsTemplate(
576
    IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
577
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) {
578 579 580
  AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
                          value);
}
581 582 583 584
template void ClassBoilerplate::AddToElementsTemplate(
    Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
template void ClassBoilerplate::AddToElementsTemplate(
585 586
    LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
587

588
template <typename IsolateT>
589
Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
590
    IsolateT* isolate, ClassLiteral* expr) {
591 592 593
  // Create a non-caching handle scope to ensure that the temporary handle used
  // by ObjectDescriptor for passing Smis around does not corrupt handle cache
  // in CanonicalHandleScope.
594
  typename IsolateT::HandleScopeType scope(isolate);
595
  auto* factory = isolate->factory();
596 597
  ObjectDescriptor<IsolateT> static_desc(kMinimumClassPropertiesCount);
  ObjectDescriptor<IsolateT> instance_desc(kMinimumPrototypePropertiesCount);
598

599 600
  for (int i = 0; i < expr->public_members()->length(); i++) {
    ClassLiteral::Property* property = expr->public_members()->at(i);
601
    ObjectDescriptor<IsolateT>& desc =
602 603
        property->is_static() ? static_desc : instance_desc;
    if (property->is_computed_name()) {
604 605 606
      if (property->kind() != ClassLiteral::Property::FIELD) {
        desc.IncComputedCount();
      }
607 608 609 610 611 612 613 614 615 616 617 618
    } else {
      if (property->key()->AsLiteral()->IsPropertyName()) {
        desc.IncPropertiesCount();
      } else {
        desc.IncElementsCount();
      }
    }
  }

  //
  // Initialize class object template.
  //
619
  static_desc.CreateTemplates(isolate);
620 621 622 623 624
  STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
  {
    // Add length_accessor.
    PropertyAttributes attribs =
        static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
625
    static_desc.AddConstant(isolate, factory->length_string(),
626 627 628 629 630 631
                            factory->function_length_accessor(), attribs);
  }
  {
    // Add prototype_accessor.
    PropertyAttributes attribs =
        static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
632
    static_desc.AddConstant(isolate, factory->prototype_string(),
633 634 635
                            factory->function_prototype_accessor(), attribs);
  }
  {
636 637
    Handle<ClassPositions> class_positions = factory->NewClassPositions(
        expr->start_position(), expr->end_position());
638 639
    static_desc.AddConstant(isolate, factory->class_positions_symbol(),
                            class_positions, DONT_ENUM);
640 641 642 643 644
  }

  //
  // Initialize prototype object template.
  //
645
  instance_desc.CreateTemplates(isolate);
646 647 648
  {
    Handle<Object> value(
        Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
649 650
    instance_desc.AddConstant(isolate, factory->constructor_string(), value,
                              DONT_ENUM);
651 652 653 654 655 656 657
  }

  //
  // Fill in class boilerplate.
  //
  int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;

658 659
  for (int i = 0; i < expr->public_members()->length(); i++) {
    ClassLiteral::Property* property = expr->public_members()->at(i);
660 661 662 663 664 665 666 667 668 669 670
    ClassBoilerplate::ValueKind value_kind;
    switch (property->kind()) {
      case ClassLiteral::Property::METHOD:
        value_kind = ClassBoilerplate::kData;
        break;
      case ClassLiteral::Property::GETTER:
        value_kind = ClassBoilerplate::kGetter;
        break;
      case ClassLiteral::Property::SETTER:
        value_kind = ClassBoilerplate::kSetter;
        break;
671 672
      case ClassLiteral::Property::FIELD:
        DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
673 674 675 676 677 678
        if (property->is_computed_name()) {
          ++dynamic_argument_index;
        }
        continue;
    }

679
    ObjectDescriptor<IsolateT>& desc =
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
        property->is_static() ? static_desc : instance_desc;
    if (property->is_computed_name()) {
      int computed_name_index = dynamic_argument_index;
      dynamic_argument_index += 2;  // Computed name and value indices.
      desc.AddComputed(value_kind, computed_name_index);
      continue;
    }
    int value_index = dynamic_argument_index++;

    Literal* key_literal = property->key()->AsLiteral();
    uint32_t index;
    if (key_literal->AsArrayIndex(&index)) {
      desc.AddIndexedProperty(isolate, index, value_kind, value_index);

    } else {
695
      Handle<String> name = key_literal->AsRawPropertyName()->string();
696 697 698 699 700
      DCHECK(name->IsInternalizedString());
      desc.AddNamedProperty(isolate, name, value_kind, value_index);
    }
  }

701 702 703
  // All classes, even anonymous ones, have a name accessor. If static_desc is
  // in dictionary mode, the name accessor is installed at runtime in
  // DefineClass.
704
  if (!expr->has_name_static_property() &&
705 706 707 708 709 710
      !static_desc.HasDictionaryProperties()) {
    // Set class name accessor if the "name" method was not added yet.
    PropertyAttributes attribs =
        static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
    static_desc.AddConstant(isolate, factory->name_string(),
                            factory->function_name_accessor(), attribs);
711 712 713 714 715
  }

  static_desc.Finalize(isolate);
  instance_desc.Finalize(isolate);

716
  Handle<ClassBoilerplate> class_boilerplate = Handle<ClassBoilerplate>::cast(
717
      factory->NewFixedArray(kBoilerplateLength, AllocationType::kOld));
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734

  class_boilerplate->set_arguments_count(dynamic_argument_index);

  class_boilerplate->set_static_properties_template(
      *static_desc.properties_template());
  class_boilerplate->set_static_elements_template(
      *static_desc.elements_template());
  class_boilerplate->set_static_computed_properties(
      *static_desc.computed_properties());

  class_boilerplate->set_instance_properties_template(
      *instance_desc.properties_template());
  class_boilerplate->set_instance_elements_template(
      *instance_desc.elements_template());
  class_boilerplate->set_instance_computed_properties(
      *instance_desc.computed_properties());

735
  return scope.CloseAndEscape(class_boilerplate);
736 737
}

738 739 740
template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
    Isolate* isolate, ClassLiteral* expr);
template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
741
    LocalIsolate* isolate, ClassLiteral* expr);
742

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
  os << " " << ElementsKindToString(elements_kind()) << ", "
     << Brief(constant_elements());
}

void RegExpBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
  // Note: keep boilerplate layout synced with JSRegExp layout.
  STATIC_ASSERT(JSRegExp::kDataOffset == JSObject::kHeaderSize);
  STATIC_ASSERT(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
  STATIC_ASSERT(JSRegExp::kFlagsOffset ==
                JSRegExp::kSourceOffset + kTaggedSize);
  STATIC_ASSERT(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
  os << " " << Brief(data()) << ", " << Brief(source()) << ", " << flags();
}

758 759
}  // namespace internal
}  // namespace v8