runtime-literals.cc 26.5 KB
Newer Older
1 2 3 4
// Copyright 2014 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.

5
#include "src/ast/ast.h"
6
#include "src/common/globals.h"
7 8
#include "src/execution/arguments-inl.h"
#include "src/execution/isolate-inl.h"
9
#include "src/logging/counters.h"
10
#include "src/objects/allocation-site-scopes-inl.h"
11
#include "src/objects/hash-table-inl.h"
12
#include "src/objects/heap-number-inl.h"
13
#include "src/objects/heap-object-inl.h"
14
#include "src/objects/js-regexp-inl.h"
15
#include "src/objects/literal-objects-inl.h"
16
#include "src/runtime/runtime-utils.h"
17 18 19 20 21
#include "src/runtime/runtime.h"

namespace v8 {
namespace internal {

22
namespace {
23

24
bool IsUninitializedLiteralSite(Object literal_site) {
25
  return literal_site == Smi::zero();
26 27
}

28
bool HasBoilerplate(Handle<Object> literal_site) {
29 30
  return !literal_site->IsSmi();
}
31

32 33
void PreInitializeLiteralSite(Handle<FeedbackVector> vector,
                              FeedbackSlot slot) {
34
  vector->SynchronizedSet(slot, Smi::FromInt(1));
35 36
}

37 38 39
template <class ContextObject>
class JSObjectWalkVisitor {
 public:
40 41
  explicit JSObjectWalkVisitor(ContextObject* site_context)
      : site_context_(site_context) {}
42

43 44
  V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> StructureWalk(
      Handle<JSObject> object);
45 46

 protected:
47
  V8_WARN_UNUSED_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
48
      Handle<JSObject> object, Handle<JSObject> value) {
49 50 51 52 53
    // Dont create allocation sites for nested object literals
    if (!value->IsJSArray()) {
      return StructureWalk(value);
    }

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    Handle<AllocationSite> current_site = site_context()->EnterNewScope();
    MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
    site_context()->ExitScope(current_site, value);
    return copy_of_value;
  }

  inline ContextObject* site_context() { return site_context_; }
  inline Isolate* isolate() { return site_context()->isolate(); }

 private:
  ContextObject* site_context_;
};

template <class ContextObject>
MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
    Handle<JSObject> object) {
  Isolate* isolate = this->isolate();
  bool copying = ContextObject::kCopying;

73
  {
74 75 76 77 78 79 80 81
    StackLimitCheck check(isolate);

    if (check.HasOverflowed()) {
      isolate->StackOverflow();
      return MaybeHandle<JSObject>();
    }
  }

82
  if (object->map(isolate).is_deprecated()) {
83 84
    base::SharedMutexGuard<base::kExclusive> mutex_guard(
        isolate->boilerplate_migration_access());
85
    JSObject::MigrateInstance(isolate, object);
86 87 88 89 90
  }

  Handle<JSObject> copy;
  if (copying) {
    // JSFunction objects are not allowed to be in normal boilerplates at all.
91
    DCHECK(!object->IsJSFunction(isolate));
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    Handle<AllocationSite> site_to_pass;
    if (site_context()->ShouldCreateMemento(object)) {
      site_to_pass = site_context()->current();
    }
    copy = isolate->factory()->CopyJSObjectWithAllocationSite(object,
                                                              site_to_pass);
  } else {
    copy = object;
  }

  DCHECK(copying || copy.is_identical_to(object));

  HandleScope scope(isolate);

  // Deep copy own properties. Arrays only have 1 property "length".
107 108 109
  if (!copy->IsJSArray(isolate)) {
    if (copy->HasFastProperties(isolate)) {
      Handle<DescriptorArray> descriptors(
110
          copy->map(isolate).instance_descriptors(isolate), isolate);
111
      for (InternalIndex i : copy->map(isolate).IterateOwnDescriptors()) {
112
        PropertyDetails details = descriptors->GetDetails(i);
113
        DCHECK_EQ(PropertyLocation::kField, details.location());
114
        DCHECK_EQ(PropertyKind::kData, details.kind());
115 116 117
        FieldIndex index = FieldIndex::ForPropertyIndex(
            copy->map(isolate), details.field_index(),
            details.representation());
118 119
        Object raw = copy->RawFastPropertyAt(isolate, index);
        if (raw.IsJSObject(isolate)) {
120 121 122 123
          Handle<JSObject> value(JSObject::cast(raw), isolate);
          ASSIGN_RETURN_ON_EXCEPTION(
              isolate, value, VisitElementOrProperty(copy, value), JSObject);
          if (copying) copy->FastPropertyAtPut(index, *value);
124
        } else if (copying && details.representation().IsDouble()) {
125 126
          uint64_t double_value =
              HeapNumber::cast(raw).value_as_bits(kRelaxedLoad);
127
          auto value = isolate->factory()->NewHeapNumberFromBits(double_value);
128 129 130 131
          copy->FastPropertyAtPut(index, *value);
        }
      }
    } else {
132
      if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
133 134
        Handle<SwissNameDictionary> dict(
            copy->property_dictionary_swiss(isolate), isolate);
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        for (InternalIndex i : dict->IterateEntries()) {
          Object raw = dict->ValueAt(i);
          if (!raw.IsJSObject(isolate)) continue;
          DCHECK(dict->KeyAt(i).IsName());
          Handle<JSObject> value(JSObject::cast(raw), isolate);
          ASSIGN_RETURN_ON_EXCEPTION(
              isolate, value, VisitElementOrProperty(copy, value), JSObject);
          if (copying) dict->ValueAtPut(i, *value);
        }
      } else {
        Handle<NameDictionary> dict(copy->property_dictionary(isolate),
                                    isolate);
        for (InternalIndex i : dict->IterateEntries()) {
          Object raw = dict->ValueAt(isolate, i);
          if (!raw.IsJSObject(isolate)) continue;
          DCHECK(dict->KeyAt(isolate, i).IsName());
          Handle<JSObject> value(JSObject::cast(raw), isolate);
          ASSIGN_RETURN_ON_EXCEPTION(
              isolate, value, VisitElementOrProperty(copy, value), JSObject);
          if (copying) dict->ValueAtPut(i, *value);
        }
156 157 158 159
      }
    }

    // Assume non-arrays don't end up having elements.
160
    if (copy->elements(isolate).length() == 0) return copy;
161 162 163
  }

