Move the function name inferrer code from the AstOptimizer to

the parser in preparation for not using the optimizer when 
using the full codegen. Code covered by existing tests.
Review URL: http://codereview.chromium.org/3141034

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5321 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2010-08-23 13:26:03 +00:00
parent d0bdc7956e
commit 528eb97b3a
4 changed files with 80 additions and 77 deletions

View File

@ -44,6 +44,20 @@ void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
} }
void FuncNameInferrer::PushLiteralName(Handle<String> name) {
if (IsOpen() && !Heap::prototype_symbol()->Equals(*name)) {
names_stack_.Add(name);
}
}
void FuncNameInferrer::PushVariableName(Handle<String> name) {
if (IsOpen() && !Heap::result_symbol()->Equals(*name)) {
names_stack_.Add(name);
}
}
Handle<String> FuncNameInferrer::MakeNameFromStack() { Handle<String> FuncNameInferrer::MakeNameFromStack() {
if (names_stack_.is_empty()) { if (names_stack_.is_empty()) {
return Factory::empty_string(); return Factory::empty_string();

View File

@ -36,11 +36,12 @@ namespace internal {
// Inference is performed in cases when an anonymous function is assigned // Inference is performed in cases when an anonymous function is assigned
// to a variable or a property (see test-func-name-inference.cc for examples.) // to a variable or a property (see test-func-name-inference.cc for examples.)
// //
// The basic idea is that during AST traversal LHSs of expressions are // The basic idea is that during parsing of LHSs of certain expressions
// always visited before RHSs. Thus, during visiting the LHS, a name can be // (assignments, declarations, object literals) we collect name strings,
// collected, and during visiting the RHS, a function literal can be collected. // and during parsing of the RHS, a function literal can be collected. After
// Inference is performed while leaving the assignment node. // parsing the RHS we can infer a name for function literals that do not have
class FuncNameInferrer BASE_EMBEDDED { // a name.
class FuncNameInferrer : public ZoneObject {
public: public:
FuncNameInferrer() FuncNameInferrer()
: entries_stack_(10), : entries_stack_(10),
@ -61,11 +62,9 @@ class FuncNameInferrer BASE_EMBEDDED {
} }
// Pushes an encountered name onto names stack when in collection state. // Pushes an encountered name onto names stack when in collection state.
void PushName(Handle<String> name) { void PushLiteralName(Handle<String> name);
if (IsOpen()) {
names_stack_.Add(name); void PushVariableName(Handle<String> name);
}
}
// Adds a function to infer name for. // Adds a function to infer name for.
void AddFunction(FunctionLiteral* func_to_infer) { void AddFunction(FunctionLiteral* func_to_infer) {
@ -75,11 +74,16 @@ class FuncNameInferrer BASE_EMBEDDED {
} }
// Infers a function name and leaves names collection state. // Infers a function name and leaves names collection state.
void InferAndLeave() { void Infer() {
ASSERT(IsOpen()); ASSERT(IsOpen());
if (!funcs_to_infer_.is_empty()) { if (!funcs_to_infer_.is_empty()) {
InferFunctionsNames(); InferFunctionsNames();
} }
}
// Infers a function name and leaves names collection state.
void Leave() {
ASSERT(IsOpen());
names_stack_.Rewind(entries_stack_.RemoveLast()); names_stack_.Rewind(entries_stack_.RemoveLast());
} }
@ -102,34 +106,6 @@ class FuncNameInferrer BASE_EMBEDDED {
}; };
// A wrapper class that automatically calls InferAndLeave when
// leaving scope.
class ScopedFuncNameInferrer BASE_EMBEDDED {
public:
explicit ScopedFuncNameInferrer(FuncNameInferrer* inferrer)
: inferrer_(inferrer),
is_entered_(false) {}
~ScopedFuncNameInferrer() {
if (is_entered_) {
inferrer_->InferAndLeave();
}
}
// Triggers the wrapped inferrer into name collection state.
void Enter() {
inferrer_->Enter();
is_entered_ = true;
}
private:
FuncNameInferrer* inferrer_;
bool is_entered_;
DISALLOW_COPY_AND_ASSIGN(ScopedFuncNameInferrer);
};
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_FUNC_NAME_INFERRER_H_ #endif // V8_FUNC_NAME_INFERRER_H_

View File

@ -32,6 +32,7 @@
#include "bootstrapper.h" #include "bootstrapper.h"
#include "codegen.h" #include "codegen.h"
#include "compiler.h" #include "compiler.h"
#include "func-name-inferrer.h"
#include "messages.h" #include "messages.h"
#include "parser.h" #include "parser.h"
#include "platform.h" #include "platform.h"
@ -154,6 +155,7 @@ class Parser {
bool is_pre_parsing_; bool is_pre_parsing_;
ScriptDataImpl* pre_data_; ScriptDataImpl* pre_data_;
bool seen_loop_stmt_; // Used for inner loop detection. bool seen_loop_stmt_; // Used for inner loop detection.
FuncNameInferrer* fni_;
bool inside_with() const { return with_nesting_level_ > 0; } bool inside_with() const { return with_nesting_level_ > 0; }
ParserFactory* factory() const { return factory_; } ParserFactory* factory() const { return factory_; }
@ -1214,7 +1216,8 @@ Parser::Parser(Handle<Script> script,
log_(log), log_(log),
is_pre_parsing_(is_pre_parsing == PREPARSE), is_pre_parsing_(is_pre_parsing == PREPARSE),
pre_data_(pre_data), pre_data_(pre_data),
seen_loop_stmt_(false) { seen_loop_stmt_(false),
fni_(NULL) {
} }
@ -1243,6 +1246,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
HistogramTimerScope timer(&Counters::parse); HistogramTimerScope timer(&Counters::parse);
Counters::total_parse_size.Increment(source->length()); Counters::total_parse_size.Increment(source->length());
fni_ = new FuncNameInferrer();
// Initialize parser state. // Initialize parser state.
source->TryFlatten(); source->TryFlatten();
@ -1303,6 +1307,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
HistogramTimerScope timer(&Counters::parse_lazy); HistogramTimerScope timer(&Counters::parse_lazy);
Counters::total_parse_size.Increment(source->length()); Counters::total_parse_size.Increment(source->length());
fni_ = new FuncNameInferrer();
fni_->PushEnclosingName(name);
// Initialize parser state. // Initialize parser state.
source->TryFlatten(); source->TryFlatten();
scanner_.Initialize(source, start_position, end_position, JAVASCRIPT); scanner_.Initialize(source, start_position, end_position, JAVASCRIPT);
@ -2080,9 +2087,12 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
VariableProxy* last_var = NULL; // the last variable declared VariableProxy* last_var = NULL; // the last variable declared
int nvars = 0; // the number of variables declared int nvars = 0; // the number of variables declared
do { do {
if (fni_ != NULL) fni_->Enter();
// Parse variable name. // Parse variable name.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
Handle<String> name = ParseIdentifier(CHECK_OK); Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
// Declare variable. // Declare variable.
// Note that we *always* must treat the initial value via a separate init // Note that we *always* must treat the initial value via a separate init
@ -2134,6 +2144,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Expect(Token::ASSIGN, CHECK_OK); Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos; position = scanner().location().beg_pos;
value = ParseAssignmentExpression(accept_IN, CHECK_OK); value = ParseAssignmentExpression(accept_IN, CHECK_OK);
// Don't infer if it is "a = function(){...}();"-like expression.
if (fni_ != NULL && value->AsCall() == NULL) fni_->Infer();
} }
// Make sure that 'const c' actually initializes 'c' to undefined // Make sure that 'const c' actually initializes 'c' to undefined
@ -2210,6 +2222,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
Assignment* assignment = NEW(Assignment(op, last_var, value, position)); Assignment* assignment = NEW(Assignment(op, last_var, value, position));
if (block) block->AddStatement(NEW(ExpressionStatement(assignment))); if (block) block->AddStatement(NEW(ExpressionStatement(assignment)));
} }
if (fni_ != NULL) fni_->Leave();
} while (peek() == Token::COMMA); } while (peek() == Token::COMMA);
if (!is_const && nvars == 1) { if (!is_const && nvars == 1) {
@ -2822,9 +2836,11 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// ConditionalExpression // ConditionalExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression // LeftHandSideExpression AssignmentOperator AssignmentExpression
if (fni_ != NULL) fni_->Enter();
Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK); Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
if (!Token::IsAssignmentOp(peek())) { if (!Token::IsAssignmentOp(peek())) {
if (fni_ != NULL) fni_->Leave();
// Parsed conditional expression only (no assignment). // Parsed conditional expression only (no assignment).
return expression; return expression;
} }
@ -2855,6 +2871,19 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
temp_scope_->AddProperty(); temp_scope_->AddProperty();
} }
if (fni_ != NULL) {
// Check if the right hand side is a call to avoid inferring a
// name if we're dealing with "a = function(){...}();"-like
// expression.
if ((op == Token::INIT_VAR
|| op == Token::INIT_CONST
|| op == Token::ASSIGN)
&& (right->AsCall() == NULL)) {
fni_->Infer();
}
fni_->Leave();
}
return NEW(Assignment(op, expression, right, pos)); return NEW(Assignment(op, expression, right, pos));
} }
@ -3125,6 +3154,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK); Handle<String> name = ParseIdentifierName(CHECK_OK);
result = factory()->NewProperty(result, NEW(Literal(name)), pos); result = factory()->NewProperty(result, NEW(Literal(name)), pos);
if (fni_ != NULL) fni_->PushLiteralName(name);
break; break;
} }
@ -3211,6 +3241,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK); Handle<String> name = ParseIdentifierName(CHECK_OK);
result = factory()->NewProperty(result, NEW(Literal(name)), pos); result = factory()->NewProperty(result, NEW(Literal(name)), pos);
if (fni_ != NULL) fni_->PushLiteralName(name);
break; break;
} }
case Token::LPAREN: { case Token::LPAREN: {
@ -3321,6 +3352,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::IDENTIFIER: { case Token::IDENTIFIER: {
Handle<String> name = ParseIdentifier(CHECK_OK); Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
if (is_pre_parsing_) { if (is_pre_parsing_) {
result = VariableProxySentinel::identifier_proxy(); result = VariableProxySentinel::identifier_proxy();
} else { } else {
@ -3343,6 +3375,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
factory()->LookupSymbol(scanner_.literal_string(), factory()->LookupSymbol(scanner_.literal_string(),
scanner_.literal_length()); scanner_.literal_length());
result = NEW(Literal(symbol)); result = NEW(Literal(symbol));
if (fni_ != NULL) fni_->PushLiteralName(symbol);
break; break;
} }
@ -3640,6 +3673,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Expect(Token::LBRACE, CHECK_OK); Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter();
Literal* key = NULL; Literal* key = NULL;
Token::Value next = peek(); Token::Value next = peek();
switch (next) { switch (next) {
@ -3648,6 +3683,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
bool is_setter = false; bool is_setter = false;
Handle<String> id = Handle<String> id =
ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if (fni_ != NULL) fni_->PushLiteralName(id);
if ((is_getter || is_setter) && peek() != Token::COLON) { if ((is_getter || is_setter) && peek() != Token::COLON) {
ObjectLiteral::Property* property = ObjectLiteral::Property* property =
ParseObjectLiteralGetSet(is_getter, CHECK_OK); ParseObjectLiteralGetSet(is_getter, CHECK_OK);
@ -3656,6 +3693,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
} }
properties.Add(property); properties.Add(property);
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
if (fni_ != NULL) {
fni_->Infer();
fni_->Leave();
}
continue; // restart the while continue; // restart the while
} }
// Failed to parse as get/set property, so it's just a property // Failed to parse as get/set property, so it's just a property
@ -3668,6 +3710,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Handle<String> string = Handle<String> string =
factory()->LookupSymbol(scanner_.literal_string(), factory()->LookupSymbol(scanner_.literal_string(),
scanner_.literal_length()); scanner_.literal_length());
if (fni_ != NULL) fni_->PushLiteralName(string);
uint32_t index; uint32_t index;
if (!string.is_null() && string->AsArrayIndex(&index)) { if (!string.is_null() && string->AsArrayIndex(&index)) {
key = NewNumberLiteral(index); key = NewNumberLiteral(index);
@ -3711,6 +3754,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
// TODO(1240767): Consider allowing trailing comma. // TODO(1240767): Consider allowing trailing comma.
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
if (fni_ != NULL) {
fni_->Infer();
fni_->Leave();
}
} }
Expect(Token::RBRACE, CHECK_OK); Expect(Token::RBRACE, CHECK_OK);
// Computation of literal_index must happen before pre parse bailout. // Computation of literal_index must happen before pre parse bailout.
@ -3922,6 +3970,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// when peeling or unrolling such a loop. // when peeling or unrolling such a loop.
seen_loop_stmt_ = true; seen_loop_stmt_ = true;
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
return function_literal; return function_literal;
} }
} }

