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.
friend class JumpTarget;
friend class Reference;
friend class FastCodeGenerator;
+ friend class CodeGenSelector;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
lo);
}
+ { Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(fun->scope()->declarations());
+ }
+
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
}
+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);
}
+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();
}
+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
}
-static Handle<Code> ComputeLazyCompile(int argc) {
+Handle<Code> CodeGenerator::ComputeLazyCompile(int argc) {
CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
}
// ~CodeGenerator
// ProcessDeferred
// GenCode
+// ComputeLazyCompile
// BuildBoilerplate
// ComputeCallInitialize
// ComputeCallInitializeInLoop
CodeGenTag Select(FunctionLiteral* fun);
private:
+ void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts);
// AST node visit functions.
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);
}
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;
}
} 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());
}
void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
- BAILOUT("FunctionLiteral");
+ if (!expr->AllowsLazyCompilation()) {
+ BAILOUT("FunctionLiteral does not allow lazy compilation");
+ }
}
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;
+ }
}
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;
+ }
}
#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());
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());
}
-void FastCodeGenerator::VisitBlock(Block* stmt) {
- UNREACHABLE();
-}
-
-
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
UNREACHABLE();
}
}
-void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
- UNREACHABLE();
-}
-
-
void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
UNREACHABLE();
}
-void FastCodeGenerator::VisitCall(Call* expr) {
- UNREACHABLE();
-}
-
-
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
UNREACHABLE();
}
-void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
- UNREACHABLE();
-}
-
-
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
UNREACHABLE();
}
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);
MacroAssembler* masm_;
FunctionLiteral* function_;
+ Handle<Script> script_;
+ bool is_eval_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
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.
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
+ friend class CodeGenSelector;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
__ bind(&ok);
}
+ { Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(fun->scope()->declarations());
+ }
+
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
}
+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);
}
+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();
}
+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
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.
friend class Reference;
friend class Result;
friend class FastCodeGenerator;
+ friend class CodeGenSelector;
friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc
__ bind(&ok);
}
+ { Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(fun->scope()->declarations());
+ }
+
{ Comment cmnt(masm_, "[ Body");
VisitStatements(fun->body());
}
}
+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);
}
+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();
}
+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