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
5#ifndef V8_TRANSITIONS_INL_H_
6#define V8_TRANSITIONS_INL_H_
7
8#include "src/transitions.h"
9
10#include "src/ic/handler-configuration-inl.h"
11#include "src/objects/fixed-array-inl.h"
12#include "src/objects/maybe-object-inl.h"
13#include "src/objects/slots.h"
14#include "src/objects/smi.h"
15
16// Has to be the last include (doesn't have include guards):
17#include "src/objects/object-macros.h"
18
19namespace v8 {
20namespace internal {
21
22TransitionArray TransitionsAccessor::transitions() {
23 DCHECK_EQ(kFullTransitionArray, encoding());
24 return TransitionArray::cast(raw_transitions_->GetHeapObjectAssumeStrong());
25}
26
27OBJECT_CONSTRUCTORS_IMPL(TransitionArray, WeakFixedArray)
28
29CAST_ACCESSOR(TransitionArray)
30
31bool TransitionArray::HasPrototypeTransitions() {
32 return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::zero());
33}
34
35WeakFixedArray TransitionArray::GetPrototypeTransitions() {
36 DCHECK(HasPrototypeTransitions()); // Callers must check first.
37 Object prototype_transitions =
38 Get(kPrototypeTransitionsIndex)->GetHeapObjectAssumeStrong();
39 return WeakFixedArray::cast(prototype_transitions);
40}
41
42HeapObjectSlot TransitionArray::GetKeySlot(int transition_number) {
43 DCHECK(transition_number < number_of_transitions());
44 return HeapObjectSlot(RawFieldOfElementAt(ToKeyIndex(transition_number)));
45}
46
47void TransitionArray::SetPrototypeTransitions(WeakFixedArray transitions) {
48 DCHECK(transitions->IsWeakFixedArray());
49 WeakFixedArray::Set(kPrototypeTransitionsIndex,
50 HeapObjectReference::Strong(transitions));
51}
52
53int TransitionArray::NumberOfPrototypeTransitions(
54 WeakFixedArray proto_transitions) {
55 if (proto_transitions->length() == 0) return 0;
56 MaybeObject raw =
57 proto_transitions->Get(kProtoTransitionNumberOfEntriesOffset);
58 return raw.ToSmi().value();
59}
60
61Name TransitionArray::GetKey(int transition_number) {
62 DCHECK(transition_number < number_of_transitions());
63 return Name::cast(
64 Get(ToKeyIndex(transition_number))->GetHeapObjectAssumeStrong());
65}
66
67Name TransitionsAccessor::GetKey(int transition_number) {
68 switch (encoding()) {
69 case kPrototypeInfo:
70 case kUninitialized:
71 case kMigrationTarget:
72 UNREACHABLE();
73 return Name();
74 case kWeakRef: {
75 Map map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
76 return GetSimpleTransitionKey(map);
77 }
78 case kFullTransitionArray:
79 return transitions()->GetKey(transition_number);
80 }
81 UNREACHABLE();
82}
83
84void TransitionArray::SetKey(int transition_number, Name key) {
85 DCHECK(transition_number < number_of_transitions());
86 WeakFixedArray::Set(ToKeyIndex(transition_number),
87 HeapObjectReference::Strong(key));
88}
89
90HeapObjectSlot TransitionArray::GetTargetSlot(int transition_number) {
91 DCHECK(transition_number < number_of_transitions());
92 return HeapObjectSlot(RawFieldOfElementAt(ToTargetIndex(transition_number)));
93}
94
95// static
96PropertyDetails TransitionsAccessor::GetTargetDetails(Name name, Map target) {
97 DCHECK(!IsSpecialTransition(name->GetReadOnlyRoots(), name));
98 int descriptor = target->LastAdded();
99 DescriptorArray descriptors = target->instance_descriptors();
100 // Transitions are allowed only for the last added property.
101 DCHECK(descriptors->GetKey(descriptor)->Equals(name));
102 return descriptors->GetDetails(descriptor);
103}
104
105// static
106PropertyDetails TransitionsAccessor::GetSimpleTargetDetails(Map transition) {
107 return transition->GetLastDescriptorDetails();
108}
109
110// static
111Name TransitionsAccessor::GetSimpleTransitionKey(Map transition) {
112 int descriptor = transition->LastAdded();
113 return transition->instance_descriptors()->GetKey(descriptor);
114}
115
116// static
117Map TransitionsAccessor::GetTargetFromRaw(MaybeObject raw) {
118 return Map::cast(raw->GetHeapObjectAssumeWeak());
119}
120
121MaybeObject TransitionArray::GetRawTarget(int transition_number) {
122 DCHECK(transition_number < number_of_transitions());
123 return Get(ToTargetIndex(transition_number));
124}
125
126Map TransitionArray::GetTarget(int transition_number) {
127 MaybeObject raw = GetRawTarget(transition_number);
128 return TransitionsAccessor::GetTargetFromRaw(raw);
129}
130
131Map TransitionsAccessor::GetTarget(int transition_number) {
132 switch (encoding()) {
133 case kPrototypeInfo:
134 case kUninitialized:
135 case kMigrationTarget:
136 UNREACHABLE();
137 return Map();
138 case kWeakRef:
139 return Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
140 case kFullTransitionArray:
141 return transitions()->GetTarget(transition_number);
142 }
143 UNREACHABLE();
144}
145
146void TransitionArray::SetRawTarget(int transition_number, MaybeObject value) {
147 DCHECK(transition_number < number_of_transitions());
148 DCHECK(value->IsWeak());
149 DCHECK(value->GetHeapObjectAssumeWeak()->IsMap());
150 WeakFixedArray::Set(ToTargetIndex(transition_number), value);
151}
152
153bool TransitionArray::GetTargetIfExists(int transition_number, Isolate* isolate,
154 Map* target) {
155 MaybeObject raw = GetRawTarget(transition_number);
156 HeapObject heap_object;
157 if (raw->GetHeapObjectIfStrong(&heap_object) &&
158 heap_object->IsUndefined(isolate)) {
159 return false;
160 }
161 *target = TransitionsAccessor::GetTargetFromRaw(raw);
162 return true;
163}
164
165int TransitionArray::SearchNameForTesting(Name name, int* out_insertion_index) {
166 return SearchName(name, out_insertion_index);
167}
168
169int TransitionArray::SearchSpecial(Symbol symbol, int* out_insertion_index) {
170 return SearchName(symbol, out_insertion_index);
171}
172
173int TransitionArray::SearchName(Name name, int* out_insertion_index) {
174 DCHECK(name->IsUniqueName());
175 return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
176 out_insertion_index);
177}
178
179int TransitionArray::number_of_transitions() const {
180 if (length() < kFirstIndex) return 0;
181 return Get(kTransitionLengthIndex).ToSmi().value();
182}
183
184int TransitionArray::CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
185 PropertyAttributes attributes1, Name key2,
186 uint32_t hash2, PropertyKind kind2,
187 PropertyAttributes attributes2) {
188 int cmp = CompareNames(key1, hash1, key2, hash2);
189 if (cmp != 0) return cmp;
190
191 return CompareDetails(kind1, attributes1, kind2, attributes2);
192}
193
194int TransitionArray::CompareNames(Name key1, uint32_t hash1, Name key2,
195 uint32_t hash2) {
196 if (key1 != key2) {
197 // In case of hash collisions key1 is always "less" than key2.
198 return hash1 <= hash2 ? -1 : 1;
199 }
200
201 return 0;
202}
203
204int TransitionArray::CompareDetails(PropertyKind kind1,
205 PropertyAttributes attributes1,
206 PropertyKind kind2,
207 PropertyAttributes attributes2) {
208 if (kind1 != kind2) {
209 return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
210 }
211
212 if (attributes1 != attributes2) {
213 return static_cast<int>(attributes1) < static_cast<int>(attributes2) ? -1
214 : 1;
215 }
216
217 return 0;
218}
219
220void TransitionArray::Set(int transition_number, Name key, MaybeObject target) {
221 WeakFixedArray::Set(ToKeyIndex(transition_number),
222 MaybeObject::FromObject(key));
223 WeakFixedArray::Set(ToTargetIndex(transition_number), target);
224}
225
226Name TransitionArray::GetSortedKey(int transition_number) {
227 return GetKey(transition_number);
228}
229
230int TransitionArray::number_of_entries() const {
231 return number_of_transitions();
232}
233
234int TransitionArray::Capacity() {
235 if (length() <= kFirstIndex) return 0;
236 return (length() - kFirstIndex) / kEntrySize;
237}
238
239void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
240 DCHECK(number_of_transitions <= Capacity());
241 WeakFixedArray::Set(
242 kTransitionLengthIndex,
243 MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
244}
245
246} // namespace internal
247} // namespace v8
248
249#include "src/objects/object-macros-undef.h"
250
251#endif // V8_TRANSITIONS_INL_H_
252