Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index c37a4a8b2086be48e881634f36f36acf034cc56c..cbef145d971a84c9c601234b0241337b3dae2f2e 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -651,9 +651,11 @@ MaybeObject* Object::GetProperty(Object* receiver, |
receiver, result->GetCallbackObject(), name); |
case HANDLER: |
return result->proxy()->GetPropertyWithHandler(receiver, name); |
- case INTERCEPTOR: |
+ case INTERCEPTOR: { |
+ JSObject* recvr = JSObject::cast(receiver); |
return result->holder()->GetPropertyWithInterceptor( |
- receiver, name, attributes); |
+ recvr, name, attributes); |
+ } |
case TRANSITION: |
case NONEXISTENT: |
UNREACHABLE(); |
@@ -1690,7 +1692,7 @@ MaybeObject* JSObject::AddProperty(String* name, |
} |
if (HasFastProperties()) { |
// Ensure the descriptor array does not get too big. |
- if (map_of_this->NumberOfOwnDescriptors() < |
+ if (map_of_this->instance_descriptors()->number_of_descriptors() < |
DescriptorArray::kMaxNumberOfDescriptors) { |
if (value->IsJSFunction()) { |
return AddConstantFunctionProperty(name, |
@@ -1782,11 +1784,8 @@ MaybeObject* JSObject::ConvertTransitionToMapTransition( |
old_target->SetBackPointer(GetHeap()->undefined_value()); |
MaybeObject* maybe_failure = old_target->SetDescriptors(old_descriptors); |
- // Reset the backpointer before returning failure, otherwise the map ends up |
- // with an undefined backpointer and no descriptors, losing its own |
- // descriptors. Setting the backpointer always succeeds. |
- old_target->SetBackPointer(old_map); |
if (maybe_failure->IsFailure()) return maybe_failure; |
+ old_target->SetBackPointer(old_map); |
old_map->set_owns_descriptors(true); |
} |
@@ -2176,13 +2175,11 @@ enum RightTrimMode { FROM_GC, FROM_MUTATOR }; |
static void ZapEndOfFixedArray(Address new_end, int to_trim) { |
// If we are doing a big trim in old space then we zap the space. |
Object** zap = reinterpret_cast<Object**>(new_end); |
- zap++; // Header of filler must be at least one word so skip that. |
for (int i = 1; i < to_trim; i++) { |
*zap++ = Smi::FromInt(0); |
} |
} |
- |
template<RightTrimMode trim_mode> |
static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { |
ASSERT(elms->map() != HEAP->fixed_cow_array_map()); |
@@ -2223,31 +2220,14 @@ static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { |
} |
-void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
- Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
- if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
- int number_of_descriptors = descriptors->number_of_descriptors(); |
- Isolate* isolate = map->GetIsolate(); |
- Handle<DescriptorArray> new_descriptors = |
- isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); |
- DescriptorArray::WhitenessWitness witness(*new_descriptors); |
- |
- for (int i = 0; i < number_of_descriptors; ++i) { |
- new_descriptors->CopyFrom(i, *descriptors, i, witness); |
- } |
- |
- Map::SetDescriptors(map, new_descriptors); |
-} |
- |
- |
-void Map::AppendCallbackDescriptors(Handle<Map> map, |
- Handle<Object> descriptors) { |
+void Map::CopyAppendCallbackDescriptors(Handle<Map> map, |
+ Handle<Object> descriptors) { |
Isolate* isolate = map->GetIsolate(); |
Handle<DescriptorArray> array(map->instance_descriptors()); |
- NeanderArray callbacks(descriptors); |
+ v8::NeanderArray callbacks(descriptors); |
int nof_callbacks = callbacks.length(); |
- |
- ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); |
+ int descriptor_count = array->number_of_descriptors(); |
+ ASSERT(descriptor_count == map->NumberOfOwnDescriptors()); |
// Ensure the keys are symbols before writing them into the instance |
// descriptor. Since it may cause a GC, it has to be done before we |
@@ -2260,23 +2240,51 @@ void Map::AppendCallbackDescriptors(Handle<Map> map, |
entry->set_name(*key); |
} |
- int nof = map->NumberOfOwnDescriptors(); |
+ Handle<DescriptorArray> result = |
+ isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); |
+ |
+ // Ensure that marking will not progress and change color of objects. |
+ DescriptorArray::WhitenessWitness witness(*result); |
+ |
+ // Copy the descriptors from the array. |
+ for (int i = 0; i < descriptor_count; i++) { |
+ result->CopyFrom(i, *array, i, witness); |
+ } |
+ |
+ // After this point the GC is not allowed to run anymore until the map is in a |
+ // consistent state again, i.e., all the descriptors are appended and the |
+ // descriptor array is trimmed to the right size. |
+ Map::SetDescriptors(map, result); |
// Fill in new callback descriptors. Process the callbacks from |
// back to front so that the last callback with a given name takes |
// precedence over previously added callbacks with that name. |
+ int nof = descriptor_count; |
for (int i = nof_callbacks - 1; i >= 0; i--) { |
AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); |
String* key = String::cast(entry->name()); |
// Check if a descriptor with this name already exists before writing. |
- if (array->Search(key, nof) == DescriptorArray::kNotFound) { |
+ if (result->Search(key, nof) == DescriptorArray::kNotFound) { |
CallbacksDescriptor desc(key, entry, entry->property_attributes()); |
- array->Append(&desc); |
+ map->AppendDescriptor(&desc, witness); |
nof += 1; |
} |
} |
- map->SetNumberOfOwnDescriptors(nof); |
+ ASSERT(nof == map->NumberOfOwnDescriptors()); |
+ |
+ // Reinstall the original descriptor array if no new elements were added. |
+ if (nof == descriptor_count) { |
+ Map::SetDescriptors(map, array); |
+ return; |
+ } |
+ |
+ // If duplicates were detected, trim the descriptor array to the right size. |
+ int new_array_size = DescriptorArray::LengthFor(nof); |
+ if (new_array_size < result->length()) { |
+ RightTrimFixedArray<FROM_MUTATOR>( |
+ isolate->heap(), *result, result->length() - new_array_size); |
+ } |
} |
@@ -3340,7 +3348,8 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
// Allocate new content. |
int real_size = map_of_this->NumberOfOwnDescriptors(); |
- int property_count = real_size; |
+ int property_count = |
+ map_of_this->NumberOfDescribedProperties(OWN_DESCRIPTORS); |
if (expected_additional_properties > 0) { |
property_count += expected_additional_properties; |
} else { |
@@ -5004,45 +5013,32 @@ MaybeObject* Map::ShareDescriptor(Descriptor* descriptor) { |
String* name = descriptor->GetKey(); |
TransitionArray* transitions; |
- MaybeObject* maybe_transitions = |
- AddTransition(name, result, SIMPLE_TRANSITION); |
+ MaybeObject* maybe_transitions = AddTransition(name, result); |
if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
DescriptorArray* descriptors = instance_descriptors(); |
int old_size = descriptors->number_of_descriptors(); |
DescriptorArray* new_descriptors; |
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); |
+ if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
+ DescriptorArray::WhitenessWitness witness(new_descriptors); |
- if (descriptors->NumberOfSlackDescriptors() > 0) { |
- new_descriptors = descriptors; |
- new_descriptors->Append(descriptor); |
- } else { |
- // Descriptor arrays grow by 50%. |
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate( |
- old_size, old_size < 4 ? 1 : old_size / 2); |
- if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- |
- DescriptorArray::WhitenessWitness witness(new_descriptors); |
- |
- // Copy the descriptors, inserting a descriptor. |
- for (int i = 0; i < old_size; ++i) { |
- new_descriptors->CopyFrom(i, descriptors, i, witness); |
- } |
- |
- new_descriptors->Append(descriptor, witness); |
+ for (int i = 0; i < old_size; ++i) { |
+ new_descriptors->CopyFrom(i, descriptors, i, witness); |
+ } |
+ new_descriptors->Append(descriptor, witness, old_size); |
- // If the source descriptors had an enum cache we copy it. This ensures that |
- // the maps to which we push the new descriptor array back can rely on a |
- // cache always being available once it is set. If the map has more |
- // enumerated descriptors than available in the original cache, the cache |
- // will be lazily replaced by the extended cache when needed. |
- if (descriptors->HasEnumCache()) { |
- new_descriptors->CopyEnumCacheFrom(descriptors); |
- } |
+ // If the source descriptors had an enum cache we copy it. This ensures that |
+ // the maps to which we push the new descriptor array back can rely on a |
+ // cache always being available once it is set. If the map has more |
+ // enumerated descriptors than available in the original cache, the cache |
+ // will be lazily replaced by the extended cache when needed. |
+ if (descriptors->HasEnumCache()) { |
+ new_descriptors->CopyEnumCacheFrom(descriptors); |
} |
transitions->set_descriptors(new_descriptors); |
- |
set_transitions(transitions); |
result->SetBackPointer(this); |
set_owns_descriptors(false); |
@@ -5056,8 +5052,7 @@ MaybeObject* Map::ShareDescriptor(Descriptor* descriptor) { |
MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
String* name, |
- TransitionFlag flag, |
- int descriptor_index) { |
+ TransitionFlag flag) { |
ASSERT(descriptors->IsSortedNoDuplicates()); |
Map* result; |
@@ -5074,11 +5069,7 @@ MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { |
TransitionArray* transitions; |
- SimpleTransitionFlag simple_flag = |
- (descriptor_index == descriptors->number_of_descriptors() - 1) |
- ? SIMPLE_TRANSITION |
- : FULL_TRANSITION; |
- MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); |
+ MaybeObject* maybe_transitions = AddTransition(name, result); |
if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
if (descriptors->IsEmpty()) { |
@@ -5183,7 +5174,7 @@ MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { |
descriptors->CopyUpTo(number_of_own_descriptors); |
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); |
+ return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION); |
} |
@@ -5195,7 +5186,7 @@ MaybeObject* Map::Copy() { |
descriptors->CopyUpTo(number_of_own_descriptors); |
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
- return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); |
+ return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION); |
} |
@@ -5218,7 +5209,7 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, |
} |
DescriptorArray* new_descriptors; |
- MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); |
+ MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); |
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
DescriptorArray::WhitenessWitness witness(new_descriptors); |
@@ -5228,18 +5219,10 @@ MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, |
new_descriptors->CopyFrom(i, descriptors, i, witness); |
} |
- if (old_size != descriptors->number_of_descriptors()) { |
- new_descriptors->SetNumberOfDescriptors(new_size); |
- new_descriptors->Set(old_size, descriptor, witness); |
- new_descriptors->Sort(); |
- } else { |
- new_descriptors->Append(descriptor, witness); |
- } |
+ new_descriptors->Set(old_size, descriptor, witness); |
+ new_descriptors->Sort(); |
- String* key = descriptor->GetKey(); |
- int insertion_index = new_descriptors->number_of_descriptors() - 1; |
- |
- return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); |
+ return CopyReplaceDescriptors(new_descriptors, descriptor->GetKey(), flag); |
} |
@@ -5315,7 +5298,7 @@ MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, |
// Re-sort if descriptors were removed. |
if (new_size != descriptors->length()) new_descriptors->Sort(); |
- return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); |
+ return CopyReplaceDescriptors(new_descriptors, key, flag); |
} |
@@ -6090,17 +6073,16 @@ bool FixedArray::IsEqualTo(FixedArray* other) { |
#endif |
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { |
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { |
Heap* heap = Isolate::Current()->heap(); |
// Do not use DescriptorArray::cast on incomplete object. |
- int size = number_of_descriptors + slack; |
- if (size == 0) return heap->empty_descriptor_array(); |
FixedArray* result; |
+ if (number_of_descriptors == 0) return heap->empty_descriptor_array(); |
// Allocate the array of keys. |
- MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size)); |
+ MaybeObject* maybe_array = |
+ heap->AllocateFixedArray(LengthFor(number_of_descriptors)); |
if (!maybe_array->To(&result)) return maybe_array; |
- result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); |
result->set(kEnumCacheIndex, Smi::FromInt(0)); |
return result; |
} |
@@ -6117,7 +6099,7 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
if (HasEnumCache()) { |
- ASSERT(new_cache->length() > GetEnumCache()->length()); |
+ ASSERT(new_cache->length() > FixedArray::cast(GetEnumCache())->length()); |
FixedArray::cast(get(kEnumCacheIndex))-> |
set(kEnumCacheBridgeCacheIndex, new_cache); |
FixedArray::cast(get(kEnumCacheIndex))-> |
@@ -7390,6 +7372,7 @@ void StringHasher::AddSurrogatePairNoIndex(uc32 c) { |
uint32_t StringHasher::GetHashField() { |
+ ASSERT(is_valid()); |
if (length_ <= String::kMaxHashCalcLength) { |
if (is_array_index()) { |
return MakeArrayIndexHash(array_index(), length_); |
@@ -7453,51 +7436,6 @@ static bool ClearBackPointer(Heap* heap, Map* target) { |
} |
-static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) { |
- int live_enum = map->EnumLength(); |
- if (live_enum == Map::kInvalidEnumCache) { |
- live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
- } |
- if (live_enum == 0) return descriptors->ClearEnumCache(); |
- |
- FixedArray* enum_cache = descriptors->GetEnumCache(); |
- |
- int to_trim = enum_cache->length() - live_enum; |
- if (to_trim <= 0) return; |
- RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim); |
- |
- if (!descriptors->HasEnumIndicesCache()) return; |
- FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache(); |
- RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim); |
-} |
- |
- |
-static void TrimDescriptorArray(Heap* heap, |
- Map* map, |
- DescriptorArray* descriptors, |
- int number_of_own_descriptors) { |
- int number_of_descriptors = descriptors->number_of_descriptors(); |
- int to_trim = number_of_descriptors - number_of_own_descriptors; |
- if (to_trim <= 0) return; |
- |
- // Maximally keep 50% of unused descriptors. |
- int keep = Min(to_trim, number_of_own_descriptors / 2); |
- for (int i = number_of_own_descriptors; |
- i < number_of_own_descriptors + keep; |
- ++i) { |
- descriptors->EraseDescriptor(heap, i); |
- } |
- |
- if (to_trim > keep) { |
- RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim - keep); |
- } |
- descriptors->SetNumberOfDescriptors(number_of_own_descriptors); |
- |
- if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors); |
- descriptors->Sort(); |
-} |
- |
- |
// TODO(mstarzinger): This method should be moved into MarkCompactCollector, |
// because it cannot be called from outside the GC and we already have methods |
// depending on the transitions layout in the GC anyways. |
@@ -7556,7 +7494,28 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
if (descriptors_owner_died) { |
if (number_of_own_descriptors > 0) { |
- TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors); |
+ int number_of_descriptors = descriptors->number_of_descriptors(); |
+ int to_trim = number_of_descriptors - number_of_own_descriptors; |
+ if (to_trim > 0) { |
+ RightTrimFixedArray<FROM_GC>( |
+ heap, descriptors, to_trim * DescriptorArray::kDescriptorSize); |
+ if (descriptors->HasEnumCache()) { |
+ int live_enum = |
+ NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
+ if (live_enum == 0) { |
+ descriptors->ClearEnumCache(); |
+ } else { |
+ FixedArray* enum_cache = |
+ FixedArray::cast(descriptors->GetEnumCache()); |
+ to_trim = enum_cache->length() - live_enum; |
+ if (to_trim > 0) { |
+ RightTrimFixedArray<FROM_GC>( |
+ heap, FixedArray::cast(descriptors->GetEnumCache()), to_trim); |
+ } |
+ } |
+ } |
+ descriptors->Sort(); |
+ } |
ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); |
} else { |
t->set_descriptors(heap->empty_descriptor_array()); |
@@ -7576,8 +7535,8 @@ void Map::ClearNonLiveTransitions(Heap* heap) { |
int trim = t->number_of_transitions() - transition_index; |
if (trim > 0) { |
- RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition() |
- ? trim : trim * TransitionArray::kTransitionSize); |
+ RightTrimFixedArray<FROM_GC>( |
+ heap, t, trim * TransitionArray::kTransitionSize); |
} |
} |
@@ -10524,7 +10483,7 @@ InterceptorInfo* JSObject::GetIndexedInterceptor() { |
MaybeObject* JSObject::GetPropertyPostInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
// Check local property in holder, ignore interceptor. |
@@ -10542,7 +10501,7 @@ MaybeObject* JSObject::GetPropertyPostInterceptor( |
MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
// Check local property in holder, ignore interceptor. |
@@ -10556,13 +10515,13 @@ MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
MaybeObject* JSObject::GetPropertyWithInterceptor( |
- Object* receiver, |
+ JSReceiver* receiver, |
String* name, |
PropertyAttributes* attributes) { |
Isolate* isolate = GetIsolate(); |
InterceptorInfo* interceptor = GetNamedInterceptor(); |
HandleScope scope(isolate); |
- Handle<Object> receiver_handle(receiver); |
+ Handle<JSReceiver> receiver_handle(receiver); |
Handle<JSObject> holder_handle(this); |
Handle<String> name_handle(name); |
@@ -10694,16 +10653,9 @@ bool JSObject::HasRealNamedCallbackProperty(String* key) { |
int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { |
- if (HasFastProperties()) { |
- Map* map = this->map(); |
- if (filter == NONE) return map->NumberOfOwnDescriptors(); |
- if (filter == DONT_ENUM) { |
- int result = map->EnumLength(); |
- if (result != Map::kInvalidEnumCache) return result; |
- } |
- return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter); |
- } |
- return property_dictionary()->NumberOfElementsFilterAttributes(filter); |
+ return HasFastProperties() ? |
+ map()->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter) : |
+ property_dictionary()->NumberOfElementsFilterAttributes(filter); |
} |