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