}
{ Comment cmnt(masm_, "[ Body");
+ ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
+ ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
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
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));
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
-
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
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()) {
__ 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));
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+ Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
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());
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
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_);
int loop_nesting_;
int function_token_position_;
Handle<String> inferred_name_;
+ bool try_fast_codegen_;
#ifdef DEBUG
bool already_compiled_;
#endif
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());
}
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.
// 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);
}
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()) {
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()) {
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());
void FastCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
+ Comment cmnt(masm_, "[ Declarations");
int length = declarations->length();
int globals = 0;
for (int i = 0; i < length; i++) {
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_);
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);
}
__ bind(&exit);
+ decrement_loop_depth();
}
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());
void FastCodeGenerator::VisitLiteral(Literal* expr) {
+ Comment cmnt(masm_, "[ Literal");
Move(expr->context(), expr);
}
function_(NULL),
script_(script),
is_eval_(is_eval),
+ loop_depth_(0),
true_label_(NULL),
false_label_(NULL) {
}
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)
Handle<Script> script_;
bool is_eval_;
Label return_label_;
+ int loop_depth_;
Label* true_label_;
Label* false_label_;
}
{ Comment cmnt(masm_, "[ Body");
+ ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
+ ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
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.
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));
}
}
+
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
-
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
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()) {
__ 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);
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+ Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
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());
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,
// 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)
// Bit positions in compiler_hints.
static const int kHasOnlyThisPropertyAssignments = 0;
static const int kHasOnlySimpleThisPropertyAssignments = 1;
+ static const int kTryFastCodegen = 2;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
}
{ Comment cmnt(masm_, "[ Body");
+ ASSERT(loop_depth() == 0);
VisitStatements(fun->body());
+ ASSERT(loop_depth() == 0);
}
{ Comment cmnt(masm_, "[ return <undefined>;");
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.
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));
}
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()) {
__ 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);
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Comment cmnt(masm_, "[ UnaryOperation");
-
switch (expr->op()) {
case Token::VOID:
Visit(expr->expression());
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
+ Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
ASSERT_EQ(Expression::kEffect, expr->left()->context());
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());