View File

@ -28,7 +28,6 @@
#include "v8.h" #include "v8.h"
#include "ast.h" #include "ast.h"
#include "func-name-inferrer.h"
#include "scopes.h" #include "scopes.h"
#include "rewriter.h" #include "rewriter.h"
@ -39,10 +38,6 @@ namespace internal {
class AstOptimizer: public AstVisitor { class AstOptimizer: public AstVisitor {
public: public:
explicit AstOptimizer() : has_function_literal_(false) {} explicit AstOptimizer() : has_function_literal_(false) {}
explicit AstOptimizer(Handle<String> enclosing_name)
: has_function_literal_(false) {
func_name_inferrer_.PushEnclosingName(enclosing_name);
}
void Optimize(ZoneList<Statement*>* statements); void Optimize(ZoneList<Statement*>* statements);
@ -50,8 +45,6 @@ class AstOptimizer: public AstVisitor {
// Used for loop condition analysis. Cleared before visiting a loop // Used for loop condition analysis. Cleared before visiting a loop
// condition, set when a function literal is visited. // condition, set when a function literal is visited.
bool has_function_literal_; bool has_function_literal_;
// Helper object for function name inferring.
FuncNameInferrer func_name_inferrer_;
// Helpers // Helpers
void OptimizeArguments(ZoneList<Expression*>* arguments); void OptimizeArguments(ZoneList<Expression*>* arguments);
@ -211,11 +204,6 @@ void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
has_function_literal_ = true; has_function_literal_ = true;
if (node->name()->length() == 0) {
// Anonymous function.
func_name_inferrer_.AddFunction(node);
}
} }
@ -247,11 +235,6 @@ void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
var->type()->SetAsLikelySmi(); var->type()->SetAsLikelySmi();
} }
if (!var->is_this() &&
!Heap::result_symbol()->Equals(*var->name())) {
func_name_inferrer_.PushName(var->name());
}
if (FLAG_safe_int32_compiler) { if (FLAG_safe_int32_compiler) {
if (var->IsStackAllocated() && if (var->IsStackAllocated() &&
!var->is_arguments() && !var->is_arguments() &&
@ -268,11 +251,6 @@ void AstOptimizer::VisitLiteral(Literal* node) {
if (literal->IsSmi()) { if (literal->IsSmi()) {
node->type()->SetAsLikelySmi(); node->type()->SetAsLikelySmi();
node->set_side_effect_free(true); node->set_side_effect_free(true);
} else if (literal->IsString()) {
Handle<String> lit_str(Handle<String>::cast(literal));
if (!Heap::prototype_symbol()->Equals(*lit_str)) {
func_name_inferrer_.PushName(lit_str);
}
} else if (literal->IsHeapNumber()) { } else if (literal->IsHeapNumber()) {
if (node->to_int32()) { if (node->to_int32()) {
// Any HeapNumber has an int32 value if it is the input to a bit op. // Any HeapNumber has an int32 value if it is the input to a bit op.
@ -299,8 +277,6 @@ void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) { void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
for (int i = 0; i < node->properties()->length(); i++) { for (int i = 0; i < node->properties()->length(); i++) {
ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
scoped_fni.Enter();
Visit(node->properties()->at(i)->key()); Visit(node->properties()->at(i)->key());
Visit(node->properties()->at(i)->value()); Visit(node->properties()->at(i)->value());
} }
@ -314,17 +290,11 @@ void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
void AstOptimizer::VisitAssignment(Assignment* node) { void AstOptimizer::VisitAssignment(Assignment* node) {
ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
switch (node->op()) { switch (node->op()) {
case Token::INIT_VAR: case Token::INIT_VAR:
case Token::INIT_CONST: case Token::INIT_CONST:
case Token::ASSIGN: case Token::ASSIGN:
// No type can be infered from the general assignment. // No type can be infered from the general assignment.
// Don't infer if it is "a = function(){...}();"-like expression.
if (node->value()->AsCall() == NULL) {
scoped_fni.Enter();
}
break; break;
case Token::ASSIGN_BIT_OR: case Token::ASSIGN_BIT_OR:
case Token::ASSIGN_BIT_XOR: case Token::ASSIGN_BIT_XOR:
@ -430,12 +400,6 @@ void AstOptimizer::VisitCallNew(CallNew* node) {
void AstOptimizer::VisitCallRuntime(CallRuntime* node) { void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
node->arguments()->length() >= 2 &&
node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
scoped_fni.Enter();
}
OptimizeArguments(node->arguments()); OptimizeArguments(node->arguments());
} }
@ -1025,7 +989,7 @@ bool Rewriter::Optimize(FunctionLiteral* function) {
if (FLAG_optimize_ast && !body->is_empty()) { if (FLAG_optimize_ast && !body->is_empty()) {
HistogramTimerScope timer(&Counters::ast_optimization); HistogramTimerScope timer(&Counters::ast_optimization);
AstOptimizer optimizer(function->name()); AstOptimizer optimizer;
optimizer.Optimize(body); optimizer.Optimize(body);
if (optimizer.HasStackOverflow()) { if (optimizer.HasStackOverflow()) {
return false; return false;