v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
map-updater.cc
Go to the documentation of this file.
1// Copyright 2017 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
6
7#include <optional>
8#include <queue>
9
13#include "src/handles/handles.h"
16#include "src/objects/keys.h"
18#include "src/objects/objects.h"
21
22namespace v8::internal {
23
24namespace {
25
26inline bool EqualImmutableValues(Tagged<Object> obj1, Tagged<Object> obj2) {
27 if (obj1 == obj2) return true; // Valid for both kData and kAccessor kinds.
28 // TODO(ishell): compare AccessorPairs.
29 return false;
30}
31
32V8_WARN_UNUSED_RESULT DirectHandle<FieldType> GeneralizeFieldType(
33 Representation rep1, DirectHandle<FieldType> type1, Representation rep2,
34 DirectHandle<FieldType> type2, Isolate* isolate) {
35 if (FieldType::NowIs(*type1, type2)) return type2;
36 if (FieldType::NowIs(*type2, type1)) return type1;
37 return FieldType::Any(isolate);
38}
39
40void PrintGeneralization(Isolate* isolate, DirectHandle<Map> map, FILE* file,
41 const char* reason, InternalIndex modify_index,
42 int split, int descriptors, bool descriptor_to_field,
43 Representation old_representation,
44 Representation new_representation,
45 PropertyConstness old_constness,
46 PropertyConstness new_constness,
47 MaybeDirectHandle<FieldType> old_field_type,
48 MaybeDirectHandle<Object> old_value,
49 MaybeDirectHandle<FieldType> new_field_type,
50 MaybeDirectHandle<Object> new_value) {
51 OFStream os(file);
52 os << "[generalizing]";
53 Tagged<Name> name = map->instance_descriptors(isolate)->GetKey(modify_index);
54 if (IsString(name)) {
55 Cast<String>(name)->PrintOn(file);
56 } else {
57 os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
58 }
59 os << ":";
60 if (descriptor_to_field) {
61 os << "c";
62 } else {
63 os << old_representation.Mnemonic() << "{";
64 if (old_field_type.is_null()) {
65 os << Brief(*(old_value.ToHandleChecked()));
66 } else {
67 FieldType::PrintTo(*old_field_type.ToHandleChecked(), os);
68 }
69 os << ";" << old_constness << "}";
70 }
71 os << "->" << new_representation.Mnemonic() << "{";
72 if (new_field_type.is_null()) {
73 os << Brief(*(new_value.ToHandleChecked()));
74 } else {
75 FieldType::PrintTo(*new_field_type.ToHandleChecked(), os);
76 }
77 os << ";" << new_constness << "} (";
78 if (strlen(reason) > 0) {
79 os << reason;
80 } else {
81 os << "+" << (descriptors - split) << " maps";
82 }
83 os << ") [";
84 JavaScriptFrame::PrintTop(isolate, file, false, true);
85 os << "]\n";
86}
87
88} // namespace
89
91 : isolate_(isolate),
92 old_map_(old_map),
93 old_descriptors_(old_map->instance_descriptors(isolate), isolate_),
94 old_nof_(old_map_->NumberOfOwnDescriptors()),
95 new_elements_kind_(old_map_->elements_kind()),
96 is_transitionable_fast_elements_kind_(
97 IsTransitionableFastElementsKind(new_elements_kind_)) {
98 // We shouldn't try to update remote objects.
99 DCHECK(
100 !IsFunctionTemplateInfo(old_map->FindRootMap(isolate)->GetConstructor()));
101}
102
104 return old_descriptors_->GetKey(descriptor);
105}
106
108 DCHECK(descriptor.is_found());
109 if (descriptor == modified_descriptor_) {
111 // If the original map was sealed or frozen, let's use the old
112 // attributes so that we follow the same transition path as before.
113 // Note that the user could not have changed the attributes because
114 // both seal and freeze make the properties non-configurable. An exception
115 // is transitioning from [[Writable]] = true to [[Writable]] = false (this
116 // is allowed for frozen and sealed objects). To support it, we use the new
117 // attributes if they have [[Writable]] == false.
120 attributes = old_descriptors_->GetDetails(descriptor).attributes();
121 }
124 }
125 return old_descriptors_->GetDetails(descriptor);
126}
127
129 DCHECK(descriptor.is_found());
130 if (descriptor == modified_descriptor_) {
132 return {};
133 }
134 DCHECK_EQ(PropertyLocation::kDescriptor, GetDetails(descriptor).location());
135 return old_descriptors_->GetStrongValue(descriptor);
136}
137
139 DCHECK(descriptor.is_found());
140 if (descriptor == modified_descriptor_) {
142 return *new_field_type_;
143 }
144 DCHECK_EQ(PropertyLocation::kField, GetDetails(descriptor).location());
145 return old_descriptors_->GetFieldType(descriptor);
146}
147
149 InternalIndex descriptor, PropertyLocation location,
150 Representation representation) const {
151 DCHECK(descriptor.is_found());
152 // |location| is just a pre-fetched GetDetails(descriptor).location().
153 DCHECK_EQ(location, GetDetails(descriptor).location());
154 if (location == PropertyLocation::kField) {
155 return direct_handle(GetFieldType(descriptor), isolate_);
156 } else {
157 return Object::OptimalType(GetValue(descriptor), isolate_, representation);
158 }
159}
160
162 DirectHandle<DescriptorArray> descriptors, InternalIndex descriptor,
163 PropertyLocation location, Representation representation) {
164 // |location| is just a pre-fetched GetDetails(descriptor).location().
165 DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
166 if (location == PropertyLocation::kField) {
167 return direct_handle(descriptors->GetFieldType(descriptor), isolate_);
168 } else {
169 return Object::OptimalType(descriptors->GetStrongValue(descriptor),
170 isolate_, representation);
171 }
172}
173
175 InternalIndex descriptor, PropertyAttributes attributes,
176 PropertyConstness constness, Representation representation,
177 DirectHandle<FieldType> field_type) {
179 DCHECK(descriptor.is_found());
180 DCHECK(!old_map_->is_dictionary_map());
181
184
185 modified_descriptor_ = descriptor;
187 new_attributes_ = attributes;
189
190 PropertyDetails old_details =
192
193 // If property kind is not reconfigured merge the result with
194 // representation/field type from the old descriptor.
195 if (old_details.kind() == new_kind_) {
196 new_constness_ = GeneralizeConstness(constness, old_details.constness());
197
198 Representation old_representation = old_details.representation();
199 new_representation_ = representation.generalize(old_representation);
200
201 DirectHandle<FieldType> old_field_type =
203 old_details.location(), new_representation_);
204
206 GeneralizeFieldType(old_representation, old_field_type,
207 new_representation_, field_type, isolate_);
208 } else {
209 // We don't know if this is a first property kind reconfiguration
210 // and we don't know which value was in this property previously
211 // therefore we can't treat such a property as constant.
213 new_representation_ = representation;
214 new_field_type_ = field_type;
215 }
216
218 isolate_, old_map_->instance_type(), &new_representation_,
220
222 if (FindRootMap() == kEnd) return result_map_;
223 if (FindTargetMap() == kEnd) return result_map_;
226 }
228 return result_map_;
229}
230
241
243 DirectHandle<JSPrototype> prototype) {
244 DCHECK(v8_flags.move_prototype_transitions_first);
246 DCHECK_NE(old_map_->prototype(), *prototype);
247
248 // Prototype maps are replaced by deprecation when their prototype changes. No
249 // need to add a transition.
250 if (old_map_->is_prototype_map()) {
252 }
253
255
256 // TODO(olivf): The updated map can have more generic field types than the
257 // source map. This is ok, since UpdatePrototype also does an instance
258 // migration. If we wanted to avoid the migration for most cases, we could
259 // potentially back-propagate generalizations here.
260 return Update();
261}
262
263// static
265 DirectHandle<Map> map) {
266 if (!map->is_deprecated()) return map;
267 // TODO(ishell): support fast map updating if we enable it.
268 CHECK(!v8_flags.fast_map_update);
269 MapUpdater mu(isolate, map);
270 // Update map without locking the Isolate::map_updater_access mutex.
271 return mu.UpdateImpl();
272}
273
278
281 DCHECK_IMPLIES(new_prototype_.is_null() &&
282 new_elements_kind_ == old_map_->elements_kind(),
283 old_map_->is_deprecated());
284 if (FindRootMap() == kEnd) return result_map_;
285 if (FindTargetMap() == kEnd) return result_map_;
288 }
290 if (V8_UNLIKELY(v8_flags.fast_map_update && old_map_->is_deprecated())) {
292 }
293 return result_map_;
294}
295
296namespace {
297
298struct IntegrityLevelTransitionInfo {
299 explicit IntegrityLevelTransitionInfo(Tagged<Map> map)
301
306};
307
308IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions(
309 Tagged<Map> map, Isolate* isolate, DisallowGarbageCollection* no_gc,
310 ConcurrencyMode cmode) {
311 IntegrityLevelTransitionInfo info(map);
312
313 // Figure out the most restrictive integrity level transition (it should
314 // be the last one in the transition tree).
315 DCHECK(!map->is_extensible());
316 Tagged<Map> previous = Cast<Map>(map->GetBackPointer(isolate));
317 TransitionsAccessor last_transitions(isolate, previous, IsConcurrent(cmode));
318 if (!last_transitions.HasIntegrityLevelTransitionTo(
319 map, &info.integrity_level_symbol, &info.integrity_level)) {
320 // The last transition was not integrity level transition - just bail out.
321 // This can happen in the following cases:
322 // - there are private symbol transitions following the integrity level
323 // transitions (see crbug.com/v8/8854).
324 // - there is a getter added in addition to an existing setter (or a setter
325 // in addition to an existing getter).
326 return info;
327 }
328
329 Tagged<Map> source_map = previous;
330 // Now walk up the back pointer chain and skip all integrity level
331 // transitions. If we encounter any non-integrity level transition interleaved
332 // with integrity level transitions, just bail out.
333 while (!source_map->is_extensible()) {
334 previous = Cast<Map>(source_map->GetBackPointer(isolate));
335 TransitionsAccessor transitions(isolate, previous, IsConcurrent(cmode));
336 if (!transitions.HasIntegrityLevelTransitionTo(source_map)) {
337 return info;
338 }
339 source_map = previous;
340 }
341
342 // Integrity-level transitions never change number of descriptors.
343 CHECK_EQ(map->NumberOfOwnDescriptors(), source_map->NumberOfOwnDescriptors());
344
345 info.has_integrity_level_transition = true;
346 info.integrity_level_source_map = source_map;
347 return info;
348}
349
350} // namespace
351
352// static
353std::optional<Tagged<Map>> MapUpdater::TryUpdateNoLock(Isolate* isolate,
354 Tagged<Map> old_map,
355 ConcurrencyMode cmode) {
357
358 // Check the state of the root map.
359 Tagged<Map> root_map = old_map->FindRootMap(isolate);
360 if (root_map->is_deprecated()) {
361 Tagged<JSFunction> constructor =
362 Cast<JSFunction>(root_map->GetConstructor());
363 DCHECK(constructor->has_initial_map());
364 DCHECK(constructor->initial_map()->is_dictionary_map());
365 if (constructor->initial_map()->elements_kind() !=
366 old_map->elements_kind()) {
367 return {};
368 }
369 return constructor->initial_map();
370 }
371
372 if (v8_flags.move_prototype_transitions_first &&
373 root_map->prototype() != old_map->prototype()) {
374 auto maybe_transition = TransitionsAccessor::GetPrototypeTransition(
375 isolate, root_map, old_map->prototype());
376 if (!maybe_transition) {
377 return {};
378 }
379 root_map = *maybe_transition;
380 }
381
382 if (!old_map->EquivalentToForTransition(root_map, cmode)) return {};
383
384 ElementsKind from_kind = root_map->elements_kind();
385 ElementsKind to_kind = old_map->elements_kind();
386
387 IntegrityLevelTransitionInfo info(old_map);
388 if (root_map->is_extensible() != old_map->is_extensible()) {
389 DCHECK(!old_map->is_extensible());
390 DCHECK(root_map->is_extensible());
391 info = DetectIntegrityLevelTransitions(old_map, isolate, &no_gc, cmode);
392 // Bail out if there were some private symbol transitions mixed up
393 // with the integrity level transitions.
394 if (!info.has_integrity_level_transition) return {};
395 // Make sure to replay the original elements kind transitions, before
396 // the integrity level transition sets the elements to dictionary mode.
397 DCHECK(to_kind == DICTIONARY_ELEMENTS ||
398 to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
401 to_kind = info.integrity_level_source_map->elements_kind();
402 }
403 if (from_kind != to_kind) {
404 // Try to follow existing elements kind transitions.
405 root_map = root_map->LookupElementsTransitionMap(isolate, to_kind, cmode);
406 if (root_map.is_null()) return {};
407 // From here on, use the map with correct elements kind as root map.
408 }
409
410 // Replay the transitions as they were before the integrity level transition.
411 Tagged<Map> result = root_map->TryReplayPropertyTransitions(
412 isolate, info.integrity_level_source_map, cmode);
413 if (result.is_null()) return {};
414
415 if (info.has_integrity_level_transition) {
416 // Now replay the integrity level transition.
417 result = TransitionsAccessor(isolate, *result, IsConcurrent(cmode))
418 .SearchSpecial(info.integrity_level_symbol);
419 }
420 if (result.is_null()) return {};
421
422 // TODO(olivf, 370536107): For investigating crashes. Should become a CHECK
423 // again once resolved.
424 if (old_map->elements_kind() != (*result)->elements_kind()) {
425 isolate->PushStackTraceAndDie(reinterpret_cast<void*>(old_map.address()),
426 reinterpret_cast<void*>((*result).address()),
427 reinterpret_cast<void*>(root_map.address()));
428 }
429 CHECK_EQ(old_map->instance_type(), (*result)->instance_type());
430 return result;
431}
432
434 InternalIndex modify_index,
435 PropertyConstness new_constness,
436 Representation new_representation,
437 DirectHandle<FieldType> new_field_type) {
438 GeneralizeField(isolate_, map, modify_index, new_constness,
439 new_representation, new_field_type);
440
441 DCHECK(*old_descriptors_ == old_map_->instance_descriptors(isolate_) ||
443 integrity_source_map_->instance_descriptors(isolate_));
444}
445
453
454// static
456 Tagged<Map> initial_map) {
457 // Has to be an initial map.
458 CHECK(IsUndefined(initial_map->GetBackPointer(), isolate));
459
460 const int slack = initial_map->ComputeMinObjectSlack(isolate);
461 DCHECK_GE(slack, 0);
462
463 TransitionsAccessor transitions(isolate, initial_map);
465 if (slack != 0) {
466 // Resize the initial map and all maps in its transition tree.
467 callback = [slack](Tagged<Map> map) {
468#ifdef DEBUG
469 int old_visitor_id = Map::GetVisitorId(map);
470 int new_unused = map->UnusedPropertyFields() - slack;
471#endif
472 map->set_instance_size(map->InstanceSizeFromSlack(slack));
473 map->set_construction_counter(Map::kNoSlackTracking);
474 DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
475 DCHECK_EQ(new_unused, map->UnusedPropertyFields());
476 };
477 } else {
478 // Stop slack tracking for this map.
479 callback = [&](Tagged<Map> map) {
480 map->set_construction_counter(Map::kNoSlackTracking);
481 DCHECK(!TransitionsAccessor(isolate, map).HasSideStepTransitions());
482 };
483 }
484
485 {
486 // The map_updater_access lock is taken here to guarantee atomicity of all
487 // related map changes (instead of guaranteeing only atomicity of each
488 // single map change). This is needed e.g. by InstancesNeedsRewriting,
489 // which expects certain relations between maps to hold.
490 //
491 // Note: Avoid locking the full_transition_array_access lock inside this
492 // call to TraverseTransitionTree to prevent dependencies between the two
493 // locks.
494 base::MutexGuard guard(isolate->map_updater_access());
495 transitions.TraverseTransitionTree(callback);
496 }
497}
498
500 // Updating deprecated maps in-place doesn't make sense.
501 if (old_map_->is_deprecated()) return state_;
502
503 if (new_representation_.IsNone()) return state_; // Not done yet.
504
505 PropertyDetails old_details =
507
508 if (old_details.attributes() != new_attributes_ ||
509 old_details.kind() != new_kind_ ||
510 old_details.location() != new_location_) {
511 // These changes can't be done in-place.
512 return state_; // Not done yet.
513 }
514
515 Representation old_representation = old_details.representation();
516 if (!old_representation.CanBeInPlaceChangedTo(new_representation_)) {
517 return state_; // Not done yet.
518 }
519
520 DCHECK_EQ(new_kind_, old_details.kind());
521 DCHECK_EQ(new_attributes_, old_details.attributes());
523 if (v8_flags.trace_generalization) {
524 PrintGeneralization(
525 isolate_, old_map_, stdout, "uninitialized field", modified_descriptor_,
526 old_nof_, old_nof_, false, old_representation, new_representation_,
527 old_details.constness(), new_constness_,
529 isolate_),
530 {}, new_field_type_, {});
531 }
534 // Check that the descriptor array was updated.
536 .representation()
537 .Equals(new_representation_));
540
542 state_ = kEnd;
543 return state_; // Done.
544}
545
547 // Figure out the most restrictive integrity level transition (it should
548 // be the last one in the transition tree).
551 TransitionsAccessor last_transitions(isolate_, *previous);
552 if (!last_transitions.HasIntegrityLevelTransitionTo(
554 // The last transition was not integrity level transition - just bail out.
555 // This can happen in the following cases:
556 // - there are private symbol transitions following the integrity level
557 // transitions (see crbug.com/v8/8854).
558 // - there is a getter added in addition to an existing setter (or a setter
559 // in addition to an existing getter).
560 return false;
561 }
564
565 // Now walk up the back pointer chain and skip all integrity level
566 // transitions. If we encounter any non-integrity level transition interleaved
567 // with integrity level transitions, just bail out.
568 while (!integrity_source_map_->is_extensible()) {
570 isolate_);
572 if (!transitions.HasIntegrityLevelTransitionTo(*integrity_source_map_)) {
573 return false;
574 }
576 }
577
578 // Integrity-level transitions never change number of descriptors.
579 CHECK_EQ(old_map_->NumberOfOwnDescriptors(),
580 integrity_source_map_->NumberOfOwnDescriptors());
581
584 integrity_source_map_->instance_descriptors(isolate_), isolate_);
585 return true;
586}
587
590
591 if (new_prototype_.is_null()) {
593 }
594
595 // Check the state of the root map.
596 root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
597 ElementsKind from_kind = root_map_->elements_kind();
599
600 if (root_map_->is_deprecated()) {
601 state_ = kEnd;
603 Cast<JSFunction>(root_map_->GetConstructor())->initial_map(), isolate_);
605 DCHECK(result_map_->is_dictionary_map());
606 return state_;
607 }
608
609 // In this first check allow the root map to have the wrong prototype, as we
610 // will deal with prototype transitions later.
611 if (!old_map_->EquivalentToForTransition(
613 v8_flags.move_prototype_transitions_first
614 ? direct_handle(root_map_->prototype(), isolate_)
616 return Normalize("Normalize_NotEquivalent");
617 } else if (old_map_->is_extensible() != root_map_->is_extensible()) {
618 DCHECK(!old_map_->is_extensible());
619 DCHECK(root_map_->is_extensible());
620 // We have an integrity level transition in the tree, let us make a note
621 // of that transition to be able to replay it later.
623 return Normalize("Normalize_PrivateSymbolsOnNonExtensible");
624 }
625
626 // We want to build transitions to the original element kind (before
627 // the seal transitions), so change {to_kind} accordingly.
628 DCHECK(to_kind == DICTIONARY_ELEMENTS ||
629 to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
632 to_kind = integrity_source_map_->elements_kind();
633 }
634
635 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
636 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
637 to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
640 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
641 return Normalize("Normalize_InvalidElementsTransition");
642 }
643
644 int root_nof = root_map_->NumberOfOwnDescriptors();
646 modified_descriptor_.as_int() < root_nof) {
647 PropertyDetails old_details =
649 if (old_details.kind() != new_kind_ ||
650 old_details.attributes() != new_attributes_) {
651 return Normalize("Normalize_RootModification1");
652 }
653 if (old_details.location() != PropertyLocation::kField) {
654 return Normalize("Normalize_RootModification2");
655 }
656 if (!new_representation_.fits_into(old_details.representation())) {
657 return Normalize("Normalize_RootModification4");
658 }
659
660 DCHECK_EQ(PropertyKind::kData, old_details.kind());
663
664 // Modify root map in-place. The GeneralizeField method is a no-op
665 // if the {old_map_} is already general enough to hold the requested
666 // {new_constness_} and {new_field_type_}.
668 old_details.representation(), new_field_type_);
669 }
670
671 // From here on, use the map with correct elements kind and prototype as root
672 // map.
673 if (root_map_->prototype() != *new_prototype_) {
674 DCHECK(v8_flags.move_prototype_transitions_first);
675 Handle<Map> new_root_map_ =
677
678 root_map_ = new_root_map_;
679
680 if (!old_map_->EquivalentToForTransition(
682 return Normalize("Normalize_NotEquivalent");
683 }
684 }
686 DCHECK(old_map_->EquivalentToForTransition(
688
690 return state_; // Not done yet.
691}
692
696
697 int root_nof = root_map_->NumberOfOwnDescriptors();
698 for (InternalIndex i : InternalIndex::Range(root_nof, old_nof_)) {
699 PropertyDetails old_details = GetDetails(i);
700 Handle<Map> tmp_map;
702 isolate_, target_map_, GetKey(i), old_details.kind(),
703 old_details.attributes());
704 if (!maybe_tmp_map.ToHandle(&tmp_map)) break;
705 DirectHandle<DescriptorArray> tmp_descriptors(
706 tmp_map->instance_descriptors(isolate_), isolate_);
707
708 // Check if target map is incompatible.
709 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
710 DCHECK_EQ(old_details.kind(), tmp_details.kind());
711 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
712 if (old_details.kind() == PropertyKind::kAccessor &&
713 !EqualImmutableValues(GetValue(i),
714 tmp_descriptors->GetStrongValue(i))) {
715 // TODO(ishell): mutable accessors are not implemented yet.
716 return Normalize("Normalize_Incompatible");
717 }
718 if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
719 break;
720 }
721 Representation tmp_representation = tmp_details.representation();
722 if (!old_details.representation().fits_into(tmp_representation)) {
723 // Try updating the field in-place to a generalized type.
724 Representation generalized =
725 tmp_representation.generalize(old_details.representation());
726 if (!tmp_representation.CanBeInPlaceChangedTo(generalized)) {
727 break;
728 }
729 tmp_representation = generalized;
730 }
731
732 if (tmp_details.location() == PropertyLocation::kField) {
733 DirectHandle<FieldType> old_field_type =
734 GetOrComputeFieldType(i, old_details.location(), tmp_representation);
735 GeneralizeField(tmp_map, i, old_details.constness(), tmp_representation,
736 old_field_type);
737 } else {
738 // kDescriptor: Check that the value matches.
739 if (!EqualImmutableValues(GetValue(i),
740 tmp_descriptors->GetStrongValue(i))) {
741 break;
742 }
743 }
744 DCHECK(!tmp_map->is_deprecated());
745 target_map_ = tmp_map;
746 }
747
748 // Directly change the map if the target map is more general.
749 int target_nof = target_map_->NumberOfOwnDescriptors();
750 if (target_nof == old_nof_) {
751#ifdef DEBUG
753 Tagged<DescriptorArray> target_descriptors =
754 target_map_->instance_descriptors(isolate_);
755 PropertyDetails details =
756 target_descriptors->GetDetails(modified_descriptor_);
757 DCHECK_EQ(new_kind_, details.kind());
759 details.attributes());
761 DCHECK_EQ(new_location_, details.location());
767 target_descriptors->GetFieldType(modified_descriptor_)));
768 } else {
770 EqualImmutableValues({}, target_descriptors->GetStrongValue(
772 }
773 }
774#endif
775 if (*target_map_ != *old_map_) {
776 old_map_->NotifyLeafMapLayoutChange(isolate_);
777 }
780 state_ = kEnd;
781 return state_; // Done.
782 }
783
784 // We try to replay the integrity level transition here.
787 if (maybe_transition.ToHandle(&result_map_)) {
788 state_ = kEnd;
789 return state_; // Done.
790 }
791 }
792
793 // Find the last compatible target map in the transition tree.
794 for (InternalIndex i : InternalIndex::Range(target_nof, old_nof_)) {
795 PropertyDetails old_details = GetDetails(i);
796 Handle<Map> tmp_map;
798 isolate_, target_map_, GetKey(i), old_details.kind(),
799 old_details.attributes());
800 if (!maybe_tmp_map.ToHandle(&tmp_map)) break;
801 DirectHandle<DescriptorArray> tmp_descriptors(
802 tmp_map->instance_descriptors(isolate_), isolate_);
803#ifdef DEBUG
804 // Check that target map is compatible.
805 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
806 DCHECK_EQ(old_details.kind(), tmp_details.kind());
807 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
808#endif
809 if (old_details.kind() == PropertyKind::kAccessor &&
810 !EqualImmutableValues(GetValue(i),
811 tmp_descriptors->GetStrongValue(i))) {
812 return Normalize("Normalize_Incompatible");
813 }
814 DCHECK(!tmp_map->is_deprecated());
815 target_map_ = tmp_map;
816 }
817
819 return state_; // Not done yet.
820}
821
823 InstanceType instance_type = old_map_->instance_type();
824 int target_nof = target_map_->NumberOfOwnDescriptors();
825 DirectHandle<DescriptorArray> target_descriptors(
826 target_map_->instance_descriptors(isolate_), isolate_);
827
828 // Allocate a new descriptor array large enough to hold the required
829 // descriptors, with minimally the exact same size as the old descriptor
830 // array.
831 int new_slack =
832 std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
833 old_nof_;
834 DirectHandle<DescriptorArray> new_descriptors =
836 DCHECK(new_descriptors->number_of_all_descriptors() >
837 target_descriptors->number_of_all_descriptors() ||
838 new_descriptors->number_of_slack_descriptors() > 0 ||
839 new_descriptors->number_of_descriptors() ==
840 old_descriptors_->number_of_descriptors());
841 DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
842
843 int root_nof = root_map_->NumberOfOwnDescriptors();
844
845 // Given that we passed root modification check in FindRootMap() so
846 // the root descriptors are either not modified at all or already more
847 // general than we requested. Take |root_nof| entries as is.
848 // 0 -> |root_nof|
849 int current_offset = 0;
850 for (InternalIndex i : InternalIndex::Range(root_nof)) {
851 PropertyDetails old_details = old_descriptors_->GetDetails(i);
852 if (old_details.location() == PropertyLocation::kField) {
853 current_offset += old_details.field_width_in_words();
854 }
855#ifdef DEBUG
856 // Ensuring FindRootMap gave us a compatible root map.
857 // TODO(olivf): In some cases it might be nice to be able to generalize the
858 // root map (for instance if the prototype transitions overflowed). For that
859 // we'd need to generalize old_details with the root_details here.
860 PropertyDetails root_details =
861 root_map_->instance_descriptors()->GetDetails(i);
862 DCHECK_EQ(
863 old_details.representation().generalize(root_details.representation()),
864 root_details.representation());
865 if (!root_map_->IsDetached(isolate_)) {
867 root_details.representation()));
868 }
869 DCHECK_LE(old_details.constness(), root_details.constness());
870 DCHECK_EQ(old_details.attributes(), root_details.attributes());
871#endif // DEBUG
872 new_descriptors->Set(i, GetKey(i), old_descriptors_->GetValue(i),
873 old_details);
874 }
875
876 // Merge "updated" old_descriptor entries with target_descriptor entries.
877 // |root_nof| -> |target_nof|
878 for (InternalIndex i : InternalIndex::Range(root_nof, target_nof)) {
880 PropertyDetails old_details = GetDetails(i);
881 PropertyDetails target_details = target_descriptors->GetDetails(i);
882
883 PropertyKind next_kind = old_details.kind();
884 PropertyAttributes next_attributes = old_details.attributes();
885 DCHECK_EQ(next_kind, target_details.kind());
886 DCHECK_EQ(next_attributes, target_details.attributes());
887
888 PropertyConstness next_constness = GeneralizeConstness(
889 old_details.constness(), target_details.constness());
890
891 // Note: failed values equality check does not invalidate per-object
892 // property constness.
893 PropertyLocation next_location =
894 old_details.location() == PropertyLocation::kField ||
895 target_details.location() == PropertyLocation::kField ||
896 !EqualImmutableValues(target_descriptors->GetStrongValue(i),
897 GetValue(i))
900
901 // Ensure that mutable values are stored in fields.
903 next_location == PropertyLocation::kField);
904
905 Representation next_representation =
906 old_details.representation().generalize(
907 target_details.representation());
908
909 if (next_location == PropertyLocation::kField) {
910 DirectHandle<FieldType> old_field_type =
911 GetOrComputeFieldType(i, old_details.location(), next_representation);
912
913 DirectHandle<FieldType> target_field_type =
914 GetOrComputeFieldType(target_descriptors, i,
915 target_details.location(), next_representation);
916
917 DirectHandle<FieldType> next_field_type =
918 GeneralizeFieldType(old_details.representation(), old_field_type,
919 next_representation, target_field_type, isolate_);
920
922 isolate_, instance_type, &next_representation, &next_field_type);
923
924 MaybeObjectDirectHandle wrapped_type(Map::WrapFieldType(next_field_type));
925 Descriptor d;
926 if (next_kind == PropertyKind::kData) {
927 d = Descriptor::DataField(key, current_offset, next_attributes,
928 next_constness, next_representation,
929 wrapped_type);
930 } else {
931 // TODO(ishell): mutable accessors are not implemented yet.
933 }
934 current_offset += d.GetDetails().field_width_in_words();
935 new_descriptors->Set(i, &d);
936 } else {
938 DCHECK_EQ(PropertyConstness::kConst, next_constness);
939
942 Descriptor d = Descriptor::AccessorConstant(key, value, next_attributes);
943 new_descriptors->Set(i, &d);
944 }
945 }
946
947 // Take "updated" old_descriptor entries.
948 // |target_nof| -> |old_nof|
949 for (InternalIndex i : InternalIndex::Range(target_nof, old_nof_)) {
950 PropertyDetails old_details = GetDetails(i);
952
953 PropertyKind next_kind = old_details.kind();
954 PropertyAttributes next_attributes = old_details.attributes();
955 PropertyConstness next_constness = old_details.constness();
956 PropertyLocation next_location = old_details.location();
957 Representation next_representation = old_details.representation();
958
959 if (next_location == PropertyLocation::kField) {
960 DirectHandle<FieldType> next_field_type =
961 GetOrComputeFieldType(i, old_details.location(), next_representation);
962
963 // If the |new_elements_kind_| is still transitionable then the old map's
964 // elements kind is also transitionable and therefore the old descriptors
965 // array must already have generalized field type.
968 Map::IsMostGeneralFieldType(next_representation, *next_field_type));
969
970 MaybeObjectDirectHandle wrapped_type(Map::WrapFieldType(next_field_type));
971 Descriptor d;
972 if (next_kind == PropertyKind::kData) {
973 d = Descriptor::DataField(key, current_offset, next_attributes,
974 next_constness, next_representation,
975 wrapped_type);
976 } else {
977 // TODO(ishell): mutable accessors are not implemented yet.
979 }
980 current_offset += d.GetDetails().field_width_in_words();
981 new_descriptors->Set(i, &d);
982 } else {
984 DCHECK_EQ(PropertyConstness::kConst, next_constness);
985
987 Descriptor d;
988 if (next_kind == PropertyKind::kData) {
989 d = Descriptor::DataConstant(key, value, next_attributes);
990 } else {
992 d = Descriptor::AccessorConstant(key, value, next_attributes);
993 }
994 new_descriptors->Set(i, &d);
995 }
996 }
997
998 new_descriptors->Sort();
999 return new_descriptors;
1000}
1001
1003 DirectHandle<DescriptorArray> descriptors) {
1004 int root_nof = root_map_->NumberOfOwnDescriptors();
1005 Tagged<Map> current = *root_map_;
1006 for (InternalIndex i : InternalIndex::Range(root_nof, old_nof_)) {
1007 Tagged<Name> name = descriptors->GetKey(i);
1008 PropertyDetails details = descriptors->GetDetails(i);
1009 Tagged<Map> next =
1011 .SearchTransition(name, details.kind(), details.attributes());
1012 if (next.is_null()) break;
1013 Tagged<DescriptorArray> next_descriptors =
1014 next->instance_descriptors(isolate_);
1015
1016 PropertyDetails next_details = next_descriptors->GetDetails(i);
1017 DCHECK_EQ(details.kind(), next_details.kind());
1018 DCHECK_EQ(details.attributes(), next_details.attributes());
1019 if (details.constness() != next_details.constness()) break;
1020 if (details.location() != next_details.location()) break;
1021 if (!details.representation().Equals(next_details.representation())) break;
1022
1023 if (next_details.location() == PropertyLocation::kField) {
1024 Tagged<FieldType> next_field_type = next_descriptors->GetFieldType(i);
1025 if (!FieldType::NowIs(descriptors->GetFieldType(i), next_field_type)) {
1026 break;
1027 }
1028 } else {
1029 if (!EqualImmutableValues(descriptors->GetStrongValue(i),
1030 next_descriptors->GetStrongValue(i))) {
1031 break;
1032 }
1033 }
1034 current = next;
1035 }
1036 return direct_handle(current, isolate_);
1037}
1038
1040#ifdef DEBUG
1041 DirectHandle<EnumCache> old_enum_cache(
1042 old_map_->instance_descriptors()->enum_cache(), isolate_);
1043#endif
1045
1046 DirectHandle<Map> split_map = FindSplitMap(new_descriptors);
1047 int split_nof = split_map->NumberOfOwnDescriptors();
1048 if (old_nof_ == split_nof) {
1051 return state_;
1052 }
1053 InternalIndex split_index(split_nof);
1054 PropertyDetails split_details = GetDetails(split_index);
1055
1056 // Invalidate a transition target at |key|.
1057 MaybeDirectHandle<Map> maybe_transition =
1059 isolate_, split_map, GetKey(split_index), split_details.kind(),
1060 split_details.attributes());
1061 if (!maybe_transition.is_null()) {
1062 maybe_transition.ToHandleChecked()->DeprecateTransitionTree(isolate_);
1063 }
1064
1065 // If |maybe_transition| is not nullptr then the transition array already
1066 // contains entry for given descriptor. This means that the transition
1067 // could be inserted regardless of whether transitions array is full or not.
1068 if (maybe_transition.is_null() &&
1070 return Normalize("Normalize_CantHaveMoreTransitions");
1071 }
1072
1073 old_map_->NotifyLeafMapLayoutChange(isolate_);
1074
1075 if (v8_flags.trace_generalization && modified_descriptor_.is_found()) {
1076 PropertyDetails old_details =
1078 PropertyDetails new_details =
1079 new_descriptors->GetDetails(modified_descriptor_);
1080 MaybeDirectHandle<FieldType> old_field_type;
1081 MaybeDirectHandle<FieldType> new_field_type;
1082 MaybeDirectHandle<Object> old_value;
1083 MaybeDirectHandle<Object> new_value;
1084 if (old_details.location() == PropertyLocation::kField) {
1085 old_field_type = direct_handle(
1087 } else {
1088 old_value = direct_handle(
1090 }
1091 if (new_details.location() == PropertyLocation::kField) {
1092 new_field_type = direct_handle(
1093 new_descriptors->GetFieldType(modified_descriptor_), isolate_);
1094 } else {
1095 new_value = direct_handle(
1096 new_descriptors->GetStrongValue(modified_descriptor_), isolate_);
1097 }
1098
1099 PrintGeneralization(
1100 isolate_, old_map_, stdout, "", modified_descriptor_, split_nof,
1101 old_nof_,
1102 old_details.location() == PropertyLocation::kDescriptor &&
1104 old_details.representation(), new_details.representation(),
1105 old_details.constness(), new_details.constness(), old_field_type,
1106 old_value, new_field_type, new_value);
1107 }
1108
1109 Handle<Map> new_map =
1110 Map::AddMissingTransitions(isolate_, split_map, new_descriptors);
1111
1112 bool had_any_enum_cache =
1113 split_map->instance_descriptors(isolate_)
1114 ->enum_cache()
1115 ->keys()
1116 ->length() > 0 ||
1117 old_descriptors_->enum_cache()->keys()->length() > 0;
1118
1119 // Deprecated part of the transition tree is no longer reachable, so replace
1120 // current instance descriptors in the "survived" part of the tree with
1121 // the new descriptors to maintain descriptors sharing invariant.
1122 split_map->ReplaceDescriptors(isolate_, *new_descriptors);
1123
1124 // If the old descriptors had an enum cache (or if {split_map}'s descriptors
1125 // had one), make sure the new ones do too.
1126 if (had_any_enum_cache && new_map->NumberOfEnumerableProperties() > 0) {
1128 isolate_, new_map, new_map->NumberOfEnumerableProperties());
1129 }
1130
1131 // The old map has to still point to the old enum cache. This is because we
1132 // might have cached the enum indices, for iterating over objects with the old
1133 // map -- we don't want this enum cache to move ownership to the new branch,
1134 // because then it might get trimmed past the old map's field count.
1135 DCHECK_EQ(old_map_->instance_descriptors()->enum_cache(), *old_enum_cache);
1136
1138 target_map_ = new_map;
1140 } else {
1141 result_map_ = new_map;
1142 state_ = kEnd;
1143 }
1144 return state_; // Done.
1145}
1146
1149
1151 return Normalize("Normalize_CantHaveMoreTransitions");
1152 }
1153
1156 "CopyForPreventExtensions",
1157 old_map_->elements_kind() == DICTIONARY_ELEMENTS);
1158 DCHECK_IMPLIES(old_map_->elements_kind() == DICTIONARY_ELEMENTS,
1159 result_map_->elements_kind() == DICTIONARY_ELEMENTS);
1160
1161 state_ = kEnd;
1162 return state_;
1163}
1164
1165namespace {
1166
1167void PrintReconfiguration(Isolate* isolate, DirectHandle<Map> map, FILE* file,
1168 InternalIndex modify_index, PropertyKind kind,
1169 PropertyAttributes attributes) {
1170 OFStream os(file);
1171 os << "[reconfiguring]";
1172 Tagged<Name> name = map->instance_descriptors(isolate)->GetKey(modify_index);
1173 if (IsString(name)) {
1174 Cast<String>(name)->PrintOn(file);
1175 } else {
1176 os << "{symbol " << reinterpret_cast<void*>(name.ptr()) << "}";
1177 }
1178 os << ": " << (kind == PropertyKind::kData ? "kData" : "ACCESSORS")
1179 << ", attrs: ";
1180 os << attributes << " [";
1181 JavaScriptFrame::PrintTop(isolate, file, false, true);
1182 os << "]\n";
1183}
1184
1185} // namespace
1186
1187// static
1189 Isolate* isolate, DirectHandle<Map> map, InternalIndex descriptor,
1191 PropertyConstness constness) {
1192 // Dictionaries have to be reconfigured in-place.
1193 DCHECK(!map->is_dictionary_map());
1194 DCHECK_EQ(PropertyKind::kData, kind); // Only kData case is supported so far.
1195
1196 if (!IsMap(map->GetBackPointer())) {
1197 // There is no benefit from reconstructing transition tree for maps without
1198 // back pointers, normalize and try to hit the map cache instead.
1199 return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES,
1200 "Normalize_AttributesMismatchProtoMap");
1201 }
1202
1203 if (v8_flags.trace_generalization) {
1204 PrintReconfiguration(isolate, map, stdout, descriptor, kind, attributes);
1205 }
1206
1208 descriptor, attributes, constness, Representation::None(),
1209 FieldType::None(isolate));
1210}
1211
1212// static
1214 InternalIndex descriptor,
1215 DirectHandle<Name> name,
1216 PropertyConstness new_constness,
1217 Representation new_representation,
1218 DirectHandle<FieldType> new_type) {
1219 // We store raw pointers in the queue, so no allocations are allowed.
1221 PropertyDetails details =
1222 map->instance_descriptors(isolate)->GetDetails(descriptor);
1223 if (details.location() != PropertyLocation::kField) return;
1224 CHECK_EQ(PropertyKind::kData, details.kind());
1225
1226 if (new_constness != details.constness() && map->is_prototype_map()) {
1228 }
1229
1230 std::queue<Tagged<Map>> backlog;
1231 backlog.push(*map);
1232 std::vector<Tagged<Map>> sidestep_transition;
1233
1234 ReadOnlyRoots roots(isolate);
1235 while (!backlog.empty()) {
1236 Tagged<Map> current = backlog.front();
1237 backlog.pop();
1238
1239 TransitionsAccessor transitions(isolate, current);
1240 transitions.ForEachTransition(
1241 &no_gc, [&](Tagged<Map> target) { backlog.push(target); },
1242 [&](Tagged<Map> target) {
1243 if (v8_flags.move_prototype_transitions_first) {
1244 backlog.push(target);
1245 }
1246 },
1247 [&](Tagged<Object> target) {
1248 if (!target.IsSmi() && !Cast<Map>(target)->is_deprecated()) {
1249 sidestep_transition.push_back(Cast<Map>(target));
1250 }
1251 });
1252
1253 Tagged<DescriptorArray> descriptors =
1254 current->instance_descriptors(isolate);
1255 details = descriptors->GetDetails(descriptor);
1256
1257 // It is allowed to change representation here only from None
1258 // to something or from Smi or HeapObject to Tagged.
1259 CHECK(details.representation().Equals(new_representation) ||
1260 details.representation().CanBeInPlaceChangedTo(new_representation));
1261
1262 // Skip if we already updated the shared descriptor or the target was more
1263 // general in the first place.
1264 if (new_constness == details.constness() &&
1265 new_representation.Equals(details.representation()) &&
1266 FieldType::Equals(descriptors->GetFieldType(descriptor), *new_type)) {
1267 continue;
1268 }
1269
1270 DCHECK_IMPLIES(IsClass(*new_type), new_representation.IsHeapObject());
1271 MaybeObjectDirectHandle wrapped_type(Map::WrapFieldType(new_type));
1273 name, descriptors->GetFieldIndex(descriptor), details.attributes(),
1274 new_constness, new_representation, wrapped_type);
1275 DCHECK_EQ(descriptors->GetKey(descriptor), *d.key_);
1276 descriptors->Replace(descriptor, &d);
1277 }
1278
1279 for (Tagged<Map> current : sidestep_transition) {
1280 Tagged<DescriptorArray> descriptors =
1281 current->instance_descriptors(isolate);
1282 details = descriptors->GetDetails(descriptor);
1283 // Through side-steps we can reach transition trees which are already more
1284 // generalized. Ensure we don't re-concretize them.
1285 PropertyConstness cur_new_constness =
1286 GeneralizeConstness(new_constness, details.constness());
1287 Representation cur_new_representation =
1288 new_representation.generalize(details.representation());
1289 DirectHandle<FieldType> cur_new_type = GeneralizeFieldType(
1290 details.representation(),
1291 direct_handle(descriptors->GetFieldType(descriptor), isolate),
1292 cur_new_representation, new_type, isolate);
1293 CHECK(new_representation.fits_into(cur_new_representation));
1294 // Skip if we already updated the shared descriptor or the target was more
1295 // general in the first place.
1296 if (cur_new_constness != details.constness() ||
1297 !cur_new_representation.Equals(details.representation()) ||
1298 !FieldType::Equals(descriptors->GetFieldType(descriptor),
1299 *cur_new_type)) {
1300 GeneralizeField(isolate, direct_handle(current, isolate), descriptor,
1301 cur_new_constness, cur_new_representation, cur_new_type);
1302 }
1303 }
1304}
1305
1306// TODO(jgruber): Lock the map-updater mutex.
1307// static
1309 InternalIndex modify_index,
1310 PropertyConstness new_constness,
1311 Representation new_representation,
1312 DirectHandle<FieldType> new_field_type) {
1313 CHECK(!map->is_deprecated());
1314
1315 // Check if we actually need to generalize the field type at all.
1316 DirectHandle<DescriptorArray> old_descriptors(
1317 map->instance_descriptors(isolate), isolate);
1318 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
1319 PropertyConstness old_constness = old_details.constness();
1320 Representation old_representation = old_details.representation();
1321 DirectHandle<FieldType> old_field_type(
1322 old_descriptors->GetFieldType(modify_index), isolate);
1323 CHECK_IMPLIES(IsClass(*old_field_type), old_representation.IsHeapObject());
1324
1325 // Return if the current map is general enough to hold requested constness and
1326 // representation/field type.
1327 if (IsGeneralizableTo(new_constness, old_constness) &&
1328 old_representation.Equals(new_representation) &&
1329 FieldType::NowIs(*new_field_type, old_field_type)) {
1331 *GeneralizeFieldType(old_representation, old_field_type,
1332 new_representation, new_field_type, isolate),
1333 old_field_type));
1334 return;
1335 }
1336
1337 // Determine the field owner.
1338 DirectHandle<Map> field_owner(map->FindFieldOwner(isolate, modify_index),
1339 isolate);
1341 field_owner->instance_descriptors(isolate), isolate);
1342 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
1343
1344 new_field_type =
1345 GeneralizeFieldType(old_representation, old_field_type,
1346 new_representation, new_field_type, isolate);
1347
1348 new_constness = GeneralizeConstness(old_constness, new_constness);
1349
1350 PropertyDetails details = descriptors->GetDetails(modify_index);
1351 DirectHandle<Name> name(descriptors->GetKey(modify_index), isolate);
1352
1353 UpdateFieldType(isolate, field_owner, modify_index, name, new_constness,
1354 new_representation, new_field_type);
1355
1356 DCHECK_IMPLIES(IsClass(*new_field_type), new_representation.IsHeapObject());
1357
1359 if (new_constness != old_constness) {
1360 dep_groups |= DependentCode::kFieldConstGroup;
1361 }
1362 if (!FieldType::Equals(*new_field_type, *old_field_type)) {
1363 dep_groups |= DependentCode::kFieldTypeGroup;
1364 }
1365 if (!new_representation.Equals(old_representation)) {
1367 }
1368
1369 DependentCode::DeoptimizeDependencyGroups(isolate, *field_owner, dep_groups);
1370
1371 if (v8_flags.trace_generalization) {
1372 PrintGeneralization(
1373 isolate, map, stdout, "field type generalization", modify_index,
1374 map->NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors(), false,
1375 details.representation(),
1376 descriptors->GetDetails(modify_index).representation(), old_constness,
1377 new_constness, old_field_type, MaybeDirectHandle<Object>(),
1378 new_field_type, MaybeDirectHandle<Object>());
1379 }
1380}
1381
1382} // namespace v8::internal
Isolate * isolate_
Builtins::Kind kind
Definition builtins.cc:40
static void DeoptimizeDependencyGroups(Isolate *isolate, ObjectT object, DependencyGroups groups)
static V8_EXPORT_PRIVATE Handle< DescriptorArray > Allocate(IsolateT *isolate, int nof_descriptors, int slack, AllocationType allocation=AllocationType::kYoung)
static Descriptor DataField(Isolate *isolate, DirectHandle< Name > key, int field_index, PropertyAttributes attributes, Representation representation)
Definition property.cc:81
static Descriptor AccessorConstant(DirectHandle< Name > key, DirectHandle< Object > foreign, PropertyAttributes attributes)
Definition property.cc:118
static Descriptor DataConstant(DirectHandle< Name > key, DirectHandle< Object > value, PropertyAttributes attributes)
Definition property.cc:100
PropertyDetails GetDetails() const
Definition property.h:31
static Handle< FixedArray > InitializeFastPropertyEnumCache(Isolate *isolate, DirectHandle< Map > map, int enum_length, AllocationType allocation=AllocationType::kOld)
Definition keys.cc:513
static V8_EXPORT_PRIVATE void PrintTo(Tagged< FieldType > type, std::ostream &os)
Definition field-type.cc:94
static V8_EXPORT_PRIVATE bool Equals(Tagged< FieldType > type, Tagged< FieldType > other)
Definition field-type.cc:79
static V8_EXPORT_PRIVATE Tagged< FieldType > Any()
Definition field-type.cc:22
static V8_EXPORT_PRIVATE Tagged< FieldType > None()
Definition field-type.cc:17
static bool NowIs(Tagged< FieldType > type, Tagged< FieldType > other)
Definition field-type.cc:68
constexpr int as_int() const
LocalIsolate * main_thread_local_isolate()
Definition isolate.h:2183
base::Mutex * map_updater_access()
Definition isolate.h:760
static Tagged< Map > InvalidatePrototypeChains(Tagged< Map > map)
static void PrintTop(Isolate *isolate, FILE *file, bool print_args, bool print_line_number)
Definition frames.cc:2562
State ConstructNewMapWithIntegrityLevelTransition()
PropertyLocation new_location_
static void GeneralizeField(Isolate *isolate, DirectHandle< Map > map, InternalIndex modify_index, PropertyConstness new_constness, Representation new_representation, DirectHandle< FieldType > new_field_type)
static void UpdateFieldType(Isolate *isolate, DirectHandle< Map > map, InternalIndex descriptor_number, DirectHandle< Name > name, PropertyConstness new_constness, Representation new_representation, DirectHandle< FieldType > new_type)
Tagged< FieldType > GetFieldType(InternalIndex descriptor) const
DirectHandle< FieldType > new_field_type_
Representation new_representation_
static void CompleteInobjectSlackTracking(Isolate *isolate, Tagged< Map > initial_map)
DirectHandle< FieldType > GetOrComputeFieldType(InternalIndex descriptor, PropertyLocation location, Representation representation) const
Handle< Map > ReconfigureToDataField(InternalIndex descriptor, PropertyAttributes attributes, PropertyConstness constness, Representation representation, DirectHandle< FieldType > field_type)
Handle< Map > UpdateImpl()
Handle< Map > target_map_
State Normalize(const char *reason)
DirectHandle< Map > ReconfigureElementsKind(ElementsKind elements_kind)
Tagged< Name > GetKey(InternalIndex descriptor) const
Handle< Map > ApplyPrototypeTransition(DirectHandle< JSPrototype > prototype)
PropertyConstness new_constness_
PropertyDetails GetDetails(InternalIndex descriptor) const
PropertyAttributes new_attributes_
DirectHandle< Map > old_map_
State TryReconfigureToDataFieldInplace()
Handle< Map > result_map_
Tagged< Object > GetValue(InternalIndex descriptor) const
static std::optional< Tagged< Map > > TryUpdateNoLock(Isolate *isolate, Tagged< Map > old_map, ConcurrencyMode cmode) V8_WARN_UNUSED_RESULT
ElementsKind new_elements_kind_
DirectHandle< Symbol > integrity_level_symbol_
InternalIndex modified_descriptor_
static Handle< Map > ReconfigureExistingProperty(Isolate *isolate, DirectHandle< Map > map, InternalIndex descriptor, PropertyKind kind, PropertyAttributes attributes, PropertyConstness constness)
DirectHandle< Map > FindSplitMap(DirectHandle< DescriptorArray > descriptors)
static DirectHandle< Map > UpdateMapNoLock(Isolate *isolate, DirectHandle< Map > old_map)
DirectHandle< Map > integrity_source_map_
DirectHandle< DescriptorArray > old_descriptors_
MapUpdater(Isolate *isolate, DirectHandle< Map > old_map)
DirectHandle< JSPrototype > new_prototype_
PropertyAttributes integrity_level_
DirectHandle< DescriptorArray > BuildDescriptorArray()
static V8_EXPORT_PRIVATE Handle< Map > TransitionToUpdatePrototype(Isolate *isolate, DirectHandle< Map > map, DirectHandle< JSPrototype > prototype)
Definition map.cc:2506
static Handle< Map > CopyForPrototypeTransition(Isolate *isolate, DirectHandle< Map > map, DirectHandle< JSPrototype > prototype)
Definition map.cc:1800
static const int kNoSlackTracking
Definition map.h:349
static MaybeObjectDirectHandle WrapFieldType(DirectHandle< FieldType > type)
Definition map.cc:487
static bool IsMostGeneralFieldType(Representation representation, Tagged< FieldType > field_type)
Definition map-inl.h:157
static V8_EXPORT_PRIVATE Handle< Map > Normalize(Isolate *isolate, DirectHandle< Map > map, ElementsKind new_elements_kind, DirectHandle< JSPrototype > new_prototype, PropertyNormalizationMode mode, bool use_cache, const char *reason)
Definition map.cc:1282
static V8_EXPORT_PRIVATE Handle< Map > CopyForPreventExtensions(Isolate *isolate, DirectHandle< Map > map, PropertyAttributes attrs_to_add, DirectHandle< Symbol > transition_marker, const char *reason, bool old_map_is_dictionary_elements_kind=false)
Definition map.cc:1852
static void GeneralizeIfCanHaveTransitionableFastElementsKind(Isolate *isolate, InstanceType instance_type, Representation *representation, DirectHandle< FieldType > *field_type)
Definition map-inl.h:180
static V8_EXPORT_PRIVATE VisitorId GetVisitorId(Tagged< Map > map)
Definition map.cc:65
static V8_EXPORT_PRIVATE Handle< Map > AsElementsKind(Isolate *isolate, DirectHandle< Map > map, ElementsKind kind)
Definition map.cc:1163
static V8_EXPORT_PRIVATE Handle< Map > AddMissingTransitions(Isolate *isolate, DirectHandle< Map > map, DirectHandle< DescriptorArray > descriptors)
Definition map.cc:1618
V8_INLINE DirectHandle< T > ToHandleChecked() const
V8_INLINE bool is_null() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(Handle< S > *out) const
static DirectHandle< FieldType > OptimalType(Tagged< Object > obj, Isolate *isolate, Representation representation)
Definition objects.cc:224
PropertyAttributes attributes() const
PropertyLocation location() const
Representation representation() const
PropertyConstness constness() const
constexpr bool IsHeapObject() const
bool fits_into(const Representation &other) const
constexpr bool IsNone() const
bool IsCompatibleForLoad(const Representation &other) const
Representation generalize(Representation other)
bool Equals(const Representation &other) const
static constexpr Representation None()
bool CanBeInPlaceChangedTo(const Representation &other) const
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static bool CanHaveMoreTransitions(Isolate *isolate, DirectHandle< Map > map)
static std::optional< Tagged< Map > > GetPrototypeTransition(Isolate *isolate, Tagged< Map > map, Tagged< Object > prototype)
Tagged< Map > SearchTransition(Tagged< Name > name, PropertyKind kind, PropertyAttributes attributes)
static void SetMigrationTarget(Isolate *isolate, DirectHandle< Map > map, Tagged< Map > migration_target)
std::function< void(Tagged< Map >)> TraverseCallback
Tagged< Map > SearchSpecial(Tagged< Symbol > name)
bool HasIntegrityLevelTransitionTo(Tagged< Map > to, Tagged< Symbol > *out_symbol=nullptr, PropertyAttributes *out_integrity_level=nullptr)
Handle< SharedFunctionInfo > info
LineAndColumn previous
Isolate * isolate
TNode< Object > target
TNode< Object > callback
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
Tagged< Symbol > integrity_level_symbol
bool has_integrity_level_transition
PropertyAttributes integrity_level
Tagged< Map > integrity_level_source_map
void split(const std::string &str, char delimiter, std::vector< std::string > *vparams)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
bool IsAnyHoleyNonextensibleElementsKind(ElementsKind kind)
bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, ElementsKind to_kind)
Tagged(T object) -> Tagged< T >
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
bool IsAnyNonextensibleElementsKind(ElementsKind kind)
@ SLOW_STRING_WRAPPER_ELEMENTS
@ SLOW_SLOPPY_ARGUMENTS_ELEMENTS
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
PropertyConstness GeneralizeConstness(PropertyConstness a, PropertyConstness b)
bool IsClass(Tagged< FieldType > obj)
Definition field-type.cc:48
instance_descriptors
Definition map-inl.h:52
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsGeneralizableTo(PropertyLocation a, PropertyLocation b)
return value
Definition map-inl.h:893
bool IsTypedArrayOrRabGsabTypedArrayElementsKind(ElementsKind kind)
bool IsTransitionableFastElementsKind(ElementsKind from_kind)
constexpr bool IsConcurrent(ConcurrencyMode mode)
Definition globals.h:2599
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset prototype
Definition map-inl.h:69
@ CLEAR_INOBJECT_PROPERTIES
Definition objects.h:61
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_IMPLIES(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_UNLIKELY(condition)
Definition v8config.h:660