  // Deep copy own elements.
164
  switch (copy->GetElementsKind(isolate)) {
165
    case PACKED_ELEMENTS:
166 167
    case PACKED_FROZEN_ELEMENTS:
    case PACKED_SEALED_ELEMENTS:
168
    case PACKED_NONEXTENSIBLE_ELEMENTS:
169 170
    case HOLEY_FROZEN_ELEMENTS:
    case HOLEY_SEALED_ELEMENTS:
171
    case HOLEY_NONEXTENSIBLE_ELEMENTS:
172
    case HOLEY_ELEMENTS: {
173 174 175 176
      Handle<FixedArray> elements(FixedArray::cast(copy->elements(isolate)),
                                  isolate);
      if (elements->map(isolate) ==
          ReadOnlyRoots(isolate).fixed_cow_array_map()) {
177 178
#ifdef DEBUG
        for (int i = 0; i < elements->length(); i++) {
179
          DCHECK(!elements->get(i).IsJSObject());
180 181 182 183
        }
#endif
      } else {
        for (int i = 0; i < elements->length(); i++) {
184 185
          Object raw = elements->get(isolate, i);
          if (!raw.IsJSObject(isolate)) continue;
186 187 188 189 190 191 192 193 194
          Handle<JSObject> value(JSObject::cast(raw), isolate);
          ASSIGN_RETURN_ON_EXCEPTION(
              isolate, value, VisitElementOrProperty(copy, value), JSObject);
          if (copying) elements->set(i, *value);
        }
      }
      break;
    }
    case DICTIONARY_ELEMENTS: {
195 196
      Handle<NumberDictionary> element_dictionary(
          copy->element_dictionary(isolate), isolate);
197
      for (InternalIndex i : element_dictionary->IterateEntries()) {
198 199
        Object raw = element_dictionary->ValueAt(isolate, i);
        if (!raw.IsJSObject(isolate)) continue;
200 201 202 203 204 205 206 207 208 209 210 211 212
        Handle<JSObject> value(JSObject::cast(raw), isolate);
        ASSIGN_RETURN_ON_EXCEPTION(
            isolate, value, VisitElementOrProperty(copy, value), JSObject);
        if (copying) element_dictionary->ValueAtPut(i, *value);
      }
      break;
    }
    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
      UNIMPLEMENTED();
      break;
    case FAST_STRING_WRAPPER_ELEMENTS:
    case SLOW_STRING_WRAPPER_ELEMENTS:
213
    case WASM_ARRAY_ELEMENTS:
214 215
      UNREACHABLE();

216
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
217 218

      TYPED_ARRAYS(TYPED_ARRAY_CASE)
219
      RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)
220 221 222 223
#undef TYPED_ARRAY_CASE
      // Typed elements cannot be created using an object literal.
      UNREACHABLE();

224 225 226 227
    case PACKED_SMI_ELEMENTS:
    case HOLEY_SMI_ELEMENTS:
    case PACKED_DOUBLE_ELEMENTS:
    case HOLEY_DOUBLE_ELEMENTS:
228 229 230 231 232 233 234 235
    case NO_ELEMENTS:
      // No contained objects, nothing to do.
      break;
  }

  return copy;
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
class DeprecationUpdateContext {
 public:
  explicit DeprecationUpdateContext(Isolate* isolate) { isolate_ = isolate; }
  Isolate* isolate() { return isolate_; }
  bool ShouldCreateMemento(Handle<JSObject> object) { return false; }
  inline void ExitScope(Handle<AllocationSite> scope_site,
                        Handle<JSObject> object) {}
  Handle<AllocationSite> EnterNewScope() { return Handle<AllocationSite>(); }
  Handle<AllocationSite> current() {
    UNREACHABLE();
  }

