diff options
Diffstat (limited to 'src/3rdparty/v8/src/parser.cc')
-rw-r--r-- | src/3rdparty/v8/src/parser.cc | 809 |
1 files changed, 390 insertions, 419 deletions
diff --git a/src/3rdparty/v8/src/parser.cc b/src/3rdparty/v8/src/parser.cc index b26a9f9..da4685f 100644 --- a/src/3rdparty/v8/src/parser.cc +++ b/src/3rdparty/v8/src/parser.cc @@ -86,8 +86,8 @@ class PositionStack { }; -RegExpBuilder::RegExpBuilder() - : zone_(Isolate::Current()->zone()), +RegExpBuilder::RegExpBuilder(Zone* zone) + : zone_(zone), pending_empty_(false), characters_(NULL), terms_(), @@ -103,7 +103,7 @@ void RegExpBuilder::FlushCharacters() { if (characters_ != NULL) { RegExpTree* atom = new(zone()) RegExpAtom(characters_->ToConstVector()); characters_ = NULL; - text_.Add(atom); + text_.Add(atom, zone()); LAST(ADD_ATOM); } } @@ -115,12 +115,12 @@ void RegExpBuilder::FlushText() { if (num_text == 0) { return; } else if (num_text == 1) { - terms_.Add(text_.last()); + terms_.Add(text_.last(), zone()); } else { - RegExpText* text = new(zone()) RegExpText(); + RegExpText* text = new(zone()) RegExpText(zone()); for (int i = 0; i < num_text; i++) - text_.Get(i)->AppendToText(text); - terms_.Add(text); + text_.Get(i)->AppendToText(text, zone()); + terms_.Add(text, zone()); } text_.Clear(); } @@ -129,9 +129,9 @@ void RegExpBuilder::FlushText() { void RegExpBuilder::AddCharacter(uc16 c) { pending_empty_ = false; if (characters_ == NULL) { - characters_ = new(zone()) ZoneList<uc16>(4); + characters_ = new(zone()) ZoneList<uc16>(4, zone()); } - characters_->Add(c); + characters_->Add(c, zone()); LAST(ADD_CHAR); } @@ -148,10 +148,10 @@ void RegExpBuilder::AddAtom(RegExpTree* term) { } if (term->IsTextElement()) { FlushCharacters(); - text_.Add(term); + text_.Add(term, zone()); } else { FlushText(); - terms_.Add(term); + terms_.Add(term, zone()); } LAST(ADD_ATOM); } @@ -159,7 +159,7 @@ void RegExpBuilder::AddAtom(RegExpTree* term) { void RegExpBuilder::AddAssertion(RegExpTree* assert) { FlushText(); - terms_.Add(assert); + terms_.Add(assert, zone()); LAST(ADD_ASSERT); } @@ -178,9 +178,9 @@ void RegExpBuilder::FlushTerms() { } else if (num_terms == 1) { alternative = terms_.last(); } else { - alternative = new(zone()) RegExpAlternative(terms_.GetList()); + alternative = new(zone()) RegExpAlternative(terms_.GetList(zone())); } - alternatives_.Add(alternative); + alternatives_.Add(alternative, zone()); terms_.Clear(); LAST(ADD_NONE); } @@ -195,7 +195,7 @@ RegExpTree* RegExpBuilder::ToRegExp() { if (num_alternatives == 1) { return alternatives_.last(); } - return new(zone()) RegExpDisjunction(alternatives_.GetList()); + return new(zone()) RegExpDisjunction(alternatives_.GetList(zone())); } @@ -214,7 +214,7 @@ void RegExpBuilder::AddQuantifierToAtom(int min, int num_chars = char_vector.length(); if (num_chars > 1) { Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1); - text_.Add(new(zone()) RegExpAtom(prefix)); + text_.Add(new(zone()) RegExpAtom(prefix), zone()); char_vector = char_vector.SubVector(num_chars - 1, num_chars); } characters_ = NULL; @@ -233,7 +233,7 @@ void RegExpBuilder::AddQuantifierToAtom(int min, if (min == 0) { return; } - terms_.Add(atom); + terms_.Add(atom, zone()); return; } } else { @@ -241,7 +241,7 @@ void RegExpBuilder::AddQuantifierToAtom(int min, UNREACHABLE(); return; } - terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom)); + terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom), zone()); LAST(ADD_TERM); } @@ -270,7 +270,7 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id) { if (symbol_cache_.length() <= symbol_id) { // Increase length to index + 1. symbol_cache_.AddBlock(Handle<String>::null(), - symbol_id + 1 - symbol_cache_.length()); + symbol_id + 1 - symbol_cache_.length(), zone()); } Handle<String> result = symbol_cache_.at(symbol_id); if (result.is_null()) { @@ -408,7 +408,7 @@ unsigned* ScriptDataImpl::ReadAddress(int position) { Scope* Parser::NewScope(Scope* parent, ScopeType type) { - Scope* result = new(zone()) Scope(parent, type); + Scope* result = new(zone()) Scope(parent, type, zone()); result->Initialize(); return result; } @@ -493,10 +493,10 @@ Parser::FunctionState::FunctionState(Parser* parser, outer_function_state_(parser->current_function_state_), outer_scope_(parser->top_scope_), saved_ast_node_id_(isolate->ast_node_id()), - factory_(isolate) { + factory_(isolate, parser->zone()) { parser->top_scope_ = scope; parser->current_function_state_ = this; - isolate->set_ast_node_id(AstNode::kDeclarationsId + 1); + isolate->set_ast_node_id(BailoutId::FirstUsable().ToInt()); } @@ -532,13 +532,13 @@ Parser::FunctionState::~FunctionState() { // ---------------------------------------------------------------------------- // Implementation of Parser -Parser::Parser(Handle<Script> script, +Parser::Parser(CompilationInfo* info, int parser_flags, v8::Extension* extension, ScriptDataImpl* pre_data) - : isolate_(script->GetIsolate()), - symbol_cache_(pre_data ? pre_data->symbol_count() : 0), - script_(script), + : isolate_(info->isolate()), + symbol_cache_(pre_data ? pre_data->symbol_count() : 0, info->zone()), + script_(info->script()), scanner_(isolate_->unicode_cache()), reusable_preparser_(NULL), top_scope_(NULL), @@ -551,7 +551,10 @@ Parser::Parser(Handle<Script> script, allow_lazy_((parser_flags & kAllowLazy) != 0), allow_modules_((parser_flags & kAllowModules) != 0), stack_overflow_(false), - parenthesized_function_(false) { + parenthesized_function_(false), + zone_(info->zone()), + info_(info) { + ASSERT(!script_.is_null()); isolate_->set_ast_node_id(0); if ((parser_flags & kLanguageModeMask) == EXTENDED_MODE) { scanner().SetHarmonyScoping(true); @@ -562,16 +565,17 @@ Parser::Parser(Handle<Script> script, } -FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { - ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT); - +FunctionLiteral* Parser::ParseProgram() { + ZoneScope zone_scope(zone(), DONT_DELETE_ON_EXIT); HistogramTimerScope timer(isolate()->counters()->parse()); Handle<String> source(String::cast(script_->source())); isolate()->counters()->total_parse_size()->Increment(source->length()); - fni_ = new(zone()) FuncNameInferrer(isolate()); + int64_t start = FLAG_trace_parse ? OS::Ticks() : 0; + fni_ = new(zone()) FuncNameInferrer(isolate(), zone()); // Initialize parser state. source->TryFlatten(); + FunctionLiteral* result; if (source->IsExternalTwoByteString()) { // Notice that the stream is destroyed at the end of the branch block. // The last line of the blocks can't be moved outside, even though they're @@ -579,12 +583,27 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { ExternalTwoByteStringUtf16CharacterStream stream( Handle<ExternalTwoByteString>::cast(source), 0, source->length()); scanner_.Initialize(&stream); - return DoParseProgram(info, source, &zone_scope); + result = DoParseProgram(info(), source, &zone_scope); } else { GenericStringUtf16CharacterStream stream(source, 0, source->length()); scanner_.Initialize(&stream); - return DoParseProgram(info, source, &zone_scope); + result = DoParseProgram(info(), source, &zone_scope); + } + + if (FLAG_trace_parse && result != NULL) { + double ms = static_cast<double>(OS::Ticks() - start) / 1000; + if (info()->is_eval()) { + PrintF("[parsing eval"); + } else if (info()->script()->name()->IsString()) { + String* name = String::cast(info()->script()->name()); + SmartArrayPointer<char> name_chars = name->ToCString(); + PrintF("[parsing script: %s", *name_chars); + } else { + PrintF("[parsing script"); + } + PrintF(" - took %0.3f ms]\n", ms); } + return result; } @@ -596,34 +615,37 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, if (pre_data_ != NULL) pre_data_->Initialize(); // Compute the parsing mode. - mode_ = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY; - if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY; + Mode mode = (FLAG_lazy && allow_lazy_) ? PARSE_LAZILY : PARSE_EAGERLY; + if (allow_natives_syntax_ || extension_ != NULL) mode = PARSE_EAGERLY; + ParsingModeScope parsing_mode(this, mode); Handle<String> no_name = isolate()->factory()->empty_symbol(); FunctionLiteral* result = NULL; { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE); info->SetGlobalScope(scope); + if (!info->context().is_null()) { + scope = Scope::DeserializeScopeChain(*info->context(), scope, zone()); + } if (info->is_eval()) { - Handle<SharedFunctionInfo> shared = info->shared_info(); - if (!info->is_global() && (shared.is_null() || shared->is_function())) { - scope = Scope::DeserializeScopeChain(*info->calling_context(), scope); - } if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) { scope = NewScope(scope, EVAL_SCOPE); } + } else if (info->is_global()) { + scope = NewScope(scope, GLOBAL_SCOPE); } scope->set_start_position(0); scope->set_end_position(source->length()); - FunctionState function_state(this, scope, isolate()); + + FunctionState function_state(this, scope, isolate()); // Enters 'scope'. top_scope_->SetLanguageMode(info->language_mode()); if (info->is_qml_mode()) { scope->EnableQmlModeFlag(); } - ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16); + ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; int beg_loc = scanner().location().beg_pos; - ParseSourceElements(body, Token::EOS, info->is_eval(), &ok); + ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok); if (ok && !top_scope_->is_classic_mode()) { CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); } @@ -645,7 +667,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, 0, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, - FunctionLiteral::kGlobalOrEval); + FunctionLiteral::kGlobalOrEval, + FunctionLiteral::kNotParenthesized); result->set_ast_properties(factory()->visitor()->ast_properties()); } else if (stack_overflow_) { isolate()->StackOverflow(); @@ -662,45 +685,51 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, } -FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { - ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT); +FunctionLiteral* Parser::ParseLazy() { + ZoneScope zone_scope(zone(), 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()); + int64_t start = FLAG_trace_parse ? OS::Ticks() : 0; + Handle<SharedFunctionInfo> shared_info = info()->shared_info(); - Handle<SharedFunctionInfo> shared_info = info->shared_info(); // Initialize parser state. source->TryFlatten(); + FunctionLiteral* result; if (source->IsExternalTwoByteString()) { ExternalTwoByteStringUtf16CharacterStream stream( Handle<ExternalTwoByteString>::cast(source), shared_info->start_position(), shared_info->end_position()); - FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope); - return result; + result = ParseLazy(&stream, &zone_scope); } else { GenericStringUtf16CharacterStream stream(source, shared_info->start_position(), shared_info->end_position()); - FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope); - return result; + result = ParseLazy(&stream, &zone_scope); } + + if (FLAG_trace_parse && result != NULL) { + double ms = static_cast<double>(OS::Ticks() - start) / 1000; + SmartArrayPointer<char> name_chars = result->debug_name()->ToCString(); + PrintF("[parsing function: %s - took %0.3f ms]\n", *name_chars, ms); + } + return result; } -FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, - Utf16CharacterStream* source, +FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source, ZoneScope* zone_scope) { - Handle<SharedFunctionInfo> shared_info = info->shared_info(); + 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())); - fni_ = new(zone()) FuncNameInferrer(isolate()); + fni_ = new(zone()) FuncNameInferrer(isolate(), zone()); fni_->PushEnclosingName(name); - mode_ = PARSE_EAGERLY; + ParsingModeScope parsing_mode(this, PARSE_EAGERLY); // Place holder for the result. FunctionLiteral* result = NULL; @@ -708,15 +737,16 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, { // Parse the function literal. Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE); - info->SetGlobalScope(scope); - if (!info->closure().is_null()) { - scope = Scope::DeserializeScopeChain(info->closure()->context(), scope); + info()->SetGlobalScope(scope); + if (!info()->closure().is_null()) { + scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope, + zone()); } FunctionState function_state(this, scope, isolate()); - ASSERT(scope->language_mode() != STRICT_MODE || !info->is_classic_mode()); + ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode()); ASSERT(scope->language_mode() != EXTENDED_MODE || - info->is_extended_mode()); - ASSERT(info->language_mode() == shared_info->language_mode()); + info()->is_extended_mode()); + ASSERT(info()->language_mode() == shared_info->language_mode()); scope->SetLanguageMode(shared_info->language_mode()); if (shared_info->qml_mode()) { top_scope_->EnableQmlModeFlag(); @@ -808,152 +838,25 @@ void Parser::ReportMessageAt(Scanner::Location source_location, } -// Base class containing common code for the different finder classes used by -// the parser. -class ParserFinder { - protected: - ParserFinder() {} - static Assignment* AsAssignment(Statement* stat) { - if (stat == NULL) return NULL; - ExpressionStatement* exp_stat = stat->AsExpressionStatement(); - if (exp_stat == NULL) return NULL; - return exp_stat->expression()->AsAssignment(); - } -}; - - -// An InitializationBlockFinder finds and marks sequences of statements of the -// form expr.a = ...; expr.b = ...; etc. -class InitializationBlockFinder : public ParserFinder { - public: - // 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)) { - UpdateBlock(assignment); - } else { - EndBlock(); - } - } - if (!InBlock() && (assignment != NULL) && - (assignment->op() == Token::ASSIGN)) { - StartBlock(assignment); - } - } - - private: - // The minimum number of contiguous assignment that will - // be treated as an initialization block. Benchmarks show that - // 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"]. - static bool SameObject(Expression* e1, Expression* e2) { - VariableProxy* v1 = e1->AsVariableProxy(); - VariableProxy* v2 = e2->AsVariableProxy(); - if (v1 != NULL && v2 != NULL) { - return v1->name()->Equals(*v2->name()); - } - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - Literal* key1 = p1->key()->AsLiteral(); - Literal* key2 = p2->key()->AsLiteral(); - if ((key1 == NULL) || (key2 == NULL)) return false; - if (!key1->handle()->IsString() || !key2->handle()->IsString()) { - return false; - } - String* name1 = String::cast(*key1->handle()); - String* name2 = String::cast(*key2->handle()); - if (!name1->Equals(name2)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - // Returns true if the expressions appear to denote different properties - // of the same object. - static bool PropertyOfSameObject(Expression* e1, Expression* e2) { - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - bool BlockContinues(Assignment* assignment) { - if ((assignment == NULL) || (first_in_block_ == NULL)) return false; - if (assignment->op() != Token::ASSIGN) return false; - return PropertyOfSameObject(first_in_block_->target(), - assignment->target()); - } - - void StartBlock(Assignment* assignment) { - first_in_block_ = assignment; - last_in_block_ = assignment; - block_size_ = 1; - } - - void UpdateBlock(Assignment* assignment) { - last_in_block_ = assignment; - ++block_size_; - } - - void EndBlock() { - if (block_size_ >= kMinInitializationBlock) { - first_in_block_->mark_block_start(); - last_in_block_->mark_block_end(); - } - last_in_block_ = first_in_block_ = NULL; - block_size_ = 0; - } - - bool InBlock() { return first_in_block_ != NULL; } - - const bool enabled_; - Assignment* first_in_block_; - Assignment* last_in_block_; - int block_size_; - - DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder); -}; - - // 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 ThisNamedPropertyAssignmentFinder : public ParserFinder { +class ThisNamedPropertyAssignmentFinder { public: - explicit ThisNamedPropertyAssignmentFinder(Isolate* isolate) + ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) : isolate_(isolate), only_simple_this_property_assignments_(true), - names_(0), - assigned_arguments_(0), - assigned_constants_(0) { + names_(0, zone), + assigned_arguments_(0, zone), + assigned_constants_(0, zone), + zone_(zone) { + } + + static Assignment* AsAssignment(Statement* stat) { + if (stat == NULL) return NULL; + ExpressionStatement* exp_stat = stat->AsExpressionStatement(); + if (exp_stat == NULL) return NULL; + return exp_stat->expression()->AsAssignment(); } void Update(Scope* scope, Statement* stat) { @@ -1062,9 +965,9 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { return; } } - names_.Add(name); - assigned_arguments_.Add(index); - assigned_constants_.Add(isolate_->factory()->undefined_value()); + names_.Add(name, zone()); + assigned_arguments_.Add(index, zone()); + assigned_constants_.Add(isolate_->factory()->undefined_value(), zone()); } void AssignmentFromConstant(Handle<String> name, Handle<Object> value) { @@ -1076,9 +979,9 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { return; } } - names_.Add(name); - assigned_arguments_.Add(-1); - assigned_constants_.Add(value); + names_.Add(name, zone()); + assigned_arguments_.Add(-1, zone()); + assigned_constants_.Add(value, zone()); } void AssignmentFromSomethingElse() { @@ -1090,23 +993,27 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder { 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); + names_.Initialize(4, zone()); + assigned_arguments_.Initialize(4, zone()); + assigned_constants_.Initialize(4, zone()); } } + Zone* zone() const { return zone_; } + Isolate* isolate_; bool only_simple_this_property_assignments_; ZoneStringList names_; ZoneList<int> assigned_arguments_; ZoneObjectList assigned_constants_; + Zone* zone_; }; void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, int end_token, bool is_eval, + bool is_global, bool* ok) { // SourceElements :: // (ModuleElement)* <end_token> @@ -1118,8 +1025,8 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, TargetScope scope(&this->target_stack_); ASSERT(processor != NULL); - InitializationBlockFinder block_finder(top_scope_, target_stack_); - ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate()); + ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), + zone()); bool directive_prologue = true; // Parsing directive prologue. while (peek() != end_token) { @@ -1128,7 +1035,12 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } Scanner::Location token_loc = scanner().peek_location(); - Statement* stat = ParseModuleElement(NULL, CHECK_OK); + Statement* stat; + if (is_global && !is_eval) { + stat = ParseModuleElement(NULL, CHECK_OK); + } else { + stat = ParseBlockElement(NULL, CHECK_OK); + } if (stat == NULL || stat->IsEmpty()) { directive_prologue = false; // End of directive prologue. continue; @@ -1172,12 +1084,11 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } } - 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); } - processor->Add(stat); + processor->Add(stat, zone()); } // Propagate the collected information on this property assignments. @@ -1243,12 +1154,10 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels, } -Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { +Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { // ModuleDeclaration: // 'module' Identifier Module - // Create new block with one expected declaration. - Block* block = factory()->NewBlock(NULL, 1, true); Handle<String> name = ParseIdentifier(CHECK_OK); #ifdef DEBUG @@ -1272,10 +1181,11 @@ Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) { } #endif - // TODO(rossberg): Add initialization statement to block. - - if (names) names->Add(name); - return block; + if (names) names->Add(name, zone()); + if (module->body() == NULL) + return factory()->NewEmptyStatement(); + else + return module->body(); } @@ -1323,16 +1233,14 @@ Module* Parser::ParseModuleLiteral(bool* ok) { { BlockState block_state(this, scope); - TargetCollector collector; + TargetCollector collector(zone()); Target target(&this->target_stack_, &collector); Target target_body(&this->target_stack_, body); - InitializationBlockFinder block_finder(top_scope_, target_stack_); while (peek() != Token::RBRACE) { Statement* stat = ParseModuleElement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) { - body->AddStatement(stat); - block_finder.Update(stat); + body->AddStatement(stat, zone()); } } } @@ -1341,16 +1249,23 @@ Module* Parser::ParseModuleLiteral(bool* ok) { scope->set_end_position(scanner().location().end_pos); body->set_scope(scope); - // Instance objects have to be created ahead of time (before code generation - // linking them) because of potentially cyclic references between them. - // We create them here, to avoid another pass over the AST. + // Check that all exports are bound. Interface* interface = scope->interface(); + for (Interface::Iterator it = interface->iterator(); + !it.done(); it.Advance()) { + if (scope->LocalLookup(it.name()) == NULL) { + Handle<String> name(it.name()); + ReportMessage("module_export_undefined", + Vector<Handle<String> >(&name, 1)); + *ok = false; + return NULL; + } + } + interface->MakeModule(ok); - ASSERT(ok); - interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok); - ASSERT(ok); + ASSERT(*ok); interface->Freeze(ok); - ASSERT(ok); + ASSERT(*ok); return factory()->NewModuleLiteral(body, interface); } @@ -1368,7 +1283,7 @@ Module* Parser::ParseModulePath(bool* ok) { PrintF("# Path .%s ", name->ToAsciiArray()); #endif Module* member = factory()->NewModulePath(result, name); - result->interface()->Add(name, member->interface(), ok); + result->interface()->Add(name, member->interface(), zone(), ok); if (!*ok) { #ifdef DEBUG if (FLAG_print_interfaces) { @@ -1399,7 +1314,8 @@ Module* Parser::ParseModuleVariable(bool* ok) { PrintF("# Module variable %s ", name->ToAsciiArray()); #endif VariableProxy* proxy = top_scope_->NewUnresolved( - factory(), name, scanner().location().beg_pos, Interface::NewModule()); + factory(), name, Interface::NewModule(zone()), + scanner().location().beg_pos); return factory()->NewModuleVariable(proxy); } @@ -1420,10 +1336,12 @@ Module* Parser::ParseModuleUrl(bool* ok) { Module* result = factory()->NewModuleUrl(symbol); Interface* interface = result->interface(); - interface->MakeSingleton(Isolate::Current()->factory()->NewJSModule(), ok); - ASSERT(ok); interface->Freeze(ok); - ASSERT(ok); + ASSERT(*ok); + // Create dummy scope to avoid errors as long as the feature isn't finished. + Scope* scope = NewScope(top_scope_, MODULE_SCOPE); + interface->Unify(scope->interface(), zone(), ok); + ASSERT(*ok); return result; } @@ -1448,14 +1366,14 @@ Block* Parser::ParseImportDeclaration(bool* ok) { // TODO(ES6): implement destructuring ImportSpecifiers Expect(Token::IMPORT, CHECK_OK); - ZoneStringList names(1); + ZoneStringList names(1, zone()); Handle<String> name = ParseIdentifierName(CHECK_OK); - names.Add(name); + names.Add(name, zone()); while (peek() == Token::COMMA) { Consume(Token::COMMA); name = ParseIdentifierName(CHECK_OK); - names.Add(name); + names.Add(name, zone()); } ExpectContextualKeyword("from", CHECK_OK); @@ -1470,8 +1388,8 @@ Block* Parser::ParseImportDeclaration(bool* ok) { if (FLAG_print_interface_details) PrintF("# Import %s ", names[i]->ToAsciiArray()); #endif - Interface* interface = Interface::NewUnknown(); - module->interface()->Add(names[i], interface, ok); + Interface* interface = Interface::NewUnknown(zone()); + module->interface()->Add(names[i], interface, zone(), ok); if (!*ok) { #ifdef DEBUG if (FLAG_print_interfaces) { @@ -1487,7 +1405,6 @@ Block* Parser::ParseImportDeclaration(bool* ok) { Declaration* declaration = factory()->NewImportDeclaration(proxy, module, top_scope_); Declare(declaration, true, CHECK_OK); - // TODO(rossberg): Add initialization statement to block. } return block; @@ -1506,17 +1423,17 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { Expect(Token::EXPORT, CHECK_OK); Statement* result = NULL; - ZoneStringList names(1); + ZoneStringList names(1, zone()); switch (peek()) { case Token::IDENTIFIER: { Handle<String> name = ParseIdentifier(CHECK_OK); // Handle 'module' as a context-sensitive keyword. if (!name->IsEqualTo(CStrVector("module"))) { - names.Add(name); + names.Add(name, zone()); while (peek() == Token::COMMA) { Consume(Token::COMMA); name = ParseIdentifier(CHECK_OK); - names.Add(name); + names.Add(name, zone()); } ExpectSemicolon(CHECK_OK); result = factory()->NewEmptyStatement(); @@ -1549,8 +1466,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { if (FLAG_print_interface_details) PrintF("# Export %s ", names[i]->ToAsciiArray()); #endif - Interface* inner = Interface::NewUnknown(); - interface->Add(names[i], inner, CHECK_OK); + Interface* inner = Interface::NewUnknown(zone()); + interface->Add(names[i], inner, zone(), CHECK_OK); + if (!*ok) + return NULL; VariableProxy* proxy = NewUnresolved(names[i], LET, inner); USE(proxy); // TODO(rossberg): Rethink whether we actually need to store export @@ -1683,7 +1602,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { if (statement) { statement->set_statement_pos(statement_pos); } - if (result) result->AddStatement(statement); + if (result) result->AddStatement(statement, zone()); return result; } @@ -1726,7 +1645,7 @@ VariableProxy* Parser::NewUnresolved( // Let/const variables in harmony mode are always added to the immediately // enclosing scope. return DeclarationScope(mode)->NewUnresolved( - factory(), name, scanner().location().beg_pos, interface); + factory(), name, interface, scanner().location().beg_pos); } @@ -1737,7 +1656,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { Scope* declaration_scope = DeclarationScope(mode); Variable* var = NULL; - // If a function scope exists, then we can statically declare this + // If a suitable scope exists, then we can statically declare this // variable and also set its mode. In any case, a Declaration node // will be added to the scope so that the declaration can be added // to the corresponding activation frame at runtime if necessary. @@ -1745,56 +1664,58 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // 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. - // Also for block scoped let/const bindings the variable can be - // statically declared. if (declaration_scope->is_function_scope() || declaration_scope->is_strict_or_extended_eval_scope() || declaration_scope->is_block_scope() || declaration_scope->is_module_scope() || - declaration->AsModuleDeclaration() != NULL) { - // Declare the variable in the function scope. - var = declaration_scope->LocalLookup(name); + declaration_scope->is_global_scope()) { + // Declare the variable in the declaration scope. + // For the global scope, we have to check for collisions with earlier + // (i.e., enclosing) global scopes, to maintain the illusion of a single + // global scope. + var = declaration_scope->is_global_scope() + ? declaration_scope->Lookup(name) + : declaration_scope->LocalLookup(name); if (var == NULL) { // Declare the name. var = declaration_scope->DeclareLocal( name, mode, declaration->initialization(), proxy->interface()); - } else { + } else if ((mode != VAR || var->mode() != VAR) && + (!declaration_scope->is_global_scope() || + IsLexicalVariableMode(mode) || + IsLexicalVariableMode(var->mode()))) { // The name was declared in this scope before; check for conflicting // re-declarations. We have a conflict if either of the declarations is - // not a var. There is similar code in runtime.cc in the Declare + // not a var (in the global scope, we also have to ignore legacy const for + // compatibility). There is similar code in runtime.cc in the Declare // functions. The function CheckNonConflictingScope checks for conflicting // var and let bindings from different scopes whereas this is a check for // conflicting declarations within the same scope. This check also covers + // the special case // // function () { let x; { var x; } } // // because the var declaration is hoisted to the function scope where 'x' // is already bound. - if ((mode != VAR) || (var->mode() != VAR)) { - // We only have vars, consts and lets in declarations. - ASSERT(var->mode() == VAR || - var->mode() == CONST || - var->mode() == CONST_HARMONY || - var->mode() == LET); - if (is_extended_mode()) { - // In harmony mode we treat re-declarations as early errors. See - // ES5 16 for a definition of early errors. - SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS); - const char* elms[2] = { "Variable", *c_string }; - Vector<const char*> args(elms, 2); - ReportMessage("redeclaration", args); - *ok = false; - return; - } - 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 = - NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), - type_string, name); - declaration_scope->SetIllegalRedeclaration(expression); + ASSERT(IsDeclaredVariableMode(var->mode())); + if (is_extended_mode()) { + // In harmony mode we treat re-declarations as early errors. See + // ES5 16 for a definition of early errors. + SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS); + const char* elms[2] = { "Variable", *c_string }; + Vector<const char*> args(elms, 2); + ReportMessage("redeclaration", args); + *ok = false; + return; } + 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 = + NewThrowTypeError(isolate()->factory()->redeclaration_symbol(), + type_string, name); + declaration_scope->SetIllegalRedeclaration(expression); } } @@ -1816,8 +1737,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // Runtime::DeclareContextSlot() calls. declaration_scope->AddDeclaration(declaration); - if ((mode == CONST || mode == CONST_HARMONY) && - declaration_scope->is_global_scope()) { + if (mode == CONST && declaration_scope->is_global_scope()) { // For global const variables we bind the proxy to a variable. ASSERT(resolve); // should be set by all callers Variable::Kind kind = Variable::NORMAL; @@ -1868,6 +1788,25 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // both access to the static and the dynamic context chain; the // runtime needs to provide both. if (resolve && var != NULL) { + if (declaration_scope->is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } + proxy->BindTo(var); if (FLAG_harmony_modules) { @@ -1876,7 +1815,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { if (FLAG_print_interface_details) PrintF("# Declare %s\n", var->name()->ToAsciiArray()); #endif - proxy->interface()->Unify(var->interface(), &ok); + proxy->interface()->Unify(var->interface(), zone(), &ok); if (!ok) { #ifdef DEBUG if (FLAG_print_interfaces) { @@ -1942,7 +1881,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // TODO(1240846): It's weird that native function declarations are // introduced dynamically when we meet their declarations, whereas // other functions are set up when entering the surrounding scope. - VariableProxy* proxy = NewUnresolved(name, VAR); + VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue()); Declaration* declaration = factory()->NewVariableDeclaration(proxy, VAR, top_scope_); Declare(declaration, true, CHECK_OK); @@ -1968,14 +1907,17 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) { 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 + // scope, we treat it as such and introduce the function with its // initial value upon entering the corresponding scope. - VariableMode mode = is_extended_mode() ? LET : VAR; - VariableProxy* proxy = NewUnresolved(name, mode); + // In extended mode, a function behaves as a lexical binding, except in the + // global scope. + VariableMode mode = + is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR; + VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue()); Declaration* declaration = factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_); Declare(declaration, true, CHECK_OK); - if (names) names->Add(name); + if (names) names->Add(name, zone()); return factory()->NewEmptyStatement(); } @@ -1993,12 +1935,10 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { Block* result = factory()->NewBlock(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); - block_finder.Update(stat); + result->AddStatement(stat, zone()); } } Expect(Token::RBRACE, CHECK_OK); @@ -2020,16 +1960,14 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { Expect(Token::LBRACE, CHECK_OK); block_scope->set_start_position(scanner().location().beg_pos); { BlockState block_state(this, block_scope); - TargetCollector collector; + TargetCollector collector(zone()); Target target(&this->target_stack_, &collector); Target target_body(&this->target_stack_, body); - InitializationBlockFinder block_finder(top_scope_, target_stack_); while (peek() != Token::RBRACE) { Statement* stat = ParseBlockElement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) { - body->AddStatement(stat); - block_finder.Update(stat); + body->AddStatement(stat, zone()); } } } @@ -2203,7 +2141,9 @@ Block* Parser::ParseVariableDeclarations( // 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. - VariableProxy* proxy = NewUnresolved(name, mode); + Interface* interface = + is_const ? Interface::NewConst() : Interface::NewValue(); + VariableProxy* proxy = NewUnresolved(name, mode, interface); Declaration* declaration = factory()->NewVariableDeclaration(proxy, mode, top_scope_); Declare(declaration, mode != VAR, CHECK_OK); @@ -2214,7 +2154,7 @@ Block* Parser::ParseVariableDeclarations( *ok = false; return NULL; } - if (names) names->Add(name); + if (names) names->Add(name, zone()); // Parse initialization expression if present and/or needed. A // declaration of the form: @@ -2291,21 +2231,24 @@ Block* Parser::ParseVariableDeclarations( // 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()) { + if (initialization_scope->is_global_scope() && + !IsLexicalVariableMode(mode)) { // Compute the arguments for the runtime call. - ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3); + ZoneList<Expression*>* arguments = + new(zone()) ZoneList<Expression*>(3, zone()); // We have at least 1 parameter. - arguments->Add(factory()->NewLiteral(name)); + arguments->Add(factory()->NewLiteral(name), zone()); CallRuntime* initialize; if (is_const) { - arguments->Add(value); + arguments->Add(value, zone()); value = NULL; // zap the value to avoid the unnecessary assignment int qml_mode = 0; - if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) + if (top_scope_->is_qml_mode() + && !Isolate::Current()->global_object()->HasProperty(*name)) qml_mode = 1; - arguments->Add(factory()->NewNumberLiteral(qml_mode)); + arguments->Add(factory()->NewNumberLiteral(qml_mode), zone()); // Construct the call to Runtime_InitializeConstGlobal // and add it to the initialization statement block. @@ -2319,19 +2262,20 @@ Block* Parser::ParseVariableDeclarations( // Add strict mode. // We may want to pass singleton to avoid Literal allocations. LanguageMode language_mode = initialization_scope->language_mode(); - arguments->Add(factory()->NewNumberLiteral(language_mode)); + arguments->Add(factory()->NewNumberLiteral(language_mode), zone()); int qml_mode = 0; - if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) + if (top_scope_->is_qml_mode() + && !Isolate::Current()->global_object()->HasProperty(*name)) qml_mode = 1; - arguments->Add(factory()->NewNumberLiteral(qml_mode)); + arguments->Add(factory()->NewNumberLiteral(qml_mode), zone()); // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not // necessarily be stored in the global object in that case, // which is why we need to generate a separate assignment node. if (value != NULL && !inside_with()) { - arguments->Add(value); + arguments->Add(value, zone()); value = NULL; // zap the value to avoid the unnecessary assignment } @@ -2345,7 +2289,8 @@ Block* Parser::ParseVariableDeclarations( arguments); } - block->AddStatement(factory()->NewExpressionStatement(initialize)); + block->AddStatement(factory()->NewExpressionStatement(initialize), + zone()); } else if (needs_init) { // Constant initializations always assign to the declared constant which // is always at the function scope level. This is only relevant for @@ -2359,7 +2304,8 @@ Block* Parser::ParseVariableDeclarations( ASSERT(value != NULL); Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, position); - block->AddStatement(factory()->NewExpressionStatement(assignment)); + block->AddStatement(factory()->NewExpressionStatement(assignment), + zone()); value = NULL; } @@ -2371,10 +2317,11 @@ Block* Parser::ParseVariableDeclarations( // if they are inside a 'with' statement - they may change a 'with' object // property). VariableProxy* proxy = - initialization_scope->NewUnresolved(factory(), name); + initialization_scope->NewUnresolved(factory(), name, interface); Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, position); - block->AddStatement(factory()->NewExpressionStatement(assignment)); + block->AddStatement(factory()->NewExpressionStatement(assignment), + zone()); } if (fni_ != NULL) fni_->Leave(); @@ -2428,8 +2375,10 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, *ok = false; return NULL; } - if (labels == NULL) labels = new(zone()) ZoneStringList(4); - labels->Add(label); + if (labels == NULL) { + labels = new(zone()) ZoneStringList(4, zone()); + } + labels->Add(label, zone()); // Remove the "ghost" variable that turned out to be a label // from the top scope. This way, we don't try to resolve it // during the scope processing. @@ -2641,12 +2590,13 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { } Expect(Token::COLON, CHECK_OK); int pos = scanner().location().beg_pos; - ZoneList<Statement*>* statements = new(zone()) ZoneList<Statement*>(5); + ZoneList<Statement*>* statements = + new(zone()) ZoneList<Statement*>(5, zone()); while (peek() != Token::CASE && peek() != Token::DEFAULT && peek() != Token::RBRACE) { Statement* stat = ParseStatement(NULL, CHECK_OK); - statements->Add(stat); + statements->Add(stat, zone()); } return new(zone()) CaseClause(isolate(), label, statements, pos); @@ -2667,11 +2617,11 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, Expect(Token::RPAREN, CHECK_OK); bool default_seen = false; - ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4); + ZoneList<CaseClause*>* cases = new(zone()) ZoneList<CaseClause*>(4, zone()); Expect(Token::LBRACE, CHECK_OK); while (peek() != Token::RBRACE) { CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK); - cases->Add(clause); + cases->Add(clause, zone()); } Expect(Token::RBRACE, CHECK_OK); @@ -2712,7 +2662,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::TRY, CHECK_OK); - TargetCollector try_collector; + TargetCollector try_collector(zone()); Block* try_block; { Target target(&this->target_stack_, &try_collector); @@ -2730,7 +2680,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { // 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; + TargetCollector catch_collector(zone()); Scope* catch_scope = NULL; Variable* catch_variable = NULL; Block* catch_block = NULL; @@ -2785,7 +2735,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { index, try_block, catch_scope, catch_variable, catch_block); statement->set_escaping_targets(try_collector.targets()); try_block = factory()->NewBlock(NULL, 1, false); - try_block->AddStatement(statement); + try_block->AddStatement(statement, zone()); catch_block = NULL; // Clear to indicate it's been handled. } @@ -2801,7 +2751,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { int index = current_function_state_->NextHandlerIndex(); result = factory()->NewTryFinallyStatement(index, try_block, finally_block); // Combine the jump targets of the try block and the possible catch block. - try_collector.targets()->AddAll(*catch_collector.targets()); + try_collector.targets()->AddAll(*catch_collector.targets(), zone()); } result->set_escaping_targets(try_collector.targets()); @@ -2875,12 +2825,14 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { for_scope->set_start_position(scanner().location().beg_pos); if (peek() != Token::SEMICOLON) { if (peek() == Token::VAR || peek() == Token::CONST) { + bool is_const = peek() == Token::CONST; Handle<String> name; Block* variable_statement = ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK); if (peek() == Token::IN && !name.is_null()) { - VariableProxy* each = top_scope_->NewUnresolved(factory(), name); + Interface* interface = + is_const ? Interface::NewConst() : Interface::NewValue(); ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); @@ -2888,11 +2840,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Expression* enumerable = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); + VariableProxy* each = + top_scope_->NewUnresolved(factory(), name, interface); Statement* body = ParseStatement(NULL, CHECK_OK); loop->Initialize(each, enumerable, body); Block* result = factory()->NewBlock(NULL, 2, false); - result->AddStatement(variable_statement); - result->AddStatement(loop); + result->AddStatement(variable_statement, zone()); + result->AddStatement(loop, zone()); top_scope_ = saved_scope; for_scope->set_end_position(scanner().location().end_pos); for_scope = for_scope->FinalizeBlockScope(); @@ -2925,25 +2879,33 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // TODO(keuchel): Move the temporary variable to the block scope, after // implementing stack allocated block scoped variables. - Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name); + Factory* heap_factory = isolate()->factory(); + Handle<String> tempstr = + heap_factory->NewConsString(heap_factory->dot_for_symbol(), name); + Handle<String> tempname = heap_factory->LookupSymbol(tempstr); + Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); - VariableProxy* each = top_scope_->NewUnresolved(factory(), name); ForInStatement* loop = factory()->NewForInStatement(labels); Target target(&this->target_stack_, loop); + // The expression does not see the loop variable. Expect(Token::IN, CHECK_OK); + top_scope_ = saved_scope; Expression* enumerable = ParseExpression(true, CHECK_OK); + top_scope_ = for_scope; Expect(Token::RPAREN, CHECK_OK); + VariableProxy* each = + top_scope_->NewUnresolved(factory(), name, Interface::NewValue()); Statement* body = ParseStatement(NULL, CHECK_OK); Block* body_block = factory()->NewBlock(NULL, 3, false); Assignment* assignment = factory()->NewAssignment( Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition); Statement* assignment_statement = factory()->NewExpressionStatement(assignment); - body_block->AddStatement(variable_statement); - body_block->AddStatement(assignment_statement); - body_block->AddStatement(body); + body_block->AddStatement(variable_statement, zone()); + body_block->AddStatement(assignment_statement, zone()); + body_block->AddStatement(body, zone()); loop->Initialize(temp_proxy, enumerable, body_block); top_scope_ = saved_scope; for_scope->set_end_position(scanner().location().end_pos); @@ -3026,8 +2988,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // } ASSERT(init != NULL); Block* result = factory()->NewBlock(NULL, 2, false); - result->AddStatement(init); - result->AddStatement(loop); + result->AddStatement(init, zone()); + result->AddStatement(loop, zone()); result->set_scope(for_scope); if (loop) loop->Initialize(NULL, cond, next, body); return result; @@ -3409,6 +3371,12 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { // should not point to the closing brace otherwise it will intersect // with positions recorded for function literal and confuse debugger. pos = scanner().peek_location().beg_pos; + // Also the trailing parenthesis are a hint that the function will + // be called immediately. If we happen to have parsed a preceding + // function literal eagerly, we can also compile it eagerly. + if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) { + result->AsFunctionLiteral()->set_parenthesized(); + } } ZoneList<Expression*>* args = ParseArguments(CHECK_OK); @@ -3470,7 +3438,7 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { if (!stack->is_empty()) { int last = stack->pop(); result = factory()->NewCallNew( - result, new(zone()) ZoneList<Expression*>(0), last); + result, new(zone()) ZoneList<Expression*>(0, zone()), last); } return result; } @@ -3660,9 +3628,9 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { if (FLAG_print_interface_details) PrintF("# Variable %s ", name->ToAsciiArray()); #endif - Interface* interface = Interface::NewUnknown(); + Interface* interface = Interface::NewUnknown(zone()); result = top_scope_->NewUnresolved( - factory(), name, scanner().location().beg_pos, interface); + factory(), name, interface, scanner().location().beg_pos); break; } @@ -3760,7 +3728,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { // ArrayLiteral :: // '[' Expression? (',' Expression?)* ']' - ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4); + ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4, zone()); Expect(Token::LBRACK, CHECK_OK); while (peek() != Token::RBRACK) { Expression* elem; @@ -3769,7 +3737,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { } else { elem = ParseAssignmentExpression(true, CHECK_OK); } - values->Add(elem); + values->Add(elem, zone()); if (peek() != Token::RBRACK) { Expect(Token::COMMA, CHECK_OK); } @@ -3783,10 +3751,12 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { Handle<FixedArray> object_literals = isolate()->factory()->NewFixedArray(values->length(), TENURED); Handle<FixedDoubleArray> double_literals; - ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS; + ElementsKind elements_kind = FAST_SMI_ELEMENTS; bool has_only_undefined_values = true; + bool has_hole_values = false; // Fill in the literals. + Heap* heap = isolate()->heap(); bool is_simple = true; int depth = 1; for (int i = 0, n = values->length(); i < n; i++) { @@ -3795,12 +3765,18 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { depth = m_literal->depth() + 1; } Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i)); - if (boilerplate_value->IsUndefined()) { + if (boilerplate_value->IsTheHole()) { + has_hole_values = true; object_literals->set_the_hole(i); if (elements_kind == FAST_DOUBLE_ELEMENTS) { double_literals->set_the_hole(i); } + } else if (boilerplate_value->IsUndefined()) { is_simple = false; + object_literals->set(i, Smi::FromInt(0)); + if (elements_kind == FAST_DOUBLE_ELEMENTS) { + double_literals->set(i, 0); + } } else { // Examine each literal element, and adjust the ElementsKind if the // literal element is not of a type that can be stored in the current @@ -3810,7 +3786,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { // ultimately end up in FAST_ELEMENTS. has_only_undefined_values = false; object_literals->set(i, *boilerplate_value); - if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { + if (elements_kind == FAST_SMI_ELEMENTS) { // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or // FAST_ELEMENTS is required. if (!boilerplate_value->IsSmi()) { @@ -3858,7 +3834,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { // elements array to a copy-on-write array. if (is_simple && depth == 1 && values->length() > 0 && elements_kind != FAST_DOUBLE_ELEMENTS) { - object_literals->set_map(isolate()->heap()->fixed_cow_array_map()); + object_literals->set_map(heap->fixed_cow_array_map()); } Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS @@ -3870,6 +3846,10 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED); + if (has_hole_values || !FLAG_packed_arrays) { + elements_kind = GetHoleyElementsKind(elements_kind); + } + literals->set(0, Smi::FromInt(elements_kind)); literals->set(1, *element_values); @@ -4126,7 +4106,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { // )*[','] '}' ZoneList<ObjectLiteral::Property*>* properties = - new(zone()) ZoneList<ObjectLiteral::Property*>(4); + new(zone()) ZoneList<ObjectLiteral::Property*>(4, zone()); int number_of_boilerplate_properties = 0; bool has_function = false; @@ -4163,7 +4143,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { } // Validate the property. checker.CheckProperty(property, loc, CHECK_OK); - properties->Add(property); + properties->Add(property, zone()); if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); if (fni_ != NULL) { @@ -4231,7 +4211,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++; // Validate the property checker.CheckProperty(property, loc, CHECK_OK); - properties->Add(property); + properties->Add(property, zone()); // TODO(1240767): Consider allowing trailing comma. if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); @@ -4290,12 +4270,12 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' - ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4); + ZoneList<Expression*>* result = new(zone()) ZoneList<Expression*>(4, zone()); Expect(Token::LPAREN, CHECK_OK); bool done = (peek() == Token::RPAREN); while (!done) { Expression* argument = ParseAssignmentExpression(true, CHECK_OK); - result->Add(argument); + result->Add(argument, zone()); if (result->length() > kMaxNumFunctionParameters) { ReportMessageAt(scanner().location(), "too_many_arguments", Vector<const char*>::empty()); @@ -4341,6 +4321,7 @@ class SingletonLogger : public ParserRecorder { int end, const char* message, const char* argument_opt) { + if (has_error_) return; has_error_ = true; start_ = start; end_ = end; @@ -4435,6 +4416,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, Handle<FixedArray> this_property_assignments; FunctionLiteral::ParameterFlag duplicate_parameters = FunctionLiteral::kNoDuplicateParameters; + FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ + ? FunctionLiteral::kIsParenthesized + : FunctionLiteral::kNotParenthesized; AstProperties ast_properties; // Parse function body. { FunctionState function_state(this, scope, isolate()); @@ -4495,7 +4479,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST; fvar = new(zone()) Variable(top_scope_, function_name, fvar_mode, true /* is valid LHS */, - Variable::NORMAL, kCreatedInitialized); + Variable::NORMAL, kCreatedInitialized, Interface::NewConst()); VariableProxy* proxy = factory()->NewVariableProxy(fvar); VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_); @@ -4506,7 +4490,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, // The heuristics are: // - It must not have been prohibited by the caller to Parse (some callers // need a full AST). - // - The outer scope must be trivial (only global variables in scope). + // - The outer scope must allow lazy compilation of inner functions. // - The function mustn't be a function expression with an open parenthesis // before; we consider that a hint that the function will be called // immediately, and it would be a waste of time to make it lazily @@ -4514,8 +4498,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, // These are all things we can know at this point, without looking at the // function itself. bool is_lazily_compiled = (mode() == PARSE_LAZILY && - top_scope_->outer_scope()->is_global_scope() && - top_scope_->HasTrivialOuterContext() && + top_scope_->AllowsLazyCompilation() && !parenthesized_function_); parenthesized_function_ = false; // The bit was set for this function only. @@ -4584,18 +4567,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, } if (!is_lazily_compiled) { - body = new(zone()) ZoneList<Statement*>(8); + ParsingModeScope parsing_mode(this, PARSE_EAGERLY); + body = new(zone()) ZoneList<Statement*>(8, zone()); if (fvar != NULL) { - VariableProxy* fproxy = - top_scope_->NewUnresolved(factory(), function_name); + VariableProxy* fproxy = top_scope_->NewUnresolved( + factory(), function_name, Interface::NewConst()); fproxy->BindTo(fvar); body->Add(factory()->NewExpressionStatement( factory()->NewAssignment(fvar_init_op, fproxy, factory()->NewThisFunction(), - RelocInfo::kNoPosition))); + RelocInfo::kNoPosition)), + zone()); } - ParseSourceElements(body, Token::RBRACE, false, CHECK_OK); + ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); materialized_literal_count = function_state.materialized_literal_count(); expected_property_count = function_state.expected_property_count(); @@ -4673,7 +4658,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, num_parameters, duplicate_parameters, type, - FunctionLiteral::kIsFunction); + FunctionLiteral::kIsFunction, + parenthesized); function_literal->set_function_token_position(function_token_position); function_literal->set_ast_properties(&ast_properties); @@ -4745,6 +4731,13 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { return NULL; } + // Check that the function is defined if it's an inline runtime call. + if (function == NULL && name->Get(0) == '_') { + ReportMessage("not_defined", Vector<Handle<String> >(&name, 1)); + *ok = false; + return NULL; + } + // We have a valid intrinsics call or a call to a builtin. return factory()->NewCallRuntime(name, function, args); } @@ -4992,7 +4985,7 @@ void Parser::RegisterTargetUse(Label* target, Target* stop) { // the break target to any TargetCollectors passed on the stack. for (Target* t = target_stack_; t != stop; t = t->previous()) { TargetCollector* collector = t->node()->AsTargetCollector(); - if (collector != NULL) collector->AddTarget(target); + if (collector != NULL) collector->AddTarget(target, zone()); } } @@ -5039,9 +5032,9 @@ Expression* Parser::NewThrowError(Handle<String> constructor, Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements( elements, FAST_ELEMENTS, TENURED); - ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2); - args->Add(factory()->NewLiteral(type)); - args->Add(factory()->NewLiteral(array)); + ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone()); + args->Add(factory()->NewLiteral(type), zone()); + args->Add(factory()->NewLiteral(array), zone()); CallRuntime* call_constructor = factory()->NewCallRuntime(constructor, NULL, args); return factory()->NewThrow(call_constructor, scanner().location().beg_pos); @@ -5053,8 +5046,10 @@ Expression* Parser::NewThrowError(Handle<String> constructor, RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error, - bool multiline) + bool multiline, + Zone* zone) : isolate_(Isolate::Current()), + zone_(zone), error_(error), captures_(NULL), in_(in), @@ -5085,7 +5080,7 @@ void RegExpParser::Advance() { StackLimitCheck check(isolate()); if (check.HasOverflowed()) { ReportError(CStrVector(Isolate::kStackOverflowMessage)); - } else if (isolate()->zone()->excess_allocation()) { + } else if (zone()->excess_allocation()) { ReportError(CStrVector("Regular expression too large")); } else { current_ = in()->Get(next_pos_); @@ -5150,7 +5145,7 @@ RegExpTree* RegExpParser::ParsePattern() { // Atom Quantifier RegExpTree* RegExpParser::ParseDisjunction() { // Used to store current state while parsing subexpressions. - RegExpParserState initial_state(NULL, INITIAL, 0); + RegExpParserState initial_state(NULL, INITIAL, 0, zone()); RegExpParserState* stored_state = &initial_state; // Cache the builder in a local variable for quick access. RegExpBuilder* builder = initial_state.builder(); @@ -5235,8 +5230,8 @@ RegExpTree* RegExpParser::ParseDisjunction() { Advance(); // everything except \x0a, \x0d, \u2028 and \u2029 ZoneList<CharacterRange>* ranges = - new(zone()) ZoneList<CharacterRange>(2); - CharacterRange::AddClassEscape('.', ranges); + new(zone()) ZoneList<CharacterRange>(2, zone()); + CharacterRange::AddClassEscape('.', ranges, zone()); RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false); builder->AddAtom(atom); break; @@ -5262,17 +5257,16 @@ RegExpTree* RegExpParser::ParseDisjunction() { Advance(2); } else { if (captures_ == NULL) { - captures_ = new(zone()) ZoneList<RegExpCapture*>(2); + captures_ = new(zone()) ZoneList<RegExpCapture*>(2, zone()); } if (captures_started() >= kMaxCaptures) { ReportError(CStrVector("Too many captures") CHECK_FAILED); } - captures_->Add(NULL); + captures_->Add(NULL, zone()); } // Store current state and begin new disjunction parsing. - stored_state = new(zone()) RegExpParserState(stored_state, - type, - captures_started()); + stored_state = new(zone()) RegExpParserState(stored_state, type, + captures_started(), zone()); builder = stored_state->builder(); continue; } @@ -5306,8 +5300,8 @@ RegExpTree* RegExpParser::ParseDisjunction() { uc32 c = Next(); Advance(2); ZoneList<CharacterRange>* ranges = - new(zone()) ZoneList<CharacterRange>(2); - CharacterRange::AddClassEscape(c, ranges); + new(zone()) ZoneList<CharacterRange>(2, zone()); + CharacterRange::AddClassEscape(c, ranges, zone()); RegExpTree* atom = new(zone()) RegExpCharacterClass(ranges, false); builder->AddAtom(atom); break; @@ -5782,11 +5776,12 @@ static const uc16 kNoCharClass = 0; // escape (i.e., 's' means whitespace, from '\s'). static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges, uc16 char_class, - CharacterRange range) { + CharacterRange range, + Zone* zone) { if (char_class != kNoCharClass) { - CharacterRange::AddClassEscape(char_class, ranges); + CharacterRange::AddClassEscape(char_class, ranges, zone); } else { - ranges->Add(range); + ranges->Add(range, zone); } } @@ -5802,7 +5797,8 @@ RegExpTree* RegExpParser::ParseCharacterClass() { is_negated = true; Advance(); } - ZoneList<CharacterRange>* ranges = new(zone()) ZoneList<CharacterRange>(2); + ZoneList<CharacterRange>* ranges = + new(zone()) ZoneList<CharacterRange>(2, zone()); while (has_more() && current() != ']') { uc16 char_class = kNoCharClass; CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED); @@ -5813,25 +5809,25 @@ RegExpTree* RegExpParser::ParseCharacterClass() { // following code report an error. break; } else if (current() == ']') { - AddRangeOrEscape(ranges, char_class, first); - ranges->Add(CharacterRange::Singleton('-')); + AddRangeOrEscape(ranges, char_class, first, zone()); + ranges->Add(CharacterRange::Singleton('-'), zone()); break; } uc16 char_class_2 = kNoCharClass; CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED); if (char_class != kNoCharClass || char_class_2 != kNoCharClass) { // Either end is an escaped character class. Treat the '-' verbatim. - AddRangeOrEscape(ranges, char_class, first); - ranges->Add(CharacterRange::Singleton('-')); - AddRangeOrEscape(ranges, char_class_2, next); + AddRangeOrEscape(ranges, char_class, first, zone()); + ranges->Add(CharacterRange::Singleton('-'), zone()); + AddRangeOrEscape(ranges, char_class_2, next, zone()); continue; } if (first.from() > next.to()) { return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED); } - ranges->Add(CharacterRange::Range(first.from(), next.to())); + ranges->Add(CharacterRange::Range(first.from(), next.to()), zone()); } else { - AddRangeOrEscape(ranges, char_class, first); + AddRangeOrEscape(ranges, char_class, first, zone()); } } if (!has_more()) { @@ -5839,7 +5835,7 @@ RegExpTree* RegExpParser::ParseCharacterClass() { } Advance(); if (ranges->length() == 0) { - ranges->Add(CharacterRange::Everything()); + ranges->Add(CharacterRange::Everything(), zone()); is_negated = !is_negated; } return new(zone()) RegExpCharacterClass(ranges, is_negated); @@ -5947,31 +5943,6 @@ static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source, } -// Preparse, but only collect data that is immediately useful, -// even if the preparser data is only used once. -ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source, - v8::Extension* extension, - 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; - int source_length = source->length(); - if (source->IsExternalTwoByteString()) { - ExternalTwoByteStringUtf16CharacterStream stream( - Handle<ExternalTwoByteString>::cast(source), 0, source_length); - return DoPreParse(&stream, flags, &recorder); - } else { - GenericStringUtf16CharacterStream stream(source, 0, source_length); - return DoPreParse(&stream, flags, &recorder); - } -} - - ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source, v8::Extension* extension, int flags) { @@ -5986,9 +5957,10 @@ ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source, bool RegExpParser::ParseRegExp(FlatStringReader* input, bool multiline, - RegExpCompileData* result) { + RegExpCompileData* result, + Zone* zone) { ASSERT(result != NULL); - RegExpParser parser(input, &result->error, multiline); + RegExpParser parser(input, &result->error, multiline, zone); RegExpTree* tree = parser.ParsePattern(); if (parser.failed()) { ASSERT(tree == NULL); @@ -6009,7 +5981,6 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input, bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) { ASSERT(info->function() == NULL); FunctionLiteral* result = NULL; - Handle<Script> script = info->script(); ASSERT((parsing_flags & kLanguageModeMask) == CLASSIC_MODE); if (!info->is_native() && FLAG_harmony_scoping) { // Harmony scoping is requested. @@ -6024,15 +5995,15 @@ bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) { } if (info->is_lazy()) { ASSERT(!info->is_eval()); - Parser parser(script, parsing_flags, NULL, NULL); + Parser parser(info, parsing_flags, NULL, NULL); if (info->shared_info()->is_function()) { - result = parser.ParseLazy(info); + result = parser.ParseLazy(); } else { - result = parser.ParseProgram(info); + result = parser.ParseProgram(); } } else { ScriptDataImpl* pre_data = info->pre_parse_data(); - Parser parser(script, parsing_flags, info->extension(), pre_data); + Parser parser(info, parsing_flags, info->extension(), pre_data); if (pre_data != NULL && pre_data->has_error()) { Scanner::Location loc = pre_data->MessageLocation(); const char* message = pre_data->BuildMessage(); @@ -6045,7 +6016,7 @@ bool ParserApi::Parse(CompilationInfo* info, int parsing_flags) { DeleteArray(args.start()); ASSERT(info->isolate()->has_pending_exception()); } else { - result = parser.ParseProgram(info); + result = parser.ParseProgram(); } } info->SetFunction(result); |