diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-16 09:59:13 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-20 10:28:53 +0000 |
commit | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch) | |
tree | c8315530db18a8ee566521c39ab8a6af4f72bc03 /chromium/v8/src/ast | |
parent | 3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff) | |
download | qtwebengine-chromium-6c11fb357ec39bf087b8b632e2b1e375aef1b38b.tar.gz |
BASELINE: Update Chromium to 74.0.3729.159
Change-Id: I8d2497da544c275415aedd94dd25328d555de811
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/v8/src/ast')
-rw-r--r-- | chromium/v8/src/ast/ast-traversal-visitor.h | 4 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-value-factory.cc | 1 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-value-factory.h | 3 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast.cc | 28 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast.h | 137 | ||||
-rw-r--r-- | chromium/v8/src/ast/modules.cc | 47 | ||||
-rw-r--r-- | chromium/v8/src/ast/modules.h | 7 | ||||
-rw-r--r-- | chromium/v8/src/ast/prettyprinter.cc | 9 | ||||
-rw-r--r-- | chromium/v8/src/ast/prettyprinter.h | 1 | ||||
-rw-r--r-- | chromium/v8/src/ast/scopes.cc | 811 | ||||
-rw-r--r-- | chromium/v8/src/ast/scopes.h | 165 | ||||
-rw-r--r-- | chromium/v8/src/ast/source-range-ast-visitor.cc | 13 | ||||
-rw-r--r-- | chromium/v8/src/ast/variables.h | 8 |
13 files changed, 603 insertions, 631 deletions
diff --git a/chromium/v8/src/ast/ast-traversal-visitor.h b/chromium/v8/src/ast/ast-traversal-visitor.h index 21986789ba7..b4836ff7847 100644 --- a/chromium/v8/src/ast/ast-traversal-visitor.h +++ b/chromium/v8/src/ast/ast-traversal-visitor.h @@ -467,7 +467,7 @@ void AstTraversalVisitor<Subclass>::VisitCompareOperation( } template <class Subclass> -void AstTraversalVisitor<Subclass>::VisitThisFunction(ThisFunction* expr) { +void AstTraversalVisitor<Subclass>::VisitThisExpression(ThisExpression* expr) { PROCESS_EXPRESSION(expr); } @@ -555,7 +555,6 @@ template <class Subclass> void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference( SuperPropertyReference* expr) { PROCESS_EXPRESSION(expr); - RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var())); RECURSE_EXPRESSION(Visit(expr->home_object())); } @@ -563,7 +562,6 @@ template <class Subclass> void AstTraversalVisitor<Subclass>::VisitSuperCallReference( SuperCallReference* expr) { PROCESS_EXPRESSION(expr); - RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var())); RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var())); RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var())); } diff --git a/chromium/v8/src/ast/ast-value-factory.cc b/chromium/v8/src/ast/ast-value-factory.cc index 2a35097f9c7..94d500c07de 100644 --- a/chromium/v8/src/ast/ast-value-factory.cc +++ b/chromium/v8/src/ast/ast-value-factory.cc @@ -124,6 +124,7 @@ bool AstRawString::Compare(void* a, void* b) { DCHECK_EQ(lhs->Hash(), rhs->Hash()); if (lhs->length() != rhs->length()) return false; + if (lhs->length() == 0) return true; const unsigned char* l = lhs->raw_data(); const unsigned char* r = rhs->raw_data(); size_t length = rhs->length(); diff --git a/chromium/v8/src/ast/ast-value-factory.h b/chromium/v8/src/ast/ast-value-factory.h index 472527bebe2..dd557f5ac95 100644 --- a/chromium/v8/src/ast/ast-value-factory.h +++ b/chromium/v8/src/ast/ast-value-factory.h @@ -202,10 +202,12 @@ class AstBigInt { F(await, "await") \ F(bigint, "bigint") \ F(boolean, "boolean") \ + F(computed, "<computed>") \ F(constructor, "constructor") \ F(default, "default") \ F(done, "done") \ F(dot, ".") \ + F(dot_default, ".default") \ F(dot_for, ".for") \ F(dot_generator_object, ".generator_object") \ F(dot_iterator, ".iterator") \ @@ -235,7 +237,6 @@ class AstBigInt { F(return, "return") \ F(set, "set") \ F(set_space, "set ") \ - F(star_default_star, "*default*") \ F(string, "string") \ F(symbol, "symbol") \ F(target, "target") \ diff --git a/chromium/v8/src/ast/ast.cc b/chromium/v8/src/ast/ast.cc index 1c1802d602f..f70579bd69c 100644 --- a/chromium/v8/src/ast/ast.cc +++ b/chromium/v8/src/ast/ast.cc @@ -23,6 +23,7 @@ #include "src/property-details.h" #include "src/property.h" #include "src/string-stream.h" +#include "src/zone/zone-list-inl.h" namespace v8 { namespace internal { @@ -155,8 +156,8 @@ VariableProxy::VariableProxy(Variable* var, int start_position) : Expression(start_position, kVariableProxy), raw_name_(var->raw_name()), next_unresolved_(nullptr) { - bit_field_ |= IsThisField::encode(var->is_this()) | - IsAssignedField::encode(false) | + DCHECK(!var->is_this()); + bit_field_ |= IsAssignedField::encode(false) | IsResolvedField::encode(false) | HoleCheckModeField::encode(HoleCheckMode::kElided); BindTo(var); @@ -171,7 +172,7 @@ VariableProxy::VariableProxy(const VariableProxy* copy_from) } void VariableProxy::BindTo(Variable* var) { - DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); + DCHECK_EQ(raw_name(), var->raw_name()); set_var(var); set_is_resolved(); var->set_is_used(); @@ -213,6 +214,18 @@ bool FunctionLiteral::AllowsLazyCompilation() { return scope()->AllowsLazyCompilation(); } +bool FunctionLiteral::SafeToSkipArgumentsAdaptor() const { + // TODO(bmeurer,verwaest): The --fast_calls_with_arguments_mismatches + // is mostly here for checking the real-world impact of the calling + // convention. There's not really a point in turning off this flag + // otherwise, so we should remove it at some point, when we're done + // with the experiments (https://crbug.com/v8/8895). + return FLAG_fast_calls_with_arguments_mismatches && + language_mode() == LanguageMode::kStrict && + scope()->arguments() == nullptr && + scope()->rest_parameter() == nullptr; +} + Handle<String> FunctionLiteral::name(Isolate* isolate) const { return raw_name_ ? raw_name_->string() : isolate->factory()->empty_string(); } @@ -457,15 +470,10 @@ void ObjectLiteral::BuildBoilerplateDescription(Isolate* isolate) { has_seen_proto = true; continue; } - if (property->is_computed_name()) { - continue; - } + if (property->is_computed_name()) continue; Literal* key = property->key()->AsLiteral(); - - if (!key->IsPropertyName()) { - index_keys++; - } + if (!key->IsPropertyName()) index_keys++; } Handle<ObjectBoilerplateDescription> boilerplate_description = diff --git a/chromium/v8/src/ast/ast.h b/chromium/v8/src/ast/ast.h index 4f9f083d123..80f76bd6e4b 100644 --- a/chromium/v8/src/ast/ast.h +++ b/chromium/v8/src/ast/ast.h @@ -11,6 +11,7 @@ #include "src/ast/modules.h" #include "src/ast/variables.h" #include "src/bailout-reason.h" +#include "src/base/threaded-list.h" #include "src/globals.h" #include "src/heap/factory.h" #include "src/isolate.h" @@ -100,7 +101,7 @@ namespace internal { V(SuperCallReference) \ V(SuperPropertyReference) \ V(TemplateLiteral) \ - V(ThisFunction) \ + V(ThisExpression) \ V(Throw) \ V(UnaryOperation) \ V(VariableProxy) \ @@ -483,26 +484,14 @@ inline NestedVariableDeclaration* VariableDeclaration::AsNested() { class FunctionDeclaration final : public Declaration { public: FunctionLiteral* fun() const { return fun_; } - bool declares_sloppy_block_function() const { - return DeclaresSloppyBlockFunction::decode(bit_field_); - } private: friend class AstNodeFactory; - class DeclaresSloppyBlockFunction - : public BitField<bool, Declaration::kNextBitFieldIndex, 1> {}; - - FunctionDeclaration(FunctionLiteral* fun, bool declares_sloppy_block_function, - int pos) - : Declaration(pos, kFunctionDeclaration), fun_(fun) { - bit_field_ = DeclaresSloppyBlockFunction::update( - bit_field_, declares_sloppy_block_function); - } + FunctionDeclaration(FunctionLiteral* fun, int pos) + : Declaration(pos, kFunctionDeclaration), fun_(fun) {} FunctionLiteral* fun_; - - static const uint8_t kNextBitFieldIndex = DeclaresSloppyBlockFunction::kNext; }; @@ -977,14 +966,30 @@ class SloppyBlockFunctionStatement final : public Statement { public: Statement* statement() const { return statement_; } void set_statement(Statement* statement) { statement_ = statement; } + Scope* scope() const { return var_->scope(); } + Variable* var() const { return var_; } + Token::Value init() const { return TokenField::decode(bit_field_); } + const AstRawString* name() const { return var_->raw_name(); } + SloppyBlockFunctionStatement** next() { return &next_; } private: friend class AstNodeFactory; - SloppyBlockFunctionStatement(int pos, Statement* statement) - : Statement(pos, kSloppyBlockFunctionStatement), statement_(statement) {} + class TokenField + : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {}; + + SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init, + Statement* statement) + : Statement(pos, kSloppyBlockFunctionStatement), + var_(var), + statement_(statement), + next_(nullptr) { + bit_field_ = TokenField::update(bit_field_, init); + } + Variable* var_; Statement* statement_; + SloppyBlockFunctionStatement* next_; }; @@ -1495,11 +1500,15 @@ class ArrayLiteral final : public AggregateLiteral { enum class HoleCheckMode { kRequired, kElided }; +class ThisExpression final : public Expression { + private: + friend class AstNodeFactory; + ThisExpression() : Expression(kNoSourcePosition, kThisExpression) {} +}; + class VariableProxy final : public Expression { public: - bool IsValidReferenceExpression() const { - return !is_this() && !is_new_target(); - } + bool IsValidReferenceExpression() const { return !is_new_target(); } Handle<String> name() const { return raw_name()->string(); } const AstRawString* raw_name() const { @@ -1520,8 +1529,6 @@ class VariableProxy final : public Expression { return Scanner::Location(position(), position() + raw_name()->length()); } - bool is_this() const { return IsThisField::decode(bit_field_); } - bool is_assigned() const { return IsAssignedField::decode(bit_field_); } void set_is_assigned() { bit_field_ = IsAssignedField::update(bit_field_, true); @@ -1594,8 +1601,8 @@ class VariableProxy final : public Expression { : Expression(start_position, kVariableProxy), raw_name_(name), next_unresolved_(nullptr) { - bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) | - IsAssignedField::encode(false) | + DCHECK_NE(THIS_VARIABLE, variable_kind); + bit_field_ |= IsAssignedField::encode(false) | IsResolvedField::encode(false) | IsRemovedFromUnresolvedField::encode(false) | HoleCheckModeField::encode(HoleCheckMode::kElided); @@ -1603,9 +1610,8 @@ class VariableProxy final : public Expression { explicit VariableProxy(const VariableProxy* copy_from); - class IsThisField : public BitField<bool, Expression::kNextBitFieldIndex, 1> { - }; - class IsAssignedField : public BitField<bool, IsThisField::kNext, 1> {}; + class IsAssignedField + : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {}; class IsRemovedFromUnresolvedField : public BitField<bool, IsResolvedField::kNext, 1> {}; @@ -2190,8 +2196,6 @@ class FunctionLiteral final : public Expression { kWrapped, }; - enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 }; - enum ParameterFlag : uint8_t { kNoDuplicateParameters, kHasDuplicateParameters @@ -2226,7 +2230,7 @@ class FunctionLiteral final : public Expression { } bool is_oneshot_iife() const { return OneshotIIFEBit::decode(bit_field_); } bool is_toplevel() const { - return function_literal_id() == FunctionLiteral::kIdTypeTopLevel; + return function_literal_id() == kFunctionLiteralIdTopLevel; } bool is_wrapped() const { return function_type() == kWrapped; } LanguageMode language_mode() const; @@ -2251,6 +2255,18 @@ class FunctionLiteral final : public Expression { return false; } + // We can safely skip the arguments adaptor frame setup even + // in case of arguments mismatches for strict mode functions, + // as long as there's + // + // 1. no use of the arguments object (either explicitly or + // potentially implicitly via a direct eval() call), and + // 2. rest parameters aren't being used in the function. + // + // See http://bit.ly/v8-faster-calls-with-arguments-mismatch + // for the details here (https://crbug.com/v8/8895). + bool SafeToSkipArgumentsAdaptor() const; + // Returns either name or inferred name as a cstring. std::unique_ptr<char[]> GetDebugName() const; @@ -2550,56 +2566,41 @@ class NativeFunctionLiteral final : public Expression { }; -class ThisFunction final : public Expression { - private: - friend class AstNodeFactory; - explicit ThisFunction(int pos) : Expression(pos, kThisFunction) {} -}; - - class SuperPropertyReference final : public Expression { public: - VariableProxy* this_var() const { return this_var_; } Expression* home_object() const { return home_object_; } private: friend class AstNodeFactory; - SuperPropertyReference(VariableProxy* this_var, Expression* home_object, - int pos) - : Expression(pos, kSuperPropertyReference), - this_var_(this_var), - home_object_(home_object) { - DCHECK(this_var->is_this()); + // We take in ThisExpression* only as a proof that it was accessed. + SuperPropertyReference(Expression* home_object, int pos) + : Expression(pos, kSuperPropertyReference), home_object_(home_object) { DCHECK(home_object->IsProperty()); } - VariableProxy* this_var_; Expression* home_object_; }; class SuperCallReference final : public Expression { public: - VariableProxy* this_var() const { return this_var_; } VariableProxy* new_target_var() const { return new_target_var_; } VariableProxy* this_function_var() const { return this_function_var_; } private: friend class AstNodeFactory; - SuperCallReference(VariableProxy* this_var, VariableProxy* new_target_var, + // We take in ThisExpression* only as a proof that it was accessed. + SuperCallReference(VariableProxy* new_target_var, VariableProxy* this_function_var, int pos) : Expression(pos, kSuperCallReference), - this_var_(this_var), new_target_var_(new_target_var), this_function_var_(this_function_var) { - DCHECK(this_var->is_this()); DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target")); DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function")); } - VariableProxy* this_var_; VariableProxy* new_target_var_; VariableProxy* this_function_var_; }; @@ -2780,6 +2781,7 @@ class AstNodeFactory final { : zone_(zone), ast_value_factory_(ast_value_factory), empty_statement_(new (zone) class EmptyStatement()), + this_expression_(new (zone) class ThisExpression()), failure_expression_(new (zone) class FailureExpression()) {} AstNodeFactory* ast_node_factory() { return this; } @@ -2794,10 +2796,8 @@ class AstNodeFactory final { return new (zone_) NestedVariableDeclaration(scope, pos); } - FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, - bool is_sloppy_block_function, - int pos) { - return new (zone_) FunctionDeclaration(fun, is_sloppy_block_function, pos); + FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, int pos) { + return new (zone_) FunctionDeclaration(fun, pos); } Block* NewBlock(int capacity, bool ignore_completion_value) { @@ -2936,12 +2936,18 @@ class AstNodeFactory final { return empty_statement_; } + class ThisExpression* ThisExpression() { + return this_expression_; + } + class FailureExpression* FailureExpression() { return failure_expression_; } - SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(int pos) { - return new (zone_) SloppyBlockFunctionStatement(pos, EmptyStatement()); + SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement( + int pos, Variable* var, Token::Value init) { + return new (zone_) + SloppyBlockFunctionStatement(pos, var, init, EmptyStatement()); } CaseClause* NewCaseClause(Expression* label, @@ -3143,6 +3149,8 @@ class AstNodeFactory final { Expression* value, int pos) { DCHECK(Token::IsAssignmentOp(op)); + DCHECK_NOT_NULL(target); + DCHECK_NOT_NULL(value); if (op != Token::INIT && target->IsVariableProxy()) { target->AsVariableProxy()->set_is_assigned(); @@ -3206,7 +3214,7 @@ class AstNodeFactory final { FunctionLiteral::kAnonymousExpression, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false, - FunctionLiteral::kIdTypeTopLevel); + kFunctionLiteralIdTopLevel); } ClassLiteral::Property* NewClassLiteralProperty( @@ -3242,22 +3250,16 @@ class AstNodeFactory final { return new (zone_) DoExpression(block, result, pos); } - ThisFunction* NewThisFunction(int pos) { - return new (zone_) ThisFunction(pos); - } - - SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var, - Expression* home_object, + SuperPropertyReference* NewSuperPropertyReference(Expression* home_object, int pos) { - return new (zone_) SuperPropertyReference(this_var, home_object, pos); + return new (zone_) SuperPropertyReference(home_object, pos); } - SuperCallReference* NewSuperCallReference(VariableProxy* this_var, - VariableProxy* new_target_var, + SuperCallReference* NewSuperCallReference(VariableProxy* new_target_var, VariableProxy* this_function_var, int pos) { return new (zone_) - SuperCallReference(this_var, new_target_var, this_function_var, pos); + SuperCallReference(new_target_var, this_function_var, pos); } EmptyParentheses* NewEmptyParentheses(int pos) { @@ -3295,6 +3297,7 @@ class AstNodeFactory final { Zone* zone_; AstValueFactory* ast_value_factory_; class EmptyStatement* empty_statement_; + class ThisExpression* this_expression_; class FailureExpression* failure_expression_; }; diff --git a/chromium/v8/src/ast/modules.cc b/chromium/v8/src/ast/modules.cc index 0f66ac91ecd..d1be965a4ab 100644 --- a/chromium/v8/src/ast/modules.cc +++ b/chromium/v8/src/ast/modules.cc @@ -91,20 +91,11 @@ void ModuleDescriptor::AddStarExport(const AstRawString* module_request, } namespace { - Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) { return (s == nullptr) ? Handle<Object>::cast(isolate->factory()->undefined_value()) : Handle<Object>::cast(s->string()); } - -const AstRawString* FromStringOrUndefined(Isolate* isolate, - AstValueFactory* avfactory, - Handle<Object> object) { - if (object->IsUndefined(isolate)) return nullptr; - return avfactory->GetString(Handle<String>::cast(object)); -} - } // namespace Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize( @@ -117,21 +108,6 @@ Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize( location.beg_pos, location.end_pos); } -ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize( - Isolate* isolate, AstValueFactory* avfactory, - Handle<ModuleInfoEntry> entry) { - Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid()); - result->export_name = FromStringOrUndefined( - isolate, avfactory, handle(entry->export_name(), isolate)); - result->local_name = FromStringOrUndefined( - isolate, avfactory, handle(entry->local_name(), isolate)); - result->import_name = FromStringOrUndefined( - isolate, avfactory, handle(entry->import_name(), isolate)); - result->module_request = entry->module_request(); - result->cell_index = entry->cell_index(); - return result; -} - Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate, Zone* zone) const { // We serialize regular exports in a way that lets us later iterate over their @@ -183,29 +159,6 @@ Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate, return result; } -void ModuleDescriptor::DeserializeRegularExports( - Isolate* isolate, AstValueFactory* avfactory, - Handle<ModuleInfo> module_info) { - for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) { - Handle<String> local_name(module_info->RegularExportLocalName(i), isolate); - int cell_index = module_info->RegularExportCellIndex(i); - Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), - isolate); - - for (int j = 0, length = export_names->length(); j < length; ++j) { - Handle<String> export_name(String::cast(export_names->get(j)), isolate); - - Entry* entry = - new (avfactory->zone()) Entry(Scanner::Location::invalid()); - entry->local_name = avfactory->GetString(local_name); - entry->export_name = avfactory->GetString(export_name); - entry->cell_index = cell_index; - - AddRegularExport(entry); - } - } -} - void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) { for (auto it = regular_exports_.begin(); it != regular_exports_.end();) { Entry* entry = it->second; diff --git a/chromium/v8/src/ast/modules.h b/chromium/v8/src/ast/modules.h index 44e86dce42b..ebc3e3a2884 100644 --- a/chromium/v8/src/ast/modules.h +++ b/chromium/v8/src/ast/modules.h @@ -107,12 +107,7 @@ class ModuleDescriptor : public ZoneObject { module_request(-1), cell_index(0) {} - // (De-)serialization support. - // Note that the location value is not preserved as it's only needed by the - // parser. (A Deserialize'd entry has an invalid location.) Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const; - static Entry* Deserialize(Isolate* isolate, AstValueFactory* avfactory, - Handle<ModuleInfoEntry> entry); }; enum CellIndexKind { kInvalid, kExport, kImport }; @@ -191,8 +186,6 @@ class ModuleDescriptor : public ZoneObject { Handle<FixedArray> SerializeRegularExports(Isolate* isolate, Zone* zone) const; - void DeserializeRegularExports(Isolate* isolate, AstValueFactory* avfactory, - Handle<ModuleInfo> module_info); private: ModuleRequestMap module_requests_; diff --git a/chromium/v8/src/ast/prettyprinter.cc b/chromium/v8/src/ast/prettyprinter.cc index a53d07064d5..c7f6e3d9f03 100644 --- a/chromium/v8/src/ast/prettyprinter.cc +++ b/chromium/v8/src/ast/prettyprinter.cc @@ -12,6 +12,7 @@ #include "src/globals.h" #include "src/objects-inl.h" #include "src/string-builder-inl.h" +#include "src/vector.h" namespace v8 { namespace internal { @@ -500,8 +501,7 @@ void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) { Print(")"); } -void CallPrinter::VisitThisFunction(ThisFunction* node) {} - +void CallPrinter::VisitThisExpression(ThisExpression* node) { Print("this"); } void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} @@ -1391,11 +1391,10 @@ void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) { Visit(node->argument()); } -void AstPrinter::VisitThisFunction(ThisFunction* node) { - IndentedScope indent(this, "THIS-FUNCTION", node->position()); +void AstPrinter::VisitThisExpression(ThisExpression* node) { + IndentedScope indent(this, "THIS-EXPRESSION", node->position()); } - void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); } diff --git a/chromium/v8/src/ast/prettyprinter.h b/chromium/v8/src/ast/prettyprinter.h index e6f27669158..e1efdbfb886 100644 --- a/chromium/v8/src/ast/prettyprinter.h +++ b/chromium/v8/src/ast/prettyprinter.h @@ -8,6 +8,7 @@ #include "src/allocation.h" #include "src/ast/ast.h" #include "src/base/compiler-specific.h" +#include "src/function-kind.h" namespace v8 { namespace internal { diff --git a/chromium/v8/src/ast/scopes.cc b/chromium/v8/src/ast/scopes.cc index 28869cd94ae..e625865a110 100644 --- a/chromium/v8/src/ast/scopes.cc +++ b/chromium/v8/src/ast/scopes.cc @@ -83,28 +83,6 @@ Variable* VariableMap::Lookup(const AstRawString* name) { return nullptr; } -void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) { - if (statement_ != nullptr) { - statement_->set_statement(statement); - } -} - -SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone) - : ZoneHashMap(8, ZoneAllocationPolicy(zone)), count_(0) {} - -void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name, - Scope* scope, - SloppyBlockFunctionStatement* statement) { - auto* delegate = new (zone) Delegate(scope, statement, count_++); - // AstRawStrings are unambiguous, i.e., the same string is always represented - // by the same AstRawString*. - Entry* p = - ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->Hash(), - ZoneAllocationPolicy(zone)); - delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value)); - p->value = delegate; -} - // ---------------------------------------------------------------------------- // Implementation of Scope @@ -132,10 +110,8 @@ DeclarationScope::DeclarationScope(Zone* zone, : Scope(zone), function_kind_(kNormalFunction), params_(4, zone) { DCHECK_EQ(scope_type_, SCRIPT_SCOPE); SetDefaults(); - - // Make sure that if we don't find the global 'this', it won't be declared as - // a regular dynamic global by predeclaring it with the right variable kind. - DeclareDynamicGlobal(ast_value_factory->this_string(), THIS_VARIABLE, this); + receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(), + THIS_VARIABLE, this); } DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, @@ -149,59 +125,19 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, } ModuleScope::ModuleScope(DeclarationScope* script_scope, - AstValueFactory* ast_value_factory) - : DeclarationScope(ast_value_factory->zone(), script_scope, MODULE_SCOPE, - kModule) { - Zone* zone = ast_value_factory->zone(); - module_descriptor_ = new (zone) ModuleDescriptor(zone); + AstValueFactory* avfactory) + : DeclarationScope(avfactory->zone(), script_scope, MODULE_SCOPE, kModule), + module_descriptor_(new (avfactory->zone()) + ModuleDescriptor(avfactory->zone())) { set_language_mode(LanguageMode::kStrict); - DeclareThis(ast_value_factory); + DeclareThis(avfactory); } ModuleScope::ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info, AstValueFactory* avfactory) - : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info) { - Zone* zone = avfactory->zone(); - Handle<ModuleInfo> module_info(scope_info->ModuleDescriptorInfo(), isolate); - + : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info), + module_descriptor_(nullptr) { set_language_mode(LanguageMode::kStrict); - module_descriptor_ = new (zone) ModuleDescriptor(zone); - - // Deserialize special exports. - Handle<FixedArray> special_exports(module_info->special_exports(), isolate); - for (int i = 0, n = special_exports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> serialized_entry( - ModuleInfoEntry::cast(special_exports->get(i)), isolate); - module_descriptor_->AddSpecialExport( - ModuleDescriptor::Entry::Deserialize(isolate, avfactory, - serialized_entry), - avfactory->zone()); - } - - // Deserialize regular exports. - module_descriptor_->DeserializeRegularExports(isolate, avfactory, - module_info); - - // Deserialize namespace imports. - Handle<FixedArray> namespace_imports(module_info->namespace_imports(), - isolate); - for (int i = 0, n = namespace_imports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> serialized_entry( - ModuleInfoEntry::cast(namespace_imports->get(i)), isolate); - module_descriptor_->AddNamespaceImport( - ModuleDescriptor::Entry::Deserialize(isolate, avfactory, - serialized_entry), - avfactory->zone()); - } - - // Deserialize regular imports. - Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); - for (int i = 0, n = regular_imports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> serialized_entry( - ModuleInfoEntry::cast(regular_imports->get(i)), isolate); - module_descriptor_->AddRegularImport(ModuleDescriptor::Entry::Deserialize( - isolate, avfactory, serialized_entry)); - } } Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) @@ -262,8 +198,11 @@ void DeclarationScope::SetDefaults() { force_eager_compilation_ = false; has_arguments_parameter_ = false; scope_uses_super_property_ = false; + has_checked_syntax_ = false; + has_this_reference_ = false; + has_this_declaration_ = + (is_function_scope() && !is_arrow_scope()) || is_module_scope(); has_rest_ = false; - sloppy_block_function_map_ = nullptr; receiver_ = nullptr; new_target_ = nullptr; function_ = nullptr; @@ -319,10 +258,6 @@ bool Scope::HasSimpleParameters() { return !scope->is_function_scope() || scope->has_simple_parameters(); } -bool DeclarationScope::ShouldEagerCompile() const { - return force_eager_compilation_ || should_eager_compile_; -} - void DeclarationScope::set_should_eager_compile() { should_eager_compile_ = !was_lazily_parsed_; } @@ -359,15 +294,16 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, Scope* outer_scope = nullptr; while (!scope_info.is_null()) { if (scope_info->scope_type() == WITH_SCOPE) { - // For scope analysis, debug-evaluate is equivalent to a with scope. - outer_scope = - new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate)); - - // TODO(yangguo): Remove once debug-evaluate properly keeps track of the - // function scope in which we are evaluating. if (scope_info->IsDebugEvaluateScope()) { + outer_scope = new (zone) + DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info, isolate)); outer_scope->set_is_debug_evaluate_scope(); + } else { + // For scope analysis, debug-evaluate is equivalent to a with scope. + outer_scope = + new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate)); } + } else if (scope_info->scope_type() == SCRIPT_SCOPE) { // If we reach a script scope, it's the outermost scope. Install the // scope info of this script context onto the existing script scope to @@ -455,19 +391,9 @@ const ModuleScope* Scope::AsModuleScope() const { return static_cast<const ModuleScope*>(this); } -int Scope::num_parameters() const { - return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; -} - void DeclarationScope::DeclareSloppyBlockFunction( - const AstRawString* name, Scope* scope, - SloppyBlockFunctionStatement* statement) { - if (sloppy_block_function_map_ == nullptr) { - sloppy_block_function_map_ = - new (zone()->New(sizeof(SloppyBlockFunctionMap))) - SloppyBlockFunctionMap(zone()); - } - sloppy_block_function_map_->Declare(zone(), name, scope, statement); + SloppyBlockFunctionStatement* sloppy_block_function) { + sloppy_block_functions_.Add(sloppy_block_function); } void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { @@ -477,8 +403,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_); DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_); - SloppyBlockFunctionMap* map = sloppy_block_function_map(); - if (map == nullptr) return; + if (sloppy_block_functions_.is_empty()) return; // In case of complex parameters the current scope is the body scope and the // parameters are stored in the outer scope. @@ -486,14 +411,17 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { DCHECK(parameter_scope->is_function_scope() || is_eval_scope() || is_script_scope()); - // The declarations need to be added in the order they were seen, - // so accumulate declared names sorted by index. - ZoneMap<int, const AstRawString*> names_to_declare(zone()); + DeclarationScope* decl_scope = this; + while (decl_scope->is_eval_scope()) { + decl_scope = decl_scope->outer_scope()->GetDeclarationScope(); + } + Scope* outer_scope = decl_scope->outer_scope(); // For each variable which is used as a function declaration in a sloppy // block, - for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { - const AstRawString* name = static_cast<AstRawString*>(p->key); + for (SloppyBlockFunctionStatement* sloppy_block_function : + sloppy_block_functions_) { + const AstRawString* name = sloppy_block_function->name(); // If the variable wouldn't conflict with a lexical declaration // or parameter, @@ -504,79 +432,52 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { continue; } - bool declaration_queued = false; - - // Write in assignments to var for each block-scoped function declaration - auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value); - - DeclarationScope* decl_scope = this; - while (decl_scope->is_eval_scope()) { - decl_scope = decl_scope->outer_scope()->GetDeclarationScope(); - } - Scope* outer_scope = decl_scope->outer_scope(); - - for (SloppyBlockFunctionMap::Delegate* delegate = delegates; - delegate != nullptr; delegate = delegate->next()) { - // Check if there's a conflict with a lexical declaration - Scope* query_scope = delegate->scope()->outer_scope(); - Variable* var = nullptr; - bool should_hoist = true; - - // Note that we perform this loop for each delegate named 'name', - // which may duplicate work if those delegates share scopes. - // It is not sufficient to just do a Lookup on query_scope: for - // example, that does not prevent hoisting of the function in - // `{ let e; try {} catch (e) { function e(){} } }` - do { - var = query_scope->LookupInScopeOrScopeInfo(name); - if (var != nullptr && IsLexicalVariableMode(var->mode())) { - should_hoist = false; - break; - } - query_scope = query_scope->outer_scope(); - } while (query_scope != outer_scope); - - if (!should_hoist) continue; - - if (!declaration_queued) { - declaration_queued = true; - names_to_declare.insert({delegate->index(), name}); - } - - if (factory) { - DCHECK(!is_being_lazily_parsed_); - int pos = delegate->position(); - Assignment* assignment = factory->NewAssignment( - Token::ASSIGN, NewUnresolved(factory, name, pos), - delegate->scope()->NewUnresolved(factory, name, pos), pos); - assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy); - Statement* statement = factory->NewExpressionStatement(assignment, pos); - delegate->set_statement(statement); + // Check if there's a conflict with a lexical declaration + Scope* query_scope = sloppy_block_function->scope()->outer_scope(); + Variable* var = nullptr; + bool should_hoist = true; + + // It is not sufficient to just do a Lookup on query_scope: for + // example, that does not prevent hoisting of the function in + // `{ let e; try {} catch (e) { function e(){} } }` + do { + var = query_scope->LookupInScopeOrScopeInfo(name); + if (var != nullptr && IsLexicalVariableMode(var->mode())) { + should_hoist = false; + break; } - } - } + query_scope = query_scope->outer_scope(); + } while (query_scope != outer_scope); - if (names_to_declare.empty()) return; + if (!should_hoist) continue; - for (const auto& index_and_name : names_to_declare) { - const AstRawString* name = index_and_name.second; if (factory) { DCHECK(!is_being_lazily_parsed_); - VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE); - auto declaration = factory->NewVariableDeclaration(kNoSourcePosition); + int pos = sloppy_block_function->position(); + bool ok = true; bool was_added; + auto declaration = factory->NewVariableDeclaration(pos); // Based on the preceding checks, it doesn't matter what we pass as // sloppy_mode_block_scope_function_redefinition. - bool ok = true; - DeclareVariable(declaration, proxy, VariableMode::kVar, NORMAL_VARIABLE, - Variable::DefaultInitializationFlag(VariableMode::kVar), - &was_added, nullptr, &ok); + Variable* var = DeclareVariable( + declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE, + Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added, + nullptr, &ok); DCHECK(ok); + VariableProxy* source = + factory->NewVariableProxy(sloppy_block_function->var()); + VariableProxy* target = factory->NewVariableProxy(var); + Assignment* assignment = factory->NewAssignment( + sloppy_block_function->init(), target, source, pos); + assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy); + Statement* statement = factory->NewExpressionStatement(assignment, pos); + sloppy_block_function->set_statement(statement); } else { DCHECK(is_being_lazily_parsed_); bool was_added; Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added); - var->set_maybe_assigned(); + if (sloppy_block_function->init() == Token::ASSIGN) + var->set_maybe_assigned(); } } } @@ -605,8 +506,7 @@ bool DeclarationScope::Analyze(ParseInfo* info) { // 1) top-level code, // 2) a function/eval/module on the top-level // 3) a function/eval in a scope that was already resolved. - DCHECK(scope->scope_type() == SCRIPT_SCOPE || - scope->outer_scope()->scope_type() == SCRIPT_SCOPE || + DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() || scope->outer_scope()->already_resolved_); // The outer scope is never lazy. @@ -633,20 +533,16 @@ bool DeclarationScope::Analyze(ParseInfo* info) { } void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) { - DCHECK(!already_resolved_); - DCHECK(is_declaration_scope()); DCHECK(has_this_declaration()); bool derived_constructor = IsDerivedConstructor(function_kind_); - bool was_added; - Variable* var = - Declare(zone(), ast_value_factory->this_string(), - derived_constructor ? VariableMode::kConst : VariableMode::kVar, - THIS_VARIABLE, - derived_constructor ? kNeedsInitialization : kCreatedInitialized, - kNotAssigned, &was_added); - DCHECK(was_added); - receiver_ = var; + + receiver_ = new (zone()) + Variable(this, ast_value_factory->this_string(), + derived_constructor ? VariableMode::kConst : VariableMode::kVar, + THIS_VARIABLE, + derived_constructor ? kNeedsInitialization : kCreatedInitialized, + kNotAssigned); } void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) { @@ -844,8 +740,9 @@ void Scope::ReplaceOuterScope(Scope* outer) { Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { DCHECK(!scope_info_.is_null()); DCHECK_NULL(cache->variables_.Lookup(name)); + DisallowHeapAllocation no_gc; - Handle<String> name_handle = name->string(); + String name_handle = *name->string(); // The Scope is backed up by ScopeInfo. This means it cannot operate in a // heap-independent mode, and all strings must be internalized immediately. So // it's ok to get the Handle<String> here. @@ -859,12 +756,12 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { { location = VariableLocation::CONTEXT; - index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, + index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, &init_flag, &maybe_assigned_flag); found = index >= 0; } - if (!found && scope_type() == MODULE_SCOPE) { + if (!found && is_module_scope()) { location = VariableLocation::MODULE; index = scope_info_->ModuleIndex(name_handle, &mode, &init_flag, &maybe_assigned_flag); @@ -872,7 +769,7 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { } if (!found) { - index = scope_info_->FunctionContextSlotIndex(*name_handle); + index = scope_info_->FunctionContextSlotIndex(name_handle); if (index < 0) return nullptr; // Nowhere found. Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache); DCHECK_EQ(VariableMode::kConst, var->mode()); @@ -880,18 +777,14 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { return cache->variables_.Lookup(name); } - VariableKind kind = NORMAL_VARIABLE; - if (location == VariableLocation::CONTEXT && - index == scope_info_->ReceiverContextSlotIndex()) { - kind = THIS_VARIABLE; + if (!is_module_scope()) { + DCHECK_NE(index, scope_info_->ReceiverContextSlotIndex()); } - // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and - // ARGUMENTS bindings as their corresponding VariableKind. bool was_added; Variable* var = - cache->variables_.Declare(zone(), this, name, mode, kind, init_flag, - maybe_assigned_flag, &was_added); + cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE, + init_flag, maybe_assigned_flag, &was_added); DCHECK(was_added); var->AllocateTo(location, index); return var; @@ -953,15 +846,29 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, mode == VariableMode::kVar || mode == VariableMode::kLet || mode == VariableMode::kConst); DCHECK(!GetDeclarationScope()->was_lazily_parsed()); - return Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added); + Variable* var = + Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added); + + // Pessimistically assume that top-level variables will be assigned and used. + // + // Top-level variables in a script can be accessed by other scripts or even + // become global properties. While this does not apply to top-level variables + // in a module (assuming they are not exported), we must still mark these as + // assigned because they might be accessed by a lazily parsed top-level + // function, which, for efficiency, we preparse without variable tracking. + if (is_script_scope() || is_module_scope()) { + if (mode != VariableMode::kConst) var->set_maybe_assigned(); + var->set_is_used(); + } + + return var; } -// TODO(leszeks): Avoid passing the proxy into here, passing the raw_name alone -// instead. Variable* Scope::DeclareVariable( - Declaration* declaration, VariableProxy* proxy, VariableMode mode, - VariableKind kind, InitializationFlag init, bool* was_added, - bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { + Declaration* declaration, const AstRawString* name, int pos, + VariableMode mode, VariableKind kind, InitializationFlag init, + bool* was_added, bool* sloppy_mode_block_scope_function_redefinition, + bool* ok) { DCHECK(IsDeclaredVariableMode(mode)); DCHECK(!already_resolved_); DCHECK(!GetDeclarationScope()->is_being_lazily_parsed()); @@ -969,7 +876,7 @@ Variable* Scope::DeclareVariable( if (mode == VariableMode::kVar && !is_declaration_scope()) { return GetDeclarationScope()->DeclareVariable( - declaration, proxy, mode, kind, init, was_added, + declaration, name, pos, mode, kind, init, was_added, sloppy_mode_block_scope_function_redefinition, ok); } DCHECK(!is_catch_scope()); @@ -977,19 +884,7 @@ Variable* Scope::DeclareVariable( DCHECK(is_declaration_scope() || (IsLexicalVariableMode(mode) && is_block_scope())); - DCHECK_NOT_NULL(proxy->raw_name()); - const AstRawString* name = proxy->raw_name(); - - // Pessimistically assume that top-level variables will be assigned. - // - // Top-level variables in a script can be accessed by other scripts or even - // become global properties. While this does not apply to top-level variables - // in a module (assuming they are not exported), we must still mark these as - // assigned because they might be accessed by a lazily parsed top-level - // function, which, for efficiency, we preparse without variable tracking. - if (is_script_scope() || is_module_scope()) { - if (mode != VariableMode::kConst) proxy->set_is_assigned(); - } + DCHECK_NOT_NULL(name); Variable* var = LookupLocal(name); // Declare the variable in the declaration scope. @@ -1002,7 +897,9 @@ Variable* Scope::DeclareVariable( // The proxy is bound to a lookup variable to force a dynamic declaration // using the DeclareEvalVar or DeclareEvalFunction runtime functions. DCHECK_EQ(NORMAL_VARIABLE, kind); - var = NonLocal(proxy->raw_name(), VariableMode::kDynamic); + var = NonLocal(name, VariableMode::kDynamic); + // Mark the var as used in case anyone outside the eval wants to use it. + var->set_is_used(); } else { // Declare the name. var = DeclareLocal(name, mode, kind, was_added, init); @@ -1029,16 +926,9 @@ Variable* Scope::DeclareVariable( // In harmony we treat re-declarations as early errors. See ES5 16 for a // definition of early errors. // - // Allow duplicate function decls for web compat, see bug 4693. If the - // duplication is allowed, then the var will show up in the - // SloppyBlockFunctionMap. - SloppyBlockFunctionMap* map = - GetDeclarationScope()->sloppy_block_function_map(); - *ok = - map != nullptr && declaration->IsFunctionDeclaration() && - declaration->AsFunctionDeclaration() - ->declares_sloppy_block_function() && - map->Lookup(const_cast<AstRawString*>(name), name->Hash()) != nullptr; + // Allow duplicate function decls for web compat, see bug 4693. + *ok = var->is_sloppy_block_function() && + kind == SLOPPY_BLOCK_FUNCTION_VARIABLE; *sloppy_mode_block_scope_function_redefinition = *ok; } } @@ -1055,7 +945,6 @@ Variable* Scope::DeclareVariable( // lead to repeated DeclareEvalVar or DeclareEvalFunction calls. decls_.Add(declaration); declaration->set_var(var); - proxy->BindTo(var); return var; } @@ -1079,12 +968,16 @@ Variable* Scope::DeclareVariableName(const AstRawString* name, Variable* var = DeclareLocal(name, mode, kind, was_added); if (!*was_added) { if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) { - // Duplicate functions are allowed in the sloppy mode, but if this is not - // a function declaration, it's an error. This is an error PreParser - // hasn't previously detected. - return nullptr; + if (!var->is_sloppy_block_function() || + kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) { + // Duplicate functions are allowed in the sloppy mode, but if this is + // not a function declaration, it's an error. This is an error PreParser + // hasn't previously detected. + return nullptr; + } + // Sloppy block function redefinition. } - if (mode == VariableMode::kVar) var->set_maybe_assigned(); + var->set_maybe_assigned(); } var->set_is_used(); return var; @@ -1142,36 +1035,61 @@ Variable* Scope::NewTemporary(const AstRawString* name, return var; } -Declaration* Scope::CheckConflictingVarDeclarations() { +Declaration* DeclarationScope::CheckConflictingVarDeclarations() { + if (has_checked_syntax_) return nullptr; for (Declaration* decl : decls_) { // Lexical vs lexical conflicts within the same scope have already been // captured in Parser::Declare. The only conflicts we still need to check // are lexical vs nested var. - Scope* current = nullptr; if (decl->IsVariableDeclaration() && decl->AsVariableDeclaration()->AsNested() != nullptr) { - current = decl->AsVariableDeclaration()->AsNested()->scope(); - } else if (is_eval_scope() && is_sloppy(language_mode())) { - if (IsLexicalVariableMode(decl->var()->mode())) continue; - current = outer_scope_; + Scope* current = decl->AsVariableDeclaration()->AsNested()->scope(); + DCHECK(decl->var()->mode() == VariableMode::kVar || + decl->var()->mode() == VariableMode::kDynamic); + // Iterate through all scopes until the declaration scope. + do { + // There is a conflict if there exists a non-VAR binding. + if (current->is_catch_scope()) { + current = current->outer_scope(); + continue; + } + Variable* other_var = current->LookupLocal(decl->var()->raw_name()); + if (other_var != nullptr) { + DCHECK(IsLexicalVariableMode(other_var->mode())); + return decl; + } + current = current->outer_scope(); + } while (current != this); } - if (current == nullptr) continue; - DCHECK(decl->var()->mode() == VariableMode::kVar || - decl->var()->mode() == VariableMode::kDynamic); + } + + if (V8_LIKELY(!is_eval_scope())) return nullptr; + if (!is_sloppy(language_mode())) return nullptr; + + // Var declarations in sloppy eval are hoisted to the first non-eval + // declaration scope. Check for conflicts between the eval scope that + // declaration scope. + Scope* end = this; + do { + end = end->outer_scope_->GetDeclarationScope(); + } while (end->is_eval_scope()); + end = end->outer_scope_; + + for (Declaration* decl : decls_) { + if (IsLexicalVariableMode(decl->var()->mode())) continue; + Scope* current = outer_scope_; // Iterate through all scopes until and including the declaration scope. - while (true) { - // There is a conflict if there exists a non-VAR binding. + do { + // There is a conflict if there exists a non-VAR binding up to the + // declaration scope in which this sloppy-eval runs. Variable* other_var = current->LookupInScopeOrScopeInfo(decl->var()->raw_name()); if (other_var != nullptr && IsLexicalVariableMode(other_var->mode())) { + DCHECK(!current->is_catch_scope()); return decl; } - if (current->is_declaration_scope() && - !(current->is_eval_scope() && is_sloppy(current->language_mode()))) { - break; - } current = current->outer_scope(); - } + } while (current != end); } return nullptr; } @@ -1188,6 +1106,21 @@ const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope, return nullptr; } +void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) { + if (is_script_scope()) { + DCHECK_NOT_NULL(receiver_); + return; + } + DCHECK(has_this_declaration()); + DeclareThis(ast_value_factory); + if (is_debug_evaluate_scope()) { + receiver_->AllocateTo(VariableLocation::LOOKUP, -1); + } else { + receiver_->AllocateTo(VariableLocation::CONTEXT, + scope_info_->ReceiverContextSlotIndex()); + } +} + bool DeclarationScope::AllocateVariables(ParseInfo* info) { // Module variables must be allocated before variable resolution // to ensure that UpdateNeedsHoleCheck() can detect import variables. @@ -1197,11 +1130,28 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) { DCHECK(info->pending_error_handler()->has_pending_error()); return false; } - AllocateVariablesRecursively(); + + // // Don't allocate variables of preparsed scopes. + if (!was_lazily_parsed()) AllocateVariablesRecursively(); return true; } +bool Scope::HasThisReference() const { + if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) { + return true; + } + + for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { + if (!scope->is_declaration_scope() || + !scope->AsDeclarationScope()->has_this_declaration()) { + if (scope->HasThisReference()) return true; + } + } + + return false; +} + bool Scope::AllowsLazyParsingWithoutUnresolvedVariables( const Scope* outer) const { // If none of the outer scopes need to decide whether to context allocate @@ -1227,7 +1177,10 @@ bool Scope::AllowsLazyParsingWithoutUnresolvedVariables( } bool DeclarationScope::AllowsLazyCompilation() const { - return !force_eager_compilation_; + // Functions which force eager compilation and class member initializer + // functions are not lazily compilable. + return !force_eager_compilation_ && + !IsClassMembersInitializerFunction(function_kind()); } int Scope::ContextChainLength(Scope* scope) const { @@ -1294,9 +1247,9 @@ bool Scope::ShouldBanArguments() { DeclarationScope* Scope::GetReceiverScope() { Scope* scope = this; - while (!scope->is_script_scope() && - (!scope->is_function_scope() || - scope->AsDeclarationScope()->is_arrow_scope())) { + while (!scope->is_declaration_scope() || + (!scope->is_script_scope() && + !scope->AsDeclarationScope()->has_this_declaration())) { scope = scope->outer_scope(); } return scope->AsDeclarationScope(); @@ -1310,77 +1263,103 @@ Scope* Scope::GetOuterScopeWithContext() { return scope; } -void Scope::CollectNonLocals(DeclarationScope* max_outer_scope, - Isolate* isolate, ParseInfo* info, - Handle<StringSet>* non_locals) { - // Module variables must be allocated before variable resolution - // to ensure that UpdateNeedsHoleCheck() can detect import variables. - if (is_module_scope()) AsModuleScope()->AllocateModuleVariables(); +namespace { +bool WasLazilyParsed(Scope* scope) { + return scope->is_declaration_scope() && + scope->AsDeclarationScope()->was_lazily_parsed(); +} - // 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_) { - DCHECK(!proxy->is_resolved()); - Variable* var = - Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope()); - if (var == nullptr) { - *non_locals = StringSet::Add(isolate, *non_locals, proxy->name()); +} // namespace + +template <typename FunctionType> +void Scope::ForEach(FunctionType callback) { + Scope* scope = this; + while (true) { + Iteration iteration = callback(scope); + // Try to descend into inner scopes first. + if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) { + scope = scope->inner_scope_; } else { - // 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(); + // Find the next outer scope with a sibling. + while (scope->sibling_ == nullptr) { + if (scope == this) return; + scope = scope->outer_scope_; + } + if (scope == this) return; + scope = scope->sibling_; } } +} - // Clear unresolved_list_ as it's in an inconsistent state. - unresolved_list_.Clear(); +void Scope::CollectNonLocals(DeclarationScope* max_outer_scope, + Isolate* isolate, ParseInfo* info, + Handle<StringSet>* non_locals) { + this->ForEach([max_outer_scope, isolate, info, non_locals](Scope* scope) { + // Module variables must be allocated before variable resolution + // to ensure that UpdateNeedsHoleCheck() can detect import variables. + if (scope->is_module_scope()) { + scope->AsModuleScope()->AllocateModuleVariables(); + } - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - scope->CollectNonLocals(max_outer_scope, isolate, info, non_locals); - } + // 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 = WasLazilyParsed(scope) ? scope->outer_scope() : scope; + + for (VariableProxy* proxy : scope->unresolved_list_) { + DCHECK(!proxy->is_resolved()); + Variable* var = + Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope()); + if (var == nullptr) { + *non_locals = StringSet::Add(isolate, *non_locals, proxy->name()); + } else { + // 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. + scope->ResolveTo(info, proxy, var); + if (!var->is_dynamic() && lookup != scope) + var->ForceContextAllocation(); + } + } + + // Clear unresolved_list_ as it's in an inconsistent state. + scope->unresolved_list_.Clear(); + return Iteration::kDescend; + }); } void Scope::AnalyzePartially(DeclarationScope* max_outer_scope, AstNodeFactory* ast_node_factory, UnresolvedList* new_unresolved_list) { - DCHECK_IMPLIES(is_declaration_scope(), - !AsDeclarationScope()->was_lazily_parsed()); - - for (VariableProxy* proxy = unresolved_list_.first(); proxy != nullptr; - proxy = proxy->next_unresolved()) { - DCHECK(!proxy->is_resolved()); - Variable* var = - Lookup<kParsedScope>(proxy, this, max_outer_scope->outer_scope()); - if (var == nullptr) { - // Don't copy unresolved references to the script scope, unless it's a - // reference to a private name or method. In that case keep it so we - // can fail later. - if (!max_outer_scope->outer_scope()->is_script_scope() || - proxy->IsPrivateName()) { - VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); - new_unresolved_list->Add(copy); + this->ForEach([max_outer_scope, ast_node_factory, + new_unresolved_list](Scope* scope) { + DCHECK_IMPLIES(scope->is_declaration_scope(), + !scope->AsDeclarationScope()->was_lazily_parsed()); + + for (VariableProxy* proxy = scope->unresolved_list_.first(); + proxy != nullptr; proxy = proxy->next_unresolved()) { + DCHECK(!proxy->is_resolved()); + Variable* var = + Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope()); + if (var == nullptr) { + // Don't copy unresolved references to the script scope, unless it's a + // reference to a private name or method. In that case keep it so we + // can fail later. + if (!max_outer_scope->outer_scope()->is_script_scope() || + proxy->IsPrivateName()) { + VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); + new_unresolved_list->Add(copy); + } + } else { + var->set_is_used(); + if (proxy->is_assigned()) var->set_maybe_assigned(); } - } 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->AnalyzePartially(max_outer_scope, ast_node_factory, - new_unresolved_list); - } + // Clear unresolved_list_ as it's in an inconsistent state. + scope->unresolved_list_.Clear(); + return Iteration::kDescend; + }); } Handle<StringSet> DeclarationScope::CollectNonLocals( @@ -1399,7 +1378,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, locals_.Clear(); inner_scope_ = nullptr; unresolved_list_.Clear(); - sloppy_block_function_map_ = nullptr; + sloppy_block_functions_.Clear(); rare_data_ = nullptr; has_rest_ = false; @@ -1428,14 +1407,25 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, was_lazily_parsed_ = !aborted; } -void Scope::SavePreparseData(Parser* parser) { - if (PreparseDataBuilder::ScopeIsSkippableFunctionScope(this)) { - AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser); - } +bool Scope::IsSkippableFunctionScope() { + // Lazy non-arrow function scopes are skippable. Lazy functions are exactly + // those Scopes which have their own PreparseDataBuilder object. This + // logic ensures that the scope allocation data is consistent with the + // skippable function data (both agree on where the lazy function boundaries + // are). + if (!is_function_scope()) return false; + DeclarationScope* declaration_scope = AsDeclarationScope(); + return !declaration_scope->is_arrow_scope() && + declaration_scope->preparse_data_builder() != nullptr; +} - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - scope->SavePreparseData(parser); - } +void Scope::SavePreparseData(Parser* parser) { + this->ForEach([parser](Scope* scope) { + if (scope->IsSkippableFunctionScope()) { + scope->AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser); + } + return Iteration::kDescend; + }); } void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) { @@ -1685,27 +1675,26 @@ void Scope::Print(int n) { } void Scope::CheckScopePositions() { - // Visible leaf scopes must have real positions. - if (!is_hidden() && inner_scope_ == nullptr) { - DCHECK_NE(kNoSourcePosition, start_position()); - DCHECK_NE(kNoSourcePosition, end_position()); - } - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - scope->CheckScopePositions(); - } + this->ForEach([](Scope* scope) { + // Visible leaf scopes must have real positions. + if (!scope->is_hidden() && scope->inner_scope_ == nullptr) { + DCHECK_NE(kNoSourcePosition, scope->start_position()); + DCHECK_NE(kNoSourcePosition, scope->end_position()); + } + return Iteration::kDescend; + }); } void Scope::CheckZones() { DCHECK(!needs_migration_); - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - if (scope->is_declaration_scope() && - scope->AsDeclarationScope()->was_lazily_parsed()) { + this->ForEach([](Scope* scope) { + if (WasLazilyParsed(scope)) { DCHECK_NULL(scope->zone()); DCHECK_NULL(scope->inner_scope_); - continue; + return Iteration::kContinue; } - scope->CheckZones(); - } + return Iteration::kDescend; + }); } #endif // DEBUG @@ -1803,16 +1792,6 @@ template Variable* Scope::Lookup<Scope::kDeserializedScope>( VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, Scope* entry_point, bool force_context_allocation); -namespace { -bool CanBeShadowed(Scope* scope, Variable* var) { - if (var == nullptr) return false; - - // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. - // TODO(wingo): There are other variables in this category; add them. - return !var->is_this(); -} -}; // namespace - Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, Scope* entry_point, bool force_context_allocation) { @@ -1825,7 +1804,7 @@ Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope, : Lookup<kDeserializedScope>(proxy, scope->outer_scope_, outer_scope_end, entry_point); - if (!CanBeShadowed(scope, var)) return var; + if (var == nullptr) return var; // The current scope is a with scope, so the variable binding can not be // statically resolved. However, note that it was necessary to do a lookup @@ -1859,7 +1838,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope, nullptr, force_context_allocation) : Lookup<kDeserializedScope>(proxy, scope->outer_scope_, outer_scope_end, entry); - if (!CanBeShadowed(scope, var)) return var; + if (var == nullptr) return var; // A variable binding may have been found in an outer scope, but the current // scope makes a sloppy 'eval' call, so the found variable may not be the @@ -1949,12 +1928,6 @@ void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { return SetNeedsHoleCheck(var, proxy); } - if (var->is_this()) { - DCHECK(IsDerivedConstructor(scope->GetClosureScope()->function_kind())); - // TODO(littledan): implement 'this' hole check elimination. - return SetNeedsHoleCheck(var, proxy); - } - // We should always have valid source positions. DCHECK_NE(var->initializer_position(), kNoSourcePosition); DCHECK_NE(proxy->position(), kNoSourcePosition); @@ -1994,16 +1967,50 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { proxy->BindTo(var); } +bool Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope, + Scope* end) { + // Resolve the variable in all parsed scopes to force context allocation. + for (; scope != end; scope = scope->outer_scope_) { + Variable* var = scope->LookupLocal(proxy->raw_name()); + if (var != nullptr) { + var->set_is_used(); + if (!var->is_dynamic()) { + var->ForceContextAllocation(); + if (proxy->is_assigned()) var->set_maybe_assigned(); + } + return true; + } + } + + if (!proxy->IsPrivateName()) return true; + + // If we're resolving a private name, throw an exception of we didn't manage + // to resolve. In case of eval, also look in all outer scope-info backed + // scopes except for the script scope. Don't throw an exception if a reference + // was found. + Scope* start = scope; + for (; !scope->is_script_scope(); scope = scope->outer_scope_) { + if (scope->LookupInScopeInfo(proxy->raw_name(), start) != nullptr) { + return true; + } + } + + return false; +} + bool Scope::ResolveVariablesRecursively(ParseInfo* info) { DCHECK(info->script_scope()->is_script_scope()); // Lazy parsed declaration scopes are already partially analyzed. If there are // unresolved references remaining, they just need to be resolved in outer // scopes. - if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { + if (WasLazilyParsed(this)) { DCHECK_EQ(variables_.occupancy(), 0); + Scope* end = info->scope(); + // Resolve in all parsed scopes except for the script scope. + if (!end->is_script_scope()) end = end->outer_scope(); + for (VariableProxy* proxy : unresolved_list_) { - Variable* var = Lookup<kParsedScope>(proxy, outer_scope(), nullptr); - if (var == nullptr) { + if (!ResolvePreparsedVariable(proxy, outer_scope(), end)) { info->pending_error_handler()->ReportMessageAt( proxy->position(), proxy->position() + 1, MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name(), @@ -2011,11 +2018,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) { DCHECK(proxy->IsPrivateName()); return false; } - if (!var->is_dynamic()) { - var->set_is_used(); - var->ForceContextAllocation(); - if (proxy->is_assigned()) var->set_maybe_assigned(); - } } } else { // Resolve unresolved variables for this scope. @@ -2037,7 +2039,7 @@ bool Scope::MustAllocate(Variable* var) { // Give var a read/write use if there is a chance it might be accessed // via an eval() call. This is only possible if the variable has a // visible name. - if ((var->is_this() || !var->raw_name()->IsEmpty()) && + if (!var->raw_name()->IsEmpty() && (inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) { var->set_is_used(); if (inner_scope_calls_eval_) var->set_maybe_assigned(); @@ -2118,18 +2120,15 @@ void DeclarationScope::AllocateParameterLocals() { } void DeclarationScope::AllocateParameter(Variable* var, int index) { - if (MustAllocate(var)) { - if (has_forced_context_allocation_for_parameters() || - MustAllocateInContext(var)) { - DCHECK(var->IsUnallocated() || var->IsContextSlot()); - if (var->IsUnallocated()) { - AllocateHeapSlot(var); - } - } else { - DCHECK(var->IsUnallocated() || var->IsParameter()); - if (var->IsUnallocated()) { - var->AllocateTo(VariableLocation::PARAMETER, index); - } + if (!MustAllocate(var)) return; + if (has_forced_context_allocation_for_parameters() || + MustAllocateInContext(var)) { + DCHECK(var->IsUnallocated() || var->IsContextSlot()); + if (var->IsUnallocated()) AllocateHeapSlot(var); + } else { + DCHECK(var->IsUnallocated() || var->IsParameter()); + if (var->IsUnallocated()) { + var->AllocateTo(VariableLocation::PARAMETER, index); } } } @@ -2142,7 +2141,7 @@ void DeclarationScope::AllocateReceiver() { } void Scope::AllocateNonParameterLocal(Variable* var) { - DCHECK(var->scope() == this); + DCHECK_EQ(var->scope(), this); if (var->IsUnallocated() && MustAllocate(var)) { if (MustAllocateInContext(var)) { AllocateHeapSlot(var); @@ -2201,51 +2200,47 @@ void ModuleScope::AllocateModuleVariables() { } void Scope::AllocateVariablesRecursively() { - DCHECK(!already_resolved_); - - // Don't allocate variables of preparsed scopes. - if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { - return; - } - - // Allocate variables for inner scopes. - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - scope->AllocateVariablesRecursively(); - } - - DCHECK(!already_resolved_); - DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); + this->ForEach([](Scope* scope) -> Iteration { + DCHECK(!scope->already_resolved_); + if (WasLazilyParsed(scope)) return Iteration::kContinue; + DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope->num_heap_slots_); + + // Allocate variables for this scope. + // Parameters must be allocated first, if any. + if (scope->is_declaration_scope()) { + if (scope->is_function_scope()) { + scope->AsDeclarationScope()->AllocateParameterLocals(); + } + scope->AsDeclarationScope()->AllocateReceiver(); + } + scope->AllocateNonParameterLocalsAndDeclaredGlobals(); + + // Force allocation of a context for this scope if necessary. For a 'with' + // scope and for a function scope that makes an 'eval' call we need a + // context, even if no local variables were statically allocated in the + // scope. Likewise for modules and function scopes representing asm.js + // modules. Also force a context, if the scope is stricter than the outer + // scope. + bool must_have_context = + scope->is_with_scope() || scope->is_module_scope() || + scope->IsAsmModule() || scope->ForceContextForLanguageMode() || + (scope->is_function_scope() && + scope->AsDeclarationScope()->calls_sloppy_eval()) || + (scope->is_block_scope() && scope->is_declaration_scope() && + scope->AsDeclarationScope()->calls_sloppy_eval()); - // Allocate variables for this scope. - // Parameters must be allocated first, if any. - if (is_declaration_scope()) { - if (is_function_scope()) { - AsDeclarationScope()->AllocateParameterLocals(); + // If we didn't allocate any locals in the local context, then we only + // need the minimal number of slots if we must have a context. + if (scope->num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && + !must_have_context) { + scope->num_heap_slots_ = 0; } - AsDeclarationScope()->AllocateReceiver(); - } - AllocateNonParameterLocalsAndDeclaredGlobals(); - - // Force allocation of a context for this scope if necessary. For a 'with' - // scope and for a function scope that makes an 'eval' call we need a context, - // even if no local variables were statically allocated in the scope. - // Likewise for modules and function scopes representing asm.js modules. - // Also force a context, if the scope is stricter than the outer scope. - bool must_have_context = - is_with_scope() || is_module_scope() || IsAsmModule() || - ForceContextForLanguageMode() || - (is_function_scope() && AsDeclarationScope()->calls_sloppy_eval()) || - (is_block_scope() && is_declaration_scope() && - AsDeclarationScope()->calls_sloppy_eval()); - - // If we didn't allocate any locals in the local context, then we only - // need the minimal number of slots if we must have a context. - if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) { - num_heap_slots_ = 0; - } - - // Allocation done. - DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); + + // Allocation done. + DCHECK(scope->num_heap_slots_ == 0 || + scope->num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); + return Iteration::kDescend; + }); } void Scope::AllocateScopeInfosRecursively(Isolate* isolate, diff --git a/chromium/v8/src/ast/scopes.h b/chromium/v8/src/ast/scopes.h index 971cfc519b0..732d759757f 100644 --- a/chromium/v8/src/ast/scopes.h +++ b/chromium/v8/src/ast/scopes.h @@ -8,6 +8,8 @@ #include "src/ast/ast.h" #include "src/base/compiler-specific.h" #include "src/base/hashmap.h" +#include "src/base/threaded-list.h" +#include "src/function-kind.h" #include "src/globals.h" #include "src/objects.h" #include "src/pointer-with-payload.h" @@ -43,37 +45,6 @@ class VariableMap: public ZoneHashMap { void Add(Zone* zone, Variable* var); }; - -// Sloppy block-scoped function declarations to var-bind -class SloppyBlockFunctionMap : public ZoneHashMap { - public: - class Delegate : public ZoneObject { - public: - Delegate(Scope* scope, SloppyBlockFunctionStatement* statement, int index) - : scope_(scope), statement_(statement), next_(nullptr), index_(index) {} - void set_statement(Statement* statement); - - void set_next(Delegate* next) { next_ = next; } - Delegate* next() const { return next_; } - Scope* scope() const { return scope_; } - int index() const { return index_; } - int position() const { return statement_->position(); } - - private: - Scope* scope_; - SloppyBlockFunctionStatement* statement_; - Delegate* next_; - int index_; - }; - - explicit SloppyBlockFunctionMap(Zone* zone); - void Declare(Zone* zone, const AstRawString* name, Scope* scope, - SloppyBlockFunctionStatement* statement); - - private: - int count_; -}; - class Scope; template <> @@ -111,9 +82,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { typedef base::ThreadedList<VariableProxy, VariableProxy::UnresolvedNext> UnresolvedList; - // TODO(verwaest): Is this needed on Scope? - int num_parameters() const; - DeclarationScope* AsDeclarationScope(); const DeclarationScope* AsDeclarationScope() const; ModuleScope* AsModuleScope(); @@ -225,8 +193,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { VariableKind kind, bool* was_added, InitializationFlag init_flag = kCreatedInitialized); - Variable* DeclareVariable(Declaration* declaration, VariableProxy* proxy, - VariableMode mode, VariableKind kind, + Variable* DeclareVariable(Declaration* declaration, const AstRawString* name, + int pos, VariableMode mode, VariableKind kind, InitializationFlag init, bool* was_added, bool* sloppy_mode_block_scope_function_redefinition, bool* ok); @@ -280,14 +248,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // TODO(verwaest): Move to DeclarationScope? Variable* NewTemporary(const AstRawString* name); - // --------------------------------------------------------------------------- - // Illegal redeclaration support. - - // Check if the scope has conflicting var - // declarations, i.e. a var declaration that has been hoisted from a nested - // scope over a let binding of the same name. - Declaration* CheckConflictingVarDeclarations(); - // Find variable with (variable->mode() <= |mode_limit|) that was declared in // |scope|. This is used to catch patterns like `try{}catch(e){let e;}` and // function([e]) { let e }, which are errors even though the two 'e's are each @@ -421,6 +381,33 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { return num_heap_slots() > 0; } + // Use Scope::ForEach for depth first traversal of scopes. + // Before: + // void Scope::VisitRecursively() { + // DoSomething(); + // for (Scope* s = inner_scope_; s != nullptr; s = s->sibling_) { + // if (s->ShouldContinue()) continue; + // s->VisitRecursively(); + // } + // } + // + // After: + // void Scope::VisitIteratively() { + // this->ForEach([](Scope* s) { + // s->DoSomething(); + // return s->ShouldContinue() ? kContinue : kDescend; + // }); + // } + template <typename FunctionType> + V8_INLINE void ForEach(FunctionType callback); + enum Iteration { + // Continue the iteration on the same level, do not recurse/descent into + // inner scopes. + kContinue, + // Recurse/descend into inner scopes. + kDescend + }; + // --------------------------------------------------------------------------- // Accessors. @@ -488,6 +475,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Find the innermost outer scope that needs a context. Scope* GetOuterScopeWithContext(); + bool HasThisReference() const; + // Analyze() must have been called once to create the ScopeInfo. Handle<ScopeInfo> scope_info() const { DCHECK(!scope_info_.is_null()); @@ -513,6 +502,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { bool HasSimpleParameters(); void set_is_debug_evaluate_scope() { is_debug_evaluate_scope_ = true; } bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; } + bool IsSkippableFunctionScope(); bool RemoveInnerScope(Scope* inner_scope) { DCHECK_NOT_NULL(inner_scope); @@ -599,6 +589,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { static Variable* LookupSloppyEval(VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, Scope* entry_point, bool force_context_allocation); + static bool ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope, + Scope* end); void ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var); V8_WARN_UNUSED_RESULT bool ResolveVariable(ParseInfo* info, VariableProxy* proxy); @@ -618,14 +610,15 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Variable allocation. void AllocateStackSlot(Variable* var); - void AllocateHeapSlot(Variable* var); + V8_INLINE void AllocateHeapSlot(Variable* var); void AllocateNonParameterLocal(Variable* var); void AllocateDeclaredGlobal(Variable* var); - void AllocateNonParameterLocalsAndDeclaredGlobals(); + V8_INLINE void AllocateNonParameterLocalsAndDeclaredGlobals(); void AllocateVariablesRecursively(); void AllocateScopeInfosRecursively(Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope); + void AllocateDebuggerScopeInfos(Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope); @@ -766,6 +759,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { return var; } + void DeserializeReceiver(AstValueFactory* ast_value_factory); + #ifdef DEBUG void set_is_being_lazily_parsed(bool is_being_lazily_parsed) { is_being_lazily_parsed_ = is_being_lazily_parsed; @@ -779,7 +774,23 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { zone_ = zone; } - bool ShouldEagerCompile() const; + // --------------------------------------------------------------------------- + // Illegal redeclaration support. + + // Check if the scope has conflicting var + // declarations, i.e. a var declaration that has been hoisted from a nested + // scope over a let binding of the same name. + Declaration* CheckConflictingVarDeclarations(); + + void set_has_checked_syntax(bool has_checked_syntax) { + has_checked_syntax_ = has_checked_syntax; + } + bool has_checked_syntax() const { return has_checked_syntax_; } + + bool ShouldEagerCompile() const { + return force_eager_compilation_ || should_eager_compile_; + } + void set_should_eager_compile(); void SetScriptScopeInfo(Handle<ScopeInfo> scope_info) { @@ -833,17 +844,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // The variable corresponding to the 'this' value. Variable* receiver() { - DCHECK(has_this_declaration()); + DCHECK(has_this_declaration() || is_script_scope()); DCHECK_NOT_NULL(receiver_); return receiver_; } - // TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate - // "this" (and no other variable) on the native context. Script scopes then - // will not have a "this" declaration. - bool has_this_declaration() const { - return (is_function_scope() && !is_arrow_scope()) || is_module_scope(); - } + bool has_this_declaration() const { return has_this_declaration_; } // The variable corresponding to the 'new.target' value. Variable* new_target_var() { return new_target_; } @@ -935,17 +941,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { void AddLocal(Variable* var); void DeclareSloppyBlockFunction( - const AstRawString* name, Scope* scope, - SloppyBlockFunctionStatement* statement = nullptr); + SloppyBlockFunctionStatement* sloppy_block_function); - // Go through sloppy_block_function_map_ and hoist those (into this scope) + // Go through sloppy_block_functions_ and hoist those (into this scope) // which should be hoisted. void HoistSloppyBlockFunctions(AstNodeFactory* factory); - SloppyBlockFunctionMap* sloppy_block_function_map() { - return sloppy_block_function_map_; - } - // Compute top scope and allocate variables. For lazy compilation the top // scope only contains the single lazily compiled function, so this // doesn't re-allocate variables repeatedly. @@ -988,9 +989,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { void PrintParameters(); #endif - void AllocateLocals(); - void AllocateParameterLocals(); - void AllocateReceiver(); + V8_INLINE void AllocateLocals(); + V8_INLINE void AllocateParameterLocals(); + V8_INLINE void AllocateReceiver(); void ResetAfterPreparsing(AstValueFactory* ast_value_factory, bool aborted); @@ -1020,8 +1021,15 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { return preparse_data_builder_; } + void set_has_this_reference() { has_this_reference_ = true; } + bool has_this_reference() const { return has_this_reference_; } + void UsesThis() { + set_has_this_reference(); + GetReceiverScope()->receiver()->ForceContextAllocation(); + } + private: - void AllocateParameter(Variable* var, int index); + V8_INLINE void AllocateParameter(Variable* var, int index); // Resolve and fill in the allocation information for all variables // in this scopes. Must be called *after* all scopes have been @@ -1055,16 +1063,19 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { #endif bool is_skipped_function_ : 1; bool has_inferred_function_name_ : 1; - - int num_parameters_ = 0; + bool has_checked_syntax_ : 1; + bool has_this_reference_ : 1; + bool has_this_declaration_ : 1; // If the scope is a function scope, this is the function kind. const FunctionKind function_kind_; + int num_parameters_ = 0; + // Parameter list in source order. ZonePtrList<Variable> params_; // Map of function names to lists of functions defined in sloppy blocks - SloppyBlockFunctionMap* sloppy_block_function_map_; + base::ThreadedList<SloppyBlockFunctionStatement> sloppy_block_functions_; // Convenience variable. Variable* receiver_; // Function variable, if any; function scopes only. @@ -1128,27 +1139,21 @@ Scope::Snapshot::Snapshot(Scope* scope) class ModuleScope final : public DeclarationScope { public: - ModuleScope(DeclarationScope* script_scope, - AstValueFactory* ast_value_factory); + ModuleScope(DeclarationScope* script_scope, AstValueFactory* avfactory); - // Deserialization. - // The generated ModuleDescriptor does not preserve all information. In - // particular, its module_requests map will be empty because we no longer need - // the map after parsing. + // Deserialization. Does not restore the module descriptor. ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info, - AstValueFactory* ast_value_factory); + AstValueFactory* avfactory); - ModuleDescriptor* module() const { - DCHECK_NOT_NULL(module_descriptor_); - return module_descriptor_; - } + // Returns nullptr in a deserialized scope. + ModuleDescriptor* module() const { return module_descriptor_; } // Set MODULE as VariableLocation for all variables that will live in a // module's export table. void AllocateModuleVariables(); private: - ModuleDescriptor* module_descriptor_; + ModuleDescriptor* const module_descriptor_; }; } // namespace internal diff --git a/chromium/v8/src/ast/source-range-ast-visitor.cc b/chromium/v8/src/ast/source-range-ast-visitor.cc index 442b23718c0..d171e305875 100644 --- a/chromium/v8/src/ast/source-range-ast-visitor.cc +++ b/chromium/v8/src/ast/source-range-ast-visitor.cc @@ -56,7 +56,18 @@ void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange( if (statements->is_empty()) return; Statement* last_statement = statements->last(); - AstNodeSourceRanges* last_range = source_range_map_->Find(last_statement); + AstNodeSourceRanges* last_range = nullptr; + + if (last_statement->IsExpressionStatement() && + last_statement->AsExpressionStatement()->expression()->IsThrow()) { + // For ThrowStatement, source range is tied to Throw expression not + // ExpressionStatement. + last_range = source_range_map_->Find( + last_statement->AsExpressionStatement()->expression()); + } else { + last_range = source_range_map_->Find(last_statement); + } + if (last_range == nullptr) return; if (last_range->HasRange(SourceRangeKind::kContinuation)) { diff --git a/chromium/v8/src/ast/variables.h b/chromium/v8/src/ast/variables.h index 13a444536dd..6dbb9dbac48 100644 --- a/chromium/v8/src/ast/variables.h +++ b/chromium/v8/src/ast/variables.h @@ -6,6 +6,7 @@ #define V8_AST_VARIABLES_H_ #include "src/ast/ast-value-factory.h" +#include "src/base/threaded-list.h" #include "src/globals.h" #include "src/zone/zone.h" @@ -59,7 +60,7 @@ class Variable final : public ZoneObject { return ForceContextAllocationField::decode(bit_field_); } void ForceContextAllocation() { - DCHECK(IsUnallocated() || IsContextSlot() || + DCHECK(IsUnallocated() || IsContextSlot() || IsLookupSlot() || location() == VariableLocation::MODULE); bit_field_ = ForceContextAllocationField::update(bit_field_, true); } @@ -137,6 +138,9 @@ class Variable final : public ZoneObject { } bool is_parameter() const { return kind() == PARAMETER_VARIABLE; } + bool is_sloppy_block_function() { + return kind() == SLOPPY_BLOCK_FUNCTION_VARIABLE; + } Variable* local_if_not_shadowed() const { DCHECK(mode() == VariableMode::kDynamicLocal && @@ -207,7 +211,7 @@ class Variable final : public ZoneObject { class VariableModeField : public BitField16<VariableMode, 0, 3> {}; class VariableKindField - : public BitField16<VariableKind, VariableModeField::kNext, 2> {}; + : public BitField16<VariableKind, VariableModeField::kNext, 3> {}; class LocationField : public BitField16<VariableLocation, VariableKindField::kNext, 3> {}; class ForceContextAllocationField |