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:
parent
d0bdc7956e
commit
528eb97b3a
@ -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() {
|
||||
if (names_stack_.is_empty()) {
|
||||
return Factory::empty_string();
|
||||
|
@ -36,11 +36,12 @@ namespace internal {
|
||||
// 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.)
|
||||
//
|
||||
// The basic idea is that during AST traversal LHSs of expressions are
|
||||
// always visited before RHSs. Thus, during visiting the LHS, a name can be
|
||||
// collected, and during visiting the RHS, a function literal can be collected.
|
||||
// Inference is performed while leaving the assignment node.
|
||||
class FuncNameInferrer BASE_EMBEDDED {
|
||||
// The basic idea is that during parsing of LHSs of certain expressions
|
||||
// (assignments, declarations, object literals) we collect name strings,
|
||||
// and during parsing of the RHS, a function literal can be collected. After
|
||||
// parsing the RHS we can infer a name for function literals that do not have
|
||||
// a name.
|
||||
class FuncNameInferrer : public ZoneObject {
|
||||
public:
|
||||
FuncNameInferrer()
|
||||
: entries_stack_(10),
|
||||
@ -61,11 +62,9 @@ class FuncNameInferrer BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
// Pushes an encountered name onto names stack when in collection state.
|
||||
void PushName(Handle<String> name) {
|
||||
if (IsOpen()) {
|
||||
names_stack_.Add(name);
|
||||
}
|
||||
}
|
||||
void PushLiteralName(Handle<String> name);
|
||||
|
||||
void PushVariableName(Handle<String> name);
|
||||
|
||||
// Adds a function to infer name for.
|
||||
void AddFunction(FunctionLiteral* func_to_infer) {
|
||||
@ -75,11 +74,16 @@ class FuncNameInferrer BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
// Infers a function name and leaves names collection state.
|
||||
void InferAndLeave() {
|
||||
void Infer() {
|
||||
ASSERT(IsOpen());
|
||||
if (!funcs_to_infer_.is_empty()) {
|
||||
InferFunctionsNames();
|
||||
}
|
||||
}
|
||||
|
||||
// Infers a function name and leaves names collection state.
|
||||
void Leave() {
|
||||
ASSERT(IsOpen());
|
||||
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
|
||||
|
||||
#endif // V8_FUNC_NAME_INFERRER_H_
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "bootstrapper.h"
|
||||
#include "codegen.h"
|
||||
#include "compiler.h"
|
||||
#include "func-name-inferrer.h"
|
||||
#include "messages.h"
|
||||
#include "parser.h"
|
||||
#include "platform.h"
|
||||
@ -154,6 +155,7 @@ class Parser {
|
||||
bool is_pre_parsing_;
|
||||
ScriptDataImpl* pre_data_;
|
||||
bool seen_loop_stmt_; // Used for inner loop detection.
|
||||
FuncNameInferrer* fni_;
|
||||
|
||||
bool inside_with() const { return with_nesting_level_ > 0; }
|
||||
ParserFactory* factory() const { return factory_; }
|
||||
@ -1214,7 +1216,8 @@ Parser::Parser(Handle<Script> script,
|
||||
log_(log),
|
||||
is_pre_parsing_(is_pre_parsing == PREPARSE),
|
||||
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);
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
fni_ = new FuncNameInferrer();
|
||||
|
||||
// Initialize parser state.
|
||||
source->TryFlatten();
|
||||
@ -1303,6 +1307,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
|
||||
HistogramTimerScope timer(&Counters::parse_lazy);
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
|
||||
fni_ = new FuncNameInferrer();
|
||||
fni_->PushEnclosingName(name);
|
||||
|
||||
// Initialize parser state.
|
||||
source->TryFlatten();
|
||||
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
|
||||
int nvars = 0; // the number of variables declared
|
||||
do {
|
||||
if (fni_ != NULL) fni_->Enter();
|
||||
|
||||
// Parse variable name.
|
||||
if (nvars > 0) Consume(Token::COMMA);
|
||||
Handle<String> name = ParseIdentifier(CHECK_OK);
|
||||
if (fni_ != NULL) fni_->PushVariableName(name);
|
||||
|
||||
// Declare variable.
|
||||
// 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);
|
||||
position = scanner().location().beg_pos;
|
||||
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
|
||||
@ -2210,6 +2222,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
|
||||
Assignment* assignment = NEW(Assignment(op, last_var, value, position));
|
||||
if (block) block->AddStatement(NEW(ExpressionStatement(assignment)));
|
||||
}
|
||||
|
||||
if (fni_ != NULL) fni_->Leave();
|
||||
} while (peek() == Token::COMMA);
|
||||
|
||||
if (!is_const && nvars == 1) {
|
||||
@ -2822,9 +2836,11 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
||||
// ConditionalExpression
|
||||
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||
|
||||
if (fni_ != NULL) fni_->Enter();
|
||||
Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
|
||||
|
||||
if (!Token::IsAssignmentOp(peek())) {
|
||||
if (fni_ != NULL) fni_->Leave();
|
||||
// Parsed conditional expression only (no assignment).
|
||||
return expression;
|
||||
}
|
||||
@ -2855,6 +2871,19 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -3125,6 +3154,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
int pos = scanner().location().beg_pos;
|
||||
Handle<String> name = ParseIdentifierName(CHECK_OK);
|
||||
result = factory()->NewProperty(result, NEW(Literal(name)), pos);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(name);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3211,6 +3241,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
||||
int pos = scanner().location().beg_pos;
|
||||
Handle<String> name = ParseIdentifierName(CHECK_OK);
|
||||
result = factory()->NewProperty(result, NEW(Literal(name)), pos);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(name);
|
||||
break;
|
||||
}
|
||||
case Token::LPAREN: {
|
||||
@ -3321,6 +3352,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
||||
|
||||
case Token::IDENTIFIER: {
|
||||
Handle<String> name = ParseIdentifier(CHECK_OK);
|
||||
if (fni_ != NULL) fni_->PushVariableName(name);
|
||||
if (is_pre_parsing_) {
|
||||
result = VariableProxySentinel::identifier_proxy();
|
||||
} else {
|
||||
@ -3343,6 +3375,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
||||
factory()->LookupSymbol(scanner_.literal_string(),
|
||||
scanner_.literal_length());
|
||||
result = NEW(Literal(symbol));
|
||||
if (fni_ != NULL) fni_->PushLiteralName(symbol);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3640,6 +3673,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
|
||||
Expect(Token::LBRACE, CHECK_OK);
|
||||
while (peek() != Token::RBRACE) {
|
||||
if (fni_ != NULL) fni_->Enter();
|
||||
|
||||
Literal* key = NULL;
|
||||
Token::Value next = peek();
|
||||
switch (next) {
|
||||
@ -3648,6 +3683,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
bool is_setter = false;
|
||||
Handle<String> id =
|
||||
ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(id);
|
||||
|
||||
if ((is_getter || is_setter) && peek() != Token::COLON) {
|
||||
ObjectLiteral::Property* property =
|
||||
ParseObjectLiteralGetSet(is_getter, CHECK_OK);
|
||||
@ -3656,6 +3693,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
}
|
||||
properties.Add(property);
|
||||
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
|
||||
|
||||
if (fni_ != NULL) {
|
||||
fni_->Infer();
|
||||
fni_->Leave();
|
||||
}
|
||||
continue; // restart the while
|
||||
}
|
||||
// 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 =
|
||||
factory()->LookupSymbol(scanner_.literal_string(),
|
||||
scanner_.literal_length());
|
||||
if (fni_ != NULL) fni_->PushLiteralName(string);
|
||||
uint32_t index;
|
||||
if (!string.is_null() && string->AsArrayIndex(&index)) {
|
||||
key = NewNumberLiteral(index);
|
||||
@ -3711,6 +3754,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||
|
||||
// TODO(1240767): Consider allowing trailing comma.
|
||||
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
|
||||
|
||||
if (fni_ != NULL) {
|
||||
fni_->Infer();
|
||||
fni_->Leave();
|
||||
}
|
||||
}
|
||||
Expect(Token::RBRACE, CHECK_OK);
|
||||
// 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.
|
||||
seen_loop_stmt_ = true;
|
||||
|
||||
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
|
||||
return function_literal;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include "ast.h"
|
||||
#include "func-name-inferrer.h"
|
||||
#include "scopes.h"
|
||||
#include "rewriter.h"
|
||||
|
||||
@ -39,10 +38,6 @@ namespace internal {
|
||||
class AstOptimizer: public AstVisitor {
|
||||
public:
|
||||
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);
|
||||
|
||||
@ -50,8 +45,6 @@ class AstOptimizer: public AstVisitor {
|
||||
// Used for loop condition analysis. Cleared before visiting a loop
|
||||
// condition, set when a function literal is visited.
|
||||
bool has_function_literal_;
|
||||
// Helper object for function name inferring.
|
||||
FuncNameInferrer func_name_inferrer_;
|
||||
|
||||
// Helpers
|
||||
void OptimizeArguments(ZoneList<Expression*>* arguments);
|
||||
@ -211,11 +204,6 @@ void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
|
||||
|
||||
void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
|
||||
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();
|
||||
}
|
||||
|
||||
if (!var->is_this() &&
|
||||
!Heap::result_symbol()->Equals(*var->name())) {
|
||||
func_name_inferrer_.PushName(var->name());
|
||||
}
|
||||
|
||||
if (FLAG_safe_int32_compiler) {
|
||||
if (var->IsStackAllocated() &&
|
||||
!var->is_arguments() &&
|
||||
@ -268,11 +251,6 @@ void AstOptimizer::VisitLiteral(Literal* node) {
|
||||
if (literal->IsSmi()) {
|
||||
node->type()->SetAsLikelySmi();
|
||||
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()) {
|
||||
if (node->to_int32()) {
|
||||
// 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) {
|
||||
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)->value());
|
||||
}
|
||||
@ -314,17 +290,11 @@ void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
|
||||
|
||||
|
||||
void AstOptimizer::VisitAssignment(Assignment* node) {
|
||||
ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
|
||||
switch (node->op()) {
|
||||
case Token::INIT_VAR:
|
||||
case Token::INIT_CONST:
|
||||
case Token::ASSIGN:
|
||||
// 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;
|
||||
case Token::ASSIGN_BIT_OR:
|
||||
case Token::ASSIGN_BIT_XOR:
|
||||
@ -430,12 +400,6 @@ void AstOptimizer::VisitCallNew(CallNew* 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());
|
||||
}
|
||||
|
||||
@ -1025,7 +989,7 @@ bool Rewriter::Optimize(FunctionLiteral* function) {
|
||||
|
||||
if (FLAG_optimize_ast && !body->is_empty()) {
|
||||
HistogramTimerScope timer(&Counters::ast_optimization);
|
||||
AstOptimizer optimizer(function->name());
|
||||
AstOptimizer optimizer;
|
||||
optimizer.Optimize(body);
|
||||
if (optimizer.HasStackOverflow()) {
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user