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
This commit is contained in:
parent
7d933936d3
commit
ef371f3f24
@ -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++) {
|
||||
|
@ -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
|
||||
|
@ -871,10 +871,12 @@ class ObjectLiteral: public MaterializedLiteral {
|
||||
ZoneList<Property*>* 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<Property*>* properties() const { return properties_; }
|
||||
|
||||
bool fast_elements() const { return fast_elements_; }
|
||||
|
||||
private:
|
||||
Handle<FixedArray> constant_properties_;
|
||||
ZoneList<Property*>* properties_;
|
||||
bool fast_elements_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -212,6 +212,7 @@ class Parser {
|
||||
ZoneList<ObjectLiteral::Property*>* properties,
|
||||
Handle<FixedArray> constants,
|
||||
bool* is_simple,
|
||||
bool* fast_elements,
|
||||
int* depth);
|
||||
|
||||
// Populate the literals fixed array for a materialized array literal.
|
||||
@ -3446,7 +3447,11 @@ Handle<FixedArray> 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<ObjectLiteral::Property*>* properties,
|
||||
Handle<FixedArray> 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<Object> 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<String>::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<uint32_t>(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<FixedArray> 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);
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,8 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script,
|
||||
class CompileTimeValue: public AllStatic {
|
||||
public:
|
||||
enum Type {
|
||||
OBJECT_LITERAL,
|
||||
OBJECT_LITERAL_FAST_ELEMENTS,
|
||||
OBJECT_LITERAL_SLOW_ELEMENTS,
|
||||
ARRAY_LITERAL
|
||||
};
|
||||
|
||||
|
@ -248,7 +248,8 @@ static Handle<Object> CreateLiteralBoilerplate(
|
||||
|
||||
static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
Handle<FixedArray> literals,
|
||||
Handle<FixedArray> constant_properties) {
|
||||
Handle<FixedArray> constant_properties,
|
||||
bool should_have_fast_elements) {
|
||||
// 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
|
||||
@ -264,6 +265,10 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
&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,
|
||||
@ -345,8 +350,10 @@ static Handle<Object> CreateLiteralBoilerplate(
|
||||
Handle<FixedArray> array) {
|
||||
Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
|
||||
switch (CompileTimeValue::GetType(array)) {
|
||||
case CompileTimeValue::OBJECT_LITERAL:
|
||||
return CreateObjectLiteralBoilerplate(literals, elements);
|
||||
case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
|
||||
return CreateObjectLiteralBoilerplate(literals, elements, true);
|
||||
case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
|
||||
return CreateObjectLiteralBoilerplate(literals, elements, false);
|
||||
case CompileTimeValue::ARRAY_LITERAL:
|
||||
return CreateArrayLiteralBoilerplate(literals, elements);
|
||||
default:
|
||||
@ -356,26 +363,6 @@ static Handle<Object> CreateLiteralBoilerplate(
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT(args.length() == 3);
|
||||
// Copy the arguments.
|
||||
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
|
||||
CONVERT_SMI_CHECKED(literals_index, args[1]);
|
||||
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
|
||||
|
||||
Handle<Object> result =
|
||||
CreateObjectLiteralBoilerplate(literals, constant_properties);
|
||||
|
||||
if (result.is_null()) return Failure::Exception();
|
||||
|
||||
// Update the functions literal and return the boilerplate.
|
||||
literals->set(literals_index, *result);
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
|
||||
// Takes a FixedArray of elements containing the literal elements of
|
||||
// the array literal and produces JSArray with those elements.
|
||||
@ -399,15 +386,19 @@ static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
|
||||
|
||||
static Object* Runtime_CreateObjectLiteral(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT(args.length() == 3);
|
||||
ASSERT(args.length() == 4);
|
||||
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;
|
||||
|
||||
// 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);
|
||||
boilerplate = CreateObjectLiteralBoilerplate(literals,
|
||||
constant_properties,
|
||||
should_have_fast_elements);
|
||||
if (boilerplate.is_null()) return Failure::Exception();
|
||||
// Update the functions literal and return the boilerplate.
|
||||
literals->set(literals_index, *boilerplate);
|
||||
@ -418,15 +409,19 @@ static Object* Runtime_CreateObjectLiteral(Arguments args) {
|
||||
|
||||
static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT(args.length() == 3);
|
||||
ASSERT(args.length() == 4);
|
||||
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;
|
||||
|
||||
// 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);
|
||||
boilerplate = CreateObjectLiteralBoilerplate(literals,
|
||||
constant_properties,
|
||||
should_have_fast_elements);
|
||||
if (boilerplate.is_null()) return Failure::Exception();
|
||||
// Update the functions literal and return the boilerplate.
|
||||
literals->set(literals_index, *boilerplate);
|
||||
|
@ -233,11 +233,10 @@ namespace internal {
|
||||
/* Literals */ \
|
||||
F(MaterializeRegExpLiteral, 4, 1)\
|
||||
F(CreateArrayLiteralBoilerplate, 3, 1) \
|
||||
F(CreateObjectLiteralBoilerplate, 3, 1) \
|
||||
F(CloneLiteralBoilerplate, 1, 1) \
|
||||
F(CloneShallowLiteralBoilerplate, 1, 1) \
|
||||
F(CreateObjectLiteral, 3, 1) \
|
||||
F(CreateObjectLiteralShallow, 3, 1) \
|
||||
F(CreateObjectLiteral, 4, 1) \
|
||||
F(CreateObjectLiteralShallow, 4, 1) \
|
||||
F(CreateArrayLiteral, 3, 1) \
|
||||
F(CreateArrayLiteralShallow, 3, 1) \
|
||||
\
|
||||
|
@ -2424,11 +2424,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);
|
||||
|
||||
|
@ -903,10 +903,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
__ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
|
||||
__ Push(Smi::FromInt(expr->literal_index()));
|
||||
__ Push(expr->constant_properties());
|
||||
__ Push(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
|
||||
|
Loading…
Reference in New Issue
Block a user