Adding declaration of global variables and functions in new compiler.

Adding calls to global functions to the new compiler.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3099 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2009-10-21 09:17:39 +00:00
parent cd2065be00
commit 88371e63f6
11 changed files with 504 additions and 39 deletions

View File

@ -330,10 +330,11 @@ class CodeGenerator: public AstVisitor {
const InlineRuntimeLUT& new_entry,
InlineRuntimeLUT* old_entry);
static Handle<Code> ComputeLazyCompile(int argc);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
// Declare global variables and functions in the given array of
// name/value pairs.
@ -426,6 +427,7 @@ class CodeGenerator: public AstVisitor {
friend class JumpTarget;
friend class Reference;
friend class FastCodeGenerator;
friend class CodeGenSelector;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};

View File

@ -85,6 +85,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
lo);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations());
}
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
@ -104,6 +108,25 @@ 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.
__ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0)));
__ push(r0);
__ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
SetStatementPosition(stmt);
VisitStatements(stmt->statements());
}
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Comment cmnt(masm_, "[ ExpressionStatement");
SetStatementPosition(stmt);
@ -136,6 +159,29 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
Handle<JSFunction> boilerplate = BuildBoilerplate(expr);
if (HasStackOverflow()) return;
ASSERT(boilerplate->IsBoilerplate());
// Create a new closure.
__ mov(r0, Operand(boilerplate));
__ push(r0);
__ push(cp);
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
__ push(r0);
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
@ -224,4 +270,72 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Comment cmnt(masm_, "[ Call");
Expression* fun = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
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)
__ ldr(r0, CodeGenerator::GlobalObject());
__ push(r0);
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ mov(r0, Operand(args->at(i)->AsLiteral()->handle()));
__ push(r0);
}
}
// Record source position for debugger
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
if (expr->location().is_temporary()) {
__ str(r0, MemOperand(sp));
} else {
ASSERT(expr->location().is_nowhere());
__ pop();
}
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL);
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ mov(r0, Operand(args->at(i)->AsLiteral()->handle()));
__ push(r0);
}
}
__ CallRuntime(function, arg_count);
if (expr->location().is_temporary()) {
__ push(r0);
} else {
ASSERT(expr->location().is_nowhere());
}
}
} } // namespace v8::internal

View File

