v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
transitions.cc
Go to the documentation of this file.
1// Copyright 2012 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
12#include "src/utils/utils.h"
13
14namespace v8::internal {
15
16// static
20 map->raw_transitions(isolate, kAcquireLoad);
21 switch (GetEncoding(isolate, raw_transitions)) {
22 case kWeakRef:
23 return Cast<Map>(raw_transitions.GetHeapObjectAssumeWeak());
24 default:
25 return Tagged<Map>();
26 }
27}
28
30 switch (encoding()) {
31 case kWeakRef:
32 return raw_transitions_.GetHeapObjectAssumeWeak() == map;
33 case kPrototypeInfo:
34 case kUninitialized:
37 return false;
38 }
40}
41
42// static
45 DirectHandle<Map> target,
46 TransitionKindFlag flag) {
48 Encoding encoding = GetEncoding(isolate, map);
50 ReadOnlyRoots roots(isolate);
51 (*target)->SetBackPointer(*map);
52
53 // If the map doesn't have any transitions at all yet, install the new one.
55 if (flag == SIMPLE_PROPERTY_TRANSITION) {
56 ReplaceTransitions(isolate, map, MakeWeak(*target));
57 return;
58 }
59 // If the flag requires a full TransitionArray, allocate one.
61 isolate->factory()->NewTransitionArray(1, 0);
62 result->Set(0, *name, MakeWeak(*target));
63 ReplaceTransitions(isolate, map, result);
65 return;
66 }
67
68 if (encoding == kWeakRef) {
69 Tagged<Map> simple_transition = GetSimpleTransition(isolate, map);
70 DCHECK(!simple_transition.is_null());
71
72 if (flag == SIMPLE_PROPERTY_TRANSITION) {
73 Tagged<Name> key = GetSimpleTransitionKey(simple_transition);
74 PropertyDetails old_details =
75 simple_transition->GetLastDescriptorDetails(isolate);
76 PropertyDetails new_details = GetTargetDetails(*name, **target);
77 if (key->Equals(*name) && old_details.kind() == new_details.kind() &&
78 old_details.attributes() == new_details.attributes()) {
79 ReplaceTransitions(isolate, map, MakeWeak(*target));
80 return;
81 }
82 }
83
84 // Otherwise allocate a full TransitionArray with slack for a new entry.
86 isolate->factory()->NewTransitionArray(1, 1);
87
88 // Reload `simple_transition`. Allocations might have caused it to be
89 // cleared.
90 simple_transition = GetSimpleTransition(isolate, map);
91 if (simple_transition.is_null()) {
92 result->Set(0, *name, MakeWeak(*target));
93 ReplaceTransitions(isolate, map, result);
95 return;
96 }
97
98 // Insert the original transition in index 0.
99 result->Set(0, GetSimpleTransitionKey(simple_transition),
100 MakeWeak(simple_transition));
101
102 // Search for the correct index to insert the new transition.
103 int insertion_index;
104 int index;
105 if (flag == SPECIAL_TRANSITION) {
106 index =
107 result->SearchSpecial(Cast<Symbol>(*name), false, &insertion_index);
108 } else {
109 PropertyDetails details = GetTargetDetails(*name, **target);
110 index = result->Search(details.kind(), *name, details.attributes(),
111 &insertion_index);
112 }
113 DCHECK_EQ(index, kNotFound);
114 USE(index);
115
116 result->SetNumberOfTransitions(2);
117 if (insertion_index == 0) {
118 // If the new transition will be inserted in index 0, move the original
119 // transition to index 1.
120 result->Set(1, GetSimpleTransitionKey(simple_transition),
121 MakeWeak(simple_transition));
122 }
123 result->SetKey(insertion_index, *name);
124 result->SetRawTarget(insertion_index, MakeWeak(*target));
125
126 SLOW_DCHECK(result->IsSortedNoDuplicates());
127 ReplaceTransitions(isolate, map, result);
129 return;
130 }
131
132 // At this point, we know that the map has a full TransitionArray.
134
135 int number_of_transitions = 0;
136 int new_nof = 0;
137 int insertion_index = kNotFound;
138 const bool is_special_transition = flag == SPECIAL_TRANSITION;
139 DCHECK_EQ(is_special_transition, IsSpecialTransition(roots, *name));
140 PropertyDetails details = is_special_transition
142 : GetTargetDetails(*name, **target);
143
144 {
146 Tagged<TransitionArray> array = GetTransitionArray(isolate, map);
147 number_of_transitions = array->number_of_transitions();
148
149 int index =
150 is_special_transition
151 ? array->SearchSpecial(Cast<Symbol>(*name), false, &insertion_index)
152 : array->Search(details.kind(), *name, details.attributes(),
153 &insertion_index);
154 // If an existing entry was found, overwrite it and return.
155 if (index != kNotFound) {
156 base::MutexGuard mutex_guard(isolate->full_transition_array_access());
157 array->SetRawTarget(index, MakeWeak(*target));
158 return;
159 }
160
161 new_nof = number_of_transitions + 1;
163 DCHECK_GE(insertion_index, 0);
164 DCHECK_LE(insertion_index, number_of_transitions);
165
166 // If there is enough capacity, insert new entry into the existing array.
167 if (new_nof <= array->Capacity()) {
168 base::MutexGuard mutex_guard(isolate->full_transition_array_access());
169 array->SetNumberOfTransitions(new_nof);
170 for (int i = number_of_transitions; i > insertion_index; --i) {
171 array->SetKey(i, array->GetKey(i - 1));
172 array->SetRawTarget(i, array->GetRawTarget(i - 1));
173 }
174 array->SetKey(insertion_index, *name);
175 array->SetRawTarget(insertion_index, MakeWeak(*target));
176 SLOW_DCHECK(array->IsSortedNoDuplicates());
177 return;
178 }
179 }
180
181 // We're gonna need a bigger TransitionArray.
182 DirectHandle<TransitionArray> result = isolate->factory()->NewTransitionArray(
183 new_nof,
184 Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
185
186 // The map's transition array may have shrunk during the allocation above as
187 // it was weakly traversed, though it is guaranteed not to disappear. Trim the
188 // result copy if needed, and recompute variables.
190 Tagged<TransitionArray> array = GetTransitionArray(isolate, map);
191 if (array->number_of_transitions() != number_of_transitions) {
192 DCHECK_LT(array->number_of_transitions(), number_of_transitions);
193
194 int index =
195 is_special_transition
196 ? array->SearchSpecial(Cast<Symbol>(*name), false, &insertion_index)
197 : array->Search(details.kind(), *name, details.attributes(),
198 &insertion_index);
199 CHECK_EQ(index, kNotFound);
200 USE(index);
201 DCHECK_GE(insertion_index, 0);
202 DCHECK_LE(insertion_index, number_of_transitions);
203
204 number_of_transitions = array->number_of_transitions();
205 new_nof = number_of_transitions + 1;
206 result->SetNumberOfTransitions(new_nof);
207 }
208
209 if (array->HasPrototypeTransitions()) {
210 result->SetPrototypeTransitions(array->GetPrototypeTransitions());
211 }
212 if (array->HasSideStepTransitions()) {
213 result->SetSideStepTransitions(array->GetSideStepTransitions());
214 }
215
216 DCHECK_NE(kNotFound, insertion_index);
217 for (int i = 0; i < insertion_index; ++i) {
218 result->Set(i, array->GetKey(i), array->GetRawTarget(i));
219 }
220 result->Set(insertion_index, *name, MakeWeak(*target));
221 for (int i = insertion_index; i < number_of_transitions; ++i) {
222 result->Set(i + 1, array->GetKey(i), array->GetRawTarget(i));
223 }
224
225 SLOW_DCHECK(result->IsSortedNoDuplicates());
226 ReplaceTransitions(isolate, map, result);
227}
228
231 DCHECK(IsUniqueName(name));
232 switch (encoding()) {
233 case kPrototypeInfo:
234 case kUninitialized:
235 case kMigrationTarget:
236 return Tagged<Map>();
237 case kWeakRef: {
238 Tagged<Map> map = Cast<Map>(raw_transitions_.GetHeapObjectAssumeWeak());
239 if (!IsMatchingMap(map, name, kind, attributes)) return Tagged<Map>();
240 return map;
241 }
245 return transitions()->SearchAndGetTarget(kind, name, attributes);
246 }
247 }
248 UNREACHABLE();
249}
250
252 if (encoding() != kFullTransitionArray) return {};
255 int transition = transitions()->SearchSpecial(name, concurrent_access_);
256 if (transition == kNotFound) return {};
257 return transitions()->GetTarget(transition);
258}
259
260// static
262 Tagged<Name> name) {
263 if (!IsSymbol(name)) return false;
264 return name == roots.nonextensible_symbol() ||
265 name == roots.sealed_symbol() || name == roots.frozen_symbol() ||
266 name == roots.elements_transition_symbol() ||
267 name == roots.strict_function_transition_symbol();
268}
269
272 DCHECK(IsInternalizedString(*name));
275 if (target.is_null()) return MaybeHandle<Map>();
276#ifdef DEBUG
277 PropertyDetails details = target->GetLastDescriptorDetails(isolate_);
278 DCHECK_EQ(NONE, details.attributes());
281#endif
282 return Handle<Map>(target, isolate_);
283}
284
288 DCHECK(IsUniqueName(name));
289 switch (encoding()) {
290 case kPrototypeInfo:
291 case kUninitialized:
292 case kMigrationTarget:
293 return;
294 case kWeakRef: {
295 Tagged<Map> target =
296 Cast<Map>(raw_transitions_.GetHeapObjectAssumeWeak());
297 InternalIndex descriptor = target->LastAdded();
298 Tagged<DescriptorArray> descriptors =
299 target->instance_descriptors(kRelaxedLoad);
300 Tagged<Name> key = descriptors->GetKey(descriptor);
301 if (key == name) {
302 callback(target);
303 }
304 return;
305 }
309 return transitions()->ForEachTransitionTo(name, callback);
310 }
311 }
312 UNREACHABLE();
313}
314
315// static
317 DirectHandle<Map> map) {
318 if (map->is_dictionary_map()) return false;
320 map->raw_transitions(isolate, kAcquireLoad);
322 return GetTransitionArray(isolate, raw_transitions)
323 ->number_of_transitions() < kMaxNumberOfTransitions;
324 }
325 return true;
326}
327
328// static
331 PropertyAttributes attributes) {
332 InternalIndex descriptor = target->LastAdded();
333 Tagged<DescriptorArray> descriptors =
334 target->instance_descriptors(kRelaxedLoad);
335 Tagged<Name> key = descriptors->GetKey(descriptor);
336 if (key != name) return false;
337 return descriptors->GetDetails(descriptor)
338 .HasKindAndAttributes(kind, attributes);
339}
340
341// static
343 Isolate* isolate, Tagged<WeakFixedArray> array) {
344 const int header = kProtoTransitionHeaderSize;
346 if (number_of_transitions == 0) {
347 // Empty array cannot be compacted.
348 return false;
349 }
350 int new_number_of_transitions = 0;
351 for (int i = 0; i < number_of_transitions; i++) {
352 Tagged<MaybeObject> target = array->get(header + i);
353 DCHECK(target.IsCleared() ||
354 (target.IsWeak() && IsMap(target.GetHeapObject())));
355 if (!target.IsCleared()) {
356 if (new_number_of_transitions != i) {
357 array->set(header + new_number_of_transitions, target);
358 }
359 new_number_of_transitions++;
360 }
361 }
362 // Fill slots that became free with undefined value.
363 Tagged<MaybeObject> undefined = *isolate->factory()->undefined_value();
364 for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
365 array->set(header + i, undefined);
366 }
367 if (number_of_transitions != new_number_of_transitions) {
368 SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
369 }
370 return new_number_of_transitions < number_of_transitions;
371}
372
373// static
375 DirectHandle<WeakFixedArray> array, int new_capacity, Isolate* isolate) {
376 // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
377 int capacity = array->length() - kProtoTransitionHeaderSize;
378 new_capacity = std::min({kMaxCachedPrototypeTransitions, new_capacity});
379 DCHECK_GT(new_capacity, capacity);
380 int grow_by = new_capacity - capacity;
382 isolate->factory()->CopyWeakFixedArrayAndGrow(array, grow_by);
383 if (capacity < 0) {
384 // There was no prototype transitions array before, so the size
385 // couldn't be copied. Initialize it explicitly.
386 SetNumberOfPrototypeTransitions(*new_array, 0);
387 }
388 return new_array;
389}
390
391// static
394 DirectHandle<Object> prototype,
395 DirectHandle<Map> target_map) {
396 DCHECK_IMPLIES(v8_flags.move_prototype_transitions_first,
397 IsUndefined(map->GetBackPointer()));
398 DCHECK(IsMap(Cast<HeapObject>(*prototype)->map()));
399
400 // Only the main thread should write to transition arrays.
401 DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
402
403 // It's OK to read the transition array without holding the
404 // full_transition_array_access lock in read mode, since this is only called
405 // in the main thread, and the main thread is the only writer. In addition, we
406 // shouldn't GC while holding the lock, because it will cause a deadlock if a
407 // background thread is waiting for the shared mutex outside of a safepoint.
408
409 // Don't cache prototype transition if this map is either shared, or a map of
410 // a prototype.
411 if (map->is_prototype_map()) return false;
412 if (map->is_dictionary_map() || !v8_flags.cache_prototype_transitions)
413 return false;
414
416
418 isolate);
419 int capacity = cache->length() - header;
420 int transitions = TransitionArray::NumberOfPrototypeTransitions(*cache) + 1;
421
422 if (transitions > capacity) {
423 // Grow the array if compacting it doesn't free space.
424 bool compacted;
425 {
426 base::MutexGuard guard(isolate->full_transition_array_access());
428 compacted =
430 }
431 if (!compacted) {
433 return false;
434
436 cache, 2 * transitions, isolate);
437 SetPrototypeTransitions(isolate, map, cache);
438 }
439 }
440
441 if (v8_flags.move_prototype_transitions_first) {
442 target_map->SetBackPointer(*map);
443 }
444
445 // Reload number of transitions as they might have been compacted.
447 int entry = header + last;
448
449 {
450 base::MutexGuard guard(isolate->full_transition_array_access());
452 cache->set(entry, MakeWeak(*target_map));
454 }
455 return true;
456}
457
458// static
460 Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype) {
464 for (int i = 0; i < length; i++) {
465 Tagged<MaybeObject> target =
467 DCHECK(target.IsWeakOrCleared());
468 Tagged<HeapObject> heap_object;
469 if (target.GetHeapObjectIfWeak(&heap_object)) {
470 Tagged<Map> target_map = Cast<Map>(heap_object);
471 if (target_map->prototype() == prototype) {
472 return target_map;
473 }
474 }
475 }
476 return {};
477}
478
479// static
481 Isolate* isolate, Tagged<Map> map) {
483 map->raw_transitions(isolate, kAcquireLoad);
485 return ReadOnlyRoots(isolate).empty_weak_fixed_array();
486 }
487 Tagged<TransitionArray> transition_array =
489 if (!transition_array->HasPrototypeTransitions()) {
490 return ReadOnlyRoots(isolate).empty_weak_fixed_array();
491 }
492 return transition_array->GetPrototypeTransitions();
493}
494
495// static
497 Tagged<WeakFixedArray> proto_transitions, int value) {
498 DCHECK_NE(proto_transitions->length(), 0);
499 proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
500 Smi::FromInt(value));
501}
502
504 switch (encoding()) {
505 case kPrototypeInfo:
506 case kUninitialized:
507 case kMigrationTarget:
508 return 0;
509 case kWeakRef:
510 return 1;
512 return transitions()->number_of_transitions();
513 }
514 UNREACHABLE();
515}
516
518 switch (encoding()) {
519 case kPrototypeInfo:
520 case kUninitialized:
521 case kMigrationTarget:
522 case kWeakRef:
523 return false;
525 return transitions()->HasPrototypeTransitions();
526 }
527 UNREACHABLE();
528}
529
530// static
533 Tagged<Map> migration_target) {
534 // We only cache the migration target for maps with empty transitions for GC's
535 // sake.
536 if (GetEncoding(isolate, map) != kUninitialized) return;
537 DCHECK(map->is_deprecated());
538 map->set_raw_transitions(migration_target, kReleaseStore);
539}
540
542 if (encoding() == kMigrationTarget) {
543 return Cast<Map>(map_->raw_transitions(kAcquireLoad));
544 }
545 return Tagged<Map>();
546}
547
548// static
550 Isolate* isolate, DirectHandle<Map> map,
551 Tagged<UnionOf<TransitionArray, MaybeWeak<Map>>> new_transitions) {
552#if DEBUG
553 if (GetEncoding(isolate, map) == kFullTransitionArray) {
554 CheckNewTransitionsAreConsistent(
555 isolate, map, new_transitions.GetHeapObjectAssumeStrong());
556 DCHECK_NE(GetTransitionArray(isolate, map),
557 new_transitions.GetHeapObjectAssumeStrong());
558 }
559#endif
560 map->set_raw_transitions(new_transitions, kReleaseStore);
561 USE(isolate);
562}
563
564// static
566 Isolate* isolate, DirectHandle<Map> map,
567 DirectHandle<TransitionArray> new_transitions) {
568 ReplaceTransitions(isolate, map, *new_transitions);
569}
570
571// static
573 Isolate* isolate, DirectHandle<Map> map,
574 DirectHandle<WeakFixedArray> proto_transitions) {
575 EnsureHasFullTransitionArray(isolate, map);
576 GetTransitionArray(isolate, map->raw_transitions(isolate, kAcquireLoad))
577 ->SetPrototypeTransitions(*proto_transitions);
578}
579
580// static
582 DirectHandle<Map> map) {
584 GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad));
585 if (encoding == kFullTransitionArray) return;
586 int nof =
589 isolate->factory()->NewTransitionArray(nof);
590 // Reload encoding after possible GC.
591 encoding = GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad));
592 if (nof == 1) {
593 if (encoding == kUninitialized) {
594 // If allocation caused GC and cleared the target, trim the new array.
595 result->SetNumberOfTransitions(0);
596 } else {
597 // Otherwise populate the new array.
598 Tagged<Map> target = GetSimpleTransition(isolate, map);
600 result->Set(0, key, MakeWeak(target));
601 }
602 }
603 ReplaceTransitions(isolate, map, result);
604}
605
608 // Mostly arbitrary but more than enough to run the test suite in static
609 // memory.
610 static constexpr int kStaticStackSize = 16;
611 base::SmallVector<Tagged<Map>, kStaticStackSize> stack;
612 stack.emplace_back(map_);
613
614 // Pre-order iterative depth-first-search.
615 while (!stack.empty()) {
616 Tagged<Map> current_map = stack.back();
617 stack.pop_back();
618
619 callback(current_map);
620
622 current_map->raw_transitions(isolate_, kAcquireLoad);
624
625 switch (encoding) {
626 case kPrototypeInfo:
627 case kUninitialized:
628 case kMigrationTarget:
629 break;
630 case kWeakRef: {
631 stack.emplace_back(
632 Cast<Map>(raw_transitions.GetHeapObjectAssumeWeak()));
633 break;
634 }
636 Tagged<TransitionArray> transitions =
637 Cast<TransitionArray>(raw_transitions.GetHeapObjectAssumeStrong());
638 if (transitions->HasPrototypeTransitions()) {
639 Tagged<WeakFixedArray> proto_trans =
640 transitions->GetPrototypeTransitions();
641 int length =
643 for (int i = 0; i < length; ++i) {
645 Tagged<MaybeObject> target = proto_trans->get(index);
646 Tagged<HeapObject> heap_object;
647 if (target.GetHeapObjectIfWeak(&heap_object)) {
648 stack.emplace_back(Cast<Map>(heap_object));
649 } else {
650 DCHECK(target.IsCleared());
651 }
652 }
653 }
654 ReadOnlyRoots roots(isolate_);
655 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
656 stack.emplace_back(transitions->GetTarget(i));
657 }
658 break;
659 }
660 }
661 }
662}
663
664#ifdef DEBUG
665// static
666void TransitionsAccessor::CheckNewTransitionsAreConsistent(
667 Isolate* isolate, DirectHandle<Map> map, Tagged<Object> transitions) {
668 // This function only handles full transition arrays.
669 Tagged<TransitionArray> old_transitions = GetTransitionArray(isolate, map);
670 DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, old_transitions));
671 Tagged<TransitionArray> new_transitions = Cast<TransitionArray>(transitions);
672 ReadOnlyRoots roots(isolate);
673 for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
675 if (old_transitions->GetTargetIfExists(i, isolate, &target)) {
676 if (target->instance_descriptors(isolate) ==
677 map->instance_descriptors(isolate)) {
678 Tagged<Name> key = old_transitions->GetKey(i);
679 int new_target_index;
680 if (IsSpecialTransition(roots, key)) {
681 new_target_index = new_transitions->SearchSpecial(Cast<Symbol>(key));
682 } else {
683 PropertyDetails details = GetTargetDetails(key, target);
684 new_target_index = new_transitions->Search(details.kind(), key,
685 details.attributes());
686 }
687 DCHECK_NE(TransitionArray::kNotFound, new_target_index);
688 DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
689 }
690 } else {
691 DCHECK(IsSpecialTransition(roots, old_transitions->GetKey(i)));
692 }
693 }
694}
695#endif
696
697// Private non-static helper functions (operating on full transition arrays).
698
700 PropertyAttributes attributes,
701 int* out_insertion_index) {
702 int nof_transitions = number_of_transitions();
703 DCHECK(transition < nof_transitions);
704 Tagged<Name> key = GetKey(transition);
705 for (; transition < nof_transitions && GetKey(transition) == key;
706 transition++) {
707 Tagged<Map> target = GetTarget(transition);
708 PropertyDetails target_details =
710
711 int cmp = CompareDetails(kind, attributes, target_details.kind(),
712 target_details.attributes());
713 if (cmp == 0) {
714 return transition;
715 } else if (cmp < 0) {
716 break;
717 }
718 }
719 if (out_insertion_index != nullptr) *out_insertion_index = transition;
720 return kNotFound;
721}
722
724 int transition, PropertyKind kind, PropertyAttributes attributes) {
725 int nof_transitions = number_of_transitions();
726 DCHECK(transition < nof_transitions);
727 Tagged<Name> key = GetKey(transition);
728 for (; transition < nof_transitions && GetKey(transition) == key;
729 transition++) {
730 Tagged<Map> target = GetTarget(transition);
731 PropertyDetails target_details =
733
734 int cmp = CompareDetails(kind, attributes, target_details.kind(),
735 target_details.attributes());
736 if (cmp == 0) {
737 return target;
738 } else if (cmp < 0) {
739 break;
740 }
741 }
742 return Tagged<Map>();
743}
744
746 PropertyAttributes attributes,
747 int* out_insertion_index) {
748 int transition = SearchName(name, false, out_insertion_index);
749 if (transition == kNotFound) return kNotFound;
750 return SearchDetails(transition, kind, attributes, out_insertion_index);
751}
752
754 Tagged<Name> name,
755 PropertyAttributes attributes) {
756 int transition = SearchName(name);
757 if (transition == kNotFound) {
758 return Tagged<Map>();
759 }
760 return SearchDetailsAndGetTarget(transition, kind, attributes);
761}
762
765 int transition = SearchName(name);
766 if (transition == kNotFound) return;
767
768 int nof_transitions = number_of_transitions();
769 DCHECK(transition < nof_transitions);
770 Tagged<Name> key = GetKey(transition);
771 for (; transition < nof_transitions && GetKey(transition) == key;
772 transition++) {
773 Tagged<Map> target = GetTarget(transition);
774 callback(target);
775 }
776}
777
780 // In-place insertion sort.
781 int length = number_of_transitions();
783 for (int i = 1; i < length; i++) {
787 PropertyAttributes attributes = NONE;
790 PropertyDetails details =
792 kind = details.kind();
793 attributes = details.attributes();
794 }
795 int j;
796 for (j = i - 1; j >= 0; j--) {
797 Tagged<Name> temp_key = GetKey(j);
798 Tagged<MaybeObject> temp_target = GetRawTarget(j);
800 PropertyAttributes temp_attributes = NONE;
801 if (!TransitionsAccessor::IsSpecialTransition(roots, temp_key)) {
802 Tagged<Map> temp_target_map =
804 PropertyDetails details =
805 TransitionsAccessor::GetTargetDetails(temp_key, temp_target_map);
806 temp_kind = details.kind();
807 temp_attributes = details.attributes();
808 }
809 int cmp =
810 CompareKeys(temp_key, temp_key->hash(), temp_kind, temp_attributes,
811 key, key->hash(), kind, attributes);
812 if (cmp > 0) {
813 SetKey(j + 1, temp_key);
814 SetRawTarget(j + 1, temp_target);
815 } else {
816 break;
817 }
818 }
819 SetKey(j + 1, key);
820 SetRawTarget(j + 1, target);
821 }
822 DCHECK(IsSortedNoDuplicates());
823}
824
826 Tagged<Map> to, Tagged<Symbol>* out_symbol,
827 PropertyAttributes* out_integrity_level) {
828 ReadOnlyRoots roots(isolate_);
829 if (SearchSpecial(roots.frozen_symbol()) == to) {
830 if (out_integrity_level) *out_integrity_level = FROZEN;
831 if (out_symbol) *out_symbol = roots.frozen_symbol();
832 } else if (SearchSpecial(roots.sealed_symbol()) == to) {
833 if (out_integrity_level) *out_integrity_level = SEALED;
834 if (out_symbol) *out_symbol = roots.sealed_symbol();
835 } else if (SearchSpecial(roots.nonextensible_symbol()) == to) {
836 if (out_integrity_level) *out_integrity_level = NONE;
837 if (out_symbol) *out_symbol = roots.nonextensible_symbol();
838 } else {
839 return false;
840 }
841 return true;
842}
843
844// static
846 DirectHandle<Map> map) {
847 EnsureHasFullTransitionArray(isolate, map);
848 Tagged<TransitionArray> transitions =
849 GetTransitionArray(isolate, map->raw_transitions());
850 if (transitions->HasSideStepTransitions()) return;
852 isolate, direct_handle(transitions, isolate));
853}
854
855// static
857 Isolate* isolate, DirectHandle<TransitionArray> transitions) {
858 DCHECK(!transitions->HasSideStepTransitions()); // Callers must check first.
862 transitions->SetSideStepTransitions(*result);
863}
864
865std::ostream& operator<<(std::ostream& os, SideStepTransition::Kind sidestep) {
866 switch (sidestep) {
868 os << "Object.assign-validity-cell";
869 break;
871 os << "Object.assign-map";
872 break;
874 os << "Clone-object-IC-map";
875 break;
876 }
877 return os;
878}
879
880} // namespace v8::internal
Builtins::Kind kind
Definition builtins.cc:40
#define SLOW_DCHECK(condition)
Definition checks.h:21
void emplace_back(Args &&... args)
base::Mutex * full_transition_array_access()
Definition isolate.h:749
static int SlackForArraySize(int old_size, int size_limit)
Definition map-inl.h:1030
PropertyAttributes attributes() const
PropertyLocation location() const
static constexpr PropertyDetails Empty(PropertyCellType cell_type=PropertyCellType::kNoCell)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static ThreadId Current()
Definition thread-id.h:32
int SearchDetails(int transition, PropertyKind kind, PropertyAttributes attributes, int *out_insertion_index)
int Search(PropertyKind kind, Tagged< Name > name, PropertyAttributes attributes, int *out_insertion_index=nullptr)
int SearchName(Tagged< Name > name, bool concurrent_search=false, int *out_insertion_index=nullptr)
V8_EXPORT_PRIVATE Tagged< Map > SearchAndGetTarget(PropertyKind kind, Tagged< Name > name, PropertyAttributes attributes)
Tagged< Name > GetKey(int transition_number)
void SetKey(int transition_number, Tagged< Name > value)
static int CompareDetails(PropertyKind kind1, PropertyAttributes attributes1, PropertyKind kind2, PropertyAttributes attributes2)
static DirectHandle< WeakFixedArray > GrowPrototypeTransitionArray(DirectHandle< WeakFixedArray > array, int new_capacity, Isolate *isolate)
V8_EXPORT_PRIVATE void Sort()
static bool CompactPrototypeTransitionArray(Isolate *isolate, Tagged< WeakFixedArray > array)
void ForEachTransitionTo(Tagged< Name > name, const ForEachTransitionCallback &callback)
Tagged< MaybeObject > GetRawTarget(int transition_number)
Tagged< Map > SearchDetailsAndGetTarget(int transition, PropertyKind kind, PropertyAttributes attributes)
static int CompareKeys(Tagged< Name > key1, uint32_t hash1, PropertyKind kind1, PropertyAttributes attributes1, Tagged< Name > key2, uint32_t hash2, PropertyKind kind2, PropertyAttributes attributes2)
void SetRawTarget(int transition_number, Tagged< MaybeObject > target)
static const int kProtoTransitionNumberOfEntriesOffset
Tagged< Map > GetTarget(int transition_number)
static const int kProtoTransitionHeaderSize
static int NumberOfPrototypeTransitions(Tagged< WeakFixedArray > proto_transitions)
static void CreateSideStepTransitions(Isolate *isolate, DirectHandle< TransitionArray > transitions)
static const int kMaxCachedPrototypeTransitions
static constexpr int kNotFound
static void SetNumberOfPrototypeTransitions(Tagged< WeakFixedArray > proto_transitions, int value)
static Tagged< Map > GetSimpleTransition(Isolate *isolate, DirectHandle< Map > map)
bool HasSimpleTransitionTo(Tagged< Map > map)
void TraverseTransitionTreeInternal(const TraverseCallback &callback, DisallowGarbageCollection *no_gc)
static Tagged< WeakFixedArray > GetPrototypeTransitions(Isolate *isolate, Tagged< Map > map)
static bool CanHaveMoreTransitions(Isolate *isolate, DirectHandle< Map > map)
static std::optional< Tagged< Map > > GetPrototypeTransition(Isolate *isolate, Tagged< Map > map, Tagged< Object > prototype)
static void EnsureHasFullTransitionArray(Isolate *isolate, DirectHandle< Map > map)
Tagged< Map > SearchTransition(Tagged< Name > name, PropertyKind kind, PropertyAttributes attributes)
static Tagged< TransitionArray > GetTransitionArray(Isolate *isolate, Tagged< MaybeObject > raw_transitions)
static void ReplaceTransitions(Isolate *isolate, DirectHandle< Map > map, Tagged< UnionOf< TransitionArray, MaybeWeak< Map > > > new_transitions)
static bool PutPrototypeTransition(Isolate *isolate, DirectHandle< Map >, DirectHandle< Object > prototype, DirectHandle< Map > target_map)
static Tagged< Map > GetTargetFromRaw(Tagged< MaybeObject > raw)
static void SetMigrationTarget(Isolate *isolate, DirectHandle< Map > map, Tagged< Map > migration_target)
Tagged< MaybeObject > raw_transitions_
Tagged< TransitionArray > transitions()
static bool IsSpecialTransition(ReadOnlyRoots roots, Tagged< Name > name)
static void EnsureHasSideStepTransitions(Isolate *isolate, DirectHandle< Map > map)
static const int kMaxNumberOfTransitions
std::function< void(Tagged< Map >)> TraverseCallback
void ForEachTransitionTo(Tagged< Name > name, const ForEachTransitionCallback &callback, DisallowGarbageCollection *no_gc)
static bool IsMatchingMap(Tagged< Map > target, Tagged< Name > name, PropertyKind kind, PropertyAttributes attributes)
static PropertyDetails GetTargetDetails(Tagged< Name > name, Tagged< Map > target)
Tagged< Map > SearchSpecial(Tagged< Symbol > name)
static Tagged< Name > GetSimpleTransitionKey(Tagged< Map > transition)
MaybeHandle< Map > FindTransitionToField(DirectHandle< String > name)
static void InsertHelper(Isolate *isolate, DirectHandle< Map > map, DirectHandle< Name > name, DirectHandle< Map > target, TransitionKindFlag flag)
static Encoding GetEncoding(Isolate *isolate, Tagged< MaybeObject > raw_transitions)
static void SetPrototypeTransitions(Isolate *isolate, DirectHandle< Map > map, DirectHandle< WeakFixedArray > proto_transitions)
bool HasIntegrityLevelTransitionTo(Tagged< Map > to, Tagged< Symbol > *out_symbol=nullptr, PropertyAttributes *out_integrity_level=nullptr)
static Handle< WeakFixedArray > New(IsolateT *isolate, int capacity, AllocationType allocation=AllocationType::kYoung, MaybeDirectHandle< Object > initial_value={})
TNode< Object > target
TNode< Object > callback
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
ReadOnlyRoots GetReadOnlyRoots()
Definition roots-inl.h:86
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
@ SIMPLE_PROPERTY_TRANSITION
Definition objects.h:73
@ PROTOTYPE_TRANSITION
Definition objects.h:75
@ SPECIAL_TRANSITION
Definition objects.h:76
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
kInstanceDescriptorsOffset raw_transitions
Definition map-inl.h:61
typename detail::FlattenUnionHelper< Union<>, Ts... >::type UnionOf
Definition union.h:123
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsUniqueName(Tagged< Name > obj)
std::function< void(Tagged< Map >)> ForEachTransitionCallback
Definition transitions.h:25
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
Local< T > Handle
static constexpr RelaxedLoadTag kRelaxedLoad
Definition globals.h:2909
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_LE(lhs, rhs)
#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_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
static constexpr Tagged< Smi > Empty
Definition transitions.h:40
static constexpr uint32_t kSize
Definition transitions.h:37