  static const bool kCopying = false;

 private:
  Isolate* isolate_;
};

254 255 256 257 258 259 260 261 262 263 264 265
// AllocationSiteCreationContext aids in the creation of AllocationSites to
// accompany object literals.
class AllocationSiteCreationContext : public AllocationSiteContext {
 public:
  explicit AllocationSiteCreationContext(Isolate* isolate)
      : AllocationSiteContext(isolate) {}

  Handle<AllocationSite> EnterNewScope() {
    Handle<AllocationSite> scope_site;
    if (top().is_null()) {
      // We are creating the top level AllocationSite as opposed to a nested
      // AllocationSite.
266
      InitializeTraversal(isolate()->factory()->NewAllocationSite(true));
267 268
      scope_site = Handle<AllocationSite>(*top(), isolate());
      if (FLAG_trace_creation_allocation_sites) {
269
        PrintF("*** Creating top level %s AllocationSite %p\n", "Fat",
270
               reinterpret_cast<void*>(scope_site->ptr()));
271 272 273
      }
    } else {
      DCHECK(!current().is_null());
274
      scope_site = isolate()->factory()->NewAllocationSite(false);
275
      if (FLAG_trace_creation_allocation_sites) {
276 277 278 279
        PrintF(
            "*** Creating nested %s AllocationSite (top, current, new) (%p, "
            "%p, "
            "%p)\n",
280 281 282
            "Slim", reinterpret_cast<void*>(top()->ptr()),
            reinterpret_cast<void*>(current()->ptr()),
            reinterpret_cast<void*>(scope_site->ptr()));
283 284 285 286 287 288 289 290 291
      }
      current()->set_nested_site(*scope_site);
      update_current_site(*scope_site);
    }
    DCHECK(!scope_site.is_null());
    return scope_site;
  }
  void ExitScope(Handle<AllocationSite> scope_site, Handle<JSObject> object) {
    if (object.is_null()) return;
292
    scope_site->set_boilerplate(*object, kReleaseStore);
293 294 295 296 297
    if (FLAG_trace_creation_allocation_sites) {
      bool top_level =
          !scope_site.is_null() && top().is_identical_to(scope_site);
      if (top_level) {
        PrintF("*** Setting AllocationSite %p transition_info %p\n",
298 299
               reinterpret_cast<void*>(scope_site->ptr()),
               reinterpret_cast<void*>(object->ptr()));
300
      } else {
301
        PrintF("*** Setting AllocationSite (%p, %p) transition_info %p\n",
302 303 304
               reinterpret_cast<void*>(top()->ptr()),
               reinterpret_cast<void*>(scope_site->ptr()),
               reinterpret_cast<void*>(object->ptr()));
305 306 307 308 309 310
      }
    }
  }
  static const bool kCopying = false;
};

