literal-objects.cc 31.1 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 28 29 30 31
// The enumeration order index in the property details is unused if they are
// stored in a OrderedNameDictionary or NumberDictionary (because they handle
// 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 LocalIsolate>
41
void AddToDescriptorArrayTemplate(
42
    LocalIsolate* 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 LocalIsolate>
94
Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
95
    LocalIsolate* 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 103 104 105 106 107 108 109 110 111 112
template <typename LocalIsolate>
Handle<OrderedNameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
    LocalIsolate* isolate, Handle<OrderedNameDictionary> dictionary,
    Handle<Name> name, Handle<Object> value, PropertyDetails details,
    InternalIndex* entry_out = nullptr) {
  // OrderedNameDictionary does not maintain the enumeration order in property
  // details, so it's a normal Add().
  return OrderedNameDictionary::Add(isolate, dictionary, name, value, details)
      .ToHandleChecked();
}

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

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

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.
142 143 144
  return value_index +
         std::max({ClassBoilerplate::kMinimumClassPropertiesCount,
                   ClassBoilerplate::kMinimumPrototypePropertiesCount});
145 146
}

147 148
constexpr int kAccessorNotDefined = -1;

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

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

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

167
  if (entry.is_not_found()) {
168 169
    // Entry not found, add new one.
    int enum_order =
170 171 172
        Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
            ? kDummyEnumerationIndex
            : ComputeEnumerationIndex(key_index);
173 174 175
    Handle<Object> value_handle;
    PropertyDetails details(
        value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
176
        PropertyDetails::kConstIfDictConstnessTracking, enum_order);
177 178 179 180 181 182 183 184 185 186 187 188 189
    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(
190
        isolate, dictionary, key, value_handle, details, &entry);
191 192 193 194 195 196 197 198 199
    // 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.
200 201 202 203 204 205 206 207 208
    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);

209
    Object existing_value = dictionary->ValueAt(entry);
210 211
    if (value_kind == ClassBoilerplate::kData) {
      // Computed value is a normal method.
212
      if (existing_value.IsAccessorPair()) {
213
        AccessorPair current_pair = AccessorPair::cast(existing_value);
214 215

        int existing_getter_index =
216
            GetExistingValueIndex(current_pair.getter());
217
        int existing_setter_index =
218
            GetExistingValueIndex(current_pair.setter());
219
        // At least one of the accessors must already be defined.
220
        STATIC_ASSERT(kAccessorNotDefined < 0);
221
        DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
222 223
        if (existing_getter_index < key_index &&
            existing_setter_index < key_index) {
224 225 226
          // 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.
227 228 229
          PropertyDetails details(
              kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
230
          dictionary->DetailsAtPut(entry, details);
231 232
          dictionary->ValueAtPut(entry, value);

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
        } 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());

251
        } else {
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
          // 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);
272 273
          }
        }
274 275 276
      } else {  // if (existing_value.IsAccessorPair()) ends here
        DCHECK(value_kind == ClassBoilerplate::kData);

277 278 279 280
        DCHECK_IMPLIES(!existing_value.IsSmi(),
                       existing_value.IsAccessorInfo());
        DCHECK_IMPLIES(!existing_value.IsSmi(),
                       AccessorInfo::cast(existing_value).name() ==
281
                           *isolate->factory()->length_string());
282
        if (!existing_value.IsSmi() || Smi::ToInt(existing_value) < key_index) {
283 284
          // Overwrite existing value because it was defined before the computed
          // one (AccessorInfo "length" property is always defined before).
285 286 287
          PropertyDetails details(
              kData, DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
288
          dictionary->DetailsAtPut(entry, details);
289
          dictionary->ValueAtPut(entry, value);
290 291 292 293 294 295 296
        } 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.
297 298 299 300
            PropertyDetails details(
                kData, DONT_ENUM,
                PropertyDetails::kConstIfDictConstnessTracking,
                enum_order_computed);
301 302 303

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

        int existing_component_index =
315
            GetExistingValueIndex(current_pair.get(component));
316
        if (existing_component_index < key_index) {
317
          current_pair.set(component, value);
318 319 320 321 322 323 324 325 326
        } 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.

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

      } else {
336 337 338 339 340 341 342 343
        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);
344 345 346 347
          PropertyDetails details(
              kAccessor, DONT_ENUM,
              PropertyDetails::kConstIfDictConstnessTracking,
              enum_order_existing);
348 349 350 351 352 353 354 355 356 357 358
          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.
359 360 361 362
            PropertyDetails details(
                kData, DONT_ENUM,
                PropertyDetails::kConstIfDictConstnessTracking,
                enum_order_computed);
363 364 365 366

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

}  // namespace

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

383 384 385
  explicit ObjectDescriptor(int property_slack)
      : property_slack_(property_slack) {}

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

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

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

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

