• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/ast/ast.h"
6 #include "src/common/globals.h"
7 #include "src/execution/arguments-inl.h"
8 #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 #include "src/runtime/runtime.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 namespace {
23 
IsUninitializedLiteralSite(Object literal_site)24 bool IsUninitializedLiteralSite(Object literal_site) {
25   return literal_site == Smi::zero();
26 }
27 
HasBoilerplate(Handle<Object> literal_site)28 bool HasBoilerplate(Handle<Object> literal_site) {
29   return !literal_site->IsSmi();
30 }
31 
PreInitializeLiteralSite(Handle<FeedbackVector> vector,FeedbackSlot slot)32 void PreInitializeLiteralSite(Handle<FeedbackVector> vector,
33                               FeedbackSlot slot) {
34   vector->SynchronizedSet(slot, Smi::FromInt(1));
35 }
36 
37 template <class ContextObject>
38 class JSObjectWalkVisitor {
39  public:
JSObjectWalkVisitor(ContextObject * site_context)40   explicit JSObjectWalkVisitor(ContextObject* site_context)
41       : site_context_(site_context) {}
42 
43   V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> StructureWalk(
44       Handle<JSObject> object);
45 
46  protected:
VisitElementOrProperty(Handle<JSObject> object,Handle<JSObject> value)47   V8_WARN_UNUSED_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
48       Handle<JSObject> object, Handle<JSObject> value) {
49     // Dont create allocation sites for nested object literals
50     if (!value->IsJSArray()) {
51       return StructureWalk(value);
52     }
53 
54     Handle<AllocationSite> current_site = site_context()->EnterNewScope();
55     MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
56     site_context()->ExitScope(current_site, value);
57     return copy_of_value;
58   }
59 
site_context()60   inline ContextObject* site_context() { return site_context_; }
isolate()61   inline Isolate* isolate() { return site_context()->isolate(); }
62 
63  private:
64   ContextObject* site_context_;
65 };
66 
67 template <class ContextObject>
StructureWalk(Handle<JSObject> object)68 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
69     Handle<JSObject> object) {
70   Isolate* isolate = this->isolate();
71   bool copying = ContextObject::kCopying;
72 
73   {
74     StackLimitCheck check(isolate);
75 
76     if (check.HasOverflowed()) {
77       isolate->StackOverflow();
78       return MaybeHandle<JSObject>();
79     }
80   }
81 
82   if (object->map(isolate).is_deprecated()) {
83     base::SharedMutexGuard<base::kExclusive> mutex_guard(
84         isolate->boilerplate_migration_access());
85     JSObject::MigrateInstance(isolate, object);
86   }
87 
88   Handle<JSObject> copy;
89   if (copying) {
90     // JSFunction objects are not allowed to be in normal boilerplates at all.
91     DCHECK(!object->IsJSFunction(isolate));
92     Handle<AllocationSite> site_to_pass;
93     if (site_context()->ShouldCreateMemento(object)) {
94       site_to_pass = site_context()->current();
95     }
96     copy = isolate->factory()->CopyJSObjectWithAllocationSite(object,
97                                                               site_to_pass);
98   } else {
99     copy = object;
100   }
101 
102   DCHECK(copying || copy.is_identical_to(object));
103 
104   HandleScope scope(isolate);
105 
106   // Deep copy own properties. Arrays only have 1 property "length".
107   if (!copy->IsJSArray(isolate)) {
108     if (copy->HasFastProperties(isolate)) {
109       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         FieldIndex index = FieldIndex::ForPropertyIndex(
116             copy->map(isolate), details.field_index(),
117             details.representation());
118         Object raw = copy->RawFastPropertyAt(isolate, index);
119         if (raw.IsJSObject(isolate)) {
120           Handle<JSObject> value(JSObject::cast(raw), isolate);
121           ASSIGN_RETURN_ON_EXCEPTION(
122               isolate, value, VisitElementOrProperty(copy, value), JSObject);
123           if (copying) copy->FastPropertyAtPut(index, *value);
124         } else if (copying && details.representation().IsDouble()) {
125           uint64_t double_value =
126               HeapNumber::cast(raw).value_as_bits(kRelaxedLoad);
127           auto value = isolate->factory()->NewHeapNumberFromBits(double_value);
128           copy->FastPropertyAtPut(index, *value);
129         }
130       }
131     } else {
132       if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
133         Handle<SwissNameDictionary> dict(
134             copy->property_dictionary_swiss(isolate), isolate);
135         for (InternalIndex i : dict->IterateEntries()) {
136           Object raw = dict->ValueAt(i);
137           if (!raw.IsJSObject(isolate)) continue;
138           DCHECK(dict->KeyAt(i).IsName());
139           Handle<JSObject> value(JSObject::cast(raw), isolate);
140           ASSIGN_RETURN_ON_EXCEPTION(
141               isolate, value, VisitElementOrProperty(copy, value), JSObject);
142           if (copying) dict->ValueAtPut(i, *value);
143         }
144       } else {
145         Handle<NameDictionary> dict(copy->property_dictionary(isolate),
146                                     isolate);
147         for (InternalIndex i : dict->IterateEntries()) {
148           Object raw = dict->ValueAt(isolate, i);
149           if (!raw.IsJSObject(isolate)) continue;
150           DCHECK(dict->KeyAt(isolate, i).IsName());
151           Handle<JSObject> value(JSObject::cast(raw), isolate);
152           ASSIGN_RETURN_ON_EXCEPTION(
153               isolate, value, VisitElementOrProperty(copy, value), JSObject);
154           if (copying) dict->ValueAtPut(i, *value);
155         }
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     case PACKED_FROZEN_ELEMENTS:
167     case PACKED_SEALED_ELEMENTS:
168     case PACKED_NONEXTENSIBLE_ELEMENTS:
169     case HOLEY_FROZEN_ELEMENTS:
170     case HOLEY_SEALED_ELEMENTS:
171     case HOLEY_NONEXTENSIBLE_ELEMENTS:
172     case HOLEY_ELEMENTS: {
173       Handle<FixedArray> elements(FixedArray::cast(copy->elements(isolate)),
174                                   isolate);
175       if (elements->map(isolate) ==
176           ReadOnlyRoots(isolate).fixed_cow_array_map()) {
177 #ifdef DEBUG
178         for (int i = 0; i < elements->length(); i++) {
179           DCHECK(!elements->get(i).IsJSObject());
180         }
181 #endif
182       } else {
183         for (int i = 0; i < elements->length(); i++) {
184           Object raw = elements->get(isolate, i);
185           if (!raw.IsJSObject(isolate)) continue;
186           Handle<JSObject> value(JSObject::cast(raw), isolate);
187           ASSIGN_RETURN_ON_EXCEPTION(
188               isolate, value, VisitElementOrProperty(copy, value), JSObject);
189           if (copying) elements->set(i, *value);
190         }
191       }
192       break;
193     }
194     case DICTIONARY_ELEMENTS: {
195       Handle<NumberDictionary> element_dictionary(
196           copy->element_dictionary(isolate), isolate);
197       for (InternalIndex i : element_dictionary->IterateEntries()) {
198         Object raw = element_dictionary->ValueAt(isolate, i);
199         if (!raw.IsJSObject(isolate)) continue;
200         Handle<JSObject> value(JSObject::cast(raw), isolate);
201         ASSIGN_RETURN_ON_EXCEPTION(
202             isolate, value, VisitElementOrProperty(copy, value), JSObject);
203         if (copying) element_dictionary->ValueAtPut(i, *value);
204       }
205       break;
206     }
207     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
208     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
209       UNIMPLEMENTED();
210       break;
211     case FAST_STRING_WRAPPER_ELEMENTS:
212     case SLOW_STRING_WRAPPER_ELEMENTS:
213     case WASM_ARRAY_ELEMENTS:
214       UNREACHABLE();
215 
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 #undef TYPED_ARRAY_CASE
221       // Typed elements cannot be created using an object literal.
222       UNREACHABLE();
223 
224     case PACKED_SMI_ELEMENTS:
225     case HOLEY_SMI_ELEMENTS:
226     case PACKED_DOUBLE_ELEMENTS:
227     case HOLEY_DOUBLE_ELEMENTS:
228     case NO_ELEMENTS:
229       // No contained objects, nothing to do.
230       break;
231   }
232 
233   return copy;
234 }
235 
236 class DeprecationUpdateContext {
237  public:
DeprecationUpdateContext(Isolate * isolate)238   explicit DeprecationUpdateContext(Isolate* isolate) { isolate_ = isolate; }
isolate()239   Isolate* isolate() { return isolate_; }
ShouldCreateMemento(Handle<JSObject> object)240   bool ShouldCreateMemento(Handle<JSObject> object) { return false; }
ExitScope(Handle<AllocationSite> scope_site,Handle<JSObject> object)241   inline void ExitScope(Handle<AllocationSite> scope_site,
242                         Handle<JSObject> object) {}
EnterNewScope()243   Handle<AllocationSite> EnterNewScope() { return Handle<AllocationSite>(); }
current()244   Handle<AllocationSite> current() {
245     UNREACHABLE();
246   }
247 
248   static const bool kCopying = false;
249 
250  private:
251   Isolate* isolate_;
252 };
253 
254 // AllocationSiteCreationContext aids in the creation of AllocationSites to
255 // accompany object literals.
256 class AllocationSiteCreationContext : public AllocationSiteContext {
257  public:
AllocationSiteCreationContext(Isolate * isolate)258   explicit AllocationSiteCreationContext(Isolate* isolate)
259       : AllocationSiteContext(isolate) {}
260 
EnterNewScope()261   Handle<AllocationSite> EnterNewScope() {
262     Handle<AllocationSite> scope_site;
263     if (top().is_null()) {
264       // We are creating the top level AllocationSite as opposed to a nested
265       // AllocationSite.
266       InitializeTraversal(isolate()->factory()->NewAllocationSite(true));
267       scope_site = Handle<AllocationSite>(*top(), isolate());
268       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     } else {
273       DCHECK(!current().is_null());
274       scope_site = isolate()->factory()->NewAllocationSite(false);
275       if (FLAG_trace_creation_allocation_sites) {
276         PrintF(
277             "*** Creating nested %s AllocationSite (top, current, new) (%p, "
278             "%p, "
279             "%p)\n",
280             "Slim", reinterpret_cast<void*>(top()->ptr()),
281             reinterpret_cast<void*>(current()->ptr()),
282             reinterpret_cast<void*>(scope_site->ptr()));
283       }
284       current()->set_nested_site(*scope_site);
285       update_current_site(*scope_site);
286     }
287     DCHECK(!scope_site.is_null());
288     return scope_site;
289   }
ExitScope(Handle<AllocationSite> scope_site,Handle<JSObject> object)290   void ExitScope(Handle<AllocationSite> scope_site, Handle<JSObject> object) {
291     if (object.is_null()) return;
292     scope_site->set_boilerplate(*object, kReleaseStore);
293     if (FLAG_trace_creation_allocation_sites) {
294       bool top_level =
295           !scope_site.is_null() && top().is_identical_to(scope_site);
296       if (top_level) {
297         PrintF("*** Setting AllocationSite %p transition_info %p\n",
298                reinterpret_cast<void*>(scope_site->ptr()),
299                reinterpret_cast<void*>(object->ptr()));
300       } else {
301         PrintF("*** Setting AllocationSite (%p, %p) transition_info %p\n",
302                reinterpret_cast<void*>(top()->ptr()),
303                reinterpret_cast<void*>(scope_site->ptr()),
304                reinterpret_cast<void*>(object->ptr()));
305       }
306     }
307   }
308   static const bool kCopying = false;
309 };
310 
DeepWalk(Handle<JSObject> object,DeprecationUpdateContext * site_context)311 MaybeHandle<JSObject> DeepWalk(Handle<JSObject> object,
312                                DeprecationUpdateContext* site_context) {
313   JSObjectWalkVisitor<DeprecationUpdateContext> v(site_context);
314   MaybeHandle<JSObject> result = v.StructureWalk(object);
315   Handle<JSObject> for_assert;
316   DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
317   return result;
318 }
319 
DeepWalk(Handle<JSObject> object,AllocationSiteCreationContext * site_context)320 MaybeHandle<JSObject> DeepWalk(Handle<JSObject> object,
321                                AllocationSiteCreationContext* site_context) {
322   JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context);
323   MaybeHandle<JSObject> result = v.StructureWalk(object);
324   Handle<JSObject> for_assert;
325   DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
326   return result;
327 }
328 
DeepCopy(Handle<JSObject> object,AllocationSiteUsageContext * site_context)329 MaybeHandle<JSObject> DeepCopy(Handle<JSObject> object,
330                                AllocationSiteUsageContext* site_context) {
331   JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context);
332   MaybeHandle<JSObject> copy = v.StructureWalk(object);
333   Handle<JSObject> for_assert;
334   DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
335   return copy;
336 }
337 
338 Handle<JSObject> CreateObjectLiteral(
339     Isolate* isolate,
340     Handle<ObjectBoilerplateDescription> object_boilerplate_description,
341     int flags, AllocationType allocation);
342 
343 Handle<JSObject> CreateArrayLiteral(
344     Isolate* isolate,
345     Handle<ArrayBoilerplateDescription> array_boilerplate_description,
346     AllocationType allocation);
347 
348 struct ObjectLiteralHelper {
Createv8::internal::__anon241ebebf0111::ObjectLiteralHelper349   static inline Handle<JSObject> Create(Isolate* isolate,
350                                         Handle<HeapObject> description,
351                                         int flags, AllocationType allocation) {
352     Handle<ObjectBoilerplateDescription> object_boilerplate_description =
353         Handle<ObjectBoilerplateDescription>::cast(description);
354     return CreateObjectLiteral(isolate, object_boilerplate_description, flags,
355                                allocation);
356   }
357 };
358 
359 struct ArrayLiteralHelper {
Createv8::internal::__anon241ebebf0111::ArrayLiteralHelper360   static inline Handle<JSObject> Create(Isolate* isolate,
361                                         Handle<HeapObject> description,
362                                         int flags_not_used,
363                                         AllocationType allocation) {
364     Handle<ArrayBoilerplateDescription> array_boilerplate_description =
365         Handle<ArrayBoilerplateDescription>::cast(description);
366     return CreateArrayLiteral(isolate, array_boilerplate_description,
367                               allocation);
368   }
369 };
370 
CreateObjectLiteral(Isolate * isolate,Handle<ObjectBoilerplateDescription> object_boilerplate_description,int flags,AllocationType allocation)371 Handle<JSObject> CreateObjectLiteral(
372     Isolate* isolate,
373     Handle<ObjectBoilerplateDescription> object_boilerplate_description,
374     int flags, AllocationType allocation) {
375   Handle<NativeContext> native_context = isolate->native_context();
376   bool use_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
377   bool has_null_prototype = (flags & ObjectLiteral::kHasNullPrototype) != 0;
378 
379   // In case we have function literals, we want the object to be in
380   // slow properties mode for now. We don't go in the map cache because
381   // maps with constant functions can't be shared if the functions are
382   // not the same (which is the common case).
383   int number_of_properties =
384       object_boilerplate_description->backing_store_size();
385 
386   // Ignoring number_of_properties for force dictionary map with
387   // __proto__:null.
388   Handle<Map> map =
389       has_null_prototype
390           ? handle(native_context->slow_object_with_null_prototype_map(),
391                    isolate)
392           : isolate->factory()->ObjectLiteralMapFromCache(native_context,
393                                                           number_of_properties);
394 
395   Handle<JSObject> boilerplate =
396       isolate->factory()->NewFastOrSlowJSObjectFromMap(
397           map, number_of_properties, allocation);
398 
399   // Normalize the elements of the boilerplate to save space if needed.
400   if (!use_fast_elements) JSObject::NormalizeElements(boilerplate);
401 
402   // Add the constant properties to the boilerplate.
403   int length = object_boilerplate_description->size();
404   // TODO(verwaest): Support tracking representations in the boilerplate.
405   for (int index = 0; index < length; index++) {
406     Handle<Object> key(object_boilerplate_description->name(isolate, index),
407                        isolate);
408     Handle<Object> value(object_boilerplate_description->value(isolate, index),
409                          isolate);
410 
411     if (value->IsHeapObject()) {
412       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       } else if (HeapObject::cast(*value).IsObjectBoilerplateDescription(
418                      isolate)) {
419         Handle<ObjectBoilerplateDescription> object_boilerplate =
420             Handle<ObjectBoilerplateDescription>::cast(value);
421         value = CreateObjectLiteral(isolate, object_boilerplate,
422                                     object_boilerplate->flags(), allocation);
423       }
424     }
425 
426     uint32_t element_index = 0;
427     if (key->ToArrayIndex(&element_index)) {
428       // Array index (uint32).
429       if (value->IsUninitialized(isolate)) {
430         value = handle(Smi::zero(), isolate);
431       }
432       JSObject::SetOwnElementIgnoreAttributes(boilerplate, element_index, value,
433                                               NONE)
434           .Check();
435     } else {
436       Handle<String> name = Handle<String>::cast(key);
437       DCHECK(!name->AsArrayIndex(&element_index));
438       JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, value, NONE)
439           .Check();
440     }
441   }
442 
443   if (map->is_dictionary_map() && !has_null_prototype) {
444     // TODO(cbruni): avoid making the boilerplate fast again, the clone stub
445     // supports dict-mode objects directly.
446     JSObject::MigrateSlowToFast(
447         boilerplate, boilerplate->map().UnusedPropertyFields(), "FastLiteral");
448   }
449   return boilerplate;
450 }
451 
CreateArrayLiteral(Isolate * isolate,Handle<ArrayBoilerplateDescription> array_boilerplate_description,AllocationType allocation)452 Handle<JSObject> CreateArrayLiteral(
453     Isolate* isolate,
454     Handle<ArrayBoilerplateDescription> array_boilerplate_description,
455     AllocationType allocation) {
456   ElementsKind constant_elements_kind =
457       array_boilerplate_description->elements_kind();
458 
459   Handle<FixedArrayBase> constant_elements_values(
460       array_boilerplate_description->constant_elements(isolate), isolate);
461 
462   // Create the JSArray.
463   Handle<FixedArrayBase> copied_elements_values;
464   if (IsDoubleElementsKind(constant_elements_kind)) {
465     copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
466         Handle<FixedDoubleArray>::cast(constant_elements_values));
467   } else {
468     DCHECK(IsSmiOrObjectElementsKind(constant_elements_kind));
469     const bool is_cow = (constant_elements_values->map(isolate) ==
470                          ReadOnlyRoots(isolate).fixed_cow_array_map());
471     if (is_cow) {
472       copied_elements_values = constant_elements_values;
473       if (DEBUG_BOOL) {
474         Handle<FixedArray> fixed_array_values =
475             Handle<FixedArray>::cast(copied_elements_values);
476         for (int i = 0; i < fixed_array_values->length(); i++) {
477           DCHECK(!fixed_array_values->get(i).IsFixedArray());
478         }
479       }
480     } else {
481       Handle<FixedArray> fixed_array_values =
482           Handle<FixedArray>::cast(constant_elements_values);
483       Handle<FixedArray> fixed_array_values_copy =
484           isolate->factory()->CopyFixedArray(fixed_array_values);
485       copied_elements_values = fixed_array_values_copy;
486       for (int i = 0; i < fixed_array_values->length(); i++) {
487         Object value = fixed_array_values_copy->get(isolate, i);
488         HeapObject value_heap_object;
489         if (value.GetHeapObject(isolate, &value_heap_object)) {
490           if (value_heap_object.IsArrayBoilerplateDescription(isolate)) {
491             HandleScope sub_scope(isolate);
492             Handle<ArrayBoilerplateDescription> boilerplate(
493                 ArrayBoilerplateDescription::cast(value_heap_object), isolate);
494             Handle<JSObject> result =
495                 CreateArrayLiteral(isolate, boilerplate, allocation);
496             fixed_array_values_copy->set(i, *result);
497 
498           } else if (value_heap_object.IsObjectBoilerplateDescription(
499                          isolate)) {
500             HandleScope sub_scope(isolate);
501             Handle<ObjectBoilerplateDescription> boilerplate(
502                 ObjectBoilerplateDescription::cast(value_heap_object), isolate);
503             Handle<JSObject> result = CreateObjectLiteral(
504                 isolate, boilerplate, boilerplate->flags(), allocation);
505             fixed_array_values_copy->set(i, *result);
506           }
507         }
508       }
509     }
510   }
511   return isolate->factory()->NewJSArrayWithElements(
512       copied_elements_values, constant_elements_kind,
513       copied_elements_values->length(), allocation);
514 }
515 
516 template <typename LiteralHelper>
CreateLiteralWithoutAllocationSite(Isolate * isolate,Handle<HeapObject> description,int flags)517 MaybeHandle<JSObject> CreateLiteralWithoutAllocationSite(
518     Isolate* isolate, Handle<HeapObject> description, int flags) {
519   Handle<JSObject> literal = LiteralHelper::Create(isolate, description, flags,
520                                                    AllocationType::kYoung);
521   DeprecationUpdateContext update_context(isolate);
522   RETURN_ON_EXCEPTION(isolate, DeepWalk(literal, &update_context), JSObject);
523   return literal;
524 }
525 
526 template <typename LiteralHelper>
CreateLiteral(Isolate * isolate,MaybeHandle<FeedbackVector> maybe_vector,int literals_index,Handle<HeapObject> description,int flags)527 MaybeHandle<JSObject> CreateLiteral(Isolate* isolate,
528                                     MaybeHandle<FeedbackVector> maybe_vector,
529                                     int literals_index,
530                                     Handle<HeapObject> description, int flags) {
531   if (maybe_vector.is_null()) {
532     return CreateLiteralWithoutAllocationSite<LiteralHelper>(
533         isolate, description, flags);
534   }
535 
536   Handle<FeedbackVector> vector = maybe_vector.ToHandleChecked();
537   FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index));
538   CHECK(literals_slot.ToInt() < vector->length());
539   Handle<Object> literal_site(vector->Get(literals_slot)->cast<Object>(),
540                               isolate);
541   Handle<AllocationSite> site;
542   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     // Eagerly create AllocationSites for literals that contain an Array.
549     bool needs_initial_allocation_site =
550         (flags & AggregateLiteral::kNeedsInitialAllocationSite) != 0;
551     if (!needs_initial_allocation_site &&
552         IsUninitializedLiteralSite(*literal_site)) {
553       PreInitializeLiteralSite(vector, literals_slot);
554       return CreateLiteralWithoutAllocationSite<LiteralHelper>(
555           isolate, description, flags);
556     } else {
557       boilerplate = LiteralHelper::Create(isolate, description, flags,
558                                           AllocationType::kOld);
559     }
560     // Install AllocationSite objects.
561     AllocationSiteCreationContext creation_context(isolate);
562     site = creation_context.EnterNewScope();
563     RETURN_ON_EXCEPTION(isolate, DeepWalk(boilerplate, &creation_context),
564                         JSObject);
565     creation_context.ExitScope(site, boilerplate);
566 
567     vector->SynchronizedSet(literals_slot, *site);
568   }
569 
570   STATIC_ASSERT(static_cast<int>(ObjectLiteral::kDisableMementos) ==
571                 static_cast<int>(ArrayLiteral::kDisableMementos));
572   bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0;
573 
574   // Copy the existing boilerplate.
575   AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
576   usage_context.EnterNewScope();
577   MaybeHandle<JSObject> copy = DeepCopy(boilerplate, &usage_context);
578   usage_context.ExitScope(site, boilerplate);
579   return copy;
580 }
581 
582 }  // namespace
583 
RUNTIME_FUNCTION(Runtime_CreateObjectLiteral)584 RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
585   HandleScope scope(isolate);
586   DCHECK_EQ(4, args.length());
587   Handle<HeapObject> maybe_vector = args.at<HeapObject>(0);
588   int literals_index = args.tagged_index_value_at(1);
589   Handle<ObjectBoilerplateDescription> description =
590       args.at<ObjectBoilerplateDescription>(2);
591   int flags = args.smi_value_at(3);
592   Handle<FeedbackVector> vector;
593   if (maybe_vector->IsFeedbackVector()) {
594     vector = Handle<FeedbackVector>::cast(maybe_vector);
595   } else {
596     DCHECK(maybe_vector->IsUndefined());
597   }
598   RETURN_RESULT_OR_FAILURE(
599       isolate, CreateLiteral<ObjectLiteralHelper>(
600                    isolate, vector, literals_index, description, flags));
601 }
602 
RUNTIME_FUNCTION(Runtime_CreateObjectLiteralWithoutAllocationSite)603 RUNTIME_FUNCTION(Runtime_CreateObjectLiteralWithoutAllocationSite) {
604   HandleScope scope(isolate);
605   DCHECK_EQ(2, args.length());
606   Handle<ObjectBoilerplateDescription> description =
607       args.at<ObjectBoilerplateDescription>(0);
608   int flags = args.smi_value_at(1);
609   RETURN_RESULT_OR_FAILURE(
610       isolate, CreateLiteralWithoutAllocationSite<ObjectLiteralHelper>(
611                    isolate, description, flags));
612 }
613 
RUNTIME_FUNCTION(Runtime_CreateArrayLiteralWithoutAllocationSite)614 RUNTIME_FUNCTION(Runtime_CreateArrayLiteralWithoutAllocationSite) {
615   HandleScope scope(isolate);
616   DCHECK_EQ(2, args.length());
617   Handle<ArrayBoilerplateDescription> description =
618       args.at<ArrayBoilerplateDescription>(0);
619   int flags = args.smi_value_at(1);
620   RETURN_RESULT_OR_FAILURE(
621       isolate, CreateLiteralWithoutAllocationSite<ArrayLiteralHelper>(
622                    isolate, description, flags));
623 }
624 
RUNTIME_FUNCTION(Runtime_CreateArrayLiteral)625 RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
626   HandleScope scope(isolate);
627   DCHECK_EQ(4, args.length());
628   Handle<HeapObject> maybe_vector = args.at<HeapObject>(0);
629   int literals_index = args.tagged_index_value_at(1);
630   Handle<ArrayBoilerplateDescription> elements =
631       args.at<ArrayBoilerplateDescription>(2);
632   int flags = args.smi_value_at(3);
633   Handle<FeedbackVector> vector;
634   if (maybe_vector->IsFeedbackVector()) {
635     vector = Handle<FeedbackVector>::cast(maybe_vector);
636   } else {
637     DCHECK(maybe_vector->IsUndefined());
638   }
639   RETURN_RESULT_OR_FAILURE(
640       isolate, CreateLiteral<ArrayLiteralHelper>(
641                    isolate, vector, literals_index, elements, flags));
642 }
643 
RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral)644 RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
645   HandleScope scope(isolate);
646   DCHECK_EQ(4, args.length());
647   Handle<HeapObject> maybe_vector = args.at<HeapObject>(0);
648   int index = args.tagged_index_value_at(1);
649   Handle<String> pattern = args.at<String>(2);
650   int flags = args.smi_value_at(3);
651 
652   if (maybe_vector->IsUndefined()) {
653     // We don't have a vector; don't create a boilerplate, simply construct a
654     // plain JSRegExp instance and return it.
655     RETURN_RESULT_OR_FAILURE(
656         isolate, JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
657   }
658 
659   Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(maybe_vector);
660   FeedbackSlot literal_slot(FeedbackVector::ToSlot(index));
661   Handle<Object> literal_site(vector->Get(literal_slot)->cast<Object>(),
662                               isolate);
663 
664   // This function must not be called when a boilerplate already exists (if it
665   // exists, callers should instead copy the boilerplate into a new JSRegExp
666   // instance).
667   CHECK(!HasBoilerplate(literal_site));
668 
669   Handle<JSRegExp> regexp_instance;
670   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
671       isolate, regexp_instance,
672       JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
673 
674   // JSRegExp literal sites are initialized in a two-step process:
675   // Uninitialized-Preinitialized, and Preinitialized-Initialized.
676   if (IsUninitializedLiteralSite(*literal_site)) {
677     PreInitializeLiteralSite(vector, literal_slot);
678     return *regexp_instance;
679   }
680 
681   Handle<FixedArray> data(FixedArray::cast(regexp_instance->data()), isolate);
682   Handle<String> source(String::cast(regexp_instance->source()), isolate);
683   Handle<RegExpBoilerplateDescription> boilerplate =
684       isolate->factory()->NewRegExpBoilerplateDescription(
685           data, source,
686           Smi::FromInt(static_cast<int>(regexp_instance->flags())));
687 
688   vector->SynchronizedSet(literal_slot, *boilerplate);
689   DCHECK(HasBoilerplate(
690       handle(vector->Get(literal_slot)->cast<Object>(), isolate)));
691 
692   return *regexp_instance;
693 }
694 
695 }  // namespace internal
696 }  // namespace v8
697