diff options
| author | Ben Murdoch <benm@google.com> | 2011-12-02 17:19:32 +0000 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2011-12-02 17:27:49 +0000 |
| commit | 3fb3ca8c7ca439d408449a395897395c0faae8d1 (patch) | |
| tree | 5cb33db083ae7ebe431e2a460fb3806c54531f9c /src/parser.cc | |
| parent | 257744e915dfc84d6d07a6b2accf8402d9ffc708 (diff) | |
| download | android_external_v8-3fb3ca8c7ca439d408449a395897395c0faae8d1.tar.gz android_external_v8-3fb3ca8c7ca439d408449a395897395c0faae8d1.tar.bz2 android_external_v8-3fb3ca8c7ca439d408449a395897395c0faae8d1.zip | |
Upgrade to V8 3.4
Merge 3.4.14.35
Simple merge required updates to makefiles only.
Bug: 568872
Change-Id: I403a38452c547e06fcfa951c12eca12a1bc40978
Diffstat (limited to 'src/parser.cc')
| -rw-r--r-- | src/parser.cc | 820 |
1 files changed, 486 insertions, 334 deletions
diff --git a/src/parser.cc b/src/parser.cc index 7ad64407..ece0cfea 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -411,6 +411,7 @@ Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) { 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* parser, Scope* scope, Isolate* isolate) 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 @@ Parser::Parser(Handle<Script> script, 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(); @@ -648,6 +648,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, } if (ok) { result = new(zone()) FunctionLiteral( + isolate(), no_name, top_scope_, body, @@ -658,7 +659,8 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, 0, 0, source->length(), - false); + FunctionLiteral::ANONYMOUS_EXPRESSION, + false); // Does not have duplicate parameters. } else if (stack_overflow_) { isolate()->StackOverflow(); } @@ -674,7 +676,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, } 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 +709,7 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, 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; @@ -717,7 +719,6 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, { // Parse the function literal. - Handle<String> no_name = isolate()->factory()->empty_symbol(); Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); if (!info->closure().is_null()) { scope = Scope::DeserializeScopeChain(info, scope); @@ -728,12 +729,17 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, top_scope_->EnableStrictMode(); } - FunctionLiteralType type = - shared_info->is_expression() ? EXPRESSION : DECLARATION; + FunctionLiteral::Type type = shared_info->is_expression() + ? (shared_info->is_anonymous() + ? FunctionLiteral::ANONYMOUS_EXPRESSION + : FunctionLiteral::NAMED_EXPRESSION) + : FunctionLiteral::DECLARATION; bool ok = true; result = ParseFunctionLiteral(name, - false, // Strict mode name already checked. - RelocInfo::kNoPosition, type, &ok); + false, // Strict mode name already checked. + RelocInfo::kNoPosition, + type, + &ok); // Make sure the results agree. ASSERT(ok == (result != NULL)); } @@ -822,14 +828,24 @@ class ParserFinder { // 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 +866,14 @@ class InitializationBlockFinder : public ParserFinder { // 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 +936,7 @@ class InitializationBlockFinder : public ParserFinder { bool InBlock() { return first_in_block_ != NULL; } + const bool enabled_; Assignment* first_in_block_; Assignment* last_in_block_; int block_size_; @@ -920,17 +945,18 @@ class InitializationBlockFinder : public ParserFinder { }; -// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form +// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form // this.x = ...;, where x is a named property. It also determines whether a // function contains only assignments of this type. -class ThisNamedPropertyAssigmentFinder : public ParserFinder { +class ThisNamedPropertyAssignmentFinder : public ParserFinder { public: - explicit ThisNamedPropertyAssigmentFinder(Isolate* isolate) + explicit ThisNamedPropertyAssignmentFinder(Isolate* isolate) : isolate_(isolate), only_simple_this_property_assignments_(true), - names_(NULL), - assigned_arguments_(NULL), - assigned_constants_(NULL) {} + names_(0), + assigned_arguments_(0), + assigned_constants_(0) { + } void Update(Scope* scope, Statement* stat) { // Bail out if function already has property assignment that are @@ -957,19 +983,17 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder { // Returns a fixed array containing three elements for each assignment of the // form this.x = y; Handle<FixedArray> GetThisPropertyAssignments() { - if (names_ == NULL) { + if (names_.is_empty()) { return isolate_->factory()->empty_fixed_array(); } - ASSERT(names_ != NULL); - ASSERT(assigned_arguments_ != NULL); - ASSERT_EQ(names_->length(), assigned_arguments_->length()); - ASSERT_EQ(names_->length(), assigned_constants_->length()); + ASSERT_EQ(names_.length(), assigned_arguments_.length()); + ASSERT_EQ(names_.length(), assigned_constants_.length()); Handle<FixedArray> assignments = - isolate_->factory()->NewFixedArray(names_->length() * 3); - for (int i = 0; i < names_->length(); i++) { - assignments->set(i * 3, *names_->at(i)); - assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i))); - assignments->set(i * 3 + 2, *assigned_constants_->at(i)); + isolate_->factory()->NewFixedArray(names_.length() * 3); + for (int i = 0; i < names_.length(); ++i) { + assignments->set(i * 3, *names_[i]); + assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i])); + assignments->set(i * 3 + 2, *assigned_constants_[i]); } return assignments; } @@ -1026,18 +1050,37 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder { AssignmentFromSomethingElse(); } + + + + // We will potentially reorder the property assignments, so they must be + // simple enough that the ordering does not matter. void AssignmentFromParameter(Handle<String> name, int index) { - EnsureAllocation(); - names_->Add(name); - assigned_arguments_->Add(index); - assigned_constants_->Add(isolate_->factory()->undefined_value()); + EnsureInitialized(); + for (int i = 0; i < names_.length(); ++i) { + if (name->Equals(*names_[i])) { + assigned_arguments_[i] = index; + assigned_constants_[i] = isolate_->factory()->undefined_value(); + return; + } + } + names_.Add(name); + assigned_arguments_.Add(index); + assigned_constants_.Add(isolate_->factory()->undefined_value()); } void AssignmentFromConstant(Handle<String> name, Handle<Object> value) { - EnsureAllocation(); - names_->Add(name); - assigned_arguments_->Add(-1); - assigned_constants_->Add(value); + EnsureInitialized(); + for (int i = 0; i < names_.length(); ++i) { + if (name->Equals(*names_[i])) { + assigned_arguments_[i] = -1; + assigned_constants_[i] = value; + return; + } + } + names_.Add(name); + assigned_arguments_.Add(-1); + assigned_constants_.Add(value); } void AssignmentFromSomethingElse() { @@ -1045,22 +1088,21 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder { only_simple_this_property_assignments_ = false; } - void EnsureAllocation() { - if (names_ == NULL) { - ASSERT(assigned_arguments_ == NULL); - ASSERT(assigned_constants_ == NULL); - Zone* zone = isolate_->zone(); - names_ = new(zone) ZoneStringList(4); - assigned_arguments_ = new(zone) ZoneList<int>(4); - assigned_constants_ = new(zone) ZoneObjectList(4); + void EnsureInitialized() { + if (names_.capacity() == 0) { + ASSERT(assigned_arguments_.capacity() == 0); + ASSERT(assigned_constants_.capacity() == 0); + names_.Initialize(4); + assigned_arguments_.Initialize(4); + assigned_constants_.Initialize(4); } } Isolate* isolate_; bool only_simple_this_property_assignments_; - ZoneStringList* names_; - ZoneList<int>* assigned_arguments_; - ZoneObjectList* assigned_constants_; + ZoneStringList names_; + ZoneList<int> assigned_arguments_; + ZoneObjectList assigned_constants_; }; @@ -1077,8 +1119,8 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, TargetScope scope(&this->target_stack_); ASSERT(processor != NULL); - InitializationBlockFinder block_finder; - ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate()); + InitializationBlockFinder block_finder(top_scope_, target_stack_); + ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate()); bool directive_prologue = true; // Parsing directive prologue. while (peek() != end_token) { @@ -1132,12 +1174,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } } - // 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); @@ -1247,7 +1284,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // one must take great care not to treat it as a // fall-through. It is much easier just to wrap the entire // try-statement in a statement block and put the labels there - Block* result = new(zone()) Block(labels, 1, false); + Block* result = new(zone()) Block(isolate(), labels, 1, false); Target target(&this->target_stack_, result); TryStatement* statement = ParseTryStatement(CHECK_OK); if (statement) { @@ -1269,9 +1306,6 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { return ParseFunctionDeclaration(ok); } - case Token::NATIVE: - return ParseNativeDeclaration(ok); - case Token::DEBUGGER: stmt = ParseDebuggerStatement(ok); break; @@ -1304,13 +1338,14 @@ VariableProxy* Parser::Declare(Handle<String> name, // 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 +1361,7 @@ VariableProxy* Parser::Declare(Handle<String> name, Expression* expression = NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), type_string, name); - top_scope_->SetIllegalRedeclaration(expression); + declaration_scope->SetIllegalRedeclaration(expression); } } } @@ -1347,14 +1382,18 @@ VariableProxy* Parser::Declare(Handle<String> name, // 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 +1431,6 @@ VariableProxy* Parser::Declare(Handle<String> name, // 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 +1449,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // 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 = @@ -1443,10 +1475,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // introduced dynamically when we meet their declarations, whereas // other functions are setup when entering the surrounding scope. SharedFunctionInfoLiteral* lit = - new(zone()) SharedFunctionInfoLiteral(shared); + new(zone()) SharedFunctionInfoLiteral(isolate(), shared); VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK); return new(zone()) ExpressionStatement(new(zone()) Assignment( - Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); + isolate(), Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); } @@ -1455,12 +1487,13 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) { // '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, + FunctionLiteral::DECLARATION, CHECK_OK); // Even if we're not at the top-level of the global or a function // scope, we treat is as such and introduce the function with it's @@ -1478,12 +1511,16 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { // (ECMA-262, 3rd, 12.2) // // Construct block expecting 16 statements. - Block* result = new(zone()) Block(labels, 16, false); + Block* result = new(zone()) Block(isolate(), 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 +1531,8 @@ Block* Parser::ParseVariableStatement(bool* ok) { // 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 +1550,19 @@ bool Parser::IsEvalOrArguments(Handle<String> string) { // 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; @@ -1548,19 +1586,19 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // is inside an initializer block, it is ignored. // // Create new block with one expected declaration. - Block* block = new(zone()) Block(NULL, 1, true); - VariableProxy* last_var = NULL; // the last variable declared + Block* block = new(zone()) Block(isolate(), NULL, 1, true); 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 +1616,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // 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 +1635,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // // 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 +1653,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // 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 +1661,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, 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,11 +1694,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // 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. - arguments->Add(new(zone()) Literal(name)); + arguments->Add(NewLiteral(name)); CallRuntime* initialize; if (is_const) { @@ -1669,14 +1711,17 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // the number of arguments (1 or 2). initialize = new(zone()) CallRuntime( - isolate()->factory()->InitializeConstGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeConstGlobal), - arguments); + isolate(), + isolate()->factory()->InitializeConstGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeConstGlobal), + arguments); } 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 @@ -1693,9 +1738,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // the number of arguments (2 or 3). initialize = new(zone()) CallRuntime( - isolate()->factory()->InitializeVarGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeVarGlobal), - arguments); + isolate(), + isolate()->factory()->InitializeVarGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeVarGlobal), + arguments); } block->AddStatement(new(zone()) ExpressionStatement(initialize)); @@ -1713,8 +1759,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // 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(isolate(), op, proxy, value, position); if (block) { block->AddStatement(new(zone()) ExpressionStatement(assignment)); } @@ -1723,10 +1772,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, 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 +1800,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, // 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 +1830,20 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, 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); @@ -1803,7 +1866,8 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { } else { else_statement = EmptyStatement(); } - return new(zone()) IfStatement(condition, then_statement, else_statement); + return new(zone()) IfStatement( + isolate(), condition, then_statement, else_statement); } @@ -1814,7 +1878,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) { 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 +1908,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { 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 +1950,16 @@ Statement* Parser::ParseReturnStatement(bool* ok) { // 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,35 +1973,31 @@ Statement* Parser::ParseReturnStatement(bool* ok) { } -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_--; } // Create resulting block with two statements. // 1: Evaluate the with expression. // 2: The try-finally block evaluating the body. - Block* result = new(zone()) Block(NULL, 2, false); + Block* result = new(zone()) Block(isolate(), 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); + Block* body = new(zone()) Block(isolate(), NULL, 1, false); body->AddStatement(stat); // Create exit block. - Block* exit = new(zone()) Block(NULL, 1, false); - exit->AddStatement(new(zone()) WithExitStatement()); + Block* exit = new(zone()) Block(isolate(), NULL, 1, false); + exit->AddStatement(new(zone()) ExitContextStatement()); // Return a try-finally statement. TryFinallyStatement* wrapper = new(zone()) TryFinallyStatement(body, exit); @@ -1962,7 +2024,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { Expression* expr = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - return WithHelper(expr, labels, false, CHECK_OK); + return WithHelper(expr, labels, CHECK_OK); } @@ -1995,7 +2057,7 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { statements->Add(stat); } - return new(zone()) CaseClause(label, statements, pos); + return new(zone()) CaseClause(isolate(), label, statements, pos); } @@ -2004,7 +2066,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, // SwitchStatement :: // 'switch' '(' Expression ')' '{' CaseClause* '}' - SwitchStatement* statement = new(zone()) SwitchStatement(labels); + SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels); Target target(&this->target_stack_, statement); Expect(Token::SWITCH, CHECK_OK); @@ -2032,7 +2094,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) { 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; @@ -2040,7 +2102,8 @@ Statement* Parser::ParseThrowStatement(bool* ok) { Expression* exception = ParseExpression(true, CHECK_OK); ExpectSemicolon(CHECK_OK); - return new(zone()) ExpressionStatement(new(zone()) Throw(exception, pos)); + return new(zone()) ExpressionStatement( + new(zone()) Throw(isolate(), exception, pos)); } @@ -2058,18 +2121,13 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { 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 +2136,19 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { } // 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 +2159,39 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { 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(isolate(), 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(isolate(), NULL, 1, false); + catch_block->AddStatement(inner_try_finally); } else { Expect(Token::LBRACE, CHECK_OK); } @@ -2118,45 +2199,48 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { 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()); - try_block = new(zone()) Block(NULL, 1, false); + new(zone()) TryCatchStatement(try_block, + catch_scope, + catch_variable, + catch_block); + statement->set_escaping_targets(try_collector.targets()); + try_block = new(zone()) Block(isolate(), 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; } @@ -2166,7 +2250,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels, // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' - DoWhileStatement* loop = new(zone()) DoWhileStatement(labels); + DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); @@ -2197,7 +2281,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { // WhileStatement :: // 'while' '(' Expression ')' Statement - WhileStatement* loop = new(zone()) WhileStatement(labels); + WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::WHILE, CHECK_OK); @@ -2221,11 +2305,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { 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) { - ForInStatement* loop = new(zone()) ForInStatement(labels); + 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(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2234,7 +2320,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Statement* body = ParseStatement(NULL, CHECK_OK); loop->Initialize(each, enumerable, body); - Block* result = new(zone()) Block(NULL, 2, false); + Block* result = new(zone()) Block(isolate(), NULL, 2, false); result->AddStatement(variable_statement); result->AddStatement(loop); // Parsed for-in loop w/ variable/const declaration. @@ -2255,7 +2341,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { isolate()->factory()->invalid_lhs_in_for_in_symbol(); expression = NewThrowReferenceError(type); } - ForInStatement* loop = new(zone()) ForInStatement(labels); + ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2274,7 +2360,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { } // Standard 'for' loop - ForStatement* loop = new(zone()) ForStatement(labels); + ForStatement* loop = new(zone()) ForStatement(isolate(), labels); Target target(&this->target_stack_, loop); // Parsed initializer at this point. @@ -2310,7 +2396,8 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { Expect(Token::COMMA, CHECK_OK); int position = scanner().location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - result = new(zone()) BinaryOperation(Token::COMMA, result, right, position); + result = new(zone()) BinaryOperation( + isolate(), Token::COMMA, result, right, position); } return result; } @@ -2376,13 +2463,13 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { 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(); } - return new(zone()) Assignment(op, expression, right, pos); + return new(zone()) Assignment(isolate(), op, expression, right, pos); } @@ -2404,8 +2491,8 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { Expect(Token::COLON, CHECK_OK); int right_position = scanner().peek_location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - return new(zone()) Conditional(expression, left, right, - left_position, right_position); + return new(zone()) Conditional( + isolate(), expression, left, right, left_position, right_position); } @@ -2492,12 +2579,12 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { x = NewCompareNode(cmp, x, y, position); if (cmp != op) { // The comparison was negated - add a NOT. - x = new(zone()) UnaryOperation(Token::NOT, x, position); + x = new(zone()) UnaryOperation(isolate(), Token::NOT, x, position); } } else { // We have a "normal" binary operation. - x = new(zone()) BinaryOperation(op, x, y, position); + x = new(zone()) BinaryOperation(isolate(), op, x, y, position); } } } @@ -2514,15 +2601,15 @@ Expression* Parser::NewCompareNode(Token::Value op, bool is_strict = (op == Token::EQ_STRICT); Literal* x_literal = x->AsLiteral(); if (x_literal != NULL && x_literal->IsNull()) { - return new(zone()) CompareToNull(is_strict, y); + return new(zone()) CompareToNull(isolate(), is_strict, y); } Literal* y_literal = y->AsLiteral(); if (y_literal != NULL && y_literal->IsNull()) { - return new(zone()) CompareToNull(is_strict, x); + return new(zone()) CompareToNull(isolate(), is_strict, x); } } - return new(zone()) CompareOperation(op, x, y, position); + return new(zone()) CompareOperation(isolate(), op, x, y, position); } @@ -2545,18 +2632,26 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { 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 NewLiteral(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; + } } } @@ -2570,7 +2665,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } } - return new(zone()) UnaryOperation(op, expression, position); + return new(zone()) UnaryOperation(isolate(), op, expression, position); } else if (Token::IsCountOp(op)) { op = Next(); @@ -2591,7 +2686,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } int position = scanner().location().beg_pos; - return new(zone()) CountOperation(op, + return new(zone()) CountOperation(isolate(), + op, true /* prefix */, expression, position); @@ -2607,7 +2703,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { // 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 @@ -2627,7 +2723,8 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { Token::Value next = Next(); int position = scanner().location().beg_pos; expression = - new(zone()) CountOperation(next, + new(zone()) CountOperation(isolate(), + next, false /* postfix */, expression, position); @@ -2653,7 +2750,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new(zone()) Property(result, index, pos); + result = new(zone()) Property(isolate(), result, index, pos); Expect(Token::RBRACK, CHECK_OK); break; } @@ -2691,7 +2788,10 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle<String> name = ParseIdentifierName(CHECK_OK); - result = new(zone()) Property(result, new(zone()) Literal(name), pos); + result = new(zone()) Property(isolate(), + result, + NewLiteral(name), + pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -2727,7 +2827,8 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { if (!stack->is_empty()) { int last = stack->pop(); - result = new(zone()) CallNew(result, + result = new(zone()) CallNew(isolate(), + result, new(zone()) ZoneList<Expression*>(0), last); } @@ -2758,12 +2859,19 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, 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, - function_token_position, NESTED, CHECK_OK); + FunctionLiteral::Type type = name.is_null() + ? FunctionLiteral::ANONYMOUS_EXPRESSION + : FunctionLiteral::NAMED_EXPRESSION; + result = ParseFunctionLiteral(name, + is_strict_reserved_name, + function_token_position, + type, + CHECK_OK); } else { result = ParsePrimaryExpression(CHECK_OK); } @@ -2774,7 +2882,15 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::LBRACK); int pos = scanner().location().beg_pos; Expression* index = ParseExpression(true, CHECK_OK); - result = new(zone()) Property(result, index, pos); + result = new(zone()) Property(isolate(), 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; } @@ -2782,7 +2898,10 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::PERIOD); int pos = scanner().location().beg_pos; Handle<String> name = ParseIdentifierName(CHECK_OK); - result = new(zone()) Property(result, new(zone()) Literal(name), pos); + result = new(zone()) Property(isolate(), + result, + NewLiteral(name), + pos); if (fni_ != NULL) fni_->PushLiteralName(name); break; } @@ -2791,7 +2910,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, // Consume one of the new prefixes (already parsed). ZoneList<Expression*>* args = ParseArguments(CHECK_OK); int last = stack->pop(); - result = new CallNew(result, args, last); + result = new(zone()) CallNew(isolate(), result, args, last); break; } default: @@ -2833,6 +2952,9 @@ void Parser::ReportUnexpectedToken(Token::Value token) { 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,28 +2994,30 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { switch (peek()) { case Token::THIS: { Consume(Token::THIS); - VariableProxy* recv = top_scope_->receiver(); - result = recv; + result = new(zone()) VariableProxy(isolate(), top_scope_->receiver()); break; } case Token::NULL_LITERAL: Consume(Token::NULL_LITERAL); - result = new(zone()) Literal(isolate()->factory()->null_value()); + result = new(zone()) Literal( + isolate(), isolate()->factory()->null_value()); break; case Token::TRUE_LITERAL: Consume(Token::TRUE_LITERAL); - result = new(zone()) Literal(isolate()->factory()->true_value()); + result = new(zone()) Literal( + isolate(), isolate()->factory()->true_value()); break; case Token::FALSE_LITERAL: Consume(Token::FALSE_LITERAL); - result = new(zone()) Literal(isolate()->factory()->false_value()); + result = new(zone()) Literal( + isolate(), isolate()->factory()->false_value()); 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, @@ -2915,7 +3039,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { case Token::STRING: { Consume(Token::STRING); Handle<String> symbol = GetSymbol(CHECK_OK); - result = new(zone()) Literal(symbol); + result = NewLiteral(symbol); if (fni_ != NULL) fni_->PushLiteralName(symbol); break; } @@ -3042,8 +3166,8 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { literals->set_map(isolate()->heap()->fixed_cow_array_map()); } - return new(zone()) ArrayLiteral(literals, values, - literal_index, is_simple, depth); + return new(zone()) ArrayLiteral( + isolate(), literals, values, literal_index, is_simple, depth); } @@ -3304,6 +3428,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, 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) { @@ -3315,7 +3440,7 @@ ObjectLiteral::Property* Parser::ParseObjectLiteralGetSet(bool is_getter, ParseFunctionLiteral(name, false, // reserved words are allowed here RelocInfo::kNoPosition, - DECLARATION, + FunctionLiteral::ANONYMOUS_EXPRESSION, CHECK_OK); // Allow any number of parameters for compatiabilty with JSC. // Specification only allows zero parameters for get and one for set. @@ -3345,7 +3470,6 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode()); Expect(Token::LBRACE, CHECK_OK); - Scanner::Location loc = scanner().location(); while (peek() != Token::RBRACE) { if (fni_ != NULL) fni_->Enter(); @@ -3358,11 +3482,12 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { 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) { @@ -3386,7 +3511,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } // Failed to parse as get/set property, so it's just a property // called "get" or "set". - key = new(zone()) Literal(id); + key = NewLiteral(id); break; } case Token::STRING: { @@ -3398,7 +3523,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { key = NewNumberLiteral(index); break; } - key = new(zone()) Literal(string); + key = NewLiteral(string); break; } case Token::NUMBER: { @@ -3414,7 +3539,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { if (Token::IsKeyword(next)) { Consume(next); Handle<String> string = GetSymbol(CHECK_OK); - key = new(zone()) Literal(string); + key = NewLiteral(string); } else { // Unexpected token. Token::Value next = Next(); @@ -3467,13 +3592,14 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { &is_simple, &fast_elements, &depth); - return new(zone()) ObjectLiteral(constant_properties, - properties, - literal_index, - is_simple, - fast_elements, - depth, - has_function); + return new(zone()) ObjectLiteral(isolate(), + constant_properties, + properties, + literal_index, + is_simple, + fast_elements, + depth, + has_function); } @@ -3492,7 +3618,8 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { Handle<String> js_flags = NextLiteralString(TENURED); Next(); - return new(zone()) RegExpLiteral(js_pattern, js_flags, literal_index); + return new(zone()) RegExpLiteral( + isolate(), js_pattern, js_flags, literal_index); } @@ -3520,29 +3647,29 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) { } -FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, - bool name_is_reserved, +FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, + bool name_is_strict_reserved, int function_token_position, - FunctionLiteralType type, + FunctionLiteral::Type type, bool* ok) { // Function :: // '(' FormalParameterList? ')' '{' FunctionBody '}' - bool is_named = !var_name.is_null(); - // The name associated with this function. If it's a function expression, - // this is the actual function name, otherwise this is the name of the - // variable declared and initialized with the function (expression). In - // that case, we don't have a function name (it's empty). - Handle<String> name = - is_named ? var_name : isolate()->factory()->empty_symbol(); - // The function name, if any. - Handle<String> function_name = isolate()->factory()->empty_symbol(); - if (is_named && (type == EXPRESSION || type == NESTED)) { - function_name = name; + // Anonymous functions were passed either the empty symbol or a null + // handle as the function name. Remember if we were passed a non-empty + // handle to decide whether to invoke function name inference. + bool should_infer_name = function_name.is_null(); + + // We want a non-null handle as the function name. + if (should_infer_name) { + function_name = isolate()->factory()->empty_symbol(); } int num_parameters = 0; - Scope* scope = NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); + // Function declarations are hoisted. + Scope* scope = (type == FunctionLiteral::DECLARATION) + ? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false) + : NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8); int materialized_literal_count; int expected_property_count; @@ -3550,9 +3677,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, 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); + top_scope_->SetScopeName(function_name); // FormalParameterList :: // '(' (Identifier)*[','] ')' @@ -3564,25 +3692,24 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, 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", @@ -3603,46 +3730,56 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, // NOTE: We create a proxy and resolve it here so that in the // future we can change the AST to only refer to VariableProxies // instead of Variables and Proxis as is the case now. - if (!function_name.is_null() && function_name->length() > 0) { + if (type == FunctionLiteral::NAMED_EXPRESSION) { Variable* fvar = top_scope_->DeclareFunctionVar(function_name); VariableProxy* fproxy = top_scope_->NewUnresolved(function_name, inside_with()); fproxy->BindTo(fvar); body->Add(new(zone()) ExpressionStatement( - new(zone()) Assignment(Token::INIT_CONST, fproxy, - new(zone()) ThisFunction(), - RelocInfo::kNoPosition))); + new(zone()) Assignment(isolate(), + Token::INIT_CONST, + fproxy, + new(zone()) ThisFunction(isolate()), + RelocInfo::kNoPosition))); } - // Determine if the function will be lazily compiled. The mode can - // only be PARSE_LAZILY if the --lazy flag is true. + // Determine if the function will be lazily compiled. The mode can only + // be PARSE_LAZILY if the --lazy flag is true. We will not lazily + // compile if we do not have preparser data for the function. bool is_lazily_compiled = (mode() == PARSE_LAZILY && top_scope_->outer_scope()->is_global_scope() && top_scope_->HasTrivialOuterContext() && - !parenthesized_function_); + !parenthesized_function_ && + pre_data() != NULL); parenthesized_function_ = false; // The bit was set for this function only. - int function_block_pos = scanner().location().beg_pos; - if (is_lazily_compiled && pre_data() != NULL) { + if (is_lazily_compiled) { + int function_block_pos = scanner().location().beg_pos; FunctionEntry entry = pre_data()->GetFunctionEntry(function_block_pos); if (!entry.is_valid()) { - ReportInvalidPreparseData(name, CHECK_OK); - } - end_pos = entry.end_pos(); - if (end_pos <= function_block_pos) { - // End position greater than end of stream is safe, and hard to check. - ReportInvalidPreparseData(name, CHECK_OK); + // There is no preparser data for the function, we will not lazily + // compile after all. + is_lazily_compiled = false; + } else { + end_pos = entry.end_pos(); + if (end_pos <= function_block_pos) { + // End position greater than end of stream is safe, and hard to check. + ReportInvalidPreparseData(function_name, CHECK_OK); + } + isolate()->counters()->total_preparse_skipped()->Increment( + end_pos - function_block_pos); + // Seek to position just before terminal '}'. + 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); } - isolate()->counters()->total_preparse_skipped()->Increment( - end_pos - function_block_pos); - // Seek to position just before terminal '}'. - scanner().SeekForward(end_pos - 1); - materialized_literal_count = entry.literal_count(); - expected_property_count = entry.property_count(); - only_simple_this_property_assignments = false; - this_property_assignments = isolate()->factory()->empty_fixed_array(); - Expect(Token::RBRACE, CHECK_OK); - } else { + } + + if (!is_lazily_compiled) { ParseSourceElements(body, Token::RBRACE, CHECK_OK); materialized_literal_count = lexical_scope.materialized_literal_count(); @@ -3657,7 +3794,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, // Validate strict mode. if (top_scope_->is_strict_mode()) { - if (IsEvalOrArguments(name)) { + if (IsEvalOrArguments(function_name)) { int position = function_token_position != RelocInfo::kNoPosition ? function_token_position : (start_pos > 0 ? start_pos - 1 : start_pos); @@ -3679,7 +3816,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, *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); @@ -3700,7 +3837,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, } FunctionLiteral* function_literal = - new(zone()) FunctionLiteral(name, + new(zone()) FunctionLiteral(isolate(), + function_name, scope, body, materialized_literal_count, @@ -3710,10 +3848,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, num_parameters, start_pos, end_pos, - (function_name->length() > 0)); + type, + has_duplicate_parameters); function_literal->set_function_token_position(function_token_position); - if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal); + if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); return function_literal; } @@ -3729,7 +3868,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { 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); @@ -3760,14 +3899,15 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { } // We have a valid intrinsics call or a call to a builtin. - return new(zone()) CallRuntime(name, function, args); + return new(zone()) CallRuntime(isolate(), name, function, args); } 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; } @@ -3805,7 +3945,7 @@ void Parser::ExpectSemicolon(bool* ok) { Next(); return; } - if (scanner().has_line_terminator_before_next() || + if (scanner().HasAnyLineTerminatorBeforeNext() || tok == Token::RBRACE || tok == Token::EOS) { return; @@ -3815,12 +3955,12 @@ void Parser::ExpectSemicolon(bool* ok) { Literal* Parser::GetLiteralUndefined() { - return new(zone()) Literal(isolate()->factory()->undefined_value()); + return NewLiteral(isolate()->factory()->undefined_value()); } Literal* Parser::GetLiteralTheHole() { - return new(zone()) Literal(isolate()->factory()->the_hole_value()); + return NewLiteral(isolate()->factory()->the_hole_value()); } @@ -3829,22 +3969,27 @@ Literal* Parser::GetLiteralNumber(double value) { } +// 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); @@ -3854,8 +3999,9 @@ Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved, 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>(); @@ -3896,12 +4042,12 @@ void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { } -// 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(); @@ -3970,7 +4116,7 @@ void Parser::RegisterTargetUse(Label* target, Target* stop) { Literal* Parser::NewNumberLiteral(double number) { - return new(zone()) Literal(isolate()->factory()->NewNumber(number, TENURED)); + return NewLiteral(isolate()->factory()->NewNumber(number, TENURED)); } @@ -4017,10 +4163,15 @@ Expression* Parser::NewThrowError(Handle<String> constructor, TENURED); ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2); - args->Add(new(zone()) Literal(type)); - args->Add(new(zone()) Literal(array)); - return new(zone()) Throw(new(zone()) CallRuntime(constructor, NULL, args), - scanner().location().beg_pos); + args->Add(NewLiteral(type)); + args->Add(NewLiteral(array)); + CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(), + constructor, + NULL, + args); + return new(zone()) Throw(isolate(), + call_constructor, + scanner().location().beg_pos); } // ---------------------------------------------------------------------------- @@ -4901,7 +5052,7 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, 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, @@ -4976,6 +5127,7 @@ bool ParserApi::Parse(CompilationInfo* info) { Parser parser(script, allow_natives_syntax, NULL, NULL); result = parser.ParseLazy(info); } else { + // Whether we allow %identifier(..) syntax. bool allow_natives_syntax = info->is_native() || FLAG_allow_natives_syntax; ScriptDataImpl* pre_data = info->pre_parse_data(); |
