Added support for array literals to the toplevel compiler. They are

currently compiled the same as with the optimizing compiler: they are
cloned from a boilerplate object and the boilerplate objects are
lazily constructed.

Also changed argument pushing on ARM to use stm (store multiple),
which required changing the order of arguments to the runtime
functions DeclareGlobals and NewClosure.  They were only used from
generated code.

Finally, changed the toplevel code generator so that stack pops to
discard a temporary became addition to the stack pointer on ia32 and
x64.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3110 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2009-10-22 10:07:45 +00:00
parent ee9d2d6cee
commit fbc0eaa13d
10 changed files with 273 additions and 45 deletions

View File

@ -1172,9 +1172,9 @@ void CodeGenerator::VisitBlock(Block* node) {
void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
VirtualFrame::SpilledScope spilled_scope;
frame_->EmitPush(cp);
__ mov(r0, Operand(pairs));
frame_->EmitPush(r0);
frame_->EmitPush(cp);
__ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
@ -2255,12 +2255,10 @@ void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(boilerplate->IsBoilerplate());
// Push the boilerplate on the stack.
__ mov(r0, Operand(boilerplate));
frame_->EmitPush(r0);
// Create a new closure.
frame_->EmitPush(cp);
__ mov(r0, Operand(boilerplate));
frame_->EmitPush(r0);
frame_->CallRuntime(Runtime::kNewClosure, 2);
frame_->EmitPush(r0);
}

View File

@ -29,6 +29,7 @@
#include "codegen-inl.h"
#include "fast-codegen.h"
#include "parser.h"
namespace v8 {
namespace internal {
@ -110,11 +111,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ mov(r0, Operand(pairs));
__ push(r0);
__ push(cp); // The context is the second argument.
// The context is the first argument.
__ mov(r1, Operand(pairs));
__ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0)));
__ push(r0);
__ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit());
__ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@ -153,7 +153,7 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
__ RecordJSReturn();
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
int num_parameters = function_->scope()->num_parameters();
int num_parameters = function_->scope()->num_parameters();
__ add(sp, sp, Operand((num_parameters + 1) * kPointerSize));
__ Jump(lr);
}
@ -170,8 +170,7 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
// Create a new closure.
__ mov(r0, Operand(boilerplate));
__ push(r0);
__ push(cp);
__ stm(db_w, sp, cp.bit() | r0.bit());
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
@ -215,6 +214,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
}
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Label done;
@ -245,6 +245,80 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
}
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ 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(r1, Operand(expr->literals()));
__ 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) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
}
bool result_saved = false; // Is the result saved to the stack?
// Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array.
ZoneList<Expression*>* subexprs = expr->values();
for (int i = 0, len = subexprs->length(); i < len; i++) {
Expression* subexpr = subexprs->at(i);
// If the subexpression is a literal or a simple materialized literal it
// is already set in the cloned array.
if (subexpr->AsLiteral() != NULL ||
CompileTimeValue::IsCompileTimeValue(subexpr)) {
continue;
}
if (!result_saved) {
__ push(r0);
result_saved = true;
}
Visit(subexpr);
ASSERT(subexpr->location().is_temporary());
// Store the subexpression value in the array's elements.
__ pop(r0); // Subexpression value.
__ ldr(r1, MemOperand(sp)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ str(r0, FieldMemOperand(r1, offset));
// Update the write barrier for the array store with r0 as the scratch
// register.
__ mov(r2, Operand(offset));
__ RecordWrite(r1, r2, r0);
}
Location destination = expr->location();
if (destination.is_nowhere() && result_saved) {
__ pop();
} else if (destination.is_temporary() && !result_saved) {
__ push(r0);
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
@ -323,11 +397,10 @@ void FastCodeGenerator::VisitCall(Call* expr) {
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ mov(r0, Operand(var->name()));
__ push(r0);
// Push global object (receiver)
__ mov(r1, Operand(var->name()));
// Push global object as receiver.
__ ldr(r0, CodeGenerator::GlobalObject());
__ push(r0);
__ stm(db_w, sp, r1.bit() | r0.bit());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));

View File

@ -644,7 +644,14 @@ void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
BAILOUT("ArrayLiteral");
ZoneList<Expression*>* subexprs = expr->values();
for (int i = 0, len = subexprs->length(); i < len; i++) {
Expression* subexpr = subexprs->at(i);
if (subexpr->AsLiteral() != NULL) continue;
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
Visit(subexpr);
CHECK_BAILOUT;
}
}

