From ef371f3f24b20f7027375416078c1ec1e18c96a1 Mon Sep 17 00:00:00 2001 From: "ager@chromium.org" Date: Thu, 11 Mar 2010 10:34:29 +0000 Subject: [PATCH] Do not waste space for the fast-case elements backing storage for object-literals with few elements but large element indices. We can decide at parse time whether the created object literal should have fast-case of slow-case elements. Remove unused runtime function. Review URL: http://codereview.chromium.org/805004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4100 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 16 +++++++------- src/arm/full-codegen-arm.cc | 15 ++++++------- src/ast.h | 7 ++++++- src/ia32/codegen-ia32.cc | 6 ++++-- src/ia32/full-codegen-ia32.cc | 5 +++-- src/parser.cc | 38 +++++++++++++++++++++++++++++++-- src/parser.h | 3 ++- src/runtime.cc | 49 +++++++++++++++++++------------------------ src/runtime.h | 5 ++--- src/x64/codegen-x64.cc | 6 ++++-- src/x64/full-codegen-x64.cc | 5 +++-- 11 files changed, 99 insertions(+), 56 deletions(-) diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index eceba55..3bf3fb8 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -2709,18 +2709,20 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { Comment cmnt(masm_, "[ ObjectLiteral"); // Load the function of this activation. - __ ldr(r2, frame_->Function()); + __ ldr(r3, frame_->Function()); // Literal array. - __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); + __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); // Literal index. - __ mov(r1, Operand(Smi::FromInt(node->literal_index()))); + __ mov(r2, Operand(Smi::FromInt(node->literal_index()))); // Constant properties. - __ mov(r0, Operand(node->constant_properties())); - frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit()); + __ mov(r1, Operand(node->constant_properties())); + // Should the object literal have fast elements? + __ mov(r0, Operand(Smi::FromInt(node->fast_elements() ? 1 : 0))); + frame_->EmitPushMultiple(4, r3.bit() | r2.bit() | r1.bit() | r0.bit()); if (node->depth() > 1) { - frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); + frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); + frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); } frame_->EmitPush(r0); // save the result for (int i = 0; i < node->properties()->length(); i++) { diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 230818f..a70cf44 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -783,15 +783,16 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); - __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); - __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); - __ mov(r1, Operand(Smi::FromInt(expr->literal_index()))); - __ mov(r0, Operand(expr->constant_properties())); - __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit()); + __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); + __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); + __ mov(r1, Operand(expr->constant_properties())); + __ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0))); + __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit() | r0.bit()); if (expr->depth() > 1) { - __ CallRuntime(Runtime::kCreateObjectLiteral, 3); + __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); + __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); } // If result_saved is true the result is on top of the stack. If diff --git a/src/ast.h b/src/ast.h index d5c85bf..174679a 100644 --- a/src/ast.h +++ b/src/ast.h @@ -871,10 +871,12 @@ class ObjectLiteral: public MaterializedLiteral { ZoneList* properties, int literal_index, bool is_simple, + bool fast_elements, int depth) : MaterializedLiteral(literal_index, is_simple, depth), constant_properties_(constant_properties), - properties_(properties) {} + properties_(properties), + fast_elements_(fast_elements) {} virtual ObjectLiteral* AsObjectLiteral() { return this; } virtual void Accept(AstVisitor* v); @@ -886,9 +888,12 @@ class ObjectLiteral: public MaterializedLiteral { } ZoneList* properties() const { return properties_; } + bool fast_elements() const { return fast_elements_; } + private: Handle constant_properties_; ZoneList* properties_; + bool fast_elements_; }; diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 5c356a1..ca4bb19 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -4780,11 +4780,13 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { frame_->Push(Smi::FromInt(node->literal_index())); // Constant properties. frame_->Push(node->constant_properties()); + // Should the object literal have fast elements? + frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0)); Result clone; if (node->depth() > 1) { - clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); + clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); + clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); } frame_->Push(&clone); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 6e3ae10..cedf9c9 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -901,10 +901,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(expr->constant_properties())); + __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0))); if (expr->depth() > 1) { - __ CallRuntime(Runtime::kCreateObjectLiteral, 3); + __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); + __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); } // If result_saved is true the result is on top of the stack. If diff --git a/src/parser.cc b/src/parser.cc index 57cb0b5..4c5a529 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -212,6 +212,7 @@ class Parser { ZoneList* properties, Handle constants, bool* is_simple, + bool* fast_elements, int* depth); // Populate the literals fixed array for a materialized array literal. @@ -3446,7 +3447,11 @@ Handle CompileTimeValue::GetValue(Expression* expression) { ObjectLiteral* object_literal = expression->AsObjectLiteral(); if (object_literal != NULL) { ASSERT(object_literal->is_simple()); - result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL)); + if (object_literal->fast_elements()) { + result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS)); + } else { + result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS)); + } result->set(kElementsSlot, *object_literal->constant_properties()); } else { ArrayLiteral* array_literal = expression->AsArrayLiteral(); @@ -3484,11 +3489,14 @@ void Parser::BuildObjectLiteralConstantProperties( ZoneList* properties, Handle constant_properties, bool* is_simple, + bool* fast_elements, int* depth) { int position = 0; // Accumulate the value in local variables and store it at the end. bool is_simple_acc = true; int depth_acc = 1; + uint32_t max_element_index = 0; + uint32_t elements = 0; for (int i = 0; i < properties->length(); i++) { ObjectLiteral::Property* property = properties->at(i); if (!IsBoilerplateProperty(property)) { @@ -3507,11 +3515,31 @@ void Parser::BuildObjectLiteralConstantProperties( Handle value = GetBoilerplateValue(property->value()); is_simple_acc = is_simple_acc && !value->IsUndefined(); + // Keep track of the number of elements in the object literal and + // the largest element index. If the largest element index is + // much larger than the number of elements, creating an object + // literal with fast elements will be a waste of space. + uint32_t element_index = 0; + if (key->IsString() + && Handle::cast(key)->AsArrayIndex(&element_index) + && element_index > max_element_index) { + max_element_index = element_index; + elements++; + } else if (key->IsSmi()) { + int key_value = Smi::cast(*key)->value(); + if (key_value > 0 + && static_cast(key_value) > max_element_index) { + max_element_index = key_value; + } + elements++; + } + // Add name, value pair to the fixed array. constant_properties->set(position++, *key); constant_properties->set(position++, *value); } - + *fast_elements = + (max_element_index <= 32) || ((2 * elements) >= max_element_index); *is_simple = is_simple_acc; *depth = depth_acc; } @@ -3609,15 +3637,18 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED); bool is_simple = true; + bool fast_elements = true; int depth = 1; BuildObjectLiteralConstantProperties(properties.elements(), constant_properties, &is_simple, + &fast_elements, &depth); return new ObjectLiteral(constant_properties, properties.elements(), literal_index, is_simple, + fast_elements, depth); } @@ -4144,15 +4175,18 @@ Expression* Parser::ParseJsonObject(bool* ok) { Handle constant_properties = Factory::NewFixedArray(boilerplate_properties * 2, TENURED); bool is_simple = true; + bool fast_elements = true; int depth = 1; BuildObjectLiteralConstantProperties(properties.elements(), constant_properties, &is_simple, + &fast_elements, &depth); return new ObjectLiteral(constant_properties, properties.elements(), literal_index, is_simple, + fast_elements, depth); } diff --git a/src/parser.h b/src/parser.h index 0f808d7..2e5daf9 100644 --- a/src/parser.h +++ b/src/parser.h @@ -168,7 +168,8 @@ FunctionLiteral* MakeLazyAST(Handle