405 406
  void CreateTemplates(LocalIsolate* isolate) {
    auto* factory = isolate->factory();
407
    descriptor_array_template_ = factory->empty_descriptor_array();
408 409 410 411 412 413
    if (V8_DICT_MODE_PROTOTYPES_BOOL) {
      properties_dictionary_template_ =
          factory->empty_ordered_property_dictionary();
    } else {
      properties_dictionary_template_ = factory->empty_property_dictionary();
    }
414
    if (property_count_ || computed_count_ || property_slack_) {
415
      if (HasDictionaryProperties()) {
416 417 418 419 420 421 422 423 424 425 426
        int need_space_for =
            property_count_ + computed_count_ + property_slack_;
        if (V8_DICT_MODE_PROTOTYPES_BOOL) {
          properties_dictionary_template_ =
              OrderedNameDictionary::Allocate(isolate, need_space_for,
                                              AllocationType::kOld)
                  .ToHandleChecked();
        } else {
          properties_dictionary_template_ = NameDictionary::New(
              isolate, need_space_for, AllocationType::kOld);
        }
427
      } else {
428
        descriptor_array_template_ = DescriptorArray::Allocate(
429 430
            isolate, 0, property_count_ + property_slack_,
            AllocationType::kOld);
431 432 433 434
      }
    }
    elements_dictionary_template_ =
        element_count_ || computed_count_
435 436
            ? NumberDictionary::New(isolate, element_count_ + computed_count_,
                                    AllocationType::kOld)
437 438
            : factory->empty_slow_element_dictionary();

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

444
    temp_handle_ = handle(Smi::zero(), isolate);
445 446
  }

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

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

497
  void AddIndexedProperty(LocalIsolate* isolate, uint32_t element,
498 499
                          ClassBoilerplate::ValueKind value_kind,
                          int value_index) {
500
    Smi value = Smi::FromInt(value_index);
501 502 503 504 505 506 507 508 509 510 511 512 513
    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) {
514 515 516
    int current_index = ComputeEnumerationIndex(value_index);
    DCHECK_LE(next_enumeration_index_, current_index);
    next_enumeration_index_ = current_index + 1;
517 518
  }

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

 private:
532 533 534 535 536 537 538 539
  Handle<NameDictionary> properties_dictionary_template() const {
    return Handle<NameDictionary>::cast(properties_dictionary_template_);
  }

  Handle<OrderedNameDictionary> properties_ordered_dictionary_template() const {
    return Handle<OrderedNameDictionary>::cast(properties_dictionary_template_);
  }

540
  const int property_slack_;
541 542 543 544 545 546 547
  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_;
548 549 550 551

  // Is either a NameDictionary or OrderedNameDictionary.
  Handle<HeapObject> properties_dictionary_template_;

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

558
template <typename LocalIsolate, typename PropertyDict>
559
void ClassBoilerplate::AddToPropertiesTemplate(
560
    LocalIsolate* isolate, Handle<PropertyDict> dictionary, Handle<Name> name,
561
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) {
562 563 564
  AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
                          value);
}
565 566 567 568
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(
569 570
    LocalIsolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
571 572 573 574
template void ClassBoilerplate::AddToPropertiesTemplate(
    Isolate* isolate, Handle<OrderedNameDictionary> dictionary,
    Handle<Name> name, int key_index, ClassBoilerplate::ValueKind value_kind,
    Smi value);
575

576
template <typename LocalIsolate>
577
void ClassBoilerplate::AddToElementsTemplate(
578
    LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
579
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value) {
580 581 582
  AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
                          value);
}
583 584 585 586
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(
587 588
    LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
    int key_index, ClassBoilerplate::ValueKind value_kind, Smi value);
589

590
template <typename LocalIsolate>
591
Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
592
    LocalIsolate* isolate, ClassLiteral* expr) {
593 594 595
  // 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.
596 597 598 599 600
  typename LocalIsolate::HandleScopeType scope(isolate);
  auto* factory = isolate->factory();
  ObjectDescriptor<LocalIsolate> static_desc(kMinimumClassPropertiesCount);
  ObjectDescriptor<LocalIsolate> instance_desc(
      kMinimumPrototypePropertiesCount);
601

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

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

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

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

661 662
  for (int i = 0; i < expr->public_members()->length(); i++) {
    ClassLiteral::Property* property = expr->public_members()->at(i);
663 664 665 666 667 668 669 670 671 672 673
    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;
674 675
      case ClassLiteral::Property::FIELD:
        DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
676 677 678 679 680 681
        if (property->is_computed_name()) {
          ++dynamic_argument_index;
        }
        continue;
    }

682
    ObjectDescriptor<LocalIsolate>& desc =
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
        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 {
698
      Handle<String> name = key_literal->AsRawPropertyName()->string();
699 700 701 702 703
      DCHECK(name->IsInternalizedString());
      desc.AddNamedProperty(isolate, name, value_kind, value_index);
    }
  }

704 705 706
  // 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.
707
  if (!expr->has_name_static_property() &&
708 709 710 711 712 713
      !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);
714 715 716 717 718
  }

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

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

  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());

738
  return scope.CloseAndEscape(class_boilerplate);
739 740
}

741 742 743
template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
    Isolate* isolate, ClassLiteral* expr);
template Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
744
    LocalIsolate* isolate, ClassLiteral* expr);
745

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
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();
}

761 762
}  // namespace internal
}  // namespace v8