5 #include "src/allocation-site-scopes-inl.h" 6 #include "src/arguments-inl.h" 7 #include "src/ast/ast.h" 8 #include "src/counters.h" 9 #include "src/isolate-inl.h" 10 #include "src/objects/hash-table-inl.h" 11 #include "src/objects/heap-object-inl.h" 12 #include "src/objects/js-regexp-inl.h" 13 #include "src/objects/literal-objects-inl.h" 14 #include "src/runtime/runtime-utils.h" 15 #include "src/runtime/runtime.h" 22 bool IsUninitializedLiteralSite(Object* literal_site) {
23 return literal_site == Smi::kZero;
26 bool HasBoilerplate(Handle<Object> literal_site) {
27 return !literal_site->IsSmi();
30 void PreInitializeLiteralSite(Handle<FeedbackVector> vector,
32 vector->
Set(slot, Smi::FromInt(1));
35 Handle<Object> InnerCreateBoilerplate(Isolate* isolate,
36 Handle<Object> description,
37 PretenureFlag pretenure_flag);
39 enum DeepCopyHints { kNoHints = 0, kObjectIsShallow = 1 };
41 template <
class ContextObject>
42 class JSObjectWalkVisitor {
44 JSObjectWalkVisitor(ContextObject* site_context, DeepCopyHints hints)
45 : site_context_(site_context), hints_(hints) {}
47 V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> StructureWalk(
48 Handle<JSObject>
object);
51 V8_WARN_UNUSED_RESULT
inline MaybeHandle<JSObject> VisitElementOrProperty(
52 Handle<JSObject>
object, Handle<JSObject> value) {
54 if (!value->IsJSArray()) {
55 return StructureWalk(value);
58 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
59 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
60 site_context()->ExitScope(current_site, value);
64 inline ContextObject* site_context() {
return site_context_; }
65 inline Isolate* isolate() {
return site_context()->isolate(); }
68 ContextObject* site_context_;
69 const DeepCopyHints hints_;
72 template <
class ContextObject>
73 MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
74 Handle<JSObject>
object) {
75 Isolate* isolate = this->isolate();
76 bool copying = ContextObject::kCopying;
77 bool shallow = hints_ == kObjectIsShallow;
80 StackLimitCheck check(isolate);
82 if (check.HasOverflowed()) {
83 isolate->StackOverflow();
84 return MaybeHandle<JSObject>();
88 if (object->map()->is_deprecated()) {
89 JSObject::MigrateInstance(
object);
92 Handle<JSObject> copy;
95 DCHECK(!object->IsJSFunction());
96 Handle<AllocationSite> site_to_pass;
97 if (site_context()->ShouldCreateMemento(
object)) {
98 site_to_pass = site_context()->current();
100 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
object,
106 DCHECK(copying || copy.is_identical_to(
object));
108 if (shallow)
return copy;
110 HandleScope scope(isolate);
113 if (!copy->IsJSArray()) {
114 if (copy->HasFastProperties()) {
115 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors(),
117 int limit = copy->map()->NumberOfOwnDescriptors();
118 for (
int i = 0;
i < limit;
i++) {
119 DCHECK_EQ(kField, descriptors->GetDetails(
i).location());
120 DCHECK_EQ(kData, descriptors->GetDetails(
i).kind());
121 FieldIndex index = FieldIndex::ForDescriptor(copy->map(),
i);
122 if (copy->IsUnboxedDoubleField(index))
continue;
123 Object* raw = copy->RawFastPropertyAt(index);
124 if (raw->IsJSObject()) {
125 Handle<JSObject> value(JSObject::cast(raw), isolate);
126 ASSIGN_RETURN_ON_EXCEPTION(
127 isolate, value, VisitElementOrProperty(copy, value), JSObject);
128 if (copying) copy->FastPropertyAtPut(index, *value);
129 }
else if (copying && raw->IsMutableHeapNumber()) {
130 DCHECK(descriptors->GetDetails(
i).representation().IsDouble());
131 uint64_t double_value = MutableHeapNumber::cast(raw)->value_as_bits();
133 isolate->factory()->NewMutableHeapNumberFromBits(double_value);
134 copy->FastPropertyAtPut(index, *value);
138 Handle<NameDictionary> dict(copy->property_dictionary(), isolate);
139 for (
int i = 0;
i < dict->Capacity();
i++) {
140 Object* raw = dict->ValueAt(
i);
141 if (!raw->IsJSObject())
continue;
142 DCHECK(dict->KeyAt(
i)->IsName());
143 Handle<JSObject> value(JSObject::cast(raw), isolate);
144 ASSIGN_RETURN_ON_EXCEPTION(
145 isolate, value, VisitElementOrProperty(copy, value), JSObject);
146 if (copying) dict->ValueAtPut(
i, *value);
151 if (copy->elements()->length() == 0)
return copy;
155 switch (copy->GetElementsKind()) {
156 case PACKED_ELEMENTS:
157 case HOLEY_ELEMENTS: {
158 Handle<FixedArray> elements(FixedArray::cast(copy->elements()), isolate);
159 if (elements->map() == ReadOnlyRoots(isolate).fixed_cow_array_map()) {
161 for (
int i = 0;
i < elements->length();
i++) {
162 DCHECK(!elements->get(
i)->IsJSObject());
166 for (
int i = 0;
i < elements->length();
i++) {
167 Object* raw = elements->get(
i);
168 if (!raw->IsJSObject())
continue;
169 Handle<JSObject> value(JSObject::cast(raw), isolate);
170 ASSIGN_RETURN_ON_EXCEPTION(
171 isolate, value, VisitElementOrProperty(copy, value), JSObject);
172 if (copying) elements->set(
i, *value);
177 case DICTIONARY_ELEMENTS: {
178 Handle<NumberDictionary> element_dictionary(copy->element_dictionary(),
180 int capacity = element_dictionary->Capacity();
181 for (
int i = 0;
i < capacity;
i++) {
182 Object* raw = element_dictionary->ValueAt(
i);
183 if (!raw->IsJSObject())
continue;
184 Handle<JSObject> value(JSObject::cast(raw), isolate);
185 ASSIGN_RETURN_ON_EXCEPTION(
186 isolate, value, VisitElementOrProperty(copy, value), JSObject);
187 if (copying) element_dictionary->ValueAtPut(
i, *value);
191 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
192 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
195 case FAST_STRING_WRAPPER_ELEMENTS:
196 case SLOW_STRING_WRAPPER_ELEMENTS:
200 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 202 TYPED_ARRAYS(TYPED_ARRAY_CASE)
203 #undef TYPED_ARRAY_CASE 208 case PACKED_SMI_ELEMENTS:
209 case HOLEY_SMI_ELEMENTS:
210 case PACKED_DOUBLE_ELEMENTS:
211 case HOLEY_DOUBLE_ELEMENTS:
220 class DeprecationUpdateContext {
222 explicit DeprecationUpdateContext(Isolate* isolate) { isolate_ = isolate; }
223 Isolate* isolate() {
return isolate_; }
224 bool ShouldCreateMemento(Handle<JSObject>
object) {
return false; }
225 inline void ExitScope(Handle<AllocationSite> scope_site,
226 Handle<JSObject>
object) {}
227 Handle<AllocationSite> EnterNewScope() {
return Handle<AllocationSite>(); }
228 Handle<AllocationSite> current() {
230 return Handle<AllocationSite>();
233 static const bool kCopying =
false;
241 class AllocationSiteCreationContext :
public AllocationSiteContext {
243 explicit AllocationSiteCreationContext(Isolate* isolate)
244 : AllocationSiteContext(isolate) {}
246 Handle<AllocationSite> EnterNewScope() {
247 Handle<AllocationSite> scope_site;
248 if (top().is_null()) {
251 InitializeTraversal(isolate()->factory()->NewAllocationSite(
true));
252 scope_site = Handle<AllocationSite>(*top(), isolate());
253 if (FLAG_trace_creation_allocation_sites) {
254 PrintF(
"*** Creating top level %s AllocationSite %p\n",
"Fat",
255 static_cast<void*>(*scope_site));
258 DCHECK(!current().is_null());
259 scope_site = isolate()->factory()->NewAllocationSite(
false);
260 if (FLAG_trace_creation_allocation_sites) {
262 "*** Creating nested %s AllocationSite (top, current, new) (%p, " 265 "Slim", static_cast<void*>(*top()), static_cast<void*>(*current()),
266 static_cast<void*>(*scope_site));
268 current()->set_nested_site(*scope_site);
269 update_current_site(*scope_site);
271 DCHECK(!scope_site.is_null());
274 void ExitScope(Handle<AllocationSite> scope_site, Handle<JSObject>
object) {
275 if (
object.is_null())
return;
276 scope_site->set_boilerplate(*
object);
277 if (FLAG_trace_creation_allocation_sites) {
279 !scope_site.is_null() && top().is_identical_to(scope_site);
281 PrintF(
"*** Setting AllocationSite %p transition_info %p\n",
282 static_cast<void*>(*scope_site), static_cast<void*>(*
object));
284 PrintF(
"*** Setting AllocationSite (%p, %p) transition_info %p\n",
285 static_cast<void*>(*top()), static_cast<void*>(*scope_site),
286 static_cast<void*>(*
object));
290 static const bool kCopying =
false;
293 MaybeHandle<JSObject> DeepWalk(Handle<JSObject>
object,
294 DeprecationUpdateContext* site_context) {
295 JSObjectWalkVisitor<DeprecationUpdateContext> v(site_context, kNoHints);
296 MaybeHandle<JSObject> result = v.StructureWalk(
object);
297 Handle<JSObject> for_assert;
298 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(
object));
302 MaybeHandle<JSObject> DeepWalk(Handle<JSObject>
object,
303 AllocationSiteCreationContext* site_context) {
304 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, kNoHints);
305 MaybeHandle<JSObject> result = v.StructureWalk(
object);
306 Handle<JSObject> for_assert;
307 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(
object));
311 MaybeHandle<JSObject> DeepCopy(Handle<JSObject>
object,
312 AllocationSiteUsageContext* site_context,
313 DeepCopyHints hints) {
314 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, hints);
315 MaybeHandle<JSObject> copy = v.StructureWalk(
object);
316 Handle<JSObject> for_assert;
317 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(
object));
321 struct ObjectLiteralHelper {
322 static Handle<JSObject> Create(Isolate* isolate,
323 Handle<HeapObject> description,
int flags,
324 PretenureFlag pretenure_flag) {
325 Handle<NativeContext> native_context = isolate->native_context();
326 Handle<ObjectBoilerplateDescription> object_boilerplate_description =
327 Handle<ObjectBoilerplateDescription>::cast(description);
328 bool use_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
329 bool has_null_prototype = (flags & ObjectLiteral::kHasNullPrototype) != 0;
335 int number_of_properties =
336 object_boilerplate_description->backing_store_size();
342 ? handle(native_context->slow_object_with_null_prototype_map(),
344 : isolate->factory()->ObjectLiteralMapFromCache(
345 native_context, number_of_properties);
347 Handle<JSObject> boilerplate =
348 map->is_dictionary_map()
349 ? isolate->factory()->NewSlowJSObjectFromMap(
350 map, number_of_properties, pretenure_flag)
351 : isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
354 if (!use_fast_elements) JSObject::NormalizeElements(boilerplate);
357 int length = object_boilerplate_description->size();
359 for (
int index = 0; index < length; index++) {
360 Handle<Object> key(object_boilerplate_description->name(index), isolate);
361 Handle<Object> value(object_boilerplate_description->value(index),
364 if (value->IsObjectBoilerplateDescription() ||
365 value->IsArrayBoilerplateDescription()) {
366 value = InnerCreateBoilerplate(isolate, value, pretenure_flag);
369 if (key->ToArrayIndex(&element_index)) {
371 if (value->IsUninitialized(isolate)) {
372 value = handle(Smi::kZero, isolate);
374 JSObject::SetOwnElementIgnoreAttributes(boilerplate, element_index,
378 Handle<String> name = Handle<String>::cast(key);
379 DCHECK(!name->AsArrayIndex(&element_index));
380 JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, value, NONE)
385 if (map->is_dictionary_map() && !has_null_prototype) {
388 JSObject::MigrateSlowToFast(boilerplate,
389 boilerplate->map()->UnusedPropertyFields(),
396 struct ArrayLiteralHelper {
397 static Handle<JSObject> Create(Isolate* isolate,
398 Handle<HeapObject> description,
int flags,
399 PretenureFlag pretenure_flag) {
400 Handle<ArrayBoilerplateDescription> array_boilerplate_description =
401 Handle<ArrayBoilerplateDescription>::cast(description);
403 ElementsKind constant_elements_kind =
404 array_boilerplate_description->elements_kind();
406 Handle<FixedArrayBase> constant_elements_values(
407 array_boilerplate_description->constant_elements(), isolate);
410 Handle<FixedArrayBase> copied_elements_values;
411 if (IsDoubleElementsKind(constant_elements_kind)) {
412 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
413 Handle<FixedDoubleArray>::cast(constant_elements_values));
415 DCHECK(IsSmiOrObjectElementsKind(constant_elements_kind));
416 const bool is_cow = (constant_elements_values->map() ==
417 ReadOnlyRoots(isolate).fixed_cow_array_map());
419 copied_elements_values = constant_elements_values;
421 Handle<FixedArray> fixed_array_values =
422 Handle<FixedArray>::cast(copied_elements_values);
423 for (
int i = 0;
i < fixed_array_values->length();
i++) {
424 DCHECK(!fixed_array_values->get(
i)->IsFixedArray());
428 Handle<FixedArray> fixed_array_values =
429 Handle<FixedArray>::cast(constant_elements_values);
430 Handle<FixedArray> fixed_array_values_copy =
431 isolate->factory()->CopyFixedArray(fixed_array_values);
432 copied_elements_values = fixed_array_values_copy;
433 FOR_WITH_HANDLE_SCOPE(
434 isolate,
int,
i = 0,
i, i < fixed_array_values->length(),
i++, {
435 Handle<Object> value(fixed_array_values->get(
i), isolate);
437 if (value->IsArrayBoilerplateDescription() ||
438 value->IsObjectBoilerplateDescription()) {
439 Handle<Object> result =
440 InnerCreateBoilerplate(isolate, value, pretenure_flag);
441 fixed_array_values_copy->set(
i, *result);
447 return isolate->factory()->NewJSArrayWithElements(
448 copied_elements_values, constant_elements_kind,
449 copied_elements_values->length(), pretenure_flag);
453 Handle<Object> InnerCreateBoilerplate(Isolate* isolate,
454 Handle<Object> description,
455 PretenureFlag pretenure_flag) {
456 if (description->IsObjectBoilerplateDescription()) {
457 Handle<ObjectBoilerplateDescription> object_boilerplate_description =
458 Handle<ObjectBoilerplateDescription>::cast(description);
459 return ObjectLiteralHelper::Create(isolate, object_boilerplate_description,
460 object_boilerplate_description->flags(),
463 DCHECK(description->IsArrayBoilerplateDescription());
464 Handle<ArrayBoilerplateDescription> array_boilerplate_description =
465 Handle<ArrayBoilerplateDescription>::cast(description);
466 return ArrayLiteralHelper::Create(
467 isolate, array_boilerplate_description,
468 array_boilerplate_description->elements_kind(), pretenure_flag);
472 inline DeepCopyHints DecodeCopyHints(
int flags) {
473 DeepCopyHints copy_hints =
474 (flags & AggregateLiteral::kIsShallow) ? kObjectIsShallow : kNoHints;
475 if (FLAG_track_double_fields && !FLAG_unbox_double_fields) {
477 copy_hints = kNoHints;
482 template <
typename LiteralHelper>
483 MaybeHandle<JSObject> CreateLiteralWithoutAllocationSite(
484 Isolate* isolate, Handle<HeapObject> description,
int flags) {
485 Handle<JSObject> literal =
486 LiteralHelper::Create(isolate, description, flags, NOT_TENURED);
487 DeepCopyHints copy_hints = DecodeCopyHints(flags);
488 if (copy_hints == kNoHints) {
489 DeprecationUpdateContext update_context(isolate);
490 RETURN_ON_EXCEPTION(isolate, DeepWalk(literal, &update_context), JSObject);
495 template <
typename LiteralHelper>
496 MaybeHandle<JSObject> CreateLiteral(Isolate* isolate,
497 Handle<FeedbackVector> vector,
499 Handle<HeapObject> description,
int flags) {
500 FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index));
501 CHECK(literals_slot.ToInt() < vector->length());
502 Handle<Object> literal_site(vector->Get(literals_slot)->cast<Object>(),
504 DeepCopyHints copy_hints = DecodeCopyHints(flags);
506 Handle<AllocationSite> site;
507 Handle<JSObject> boilerplate;
509 if (HasBoilerplate(literal_site)) {
510 site = Handle<AllocationSite>::cast(literal_site);
511 boilerplate = Handle<JSObject>(site->boilerplate(), isolate);
514 bool needs_initial_allocation_site =
515 (flags & AggregateLiteral::kNeedsInitialAllocationSite) != 0;
516 if (!needs_initial_allocation_site &&
517 IsUninitializedLiteralSite(*literal_site)) {
518 PreInitializeLiteralSite(vector, literals_slot);
519 return CreateLiteralWithoutAllocationSite<LiteralHelper>(
520 isolate, description, flags);
522 boilerplate = LiteralHelper::Create(isolate, description, flags, TENURED);
525 AllocationSiteCreationContext creation_context(isolate);
526 site = creation_context.EnterNewScope();
527 RETURN_ON_EXCEPTION(isolate, DeepWalk(boilerplate, &creation_context),
529 creation_context.ExitScope(site, boilerplate);
531 vector->Set(literals_slot, *site);
534 STATIC_ASSERT(static_cast<int>(ObjectLiteral::kDisableMementos) ==
535 static_cast<int>(ArrayLiteral::kDisableMementos));
536 bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0;
539 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
540 usage_context.EnterNewScope();
541 MaybeHandle<JSObject> copy =
542 DeepCopy(boilerplate, &usage_context, copy_hints);
543 usage_context.ExitScope(site, boilerplate);
548 RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
549 HandleScope scope(isolate);
550 DCHECK_EQ(4, args.length());
551 CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 0);
552 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
553 CONVERT_ARG_HANDLE_CHECKED(ObjectBoilerplateDescription, description, 2);
554 CONVERT_SMI_ARG_CHECKED(flags, 3);
555 RETURN_RESULT_OR_FAILURE(
556 isolate, CreateLiteral<ObjectLiteralHelper>(
557 isolate, vector, literals_index, description, flags));
560 RUNTIME_FUNCTION(Runtime_CreateObjectLiteralWithoutAllocationSite) {
561 HandleScope scope(isolate);
562 DCHECK_EQ(2, args.length());
563 CONVERT_ARG_HANDLE_CHECKED(ObjectBoilerplateDescription, description, 0);
564 CONVERT_SMI_ARG_CHECKED(flags, 1);
565 RETURN_RESULT_OR_FAILURE(
566 isolate, CreateLiteralWithoutAllocationSite<ObjectLiteralHelper>(
567 isolate, description, flags));
570 RUNTIME_FUNCTION(Runtime_CreateArrayLiteralWithoutAllocationSite) {
571 HandleScope scope(isolate);
572 DCHECK_EQ(2, args.length());
573 CONVERT_ARG_HANDLE_CHECKED(ArrayBoilerplateDescription, description, 0);
574 CONVERT_SMI_ARG_CHECKED(flags, 1);
575 RETURN_RESULT_OR_FAILURE(
576 isolate, CreateLiteralWithoutAllocationSite<ArrayLiteralHelper>(
577 isolate, description, flags));
580 RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
581 HandleScope scope(isolate);
582 DCHECK_EQ(4, args.length());
583 CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 0);
584 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
585 CONVERT_ARG_HANDLE_CHECKED(ArrayBoilerplateDescription, elements, 2);
586 CONVERT_SMI_ARG_CHECKED(flags, 3);
587 RETURN_RESULT_OR_FAILURE(
588 isolate, CreateLiteral<ArrayLiteralHelper>(
589 isolate, vector, literals_index, elements, flags));
592 RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
593 HandleScope scope(isolate);
594 DCHECK_EQ(4, args.length());
595 CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 0);
596 CONVERT_SMI_ARG_CHECKED(index, 1);
597 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
598 CONVERT_SMI_ARG_CHECKED(flags, 3);
600 FeedbackSlot literal_slot(FeedbackVector::ToSlot(index));
603 Handle<Object> literal_site(vector->Get(literal_slot)->cast<Object>(),
605 Handle<Object> boilerplate;
606 if (!HasBoilerplate(literal_site)) {
607 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
608 isolate, boilerplate,
609 JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
610 if (IsUninitializedLiteralSite(*literal_site)) {
611 PreInitializeLiteralSite(vector, literal_slot);
614 vector->Set(literal_slot, *boilerplate);
616 return *JSRegExp::Copy(Handle<JSRegExp>::cast(boilerplate));