void Genesis::SetFunctionInstanceDescriptor(
Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
- Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
+ Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
DescriptorArray::WhitenessWitness witness(*descriptors);
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
void Genesis::SetStrictFunctionInstanceDescriptor(
Handle<Map> map, PrototypePropertyMode prototypeMode) {
int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
- Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(size));
+ Handle<DescriptorArray> descriptors(factory()->NewDescriptorArray(0, size));
DescriptorArray::WhitenessWitness witness(*descriptors);
Handle<Foreign> length(factory()->NewForeign(&Accessors::FunctionLength));
array_function->shared()->set_length(1);
Handle<Map> initial_map(array_function->initial_map());
- Handle<DescriptorArray> array_descriptors(factory->NewDescriptorArray(1));
+ Handle<DescriptorArray> array_descriptors(
+ factory->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
Handle<Map> string_map =
Handle<Map>(native_context()->string_function()->initial_map());
- Handle<DescriptorArray> string_descriptors(factory->NewDescriptorArray(1));
+ Handle<DescriptorArray> string_descriptors(
+ factory->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*string_descriptors);
Handle<Foreign> string_length(
PropertyAttributes final =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(5);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 5);
DescriptorArray::WhitenessWitness witness(*descriptors);
Map::SetDescriptors(initial_map, descriptors);
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE,
Heap::kArgumentsObjectSizeStrict);
// Create the descriptor array for the arguments object.
- Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(3);
+ Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*descriptors);
Map::SetDescriptors(map, descriptors);
Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
Handle<DescriptorArray> script_descriptors(
- factory()->NewDescriptorArray(13));
+ factory()->NewDescriptorArray(0, 13));
DescriptorArray::WhitenessWitness witness(*script_descriptors);
Handle<Foreign> script_source(
// Make "length" magic on instances.
Handle<Map> initial_map(array_function->initial_map());
- Handle<DescriptorArray> array_descriptors(factory()->NewDescriptorArray(1));
+ Handle<DescriptorArray> array_descriptors(
+ factory()->NewDescriptorArray(0, 1));
DescriptorArray::WhitenessWitness witness(*array_descriptors);
Handle<Foreign> array_length(factory()->NewForeign(
// Update map with length accessor from Array and add "index" and "input".
Handle<DescriptorArray> reresult_descriptors =
- factory()->NewDescriptorArray(3);
+ factory()->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
Map::SetDescriptors(initial_map, reresult_descriptors);
}
-Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
+Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors,
+ int slack) {
ASSERT(0 <= number_of_descriptors);
CALL_HEAP_FUNCTION(isolate(),
- DescriptorArray::Allocate(number_of_descriptors),
+ DescriptorArray::Allocate(number_of_descriptors, slack),
DescriptorArray);
}
result->shared()->DontAdaptArguments();
// Recursively copy parent templates' accessors, 'data' may be modified.
+ int max_number_of_additional_properties = 0;
+ FunctionTemplateInfo* info = *obj;
+ while (true) {
+ Object* props = info->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props);
+ NeanderArray props_array(props_handle);
+ max_number_of_additional_properties += props_array.length();
+ }
+ Object* parent = info->parent_template();
+ if (parent->IsUndefined()) break;
+ info = FunctionTemplateInfo::cast(parent);
+ }
+
+ Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
+
while (true) {
Handle<Object> props = Handle<Object>(obj->property_accessors());
if (!props->IsUndefined()) {
- Map::CopyAppendCallbackDescriptors(map, props);
+ Map::AppendCallbackDescriptors(map, props);
}
Handle<Object> parent = Handle<Object>(obj->parent_template());
if (parent->IsUndefined()) break;
Handle<ObjectHashTable> NewObjectHashTable(int at_least_space_for);
- Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
+ Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors,
+ int slack = 0);
Handle<DeoptimizationInputData> NewDeoptimizationInputData(
int deopt_entry_count,
PretenureFlag pretenure);
if (valid_entries == -1) valid_entries = number_of_descriptors();
String* current_key = NULL;
uint32_t current = 0;
- for (int i = 0; i < valid_entries; i++) {
+ for (int i = 0; i < number_of_descriptors(); i++) {
String* key = GetSortedKey(i);
if (key == current_key) {
PrintDescriptors();
}
+void DescriptorArray::SetNumberOfDescriptors(int number_of_descriptors) {
+ WRITE_FIELD(
+ this, kDescriptorLengthOffset, Smi::FromInt(number_of_descriptors));
+}
+
+
// Perform a binary search in a fixed array. Low and high are entry indices. If
// there are three entries in this array it should be called with low=0 and
// high=2.
}
+void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
+ // Range check.
+ ASSERT(descriptor_number < number_of_descriptors());
+ ASSERT(desc->GetDetails().descriptor_index() <=
+ number_of_descriptors());
+ ASSERT(desc->GetDetails().descriptor_index() > 0);
+
+ set(ToKeyIndex(descriptor_number), desc->GetKey());
+ set(ToValueIndex(descriptor_number), desc->GetValue());
+ set(ToDetailsIndex(descriptor_number), desc->GetDetails().AsSmi());
+}
+
+
+void DescriptorArray::EraseDescriptor(Heap* heap, int descriptor_number) {
+ set_null_unchecked(heap, ToKeyIndex(descriptor_number));
+ set_null_unchecked(heap, ToValueIndex(descriptor_number));
+}
+
+
void DescriptorArray::Append(Descriptor* desc,
- const WhitenessWitness& witness,
- int number_of_set_descriptors) {
- int descriptor_number = number_of_set_descriptors;
+ const WhitenessWitness& witness) {
+ int descriptor_number = number_of_descriptors();
int enumeration_index = descriptor_number + 1;
+ SetNumberOfDescriptors(descriptor_number + 1);
desc->SetEnumerationIndex(enumeration_index);
Set(descriptor_number, desc, witness);
}
+void DescriptorArray::Append(Descriptor* desc) {
+ int descriptor_number = number_of_descriptors();
+ int enumeration_index = descriptor_number + 1;
+ SetNumberOfDescriptors(descriptor_number + 1);
+ desc->SetEnumerationIndex(enumeration_index);
+ Set(descriptor_number, desc);
+
+ uint32_t hash = desc->GetKey()->Hash();
+
+ int insertion;
+
+ for (insertion = descriptor_number; insertion > 0; --insertion) {
+ String* key = GetSortedKey(insertion - 1);
+ if (key->Hash() <= hash) break;
+ SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1));
+ }
+
+ SetSortedKey(insertion, descriptor_number);
+}
+
+
void DescriptorArray::SwapSortedKeys(int first, int second) {
int first_key = GetSortedKeyIndex(first);
SetSortedKey(first, GetSortedKeyIndex(second));
const DescriptorArray::WhitenessWitness& witness) {
DescriptorArray* descriptors = instance_descriptors();
int number_of_own_descriptors = NumberOfOwnDescriptors();
- ASSERT(number_of_own_descriptors < descriptors->number_of_descriptors());
- descriptors->Append(desc, witness, number_of_own_descriptors);
+ ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
+ descriptors->Append(desc, witness);
SetNumberOfOwnDescriptors(number_of_own_descriptors + 1);
}
}
-void Map::CopyAppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors) {
+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) {
Isolate* isolate = map->GetIsolate();
Handle<DescriptorArray> array(map->instance_descriptors());
- v8::NeanderArray callbacks(descriptors);
+ NeanderArray callbacks(descriptors);
int nof_callbacks = callbacks.length();
- int descriptor_count = array->number_of_descriptors();
- ASSERT(descriptor_count == map->NumberOfOwnDescriptors());
+
+ ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
// 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
entry->set_name(*key);
}
- 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);
+ int nof = map->NumberOfOwnDescriptors();
// 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 (result->Search(key, nof) == DescriptorArray::kNotFound) {
+ if (array->Search(key, nof) == DescriptorArray::kNotFound) {
CallbacksDescriptor desc(key, entry, entry->property_attributes());
- map->AppendDescriptor(&desc, witness);
+ array->Append(&desc);
nof += 1;
}
}
- 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);
- }
+ map->SetNumberOfOwnDescriptors(nof);
}
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);
- for (int i = 0; i < old_size; ++i) {
- new_descriptors->CopyFrom(i, descriptors, i, witness);
- }
- new_descriptors->Append(descriptor, witness, old_size);
+ 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);
- // 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);
}
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);
new_descriptors->CopyFrom(i, descriptors, i, witness);
}
- new_descriptors->Set(old_size, descriptor, witness);
- new_descriptors->Sort();
+ 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);
+ }
- return CopyReplaceDescriptors(new_descriptors, descriptor->GetKey(), flag);
+ String* key = descriptor->GetKey();
+
+ return CopyReplaceDescriptors(new_descriptors, key, flag);
}
#endif
-MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
+MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) {
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(number_of_descriptors));
+ MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
if (!maybe_array->To(&result)) return maybe_array;
+ result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
result->set(kEnumCacheIndex, Smi::FromInt(0));
return result;
}
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);
+ // 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()) {
int live_enum =
NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
int number_of_descriptors() {
ASSERT(length() >= kFirstIndex || IsEmpty());
int len = length();
- return len <= kFirstIndex ? 0 : (len - kFirstIndex) / kDescriptorSize;
+ return len == 0 ? 0 : Smi::cast(get(kDescriptorLengthIndex))->value();
}
+ int number_of_descriptors_storage() {
+ int len = length();
+ return len == 0 ? 0 : (len - kFirstIndex) / kDescriptorSize;
+ }
+
+ int NumberOfSlackDescriptors() {
+ return number_of_descriptors_storage() - number_of_descriptors();
+ }
+
+ inline void SetNumberOfDescriptors(int number_of_descriptors);
inline int number_of_entries() { return number_of_descriptors(); }
bool HasEnumCache() {
inline void Set(int descriptor_number,
Descriptor* desc,
const WhitenessWitness&);
+ inline void Set(int descriptor_number, Descriptor* desc);
+ inline void EraseDescriptor(Heap* heap, int descriptor_number);
// Append automatically sets the enumeration index. This should only be used
// to add descriptors in bulk at the end, followed by sorting the descriptor
// array.
- inline void Append(Descriptor* desc,
- const WhitenessWitness&,
- int number_of_set_descriptors);
+ inline void Append(Descriptor* desc, const WhitenessWitness&);
+ inline void Append(Descriptor* desc);
// Transfer a complete descriptor from the src descriptor array to this
// descriptor array.
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
- MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors);
+ MUST_USE_RESULT static MaybeObject* Allocate(int number_of_descriptors,
+ int slack = 0);
// Casting.
static inline DescriptorArray* cast(Object* obj);
// Constant for denoting key was not found.
static const int kNotFound = -1;
- static const int kEnumCacheIndex = 0;
- static const int kFirstIndex = 1;
+ static const int kDescriptorLengthIndex = 0;
+ static const int kEnumCacheIndex = 1;
+ static const int kFirstIndex = 2;
// The length of the "bridge" to the enum cache.
static const int kEnumCacheBridgeLength = 2;
static const int kEnumCacheBridgeIndicesCacheIndex = 1;
// Layout description.
- static const int kEnumCacheOffset = FixedArray::kHeaderSize;
+ static const int kDescriptorLengthOffset = FixedArray::kHeaderSize;
+ static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize;
static const int kFirstOffset = kEnumCacheOffset + kPointerSize;
// Layout description for the bridge array.
// Extend the descriptor array of the map with the list of descriptors.
// In case of duplicates, the latest descriptor is used.
- static void CopyAppendCallbackDescriptors(Handle<Map> map,
- Handle<Object> descriptors);
+ static void AppendCallbackDescriptors(Handle<Map> map,
+ Handle<Object> descriptors);
+
+ static void EnsureDescriptorSlack(Handle<Map> map, int slack);
// Returns the found code or undefined if absent.
Object* FindInCodeCache(String* name, Code::Flags flags);
FACTORY->NewStringFromAscii(Vector<const char>("get", 3));
ASSERT(instance_descriptors->IsEmpty());
- Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(1);
+ Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(0, 1);
v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors);
v8::internal::Map::SetDescriptors(map, new_descriptors);