Avoid dictionary expansion during bootstrapping.
Allocate the code stubs dictionary and non monomorphic cache dictionary with an initial size which avoids these dictionaries to be expanded during bootstrapping. This gets rid of 9 dictionary expansions during bootstrapping. Preallocate the dictionary when normalizing an object to a size sufficient for holding the number of properties which is expected to be added to the object. This is used when ceating an object from an object literal boilerplate where multiple properties are known to be added. This gets rid of 10 dictionary expansions during bootstrapping. There are now 3 dictionary expansions left during bootstrapping. Review URL: http://codereview.chromium.org/160382 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2584 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
027f8d11c7
commit
cffc051177
@ -164,8 +164,11 @@ void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func,
|
||||
|
||||
|
||||
void NormalizeProperties(Handle<JSObject> object,
|
||||
PropertyNormalizationMode mode) {
|
||||
CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(mode));
|
||||
PropertyNormalizationMode mode,
|
||||
int expected_additional_properties) {
|
||||
CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(
|
||||
mode,
|
||||
expected_additional_properties));
|
||||
}
|
||||
|
||||
|
||||
@ -651,13 +654,17 @@ bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag) {
|
||||
|
||||
OptimizedObjectForAddingMultipleProperties::
|
||||
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
|
||||
int expected_additional_properties,
|
||||
bool condition) {
|
||||
object_ = object;
|
||||
if (condition && object_->HasFastProperties()) {
|
||||
// Normalize the properties of object to avoid n^2 behavior
|
||||
// when extending the object multiple properties.
|
||||
// when extending the object multiple properties. Indicate the number of
|
||||
// properties to be added.
|
||||
unused_property_fields_ = object->map()->unused_property_fields();
|
||||
NormalizeProperties(object_, KEEP_INOBJECT_PROPERTIES);
|
||||
NormalizeProperties(object_,
|
||||
KEEP_INOBJECT_PROPERTIES,
|
||||
expected_additional_properties);
|
||||
has_been_transformed_ = true;
|
||||
|
||||
} else {
|
||||
|
@ -181,7 +181,8 @@ class HandleScope {
|
||||
// of space or encountering an internal error.
|
||||
|
||||
void NormalizeProperties(Handle<JSObject> object,
|
||||
PropertyNormalizationMode mode);
|
||||
PropertyNormalizationMode mode,
|
||||
int expected_additional_properties);
|
||||
void NormalizeElements(Handle<JSObject> object);
|
||||
void TransformToFastProperties(Handle<JSObject> object,
|
||||
int unused_property_fields);
|
||||
@ -336,6 +337,7 @@ class NoHandleAllocation BASE_EMBEDDED {
|
||||
class OptimizedObjectForAddingMultipleProperties BASE_EMBEDDED {
|
||||
public:
|
||||
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
|
||||
int expected_property_count,
|
||||
bool condition = true);
|
||||
~OptimizedObjectForAddingMultipleProperties();
|
||||
private:
|
||||
|
10
src/heap.cc
10
src/heap.cc
@ -1443,13 +1443,15 @@ bool Heap::CreateInitialObjects() {
|
||||
if (obj->IsFailure()) return false;
|
||||
set_prototype_accessors(Proxy::cast(obj));
|
||||
|
||||
// Allocate the code_stubs dictionary.
|
||||
obj = NumberDictionary::Allocate(4);
|
||||
// Allocate the code_stubs dictionary. The initial size is set to avoid
|
||||
// expanding the dictionary during bootstrapping.
|
||||
obj = NumberDictionary::Allocate(128);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_code_stubs(NumberDictionary::cast(obj));
|
||||
|
||||
// Allocate the non_monomorphic_cache used in stub-cache.cc
|
||||
obj = NumberDictionary::Allocate(4);
|
||||
// Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
|
||||
// is set to avoid expanding the dictionary during bootstrapping.
|
||||
obj = NumberDictionary::Allocate(64);
|
||||
if (obj->IsFailure()) return false;
|
||||
set_non_monomorphic_cache(NumberDictionary::cast(obj));
|
||||
|
||||
|
@ -1244,7 +1244,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
// hidden symbols) and is not a real identifier.
|
||||
StringInputBuffer buffer(name);
|
||||
if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) {
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
return AddSlowProperty(name, value, attributes);
|
||||
}
|
||||
@ -1282,7 +1282,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
|
||||
if (map()->unused_property_fields() == 0) {
|
||||
if (properties()->length() > kMaxFastProperties) {
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
return AddSlowProperty(name, value, attributes);
|
||||
}
|
||||
@ -1403,7 +1403,7 @@ Object* JSObject::AddProperty(String* name,
|
||||
} else {
|
||||
// Normalize the object to prevent very large instance descriptors.
|
||||
// This eliminates unwanted N^2 allocation and lookup behavior.
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
}
|
||||
}
|
||||
@ -1473,7 +1473,7 @@ Object* JSObject::ConvertDescriptorToField(String* name,
|
||||
PropertyAttributes attributes) {
|
||||
if (map()->unused_property_fields() == 0 &&
|
||||
properties()->length() > kMaxFastProperties) {
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
return ReplaceSlowProperty(name, new_value, attributes);
|
||||
}
|
||||
@ -2124,15 +2124,22 @@ PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) {
|
||||
Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
|
||||
int expected_additional_properties) {
|
||||
if (!HasFastProperties()) return this;
|
||||
|
||||
// The global object is always normalized.
|
||||
ASSERT(!IsGlobalObject());
|
||||
|
||||
// Allocate new content.
|
||||
int property_count = map()->NumberOfDescribedProperties();
|
||||
if (expected_additional_properties > 0) {
|
||||
property_count += expected_additional_properties;
|
||||
} else {
|
||||
property_count += 2; // Make space for two more properties.
|
||||
}
|
||||
Object* obj =
|
||||
StringDictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4);
|
||||
StringDictionary::Allocate(property_count * 2);
|
||||
if (obj->IsFailure()) return obj;
|
||||
StringDictionary* dictionary = StringDictionary::cast(obj);
|
||||
|
||||
@ -2272,7 +2279,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) {
|
||||
if (!result.IsValid()) return Heap::true_value();
|
||||
|
||||
// Normalize object if needed.
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
|
||||
return DeleteNormalizedProperty(name, mode);
|
||||
@ -2469,7 +2476,7 @@ Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
|
||||
mode);
|
||||
}
|
||||
// Normalize object if needed.
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
// Make sure the properties are normalized before removing the entry.
|
||||
return DeleteNormalizedProperty(name, mode);
|
||||
@ -2802,7 +2809,7 @@ Object* JSObject::DefineGetterSetter(String* name,
|
||||
set_elements(NumberDictionary::cast(dict));
|
||||
} else {
|
||||
// Normalize object to make this operation simple.
|
||||
Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (ok->IsFailure()) return ok;
|
||||
|
||||
// For the global object allocate a new map to invalidate the global inline
|
||||
|
@ -1584,8 +1584,11 @@ class JSObject: public HeapObject {
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Convert the object to use the canonical dictionary
|
||||
// representation.
|
||||
Object* NormalizeProperties(PropertyNormalizationMode mode);
|
||||
// representation. If the object is expected to have additional properties
|
||||
// added this number can be indicated to have the backing store allocated to
|
||||
// an initial capacity for holding these properties.
|
||||
Object* NormalizeProperties(PropertyNormalizationMode mode,
|
||||
int expected_additional_properties);
|
||||
Object* NormalizeElements();
|
||||
|
||||
// Transform slow named properties to fast variants.
|
||||
|
@ -268,6 +268,7 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
{ // Add the constant properties to the boilerplate.
|
||||
int length = constant_properties->length();
|
||||
OptimizedObjectForAddingMultipleProperties opt(boilerplate,
|
||||
length / 2,
|
||||
!is_result_from_cache);
|
||||
for (int index = 0; index < length; index +=2) {
|
||||
Handle<Object> key(constant_properties->get(index+0));
|
||||
@ -3033,7 +3034,7 @@ static Object* Runtime_ToSlowProperties(Arguments args) {
|
||||
Handle<Object> object = args.at<Object>(0);
|
||||
if (object->IsJSObject()) {
|
||||
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
||||
js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
|
||||
js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
}
|
||||
return *object;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user