• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_OBJECTS_TRANSITIONS_INL_H_
6 #define V8_OBJECTS_TRANSITIONS_INL_H_
7 
8 #include "src/objects/fixed-array-inl.h"
9 #include "src/objects/maybe-object-inl.h"
10 #include "src/objects/slots.h"
11 #include "src/objects/smi.h"
12 #include "src/objects/transitions.h"
13 
14 // Has to be the last include (doesn't have include guards):
15 #include "src/objects/object-macros.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 // static
GetTransitionArray(Isolate * isolate,MaybeObject raw_transitions)21 TransitionArray TransitionsAccessor::GetTransitionArray(
22     Isolate* isolate, MaybeObject raw_transitions) {
23   DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, raw_transitions));
24   USE(isolate);
25   return TransitionArray::cast(raw_transitions.GetHeapObjectAssumeStrong());
26 }
27 
28 // static
GetTransitionArray(Isolate * isolate,Handle<Map> map)29 TransitionArray TransitionsAccessor::GetTransitionArray(Isolate* isolate,
30                                                         Handle<Map> map) {
31   MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
32   return GetTransitionArray(isolate, raw_transitions);
33 }
34 
transitions()35 TransitionArray TransitionsAccessor::transitions() {
36   return GetTransitionArray(isolate_, raw_transitions_);
37 }
38 
OBJECT_CONSTRUCTORS_IMPL(TransitionArray,WeakFixedArray)39 OBJECT_CONSTRUCTORS_IMPL(TransitionArray, WeakFixedArray)
40 
41 CAST_ACCESSOR(TransitionArray)
42 
43 bool TransitionArray::HasPrototypeTransitions() {
44   return Get(kPrototypeTransitionsIndex) != MaybeObject::FromSmi(Smi::zero());
45 }
46 
GetPrototypeTransitions()47 WeakFixedArray TransitionArray::GetPrototypeTransitions() {
48   DCHECK(HasPrototypeTransitions());  // Callers must check first.
49   Object prototype_transitions =
50       Get(kPrototypeTransitionsIndex)->GetHeapObjectAssumeStrong();
51   return WeakFixedArray::cast(prototype_transitions);
52 }
53 
GetKeySlot(int transition_number)54 HeapObjectSlot TransitionArray::GetKeySlot(int transition_number) {
55   DCHECK(transition_number < number_of_transitions());
56   return HeapObjectSlot(RawFieldOfElementAt(ToKeyIndex(transition_number)));
57 }
58 
SetPrototypeTransitions(WeakFixedArray transitions)59 void TransitionArray::SetPrototypeTransitions(WeakFixedArray transitions) {
60   DCHECK(transitions.IsWeakFixedArray());
61   WeakFixedArray::Set(kPrototypeTransitionsIndex,
62                       HeapObjectReference::Strong(transitions));
63 }
64 
NumberOfPrototypeTransitions(WeakFixedArray proto_transitions)65 int TransitionArray::NumberOfPrototypeTransitions(
66     WeakFixedArray proto_transitions) {
67   if (proto_transitions.length() == 0) return 0;
68   MaybeObject raw =
69       proto_transitions.Get(kProtoTransitionNumberOfEntriesOffset);
70   return raw.ToSmi().value();
71 }
72 
GetKey(int transition_number)73 Name TransitionArray::GetKey(int transition_number) {
74   DCHECK(transition_number < number_of_transitions());
75   return Name::cast(
76       Get(ToKeyIndex(transition_number))->GetHeapObjectAssumeStrong());
77 }
78 
GetKey(InternalIndex index)79 Name TransitionArray::GetKey(InternalIndex index) {
80   return GetKey(index.as_int());
81 }
82 
GetKey(int transition_number)83 Name TransitionsAccessor::GetKey(int transition_number) {
84   switch (encoding()) {
85     case kPrototypeInfo:
86     case kUninitialized:
87     case kMigrationTarget:
88       UNREACHABLE();
89       return Name();
90     case kWeakRef: {
91       Map map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
92       return GetSimpleTransitionKey(map);
93     }
94     case kFullTransitionArray:
95       return transitions().GetKey(transition_number);
96   }
97   UNREACHABLE();
98 }
99 
SetKey(int transition_number,Name key)100 void TransitionArray::SetKey(int transition_number, Name key) {
101   DCHECK(transition_number < number_of_transitions());
102   WeakFixedArray::Set(ToKeyIndex(transition_number),
103                       HeapObjectReference::Strong(key));
104 }
105 
GetTargetSlot(int transition_number)106 HeapObjectSlot TransitionArray::GetTargetSlot(int transition_number) {
107   DCHECK(transition_number < number_of_transitions());
108   return HeapObjectSlot(RawFieldOfElementAt(ToTargetIndex(transition_number)));
109 }
110 
111 // static
GetTargetDetails(Name name,Map target)112 PropertyDetails TransitionsAccessor::GetTargetDetails(Name name, Map target) {
113   DCHECK(!IsSpecialTransition(name.GetReadOnlyRoots(), name));
114   InternalIndex descriptor = target.LastAdded();
115   DescriptorArray descriptors = target.instance_descriptors(kRelaxedLoad);
116   // Transitions are allowed only for the last added property.
117   DCHECK(descriptors.GetKey(descriptor).Equals(name));
118   return descriptors.GetDetails(descriptor);
119 }
120 
GetSimpleTargetDetails(Map transition)121 PropertyDetails TransitionsAccessor::GetSimpleTargetDetails(Map transition) {
122   return transition.GetLastDescriptorDetails(isolate_);
123 }
124 
125 // static
GetSimpleTransitionKey(Map transition)126 Name TransitionsAccessor::GetSimpleTransitionKey(Map transition) {
127   InternalIndex descriptor = transition.LastAdded();
128   return transition.instance_descriptors().GetKey(descriptor);
129 }
130 
131 // static
GetTargetFromRaw(MaybeObject raw)132 Map TransitionsAccessor::GetTargetFromRaw(MaybeObject raw) {
133   return Map::cast(raw->GetHeapObjectAssumeWeak());
134 }
135 
GetRawTarget(int transition_number)136 MaybeObject TransitionArray::GetRawTarget(int transition_number) {
137   DCHECK(transition_number < number_of_transitions());
138   return Get(ToTargetIndex(transition_number));
139 }
140 
GetTarget(int transition_number)141 Map TransitionArray::GetTarget(int transition_number) {
142   MaybeObject raw = GetRawTarget(transition_number);
143   return TransitionsAccessor::GetTargetFromRaw(raw);
144 }
145 
GetTarget(int transition_number)146 Map TransitionsAccessor::GetTarget(int transition_number) {
147   switch (encoding()) {
148     case kPrototypeInfo:
149     case kUninitialized:
150     case kMigrationTarget:
151       UNREACHABLE();
152       return Map();
153     case kWeakRef:
154       return Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
155     case kFullTransitionArray:
156       return transitions().GetTarget(transition_number);
157   }
158   UNREACHABLE();
159 }
160 
SetRawTarget(int transition_number,MaybeObject value)161 void TransitionArray::SetRawTarget(int transition_number, MaybeObject value) {
162   DCHECK(transition_number < number_of_transitions());
163   DCHECK(value->IsWeak());
164   DCHECK(value->GetHeapObjectAssumeWeak().IsMap());
165   WeakFixedArray::Set(ToTargetIndex(transition_number), value);
166 }
167 
GetTargetIfExists(int transition_number,Isolate * isolate,Map * target)168 bool TransitionArray::GetTargetIfExists(int transition_number, Isolate* isolate,
169                                         Map* target) {
170   MaybeObject raw = GetRawTarget(transition_number);
171   HeapObject heap_object;
172   // If the raw target is a Smi, then this TransitionArray is in the process of
173   // being deserialized, and doesn't yet have an initialized entry for this
174   // transition.
175   if (raw.IsSmi()) {
176     DCHECK(isolate->has_active_deserializer());
177     DCHECK_EQ(raw.ToSmi(), Smi::uninitialized_deserialization_value());
178     return false;
179   }
180   if (raw->GetHeapObjectIfStrong(&heap_object) &&
181       heap_object.IsUndefined(isolate)) {
182     return false;
183   }
184   *target = TransitionsAccessor::GetTargetFromRaw(raw);
185   return true;
186 }
187 
SearchNameForTesting(Name name,int * out_insertion_index)188 int TransitionArray::SearchNameForTesting(Name name, int* out_insertion_index) {
189   return SearchName(name, out_insertion_index);
190 }
191 
SearchAndGetTargetForTesting(PropertyKind kind,Name name,PropertyAttributes attributes)192 Map TransitionArray::SearchAndGetTargetForTesting(
193     PropertyKind kind, Name name, PropertyAttributes attributes) {
194   return SearchAndGetTarget(kind, name, attributes);
195 }
196 
SearchSpecial(Symbol symbol,bool concurrent_search,int * out_insertion_index)197 int TransitionArray::SearchSpecial(Symbol symbol, bool concurrent_search,
198                                    int* out_insertion_index) {
199   return SearchName(symbol, concurrent_search, out_insertion_index);
200 }
201 
SearchName(Name name,bool concurrent_search,int * out_insertion_index)202 int TransitionArray::SearchName(Name name, bool concurrent_search,
203                                 int* out_insertion_index) {
204   DCHECK(name.IsUniqueName());
205   return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(),
206                                        out_insertion_index, concurrent_search);
207 }
208 
TransitionsAccessor(Isolate * isolate,Map map,bool concurrent_access)209 TransitionsAccessor::TransitionsAccessor(Isolate* isolate, Map map,
210                                          bool concurrent_access)
211     : isolate_(isolate),
212       map_(map),
213       raw_transitions_(map.raw_transitions(isolate_, kAcquireLoad)),
214       encoding_(GetEncoding(isolate_, raw_transitions_)),
215       concurrent_access_(concurrent_access) {
216   DCHECK_IMPLIES(encoding_ == kMigrationTarget, map_.is_deprecated());
217 }
218 
Capacity()219 int TransitionsAccessor::Capacity() { return transitions().Capacity(); }
220 
221 // static
GetEncoding(Isolate * isolate,MaybeObject raw_transitions)222 TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
223     Isolate* isolate, MaybeObject raw_transitions) {
224   HeapObject heap_object;
225   if (raw_transitions->IsSmi() || raw_transitions->IsCleared()) {
226     return kUninitialized;
227   } else if (raw_transitions->IsWeak()) {
228     return kWeakRef;
229   } else if (raw_transitions->GetHeapObjectIfStrong(isolate, &heap_object)) {
230     if (heap_object.IsTransitionArray()) {
231       return kFullTransitionArray;
232     } else if (heap_object.IsPrototypeInfo()) {
233       return kPrototypeInfo;
234     } else {
235       DCHECK(heap_object.IsMap());
236       return kMigrationTarget;
237     }
238   } else {
239     UNREACHABLE();
240   }
241 }
242 
243 // static
GetEncoding(Isolate * isolate,TransitionArray array)244 TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
245     Isolate* isolate, TransitionArray array) {
246   return GetEncoding(isolate, MaybeObject::FromObject(array));
247 }
248 
249 // static
GetEncoding(Isolate * isolate,Handle<Map> map)250 TransitionsAccessor::Encoding TransitionsAccessor::GetEncoding(
251     Isolate* isolate, Handle<Map> map) {
252   MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad);
253   return GetEncoding(isolate, raw_transitions);
254 }
255 
256 // static
SearchTransition(Isolate * isolate,Handle<Map> map,Name name,PropertyKind kind,PropertyAttributes attributes)257 MaybeHandle<Map> TransitionsAccessor::SearchTransition(
258     Isolate* isolate, Handle<Map> map, Name name, PropertyKind kind,
259     PropertyAttributes attributes) {
260   Map result = TransitionsAccessor(isolate, *map)
261                    .SearchTransition(name, kind, attributes);
262   if (result.is_null()) return MaybeHandle<Map>();
263   return MaybeHandle<Map>(result, isolate);
264 }
265 
266 // static
SearchSpecial(Isolate * isolate,Handle<Map> map,Symbol name)267 MaybeHandle<Map> TransitionsAccessor::SearchSpecial(Isolate* isolate,
268                                                     Handle<Map> map,
269                                                     Symbol name) {
270   Map result = TransitionsAccessor(isolate, *map).SearchSpecial(name);
271   if (result.is_null()) return MaybeHandle<Map>();
272   return MaybeHandle<Map>(result, isolate);
273 }
274 
number_of_transitions()275 int TransitionArray::number_of_transitions() const {
276   if (length() < kFirstIndex) return 0;
277   return Get(kTransitionLengthIndex).ToSmi().value();
278 }
279 
CompareKeys(Name key1,uint32_t hash1,PropertyKind kind1,PropertyAttributes attributes1,Name key2,uint32_t hash2,PropertyKind kind2,PropertyAttributes attributes2)280 int TransitionArray::CompareKeys(Name key1, uint32_t hash1, PropertyKind kind1,
281                                  PropertyAttributes attributes1, Name key2,
282                                  uint32_t hash2, PropertyKind kind2,
283                                  PropertyAttributes attributes2) {
284   int cmp = CompareNames(key1, hash1, key2, hash2);
285   if (cmp != 0) return cmp;
286 
287   return CompareDetails(kind1, attributes1, kind2, attributes2);
288 }
289 
CompareNames(Name key1,uint32_t hash1,Name key2,uint32_t hash2)290 int TransitionArray::CompareNames(Name key1, uint32_t hash1, Name key2,
291                                   uint32_t hash2) {
292   if (key1 != key2) {
293     // In case of hash collisions key1 is always "less" than key2.
294     return hash1 <= hash2 ? -1 : 1;
295   }
296 
297   return 0;
298 }
299 
CompareDetails(PropertyKind kind1,PropertyAttributes attributes1,PropertyKind kind2,PropertyAttributes attributes2)300 int TransitionArray::CompareDetails(PropertyKind kind1,
301                                     PropertyAttributes attributes1,
302                                     PropertyKind kind2,
303                                     PropertyAttributes attributes2) {
304   if (kind1 != kind2) {
305     return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1;
306   }
307 
308   if (attributes1 != attributes2) {
309     return static_cast<int>(attributes1) < static_cast<int>(attributes2) ? -1
310                                                                          : 1;
311   }
312 
313   return 0;
314 }
315 
Set(int transition_number,Name key,MaybeObject target)316 void TransitionArray::Set(int transition_number, Name key, MaybeObject target) {
317   WeakFixedArray::Set(ToKeyIndex(transition_number),
318                       MaybeObject::FromObject(key));
319   WeakFixedArray::Set(ToTargetIndex(transition_number), target);
320 }
321 
GetSortedKey(int transition_number)322 Name TransitionArray::GetSortedKey(int transition_number) {
323   return GetKey(transition_number);
324 }
325 
number_of_entries()326 int TransitionArray::number_of_entries() const {
327   return number_of_transitions();
328 }
329 
Capacity()330 int TransitionArray::Capacity() {
331   if (length() <= kFirstIndex) return 0;
332   return (length() - kFirstIndex) / kEntrySize;
333 }
334 
SetNumberOfTransitions(int number_of_transitions)335 void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
336   DCHECK(number_of_transitions <= Capacity());
337   WeakFixedArray::Set(
338       kTransitionLengthIndex,
339       MaybeObject::FromSmi(Smi::FromInt(number_of_transitions)));
340 }
341 
ExpectedTransitionKey()342 Handle<String> TransitionsAccessor::ExpectedTransitionKey() {
343   DisallowGarbageCollection no_gc;
344   switch (encoding()) {
345     case kPrototypeInfo:
346     case kUninitialized:
347     case kMigrationTarget:
348     case kFullTransitionArray:
349       return Handle<String>::null();
350     case kWeakRef: {
351       Map target = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak());
352       PropertyDetails details = GetSimpleTargetDetails(target);
353       if (details.location() != PropertyLocation::kField)
354         return Handle<String>::null();
355       DCHECK_EQ(PropertyKind::kData, details.kind());
356       if (details.attributes() != NONE) return Handle<String>::null();
357       Name name = GetSimpleTransitionKey(target);
358       if (!name.IsString()) return Handle<String>::null();
359       return handle(String::cast(name), isolate_);
360     }
361   }
362   UNREACHABLE();
363 }
364 
ExpectedTransitionTarget()365 Handle<Map> TransitionsAccessor::ExpectedTransitionTarget() {
366   DCHECK(!ExpectedTransitionKey().is_null());
367   return handle(GetTarget(0), isolate_);
368 }
369 
370 }  // namespace internal
371 }  // namespace v8
372 
373 #include "src/objects/object-macros-undef.h"
374 
375 #endif  // V8_OBJECTS_TRANSITIONS_INL_H_
376