Chromium Code Reviews| Index: src/runtime.cc |
| =================================================================== |
| --- src/runtime.cc (revision 6540) |
| +++ src/runtime.cc (working copy) |
| @@ -292,7 +292,8 @@ |
| static Handle<Object> CreateObjectLiteralBoilerplate( |
| Handle<FixedArray> literals, |
| Handle<FixedArray> constant_properties, |
| - bool should_have_fast_elements) { |
| + bool should_have_fast_elements, |
| + bool has_function_literal) { |
| // Get the global context from the literals array. This is the |
| // context in which the function was created and we use the object |
| // function from this context to create the object literal. We do |
| @@ -302,65 +303,83 @@ |
| Handle<Context> context = |
| Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); |
| - bool is_result_from_cache; |
| - Handle<Map> map = ComputeObjectLiteralMap(context, |
| - constant_properties, |
| - &is_result_from_cache); |
| + // In case we have function literals, we want the object to be in |
| + // slow properties mode for now and we don't go in the map cache. |
|
Mads Ager (chromium)
2011/02/01 13:51:00
Please expand the comment to say that we cannot sh
fschneider
2011/02/02 10:18:38
Done.
|
| + bool is_result_from_cache = false; |
| + Handle<Map> map = has_function_literal |
| + ? Handle<Map>(context->object_function()->initial_map()) |
| + : ComputeObjectLiteralMap(context, |
| + constant_properties, |
| + &is_result_from_cache); |
| Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); |
| // Normalize the elements of the boilerplate to save space if needed. |
| if (!should_have_fast_elements) NormalizeElements(boilerplate); |
| - { // 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)); |
| - Handle<Object> value(constant_properties->get(index+1)); |
| - if (value->IsFixedArray()) { |
| - // The value contains the constant_properties of a |
| - // simple object literal. |
| - Handle<FixedArray> array = Handle<FixedArray>::cast(value); |
| - value = CreateLiteralBoilerplate(literals, array); |
| - if (value.is_null()) return value; |
| - } |
| - Handle<Object> result; |
| - uint32_t element_index = 0; |
| - if (key->IsSymbol()) { |
| - if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { |
| - // Array index as string (uint32). |
| - result = SetOwnElement(boilerplate, element_index, value); |
| - } else { |
| - Handle<String> name(String::cast(*key)); |
| - ASSERT(!name->AsArrayIndex(&element_index)); |
| - result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
| - value, NONE); |
| - } |
| - } else if (key->ToArrayIndex(&element_index)) { |
| - // Array index (uint32). |
| + // Add the constant properties to the boilerplate. |
| + int length = constant_properties->length(); |
| + bool should_transform = |
| + !is_result_from_cache && boilerplate->HasFastProperties(); |
| + if (should_transform || has_function_literal) { |
| + // Normalize the properties of object to avoid n^2 behavior |
| + // when extending the object multiple properties. Indicate the number of |
| + // properties to be added. |
| + NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); |
| + } |
| + |
| + for (int index = 0; index < length; index +=2) { |
| + Handle<Object> key(constant_properties->get(index+0)); |
| + Handle<Object> value(constant_properties->get(index+1)); |
| + if (value->IsFixedArray()) { |
| + // The value contains the constant_properties of a |
| + // simple object or array literal. |
| + Handle<FixedArray> array = Handle<FixedArray>::cast(value); |
| + value = CreateLiteralBoilerplate(literals, array); |
| + if (value.is_null()) return value; |
| + } |
| + Handle<Object> result; |
| + uint32_t element_index = 0; |
| + if (key->IsSymbol()) { |
| + if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { |
| + // Array index as string (uint32). |
| result = SetOwnElement(boilerplate, element_index, value); |
| } else { |
| - // Non-uint32 number. |
| - ASSERT(key->IsNumber()); |
| - double num = key->Number(); |
| - char arr[100]; |
| - Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
| - const char* str = DoubleToCString(num, buffer); |
| - Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); |
| + Handle<String> name(String::cast(*key)); |
| + ASSERT(!name->AsArrayIndex(&element_index)); |
| result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
| value, NONE); |
| } |
| - // If setting the property on the boilerplate throws an |
| - // exception, the exception is converted to an empty handle in |
| - // the handle based operations. In that case, we need to |
| - // convert back to an exception. |
| - if (result.is_null()) return result; |
| + } else if (key->ToArrayIndex(&element_index)) { |
| + // Array index (uint32). |
| + result = SetOwnElement(boilerplate, element_index, value); |
| + } else { |
| + // Non-uint32 number. |
| + ASSERT(key->IsNumber()); |
| + double num = key->Number(); |
| + char arr[100]; |
| + Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
| + const char* str = DoubleToCString(num, buffer); |
| + Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); |
| + result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
| + value, NONE); |
| } |
| + // If setting the property on the boilerplate throws an |
| + // exception, the exception is converted to an empty handle in |
| + // the handle based operations. In that case, we need to |
| + // convert back to an exception. |
| + if (result.is_null()) return result; |
| } |
| + // Transform to fast properties if necessary. For object literals with |
| + // containing function literals we defer this operation until after all |
| + // computed properties have been assigned so that we can generate |
| + // constant function properties. |
| + if (should_transform && !has_function_literal) { |
| + TransformToFastProperties(boilerplate, |
| + boilerplate->map()->unused_property_fields()); |
| + } |
| + |
| return boilerplate; |
| } |
| @@ -389,7 +408,7 @@ |
| for (int i = 0; i < content->length(); i++) { |
| if (content->get(i)->IsFixedArray()) { |
| // The value contains the constant_properties of a |
| - // simple object literal. |
| + // simple object or array literal. |
| Handle<FixedArray> fa(FixedArray::cast(content->get(i))); |
| Handle<Object> result = |
| CreateLiteralBoilerplate(literals, fa); |
| @@ -411,9 +430,9 @@ |
| Handle<FixedArray> elements = CompileTimeValue::GetElements(array); |
| switch (CompileTimeValue::GetType(array)) { |
| case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: |
| - return CreateObjectLiteralBoilerplate(literals, elements, true); |
| + return CreateObjectLiteralBoilerplate(literals, elements, true, false); |
| case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: |
| - return CreateObjectLiteralBoilerplate(literals, elements, false); |
| + return CreateObjectLiteralBoilerplate(literals, elements, false, false); |
| case CompileTimeValue::ARRAY_LITERAL: |
| return CreateArrayLiteralBoilerplate(literals, elements); |
| default: |
| @@ -450,15 +469,17 @@ |
| CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| CONVERT_SMI_CHECKED(literals_index, args[1]); |
| CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
| - CONVERT_SMI_CHECKED(fast_elements, args[3]); |
| - bool should_have_fast_elements = fast_elements == 1; |
| + CONVERT_SMI_CHECKED(flags, args[3]); |
| + bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| + bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
| // Check if boilerplate exists. If not, create it first. |
| Handle<Object> boilerplate(literals->get(literals_index)); |
| if (*boilerplate == Heap::undefined_value()) { |
| boilerplate = CreateObjectLiteralBoilerplate(literals, |
| constant_properties, |
| - should_have_fast_elements); |
| + should_have_fast_elements, |
| + has_function_literal); |
| if (boilerplate.is_null()) return Failure::Exception(); |
| // Update the functions literal and return the boilerplate. |
| literals->set(literals_index, *boilerplate); |
| @@ -473,15 +494,17 @@ |
| CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
| CONVERT_SMI_CHECKED(literals_index, args[1]); |
| CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
| - CONVERT_SMI_CHECKED(fast_elements, args[3]); |
| - bool should_have_fast_elements = fast_elements == 1; |
| + CONVERT_SMI_CHECKED(flags, args[3]); |
| + bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| + bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
| // Check if boilerplate exists. If not, create it first. |
| Handle<Object> boilerplate(literals->get(literals_index)); |
| if (*boilerplate == Heap::undefined_value()) { |
| boilerplate = CreateObjectLiteralBoilerplate(literals, |
| constant_properties, |
| - should_have_fast_elements); |
| + should_have_fast_elements, |
| + has_function_literal); |
| if (boilerplate.is_null()) return Failure::Exception(); |
| // Update the functions literal and return the boilerplate. |
| literals->set(literals_index, *boilerplate); |