Create literal boilerplate as part of cloning in the top-level compiler.

When generating code for object and array literals we performed
the check if the a boilerplate already exists in generated code.

In the top-level compiler we now do this check in a new runtime
function. This makes the generated code more compact for top-level code.


Review URL: http://codereview.chromium.org/465148

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3437 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 264c055b
...@@ -657,32 +657,15 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -657,32 +657,15 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral"); Comment cmnt(masm_, "[ ObjectLiteral");
Label boilerplate_exists;
__ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
// r2 = literal array (0).
__ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ ldr(r0, FieldMemOperand(r2, literal_offset));
// Check whether we need to materialize the object literal boilerplate.
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r0, Operand(ip));
__ b(ne, &boilerplate_exists);
// Create boilerplate if it does not exist.
// r1 = literal index (1).
__ mov(r1, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r1, Operand(Smi::FromInt(expr->literal_index())));
// r0 = constant properties (2).
__ mov(r0, Operand(expr->constant_properties())); __ mov(r0, Operand(expr->constant_properties()));
__ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit()); __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit());
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
__ bind(&boilerplate_exists);
// r0 contains boilerplate.
// Clone boilerplate.
__ push(r0);
if (expr->depth() > 1) { if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
} else { } else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
} }
// If result_saved == true: The result is saved on top of the // If result_saved == true: The result is saved on top of the
...@@ -783,32 +766,15 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -783,32 +766,15 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
// Check if the literal's boilerplate has been instantiated.
int offset =
FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
__ ldr(r0, FieldMemOperand(r3, offset));
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r0, ip);
__ b(&make_clone, ne);
// Instantiate the boilerplate.
__ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(expr->literals())); __ mov(r1, Operand(expr->literals()));
__ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit()); __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
__ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ bind(&make_clone);
// Clone the boilerplate.
__ push(r0);
if (expr->depth() > 1) { if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else { } else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} }
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
......
...@@ -656,35 +656,14 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -656,35 +656,14 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral"); Comment cmnt(masm_, "[ ObjectLiteral");
Label exists;
// Registers will be used as follows:
// edi = JS function.
// ebx = literals array.
// eax = boilerplate
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ mov(eax, FieldOperand(ebx, literal_offset));
__ cmp(eax, Factory::undefined_value());
__ j(not_equal, &exists);
// Create boilerplate if it does not exist.
// Literal array (0).
__ push(ebx);
// Literal index (1).
__ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(Smi::FromInt(expr->literal_index())));
// Constant properties (2).
__ push(Immediate(expr->constant_properties())); __ push(Immediate(expr->constant_properties()));
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); if (expr->depth() > 1) {
__ bind(&exists); __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
// eax contains boilerplate.
// Clone boilerplate.
__ push(eax);
if (expr->depth() == 1) {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
} else { } else {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
} }
// If result_saved == true: The result is saved on top of the // If result_saved == true: The result is saved on top of the
...@@ -780,31 +759,14 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -780,31 +759,14 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
// Check if the literal's boilerplate has been instantiated.
int offset =
FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
__ mov(eax, FieldOperand(ebx, offset));
__ cmp(eax, Factory::undefined_value());
__ j(not_equal, &make_clone);
// Instantiate the boilerplate.
__ push(ebx);
__ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(expr->literals())); __ push(Immediate(expr->literals()));
__ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ bind(&make_clone);
// Clone the boilerplate.
__ push(eax);
if (expr->depth() > 1) { if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else { } else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} }
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
......
...@@ -398,6 +398,82 @@ static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { ...@@ -398,6 +398,82 @@ static Object* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
} }
static Object* Runtime_CreateObjectLiteral(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
// 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);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
}
static Object* Runtime_CreateObjectLiteralShallow(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
// 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);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
return Heap::CopyJSObject(JSObject::cast(*boilerplate));
}
static Object* Runtime_CreateArrayLiteral(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index));
if (*boilerplate == Heap::undefined_value()) {
boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
}
static Object* Runtime_CreateArrayLiteralShallow(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, literals, 0);
CONVERT_SMI_CHECKED(literals_index, args[1]);
CONVERT_ARG_CHECKED(FixedArray, elements, 2);
// Check if boilerplate exists. If not, create it first.
Handle<Object> boilerplate(literals->get(literals_index));
if (*boilerplate == Heap::undefined_value()) {
boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
if (boilerplate.is_null()) return Failure::Exception();
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
return Heap::CopyJSObject(JSObject::cast(*boilerplate));
}
static Object* Runtime_CreateCatchExtensionObject(Arguments args) { static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_CHECKED(String, key, args[0]); CONVERT_CHECKED(String, key, args[0]);
......
...@@ -223,6 +223,10 @@ namespace internal { ...@@ -223,6 +223,10 @@ namespace internal {
F(CreateObjectLiteralBoilerplate, 3, 1) \ F(CreateObjectLiteralBoilerplate, 3, 1) \
F(CloneLiteralBoilerplate, 1, 1) \ F(CloneLiteralBoilerplate, 1, 1) \
F(CloneShallowLiteralBoilerplate, 1, 1) \ F(CloneShallowLiteralBoilerplate, 1, 1) \
F(CreateObjectLiteral, 3, 1) \
F(CreateObjectLiteralShallow, 3, 1) \
F(CreateArrayLiteral, 3, 1) \
F(CreateArrayLiteralShallow, 3, 1) \
\ \
/* Catch context extension objects */ \ /* Catch context extension objects */ \
F(CreateCatchExtensionObject, 2, 1) \ F(CreateCatchExtensionObject, 2, 1) \
......
...@@ -663,31 +663,14 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -663,31 +663,14 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral"); Comment cmnt(masm_, "[ ObjectLiteral");
Label boilerplate_exists;
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rax, FieldOperand(rbx, literal_offset));
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &boilerplate_exists);
// Create boilerplate if it does not exist.
// Literal array (0).
__ push(rbx);
// Literal index (1).
__ Push(Smi::FromInt(expr->literal_index())); __ Push(Smi::FromInt(expr->literal_index()));
// Constant properties (2).
__ Push(expr->constant_properties()); __ Push(expr->constant_properties());
__ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); if (expr->depth() > 1) {
__ bind(&boilerplate_exists); __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
// rax contains boilerplate.
// Clone boilerplate.
__ push(rax);
if (expr->depth() == 1) {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
} else { } else {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
} }
// If result_saved == true: The result is saved on top of the // If result_saved == true: The result is saved on top of the
...@@ -783,31 +766,14 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -783,31 +766,14 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
// Check if the literal's boilerplate has been instantiated.
int offset =
FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize);
__ movq(rax, FieldOperand(rbx, offset));
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &make_clone);
// Instantiate the boilerplate.
__ push(rbx);
__ Push(Smi::FromInt(expr->literal_index())); __ Push(Smi::FromInt(expr->literal_index()));
__ Push(expr->literals()); __ Push(expr->literals());
__ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ bind(&make_clone);
// Clone the boilerplate.
__ push(rax);
if (expr->depth() > 1) { if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
} else { } else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} }
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment