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
parent ee9d2d6c
......@@ -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);
}
......
......@@ -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.
}
......@@ -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));
......
......@@ -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;
}
}
......
......@@ -289,11 +289,6 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
UNREACHABLE();
}
......
......@@ -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);
}
......
......@@ -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));
}
}
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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));
}
}
......
......@@ -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'));
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