311 312
MaybeHandle<JSObject> DeepWalk(Handle<JSObject> object,
                               DeprecationUpdateContext* site_context) {
313
  JSObjectWalkVisitor<DeprecationUpdateContext> v(site_context);
314 315 316 317 318 319
  MaybeHandle<JSObject> result = v.StructureWalk(object);
  Handle<JSObject> for_assert;
  DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
  return result;
}

320 321
MaybeHandle<JSObject> DeepWalk(Handle<JSObject> object,
                               AllocationSiteCreationContext* site_context) {
322
  JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context);
323 324 325 326 327 328 329
  MaybeHandle<JSObject> result = v.StructureWalk(object);
  Handle<JSObject> for_assert;
  DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
  return result;
}

MaybeHandle<JSObject> DeepCopy(Handle<JSObject> object,
330 331
                               AllocationSiteUsageContext* site_context) {
  JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context);
332 333 334 335 336 337
  MaybeHandle<JSObject> copy = v.StructureWalk(object);
  Handle<JSObject> for_assert;
  DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
  return copy;
}

338 339 340 341 342 343 344 345 346 347
Handle<JSObject> CreateObjectLiteral(
    Isolate* isolate,
    Handle<ObjectBoilerplateDescription> object_boilerplate_description,
    int flags, AllocationType allocation);

Handle<JSObject> CreateArrayLiteral(
    Isolate* isolate,
    Handle<ArrayBoilerplateDescription> array_boilerplate_description,
    AllocationType allocation);

348
struct ObjectLiteralHelper {
349 350 351
  static inline Handle<JSObject> Create(Isolate* isolate,
                                        Handle<HeapObject> description,
                                        int flags, AllocationType allocation) {
352 353
    Handle<ObjectBoilerplateDescription> object_boilerplate_description =
        Handle<ObjectBoilerplateDescription>::cast(description);
354 355
    return CreateObjectLiteral(isolate, object_boilerplate_description, flags,
                               allocation);
356
  }
357 358
};

359
struct ArrayLiteralHelper {
360 361 362 363
  static inline Handle<JSObject> Create(Isolate* isolate,
                                        Handle<HeapObject> description,
                                        int flags_not_used,
                                        AllocationType allocation) {
364 365
    Handle<ArrayBoilerplateDescription> array_boilerplate_description =
        Handle<ArrayBoilerplateDescription>::cast(description);
366 367 368 369
    return CreateArrayLiteral(isolate, array_boilerplate_description,
                              allocation);
  }
};
370

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
Handle<JSObject> CreateObjectLiteral(
    Isolate* isolate,
    Handle<ObjectBoilerplateDescription> object_boilerplate_description,
    int flags, AllocationType allocation) {
  Handle<NativeContext> native_context = isolate->native_context();
  bool use_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
  bool has_null_prototype = (flags & ObjectLiteral::kHasNullPrototype) != 0;

  // In case we have function literals, we want the object to be in
  // slow properties mode for now. We don't go in the map cache because
  // maps with constant functions can't be shared if the functions are
  // not the same (which is the common case).
  int number_of_properties =
      object_boilerplate_description->backing_store_size();

  // Ignoring number_of_properties for force dictionary map with
  // __proto__:null.
  Handle<Map> map =
      has_null_prototype
          ? handle(native_context->slow_object_with_null_prototype_map(),
                   isolate)
          : isolate->factory()->ObjectLiteralMapFromCache(native_context,
                                                          number_of_properties);

  Handle<JSObject> boilerplate =
      isolate->factory()->NewFastOrSlowJSObjectFromMap(
          map, number_of_properties, allocation);

  // Normalize the elements of the boilerplate to save space if needed.
  if (!use_fast_elements) JSObject::NormalizeElements(boilerplate);

  // Add the constant properties to the boilerplate.
  int length = object_boilerplate_description->size();
  // TODO(verwaest): Support tracking representations in the boilerplate.
  for (int index = 0; index < length; index++) {
406 407 408 409 410 411 412
    Handle<Object> key(object_boilerplate_description->name(isolate, index),
                       isolate);
    Handle<Object> value(object_boilerplate_description->value(isolate, index),
                         isolate);

    if (value->IsHeapObject()) {
      if (HeapObject::cast(*value).IsArrayBoilerplateDescription(isolate)) {
413
        Handle<ArrayBoilerplateDescription> array_boilerplate =
414
            Handle<ArrayBoilerplateDescription>::cast(value);
415
        value = CreateArrayLiteral(isolate, array_boilerplate, allocation);
416 417 418

      } else if (HeapObject::cast(*value).IsObjectBoilerplateDescription(
                     isolate)) {
419
        Handle<ObjectBoilerplateDescription> object_boilerplate =
420
            Handle<ObjectBoilerplateDescription>::cast(value);
421 422
        value = CreateObjectLiteral(isolate, object_boilerplate,
                                    object_boilerplate->flags(), allocation);
423
      }
424
    }
425

426 427 428 429
    uint32_t element_index = 0;
    if (key->ToArrayIndex(&element_index)) {
      // Array index (uint32).
      if (value->IsUninitialized(isolate)) {
430
        value = handle(Smi::zero(), isolate);
431
      }
432 433 434
      JSObject::SetOwnElementIgnoreAttributes(boilerplate, element_index, value,
                                              NONE)
          .Check();
435 436 437
    } else {
      Handle<String> name = Handle<String>::cast(key);
      DCHECK(!name->AsArrayIndex(&element_index));
438 439
      JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, value, NONE)
          .Check();
440 441
    }
  }
