// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_TRANSITIONS_INL_H_ #define V8_TRANSITIONS_INL_H_ #include "src/transitions.h" #include "src/ic/handler-configuration-inl.h" namespace v8 { namespace internal { template <TransitionsAccessor::Encoding enc> WeakCell* TransitionsAccessor::GetTargetCell() { DCHECK(!needs_reload_); if (target_cell_ != nullptr) return target_cell_; if (enc == kWeakCell) { target_cell_ = WeakCell::cast(raw_transitions_); } else if (enc == kHandler) { target_cell_ = StoreHandler::GetTransitionCell(raw_transitions_); } else { UNREACHABLE(); } return target_cell_; } TransitionArray* TransitionsAccessor::transitions() { DCHECK_EQ(kFullTransitionArray, encoding()); return TransitionArray::cast(raw_transitions_); } // static TransitionArray* TransitionArray::cast(Object* object) { DCHECK(object->IsTransitionArray()); return reinterpret_cast<TransitionArray*>(object); } bool TransitionArray::HasPrototypeTransitions() { return get(kPrototypeTransitionsIndex) != Smi::kZero; } FixedArray* TransitionArray::GetPrototypeTransitions() { DCHECK(HasPrototypeTransitions()); // Callers must check first. Object* prototype_transitions = get(kPrototypeTransitionsIndex); return FixedArray::cast(prototype_transitions); } void TransitionArray::SetPrototypeTransitions(FixedArray* transitions) { DCHECK(transitions->IsFixedArray()); set(kPrototypeTransitionsIndex, transitions); } Object** TransitionArray::GetPrototypeTransitionsSlot() { return RawFieldOfElementAt(kPrototypeTransitionsIndex); } Object** TransitionArray::GetKeySlot(int transition_number) { DCHECK(transition_number < number_of_transitions()); return RawFieldOfElementAt(ToKeyIndex(transition_number)); } Name* TransitionArray::GetKey(int transition_number) { DCHECK(transition_number < number_of_transitions()); return Name::cast(get(ToKeyIndex(transition_number))); } Name* TransitionsAccessor::GetKey(int transition_number) { WeakCell* cell = nullptr; switch (encoding()) { case kPrototypeInfo: case kUninitialized: UNREACHABLE(); return nullptr; case kWeakCell: cell = GetTargetCell<kWeakCell>(); break; case kHandler: cell = GetTargetCell<kHandler>(); break; case kFullTransitionArray: return transitions()->GetKey(transition_number); } DCHECK(!cell->cleared()); return GetSimpleTransitionKey(Map::cast(cell->value())); } void TransitionArray::SetKey(int transition_number, Name* key) { DCHECK(transition_number < number_of_transitions()); set(ToKeyIndex(transition_number), key); } Object** TransitionArray::GetTargetSlot(int transition_number) { DCHECK(transition_number < number_of_transitions()); return RawFieldOfElementAt(ToTargetIndex(transition_number)); } // static PropertyDetails TransitionsAccessor::GetTargetDetails(Name* name, Map* target) { DCHECK(!IsSpecialTransition(name)); int descriptor = target->LastAdded(); DescriptorArray* descriptors = target->instance_descriptors(); // Transitions are allowed only for the last added property. DCHECK(descriptors->GetKey(descriptor)->Equals(name)); return descriptors->GetDetails(descriptor); } // static Map* TransitionsAccessor::GetTargetFromRaw(Object* raw) { if (raw->IsWeakCell()) return Map::cast(WeakCell::cast(raw)->value()); return Map::cast(StoreHandler::GetTransitionCell(raw)->value()); } Object* TransitionArray::GetRawTarget(int transition_number) { DCHECK(transition_number < number_of_transitions()); return get(ToTargetIndex(transition_number)); } Map* TransitionArray::GetTarget(int transition_number) { Object* raw = GetRawTarget(transition_number); return TransitionsAccessor::GetTargetFromRaw(raw); } Map* TransitionsAccessor::GetTarget(int transition_number) { WeakCell* cell = nullptr; switch (encoding()) { case kPrototypeInfo: case kUninitialized: UNREACHABLE(); return nullptr; case kWeakCell: cell = GetTargetCell<kWeakCell>(); break; case kHandler: cell = GetTargetCell<kHandler>(); break; case kFullTransitionArray: return transitions()->GetTarget(transition_number); } DCHECK(!cell->cleared()); return Map::cast(cell->value()); } void TransitionArray::SetTarget(int transition_number, Object* value) { DCHECK(!value->IsMap()); DCHECK(transition_number < number_of_transitions()); set(ToTargetIndex(transition_number), value); } int TransitionArray::SearchName(Name* name, int* out_insertion_index) { DCHECK(name->IsUniqueName()); return internal::Search<ALL_ENTRIES>(this, name, number_of_entries(), out_insertion_index); } int TransitionArray::CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1, PropertyAttributes attributes1, Name* key2, uint32_t hash2, PropertyKind kind2, PropertyAttributes attributes2) { int cmp = CompareNames(key1, hash1, key2, hash2); if (cmp != 0) return cmp; return CompareDetails(kind1, attributes1, kind2, attributes2); } int TransitionArray::CompareNames(Name* key1, uint32_t hash1, Name* key2, uint32_t hash2) { if (key1 != key2) { // In case of hash collisions key1 is always "less" than key2. return hash1 <= hash2 ? -1 : 1; } return 0; } int TransitionArray::CompareDetails(PropertyKind kind1, PropertyAttributes attributes1, PropertyKind kind2, PropertyAttributes attributes2) { if (kind1 != kind2) { return static_cast<int>(kind1) < static_cast<int>(kind2) ? -1 : 1; } if (attributes1 != attributes2) { return static_cast<int>(attributes1) < static_cast<int>(attributes2) ? -1 : 1; } return 0; } void TransitionArray::Set(int transition_number, Name* key, Object* target) { set(ToKeyIndex(transition_number), key); set(ToTargetIndex(transition_number), target); } int TransitionArray::Capacity() { if (length() <= kFirstIndex) return 0; return (length() - kFirstIndex) / kTransitionSize; } void TransitionArray::SetNumberOfTransitions(int number_of_transitions) { DCHECK(number_of_transitions <= Capacity()); set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); } } // namespace internal } // namespace v8 #endif // V8_TRANSITIONS_INL_H_