@ -274,7 +274,7 @@ void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
}
static Handle<Code> ComputeLazyCompile(int argc) {
Handle<Code> CodeGenerator::ComputeLazyCompile(int argc) {
CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
}

View File

@ -56,6 +56,7 @@
// ~CodeGenerator
// ProcessDeferred
// GenCode
// ComputeLazyCompile
// BuildBoilerplate
// ComputeCallInitialize
// ComputeCallInitializeInLoop

View File

@ -51,6 +51,7 @@ class CodeGenSelector: public AstVisitor {
CodeGenTag Select(FunctionLiteral* fun);
private:
void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts);
// AST node visit functions.
@ -107,7 +108,7 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
CodeGenSelector selector;
CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
if (code_gen == CodeGenSelector::FAST) {
return FastCodeGenerator::MakeCode(literal, script);
return FastCodeGenerator::MakeCode(literal, script, is_eval);
}
ASSERT(code_gen == CodeGenSelector::NORMAL);
}
@ -450,14 +451,22 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
Scope* scope = fun->scope();
if (!scope->is_global_scope()) return NORMAL;
if (!scope->is_global_scope()) {
if (FLAG_trace_bailout) PrintF("Non-global scope\n");
return NORMAL;
}
ASSERT(scope->num_heap_slots() == 0);
ASSERT(scope->arguments() == NULL);
if (!scope->declarations()->is_empty()) return NORMAL;
if (fun->materialized_literal_count() > 0) return NORMAL;
if (fun->materialized_literal_count() > 0) {
if (FLAG_trace_bailout) PrintF("Unsupported literal\n");
return NORMAL;
}
has_supported_syntax_ = true;
VisitDeclarations(fun->scope()->declarations());
if (!has_supported_syntax_) return NORMAL;
VisitStatements(fun->body());
return has_supported_syntax_ ? FAST : NORMAL;
}
@ -479,21 +488,32 @@ CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
} while (false)
void CodeGenSelector::VisitDeclarations(ZoneList<Declaration*>* decls) {
for (int i = 0; i < decls->length(); i++) {
Visit(decls->at(i));
CHECK_BAILOUT;
}
}
void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
for (int i = 0, len = stmts->length(); i < len; i++) {
CHECK_BAILOUT;
Visit(stmts->at(i));
CHECK_BAILOUT;
}
}
void CodeGenSelector::VisitDeclaration(Declaration* decl) {
BAILOUT("Declaration");
Variable* var = decl->proxy()->var();
if (!var->is_global() || var->mode() == Variable::CONST) {
BAILOUT("Non-global declaration");
}
}
void CodeGenSelector::VisitBlock(Block* stmt) {
BAILOUT("Block");
VisitStatements(stmt->statements());
}
@ -581,7 +601,9 @@ void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {
void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
BAILOUT("FunctionLiteral");
if (!expr->AllowsLazyCompilation()) {
BAILOUT("FunctionLiteral does not allow lazy compilation");
}
}
@ -674,7 +696,25 @@ void CodeGenSelector::VisitProperty(Property* expr) {
void CodeGenSelector::VisitCall(Call* expr) {
BAILOUT("Call");
Expression* fun = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
// Check for supported calls
if (var != NULL && var->is_possibly_eval()) {
BAILOUT("Call to a function named 'eval'");
} else if (var != NULL && !var->is_this() && var->is_global()) {
// ----------------------------------
// JavaScript example: 'foo(1, 2, 3)' // foo is global
// ----------------------------------
} else {
BAILOUT("Call to a non-global function");
}
// Check all arguments to the call
for (int i = 0; i < args->length(); i++) {
Visit(args->at(i));
CHECK_BAILOUT;
}
}
@ -684,7 +724,17 @@ void CodeGenSelector::VisitCallNew(CallNew* expr) {
void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
BAILOUT("CallRuntime");
// In case of JS runtime function bail out.
if (expr->function() == NULL) BAILOUT("CallRuntime");
// Check for inline runtime call
if (expr->name()->Get(0) == '_' &&
CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
BAILOUT("InlineRuntimeCall");
}
for (int i = 0; i < expr->arguments()->length(); i++) {
Visit(expr->arguments()->at(i));
CHECK_BAILOUT;
}
}

View File

@ -29,16 +29,19 @@
#include "codegen-inl.h"
#include "fast-codegen.h"
#include "stub-cache.h"
#include "debug.h"
namespace v8 {
namespace internal {
Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
Handle<Script> script) {
Handle<Script> script,
bool is_eval) {
CodeGenerator::MakeCodePrologue(fun);
const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize);
FastCodeGenerator cgen(&masm);
FastCodeGenerator cgen(&masm, script, is_eval);
cgen.Generate(fun);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
@ -66,6 +69,95 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
return offset;
}
void FastCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
for (int i = 0; i < length; i++) {
Declaration* node = declarations->at(i);
Variable* var = node->proxy()->var();
Slot* slot = var->slot();
// If it was not possible to allocate the variable at compile
// time, we need to "declare" it at runtime to make sure it
// actually exists in the local context.
if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
UNREACHABLE();
} else {
// Count global variables and functions for later processing
globals++;
}
}
// Return in case of no declared global functions or variables.
if (globals == 0) return;
// Compute array of global variable and function declarations.
Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* node = declarations->at(i);
Variable* var = node->proxy()->var();
Slot* slot = var->slot();
if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
array->set(j++, *(var->name()));
if (node->fun() == NULL) {
if (var->mode() == Variable::CONST) {
// In case this is const property use the hole.
array->set_the_hole(j++);
} else {
array->set_undefined(j++);
}
} else {
Handle<JSFunction> function = BuildBoilerplate(node->fun());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
array->set(j++, *function);
}
}
}
// Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions.
DeclareGlobals(array);
}
Handle<JSFunction> FastCodeGenerator::BuildBoilerplate(FunctionLiteral* fun) {
#ifdef DEBUG
// We should not try to compile the same function literal more than
// once.
fun->mark_as_compiled();
#endif
// Generate code
Handle<Code> code = CodeGenerator::ComputeLazyCompile(fun->num_parameters());
// Check for stack-overflow exception.
if (code.is_null()) {
SetStackOverflow();
return Handle<JSFunction>::null();
}
// Create a boilerplate function.
Handle<JSFunction> function =
Factory::NewFunctionBoilerplate(fun->name(),
fun->materialized_literal_count(),
code);
CodeGenerator::SetFunctionInfo(function, fun, false, script_);
#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger that a new function has been added.
Debugger::OnNewFunction(function);
#endif
// Set the expected number of properties for instances and return
// the resulting function.
SetExpectedNofPropertiesFromEstimate(function,
fun->expected_property_count());
return function;
}
void FastCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) {
CodeGenerator::RecordPositions(masm_, fun->start_position());
@ -99,11 +191,6 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
UNREACHABLE();
}
@ -174,11 +261,6 @@ void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
UNREACHABLE();
@ -231,21 +313,11 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
UNREACHABLE();
}

View File