442

443 444 445 446 447 448 449 450
  if (map->is_dictionary_map() && !has_null_prototype) {
    // TODO(cbruni): avoid making the boilerplate fast again, the clone stub
    // supports dict-mode objects directly.
    JSObject::MigrateSlowToFast(
        boilerplate, boilerplate->map().UnusedPropertyFields(), "FastLiteral");
  }
  return boilerplate;
}
451

452 453 454 455 456 457 458 459
Handle<JSObject> CreateArrayLiteral(
    Isolate* isolate,
    Handle<ArrayBoilerplateDescription> array_boilerplate_description,
    AllocationType allocation) {
  ElementsKind constant_elements_kind =
      array_boilerplate_description->elements_kind();

  Handle<FixedArrayBase> constant_elements_values(
460
      array_boilerplate_description->constant_elements(isolate), isolate);
461 462 463 464 465 466 467 468

  // Create the JSArray.
  Handle<FixedArrayBase> copied_elements_values;
  if (IsDoubleElementsKind(constant_elements_kind)) {
    copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
        Handle<FixedDoubleArray>::cast(constant_elements_values));
  } else {
    DCHECK(IsSmiOrObjectElementsKind(constant_elements_kind));
469
    const bool is_cow = (constant_elements_values->map(isolate) ==
470 471 472 473
                         ReadOnlyRoots(isolate).fixed_cow_array_map());
    if (is_cow) {
      copied_elements_values = constant_elements_values;
      if (DEBUG_BOOL) {
474 475 476
        Handle<FixedArray> fixed_array_values =
            Handle<FixedArray>::cast(copied_elements_values);
        for (int i = 0; i < fixed_array_values->length(); i++) {
477
          DCHECK(!fixed_array_values->get(i).IsFixedArray());
478 479
        }
      }
480 481 482 483 484 485
    } else {
      Handle<FixedArray> fixed_array_values =
          Handle<FixedArray>::cast(constant_elements_values);
      Handle<FixedArray> fixed_array_values_copy =
          isolate->factory()->CopyFixedArray(fixed_array_values);
      copied_elements_values = fixed_array_values_copy;
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
      for (int i = 0; i < fixed_array_values->length(); i++) {
        Object value = fixed_array_values_copy->get(isolate, i);
        HeapObject value_heap_object;
        if (value.GetHeapObject(isolate, &value_heap_object)) {
          if (value_heap_object.IsArrayBoilerplateDescription(isolate)) {
            HandleScope sub_scope(isolate);
            Handle<ArrayBoilerplateDescription> boilerplate(
                ArrayBoilerplateDescription::cast(value_heap_object), isolate);
            Handle<JSObject> result =
                CreateArrayLiteral(isolate, boilerplate, allocation);
            fixed_array_values_copy->set(i, *result);

          } else if (value_heap_object.IsObjectBoilerplateDescription(
                         isolate)) {
            HandleScope sub_scope(isolate);
            Handle<ObjectBoilerplateDescription> boilerplate(
                ObjectBoilerplateDescription::cast(value_heap_object), isolate);
            Handle<JSObject> result = CreateObjectLiteral(
                isolate, boilerplate, boilerplate->flags(), allocation);
            fixed_array_values_copy->set(i, *result);
          }
        }
      }
509 510
    }
  }
