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