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