511 512 513 514
  return isolate->factory()->NewJSArrayWithElements(
      copied_elements_values, constant_elements_kind,
      copied_elements_values->length(), allocation);
}
515

516 517 518
template <typename LiteralHelper>
MaybeHandle<JSObject> CreateLiteralWithoutAllocationSite(
    Isolate* isolate, Handle<HeapObject> description, int flags) {
519 520
  Handle<JSObject> literal = LiteralHelper::Create(isolate, description, flags,
                                                   AllocationType::kYoung);
521 522
  DeprecationUpdateContext update_context(isolate);
  RETURN_ON_EXCEPTION(isolate, DeepWalk(literal, &update_context), JSObject);
523 524 525 526
  return literal;
}

template <typename LiteralHelper>
527
MaybeHandle<JSObject> CreateLiteral(Isolate* isolate,
528
                                    MaybeHandle<FeedbackVector> maybe_vector,
529 530
                                    int literals_index,
                                    Handle<HeapObject> description, int flags) {
531 532 533 534 535 536
  if (maybe_vector.is_null()) {
    return CreateLiteralWithoutAllocationSite<LiteralHelper>(
        isolate, description, flags);
  }

  Handle<FeedbackVector> vector = maybe_vector.ToHandleChecked();
537
  FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index));
538
  CHECK(literals_slot.ToInt() < vector->length());
539 540
  Handle<Object> literal_site(vector->Get(literals_slot)->cast<Object>(),
                              isolate);
541 542
  Handle<AllocationSite> site;
  Handle<JSObject> boilerplate;
543

544
  if (HasBoilerplate(literal_site)) {
545
    site = Handle<AllocationSite>::cast(literal_site);
546
    boilerplate = Handle<JSObject>(site->boilerplate(), isolate);
547
  } else {
548 549 550 551
    // Eagerly create AllocationSites for literals that contain an Array.
    bool needs_initial_allocation_site =
        (flags & AggregateLiteral::kNeedsInitialAllocationSite) != 0;
    if (!needs_initial_allocation_site &&
552
        IsUninitializedLiteralSite(*literal_site)) {
553
      PreInitializeLiteralSite(vector, literals_slot);
554 555
      return CreateLiteralWithoutAllocationSite<LiteralHelper>(
          isolate, description, flags);
556
    } else {
557 558
      boilerplate = LiteralHelper::Create(isolate, description, flags,
                                          AllocationType::kOld);
559
    }
560
    // Install AllocationSite objects.
561 562
    AllocationSiteCreationContext creation_context(isolate);
    site = creation_context.EnterNewScope();
563 564
    RETURN_ON_EXCEPTION(isolate, DeepWalk(boilerplate, &creation_context),
                        JSObject);
565 566
    creation_context.ExitScope(site, boilerplate);

567
    vector->SynchronizedSet(literals_slot, *site);
568 569
  }

570 571 572
  STATIC_ASSERT(static_cast<int>(ObjectLiteral::kDisableMementos) ==
                static_cast<int>(ArrayLiteral::kDisableMementos));
  bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0;
573

574
  // Copy the existing boilerplate.
575 576
  AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
  usage_context.EnterNewScope();
577
  MaybeHandle<JSObject> copy = DeepCopy(boilerplate, &usage_context);
578 579 580
  usage_context.ExitScope(site, boilerplate);
  return copy;
}
581

582
}  // namespace
583

584 585 586
RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
  HandleScope scope(isolate);
  DCHECK_EQ(4, args.length());
587
  CONVERT_ARG_HANDLE_CHECKED(HeapObject, maybe_vector, 0);
588
  CONVERT_TAGGED_INDEX_ARG_CHECKED(literals_index, 1);
589
  CONVERT_ARG_HANDLE_CHECKED(ObjectBoilerplateDescription, description, 2);
590
  CONVERT_SMI_ARG_CHECKED(flags, 3);
591 592
  Handle<FeedbackVector> vector;
  if (maybe_vector->IsFeedbackVector()) {
593
    vector = Handle<FeedbackVector>::cast(maybe_vector);
594 595
  } else {
    DCHECK(maybe_vector->IsUndefined());
596
  }
