Begin using the top-level code generator for code that is inside

directly-applied function literals that are themselves compiled with
the top-level code generator.

The choice is guarded by a test that the function is anonymous (thus
not expected to be recursive) and not in a loop.

A compilation hint is set in the shared function info and used to make
the choice.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3206 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b14018b7
......@@ -92,7 +92,9 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
{ Comment cmnt(masm_, "[ Body");
ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
......@@ -323,7 +325,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Comment cmnt(masm_, "[ RegExpLiteral");
Label done;
// Registers will be used as follows:
// r4 = JS function, literals array
......@@ -818,8 +820,16 @@ void FastCodeGenerator::VisitCall(Call* expr) {
EmitCallWithStub(expr);
}
} else {
// Call to some other function expression.
Visit(expr->expression());
// Call to some other expression. If the expression is an anonymous
// function literal not called in a loop, mark it as one that should
// also use the fast code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
lit->name()->Equals(Heap::empty_string()) &&
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
Visit(fun);
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
......@@ -890,7 +900,6 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
......@@ -988,12 +997,12 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
switch (expr->context()) {
......@@ -1020,7 +1029,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ mov(r2, Operand(v->AsVariable()->name()));
__ mov(r2, Operand(proxy->AsVariable()->name()));
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
......@@ -1063,6 +1072,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
......@@ -1108,6 +1118,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Comment cmnt(masm_, "[ CompareOperation");
ASSERT_EQ(Expression::kValue, expr->left()->context());
ASSERT_EQ(Expression::kValue, expr->right()->context());
Visit(expr->left());
......
......@@ -1302,7 +1302,8 @@ class FunctionLiteral: public Expression {
is_expression_(is_expression),
loop_nesting_(0),
function_token_position_(RelocInfo::kNoPosition),
inferred_name_(Heap::empty_string()) {
inferred_name_(Heap::empty_string()),
try_fast_codegen_(false) {
#ifdef DEBUG
already_compiled_ = false;
#endif
......@@ -1345,6 +1346,9 @@ class FunctionLiteral: public Expression {
inferred_name_ = inferred_name;
}
bool try_fast_codegen() { return try_fast_codegen_; }
void set_try_fast_codegen(bool flag) { try_fast_codegen_ = flag; }
#ifdef DEBUG
void mark_as_compiled() {
ASSERT(!already_compiled_);
......@@ -1368,6 +1372,7 @@ class FunctionLiteral: public Expression {
int loop_nesting_;
int function_token_position_;
Handle<String> inferred_name_;
bool try_fast_codegen_;
#ifdef DEBUG
bool already_compiled_;
#endif
......
......@@ -271,6 +271,7 @@ void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
lit->has_only_this_property_assignments(),
lit->has_only_simple_this_property_assignments(),
*lit->this_property_assignments());
fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
}
......
......@@ -83,7 +83,8 @@ class CodeGenSelector: public AstVisitor {
static Handle<Code> MakeCode(FunctionLiteral* literal,
Handle<Script> script,
Handle<Context> context,
bool is_eval) {
bool is_eval,
Handle<SharedFunctionInfo> shared) {
ASSERT(literal != NULL);
// Rewrite the AST by introducing .result assignments where needed.
......@@ -120,12 +121,21 @@ static Handle<Code> MakeCode(FunctionLiteral* literal,
// Generate code and return it.
if (FLAG_fast_compiler) {
CodeGenSelector selector;
CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
if (code_gen == CodeGenSelector::FAST) {
return FastCodeGenerator::MakeCode(literal, script, is_eval);
// If there is no shared function info, try the fast code
// generator for code in the global scope. Otherwise obey the
// explicit hint in the shared function info.
if (shared.is_null() && !literal->scope()->is_global_scope()) {
if (FLAG_trace_bailout) PrintF("Non-global scope\n");
} else if (!shared.is_null() && !shared->try_fast_codegen()) {
if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
} else {
CodeGenSelector selector;
CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
if (code_gen == CodeGenSelector::FAST) {
return FastCodeGenerator::MakeCode(literal, script, is_eval);
}
ASSERT(code_gen == CodeGenSelector::NORMAL);
}
ASSERT(code_gen == CodeGenSelector::NORMAL);
}
return CodeGenerator::MakeCode(literal, script, is_eval);
}
......@@ -210,7 +220,8 @@ static Handle<JSFunction> MakeFunction(bool is_global,
HistogramTimerScope timer(rate);
// Compile the code.
Handle<Code> code = MakeCode(lit, script, context, is_eval);
Handle<Code> code = MakeCode(lit, script, context, is_eval,
Handle<SharedFunctionInfo>::null());
// Check for stack-overflow exceptions.
if (code.is_null()) {
......@@ -411,7 +422,8 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
HistogramTimerScope timer(&Counters::compile_lazy);
// Compile the code.
Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);
Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
shared);
// Check for stack-overflow exception.
if (code.is_null()) {
......@@ -465,16 +477,17 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
Scope* scope = fun->scope();
if (!scope->is_global_scope()) {
if (FLAG_trace_bailout) PrintF("Non-global scope\n");
if (scope->num_heap_slots() != 0) {
if (FLAG_trace_bailout) PrintF("function has context slots\n");
return NORMAL;
}
if (scope->arguments() != NULL) {
if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
return NORMAL;
}
ASSERT(scope->num_heap_slots() == 0);
ASSERT(scope->arguments() == NULL);
has_supported_syntax_ = true;
VisitDeclarations(fun->scope()->declarations());
VisitDeclarations(scope->declarations());
if (!has_supported_syntax_) return NORMAL;
VisitStatements(fun->body());
......
......@@ -75,6 +75,7 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
void FastCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
Comment cmnt(masm_, "[ Declarations");
int length = declarations->length();
int globals = 0;
for (int i = 0; i < length; i++) {
......@@ -289,6 +290,7 @@ void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
Comment cmnt(masm_, "[ IfStatement");
// Expressions cannot recursively enter statements, there are no labels in
// the state.
ASSERT_EQ(NULL, true_label_);
......@@ -350,9 +352,11 @@ void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
Comment cmnt(masm_, "[ ForStatement");
Label test, body, exit;
if (stmt->init() != NULL) Visit(stmt->init());
increment_loop_depth();
// Emit the test at the bottom of the loop (even if empty).
__ jmp(&test);
__ bind(&body);
......@@ -377,6 +381,7 @@ void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
}
__ bind(&exit);
decrement_loop_depth();
}
......@@ -407,6 +412,7 @@ void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
void FastCodeGenerator::VisitConditional(Conditional* expr) {
Comment cmnt(masm_, "[ Conditional");
ASSERT_EQ(Expression::kTest, expr->condition()->context());
ASSERT_EQ(expr->context(), expr->then_expression()->context());
ASSERT_EQ(expr->context(), expr->else_expression()->context());
......@@ -447,6 +453,7 @@ void FastCodeGenerator::VisitSlot(Slot* expr) {
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
Move(expr->context(), expr);
}
......
......@@ -43,6 +43,7 @@ class FastCodeGenerator: public AstVisitor {
function_(NULL),
script_(script),
is_eval_(is_eval),
loop_depth_(0),
true_label_(NULL),
false_label_(NULL) {
}
......@@ -94,6 +95,13 @@ class FastCodeGenerator: public AstVisitor {
void SetStatementPosition(Statement* stmt);
void SetSourcePosition(int pos);
int loop_depth() { return loop_depth_; }
void increment_loop_depth() { loop_depth_++; }
void decrement_loop_depth() {
ASSERT(loop_depth_ > 0);
loop_depth_--;
}
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
......@@ -107,6 +115,7 @@ class FastCodeGenerator: public AstVisitor {
Handle<Script> script_;
bool is_eval_;
Label return_label_;
int loop_depth_;
Label* true_label_;
Label* false_label_;
......
......@@ -85,7 +85,9 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
{ Comment cmnt(masm_, "[ Body");
ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
......@@ -342,7 +344,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Comment cmnt(masm_, "[ RegExpLiteral");
Label done;
// Registers will be used as follows:
// edi = JS function.
......@@ -840,8 +842,16 @@ void FastCodeGenerator::VisitCall(Call* expr) {
EmitCallWithStub(expr);
}
} else {
// Call to some other function expression.
Visit(expr->expression());
// Call to some other expression. If the expression is an anonymous
// function literal not called in a loop, mark it as one that should
// also use the fast code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
lit->name()->Equals(Heap::empty_string()) &&
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
Visit(fun);
// Load global receiver object.
__ mov(ebx, CodeGenerator::GlobalObject());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
......@@ -850,6 +860,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
}
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
......@@ -910,7 +921,6 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
......@@ -1003,12 +1013,12 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
switch (expr->context()) {
......@@ -1034,7 +1044,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ mov(ecx, v->AsVariable()->name());
__ mov(ecx, proxy->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
......@@ -1076,6 +1086,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
......@@ -1120,6 +1131,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Comment cmnt(masm_, "[ CompareOperation");
ASSERT_EQ(Expression::kValue, expr->left()->context());
ASSERT_EQ(Expression::kValue, expr->right()->context());
Visit(expr->left());
......
......@@ -2538,7 +2538,10 @@ BOOL_GETTER(SharedFunctionInfo, compiler_hints,
BOOL_GETTER(SharedFunctionInfo, compiler_hints,
has_only_simple_this_property_assignments,
kHasOnlySimpleThisPropertyAssignments)
BOOL_ACCESSORS(SharedFunctionInfo,
compiler_hints,
try_fast_codegen,
kTryFastCodegen)
INT_ACCESSORS(SharedFunctionInfo, length, kLengthOffset)
INT_ACCESSORS(SharedFunctionInfo, formal_parameter_count,
......
......@@ -3386,6 +3386,9 @@ class SharedFunctionInfo: public HeapObject {
// this.x = y; where y is either a constant or refers to an argument.
inline bool has_only_simple_this_property_assignments();
inline bool try_fast_codegen();
inline void set_try_fast_codegen(bool flag);
// For functions which only contains this property assignments this provides
// access to the names for the properties assigned.
DECL_ACCESSORS(this_property_assignments, Object)
......@@ -3466,6 +3469,7 @@ class SharedFunctionInfo: public HeapObject {
// Bit positions in compiler_hints.
static const int kHasOnlyThisPropertyAssignments = 0;
static const int kHasOnlySimpleThisPropertyAssignments = 1;
static const int kTryFastCodegen = 2;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
......
......@@ -84,7 +84,9 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
}
{ Comment cmnt(masm_, "[ Body");
ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
......@@ -360,7 +362,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
Comment cmnt(masm_, "[ RegExp Literal");
Comment cmnt(masm_, "[ RegExpLiteral");
Label done;
// Registers will be used as follows:
// rdi = JS function.
......@@ -855,8 +857,16 @@ void FastCodeGenerator::VisitCall(Call* expr) {
EmitCallWithStub(expr);
}
} else {
// Call to some other function expression.
Visit(expr->expression());
// Call to some other expression. If the expression is an anonymous
// function literal not called in a loop, mark it as one that should
// also use the fast code generator.
FunctionLiteral* lit = fun->AsFunctionLiteral();
if (lit != NULL &&
lit->name()->Equals(Heap::empty_string()) &&
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
Visit(fun);
// Load global receiver object.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
......@@ -925,12 +935,12 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
VariableProxy* v = expr->expression()->AsVariableProxy();
ASSERT(v->AsVariable() != NULL);
ASSERT(v->AsVariable()->is_global());
Visit(v);
Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
switch (expr->context()) {
......@@ -956,7 +966,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ Move(rcx, v->AsVariable()->name());
__ Move(rcx, proxy->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
......@@ -999,7 +1009,6 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
......@@ -1092,6 +1101,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
......@@ -1136,6 +1146,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Comment cmnt(masm_, "[ CompareOperation");
ASSERT_EQ(Expression::kValue, expr->left()->context());
ASSERT_EQ(Expression::kValue, expr->right()->context());
Visit(expr->left());
......
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