Chromium Code Reviews| Index: src/objects-inl.h |
| diff --git a/src/objects-inl.h b/src/objects-inl.h |
| index b33466977fa85fe60da724e23151e8d1441c61c4..ba889b3ceb95639047ece10ce8dea1fa11b563f7 100644 |
| --- a/src/objects-inl.h |
| +++ b/src/objects-inl.h |
| @@ -47,6 +47,8 @@ |
| #include "v8memory.h" |
| #include "factory.h" |
| #include "incremental-marking.h" |
| +#include "transitions.h" |
|
Jakob Kummerow
2012/06/29 16:31:36
As an exception from not relying on indirect #incl
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| +#include "transitions-inl.h" |
| namespace v8 { |
| namespace internal { |
| @@ -524,6 +526,11 @@ bool Object::IsDescriptorArray() { |
| } |
| +bool Object::IsTransitionArray() { |
| + return IsFixedArray(); |
| +} |
| + |
| + |
| bool Object::IsDeoptimizationInputData() { |
| // Must be a fixed array. |
| if (!IsFixedArray()) return false; |
| @@ -1885,13 +1892,18 @@ bool DescriptorArray::MayContainTransitions() { |
| } |
| +bool DescriptorArray::HasTransitionArray() { |
| + return MayContainTransitions() && !get(kTransitionsIndex)->IsSmi(); |
| +} |
| + |
| + |
| int DescriptorArray::bit_field3_storage() { |
| Object* storage = READ_FIELD(this, kBitField3StorageOffset); |
| return Smi::cast(storage)->value(); |
| } |
| void DescriptorArray::set_bit_field3_storage(int value) { |
| - ASSERT(this->MayContainTransitions()); |
| + ASSERT(length() > kBitField3StorageIndex); |
| WRITE_FIELD(this, kBitField3StorageOffset, Smi::FromInt(value)); |
| } |
| @@ -1905,60 +1917,105 @@ void DescriptorArray::NoIncrementalWriteBarrierSwap(FixedArray* array, |
| } |
| -int DescriptorArray::Search(String* name) { |
| - SLOW_ASSERT(IsSortedNoDuplicates()); |
| +// Perform a binary search in a fixed array.Low and high are entry indices. If |
|
Jakob Kummerow
2012/06/29 16:31:36
nit: missing space after '.'.
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| +// there are three entries in this array it should be called with low=0 and |
| +// high=2. |
| +template<typename T> |
| +int BinarySearch(T* array, String* name, int low, int high) { |
| + uint32_t hash = name->Hash(); |
| + int limit = high; |
| + |
| + ASSERT(low <= high); |
| + |
| + while (low != high) { |
| + int mid = (low + high) / 2; |
| + String* mid_name = array->GetKey(mid); |
| + uint32_t mid_hash = mid_name->Hash(); |
| + |
| + if (mid_hash >= hash) { |
| + high = mid; |
| + } else { |
| + low = mid + 1; |
| + } |
| + } |
| + |
| + for (; low <= limit && array->GetKey(low)->Hash() == hash; ++low) { |
| + if (array->GetKey(low)->Equals(name)) return low; |
| + } |
| + |
| + return T::kNotFound; |
| +} |
| + |
| + |
| +// Perform a linear search in this fixed array. len is the number of entry |
| +// indices that are valid. |
| +template<typename T> |
| +int LinearSearch(T* array, SearchMode mode, String* name, int len) { |
| + uint32_t hash = name->Hash(); |
| + for (int number = 0; number < len; number++) { |
| + String* entry = array->GetKey(number); |
| + uint32_t current_hash = entry->Hash(); |
| + if (mode == EXPECT_SORTED && current_hash > hash) break; |
| + if (current_hash == hash && name->Equals(entry)) return number; |
| + } |
| + return T::kNotFound; |
| +} |
| + |
| + |
| +template<typename T> |
| +int Search(T* array, String* name) { |
| + // SLOW_ASSERT(IsSortedNoDuplicates()); |
|
Jakob Kummerow
2012/06/29 16:31:36
Please either (fix and) enable this or remove it.
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| // Check for empty descriptor array. |
| - int nof = number_of_descriptors(); |
| - if (nof == 0) return kNotFound; |
| + int nof = array->number_of_entries(); |
| + if (nof == 0) return T::kNotFound; |
| // Fast case: do linear search for small arrays. |
| const int kMaxElementsForLinearSearch = 8; |
| if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) { |
| - return LinearSearch(EXPECT_SORTED, name, nof); |
| + return LinearSearch(array, EXPECT_SORTED, name, nof); |
| } |
| // Slow case: perform binary search. |
| - return BinarySearch(name, 0, nof - 1); |
| + return BinarySearch(array, name, 0, nof - 1); |
| +} |
| + |
| + |
| +int DescriptorArray::Search(String* name) { |
| + return internal::Search(this, name); |
| } |
| int DescriptorArray::SearchWithCache(String* name) { |
| - int number = GetIsolate()->descriptor_lookup_cache()->Lookup(this, name); |
| + DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); |
| + int number = cache->Lookup(this, name); |
| if (number == DescriptorLookupCache::kAbsent) { |
| - number = Search(name); |
| - GetIsolate()->descriptor_lookup_cache()->Update(this, name, number); |
| + number = internal::Search(this, name); |
| + cache->Update(this, name, number); |
| } |
| return number; |
| } |
| -Map* DescriptorArray::elements_transition_map() { |
| - if (!this->MayContainTransitions()) { |
| - return NULL; |
| - } |
| - Object* transition_map = get(kTransitionsIndex); |
| - if (transition_map == Smi::FromInt(0)) { |
| - return NULL; |
| - } else { |
| - return Map::cast(transition_map); |
| - } |
| +TransitionArray* DescriptorArray::transitions() { |
| + if (!this->MayContainTransitions()) return NULL; |
|
Michael Starzinger
2012/06/28 16:02:12
Somehow it feels wrong to return NULL here. Either
Toon Verwaest
2012/06/29 08:14:55
Done.
|
| + Object* array = get(kTransitionsIndex); |
| + if (array->IsSmi()) return NULL; |
| + return TransitionArray::cast(array); |
| } |
| -void DescriptorArray::set_elements_transition_map( |
| - Map* transition_map, WriteBarrierMode mode) { |
| - ASSERT(this->length() > kTransitionsIndex); |
| - Heap* heap = GetHeap(); |
| - WRITE_FIELD(this, kTransitionsOffset, transition_map); |
| - CONDITIONAL_WRITE_BARRIER( |
| - heap, this, kTransitionsOffset, transition_map, mode); |
| - ASSERT(DescriptorArray::cast(this)); |
| +void DescriptorArray::ClearTransitions() { |
| + WRITE_FIELD(this, kTransitionsOffset, Smi::FromInt(0)); |
| } |
| -void DescriptorArray::ClearElementsTransition() { |
| - WRITE_FIELD(this, kTransitionsOffset, Smi::FromInt(0)); |
| +void DescriptorArray::set_transitions( |
|
Jakob Kummerow
2012/06/29 16:31:36
nit: for declarations, each argument on its own li
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| + TransitionArray* transitions_array, WriteBarrierMode mode) { |
| + Heap* heap = GetHeap(); |
| + WRITE_FIELD(this, kTransitionsOffset, transitions_array); |
| + CONDITIONAL_WRITE_BARRIER( |
| + heap, this, kTransitionsOffset, transitions_array, mode); |
| } |
| @@ -1976,17 +2033,6 @@ String* DescriptorArray::GetKey(int descriptor_number) { |
| } |
| -void DescriptorArray::SetKeyUnchecked(Heap* heap, |
| - int descriptor_number, |
| - String* key) { |
| - ASSERT(descriptor_number < number_of_descriptors()); |
| - set_unchecked(heap, |
| - ToKeyIndex(descriptor_number), |
| - key, |
| - UPDATE_WRITE_BARRIER); |
| -} |
| - |
| - |
| Object** DescriptorArray::GetValueSlot(int descriptor_number) { |
| ASSERT(descriptor_number < number_of_descriptors()); |
| return HeapObject::RawField( |
| @@ -2001,24 +2047,6 @@ Object* DescriptorArray::GetValue(int descriptor_number) { |
| } |
| -void DescriptorArray::SetNullValueUnchecked(Heap* heap, int descriptor_number) { |
| - ASSERT(descriptor_number < number_of_descriptors()); |
| - set_null_unchecked(heap, ToValueIndex(descriptor_number)); |
| -} |
| - |
| - |
| - |
| -void DescriptorArray::SetValueUnchecked(Heap* heap, |
| - int descriptor_number, |
| - Object* value) { |
| - ASSERT(descriptor_number < number_of_descriptors()); |
| - set_unchecked(heap, |
| - ToValueIndex(descriptor_number), |
| - value, |
| - UPDATE_WRITE_BARRIER); |
| -} |
| - |
| - |
| PropertyDetails DescriptorArray::GetDetails(int descriptor_number) { |
| ASSERT(descriptor_number < number_of_descriptors()); |
| Object* details = get(ToDetailsIndex(descriptor_number)); |
| @@ -2026,12 +2054,6 @@ PropertyDetails DescriptorArray::GetDetails(int descriptor_number) { |
| } |
| -void DescriptorArray::SetDetailsUnchecked(int descriptor_number, Smi* value) { |
| - ASSERT(descriptor_number < number_of_descriptors()); |
| - set_unchecked(ToDetailsIndex(descriptor_number), value); |
| -} |
| - |
| - |
| PropertyType DescriptorArray::GetType(int descriptor_number) { |
| return GetDetails(descriptor_number).type(); |
| } |
| @@ -2060,38 +2082,6 @@ AccessorDescriptor* DescriptorArray::GetCallbacks(int descriptor_number) { |
| } |
| -bool DescriptorArray::IsProperty(int descriptor_number) { |
| - Entry entry(this, descriptor_number); |
| - return IsPropertyDescriptor(&entry); |
| -} |
| - |
| - |
| -bool DescriptorArray::IsTransitionOnly(int descriptor_number) { |
| - switch (GetType(descriptor_number)) { |
| - case MAP_TRANSITION: |
| - case CONSTANT_TRANSITION: |
| - return true; |
| - case CALLBACKS: { |
| - Object* value = GetValue(descriptor_number); |
| - if (!value->IsAccessorPair()) return false; |
| - AccessorPair* accessors = AccessorPair::cast(value); |
| - return accessors->getter()->IsMap() && accessors->setter()->IsMap(); |
| - } |
| - case NORMAL: |
| - case FIELD: |
| - case CONSTANT_FUNCTION: |
| - case HANDLER: |
| - case INTERCEPTOR: |
| - return false; |
| - case NONEXISTENT: |
| - UNREACHABLE(); |
| - break; |
| - } |
| - UNREACHABLE(); // Keep the compiler happy. |
| - return false; |
| -} |
| - |
| - |
| void DescriptorArray::Get(int descriptor_number, Descriptor* desc) { |
| desc->Init(GetKey(descriptor_number), |
| GetValue(descriptor_number), |
| @@ -3431,12 +3421,8 @@ void Map::init_instance_descriptors() { |
| void Map::clear_instance_descriptors() { |
| - Object* object = READ_FIELD(this, |
| - kInstanceDescriptorsOrBitField3Offset); |
| + Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset); |
| if (!object->IsSmi()) { |
| -#ifdef DEBUG |
| - ZapInstanceDescriptors(); |
| -#endif |
| WRITE_FIELD( |
| this, |
| kInstanceDescriptorsOrBitField3Offset, |
| @@ -3462,11 +3448,6 @@ void Map::set_instance_descriptors(DescriptorArray* value, |
| } |
| } |
| ASSERT(!is_shared()); |
| -#ifdef DEBUG |
| - if (value != instance_descriptors()) { |
| - ZapInstanceDescriptors(); |
| - } |
| -#endif |
| WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value); |
| CONDITIONAL_WRITE_BARRIER( |
| heap, this, kInstanceDescriptorsOrBitField3Offset, value, mode); |
| @@ -3489,7 +3470,7 @@ void Map::ClearDescriptorArray() { |
| #ifdef DEBUG |
| Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset); |
| if (!object->IsSmi()) { |
| - ZapInstanceDescriptors(); |
| + ZapTransitions(); |
| } |
| #endif |
| WRITE_FIELD(this, |
| @@ -3521,13 +3502,85 @@ Object* Map::GetBackPointer() { |
| } |
| +bool Map::HasElementsTransition() { |
| + return HasTransitionArray() && transitions()->HasElementsTransition(); |
| +} |
| + |
| + |
| +bool Map::HasTransitionArray() { |
| + return instance_descriptors()->HasTransitionArray(); |
| +} |
| + |
| + |
| Map* Map::elements_transition_map() { |
| - return instance_descriptors()->elements_transition_map(); |
| + return transitions()->elements(); |
| +} |
| + |
| + |
| +// If the descriptor is using the empty transition array, install a new empty |
| +// transition array that will have place for an element transition. |
|
Jakob Kummerow
2012/06/29 16:31:36
nit:
// If the descriptor array does not have a t
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| +static MaybeObject* AllowElementsTransition(Map* map) { |
| + if (map->HasTransitionArray()) return map; |
| + |
| + TransitionArray* transitions; |
| + MaybeObject* maybe_transitions = TransitionArray::Allocate(0); |
| + if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
| + MaybeObject* added_transitions = map->set_transitions(transitions); |
| + if (added_transitions->IsFailure()) return added_transitions; |
| + return transitions; |
| +} |
| + |
| + |
| +MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) { |
| + MaybeObject* allow_elements = AllowElementsTransition(this); |
| + if (allow_elements->IsFailure()) return allow_elements; |
| + transitions()->set_elements(transitioned_map); |
| + return this; |
| +} |
| + |
| + |
| +TransitionArray* Map::transitions() { |
| + return instance_descriptors()->transitions(); |
| +} |
| + |
| + |
| +// If the map is using the empty descriptor array, install a new empty |
|
Jakob Kummerow
2012/06/29 16:31:36
This comment is confusing. Maybe something like "I
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| +// descriptor array that will contain an element transition. |
| +static MaybeObject* AllowTransitions(Map* map) { |
| + if (map->instance_descriptors()->MayContainTransitions()) return map; |
| + DescriptorArray* descriptors; |
| + MaybeObject* maybe_descriptors = |
| + DescriptorArray::Allocate(0, DescriptorArray::CANNOT_BE_SHARED); |
| + if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; |
| + map->set_instance_descriptors(descriptors); |
| + return descriptors; |
| } |
| -void Map::set_elements_transition_map(Map* transitioned_map) { |
| - return instance_descriptors()->set_elements_transition_map(transitioned_map); |
| +void Map::ClearTransitions() { |
| +#ifdef DEBUG |
| + ZapTransitions(); |
| +#endif |
| + DescriptorArray* descriptors = instance_descriptors(); |
| + if (descriptors->number_of_descriptors() == 0) { |
| + ClearDescriptorArray(); |
| + } else { |
| + descriptors->ClearTransitions(); |
| + } |
| +} |
| + |
| + |
| +MaybeObject* Map::set_transitions(TransitionArray* transitions_array) { |
| + MaybeObject* allow_transitions = AllowTransitions(this); |
| + if (allow_transitions->IsFailure()) return allow_transitions; |
| +#ifdef DEBUG |
| + if (transitions_array == transitions()) { |
|
Jakob Kummerow
2012/06/29 16:31:36
You can just do ASSERT(transitions_array != transi
Toon Verwaest
2012/07/05 12:56:11
Done.
|
| + UNREACHABLE(); |
| + } |
| + ZapTransitions(); |
| +#endif |
| + instance_descriptors()->set_transitions(transitions_array); |
| + return this; |
| } |