| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 7281)
|
| +++ src/runtime.cc (working copy)
|
| @@ -304,7 +304,8 @@
|
| Isolate* isolate,
|
| 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
|
| @@ -314,72 +315,92 @@
|
| 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. We don't go in the map cache because
|
| + // maps with constant functions can't be shared if the functions are
|
| + // not the same (which is the common case).
|
| + 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 = isolate->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), isolate);
|
| - Handle<Object> value(constant_properties->get(index+1), isolate);
|
| - if (value->IsFixedArray()) {
|
| - // The value contains the constant_properties of a
|
| - // simple object literal.
|
| - Handle<FixedArray> array = Handle<FixedArray>::cast(value);
|
| - value = CreateLiteralBoilerplate(isolate, 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,
|
| - kNonStrictMode);
|
| - } 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), isolate);
|
| + Handle<Object> value(constant_properties->get(index+1), isolate);
|
| + 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(isolate, 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,
|
| kNonStrictMode);
|
| } 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 =
|
| - isolate->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,
|
| + kNonStrictMode);
|
| + } 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 =
|
| + isolate->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;
|
| }
|
|
|
| @@ -410,7 +431,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(isolate, literals, fa);
|
| @@ -431,11 +452,20 @@
|
| Handle<FixedArray> literals,
|
| Handle<FixedArray> array) {
|
| Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
|
| + const bool kHasNoFunctionLiteral = false;
|
| switch (CompileTimeValue::GetType(array)) {
|
| case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
|
| - return CreateObjectLiteralBoilerplate(isolate, literals, elements, true);
|
| + return CreateObjectLiteralBoilerplate(isolate,
|
| + literals,
|
| + elements,
|
| + true,
|
| + kHasNoFunctionLiteral);
|
| case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
|
| - return CreateObjectLiteralBoilerplate(isolate, literals, elements, false);
|
| + return CreateObjectLiteralBoilerplate(isolate,
|
| + literals,
|
| + elements,
|
| + false,
|
| + kHasNoFunctionLiteral);
|
| case CompileTimeValue::ARRAY_LITERAL:
|
| return CreateArrayLiteralBoilerplate(isolate, literals, elements);
|
| default:
|
| @@ -476,8 +506,9 @@
|
| 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), isolate);
|
| @@ -485,7 +516,8 @@
|
| boilerplate = CreateObjectLiteralBoilerplate(isolate,
|
| 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);
|
| @@ -502,8 +534,9 @@
|
| 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), isolate);
|
| @@ -511,7 +544,8 @@
|
| boilerplate = CreateObjectLiteralBoilerplate(isolate,
|
| 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);
|
|
|