View File

@ -289,11 +289,6 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
UNREACHABLE();
}

View File

@ -2275,8 +2275,8 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// allow us to push the arguments directly into place.
frame_->SyncRange(0, frame_->element_count() - 1);
frame_->EmitPush(esi); // The context is the first argument.
frame_->EmitPush(Immediate(pairs));
frame_->EmitPush(esi); // The context is the second argument.
frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
@ -3576,11 +3576,9 @@ void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
ASSERT(boilerplate->IsBoilerplate());
frame_->SyncRange(0, frame_->element_count() - 1);
// Push the boilerplate on the stack.
frame_->EmitPush(Immediate(boilerplate));
// Create a new closure.
frame_->EmitPush(esi);
frame_->EmitPush(Immediate(boilerplate));
Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
frame_->Push(&result);
}

View File

@ -29,6 +29,7 @@
#include "codegen-inl.h"
#include "fast-codegen.h"
#include "parser.h"
namespace v8 {
namespace internal {
@ -100,8 +101,8 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(esi); // The context is the first argument.
__ push(Immediate(pairs));
__ push(esi); // The context is the second argument.
__ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0)));
__ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
@ -157,8 +158,8 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
ASSERT(boilerplate->IsBoilerplate());
// Create a new closure.
__ push(Immediate(boilerplate));
__ push(esi);
__ push(Immediate(boilerplate));
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
@ -190,7 +191,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
__ mov(Operand(esp, 0), eax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(eax);
__ add(Operand(esp), Immediate(kPointerSize));
}
} else {
@ -237,6 +238,76 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ebx, 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(expr->literals()));
__ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ bind(&make_clone);
// Clone the boilerplate.
__ push(eax);
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
}
bool result_saved = false; // Is the result saved to the stack?
// Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array.
ZoneList<Expression*>* subexprs = expr->values();
for (int i = 0, len = subexprs->length(); i < len; i++) {
Expression* subexpr = subexprs->at(i);
// If the subexpression is a literal or a simple materialized literal it
// is already set in the cloned array.
if (subexpr->AsLiteral() != NULL ||
CompileTimeValue::IsCompileTimeValue(subexpr)) {
continue;
}
if (!result_saved) {
__ push(eax);
result_saved = true;
}
Visit(subexpr);
ASSERT(subexpr->location().is_temporary());
// Store the subexpression value in the array's elements.
__ pop(eax); // Subexpression value.
__ mov(ebx, Operand(esp, 0)); // Copy of array literal.
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ mov(FieldOperand(ebx, offset), eax);
// Update the write barrier for the array store.
__ RecordWrite(ebx, offset, eax, ecx);
}
Location destination = expr->location();
if (destination.is_nowhere() && result_saved) {
__ add(Operand(esp), Immediate(kPointerSize));
} else if (destination.is_temporary() && !result_saved) {
__ push(eax);
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
@ -275,7 +346,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
__ mov(Operand(esp, 0), eax);
} else {
ASSERT(destination.is_nowhere());
__ pop(eax);
__ add(Operand(esp), Immediate(kPointerSize));
}
} else {
@ -339,7 +410,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
__ mov(Operand(esp, 0), eax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(eax);
__ add(Operand(esp), Immediate(kPointerSize));
}
}

View File

@ -577,8 +577,8 @@ static Object* Runtime_DeclareGlobals(Arguments args) {
HandleScope scope;
Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
Handle<Context> context = args.at<Context>(1);
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
bool is_eval = Smi::cast(args[2])->value() == 1;
// Compute the property attributes. According to ECMA-262, section
@ -4391,8 +4391,8 @@ static Object* Runtime_NewArgumentsFast(Arguments args) {
static Object* Runtime_NewClosure(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
CONVERT_ARG_CHECKED(Context, context, 1);
CONVERT_ARG_CHECKED(Context, context, 0);
CONVERT_ARG_CHECKED(JSFunction, boilerplate, 1);
Handle<JSFunction> result =
Factory::NewFunctionFromBoilerplate(boilerplate, context);

View File

@ -270,8 +270,8 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
frame_->SyncRange(0, frame_->element_count() - 1);
__ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT);
frame_->EmitPush(rsi); // The context is the first argument.
frame_->EmitPush(kScratchRegister);
frame_->EmitPush(rsi); // The context is the second argument.
frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0));
Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
@ -2177,12 +2177,10 @@ void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
ASSERT(boilerplate->IsBoilerplate());
frame_->SyncRange(0, frame_->element_count() - 1);
// Push the boilerplate on the stack.
__ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
frame_->EmitPush(kScratchRegister);
// Create a new closure.
frame_->EmitPush(rsi);
__ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
frame_->EmitPush(kScratchRegister);
Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
frame_->Push(&result);
}