597
  RETURN_RESULT_OR_FAILURE(
598 599 600 601 602 603 604 605 606 607 608 609
      isolate, CreateLiteral<ObjectLiteralHelper>(
                   isolate, vector, literals_index, description, flags));
}

RUNTIME_FUNCTION(Runtime_CreateObjectLiteralWithoutAllocationSite) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(ObjectBoilerplateDescription, description, 0);
  CONVERT_SMI_ARG_CHECKED(flags, 1);
  RETURN_RESULT_OR_FAILURE(
      isolate, CreateLiteralWithoutAllocationSite<ObjectLiteralHelper>(
                   isolate, description, flags));
610
}
611

612 613 614 615 616 617 618 619 620 621
RUNTIME_FUNCTION(Runtime_CreateArrayLiteralWithoutAllocationSite) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(ArrayBoilerplateDescription, description, 0);
  CONVERT_SMI_ARG_CHECKED(flags, 1);
  RETURN_RESULT_OR_FAILURE(
      isolate, CreateLiteralWithoutAllocationSite<ArrayLiteralHelper>(
                   isolate, description, flags));
}

622 623
RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
  HandleScope scope(isolate);
624
  DCHECK_EQ(4, args.length());
625
  CONVERT_ARG_HANDLE_CHECKED(HeapObject, maybe_vector, 0);
626
  CONVERT_TAGGED_INDEX_ARG_CHECKED(literals_index, 1);
627
  CONVERT_ARG_HANDLE_CHECKED(ArrayBoilerplateDescription, elements, 2);
628
  CONVERT_SMI_ARG_CHECKED(flags, 3);
629 630
  Handle<FeedbackVector> vector;
  if (maybe_vector->IsFeedbackVector()) {
631
    vector = Handle<FeedbackVector>::cast(maybe_vector);
632 633
  } else {
    DCHECK(maybe_vector->IsUndefined());
634
  }
635
  RETURN_RESULT_OR_FAILURE(
636 637
      isolate, CreateLiteral<ArrayLiteralHelper>(
                   isolate, vector, literals_index, elements, flags));
638 639
}

640 641 642
RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
  HandleScope scope(isolate);
  DCHECK_EQ(4, args.length());
643
  CONVERT_ARG_HANDLE_CHECKED(HeapObject, maybe_vector, 0);
644
  CONVERT_TAGGED_INDEX_ARG_CHECKED(index, 1);
645 646
  CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
  CONVERT_SMI_ARG_CHECKED(flags, 3);
647

648 649 650 651 652
  if (maybe_vector->IsUndefined()) {
    // We don't have a vector; don't create a boilerplate, simply construct a
    // plain JSRegExp instance and return it.
    RETURN_RESULT_OR_FAILURE(
        isolate, JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
653
  }
654

655
  Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(maybe_vector);
656
  FeedbackSlot literal_slot(FeedbackVector::ToSlot(index));
657 658
  Handle<Object> literal_site(vector->Get(literal_slot)->cast<Object>(),
                              isolate);
659 660 661 662

  // This function must not be called when a boilerplate already exists (if it
  // exists, callers should instead copy the boilerplate into a new JSRegExp
  // instance).
663 664
  CHECK(!HasBoilerplate(literal_site));

665
  Handle<JSRegExp> regexp_instance;
666
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
667
      isolate, regexp_instance,
668
      JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
669 670 671

  // JSRegExp literal sites are initialized in a two-step process:
  // Uninitialized-Preinitialized, and Preinitialized-Initialized.
672 673
  if (IsUninitializedLiteralSite(*literal_site)) {
    PreInitializeLiteralSite(vector, literal_slot);
674
    return *regexp_instance;
675
  }
676 677 678 679 680

  Handle<FixedArray> data(FixedArray::cast(regexp_instance->data()), isolate);
  Handle<String> source(String::cast(regexp_instance->source()), isolate);
  Handle<RegExpBoilerplateDescription> boilerplate =
      isolate->factory()->NewRegExpBoilerplateDescription(
681 682
          data, source,
          Smi::FromInt(static_cast<int>(regexp_instance->flags())));
683

684
  vector->SynchronizedSet(literal_slot, *boilerplate);
685 686 687 688
  DCHECK(HasBoilerplate(
      handle(vector->Get(literal_slot)->cast<Object>(), isolate)));

  return *regexp_instance;
689 690
}

691 692
}  // namespace internal
}  // namespace v8