Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(660)

Unified Diff: src/parser.cc

Issue 7348008: Merge up to 8597 to experimental/gc from the bleeding edge. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parser.h ('k') | src/platform.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parser.cc
===================================================================
--- src/parser.cc (revision 8618)
+++ src/parser.cc (working copy)
@@ -411,6 +411,7 @@
return result;
}
+
// ----------------------------------------------------------------------------
// Target is a support class to facilitate manipulation of the
// Parser's target_stack_ (the stack of potential 'break' and
@@ -536,7 +537,6 @@
LexicalScope::~LexicalScope() {
- parser_->top_scope_->Leave();
parser_->top_scope_ = previous_scope_;
parser_->lexical_scope_ = lexical_scope_parent_;
parser_->with_nesting_level_ = previous_with_nesting_level_;
@@ -592,11 +592,11 @@
FunctionLiteral* Parser::ParseProgram(Handle<String> source,
bool in_global_context,
StrictModeFlag strict_mode) {
- CompilationZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
+ ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(isolate()->counters()->parse());
isolate()->counters()->total_parse_size()->Increment(source->length());
- fni_ = new(zone()) FuncNameInferrer();
+ fni_ = new(zone()) FuncNameInferrer(isolate());
// Initialize parser state.
source->TryFlatten();
@@ -658,6 +658,7 @@
0,
0,
source->length(),
+ false,
false);
} else if (stack_overflow_) {
isolate()->StackOverflow();
@@ -674,7 +675,7 @@
}
FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
- CompilationZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
+ ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(isolate()->counters()->parse_lazy());
Handle<String> source(String::cast(script_->source()));
isolate()->counters()->total_parse_size()->Increment(source->length());
@@ -707,7 +708,7 @@
ASSERT(target_stack_ == NULL);
Handle<String> name(String::cast(shared_info->name()));
- fni_ = new(zone()) FuncNameInferrer();
+ fni_ = new(zone()) FuncNameInferrer(isolate());
fni_->PushEnclosingName(name);
mode_ = PARSE_EAGERLY;
@@ -822,14 +823,24 @@
// form expr.a = ...; expr.b = ...; etc.
class InitializationBlockFinder : public ParserFinder {
public:
- InitializationBlockFinder()
- : first_in_block_(NULL), last_in_block_(NULL), block_size_(0) {}
+ // We find and mark the initialization blocks in top level
+ // non-looping code only. This is because the optimization prevents
+ // reuse of the map transitions, so it should be used only for code
+ // that will only be run once.
+ InitializationBlockFinder(Scope* top_scope, Target* target)
+ : enabled_(top_scope->DeclarationScope()->is_global_scope() &&
+ !IsLoopTarget(target)),
+ first_in_block_(NULL),
+ last_in_block_(NULL),
+ block_size_(0) {}
~InitializationBlockFinder() {
+ if (!enabled_) return;
if (InBlock()) EndBlock();
}
void Update(Statement* stat) {
+ if (!enabled_) return;
Assignment* assignment = AsAssignment(stat);
if (InBlock()) {
if (BlockContinues(assignment)) {
@@ -850,6 +861,14 @@
// the overhead exceeds the savings below this limit.
static const int kMinInitializationBlock = 3;
+ static bool IsLoopTarget(Target* target) {
+ while (target != NULL) {
+ if (target->node()->AsIterationStatement() != NULL) return true;
+ target = target->previous();
+ }
+ return false;
+ }
+
// Returns true if the expressions appear to denote the same object.
// In the context of initialization blocks, we only consider expressions
// of the form 'expr.x' or expr["x"].
@@ -912,6 +931,7 @@
bool InBlock() { return first_in_block_ != NULL; }
+ const bool enabled_;
Assignment* first_in_block_;
Assignment* last_in_block_;
int block_size_;
@@ -1077,7 +1097,7 @@
TargetScope scope(&this->target_stack_);
ASSERT(processor != NULL);
- InitializationBlockFinder block_finder;
+ InitializationBlockFinder block_finder(top_scope_, target_stack_);
ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate());
bool directive_prologue = true; // Parsing directive prologue.
@@ -1132,12 +1152,7 @@
}
}
- // We find and mark the initialization blocks on top level code only.
- // This is because the optimization prevents reuse of the map transitions,
- // so it should be used only for code that will only be run once.
- if (top_scope_->is_global_scope()) {
- block_finder.Update(stat);
- }
+ block_finder.Update(stat);
// Find and mark all assignments to named properties in this (this.x =)
if (top_scope_->is_function_scope()) {
this_property_assignment_finder.Update(top_scope_, stat);
@@ -1269,9 +1284,6 @@
return ParseFunctionDeclaration(ok);
}
- case Token::NATIVE:
- return ParseNativeDeclaration(ok);
-
case Token::DEBUGGER:
stmt = ParseDebuggerStatement(ok);
break;
@@ -1304,13 +1316,14 @@
// to the calling function context.
// Similarly, strict mode eval scope does not leak variable declarations to
// the caller's scope so we declare all locals, too.
- if (top_scope_->is_function_scope() ||
- top_scope_->is_strict_mode_eval_scope()) {
+ Scope* declaration_scope = top_scope_->DeclarationScope();
+ if (declaration_scope->is_function_scope() ||
+ declaration_scope->is_strict_mode_eval_scope()) {
// Declare the variable in the function scope.
- var = top_scope_->LocalLookup(name);
+ var = declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
- var = top_scope_->DeclareLocal(name, mode, Scope::VAR_OR_CONST);
+ var = declaration_scope->DeclareLocal(name, mode);
} else {
// The name was declared before; check for conflicting
// re-declarations. If the previous declaration was a const or the
@@ -1326,7 +1339,7 @@
Expression* expression =
NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
type_string, name);
- top_scope_->SetIllegalRedeclaration(expression);
+ declaration_scope->SetIllegalRedeclaration(expression);
}
}
}
@@ -1347,14 +1360,18 @@
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
- VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with());
- top_scope_->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
+ VariableProxy* proxy = declaration_scope->NewUnresolved(name, false);
+ declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
// For global const variables we bind the proxy to a variable.
- if (mode == Variable::CONST && top_scope_->is_global_scope()) {
+ if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
- var = new(zone()) Variable(top_scope_, name, Variable::CONST, true, kind);
+ var = new(zone()) Variable(declaration_scope,
+ name,
+ Variable::CONST,
+ true,
+ kind);
}
// If requested and we have a local variable, bind the proxy to the variable
@@ -1392,13 +1409,6 @@
// declaration is resolved by looking up the function through a
// callback provided by the extension.
Statement* Parser::ParseNativeDeclaration(bool* ok) {
- if (extension_ == NULL) {
- ReportUnexpectedToken(Token::NATIVE);
- *ok = false;
- return NULL;
- }
-
- Expect(Token::NATIVE, CHECK_OK);
Expect(Token::FUNCTION, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
@@ -1417,7 +1427,7 @@
// isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing
// because of lazy compilation.
- top_scope_->ForceEagerCompilation();
+ top_scope_->DeclarationScope()->ForceEagerCompilation();
// Compute the function template for the native function.
v8::Handle<v8::FunctionTemplate> fun_template =
@@ -1455,10 +1465,11 @@
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
- bool is_reserved = false;
- Handle<String> name = ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
+ bool is_strict_reserved = false;
+ Handle<String> name = ParseIdentifierOrStrictReservedWord(
+ &is_strict_reserved, CHECK_OK);
FunctionLiteral* fun = ParseFunctionLiteral(name,
- is_reserved,
+ is_strict_reserved,
function_token_position,
DECLARATION,
CHECK_OK);
@@ -1481,9 +1492,13 @@
Block* result = new(zone()) Block(labels, 16, false);
Target target(&this->target_stack_, result);
Expect(Token::LBRACE, CHECK_OK);
+ InitializationBlockFinder block_finder(top_scope_, target_stack_);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatement(NULL, CHECK_OK);
- if (stat && !stat->IsEmpty()) result->AddStatement(stat);
+ if (stat && !stat->IsEmpty()) {
+ result->AddStatement(stat);
+ block_finder.Update(stat);
+ }
}
Expect(Token::RBRACE, CHECK_OK);
return result;
@@ -1494,8 +1509,8 @@
// VariableStatement ::
// VariableDeclarations ';'
- Expression* dummy; // to satisfy the ParseVariableDeclarations() signature
- Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK);
+ Handle<String> ignore;
+ Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@@ -1513,18 +1528,19 @@
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
Block* Parser::ParseVariableDeclarations(bool accept_IN,
- Expression** var,
+ Handle<String>* out,
bool* ok) {
// VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
Variable::Mode mode = Variable::VAR;
bool is_const = false;
+ Scope* declaration_scope = top_scope_->DeclarationScope();
if (peek() == Token::VAR) {
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (top_scope_->is_strict_mode()) {
+ if (declaration_scope->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1549,18 +1565,18 @@
//
// Create new block with one expected declaration.
Block* block = new(zone()) Block(NULL, 1, true);
- VariableProxy* last_var = NULL; // the last variable declared
int nvars = 0; // the number of variables declared
+ Handle<String> name;
do {
if (fni_ != NULL) fni_->Enter();
// Parse variable name.
if (nvars > 0) Consume(Token::COMMA);
- Handle<String> name = ParseIdentifier(CHECK_OK);
+ name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
// Strict mode variables may not be named eval or arguments
- if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
+ if (declaration_scope->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_var_name", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -1578,11 +1594,10 @@
// If we have a const declaration, in an inner scope, the proxy is always
// bound to the declared variable (independent of possibly surrounding with
// statements).
- last_var = Declare(name, mode, NULL,
- is_const /* always bound for CONST! */,
- CHECK_OK);
+ Declare(name, mode, NULL, is_const /* always bound for CONST! */,
+ CHECK_OK);
nvars++;
- if (top_scope_->num_var_or_const() > kMaxNumFunctionLocals) {
+ if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
ReportMessageAt(scanner().location(), "too_many_variables",
Vector<const char*>::empty());
*ok = false;
@@ -1598,10 +1613,10 @@
//
// var v; v = x;
//
- // In particular, we need to re-lookup 'v' as it may be a
- // different 'v' than the 'v' in the declaration (if we are inside
- // a 'with' statement that makes a object property with name 'v'
- // visible).
+ // In particular, we need to re-lookup 'v' (in top_scope_, not
+ // declaration_scope) as it may be a different 'v' than the 'v' in the
+ // declaration (e.g., if we are inside a 'with' statement or 'catch'
+ // block).
//
// However, note that const declarations are different! A const
// declaration of the form:
@@ -1616,6 +1631,7 @@
// one - there is no re-lookup (see the last parameter of the
// Declare() call above).
+ Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
Expression* value = NULL;
int position = -1;
if (peek() == Token::ASSIGN) {
@@ -1623,7 +1639,11 @@
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();
+ if (fni_ != NULL &&
+ value->AsCall() == NULL &&
+ value->AsCallNew() == NULL) {
+ fni_->Infer();
+ }
}
// Make sure that 'const c' actually initializes 'c' to undefined
@@ -1652,7 +1672,7 @@
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
- if (top_scope_->is_global_scope()) {
+ if (initialization_scope->is_global_scope()) {
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
// We have at least 1 parameter.
@@ -1675,8 +1695,10 @@
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
- arguments->Add(NewNumberLiteral(
- top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
+ StrictModeFlag flag = initialization_scope->is_strict_mode()
+ ? kStrictMode
+ : kNonStrictMode;
+ arguments->Add(NewNumberLiteral(flag));
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
@@ -1713,8 +1735,11 @@
// the top context for variables). Sigh...
if (value != NULL) {
Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR);
+ bool in_with = is_const ? false : inside_with();
+ VariableProxy* proxy =
+ initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment =
- new(zone()) Assignment(op, last_var, value, position);
+ new(zone()) Assignment(op, proxy, value, position);
if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment));
}
@@ -1723,10 +1748,10 @@
if (fni_ != NULL) fni_->Leave();
} while (peek() == Token::COMMA);
- if (!is_const && nvars == 1) {
- // We have a single, non-const variable.
- ASSERT(last_var != NULL);
- *var = last_var;
+ // If there was a single non-const declaration, return it in the output
+ // parameter for possible use by for/in.
+ if (nvars == 1 && !is_const) {
+ *out = name;
}
return block;
@@ -1751,7 +1776,7 @@
// Identifier ':' Statement
bool starts_with_idenfifier = peek_any_identifier();
Expression* expr = ParseExpression(true, CHECK_OK);
- if (peek() == Token::COLON && starts_with_idenfifier && expr &&
+ if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
expr->AsVariableProxy() != NULL &&
!expr->AsVariableProxy()->is_this()) {
// Expression is a single identifier, and not, e.g., a parenthesized
@@ -1781,6 +1806,20 @@
return ParseStatement(labels, ok);
}
+ // If we have an extension, we allow a native function declaration.
+ // A native function declaration starts with "native function" with
+ // no line-terminator between the two words.
+ if (extension_ != NULL &&
+ peek() == Token::FUNCTION &&
+ !scanner().HasAnyLineTerminatorBeforeNext() &&
+ expr != NULL &&
+ expr->AsVariableProxy() != NULL &&
+ expr->AsVariableProxy()->name()->Equals(
+ isolate()->heap()->native_symbol()) &&
+ !scanner().literal_contains_escapes()) {
+ return ParseNativeDeclaration(ok);
+ }
+
// Parsed expression statement.
ExpectSemicolon(CHECK_OK);
return new(zone()) ExpressionStatement(expr);
@@ -1814,7 +1853,7 @@
Expect(Token::CONTINUE, CHECK_OK);
Handle<String> label = Handle<String>::null();
Token::Value tok = peek();
- if (!scanner().has_line_terminator_before_next() &&
+ if (!scanner().HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK);
}
@@ -1844,7 +1883,7 @@
Expect(Token::BREAK, CHECK_OK);
Handle<String> label;
Token::Value tok = peek();
- if (!scanner().has_line_terminator_before_next() &&
+ if (!scanner().HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK);
}
@@ -1886,14 +1925,16 @@
// function. See ECMA-262, section 12.9, page 67.
//
// To be consistent with KJS we report the syntax error at runtime.
- if (!top_scope_->is_function_scope()) {
+ Scope* declaration_scope = top_scope_->DeclarationScope();
+ if (declaration_scope->is_global_scope() ||
+ declaration_scope->is_eval_scope()) {
Handle<String> type = isolate()->factory()->illegal_return_symbol();
Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
return new(zone()) ExpressionStatement(throw_error);
}
Token::Value tok = peek();
- if (scanner().has_line_terminator_before_next() ||
+ if (scanner().HasAnyLineTerminatorBeforeNext() ||
tok == Token::SEMICOLON ||
tok == Token::RBRACE ||
tok == Token::EOS) {
@@ -1907,17 +1948,13 @@
}
-Block* Parser::WithHelper(Expression* obj,
- ZoneStringList* labels,
- bool is_catch_block,
- bool* ok) {
+Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
// Parse the statement and collect escaping labels.
- ZoneList<Label*>* target_list = new(zone()) ZoneList<Label*>(0);
- TargetCollector collector(target_list);
+ TargetCollector collector;
Statement* stat;
{ Target target(&this->target_stack_, &collector);
with_nesting_level_++;
- top_scope_->RecordWithStatement();
+ top_scope_->DeclarationScope()->RecordWithStatement();
stat = ParseStatement(labels, CHECK_OK);
with_nesting_level_--;
}
@@ -1927,7 +1964,7 @@
Block* result = new(zone()) Block(NULL, 2, false);
if (result != NULL) {
- result->AddStatement(new(zone()) WithEnterStatement(obj, is_catch_block));
+ result->AddStatement(new(zone()) EnterWithContextStatement(obj));
// Create body block.
Block* body = new(zone()) Block(NULL, 1, false);
@@ -1935,7 +1972,7 @@
// Create exit block.
Block* exit = new(zone()) Block(NULL, 1, false);
- exit->AddStatement(new(zone()) WithExitStatement());
+ exit->AddStatement(new(zone()) ExitContextStatement());
// Return a try-finally statement.
TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit);
@@ -1962,7 +1999,7 @@
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- return WithHelper(expr, labels, false, CHECK_OK);
+ return WithHelper(expr, labels, CHECK_OK);
}
@@ -2032,7 +2069,7 @@
Expect(Token::THROW, CHECK_OK);
int pos = scanner().location().beg_pos;
- if (scanner().has_line_terminator_before_next()) {
+ if (scanner().HasAnyLineTerminatorBeforeNext()) {
ReportMessage("newline_after_throw", Vector<const char*>::empty());
*ok = false;
return NULL;
@@ -2058,18 +2095,13 @@
Expect(Token::TRY, CHECK_OK);
- ZoneList<Label*>* target_list = new(zone()) ZoneList<Label*>(0);
- TargetCollector collector(target_list);
+ TargetCollector try_collector;
Block* try_block;
- { Target target(&this->target_stack_, &collector);
+ { Target target(&this->target_stack_, &try_collector);
try_block = ParseBlock(NULL, CHECK_OK);
}
- Block* catch_block = NULL;
- Variable* catch_var = NULL;
- Block* finally_block = NULL;
-
Token::Value tok = peek();
if (tok != Token::CATCH && tok != Token::FINALLY) {
ReportMessage("no_catch_or_finally", Vector<const char*>::empty());
@@ -2078,18 +2110,19 @@
}
// If we can break out from the catch block and there is a finally block,
- // then we will need to collect jump targets from the catch block. Since
- // we don't know yet if there will be a finally block, we always collect
- // the jump targets.
- ZoneList<Label*>* catch_target_list = new(zone()) ZoneList<Label*>(0);
- TargetCollector catch_collector(catch_target_list);
- bool has_catch = false;
+ // then we will need to collect escaping targets from the catch
+ // block. Since we don't know yet if there will be a finally block, we
+ // always collect the targets.
+ TargetCollector catch_collector;
+ Scope* catch_scope = NULL;
+ Variable* catch_variable = NULL;
+ Block* catch_block = NULL;
+ Handle<String> name;
if (tok == Token::CATCH) {
- has_catch = true;
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
- Handle<String> name = ParseIdentifier(CHECK_OK);
+ name = ParseIdentifier(CHECK_OK);
if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_catch_variable", Vector<const char*>::empty());
@@ -2100,17 +2133,39 @@
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
- // Allocate a temporary for holding the finally state while
- // executing the finally block.
- catch_var =
- top_scope_->NewTemporary(isolate()->factory()->catch_var_symbol());
- Literal* name_literal = new(zone()) Literal(name);
- VariableProxy* catch_var_use = new(zone()) VariableProxy(catch_var);
- Expression* obj =
- new(zone()) CatchExtensionObject(name_literal, catch_var_use);
+ // Rewrite the catch body B to a single statement block
+ // { try B finally { PopContext }}.
+ Block* inner_body;
+ // We need to collect escapes from the body for both the inner
+ // try/finally used to pop the catch context and any possible outer
+ // try/finally.
+ TargetCollector inner_collector;
{ Target target(&this->target_stack_, &catch_collector);
- catch_block = WithHelper(obj, NULL, true, CHECK_OK);
+ { Target target(&this->target_stack_, &inner_collector);
+ catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
+ if (top_scope_->is_strict_mode()) {
+ catch_scope->EnableStrictMode();
+ }
+ catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
+
+ Scope* saved_scope = top_scope_;
+ top_scope_ = catch_scope;
+ inner_body = ParseBlock(NULL, CHECK_OK);
+ top_scope_ = saved_scope;
+ }
}
+
+ // Create exit block.
+ Block* inner_finally = new(zone()) Block(NULL, 1, false);
+ inner_finally->AddStatement(new(zone()) ExitContextStatement());
+
+ // Create a try/finally statement.
+ TryFinallyStatement* inner_try_finally =
+ new(zone()) TryFinallyStatement(inner_body, inner_finally);
+ inner_try_finally->set_escaping_targets(inner_collector.targets());
+
+ catch_block = new(zone()) Block(NULL, 1, false);
+ catch_block->AddStatement(inner_try_finally);
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@@ -2118,45 +2173,48 @@
tok = peek();
}
- if (tok == Token::FINALLY || !has_catch) {
+ Block* finally_block = NULL;
+ if (tok == Token::FINALLY || catch_block == NULL) {
Consume(Token::FINALLY);
- // Declare a variable for holding the finally state while
- // executing the finally block.
finally_block = ParseBlock(NULL, CHECK_OK);
}
// Simplify the AST nodes by converting:
- // 'try { } catch { } finally { }'
+ // 'try B0 catch B1 finally B2'
// to:
- // 'try { try { } catch { } } finally { }'
+ // 'try { try B0 catch B1 } finally B2'
if (catch_block != NULL && finally_block != NULL) {
- VariableProxy* catch_var_defn = new(zone()) VariableProxy(catch_var);
+ // If we have both, create an inner try/catch.
+ ASSERT(catch_scope != NULL && catch_variable != NULL);
TryCatchStatement* statement =
- new(zone()) TryCatchStatement(try_block, catch_var_defn, catch_block);
- statement->set_escaping_targets(collector.targets());
+ new(zone()) TryCatchStatement(try_block,
+ catch_scope,
+ catch_variable,
+ catch_block);
+ statement->set_escaping_targets(try_collector.targets());
try_block = new(zone()) Block(NULL, 1, false);
try_block->AddStatement(statement);
- catch_block = NULL;
+ catch_block = NULL; // Clear to indicate it's been handled.
}
TryStatement* result = NULL;
if (catch_block != NULL) {
ASSERT(finally_block == NULL);
- VariableProxy* catch_var_defn = new(zone()) VariableProxy(catch_var);
+ ASSERT(catch_scope != NULL && catch_variable != NULL);
result =
- new(zone()) TryCatchStatement(try_block, catch_var_defn, catch_block);
- result->set_escaping_targets(collector.targets());
+ new(zone()) TryCatchStatement(try_block,
+ catch_scope,
+ catch_variable,
+ catch_block);
} else {
ASSERT(finally_block != NULL);
result = new(zone()) TryFinallyStatement(try_block, finally_block);
- // Add the jump targets of the try block and the catch block.
- for (int i = 0; i < collector.targets()->length(); i++) {
- catch_collector.AddTarget(collector.targets()->at(i));
- }
- result->set_escaping_targets(catch_collector.targets());
+ // Combine the jump targets of the try block and the possible catch block.
+ try_collector.targets()->AddAll(*catch_collector.targets());
}
+ result->set_escaping_targets(try_collector.targets());
return result;
}
@@ -2221,10 +2279,12 @@
Expect(Token::LPAREN, CHECK_OK);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) {
- Expression* each = NULL;
+ Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(false, &each, CHECK_OK);
- if (peek() == Token::IN && each != NULL) {
+ ParseVariableDeclarations(false, &name, CHECK_OK);
+
+ if (peek() == Token::IN && !name.is_null()) {
+ VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
ForInStatement* loop = new(zone()) ForInStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2376,7 +2436,7 @@
if ((op == Token::INIT_VAR
|| op == Token::INIT_CONST
|| op == Token::ASSIGN)
- && (right->AsCall() == NULL)) {
+ && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
fni_->Infer();
}
fni_->Leave();
@@ -2545,18 +2605,26 @@
int position = scanner().location().beg_pos;
Expression* expression = ParseUnaryExpression(CHECK_OK);
- // Compute some expressions involving only number literals.
- if (expression != NULL && expression->AsLiteral() &&
- expression->AsLiteral()->handle()->IsNumber()) {
- double value = expression->AsLiteral()->handle()->Number();
- switch (op) {
- case Token::ADD:
- return expression;
- case Token::SUB:
- return NewNumberLiteral(-value);
- case Token::BIT_NOT:
- return NewNumberLiteral(~DoubleToInt32(value));
- default: break;
+ if (expression != NULL && (expression->AsLiteral() != NULL)) {
+ Handle<Object> literal = expression->AsLiteral()->handle();
+ if (op == Token::NOT) {
+ // Convert the literal to a boolean condition and negate it.
+ bool condition = literal->ToBoolean()->IsTrue();
+ Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
+ return new(zone()) Literal(result);
+ } else if (literal->IsNumber()) {
+ // Compute some expressions involving only number literals.
+ double value = literal->Number();
+ switch (op) {
+ case Token::ADD:
+ return expression;
+ case Token::SUB:
+ return NewNumberLiteral(-value);
+ case Token::BIT_NOT:
+ return NewNumberLiteral(~DoubleToInt32(value));
+ default:
+ break;
+ }
}
}
@@ -2607,7 +2675,7 @@
// LeftHandSideExpression ('++' | '--')?
Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
- if (!scanner().has_line_terminator_before_next() &&
+ if (!scanner().HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
// Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax
@@ -2758,11 +2826,12 @@
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
Handle<String> name;
- bool is_reserved_name = false;
+ bool is_strict_reserved_name = false;
if (peek_any_identifier()) {
- name = ParseIdentifierOrReservedWord(&is_reserved_name, CHECK_OK);
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
+ CHECK_OK);
}
- result = ParseFunctionLiteral(name, is_reserved_name,
+ result = ParseFunctionLiteral(name, is_strict_reserved_name,
function_token_position, NESTED, CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
@@ -2775,6 +2844,14 @@
int pos = scanner().location().beg_pos;
Expression* index = ParseExpression(true, CHECK_OK);
result = new(zone()) Property(result, index, pos);
+ if (fni_ != NULL) {
+ if (index->IsPropertyName()) {
+ fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
+ } else {
+ fni_->PushLiteralName(
+ isolate()->factory()->anonymous_function_symbol());
+ }
+ }
Expect(Token::RBRACK, CHECK_OK);
break;
}
@@ -2833,6 +2910,9 @@
return ReportMessage("unexpected_token_identifier",
Vector<const char*>::empty());
case Token::FUTURE_RESERVED_WORD:
+ return ReportMessage("unexpected_reserved",
+ Vector<const char*>::empty());
+ case Token::FUTURE_STRICT_RESERVED_WORD:
return ReportMessage(top_scope_->is_strict_mode() ?
"unexpected_strict_reserved" :
"unexpected_token_identifier",
@@ -2872,8 +2952,7 @@
switch (peek()) {
case Token::THIS: {
Consume(Token::THIS);
- VariableProxy* recv = top_scope_->receiver();
- result = recv;
+ result = new(zone()) VariableProxy(top_scope_->receiver());
break;
}
@@ -2893,7 +2972,7 @@
break;
case Token::IDENTIFIER:
- case Token::FUTURE_RESERVED_WORD: {
+ case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
result = top_scope_->NewUnresolved(name,
@@ -3304,6 +3383,7 @@
bool is_keyword = Token::IsKeyword(next);
if (next == Token::IDENTIFIER || next == Token::NUMBER ||
next == Token::FUTURE_RESERVED_WORD ||
+ next == Token::FUTURE_STRICT_RESERVED_WORD ||
next == Token::STRING || is_keyword) {
Handle<String> name;
if (is_keyword) {
@@ -3358,11 +3438,12 @@
switch (next) {
case Token::FUTURE_RESERVED_WORD:
+ case Token::FUTURE_STRICT_RESERVED_WORD:
case Token::IDENTIFIER: {
bool is_getter = false;
bool is_setter = false;
Handle<String> id =
- ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+ ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if (fni_ != NULL) fni_->PushLiteralName(id);
if ((is_getter || is_setter) && peek() != Token::COLON) {
@@ -3506,6 +3587,12 @@
while (!done) {
Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
result->Add(argument);
+ if (result->length() > kMaxNumFunctionParameters) {
+ ReportMessageAt(scanner().location(), "too_many_arguments",
+ Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
done = (peek() == Token::RPAREN);
if (!done) Expect(Token::COMMA, CHECK_OK);
}
@@ -3515,7 +3602,7 @@
FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
- bool name_is_reserved,
+ bool name_is_strict_reserved,
int function_token_position,
FunctionLiteralType type,
bool* ok) {
@@ -3544,6 +3631,7 @@
int end_pos;
bool only_simple_this_property_assignments;
Handle<FixedArray> this_property_assignments;
+ bool has_duplicate_parameters = false;
// Parse function body.
{ LexicalScope lexical_scope(this, scope, isolate());
top_scope_->SetScopeName(name);
@@ -3558,25 +3646,24 @@
bool done = (peek() == Token::RPAREN);
while (!done) {
- bool is_reserved = false;
+ bool is_strict_reserved = false;
Handle<String> param_name =
- ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
+ ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
+ CHECK_OK);
// Store locations for possible future error reports.
if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
name_loc = scanner().location();
}
if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
+ has_duplicate_parameters = true;
dupe_loc = scanner().location();
}
- if (!reserved_loc.IsValid() && is_reserved) {
+ if (!reserved_loc.IsValid() && is_strict_reserved) {
reserved_loc = scanner().location();
}
- Variable* parameter = top_scope_->DeclareLocal(param_name,
- Variable::VAR,
- Scope::PARAMETER);
- top_scope_->AddParameter(parameter);
+ top_scope_->DeclareParameter(param_name);
num_parameters++;
if (num_parameters > kMaxNumFunctionParameters) {
ReportMessageAt(scanner().location(), "too_many_parameters",
@@ -3633,6 +3720,7 @@
scanner().SeekForward(end_pos - 1);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
+ if (entry.strict_mode()) top_scope_->EnableStrictMode();
only_simple_this_property_assignments = false;
this_property_assignments = isolate()->factory()->empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK);
@@ -3673,7 +3761,7 @@
*ok = false;
return NULL;
}
- if (name_is_reserved) {
+ if (name_is_strict_reserved) {
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3704,7 +3792,8 @@
num_parameters,
start_pos,
end_pos,
- (function_name->length() > 0));
+ (function_name->length() > 0),
+ has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
@@ -3723,7 +3812,7 @@
if (extension_ != NULL) {
// The extension structures are only accessible while parsing the
// very first time not when reparsing because of lazy compilation.
- top_scope_->ForceEagerCompilation();
+ top_scope_->DeclarationScope()->ForceEagerCompilation();
}
const Runtime::Function* function = Runtime::FunctionForSymbol(name);
@@ -3761,7 +3850,8 @@
bool Parser::peek_any_identifier() {
Token::Value next = peek();
return next == Token::IDENTIFIER ||
- next == Token::FUTURE_RESERVED_WORD;
+ next == Token::FUTURE_RESERVED_WORD ||
+ next == Token::FUTURE_STRICT_RESERVED_WORD;
}
@@ -3799,7 +3889,7 @@
Next();
return;
}
- if (scanner().has_line_terminator_before_next() ||
+ if (scanner().HasAnyLineTerminatorBeforeNext() ||
tok == Token::RBRACE ||
tok == Token::EOS) {
return;
@@ -3823,22 +3913,27 @@
}
+// Parses and identifier that is valid for the current scope, in particular it
+// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
- bool is_reserved;
- return ParseIdentifierOrReservedWord(&is_reserved, ok);
+ if (top_scope_->is_strict_mode()) {
+ Expect(Token::IDENTIFIER, ok);
+ } else if (!Check(Token::IDENTIFIER)) {
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ }
+ if (!*ok) return Handle<String>();
+ return GetSymbol(ok);
}
-Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
- bool* ok) {
- *is_reserved = false;
- if (top_scope_->is_strict_mode()) {
- Expect(Token::IDENTIFIER, ok);
- } else {
- if (!Check(Token::IDENTIFIER)) {
- Expect(Token::FUTURE_RESERVED_WORD, ok);
- *is_reserved = true;
- }
+// Parses and identifier or a strict mode future reserved word, and indicate
+// whether it is strict mode future reserved.
+Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
+ bool* is_strict_reserved, bool* ok) {
+ *is_strict_reserved = false;
+ if (!Check(Token::IDENTIFIER)) {
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ *is_strict_reserved = true;
}
if (!*ok) return Handle<String>();
return GetSymbol(ok);
@@ -3848,8 +3943,9 @@
Handle<String> Parser::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER &&
- next != Token::FUTURE_RESERVED_WORD &&
- !Token::IsKeyword(next)) {
+ next != Token::FUTURE_RESERVED_WORD &&
+ next != Token::FUTURE_STRICT_RESERVED_WORD &&
+ !Token::IsKeyword(next)) {
ReportUnexpectedToken(next);
*ok = false;
return Handle<String>();
@@ -3890,12 +3986,12 @@
}
-// This function reads an identifier and determines whether or not it
+// This function reads an identifier name and determines whether or not it
// is 'get' or 'set'.
-Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- Handle<String> result = ParseIdentifier(ok);
+Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok) {
+ Handle<String> result = ParseIdentifierName(ok);
if (!*ok) return Handle<String>();
if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
const char* token = scanner().literal_ascii_string().start();
@@ -4895,7 +4991,7 @@
bool allow_lazy,
ParserRecorder* recorder) {
Isolate* isolate = Isolate::Current();
- V8JavaScriptScanner scanner(isolate->unicode_cache());
+ JavaScriptScanner scanner(isolate->unicode_cache());
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
@@ -4967,6 +5063,7 @@
Parser parser(script, true, NULL, NULL);
result = parser.ParseLazy(info);
} else {
+ // Whether we allow %identifier(..) syntax.
bool allow_natives_syntax =
info->allows_natives_syntax() || FLAG_allow_natives_syntax;
ScriptDataImpl* pre_data = info->pre_parse_data();
« no previous file with comments | « src/parser.h ('k') | src/platform.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698