@ -38,17 +38,23 @@ namespace internal {
class FastCodeGenerator: public AstVisitor {
public:
explicit FastCodeGenerator(MacroAssembler* masm)
: masm_(masm), function_(NULL) {
FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
: masm_(masm), function_(NULL), script_(script), is_eval_(is_eval) {
}
static Handle<Code> MakeCode(FunctionLiteral* fun, Handle<Script> script);
static Handle<Code> MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval);
void Generate(FunctionLiteral* fun);
private:
int SlotOffset(Slot* slot);
void VisitDeclarations(ZoneList<Declaration*>* declarations);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun);
void DeclareGlobals(Handle<FixedArray> pairs);
void SetFunctionPosition(FunctionLiteral* fun);
void SetReturnPosition(FunctionLiteral* fun);
void SetStatementPosition(Statement* stmt);
@ -61,6 +67,8 @@ class FastCodeGenerator: public AstVisitor {
MacroAssembler* masm_;
FunctionLiteral* function_;
Handle<Script> script_;
bool is_eval_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};

View File

@ -511,10 +511,11 @@ class CodeGenerator: public AstVisitor {
const InlineRuntimeLUT& new_entry,
InlineRuntimeLUT* old_entry);
static Handle<Code> ComputeLazyCompile(int argc);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
// Declare global variables and functions in the given array of
// name/value pairs.
@ -617,6 +618,7 @@ class CodeGenerator: public AstVisitor {
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
friend class CodeGenSelector;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc

View File

@ -75,6 +75,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
__ bind(&ok);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations());
}
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
@ -94,6 +98,23 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ 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.
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
SetStatementPosition(stmt);
VisitStatements(stmt->statements());
}
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Comment cmnt(masm_, "[ ExpressionStatement");
SetStatementPosition(stmt);
@ -126,6 +147,28 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
Handle<JSFunction> boilerplate = BuildBoilerplate(expr);
if (HasStackOverflow()) return;
ASSERT(boilerplate->IsBoilerplate());
// Create a new closure.
__ push(Immediate(boilerplate));
__ push(esi);
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
__ push(eax);
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
@ -213,4 +256,68 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ push(Immediate(var->name()));
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ push(Immediate(args->at(i)->AsLiteral()->handle()));
}
}
// Record source position for debugger
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
if (expr->location().is_temporary()) {
__ mov(Operand(esp, 0), eax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(eax);
}
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL);
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ push(Immediate(args->at(i)->AsLiteral()->handle()));
}
}
__ CallRuntime(function, arg_count);
if (expr->location().is_temporary()) {
__ push(eax);
} else {
ASSERT(expr->location().is_nowhere());
}
}
} } // namespace v8::internal

View File

@ -511,10 +511,11 @@ class CodeGenerator: public AstVisitor {
static bool PatchInlineRuntimeEntry(Handle<String> name,
const InlineRuntimeLUT& new_entry,
InlineRuntimeLUT* old_entry);
static Handle<Code> ComputeLazyCompile(int argc);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop);
// Declare global variables and functions in the given array of
// name/value pairs.
@ -617,6 +618,7 @@ class CodeGenerator: public AstVisitor {
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
friend class CodeGenSelector;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc

View File

@ -74,6 +74,10 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
__ bind(&ok);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(fun->scope()->declarations());
}
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
@ -102,6 +106,23 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ 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.
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
SetStatementPosition(stmt);
VisitStatements(stmt->statements());
}
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Comment cmnt(masm_, "[ ExpressionStatement");
SetStatementPosition(stmt);
@ -143,6 +164,28 @@ void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
Handle<JSFunction> boilerplate = BuildBoilerplate(expr);
if (HasStackOverflow()) return;
ASSERT(boilerplate->IsBoilerplate());
// Create a new closure.
__ Push(boilerplate);
__ push(rsi);
__ CallRuntime(Runtime::kNewClosure, 2);
if (expr->location().is_temporary()) {
__ push(rax);
} else {
ASSERT(expr->location().is_nowhere());
}
}
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
@ -227,4 +270,68 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
Variable* var = fun->AsVariableProxy()->AsVariable();
ASSERT(var != NULL && !var->is_this() && var->is_global());
ASSERT(!var->is_possibly_eval());
__ Push(var->name());
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ Push(args->at(i)->AsLiteral()->handle());
}
}
// Record source position for debugger
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
NOT_IN_LOOP);
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
if (expr->location().is_temporary()) {
__ movq(Operand(rsp, 0), rax);
} else {
ASSERT(expr->location().is_nowhere());
__ pop(rax);
}
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments();
Runtime::Function* function = expr->function();
ASSERT(function != NULL);
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
Visit(args->at(i));
ASSERT(!args->at(i)->location().is_nowhere());
if (args->at(i)->location().is_constant()) {
ASSERT(args->at(i)->AsLiteral() != NULL);
__ Push(args->at(i)->AsLiteral()->handle());
}
}
__ CallRuntime(function, arg_count);
if (expr->location().is_temporary()) {
__ push(rax);
} else {
ASSERT(expr->location().is_nowhere());
}
}
} } // namespace v8::internal