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

Unified Diff: src/parser.cc

Issue 8404030: Version 3.7.1 (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 9 years, 2 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/preparser.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 9808)
+++ src/parser.cc (working copy)
@@ -407,9 +407,9 @@
}
-Scope* Parser::NewScope(Scope* parent, Scope::Type type, bool inside_with) {
+Scope* Parser::NewScope(Scope* parent, ScopeType type) {
Scope* result = new(zone()) Scope(parent, type);
- result->Initialize(inside_with);
+ result->Initialize();
return result;
}
@@ -459,14 +459,32 @@
// ----------------------------------------------------------------------------
-// LexicalScope is a support class to facilitate manipulation of the
-// Parser's scope stack. The constructor sets the parser's top scope
-// to the incoming scope, and the destructor resets it.
-//
-// Additionally, it stores transient information used during parsing.
-// These scopes are not kept around after parsing or referenced by syntax
-// trees so they can be stack-allocated and hence used by the pre-parser.
+// LexicalScope and SaveScope are stack allocated support classes to facilitate
+// anipulation of the Parser's scope stack. The constructor sets the parser's
+// top scope to the incoming scope, and the destructor resets it. Additionally,
+// LexicalScope stores transient information used during parsing.
+
+class SaveScope BASE_EMBEDDED {
+ public:
+ SaveScope(Parser* parser, Scope* scope)
+ : parser_(parser),
+ previous_top_scope_(parser->top_scope_) {
+ parser->top_scope_ = scope;
+ }
+
+ ~SaveScope() {
+ parser_->top_scope_ = previous_top_scope_;
+ }
+
+ private:
+ // Bookkeeping
+ Parser* parser_;
+ // Previous values
+ Scope* previous_top_scope_;
+};
+
+
class LexicalScope BASE_EMBEDDED {
public:
LexicalScope(Parser* parser, Scope* scope, Isolate* isolate);
@@ -516,7 +534,6 @@
// Previous values
LexicalScope* lexical_scope_parent_;
Scope* previous_scope_;
- int previous_with_nesting_level_;
unsigned previous_ast_node_id_;
};
@@ -529,11 +546,9 @@
parser_(parser),
lexical_scope_parent_(parser->lexical_scope_),
previous_scope_(parser->top_scope_),
- previous_with_nesting_level_(parser->with_nesting_level_),
previous_ast_node_id_(isolate->ast_node_id()) {
parser->top_scope_ = scope;
parser->lexical_scope_ = this;
- parser->with_nesting_level_ = 0;
isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
}
@@ -541,7 +556,6 @@
LexicalScope::~LexicalScope() {
parser_->top_scope_ = previous_scope_;
parser_->lexical_scope_ = lexical_scope_parent_;
- parser_->with_nesting_level_ = previous_with_nesting_level_;
parser_->isolate()->set_ast_node_id(previous_ast_node_id_);
}
@@ -578,7 +592,6 @@
script_(script),
scanner_(isolate_->unicode_cache()),
top_scope_(NULL),
- with_nesting_level_(0),
lexical_scope_(NULL),
target_stack_(NULL),
allow_natives_syntax_(allow_natives_syntax),
@@ -623,6 +636,7 @@
bool in_global_context,
StrictModeFlag strict_mode,
ZoneScope* zone_scope) {
+ ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize();
@@ -630,18 +644,16 @@
mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
- Scope::Type type =
- in_global_context
- ? Scope::GLOBAL_SCOPE
- : Scope::EVAL_SCOPE;
+ ScopeType type = in_global_context ? GLOBAL_SCOPE : EVAL_SCOPE;
Handle<String> no_name = isolate()->factory()->empty_symbol();
FunctionLiteral* result = NULL;
- { Scope* scope = NewScope(top_scope_, type, inside_with());
+ { Scope* scope = NewScope(top_scope_, type);
+ scope->set_start_position(0);
+ scope->set_end_position(source->length());
LexicalScope lexical_scope(this, scope, isolate());
- if (strict_mode == kStrictMode) {
- top_scope_->EnableStrictMode();
- }
+ ASSERT(top_scope_->strict_mode_flag() == kNonStrictMode);
+ top_scope_->SetStrictModeFlag(strict_mode);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
@@ -665,8 +677,6 @@
lexical_scope.only_simple_this_property_assignments(),
lexical_scope.this_property_assignments(),
0,
- 0,
- source->length(),
FunctionLiteral::ANONYMOUS_EXPRESSION,
false); // Does not have duplicate parameters.
} else if (stack_overflow_) {
@@ -714,6 +724,7 @@
ZoneScope* zone_scope) {
Handle<SharedFunctionInfo> shared_info = info->shared_info();
scanner_.Initialize(source);
+ ASSERT(top_scope_ == NULL);
ASSERT(target_stack_ == NULL);
Handle<String> name(String::cast(shared_info->name()));
@@ -727,16 +738,15 @@
{
// Parse the function literal.
- Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
+ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope);
}
LexicalScope lexical_scope(this, scope, isolate());
-
- if (shared_info->strict_mode()) {
- top_scope_->EnableStrictMode();
- }
-
+ ASSERT(scope->strict_mode_flag() == kNonStrictMode ||
+ scope->strict_mode_flag() == info->strict_mode_flag());
+ ASSERT(info->strict_mode_flag() == shared_info->strict_mode_flag());
+ scope->SetStrictModeFlag(shared_info->strict_mode_flag());
FunctionLiteral::Type type = shared_info->is_expression()
? (shared_info->is_anonymous()
? FunctionLiteral::ANONYMOUS_EXPRESSION
@@ -1128,14 +1138,14 @@
// In harmony mode we allow additionally the following productions
// SourceElement:
// LetDeclaration
+ // ConstDeclaration
if (peek() == Token::FUNCTION) {
return ParseFunctionDeclaration(ok);
- } else if (peek() == Token::LET) {
+ } else if (peek() == Token::LET || peek() == Token::CONST) {
return ParseVariableStatement(kSourceElement, ok);
- } else {
- return ParseStatement(labels, ok);
}
+ return ParseStatement(labels, ok);
}
@@ -1183,7 +1193,7 @@
directive->Equals(isolate()->heap()->use_strict()) &&
token_loc.end_pos - token_loc.beg_pos ==
isolate()->heap()->use_strict()->length() + 2) {
- top_scope_->EnableStrictMode();
+ top_scope_->SetStrictModeFlag(kStrictMode);
// "use strict" is the only directive for now.
directive_prologue = false;
}
@@ -1321,7 +1331,7 @@
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
- if (top_scope_->is_strict_mode()) {
+ if (top_scope_->is_strict_mode() || harmony_scoping_) {
ReportMessageAt(scanner().peek_location(), "strict_function",
Vector<const char*>::empty());
*ok = false;
@@ -1353,6 +1363,10 @@
// If we are inside a function, a declaration of a var/const variable is a
// truly local variable, and the scope of the variable is always the function
// scope.
+ // Let/const variables in harmony mode are always added to the immediately
+ // enclosing scope.
+ Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
+ ? top_scope_ : top_scope_->DeclarationScope();
// If a function scope exists, then we can statically declare this
// variable and also set its mode. In any case, a Declaration node
@@ -1362,9 +1376,8 @@
// 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.
-
- Scope* declaration_scope = mode == LET ? top_scope_
- : top_scope_->DeclarationScope();
+ // Also for block scoped let/const bindings the variable can be
+ // statically declared.
if (declaration_scope->is_function_scope() ||
declaration_scope->is_strict_mode_eval_scope() ||
declaration_scope->is_block_scope()) {
@@ -1389,6 +1402,7 @@
// We only have vars, consts and lets in declarations.
ASSERT(var->mode() == VAR ||
var->mode() == CONST ||
+ var->mode() == CONST_HARMONY ||
var->mode() == LET);
if (harmony_scoping_) {
// In harmony mode we treat re-declarations as early errors. See
@@ -1400,8 +1414,8 @@
*ok = false;
return NULL;
}
- const char* type = (var->mode() == VAR) ? "var" :
- (var->mode() == CONST) ? "const" : "let";
+ const char* type = (var->mode() == VAR)
+ ? "var" : var->is_const_mode() ? "const" : "let";
Handle<String> type_string =
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
Expression* expression =
@@ -1429,12 +1443,13 @@
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
VariableProxy* proxy = declaration_scope->NewUnresolved(
- name, false, scanner().location().beg_pos);
+ name, scanner().location().beg_pos);
declaration_scope->AddDeclaration(
new(zone()) Declaration(proxy, mode, fun, top_scope_));
// For global const variables we bind the proxy to a variable.
- if (mode == CONST && declaration_scope->is_global_scope()) {
+ if ((mode == CONST || mode == CONST_HARMONY) &&
+ declaration_scope->is_global_scope()) {
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
var = new(zone()) Variable(declaration_scope, name, CONST, true, kind);
@@ -1582,20 +1597,14 @@
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
- Scope* saved_scope = top_scope_;
- Scope* block_scope = NewScope(top_scope_,
- Scope::BLOCK_SCOPE,
- inside_with());
- if (top_scope_->is_strict_mode()) {
- block_scope->EnableStrictMode();
- }
- top_scope_ = block_scope;
+ Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
// Parse the statements and collect escaping labels.
- TargetCollector collector;
- Target target(&this->target_stack_, &collector);
Expect(Token::LBRACE, CHECK_OK);
- {
+ block_scope->set_start_position(scanner().location().beg_pos);
+ { SaveScope save_scope(this, block_scope);
+ TargetCollector collector;
+ Target target(&this->target_stack_, &collector);
Target target_body(&this->target_stack_, body);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
@@ -1608,8 +1617,7 @@
}
}
Expect(Token::RBRACE, CHECK_OK);
- top_scope_ = saved_scope;
-
+ block_scope->set_end_position(scanner().location().end_pos);
block_scope = block_scope->FinalizeBlockScope();
body->set_block_scope(block_scope);
return body;
@@ -1623,6 +1631,7 @@
Handle<String> ignore;
Block* result = ParseVariableDeclarations(var_context,
+ NULL,
&ignore,
CHECK_OK);
ExpectSemicolon(CHECK_OK);
@@ -1641,12 +1650,24 @@
// *var is untouched; in particular, it is the caller's responsibility
// to initialize it properly. This mechanism is used for the parsing
// of 'for-in' loops.
-Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
- Handle<String>* out,
- bool* ok) {
+Block* Parser::ParseVariableDeclarations(
+ VariableDeclarationContext var_context,
+ VariableDeclarationProperties* decl_props,
+ Handle<String>* out,
+ bool* ok) {
// VariableDeclarations ::
- // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
-
+ // ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
+ //
+ // The ES6 Draft Rev3 specifies the following grammar for const declarations
+ //
+ // ConstDeclaration ::
+ // const ConstBinding (',' ConstBinding)* ';'
+ // ConstBinding ::
+ // Identifier '=' AssignmentExpression
+ //
+ // TODO(ES6):
+ // ConstBinding ::
+ // BindingPattern '=' AssignmentExpression
VariableMode mode = VAR;
// True if the binding needs initialization. 'let' and 'const' declared
// bindings are created uninitialized by their declaration nodes and
@@ -1659,19 +1680,32 @@
Consume(Token::VAR);
} else if (peek() == Token::CONST) {
Consume(Token::CONST);
- if (top_scope_->is_strict_mode()) {
+ if (harmony_scoping_) {
+ if (var_context != kSourceElement &&
+ var_context != kForStatement) {
+ // In harmony mode 'const' declarations are only allowed in source
+ // element positions.
+ ReportMessage("unprotected_const", Vector<const char*>::empty());
+ *ok = false;
+ return NULL;
+ }
+ mode = CONST_HARMONY;
+ init_op = Token::INIT_CONST_HARMONY;
+ } else if (top_scope_->is_strict_mode()) {
ReportMessage("strict_const", Vector<const char*>::empty());
*ok = false;
return NULL;
+ } else {
+ mode = CONST;
+ init_op = Token::INIT_CONST;
}
- mode = CONST;
is_const = true;
needs_init = true;
- init_op = Token::INIT_CONST;
} else if (peek() == Token::LET) {
Consume(Token::LET);
if (var_context != kSourceElement &&
var_context != kForStatement) {
+ // Let declarations are only allowed in source element positions.
ASSERT(var_context == kStatement);
ReportMessage("unprotected_let", Vector<const char*>::empty());
*ok = false;
@@ -1684,7 +1718,7 @@
UNREACHABLE(); // by current callers
}
- Scope* declaration_scope = (mode == LET)
+ Scope* declaration_scope = (mode == LET || mode == CONST_HARMONY)
? top_scope_ : top_scope_->DeclarationScope();
// The scope of a var/const declared variable anywhere inside a function
// is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can
@@ -1729,8 +1763,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).
- Declare(name, mode, NULL, is_const /* always bound for CONST! */,
- CHECK_OK);
+ // For let/const declarations in harmony mode, we can also immediately
+ // pre-resolve the proxy because it resides in the same scope as the
+ // declaration.
+ Declare(name, mode, NULL, mode != VAR, CHECK_OK);
nvars++;
if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
ReportMessageAt(scanner().location(), "too_many_variables",
@@ -1769,7 +1805,8 @@
Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
Expression* value = NULL;
int position = -1;
- if (peek() == Token::ASSIGN) {
+ // Harmony consts have non-optional initializers.
+ if (peek() == Token::ASSIGN || mode == CONST_HARMONY) {
Expect(Token::ASSIGN, CHECK_OK);
position = scanner().location().beg_pos;
value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
@@ -1781,6 +1818,7 @@
} else {
fni_->RemoveLastFunction();
}
+ if (decl_props != NULL) *decl_props = kHasInitializers;
}
// Make sure that 'const x' and 'let x' initialize 'x' to undefined.
@@ -1807,7 +1845,6 @@
// declaration statement has been executed. This is important in
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
-
if (initialization_scope->is_global_scope()) {
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
@@ -1832,9 +1869,7 @@
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
- StrictModeFlag flag = initialization_scope->is_strict_mode()
- ? kStrictMode
- : kNonStrictMode;
+ StrictModeFlag flag = initialization_scope->strict_mode_flag();
arguments->Add(NewNumberLiteral(flag));
// Be careful not to assign a value to the global variable if
@@ -1871,18 +1906,14 @@
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
// the top context for var declared variables). Sigh...
- // For 'let' declared variables the initialization is in the same scope
- // as the declaration. Thus dynamic lookups are unnecessary even if the
- // block scope is inside a with.
+ // For 'let' and 'const' declared variables in harmony mode the
+ // initialization is in the same scope as the declaration. Thus dynamic
+ // lookups are unnecessary even if the block scope is inside a with.
if (value != NULL) {
- bool in_with = (mode == VAR) ? inside_with() : false;
- VariableProxy* proxy =
- initialization_scope->NewUnresolved(name, in_with);
+ VariableProxy* proxy = initialization_scope->NewUnresolved(name);
Assignment* assignment =
new(zone()) Assignment(isolate(), init_op, proxy, value, position);
- if (block) {
- block->AddStatement(new(zone()) ExpressionStatement(assignment));
- }
+ block->AddStatement(new(zone()) ExpressionStatement(assignment));
}
if (fni_ != NULL) fni_->Leave();
@@ -2105,10 +2136,14 @@
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- ++with_nesting_level_;
top_scope_->DeclarationScope()->RecordWithStatement();
- Statement* stmt = ParseStatement(labels, CHECK_OK);
- --with_nesting_level_;
+ Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
+ Statement* stmt;
+ { SaveScope save_scope(this, with_scope);
+ with_scope->set_start_position(scanner().peek_location().beg_pos);
+ stmt = ParseStatement(labels, CHECK_OK);
+ with_scope->set_end_position(scanner().location().end_pos);
+ }
return new(zone()) WithStatement(expr, stmt);
}
@@ -2233,6 +2268,8 @@
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
+ catch_scope = NewScope(top_scope_, CATCH_SCOPE);
+ catch_scope->set_start_position(scanner().location().beg_pos);
name = ParseIdentifier(CHECK_OK);
if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
@@ -2245,21 +2282,15 @@
if (peek() == Token::LBRACE) {
Target target(&this->target_stack_, &catch_collector);
- catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
- if (top_scope_->is_strict_mode()) {
- catch_scope->EnableStrictMode();
- }
VariableMode mode = harmony_scoping_ ? LET : VAR;
catch_variable = catch_scope->DeclareLocal(name, mode);
- Scope* saved_scope = top_scope_;
- top_scope_ = catch_scope;
+ SaveScope save_scope(this, catch_scope);
catch_block = ParseBlock(NULL, CHECK_OK);
- top_scope_ = saved_scope;
} else {
Expect(Token::LBRACE, CHECK_OK);
}
-
+ catch_scope->set_end_position(scanner().location().end_pos);
tok = peek();
}
@@ -2365,16 +2396,22 @@
Statement* init = NULL;
+ // Create an in-between scope for let-bound iteration variables.
+ Scope* saved_scope = top_scope_;
+ Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
+ top_scope_ = for_scope;
+
Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
+ for_scope->set_start_position(scanner().location().beg_pos);
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) {
Handle<String> name;
Block* variable_statement =
- ParseVariableDeclarations(kForStatement, &name, CHECK_OK);
+ ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) {
- VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
+ VariableProxy* each = top_scope_->NewUnresolved(name);
ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
@@ -2387,12 +2424,73 @@
Block* result = new(zone()) Block(isolate(), NULL, 2, false);
result->AddStatement(variable_statement);
result->AddStatement(loop);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ ASSERT(for_scope == NULL);
// Parsed for-in loop w/ variable/const declaration.
return result;
} else {
init = variable_statement;
}
+ } else if (peek() == Token::LET) {
+ Handle<String> name;
+ VariableDeclarationProperties decl_props = kHasNoInitializers;
+ Block* variable_statement =
+ ParseVariableDeclarations(kForStatement,
+ &decl_props,
+ &name,
+ CHECK_OK);
+ bool accept_IN = !name.is_null() && decl_props != kHasInitializers;
+ if (peek() == Token::IN && accept_IN) {
+ // Rewrite a for-in statement of the form
+ //
+ // for (let x in e) b
+ //
+ // into
+ //
+ // <let x' be a temporary variable>
+ // for (x' in e) {
+ // let x;
+ // x = x';
+ // b;
+ // }
+ // TODO(keuchel): Move the temporary variable to the block scope, after
+ // implementing stack allocated block scoped variables.
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
+ VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp);
+ 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);
+ Expression* enumerable = ParseExpression(true, CHECK_OK);
+ Expect(Token::RPAREN, CHECK_OK);
+
+ Statement* body = ParseStatement(NULL, CHECK_OK);
+ Block* body_block = new(zone()) Block(isolate(), NULL, 3, false);
+ Assignment* assignment = new(zone()) Assignment(isolate(),
+ Token::ASSIGN,
+ each,
+ temp_proxy,
+ RelocInfo::kNoPosition);
+ Statement* assignment_statement =
+ new(zone()) ExpressionStatement(assignment);
+ body_block->AddStatement(variable_statement);
+ body_block->AddStatement(assignment_statement);
+ body_block->AddStatement(body);
+ loop->Initialize(temp_proxy, enumerable, body_block);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ body_block->set_block_scope(for_scope);
+ // Parsed for-in loop w/ let declaration.
+ return loop;
+
+ } else {
+ init = variable_statement;
+ }
} else {
Expression* expression = ParseExpression(false, CHECK_OK);
if (peek() == Token::IN) {
@@ -2414,6 +2512,10 @@
Statement* body = ParseStatement(NULL, CHECK_OK);
if (loop) loop->Initialize(expression, enumerable, body);
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ ASSERT(for_scope == NULL);
// Parsed for-in loop.
return loop;
@@ -2444,8 +2546,31 @@
Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseStatement(NULL, CHECK_OK);
- if (loop) loop->Initialize(init, cond, next, body);
- return loop;
+ top_scope_ = saved_scope;
+ for_scope->set_end_position(scanner().location().end_pos);
+ for_scope = for_scope->FinalizeBlockScope();
+ if (for_scope != NULL) {
+ // Rewrite a for statement of the form
+ //
+ // for (let x = i; c; n) b
+ //
+ // into
+ //
+ // {
+ // let x = i;
+ // for (; c; n) b
+ // }
+ ASSERT(init != NULL);
+ Block* result = new(zone()) Block(isolate(), NULL, 2, false);
+ result->AddStatement(init);
+ result->AddStatement(loop);
+ result->set_block_scope(for_scope);
+ if (loop) loop->Initialize(NULL, cond, next, body);
+ return result;
+ } else {
+ if (loop) loop->Initialize(init, cond, next, body);
+ return loop;
+ }
}
@@ -3065,9 +3190,7 @@
case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
- result = top_scope_->NewUnresolved(name,
- inside_with(),
- scanner().location().beg_pos);
+ result = top_scope_->NewUnresolved(name, scanner().location().beg_pos);
break;
}
@@ -3184,9 +3307,11 @@
// Update the scope information before the pre-parsing bailout.
int literal_index = lexical_scope_->NextMaterializedLiteralIndex();
- // Allocate a fixed array with all the literals.
- Handle<FixedArray> literals =
+ // Allocate a fixed array to hold all the object literals.
+ Handle<FixedArray> object_literals =
isolate()->factory()->NewFixedArray(values->length(), TENURED);
+ Handle<FixedDoubleArray> double_literals;
+ ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
// Fill in the literals.
bool is_simple = true;
@@ -3198,19 +3323,75 @@
}
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
if (boilerplate_value->IsUndefined()) {
- literals->set_the_hole(i);
+ object_literals->set_the_hole(i);
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ double_literals->set_the_hole(i);
+ }
is_simple = false;
} else {
- literals->set(i, *boilerplate_value);
+ // Examine each literal element, and adjust the ElementsKind if the
+ // literal element is not of a type that can be stored in the current
+ // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
+ // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
+ // the tagged value, no matter what the ElementsKind is in case we
+ // ultimately end up in FAST_ELEMENTS.
+ object_literals->set(i, *boilerplate_value);
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+ // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
+ // FAST_ELEMENTS is required.
+ if (!boilerplate_value->IsSmi()) {
+ if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
+ // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
+ // avoid over-allocating in TENURED space.
+ double_literals = isolate()->factory()->NewFixedDoubleArray(
+ values->length(), TENURED);
+ // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
+ // FAST_DOUBLE_ELEMENTS array so that they are in sync.
+ for (int j = 0; j < i; ++j) {
+ Object* smi_value = object_literals->get(j);
+ if (smi_value->IsTheHole()) {
+ double_literals->set_the_hole(j);
+ } else {
+ double_literals->set(j, Smi::cast(smi_value)->value());
+ }
+ }
+ double_literals->set(i, boilerplate_value->Number());
+ elements_kind = FAST_DOUBLE_ELEMENTS;
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
+ }
+ } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+ // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
+ // until the first value is seen that can't be stored as a double.
+ if (boilerplate_value->IsNumber()) {
+ double_literals->set(i, boilerplate_value->Number());
+ } else {
+ elements_kind = FAST_ELEMENTS;
+ }
+ }
}
}
// Simple and shallow arrays can be lazily copied, we transform the
// elements array to a copy-on-write array.
- if (is_simple && depth == 1 && values->length() > 0) {
- literals->set_map(isolate()->heap()->fixed_cow_array_map());
+ if (is_simple && depth == 1 && values->length() > 0 &&
+ elements_kind != FAST_DOUBLE_ELEMENTS) {
+ object_literals->set_map(isolate()->heap()->fixed_cow_array_map());
}
+ Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
+ ? Handle<FixedArrayBase>(double_literals)
+ : Handle<FixedArrayBase>(object_literals);
+
+ // Remember both the literal's constant values as well as the ElementsKind
+ // in a 2-element FixedArray.
+ Handle<FixedArray> literals =
+ isolate()->factory()->NewFixedArray(2, TENURED);
+
+ literals->set(0, Smi::FromInt(elements_kind));
+ literals->set(1, *element_values);
+
return new(zone()) ArrayLiteral(
isolate(), literals, values, literal_index, is_simple, depth);
}
@@ -3715,13 +3896,11 @@
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
Scope* scope = (type == FunctionLiteral::DECLARATION && !harmony_scoping_)
- ? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
- : NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
+ ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
+ : NewScope(top_scope_, FUNCTION_SCOPE);
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
int materialized_literal_count;
int expected_property_count;
- int start_pos;
- int end_pos;
bool only_simple_this_property_assignments;
Handle<FixedArray> this_property_assignments;
bool has_duplicate_parameters = false;
@@ -3732,7 +3911,7 @@
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
- start_pos = scanner().location().beg_pos;
+ scope->set_start_position(scanner().location().beg_pos);
Scanner::Location name_loc = Scanner::Location::invalid();
Scanner::Location dupe_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid();
@@ -3778,13 +3957,21 @@
// future we can change the AST to only refer to VariableProxies
// instead of Variables and Proxis as is the case now.
if (type == FunctionLiteral::NAMED_EXPRESSION) {
- Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
- VariableProxy* fproxy =
- top_scope_->NewUnresolved(function_name, inside_with());
+ VariableMode fvar_mode;
+ Token::Value fvar_init_op;
+ if (harmony_scoping_) {
+ fvar_mode = CONST_HARMONY;
+ fvar_init_op = Token::INIT_CONST_HARMONY;
+ } else {
+ fvar_mode = CONST;
+ fvar_init_op = Token::INIT_CONST;
+ }
+ Variable* fvar = top_scope_->DeclareFunctionVar(function_name, fvar_mode);
+ VariableProxy* fproxy = top_scope_->NewUnresolved(function_name);
fproxy->BindTo(fvar);
body->Add(new(zone()) ExpressionStatement(
new(zone()) Assignment(isolate(),
- Token::INIT_CONST,
+ fvar_init_op,
fproxy,
new(zone()) ThisFunction(isolate()),
RelocInfo::kNoPosition)));
@@ -3808,18 +3995,18 @@
// compile after all.
is_lazily_compiled = false;
} else {
- end_pos = entry.end_pos();
- if (end_pos <= function_block_pos) {
+ scope->set_end_position(entry.end_pos());
+ if (scope->end_position() <= 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);
+ scope->end_position() - function_block_pos);
// Seek to position just before terminal '}'.
- scanner().SeekForward(end_pos - 1);
+ scanner().SeekForward(scope->end_position() - 1);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
- if (entry.strict_mode()) top_scope_->EnableStrictMode();
+ if (entry.strict_mode()) top_scope_->SetStrictModeFlag(kStrictMode);
only_simple_this_property_assignments = false;
this_property_assignments = isolate()->factory()->empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK);
@@ -3836,12 +4023,13 @@
this_property_assignments = lexical_scope.this_property_assignments();
Expect(Token::RBRACE, CHECK_OK);
- end_pos = scanner().location().end_pos;
+ scope->set_end_position(scanner().location().end_pos);
}
// Validate strict mode.
if (top_scope_->is_strict_mode()) {
if (IsEvalOrArguments(function_name)) {
+ int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3864,6 +4052,7 @@
return NULL;
}
if (name_is_strict_reserved) {
+ int start_pos = scope->start_position();
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3879,7 +4068,9 @@
*ok = false;
return NULL;
}
- CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
+ CheckOctalLiteral(scope->start_position(),
+ scope->end_position(),
+ CHECK_OK);
}
}
@@ -3897,8 +4088,6 @@
only_simple_this_property_assignments,
this_property_assignments,
num_parameters,
- start_pos,
- end_pos,
type,
has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
@@ -5119,17 +5308,16 @@
// Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
- bool allow_lazy,
- ParserRecorder* recorder,
- bool harmony_scoping) {
+ int flags,
+ ParserRecorder* recorder) {
Isolate* isolate = Isolate::Current();
JavaScriptScanner scanner(isolate->unicode_cache());
- scanner.SetHarmonyScoping(harmony_scoping);
+ scanner.SetHarmonyScoping((flags & kHarmonyScoping) != 0);
scanner.Initialize(source);
intptr_t stack_limit = isolate->stack_guard()->real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner,
recorder,
- allow_lazy,
+ flags,
stack_limit)) {
isolate->StackOverflow();
return NULL;
@@ -5146,25 +5334,28 @@
// even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping) {
+ int flags) {
bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) {
// Partial preparsing is only about lazily compiled functions.
// If we don't allow lazy compilation, the log data will be empty.
return NULL;
}
+ flags |= kAllowLazy;
PartialParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder, harmony_scoping);
+ return DoPreParse(source, flags, &recorder);
}
ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
v8::Extension* extension,
- bool harmony_scoping) {
+ int flags) {
Handle<Script> no_script;
- bool allow_lazy = FLAG_lazy && (extension == NULL);
+ if (FLAG_lazy && (extension == NULL)) {
+ flags |= kAllowLazy;
+ }
CompleteParserRecorder recorder;
- return DoPreParse(source, allow_lazy, &recorder, harmony_scoping);
+ return DoPreParse(source, flags, &recorder);
}
@@ -5227,7 +5418,7 @@
Handle<String> source = Handle<String>(String::cast(script->source()));
result = parser.ParseProgram(source,
info->is_global(),
- info->StrictMode());
+ info->strict_mode_flag());
}
}
info->SetFunction(result);
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698