diff options
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r-- | deps/v8/src/ast/ast-function-literal-id-reindexer.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-source-ranges.h | 25 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.cc | 11 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.h | 96 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.cc | 6 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.h | 36 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes-inl.h | 66 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.cc | 231 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.h | 73 | ||||
-rw-r--r-- | deps/v8/src/ast/variables.h | 3 |
11 files changed, 325 insertions, 228 deletions
diff --git a/deps/v8/src/ast/ast-function-literal-id-reindexer.cc b/deps/v8/src/ast/ast-function-literal-id-reindexer.cc index 5cb1e87d23..7e3a25890b 100644 --- a/deps/v8/src/ast/ast-function-literal-id-reindexer.cc +++ b/deps/v8/src/ast/ast-function-literal-id-reindexer.cc @@ -14,7 +14,7 @@ AstFunctionLiteralIdReindexer::AstFunctionLiteralIdReindexer(size_t stack_limit, int delta) : AstTraversalVisitor(stack_limit), delta_(delta) {} -AstFunctionLiteralIdReindexer::~AstFunctionLiteralIdReindexer() {} +AstFunctionLiteralIdReindexer::~AstFunctionLiteralIdReindexer() = default; void AstFunctionLiteralIdReindexer::Reindex(Expression* pattern) { Visit(pattern); diff --git a/deps/v8/src/ast/ast-source-ranges.h b/deps/v8/src/ast/ast-source-ranges.h index cf7bab53da..60222a4035 100644 --- a/deps/v8/src/ast/ast-source-ranges.h +++ b/deps/v8/src/ast/ast-source-ranges.h @@ -21,8 +21,9 @@ struct SourceRange { static SourceRange OpenEnded(int32_t start) { return SourceRange(start, kNoSourcePosition); } - static SourceRange ContinuationOf(const SourceRange& that) { - return that.IsEmpty() ? Empty() : OpenEnded(that.end); + static SourceRange ContinuationOf(const SourceRange& that, + int end = kNoSourcePosition) { + return that.IsEmpty() ? Empty() : SourceRange(that.end, end); } int32_t start, end; }; @@ -56,7 +57,7 @@ enum class SourceRangeKind { class AstNodeSourceRanges : public ZoneObject { public: - virtual ~AstNodeSourceRanges() {} + virtual ~AstNodeSourceRanges() = default; virtual SourceRange GetRange(SourceRangeKind kind) = 0; }; @@ -65,7 +66,7 @@ class BinaryOperationSourceRanges final : public AstNodeSourceRanges { explicit BinaryOperationSourceRanges(const SourceRange& right_range) : right_range_(right_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { DCHECK_EQ(kind, SourceRangeKind::kRight); return right_range_; } @@ -79,7 +80,7 @@ class ContinuationSourceRanges : public AstNodeSourceRanges { explicit ContinuationSourceRanges(int32_t continuation_position) : continuation_position_(continuation_position) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { DCHECK_EQ(kind, SourceRangeKind::kContinuation); return SourceRange::OpenEnded(continuation_position_); } @@ -99,7 +100,7 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges { explicit CaseClauseSourceRanges(const SourceRange& body_range) : body_range_(body_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { DCHECK_EQ(kind, SourceRangeKind::kBody); return body_range_; } @@ -114,7 +115,7 @@ class ConditionalSourceRanges final : public AstNodeSourceRanges { const SourceRange& else_range) : then_range_(then_range), else_range_(else_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { switch (kind) { case SourceRangeKind::kThen: return then_range_; @@ -136,7 +137,7 @@ class IfStatementSourceRanges final : public AstNodeSourceRanges { const SourceRange& else_range) : then_range_(then_range), else_range_(else_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { switch (kind) { case SourceRangeKind::kElse: return else_range_; @@ -162,7 +163,7 @@ class IterationStatementSourceRanges final : public AstNodeSourceRanges { explicit IterationStatementSourceRanges(const SourceRange& body_range) : body_range_(body_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { switch (kind) { case SourceRangeKind::kBody: return body_range_; @@ -198,7 +199,7 @@ class NaryOperationSourceRanges final : public AstNodeSourceRanges { void AddRange(const SourceRange& range) { ranges_.push_back(range); } size_t RangeCount() const { return ranges_.size(); } - SourceRange GetRange(SourceRangeKind kind) { UNREACHABLE(); } + SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); } private: ZoneVector<SourceRange> ranges_; @@ -227,7 +228,7 @@ class TryCatchStatementSourceRanges final : public AstNodeSourceRanges { explicit TryCatchStatementSourceRanges(const SourceRange& catch_range) : catch_range_(catch_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { switch (kind) { case SourceRangeKind::kCatch: return catch_range_; @@ -247,7 +248,7 @@ class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges { explicit TryFinallyStatementSourceRanges(const SourceRange& finally_range) : finally_range_(finally_range) {} - SourceRange GetRange(SourceRangeKind kind) { + SourceRange GetRange(SourceRangeKind kind) override { switch (kind) { case SourceRangeKind::kFinally: return finally_range_; diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc index 8cf81b24a5..67ea77bfbf 100644 --- a/deps/v8/src/ast/ast-value-factory.cc +++ b/deps/v8/src/ast/ast-value-factory.cc @@ -242,6 +242,17 @@ const AstRawString* AstValueFactory::GetString(Handle<String> literal) { return result; } +const AstRawString* AstValueFactory::CloneFromOtherFactory( + const AstRawString* raw_string) { + const AstRawString* result = GetString( + raw_string->hash_field(), raw_string->is_one_byte(), + Vector<const byte>(raw_string->raw_data(), raw_string->byte_length())); + // Check we weren't trying to clone a string that was already in this + // ast-value-factory. + DCHECK_NE(result, raw_string); + return result; +} + AstConsString* AstValueFactory::NewConsString() { AstConsString* new_string = new (zone_) AstConsString; DCHECK_NOT_NULL(new_string); diff --git a/deps/v8/src/ast/ast-value-factory.h b/deps/v8/src/ast/ast-value-factory.h index e85b0675bf..726d961362 100644 --- a/deps/v8/src/ast/ast-value-factory.h +++ b/deps/v8/src/ast/ast-value-factory.h @@ -194,48 +194,49 @@ class AstBigInt { }; // For generating constants. -#define AST_STRING_CONSTANTS(F) \ - F(anonymous_function, "(anonymous function)") \ - F(arguments, "arguments") \ - F(async, "async") \ - F(await, "await") \ - F(bigint, "bigint") \ - F(boolean, "boolean") \ - F(constructor, "constructor") \ - F(default, "default") \ - F(done, "done") \ - F(dot, ".") \ - F(dot_for, ".for") \ - F(dot_generator_object, ".generator_object") \ - F(dot_iterator, ".iterator") \ - F(dot_result, ".result") \ - F(dot_switch_tag, ".switch_tag") \ - F(dot_catch, ".catch") \ - F(empty, "") \ - F(eval, "eval") \ - F(function, "function") \ - F(get_space, "get ") \ - F(length, "length") \ - F(let, "let") \ - F(name, "name") \ - F(native, "native") \ - F(new_target, ".new.target") \ - F(next, "next") \ - F(number, "number") \ - F(object, "object") \ - F(proto, "__proto__") \ - F(prototype, "prototype") \ - F(return, "return") \ - F(set_space, "set ") \ - F(star_default_star, "*default*") \ - F(string, "string") \ - F(symbol, "symbol") \ - F(this, "this") \ - F(this_function, ".this_function") \ - F(throw, "throw") \ - F(undefined, "undefined") \ - F(use_asm, "use asm") \ - F(use_strict, "use strict") \ +#define AST_STRING_CONSTANTS(F) \ + F(anonymous_function, "(anonymous function)") \ + F(arguments, "arguments") \ + F(async, "async") \ + F(await, "await") \ + F(bigint, "bigint") \ + F(boolean, "boolean") \ + F(constructor, "constructor") \ + F(default, "default") \ + F(done, "done") \ + F(dot, ".") \ + F(dot_for, ".for") \ + F(dot_generator_object, ".generator_object") \ + F(dot_iterator, ".iterator") \ + F(dot_promise, ".promise") \ + F(dot_result, ".result") \ + F(dot_switch_tag, ".switch_tag") \ + F(dot_catch, ".catch") \ + F(empty, "") \ + F(eval, "eval") \ + F(function, "function") \ + F(get_space, "get ") \ + F(length, "length") \ + F(let, "let") \ + F(name, "name") \ + F(native, "native") \ + F(new_target, ".new.target") \ + F(next, "next") \ + F(number, "number") \ + F(object, "object") \ + F(proto, "__proto__") \ + F(prototype, "prototype") \ + F(return, "return") \ + F(set_space, "set ") \ + F(star_default_star, "*default*") \ + F(string, "string") \ + F(symbol, "symbol") \ + F(this, "this") \ + F(this_function, ".this_function") \ + F(throw, "throw") \ + F(undefined, "undefined") \ + F(use_asm, "use asm") \ + F(use_strict, "use strict") \ F(value, "value") class AstStringConstants final { @@ -297,10 +298,15 @@ class AstValueFactory { return GetTwoByteStringInternal(literal); } const AstRawString* GetString(Handle<String> literal); + + // Clones an AstRawString from another ast value factory, adding it to this + // factory and returning the clone. + const AstRawString* CloneFromOtherFactory(const AstRawString* raw_string); + V8_EXPORT_PRIVATE AstConsString* NewConsString(); - AstConsString* NewConsString(const AstRawString* str); - AstConsString* NewConsString(const AstRawString* str1, - const AstRawString* str2); + V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str); + V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str1, + const AstRawString* str2); V8_EXPORT_PRIVATE void Internalize(Isolate* isolate); diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc index 5a4add6039..617a26b937 100644 --- a/deps/v8/src/ast/ast.cc +++ b/deps/v8/src/ast/ast.cc @@ -551,12 +551,6 @@ bool ObjectLiteral::IsFastCloningSupported() const { ConstructorBuiltins::kMaximumClonedShallowObjectProperties; } -bool ArrayLiteral::is_empty() const { - DCHECK(is_initialized()); - return values()->is_empty() && (boilerplate_description().is_null() || - boilerplate_description()->is_empty()); -} - int ArrayLiteral::InitDepthAndFlags() { if (is_initialized()) return depth(); diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index 6c1e989d30..6cc2cbc8ec 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -383,7 +383,7 @@ class DoExpression final : public Expression { class Declaration : public AstNode { public: - typedef ThreadedList<Declaration> List; + typedef base::ThreadedList<Declaration> List; VariableProxy* proxy() const { return proxy_; } @@ -397,6 +397,7 @@ class Declaration : public AstNode { Declaration** next() { return &next_; } Declaration* next_; friend List; + friend base::ThreadedListTraits<Declaration>; }; class VariableDeclaration : public Declaration { @@ -1477,8 +1478,6 @@ class ArrayLiteral final : public AggregateLiteral { int first_spread_index() const { return first_spread_index_; } - bool is_empty() const; - // Populate the depth field and flags, returns the depth. int InitDepthAndFlags(); @@ -1578,8 +1577,15 @@ class VariableProxy final : public Expression { // Bind this proxy to the variable var. void BindTo(Variable* var); - void set_next_unresolved(VariableProxy* next) { next_unresolved_ = next; } - VariableProxy* next_unresolved() { return next_unresolved_; } + V8_INLINE VariableProxy* next_unresolved() { return next_unresolved_; } + + // Provides an access type for the ThreadedList used by the PreParsers + // expressions, lists, and formal parameters. + struct PreParserNext { + static VariableProxy** next(VariableProxy* t) { + return t->pre_parser_expr_next(); + } + }; private: friend class AstNodeFactory; @@ -1590,7 +1596,8 @@ class VariableProxy final : public Expression { int start_position) : Expression(start_position, kVariableProxy), raw_name_(name), - next_unresolved_(nullptr) { + next_unresolved_(nullptr), + pre_parser_expr_next_(nullptr) { bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) | IsAssignedField::encode(false) | IsResolvedField::encode(false) | @@ -1613,9 +1620,15 @@ class VariableProxy final : public Expression { const AstRawString* raw_name_; // if !is_resolved_ Variable* var_; // if is_resolved_ }; + + V8_INLINE VariableProxy** next() { return &next_unresolved_; } VariableProxy* next_unresolved_; -}; + VariableProxy** pre_parser_expr_next() { return &pre_parser_expr_next_; } + VariableProxy* pre_parser_expr_next_; + + friend base::ThreadedListTraits<VariableProxy>; +}; // Left-hand side can only be a property, a global or a (parameter or local) // slot. @@ -2248,7 +2261,7 @@ class FunctionLiteral final : public Expression { void mark_as_iife() { bit_field_ = IIFEBit::update(bit_field_, true); } bool is_iife() const { return IIFEBit::decode(bit_field_); } - bool is_top_level() const { + bool is_toplevel() const { return function_literal_id() == FunctionLiteral::kIdTypeTopLevel; } bool is_wrapped() const { return function_type() == kWrapped; } @@ -2308,7 +2321,7 @@ class FunctionLiteral final : public Expression { // - (function() { ... })(); // - var x = function() { ... }(); bool ShouldEagerCompile() const; - void SetShouldEagerCompile(); + V8_EXPORT_PRIVATE void SetShouldEagerCompile(); FunctionType function_type() const { return FunctionTypeBits::decode(bit_field_); @@ -2736,7 +2749,7 @@ class TemplateLiteral final : public Expression { // class SpecificVisitor : public AstVisitor<SpecificVisitor> { ... } template <class Subclass> -class AstVisitor BASE_EMBEDDED { +class AstVisitor { public: void Visit(AstNode* node) { impl()->Visit(node); } @@ -2823,7 +2836,7 @@ class AstVisitor BASE_EMBEDDED { // ---------------------------------------------------------------------------- // AstNode factory -class AstNodeFactory final BASE_EMBEDDED { +class AstNodeFactory final { public: AstNodeFactory(AstValueFactory* ast_value_factory, Zone* zone) : zone_(zone), ast_value_factory_(ast_value_factory) {} @@ -3330,7 +3343,6 @@ class AstNodeFactory final BASE_EMBEDDED { } Zone* zone() const { return zone_; } - void set_zone(Zone* zone) { zone_ = zone; } private: // This zone may be deallocated upon returning from parsing a function body diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc index d2e56a9335..f9c2243099 100644 --- a/deps/v8/src/ast/prettyprinter.cc +++ b/deps/v8/src/ast/prettyprinter.cc @@ -31,7 +31,7 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) InitializeAstVisitor(isolate); } -CallPrinter::~CallPrinter() {} +CallPrinter::~CallPrinter() = default; CallPrinter::ErrorHint CallPrinter::GetErrorHint() const { if (is_call_error_) { @@ -666,7 +666,7 @@ void AstPrinter::PrintLiteral(const AstConsString* value, bool quote) { //----------------------------------------------------------------------------- -class IndentedScope BASE_EMBEDDED { +class IndentedScope { public: IndentedScope(AstPrinter* printer, const char* txt) : ast_printer_(printer) { diff --git a/deps/v8/src/ast/scopes-inl.h b/deps/v8/src/ast/scopes-inl.h new file mode 100644 index 0000000000..a70166c5ca --- /dev/null +++ b/deps/v8/src/ast/scopes-inl.h @@ -0,0 +1,66 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_AST_SCOPES_INL_H_ +#define V8_AST_SCOPES_INL_H_ + +#include "src/ast/scopes.h" + +namespace v8 { +namespace internal { + +template <typename T> +void Scope::ResolveScopesThenForEachVariable(DeclarationScope* max_outer_scope, + T variable_proxy_stackvisitor, + ParseInfo* info) { + // Module variables must be allocated before variable resolution + // to ensure that UpdateNeedsHoleCheck() can detect import variables. + if (info != nullptr && is_module_scope()) { + AsModuleScope()->AllocateModuleVariables(); + } + // Lazy parsed declaration scopes are already partially analyzed. If there are + // unresolved references remaining, they just need to be resolved in outer + // scopes. + Scope* lookup = + is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed() + ? outer_scope() + : this; + + for (VariableProxy *proxy = unresolved_list_.first(), *next = nullptr; + proxy != nullptr; proxy = next) { + next = proxy->next_unresolved(); + + DCHECK(!proxy->is_resolved()); + Variable* var = + lookup->LookupRecursive(info, proxy, max_outer_scope->outer_scope()); + if (var == nullptr) { + variable_proxy_stackvisitor(proxy); + } else if (var != Scope::kDummyPreParserVariable && + var != Scope::kDummyPreParserLexicalVariable) { + if (info != nullptr) { + // In this case we need to leave scopes in a way that they can be + // allocated. If we resolved variables from lazy parsed scopes, we need + // to context allocate the var. + ResolveTo(info, proxy, var); + if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation(); + } else { + var->set_is_used(); + if (proxy->is_assigned()) var->set_maybe_assigned(); + } + } + } + + // Clear unresolved_list_ as it's in an inconsistent state. + unresolved_list_.Clear(); + + for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { + scope->ResolveScopesThenForEachVariable(max_outer_scope, + variable_proxy_stackvisitor, info); + } +} + +} // namespace internal +} // namespace v8 + +#endif // V8_AST_SCOPES_INL_H_ diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 74d50c44de..e9fb195609 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -8,6 +8,7 @@ #include "src/accessors.h" #include "src/ast/ast.h" +#include "src/ast/scopes-inl.h" #include "src/base/optional.h" #include "src/bootstrapper.h" #include "src/counters.h" @@ -23,15 +24,11 @@ namespace v8 { namespace internal { namespace { -void* kDummyPreParserVariable = reinterpret_cast<void*>(0x1); -void* kDummyPreParserLexicalVariable = reinterpret_cast<void*>(0x2); - bool IsLexical(Variable* variable) { - if (variable == kDummyPreParserLexicalVariable) return true; - if (variable == kDummyPreParserVariable) return false; + if (variable == Scope::kDummyPreParserLexicalVariable) return true; + if (variable == Scope::kDummyPreParserVariable) return false; return IsLexicalVariableMode(variable->mode()); } - } // namespace // ---------------------------------------------------------------------------- @@ -76,8 +73,9 @@ Variable* VariableMap::DeclareName(Zone* zone, const AstRawString* name, if (p->value == nullptr) { // The variable has not been declared yet -> insert it. DCHECK_EQ(name, p->key); - p->value = mode == VariableMode::kVar ? kDummyPreParserVariable - : kDummyPreParserLexicalVariable; + p->value = mode == VariableMode::kVar + ? Scope::kDummyPreParserVariable + : Scope::kDummyPreParserLexicalVariable; } return reinterpret_cast<Variable*>(p->value); } @@ -154,7 +152,7 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type) Scope::Snapshot::Snapshot(Scope* scope) : outer_scope_(scope), top_inner_scope_(scope->inner_scope_), - top_unresolved_(scope->unresolved_), + top_unresolved_(scope->unresolved_list_.first()), top_local_(scope->GetClosureScope()->locals_.end()), top_decl_(scope->GetClosureScope()->decls_.end()), outer_scope_calls_eval_(scope->scope_calls_eval_) { @@ -310,6 +308,8 @@ void DeclarationScope::SetDefaults() { has_arguments_parameter_ = false; scope_uses_super_property_ = false; has_rest_ = false; + has_promise_ = false; + has_generator_object_ = false; sloppy_block_function_map_ = nullptr; receiver_ = nullptr; new_target_ = nullptr; @@ -319,7 +319,7 @@ void DeclarationScope::SetDefaults() { should_eager_compile_ = false; was_lazily_parsed_ = false; is_skipped_function_ = false; - produced_preparsed_scope_data_ = nullptr; + preparsed_scope_data_builder_ = nullptr; #ifdef DEBUG DeclarationScope* outer_declaration_scope = outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr; @@ -337,7 +337,7 @@ void Scope::SetDefaults() { #endif inner_scope_ = nullptr; sibling_ = nullptr; - unresolved_ = nullptr; + unresolved_list_.Clear(); start_position_ = kNoSourcePosition; end_position_ = kNoSourcePosition; @@ -779,6 +779,7 @@ Variable* DeclarationScope::DeclareGeneratorObjectVar( Variable* result = EnsureRareData()->generator_object = NewTemporary(name, kNotAssigned); result->set_is_used(); + has_generator_object_ = true; return result; } @@ -787,6 +788,7 @@ Variable* DeclarationScope::DeclarePromiseVar(const AstRawString* name) { DCHECK_NULL(promise_var()); Variable* result = EnsureRareData()->promise = NewTemporary(name); result->set_is_used(); + has_promise_ = true; return result; } @@ -834,16 +836,9 @@ Scope* Scope::FinalizeBlockScope() { } // Move unresolved variables - if (unresolved_ != nullptr) { - if (outer_scope()->unresolved_ != nullptr) { - VariableProxy* unresolved = unresolved_; - while (unresolved->next_unresolved() != nullptr) { - unresolved = unresolved->next_unresolved(); - } - unresolved->set_next_unresolved(outer_scope()->unresolved_); - } - outer_scope()->unresolved_ = unresolved_; - unresolved_ = nullptr; + if (!unresolved_list_.is_empty()) { + outer_scope()->unresolved_list_.Prepend(std::move(unresolved_list_)); + unresolved_list_.Clear(); } if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true; @@ -887,7 +882,7 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { DCHECK_EQ(new_parent->outer_scope_, outer_scope_); DCHECK_EQ(new_parent, new_parent->GetClosureScope()); DCHECK_NULL(new_parent->inner_scope_); - DCHECK_NULL(new_parent->unresolved_); + DCHECK(new_parent->unresolved_list_.is_empty()); DCHECK(new_parent->locals_.is_empty()); Scope* inner_scope = new_parent->sibling_; if (inner_scope != top_inner_scope_) { @@ -910,14 +905,21 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { new_parent->sibling_ = top_inner_scope_; } - if (outer_scope_->unresolved_ != top_unresolved_) { - VariableProxy* last = outer_scope_->unresolved_; - while (last->next_unresolved() != top_unresolved_) { - last = last->next_unresolved(); + if (outer_scope_->unresolved_list_.first() != top_unresolved_) { + // If the marked VariableProxy (snapshoted) is not the first, we need to + // find it and move all VariableProxys up to that point into the new_parent, + // then we restore the snapshoted state by reinitializing the outer_scope + // list. + { + auto iter = outer_scope_->unresolved_list_.begin(); + while (*iter != top_unresolved_) { + ++iter; + } + outer_scope_->unresolved_list_.Rewind(iter); } - last->set_next_unresolved(nullptr); - new_parent->unresolved_ = outer_scope_->unresolved_; - outer_scope_->unresolved_ = top_unresolved_; + + new_parent->unresolved_list_ = std::move(outer_scope_->unresolved_list_); + outer_scope_->unresolved_list_.ReinitializeHead(top_unresolved_); } // TODO(verwaest): This currently only moves do-expression declared variables @@ -1261,8 +1263,7 @@ void Scope::DeclareCatchVariableName(const AstRawString* name) { void Scope::AddUnresolved(VariableProxy* proxy) { DCHECK(!already_resolved_); DCHECK(!proxy->is_resolved()); - proxy->set_next_unresolved(unresolved_); - unresolved_ = proxy; + unresolved_list_.AddFront(proxy); } Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, @@ -1274,22 +1275,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, } bool Scope::RemoveUnresolved(VariableProxy* var) { - if (unresolved_ == var) { - unresolved_ = var->next_unresolved(); - var->set_next_unresolved(nullptr); - return true; - } - VariableProxy* current = unresolved_; - while (current != nullptr) { - VariableProxy* next = current->next_unresolved(); - if (var == next) { - current->set_next_unresolved(next->next_unresolved()); - var->set_next_unresolved(nullptr); - return true; - } - current = next; - } - return false; + return unresolved_list_.Remove(var); } Variable* Scope::NewTemporary(const AstRawString* name) { @@ -1483,11 +1469,12 @@ Scope* Scope::GetOuterScopeWithContext() { Handle<StringSet> DeclarationScope::CollectNonLocals( Isolate* isolate, ParseInfo* info, Handle<StringSet> non_locals) { - VariableProxy* free_variables = FetchFreeVariables(this, info); - for (VariableProxy* proxy = free_variables; proxy != nullptr; - proxy = proxy->next_unresolved()) { - non_locals = StringSet::Add(isolate, non_locals, proxy->name()); - } + ResolveScopesThenForEachVariable(this, + [=, &non_locals](VariableProxy* proxy) { + non_locals = StringSet::Add( + isolate, non_locals, proxy->name()); + }, + info); return non_locals; } @@ -1504,10 +1491,15 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, decls_.Clear(); locals_.Clear(); inner_scope_ = nullptr; - unresolved_ = nullptr; + unresolved_list_.Clear(); sloppy_block_function_map_ = nullptr; rare_data_ = nullptr; has_rest_ = false; + has_promise_ = false; + has_generator_object_ = false; + + DCHECK_NE(zone_, ast_value_factory->zone()); + zone_->ReleaseMemory(); if (aborted) { // Prepare scope for use in the outer zone. @@ -1532,7 +1524,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, void Scope::SavePreParsedScopeData() { DCHECK(FLAG_preparser_scope_analysis); - if (ProducedPreParsedScopeData::ScopeIsSkippableFunctionScope(this)) { + if (PreParsedScopeDataBuilder::ScopeIsSkippableFunctionScope(this)) { AsDeclarationScope()->SavePreParsedScopeDataForDeclarationScope(); } @@ -1542,30 +1534,33 @@ void Scope::SavePreParsedScopeData() { } void DeclarationScope::SavePreParsedScopeDataForDeclarationScope() { - if (produced_preparsed_scope_data_ != nullptr) { + if (preparsed_scope_data_builder_ != nullptr) { DCHECK(FLAG_preparser_scope_analysis); - produced_preparsed_scope_data_->SaveScopeAllocationData(this); + preparsed_scope_data_builder_->SaveScopeAllocationData(this); } } void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) { DCHECK(!force_eager_compilation_); - VariableProxy* unresolved = nullptr; - - if (!outer_scope_->is_script_scope() || - (FLAG_preparser_scope_analysis && - produced_preparsed_scope_data_ != nullptr && - produced_preparsed_scope_data_->ContainsInnerFunctions())) { + base::ThreadedList<VariableProxy> new_unresolved_list; + if (!IsArrowFunction(function_kind_) && + (!outer_scope_->is_script_scope() || + (FLAG_preparser_scope_analysis && + preparsed_scope_data_builder_ != nullptr && + preparsed_scope_data_builder_->ContainsInnerFunctions()))) { // Try to resolve unresolved variables for this Scope and migrate those // which cannot be resolved inside. It doesn't make sense to try to resolve // them in the outer Scopes here, because they are incomplete. - for (VariableProxy* proxy = FetchFreeVariables(this); proxy != nullptr; - proxy = proxy->next_unresolved()) { - DCHECK(!proxy->is_resolved()); - VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); - copy->set_next_unresolved(unresolved); - unresolved = copy; - } + ResolveScopesThenForEachVariable( + this, [=, &new_unresolved_list](VariableProxy* proxy) { + // Don't copy unresolved references to the script scope, unless it's a + // reference to a private field. In that case keep it so we can fail + // later. + if (!outer_scope_->is_script_scope() || proxy->is_private_field()) { + VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); + new_unresolved_list.AddFront(copy); + } + }); // Migrate function_ to the right Zone. if (function_ != nullptr) { @@ -1586,7 +1581,7 @@ void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) { ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false); - unresolved_ = unresolved; + unresolved_list_ = std::move(new_unresolved_list); } #ifdef DEBUG @@ -1673,8 +1668,8 @@ void PrintMap(int indent, const char* label, VariableMap* map, bool locals, for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { Variable* var = reinterpret_cast<Variable*>(p->value); if (var == function_var) continue; - if (var == kDummyPreParserVariable || - var == kDummyPreParserLexicalVariable) { + if (var == Scope::kDummyPreParserVariable || + var == Scope::kDummyPreParserLexicalVariable) { continue; } bool local = !IsDynamicVariableMode(var->mode()); @@ -2045,8 +2040,7 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) { // scopes. if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { DCHECK_EQ(variables_.occupancy(), 0); - for (VariableProxy* proxy = unresolved_; proxy != nullptr; - proxy = proxy->next_unresolved()) { + for (VariableProxy* proxy : unresolved_list_) { Variable* var = outer_scope()->LookupRecursive(info, proxy, nullptr); if (var == nullptr) { DCHECK(proxy->is_private_field()); @@ -2060,8 +2054,7 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) { } } else { // Resolve unresolved variables for this scope. - for (VariableProxy* proxy = unresolved_; proxy != nullptr; - proxy = proxy->next_unresolved()) { + for (VariableProxy* proxy : unresolved_list_) { if (!ResolveVariable(info, proxy)) return false; } @@ -2074,57 +2067,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) { return true; } -VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, - ParseInfo* info, - VariableProxy* stack) { - // Module variables must be allocated before variable resolution - // to ensure that UpdateNeedsHoleCheck() can detect import variables. - if (info != nullptr && is_module_scope()) { - AsModuleScope()->AllocateModuleVariables(); - } - // Lazy parsed declaration scopes are already partially analyzed. If there are - // unresolved references remaining, they just need to be resolved in outer - // scopes. - Scope* lookup = - is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed() - ? outer_scope() - : this; - for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; - proxy = next) { - next = proxy->next_unresolved(); - DCHECK(!proxy->is_resolved()); - Variable* var = - lookup->LookupRecursive(info, proxy, max_outer_scope->outer_scope()); - if (var == nullptr) { - proxy->set_next_unresolved(stack); - stack = proxy; - } else if (var != kDummyPreParserVariable && - var != kDummyPreParserLexicalVariable) { - if (info != nullptr) { - // In this case we need to leave scopes in a way that they can be - // allocated. If we resolved variables from lazy parsed scopes, we need - // to context allocate the var. - ResolveTo(info, proxy, var); - if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation(); - } else { - var->set_is_used(); - if (proxy->is_assigned()) { - var->set_maybe_assigned(); - } - } - } - } - - // Clear unresolved_ as it's in an inconsistent state. - unresolved_ = nullptr; - - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - stack = scope->FetchFreeVariables(max_outer_scope, info, stack); - } - - return stack; -} - bool Scope::MustAllocate(Variable* var) { if (var == kDummyPreParserLexicalVariable || var == kDummyPreParserVariable) { return true; @@ -2236,6 +2178,24 @@ void DeclarationScope::AllocateReceiver() { AllocateParameter(receiver(), -1); } +void DeclarationScope::AllocatePromise() { + if (!has_promise_) return; + DCHECK_NOT_NULL(promise_var()); + DCHECK_EQ(this, promise_var()->scope()); + AllocateStackSlot(promise_var()); + DCHECK_EQ(VariableLocation::LOCAL, promise_var()->location()); + DCHECK_EQ(kPromiseVarIndex, promise_var()->index()); +} + +void DeclarationScope::AllocateGeneratorObject() { + if (!has_generator_object_) return; + DCHECK_NOT_NULL(generator_object_var()); + DCHECK_EQ(this, generator_object_var()->scope()); + AllocateStackSlot(generator_object_var()); + DCHECK_EQ(VariableLocation::LOCAL, generator_object_var()->location()); + DCHECK_EQ(kGeneratorObjectVarIndex, generator_object_var()->index()); +} + void Scope::AllocateNonParameterLocal(Variable* var) { DCHECK(var->scope() == this); if (var->IsUnallocated() && MustAllocate(var)) { @@ -2304,6 +2264,19 @@ void Scope::AllocateVariablesRecursively() { return; } + // Make sure to allocate the .promise (for async functions) or + // .generator_object (for async generators) first, so that it + // get's the required stack slot 0 in case it's needed. See + // http://bit.ly/v8-zero-cost-async-stack-traces for details. + if (is_function_scope()) { + FunctionKind kind = GetClosureScope()->function_kind(); + if (IsAsyncGeneratorFunction(kind)) { + AsDeclarationScope()->AllocateGeneratorObject(); + } else if (IsAsyncFunction(kind)) { + AsDeclarationScope()->AllocatePromise(); + } + } + // Allocate variables for inner scopes. for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { scope->AllocateVariablesRecursively(); @@ -2410,5 +2383,9 @@ int Scope::ContextLocalCount() const { (is_function_var_in_context ? 1 : 0); } +void* const Scope::kDummyPreParserVariable = reinterpret_cast<void*>(0x1); +void* const Scope::kDummyPreParserLexicalVariable = + reinterpret_cast<void*>(0x2); + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index f43761af58..0b88cc027c 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -20,8 +20,7 @@ class AstValueFactory; class AstRawString; class Declaration; class ParseInfo; -class PreParsedScopeData; -class ProducedPreParsedScopeData; +class PreParsedScopeDataBuilder; class SloppyBlockFunctionStatement; class Statement; class StringSet; @@ -103,7 +102,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { void SetScopeName(const AstRawString* scope_name) { scope_name_ = scope_name; } - void set_needs_migration() { needs_migration_ = true; } #endif // TODO(verwaest): Is this needed on Scope? @@ -114,7 +112,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ModuleScope* AsModuleScope(); const ModuleScope* AsModuleScope() const; - class Snapshot final BASE_EMBEDDED { + class Snapshot final { public: explicit Snapshot(Scope* scope); ~Snapshot(); @@ -125,8 +123,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { Scope* outer_scope_; Scope* top_inner_scope_; VariableProxy* top_unresolved_; - ThreadedList<Variable>::Iterator top_local_; - ThreadedList<Declaration>::Iterator top_decl_; + base::ThreadedList<Variable>::Iterator top_local_; + base::ThreadedList<Declaration>::Iterator top_decl_; const bool outer_scope_calls_eval_; }; @@ -203,9 +201,9 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { void DeclareCatchVariableName(const AstRawString* name); // Declarations list. - ThreadedList<Declaration>* declarations() { return &decls_; } + base::ThreadedList<Declaration>* declarations() { return &decls_; } - ThreadedList<Variable>* locals() { return &locals_; } + base::ThreadedList<Variable>* locals() { return &locals_; } // Create a new unresolved variable. VariableProxy* NewUnresolved(AstNodeFactory* factory, @@ -218,8 +216,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { DCHECK(!already_resolved_); DCHECK_EQ(factory->zone(), zone()); VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_pos); - proxy->set_next_unresolved(unresolved_); - unresolved_ = proxy; + AddUnresolved(proxy); return proxy; } @@ -480,6 +477,9 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { return false; } + static void* const kDummyPreParserVariable; + static void* const kDummyPreParserLexicalVariable; + protected: explicit Scope(Zone* zone); @@ -522,12 +522,12 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { VariableMap variables_; // In case of non-scopeinfo-backed scopes, this contains the variables of the // map above in order of addition. - ThreadedList<Variable> locals_; + base::ThreadedList<Variable> locals_; // Unresolved variables referred to from this scope. The proxies themselves // form a linked list of all unresolved proxies. - VariableProxy* unresolved_; + base::ThreadedList<VariableProxy> unresolved_list_; // Declarations. - ThreadedList<Declaration> decls_; + base::ThreadedList<Declaration> decls_; // Serialized scope info support. Handle<ScopeInfo> scope_info_; @@ -597,9 +597,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Finds free variables of this scope. This mutates the unresolved variables // list along the way, so full resolution cannot be done afterwards. // If a ParseInfo* is passed, non-free variables will be resolved. - VariableProxy* FetchFreeVariables(DeclarationScope* max_outer_scope, - ParseInfo* info = nullptr, - VariableProxy* stack = nullptr); + template <typename T> + void ResolveScopesThenForEachVariable(DeclarationScope* max_outer_scope, + T variable_proxy_stackvisitor, + ParseInfo* info = nullptr); // Predicates. bool MustAllocate(Variable* var); @@ -682,6 +683,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { } bool is_being_lazily_parsed() const { return is_being_lazily_parsed_; } #endif + void set_zone(Zone* zone) { +#ifdef DEBUG + needs_migration_ = true; +#endif + zone_ = zone; + } bool ShouldEagerCompile() const; void set_should_eager_compile(); @@ -759,11 +766,22 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // literals, or nullptr. Only valid for function scopes. Variable* function_var() const { return function_; } + // The variable holding the JSGeneratorObject for generator, async + // and async generator functions, and modules. Only valid for + // function and module scopes. Variable* generator_object_var() const { DCHECK(is_function_scope() || is_module_scope()); return GetRareVariable(RareVariable::kGeneratorObject); } + // For async generators, the .generator_object variable is always + // allocated to a fixed stack slot, such that the stack trace + // construction logic can access it. + static constexpr int kGeneratorObjectVarIndex = 0; + + // The variable holding the promise returned from async functions. + // Only valid for function scopes in async functions (i.e. not + // for async generators). Variable* promise_var() const { DCHECK(is_function_scope()); DCHECK(IsAsyncFunction(function_kind_)); @@ -771,6 +789,11 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { return GetRareVariable(RareVariable::kPromise); } + // For async functions, the .promise variable is always allocated + // to a fixed stack slot, such that the stack trace construction + // logic can access it. + static constexpr int kPromiseVarIndex = 0; + // Parameters. The left-most parameter has index 0. // Only valid for function and module scopes. Variable* parameter(int index) const { @@ -898,6 +921,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { void AllocateLocals(); void AllocateParameterLocals(); void AllocateReceiver(); + void AllocatePromise(); + void AllocateGeneratorObject(); void ResetAfterPreparsing(AstValueFactory* ast_value_factory, bool aborted); @@ -919,13 +944,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // saved in produced_preparsed_scope_data_. void SavePreParsedScopeDataForDeclarationScope(); - void set_produced_preparsed_scope_data( - ProducedPreParsedScopeData* produced_preparsed_scope_data) { - produced_preparsed_scope_data_ = produced_preparsed_scope_data; + void set_preparsed_scope_data_builder( + PreParsedScopeDataBuilder* preparsed_scope_data_builder) { + preparsed_scope_data_builder_ = preparsed_scope_data_builder; } - ProducedPreParsedScopeData* produced_preparsed_scope_data() const { - return produced_preparsed_scope_data_; + PreParsedScopeDataBuilder* preparsed_scope_data_builder() const { + return preparsed_scope_data_builder_; } private: @@ -954,6 +979,10 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { bool force_eager_compilation_ : 1; // This function scope has a rest parameter. bool has_rest_ : 1; + // This function scope has a .promise variable. + bool has_promise_ : 1; + // This function scope has a .generator_object variable. + bool has_generator_object_ : 1; // This scope has a parameter called "arguments". bool has_arguments_parameter_ : 1; // This scope uses "super" property ('super.foo'). @@ -981,7 +1010,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { Variable* arguments_; // For producing the scope allocation data during preparsing. - ProducedPreParsedScopeData* produced_preparsed_scope_data_; + PreParsedScopeDataBuilder* preparsed_scope_data_builder_; struct RareData : public ZoneObject { // Convenience variable; Subclass constructor only diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h index 10ac5c48a5..d33062973b 100644 --- a/deps/v8/src/ast/variables.h +++ b/deps/v8/src/ast/variables.h @@ -181,7 +181,7 @@ class Variable final : public ZoneObject { : kNeedsInitialization; } - typedef ThreadedList<Variable> List; + typedef base::ThreadedList<Variable> List; private: Scope* scope_; @@ -215,6 +215,7 @@ class Variable final : public ZoneObject { ForceHoleInitializationField::kNext, 1> {}; Variable** next() { return &next_; } friend List; + friend base::ThreadedListTraits<Variable>; }; } // namespace internal } // namespace v8 |