View File

@ -30,6 +30,7 @@
#include "codegen-inl.h"
#include "debug.h"
#include "fast-codegen.h"
#include "parser.h"
namespace v8 {
namespace internal {
@ -108,8 +109,8 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(rsi); // The context is the first argument.
__ Push(pairs);
__ push(rsi); // The context is the second argument.
__ Push(Smi::FromInt(is_eval_ ? 1 : 0));
__ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
@ -174,8 +175,8 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
ASSERT(boilerplate->IsBoilerplate());
// Create a new closure.
__ Push(boilerplate);
__ push(rsi);
__ Push(boilerplate);
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
@ -206,7 +207,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
__ movq(Operand(rsp, 0), rax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(rax);
__ addq(rsp, Immediate(kPointerSize));
}
} else {
@ -253,6 +254,76 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral");
Label make_clone;
// Fetch the function's literals array.
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rbx, 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(expr->literals());
__ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
__ bind(&make_clone);
// Clone the boilerplate.
__ push(rax);
if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} else {
__ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1);
}
bool result_saved = false; // Is the result saved to the stack?
// Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array.
ZoneList<Expression*>* subexprs = expr->values();
for (int i = 0, len = subexprs->length(); i < len; i++) {
Expression* subexpr = subexprs->at(i);
// If the subexpression is a literal or a simple materialized literal it
// is already set in the cloned array.
if (subexpr->AsLiteral() != NULL ||
CompileTimeValue::IsCompileTimeValue(subexpr)) {
continue;
}
if (!result_saved) {
__ push(rax);
result_saved = true;
}
Visit(subexpr);
ASSERT(subexpr->location().is_temporary());
// Store the subexpression value in the array's elements.
__ pop(rax); // Subexpression value.
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ movq(FieldOperand(rbx, offset), rax);
// Update the write barrier for the array store.
__ RecordWrite(rbx, offset, rax, rcx);
}
Location destination = expr->location();
if (destination.is_nowhere() && result_saved) {
__ addq(rsp, Immediate(kPointerSize));
} else if (destination.is_temporary() && !result_saved) {
__ push(rax);
}
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
Comment cmnt(masm_, "[ Assignment");
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
@ -290,7 +361,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
if (destination.is_temporary()) {
__ movq(Operand(rsp, 0), rax);
} else {
__ pop(rax);
__ addq(rsp, Immediate(kPointerSize));
}
} else {
if (source.is_temporary()) {
@ -352,7 +423,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
__ movq(Operand(rsp, 0), rax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(rax);
__ addq(rsp, Immediate(kPointerSize));
}
}

View File

@ -33,3 +33,20 @@ assertEquals(null, eval("null"));
assertEquals("abc", eval("'abc'"));
assertEquals(8, eval("6;'abc';8"));
// Test some materialized array literals.
assertEquals([1,2,3,4], eval('[1,2,3,4]'));
assertEquals([[1,2],3,4], eval('[[1,2],3,4]'));
assertEquals([1,[2,3,4]], eval('[1,[2,3,4]]'));
assertEquals([1,2,3,4], eval('var a=1, b=2; [a,b,3,4]'))
assertEquals([1,2,3,4], eval('var a=1, b=2, c = [a,b,3,4]; c'));
function double(x) { return x + x; }
var s = 'var a = 1, b = 2; [double(a), double(b), double(3), double(4)]';
assertEquals([2,4,6,8], eval(s));
// Test array literals in effect context.
assertEquals(17, eval('[1,2,3,4]; 17'));
assertEquals(19, eval('var a=1, b=2; [a,b,3,4]; 19'));
assertEquals(23, eval('var a=1, b=2; c=23; [a,b,3,4]; c'));