diff options
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r-- | deps/v8/src/ast/ast-traversal-visitor.h | 6 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.cc | 12 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.h | 291 | ||||
-rw-r--r-- | deps/v8/src/ast/modules.cc | 7 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.cc | 80 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.h | 8 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.cc | 165 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.h | 95 | ||||
-rw-r--r-- | deps/v8/src/ast/source-range-ast-visitor.cc | 8 | ||||
-rw-r--r-- | deps/v8/src/ast/source-range-ast-visitor.h | 1 | ||||
-rw-r--r-- | deps/v8/src/ast/variables.h | 58 |
11 files changed, 441 insertions, 290 deletions
diff --git a/deps/v8/src/ast/ast-traversal-visitor.h b/deps/v8/src/ast/ast-traversal-visitor.h index b4836ff784..2796e59a8d 100644 --- a/deps/v8/src/ast/ast-traversal-visitor.h +++ b/deps/v8/src/ast/ast-traversal-visitor.h @@ -383,6 +383,12 @@ void AstTraversalVisitor<Subclass>::VisitThrow(Throw* expr) { } template <class Subclass> +void AstTraversalVisitor<Subclass>::VisitOptionalChain(OptionalChain* expr) { + PROCESS_EXPRESSION(expr); + RECURSE_EXPRESSION(Visit(expr->expression())); +} + +template <class Subclass> void AstTraversalVisitor<Subclass>::VisitProperty(Property* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->obj())); diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc index 9987eb2844..4b6c4805de 100644 --- a/deps/v8/src/ast/ast.cc +++ b/deps/v8/src/ast/ast.cc @@ -122,6 +122,10 @@ bool Expression::IsUndefinedLiteral() const { var_proxy->raw_name()->IsOneByteEqualTo("undefined"); } +bool Expression::IsLiteralButNotNullOrUndefined() const { + return IsLiteral() && !IsNullOrUndefinedLiteral(); +} + bool Expression::ToBooleanIsTrue() const { return IsLiteral() && AsLiteral()->ToBooleanIsTrue(); } @@ -217,13 +221,7 @@ bool FunctionLiteral::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 && + return language_mode() == LanguageMode::kStrict && scope()->arguments() == nullptr && scope()->rest_parameter() == nullptr; } diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index bd52d1b2c0..ced9f775dd 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -16,6 +16,7 @@ #include "src/common/globals.h" #include "src/execution/isolate.h" #include "src/heap/factory.h" +#include "src/objects/function-syntax-kind.h" #include "src/objects/literal-objects.h" #include "src/objects/smi.h" #include "src/parsing/token.h" @@ -94,6 +95,7 @@ namespace internal { V(ImportCallExpression) \ V(Literal) \ V(NativeFunctionLiteral) \ + V(OptionalChain) \ V(Property) \ V(ResolvedProperty) \ V(Spread) \ @@ -168,11 +170,13 @@ class AstNode: public ZoneObject { void* operator new(size_t size); int position_; - class NodeTypeField : public BitField<NodeType, 0, 6> {}; + using NodeTypeField = BitField<NodeType, 0, 6>; protected: uint32_t bit_field_; - static const uint8_t kNextBitFieldIndex = NodeTypeField::kNext; + + template <class T, int size> + using NextBitField = NodeTypeField::Next<T, size>; AstNode(int position, NodeType type) : position_(position), bit_field_(NodeTypeField::encode(type)) {} @@ -182,8 +186,6 @@ class AstNode: public ZoneObject { class Statement : public AstNode { protected: Statement(int position, NodeType type) : AstNode(position, type) {} - - static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex; }; @@ -245,6 +247,14 @@ class Expression : public AstNode { // that this also checks for loads of the global "undefined" variable. bool IsUndefinedLiteral() const; + // True if either null literal or undefined literal. + inline bool IsNullOrUndefinedLiteral() const { + return IsNullLiteral() || IsUndefinedLiteral(); + } + + // True if a literal and not null or undefined. + bool IsLiteralButNotNullOrUndefined() const; + bool IsCompileTimeValue(); bool IsPattern() { @@ -265,15 +275,15 @@ class Expression : public AstNode { } private: - class IsParenthesizedField - : public BitField<bool, AstNode::kNextBitFieldIndex, 1> {}; + using IsParenthesizedField = AstNode::NextBitField<bool, 1>; protected: Expression(int pos, NodeType type) : AstNode(pos, type) { DCHECK(!is_parenthesized()); } - static const uint8_t kNextBitFieldIndex = IsParenthesizedField::kNext; + template <class T, int size> + using NextBitField = IsParenthesizedField::Next<T, size>; }; class FailureExpression : public Expression { @@ -321,8 +331,7 @@ class BreakableStatement : public Statement { } private: - class BreakableTypeField - : public BitField<BreakableType, Statement::kNextBitFieldIndex, 1> {}; + using BreakableTypeField = Statement::NextBitField<BreakableType, 1>; protected: BreakableStatement(BreakableType breakable_type, int position, NodeType type) @@ -330,7 +339,8 @@ class BreakableStatement : public Statement { bit_field_ |= BreakableTypeField::encode(breakable_type); } - static const uint8_t kNextBitFieldIndex = BreakableTypeField::kNext; + template <class T, int size> + using NextBitField = BreakableTypeField::Next<T, size>; }; class Block : public BreakableStatement { @@ -357,10 +367,8 @@ class Block : public BreakableStatement { ZonePtrList<Statement> statements_; Scope* scope_; - class IgnoreCompletionField - : public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {}; - class IsLabeledField - : public BitField<bool, IgnoreCompletionField::kNext, 1> {}; + using IgnoreCompletionField = BreakableStatement::NextBitField<bool, 1>; + using IsLabeledField = IgnoreCompletionField::Next<bool, 1>; protected: Block(Zone* zone, ZonePtrList<const AstRawString>* labels, int capacity, @@ -448,8 +456,7 @@ class VariableDeclaration : public Declaration { private: friend class AstNodeFactory; - class IsNestedField - : public BitField<bool, Declaration::kNextBitFieldIndex, 1> {}; + using IsNestedField = Declaration::NextBitField<bool, 1>; protected: explicit VariableDeclaration(int pos, bool is_nested = false) @@ -457,7 +464,8 @@ class VariableDeclaration : public Declaration { bit_field_ = IsNestedField::update(bit_field_, is_nested); } - static const uint8_t kNextBitFieldIndex = IsNestedField::kNext; + template <class T, int size> + using NextBitField = IsNestedField::Next<T, size>; }; // For var declarations that appear in a block scope. @@ -524,9 +532,6 @@ class IterationStatement : public BreakableStatement { body_(nullptr) {} void Initialize(Statement* body) { body_ = body; } - static const uint8_t kNextBitFieldIndex = - BreakableStatement::kNextBitFieldIndex; - private: ZonePtrList<const AstRawString>* labels_; ZonePtrList<const AstRawString>* own_labels_; @@ -740,8 +745,7 @@ class ReturnStatement final : public JumpStatement { Expression* expression_; int end_position_; - class TypeField - : public BitField<Type, JumpStatement::kNextBitFieldIndex, 1> {}; + using TypeField = JumpStatement::NextBitField<Type, 1>; }; @@ -977,8 +981,7 @@ class SloppyBlockFunctionStatement final : public Statement { private: friend class AstNodeFactory; - class TokenField - : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {}; + using TokenField = Statement::NextBitField<Token::Value, 8>; SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init, Statement* statement) @@ -1079,7 +1082,7 @@ class Literal final : public Expression { private: friend class AstNodeFactory; - class TypeField : public BitField<Type, Expression::kNextBitFieldIndex, 4> {}; + using TypeField = Expression::NextBitField<Type, 4>; Literal(int smi, int position) : Expression(position, kLiteral), smi_(smi) { bit_field_ = TypeField::update(bit_field_, kSmi); @@ -1210,10 +1213,9 @@ class AggregateLiteral : public MaterializedLiteral { private: int depth_ : 31; - class NeedsInitialAllocationSiteField - : public BitField<bool, MaterializedLiteral::kNextBitFieldIndex, 1> {}; - class IsSimpleField - : public BitField<bool, NeedsInitialAllocationSiteField::kNext, 1> {}; + using NeedsInitialAllocationSiteField = + MaterializedLiteral::NextBitField<bool, 1>; + using IsSimpleField = NeedsInitialAllocationSiteField::Next<bool, 1>; protected: friend class AstNodeFactory; @@ -1236,7 +1238,8 @@ class AggregateLiteral : public MaterializedLiteral { bit_field_ = NeedsInitialAllocationSiteField::update(bit_field_, required); } - static const uint8_t kNextBitFieldIndex = IsSimpleField::kNext; + template <class T, int size> + using NextBitField = IsSimpleField::Next<T, size>; }; // Common supertype for ObjectLiteralProperty and ClassLiteralProperty @@ -1375,12 +1378,6 @@ class ObjectLiteral final : public AggregateLiteral { static_cast<int>(AggregateLiteral::kNeedsInitialAllocationSite) < static_cast<int>(kFastElements)); - struct Accessors: public ZoneObject { - Accessors() : getter(nullptr), setter(nullptr) {} - ObjectLiteralProperty* getter; - ObjectLiteralProperty* setter; - }; - private: friend class AstNodeFactory; @@ -1408,19 +1405,14 @@ class ObjectLiteral final : public AggregateLiteral { void set_has_null_protoype(bool has_null_prototype) { bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype); } - uint32_t boilerplate_properties_; Handle<ObjectBoilerplateDescription> boilerplate_description_; ZoneList<Property*> properties_; - class HasElementsField - : public BitField<bool, AggregateLiteral::kNextBitFieldIndex, 1> {}; - class HasRestPropertyField - : public BitField<bool, HasElementsField::kNext, 1> {}; - class FastElementsField - : public BitField<bool, HasRestPropertyField::kNext, 1> {}; - class HasNullPrototypeField - : public BitField<bool, FastElementsField::kNext, 1> {}; + using HasElementsField = AggregateLiteral::NextBitField<bool, 1>; + using HasRestPropertyField = HasElementsField::Next<bool, 1>; + using FastElementsField = HasRestPropertyField::Next<bool, 1>; + using HasNullPrototypeField = FastElementsField::Next<bool, 1>; }; // An array literal has a literals object that is used @@ -1512,6 +1504,9 @@ class VariableProxy final : public Expression { var()->SetMaybeAssigned(); } } + void clear_is_assigned() { + bit_field_ = IsAssignedField::update(bit_field_, false); + } bool is_resolved() const { return IsResolvedField::decode(bit_field_); } void set_is_resolved() { @@ -1586,15 +1581,11 @@ class VariableProxy final : public Expression { explicit VariableProxy(const VariableProxy* copy_from); - class IsAssignedField - : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; - class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {}; - class IsRemovedFromUnresolvedField - : public BitField<bool, IsResolvedField::kNext, 1> {}; - class IsNewTargetField - : public BitField<bool, IsRemovedFromUnresolvedField::kNext, 1> {}; - class HoleCheckModeField - : public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {}; + using IsAssignedField = Expression::NextBitField<bool, 1>; + using IsResolvedField = IsAssignedField::Next<bool, 1>; + using IsRemovedFromUnresolvedField = IsResolvedField::Next<bool, 1>; + using IsNewTargetField = IsRemovedFromUnresolvedField::Next<bool, 1>; + using HoleCheckModeField = IsNewTargetField::Next<HoleCheckMode, 1>; union { const AstRawString* raw_name_; // if !is_resolved_ @@ -1607,20 +1598,41 @@ class VariableProxy final : public Expression { friend base::ThreadedListTraits<VariableProxy>; }; +// Wraps an optional chain to provide a wrapper for jump labels. +class OptionalChain final : public Expression { + public: + Expression* expression() const { return expression_; } + + private: + friend class AstNodeFactory; + + explicit OptionalChain(Expression* expression) + : Expression(0, kOptionalChain), expression_(expression) {} + + Expression* expression_; +}; + // Assignments to a property will use one of several types of property access. // Otherwise, the assignment is to a non-property (a global, a local slot, a // parameter slot, or a destructuring pattern). enum AssignType { - NON_PROPERTY, // destructuring - NAMED_PROPERTY, // obj.key - KEYED_PROPERTY, // obj[key] - NAMED_SUPER_PROPERTY, // super.key - KEYED_SUPER_PROPERTY, // super[key] - PRIVATE_METHOD // obj.#key: #key is a private method + NON_PROPERTY, // destructuring + NAMED_PROPERTY, // obj.key + KEYED_PROPERTY, // obj[key] + NAMED_SUPER_PROPERTY, // super.key + KEYED_SUPER_PROPERTY, // super[key] + PRIVATE_METHOD, // obj.#key: #key is a private method + PRIVATE_GETTER_ONLY, // obj.#key: #key only has a getter defined + PRIVATE_SETTER_ONLY, // obj.#key: #key only has a setter defined + PRIVATE_GETTER_AND_SETTER // obj.#key: #key has both accessors defined }; class Property final : public Expression { public: + bool is_optional_chain_link() const { + return IsOptionalChainLinkField::decode(bit_field_); + } + bool IsValidReferenceExpression() const { return true; } Expression* obj() const { return obj_; } @@ -1637,8 +1649,21 @@ class Property final : public Expression { VariableProxy* proxy = property->key()->AsVariableProxy(); DCHECK_NOT_NULL(proxy); Variable* var = proxy->var(); - // Use KEYED_PROPERTY for private fields. - return var->requires_brand_check() ? PRIVATE_METHOD : KEYED_PROPERTY; + + switch (var->mode()) { + case VariableMode::kPrivateMethod: + return PRIVATE_METHOD; + case VariableMode::kConst: + return KEYED_PROPERTY; // Use KEYED_PROPERTY for private fields. + case VariableMode::kPrivateGetterOnly: + return PRIVATE_GETTER_ONLY; + case VariableMode::kPrivateSetterOnly: + return PRIVATE_SETTER_ONLY; + case VariableMode::kPrivateGetterAndSetter: + return PRIVATE_GETTER_AND_SETTER; + default: + UNREACHABLE(); + } } bool super_access = property->IsSuperAccess(); return (property->key()->IsPropertyName()) @@ -1649,10 +1674,13 @@ class Property final : public Expression { private: friend class AstNodeFactory; - Property(Expression* obj, Expression* key, int pos) + Property(Expression* obj, Expression* key, int pos, bool optional_chain) : Expression(pos, kProperty), obj_(obj), key_(key) { + bit_field_ |= IsOptionalChainLinkField::encode(optional_chain); } + using IsOptionalChainLinkField = Expression::NextBitField<bool, 1>; + Expression* obj_; Expression* key_; }; @@ -1690,6 +1718,10 @@ class Call final : public Expression { return IsTaggedTemplateField::decode(bit_field_); } + bool is_optional_chain_link() const { + return IsOptionalChainLinkField::decode(bit_field_); + } + bool only_last_arg_is_spread() { return !arguments_.is_empty() && arguments_.last()->IsSpread(); } @@ -1722,13 +1754,14 @@ class Call final : public Expression { Call(Zone* zone, Expression* expression, const ScopedPtrList<Expression>& arguments, int pos, - PossiblyEval possibly_eval) + PossiblyEval possibly_eval, bool optional_chain) : Expression(pos, kCall), expression_(expression), arguments_(0, nullptr) { bit_field_ |= IsPossiblyEvalField::encode(possibly_eval == IS_POSSIBLY_EVAL) | - IsTaggedTemplateField::encode(false); + IsTaggedTemplateField::encode(false) | + IsOptionalChainLinkField::encode(optional_chain); arguments.CopyTo(&arguments_, zone); } @@ -1739,14 +1772,14 @@ class Call final : public Expression { expression_(expression), arguments_(0, nullptr) { bit_field_ |= IsPossiblyEvalField::encode(false) | - IsTaggedTemplateField::encode(true); + IsTaggedTemplateField::encode(true) | + IsOptionalChainLinkField::encode(false); arguments.CopyTo(&arguments_, zone); } - class IsPossiblyEvalField - : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; - class IsTaggedTemplateField - : public BitField<bool, IsPossiblyEvalField::kNext, 1> {}; + using IsPossiblyEvalField = Expression::NextBitField<bool, 1>; + using IsTaggedTemplateField = IsPossiblyEvalField::Next<bool, 1>; + using IsOptionalChainLinkField = IsTaggedTemplateField::Next<bool, 1>; Expression* expression_; ZonePtrList<Expression> arguments_; @@ -1838,8 +1871,7 @@ class UnaryOperation final : public Expression { Expression* expression_; - class OperatorField - : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; + using OperatorField = Expression::NextBitField<Token::Value, 7>; }; @@ -1865,8 +1897,7 @@ class BinaryOperation final : public Expression { Expression* left_; Expression* right_; - class OperatorField - : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; + using OperatorField = Expression::NextBitField<Token::Value, 7>; }; class NaryOperation final : public Expression { @@ -1925,8 +1956,7 @@ class NaryOperation final : public Expression { }; ZoneVector<NaryOperationEntry> subsequent_; - class OperatorField - : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; + using OperatorField = Expression::NextBitField<Token::Value, 7>; }; class CountOperation final : public Expression { @@ -1946,9 +1976,8 @@ class CountOperation final : public Expression { bit_field_ |= IsPrefixField::encode(is_prefix) | TokenField::encode(op); } - class IsPrefixField - : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; - class TokenField : public BitField<Token::Value, IsPrefixField::kNext, 7> {}; + using IsPrefixField = Expression::NextBitField<bool, 1>; + using TokenField = IsPrefixField::Next<Token::Value, 7>; Expression* expression_; }; @@ -1978,8 +2007,7 @@ class CompareOperation final : public Expression { Expression* left_; Expression* right_; - class OperatorField - : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; + using OperatorField = Expression::NextBitField<Token::Value, 7>; }; @@ -2071,10 +2099,8 @@ class Assignment : public Expression { private: friend class AstNodeFactory; - class TokenField - : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; - class LookupHoistingModeField : public BitField<bool, TokenField::kNext, 1> { - }; + using TokenField = Expression::NextBitField<Token::Value, 7>; + using LookupHoistingModeField = TokenField::Next<bool, 1>; Expression* target_; Expression* value_; @@ -2132,8 +2158,7 @@ class Suspend : public Expression { Expression* expression_; - class OnAbruptResumeField - : public BitField<OnAbruptResume, Expression::kNextBitFieldIndex, 1> {}; + using OnAbruptResumeField = Expression::NextBitField<OnAbruptResume, 1>; }; class Yield final : public Suspend { @@ -2175,14 +2200,6 @@ class Throw final : public Expression { class FunctionLiteral final : public Expression { public: - enum FunctionType { - kAnonymousExpression, - kNamedExpression, - kDeclaration, - kAccessorOrMethod, - kWrapped, - }; - enum ParameterFlag : uint8_t { kNoDuplicateParameters, kHasDuplicateParameters @@ -2204,12 +2221,8 @@ class FunctionLiteral final : public Expression { int function_token_position() const { return function_token_position_; } int start_position() const; int end_position() const; - bool is_declaration() const { return function_type() == kDeclaration; } - bool is_named_expression() const { - return function_type() == kNamedExpression; - } bool is_anonymous_expression() const { - return function_type() == kAnonymousExpression; + return syntax_kind() == FunctionSyntaxKind::kAnonymousExpression; } void mark_as_oneshot_iife() { @@ -2219,7 +2232,6 @@ class FunctionLiteral final : public Expression { bool is_toplevel() const { return function_literal_id() == kFunctionLiteralIdTopLevel; } - bool is_wrapped() const { return function_type() == kWrapped; } V8_EXPORT_PRIVATE LanguageMode language_mode() const; static bool NeedsHomeObject(Expression* expr); @@ -2289,8 +2301,8 @@ class FunctionLiteral final : public Expression { V8_EXPORT_PRIVATE bool ShouldEagerCompile() const; V8_EXPORT_PRIVATE void SetShouldEagerCompile(); - FunctionType function_type() const { - return FunctionTypeBits::decode(bit_field_); + FunctionSyntaxKind syntax_kind() const { + return FunctionSyntaxKindBits::decode(bit_field_); } FunctionKind kind() const; @@ -2342,7 +2354,7 @@ class FunctionLiteral final : public Expression { AstValueFactory* ast_value_factory, DeclarationScope* scope, const ScopedPtrList<Statement>& body, int expected_property_count, int parameter_count, - int function_length, FunctionType function_type, + int function_length, FunctionSyntaxKind function_syntax_kind, ParameterFlag has_duplicate_parameters, EagerCompileHint eager_compile_hint, int position, bool has_braces, int function_literal_id, @@ -2359,28 +2371,28 @@ class FunctionLiteral final : public Expression { body_(0, nullptr), raw_inferred_name_(ast_value_factory->empty_cons_string()), produced_preparse_data_(produced_preparse_data) { - bit_field_ |= - FunctionTypeBits::encode(function_type) | Pretenure::encode(false) | - HasDuplicateParameters::encode(has_duplicate_parameters == - kHasDuplicateParameters) | - DontOptimizeReasonField::encode(BailoutReason::kNoReason) | - RequiresInstanceMembersInitializer::encode(false) | - HasBracesField::encode(has_braces) | OneshotIIFEBit::encode(false); + bit_field_ |= FunctionSyntaxKindBits::encode(function_syntax_kind) | + Pretenure::encode(false) | + HasDuplicateParameters::encode(has_duplicate_parameters == + kHasDuplicateParameters) | + DontOptimizeReasonField::encode(BailoutReason::kNoReason) | + RequiresInstanceMembersInitializer::encode(false) | + HasBracesField::encode(has_braces) | + OneshotIIFEBit::encode(false); if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile(); body.CopyTo(&body_, zone); } - class FunctionTypeBits - : public BitField<FunctionType, Expression::kNextBitFieldIndex, 3> {}; - class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {}; - class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {}; - class DontOptimizeReasonField - : public BitField<BailoutReason, HasDuplicateParameters::kNext, 8> {}; - class RequiresInstanceMembersInitializer - : public BitField<bool, DontOptimizeReasonField::kNext, 1> {}; - class HasBracesField - : public BitField<bool, RequiresInstanceMembersInitializer::kNext, 1> {}; - class OneshotIIFEBit : public BitField<bool, HasBracesField::kNext, 1> {}; + using FunctionSyntaxKindBits = + Expression::NextBitField<FunctionSyntaxKind, 3>; + using Pretenure = FunctionSyntaxKindBits::Next<bool, 1>; + using HasDuplicateParameters = Pretenure::Next<bool, 1>; + using DontOptimizeReasonField = + HasDuplicateParameters::Next<BailoutReason, 8>; + using RequiresInstanceMembersInitializer = + DontOptimizeReasonField::Next<bool, 1>; + using HasBracesField = RequiresInstanceMembersInitializer::Next<bool, 1>; + using OneshotIIFEBit = HasBracesField::Next<bool, 1>; // expected_property_count_ is the sum of instance fields and properties. // It can vary depending on whether a function is lazily or eagerly parsed. @@ -2432,6 +2444,11 @@ class ClassLiteralProperty final : public LiteralProperty { return private_or_computed_name_var_; } + bool NeedsHomeObjectOnClassPrototype() const { + return is_private() && kind_ == METHOD && + FunctionLiteral::NeedsHomeObject(value_); + } + private: friend class AstNodeFactory; @@ -2525,12 +2542,9 @@ class ClassLiteral final : public Expression { ZonePtrList<Property>* properties_; FunctionLiteral* static_fields_initializer_; FunctionLiteral* instance_members_initializer_function_; - class HasNameStaticProperty - : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; - class HasStaticComputedNames - : public BitField<bool, HasNameStaticProperty::kNext, 1> {}; - class IsAnonymousExpression - : public BitField<bool, HasStaticComputedNames::kNext, 1> {}; + using HasNameStaticProperty = Expression::NextBitField<bool, 1>; + using HasStaticComputedNames = HasNameStaticProperty::Next<bool, 1>; + using IsAnonymousExpression = HasStaticComputedNames::Next<bool, 1>; }; @@ -3046,8 +3060,13 @@ class AstNodeFactory final { return new (zone_) Variable(variable); } - Property* NewProperty(Expression* obj, Expression* key, int pos) { - return new (zone_) Property(obj, key, pos); + OptionalChain* NewOptionalChain(Expression* expression) { + return new (zone_) OptionalChain(expression); + } + + Property* NewProperty(Expression* obj, Expression* key, int pos, + bool optional_chain = false) { + return new (zone_) Property(obj, key, pos, optional_chain); } ResolvedProperty* NewResolvedProperty(VariableProxy* obj, @@ -3058,8 +3077,10 @@ class AstNodeFactory final { Call* NewCall(Expression* expression, const ScopedPtrList<Expression>& arguments, int pos, - Call::PossiblyEval possibly_eval = Call::NOT_EVAL) { - return new (zone_) Call(zone_, expression, arguments, pos, possibly_eval); + Call::PossiblyEval possibly_eval = Call::NOT_EVAL, + bool optional_chain = false) { + return new (zone_) + Call(zone_, expression, arguments, pos, possibly_eval, optional_chain); } Call* NewTaggedTemplate(Expression* expression, @@ -3189,13 +3210,13 @@ class AstNodeFactory final { const ScopedPtrList<Statement>& body, int expected_property_count, int parameter_count, int function_length, FunctionLiteral::ParameterFlag has_duplicate_parameters, - FunctionLiteral::FunctionType function_type, + FunctionSyntaxKind function_syntax_kind, FunctionLiteral::EagerCompileHint eager_compile_hint, int position, bool has_braces, int function_literal_id, ProducedPreparseData* produced_preparse_data = nullptr) { return new (zone_) FunctionLiteral( zone_, name, ast_value_factory_, scope, body, expected_property_count, - parameter_count, function_length, function_type, + parameter_count, function_length, function_syntax_kind, has_duplicate_parameters, eager_compile_hint, position, has_braces, function_literal_id, produced_preparse_data); } @@ -3209,7 +3230,7 @@ class AstNodeFactory final { return new (zone_) FunctionLiteral( zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope, body, expected_property_count, parameter_count, parameter_count, - FunctionLiteral::kAnonymousExpression, + FunctionSyntaxKind::kAnonymousExpression, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false, kFunctionLiteralIdTopLevel); diff --git a/deps/v8/src/ast/modules.cc b/deps/v8/src/ast/modules.cc index 261b72c352..dbd20f50a8 100644 --- a/deps/v8/src/ast/modules.cc +++ b/deps/v8/src/ast/modules.cc @@ -84,10 +84,11 @@ void SourceTextModuleDescriptor::AddStarExport( } namespace { -Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) { +Handle<HeapObject> ToStringOrUndefined(Isolate* isolate, + const AstRawString* s) { return (s == nullptr) - ? Handle<Object>::cast(isolate->factory()->undefined_value()) - : Handle<Object>::cast(s->string()); + ? Handle<HeapObject>::cast(isolate->factory()->undefined_value()) + : Handle<HeapObject>::cast(s->string()); } } // namespace diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc index c0fe3baff3..581517ee4e 100644 --- a/deps/v8/src/ast/prettyprinter.cc +++ b/deps/v8/src/ast/prettyprinter.cc @@ -27,6 +27,8 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) is_call_error_ = false; is_iterator_error_ = false; is_async_iterator_error_ = false; + destructuring_prop_ = nullptr; + destructuring_assignment_ = nullptr; is_user_js_ = is_user_js; function_kind_ = kNormalFunction; InitializeAstVisitor(isolate); @@ -299,24 +301,50 @@ void CallPrinter::VisitVariableProxy(VariableProxy* node) { void CallPrinter::VisitAssignment(Assignment* node) { - Find(node->target()); - if (node->target()->IsArrayLiteral()) { - // Special case the visit for destructuring array assignment. - bool was_found = false; - if (node->value()->position() == position_) { - is_iterator_error_ = true; + bool was_found = false; + if (node->target()->IsObjectLiteral()) { + ObjectLiteral* target = node->target()->AsObjectLiteral(); + if (target->position() == position_) { was_found = !found_; - if (was_found) { - found_ = true; + found_ = true; + destructuring_assignment_ = node; + } else { + for (ObjectLiteralProperty* prop : *target->properties()) { + if (prop->value()->position() == position_) { + was_found = !found_; + found_ = true; + destructuring_prop_ = prop; + destructuring_assignment_ = node; + break; + } } } - Find(node->value(), true); - if (was_found) { - done_ = true; - found_ = false; + } + if (!was_found) { + Find(node->target()); + if (node->target()->IsArrayLiteral()) { + // Special case the visit for destructuring array assignment. + bool was_found = false; + if (node->value()->position() == position_) { + is_iterator_error_ = true; + was_found = !found_; + found_ = true; + } + Find(node->value(), true); + if (was_found) { + done_ = true; + found_ = false; + } + } else { + Find(node->value()); } } else { - Find(node->value()); + Find(node->value(), true); + } + + if (was_found) { + done_ = true; + found_ = false; } } @@ -342,6 +370,9 @@ void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); } void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } +void CallPrinter::VisitOptionalChain(OptionalChain* node) { + Find(node->expression()); +} void CallPrinter::VisitProperty(Property* node) { Expression* key = node->key(); @@ -349,12 +380,18 @@ void CallPrinter::VisitProperty(Property* node) { if (literal != nullptr && literal->BuildValue(isolate_)->IsInternalizedString()) { Find(node->obj(), true); + if (node->is_optional_chain_link()) { + Print("?"); + } Print("."); // TODO(adamk): Teach Literal how to print its values without // allocating on the heap. PrintLiteral(literal->BuildValue(isolate_), false); } else { Find(node->obj(), true); + if (node->is_optional_chain_link()) { + Print("?."); + } Print("["); Find(key, true); Print("]"); @@ -1272,6 +1309,11 @@ void AstPrinter::VisitThrow(Throw* node) { Visit(node->exception()); } +void AstPrinter::VisitOptionalChain(OptionalChain* node) { + IndentedScope indent(this, "OPTIONAL_CHAIN", node->position()); + Visit(node->expression()); +} + void AstPrinter::VisitProperty(Property* node) { EmbeddedVector<char, 128> buf; SNPrintF(buf, "PROPERTY"); @@ -1289,6 +1331,18 @@ void AstPrinter::VisitProperty(Property* node) { PrintIndentedVisit("PRIVATE_METHOD", node->key()); break; } + case PRIVATE_GETTER_ONLY: { + PrintIndentedVisit("PRIVATE_GETTER_ONLY", node->key()); + break; + } + case PRIVATE_SETTER_ONLY: { + PrintIndentedVisit("PRIVATE_SETTER_ONLY", node->key()); + break; + } + case PRIVATE_GETTER_AND_SETTER: { + PrintIndentedVisit("PRIVATE_GETTER_AND_SETTER", node->key()); + break; + } case KEYED_PROPERTY: case KEYED_SUPER_PROPERTY: { PrintIndentedVisit("KEY", node->key()); diff --git a/deps/v8/src/ast/prettyprinter.h b/deps/v8/src/ast/prettyprinter.h index cceb5fc269..322fd9fb14 100644 --- a/deps/v8/src/ast/prettyprinter.h +++ b/deps/v8/src/ast/prettyprinter.h @@ -31,6 +31,12 @@ class CallPrinter final : public AstVisitor<CallPrinter> { kCallAndAsyncIterator }; ErrorHint GetErrorHint() const; + ObjectLiteralProperty* destructuring_prop() const { + return destructuring_prop_; + } + Assignment* destructuring_assignment() const { + return destructuring_assignment_; + } // Individual nodes #define DECLARE_VISIT(type) void Visit##type(type* node); @@ -54,6 +60,8 @@ class CallPrinter final : public AstVisitor<CallPrinter> { bool is_iterator_error_; bool is_async_iterator_error_; bool is_call_error_; + ObjectLiteralProperty* destructuring_prop_; + Assignment* destructuring_assignment_; FunctionKind function_kind_; DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 237d98ec60..c4d0999978 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -40,7 +40,6 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope, VariableKind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag, - RequiresBrandCheckFlag requires_brand_check, bool* was_added) { // AstRawStrings are unambiguous, i.e., the same string is always represented // by the same AstRawString*. @@ -52,9 +51,8 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope, if (*was_added) { // The variable has not been declared yet -> insert it. DCHECK_EQ(name, p->key); - Variable* variable = - new (zone) Variable(scope, name, mode, kind, initialization_flag, - maybe_assigned_flag, requires_brand_check); + Variable* variable = new (zone) Variable( + scope, name, mode, kind, initialization_flag, maybe_assigned_flag); p->value = variable; } return reinterpret_cast<Variable*>(p->value); @@ -170,7 +168,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) #ifdef DEBUG already_resolved_ = true; #endif - if (scope_info->CallsSloppyEval()) scope_calls_eval_ = true; set_language_mode(scope_info->language_mode()); num_heap_slots_ = scope_info->ContextLength(); DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); @@ -186,6 +183,10 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type, params_(0, zone) { DCHECK_NE(scope_type, SCRIPT_SCOPE); SetDefaults(); + if (scope_info->SloppyEvalCanExtendVars()) { + DCHECK(!is_eval_scope()); + sloppy_eval_can_extend_vars_ = true; + } } Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, @@ -258,7 +259,8 @@ void Scope::SetDefaults() { set_language_mode(LanguageMode::kSloppy); - scope_calls_eval_ = false; + calls_eval_ = false; + sloppy_eval_can_extend_vars_ = false; scope_nonlinear_ = false; is_hidden_ = false; is_debug_evaluate_scope_ = false; @@ -380,11 +382,8 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, if (deserialization_mode == DeserializationMode::kIncludingVariables && script_scope->scope_info_.is_null()) { - Handle<ScriptContextTable> table( - isolate->native_context()->script_context_table(), isolate); - Handle<Context> first = ScriptContextTable::GetContext(isolate, table, 0); - Handle<ScopeInfo> scope_info(first->scope_info(), isolate); - script_scope->SetScriptScopeInfo(scope_info); + script_scope->SetScriptScopeInfo( + ReadOnlyRoots(isolate).global_this_binding_scope_info_handle()); } if (innermost_scope == nullptr) return script_scope; @@ -626,7 +625,7 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name, : NORMAL_VARIABLE; function_ = new (zone()) Variable(this, name, VariableMode::kConst, kind, kCreatedInitialized); - if (calls_sloppy_eval()) { + if (sloppy_eval_can_extend_vars()) { cache->NonLocal(name, VariableMode::kDynamic); } else { cache->variables_.Add(zone(), function_); @@ -652,7 +651,8 @@ Scope* Scope::FinalizeBlockScope() { #endif if (variables_.occupancy() > 0 || - (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval())) { + (is_declaration_scope() && + AsDeclarationScope()->sloppy_eval_can_extend_vars())) { return this; } @@ -682,10 +682,10 @@ Scope* Scope::FinalizeBlockScope() { if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true; - // No need to propagate scope_calls_eval_, since if it was relevant to - // this scope we would have had to bail out at the top. - DCHECK(!scope_calls_eval_ || !is_declaration_scope() || - !is_sloppy(language_mode())); + // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant + // to this scope we would have had to bail out at the top. + DCHECK(!is_declaration_scope() || + !AsDeclarationScope()->sloppy_eval_can_extend_vars()); // This block does not need a context. num_heap_slots_ = 0; @@ -750,8 +750,8 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { outer_closure->locals_.Rewind(top_local_); // Move eval calls since Snapshot's creation into new_parent. - if (outer_scope_and_calls_eval_->scope_calls_eval_) { - new_parent->scope_calls_eval_ = true; + if (outer_scope_and_calls_eval_->calls_eval_) { + new_parent->RecordDeclarationScopeEvalCall(); new_parent->inner_scope_calls_eval_ = true; } @@ -787,13 +787,11 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { VariableMode mode; InitializationFlag init_flag; MaybeAssignedFlag maybe_assigned_flag; - RequiresBrandCheckFlag requires_brand_check = kNoBrandCheck; { location = VariableLocation::CONTEXT; index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, - &init_flag, &maybe_assigned_flag, - &requires_brand_check); + &init_flag, &maybe_assigned_flag); found = index >= 0; } @@ -818,9 +816,9 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { } bool was_added; - Variable* var = cache->variables_.Declare( - zone(), this, name, mode, NORMAL_VARIABLE, init_flag, maybe_assigned_flag, - requires_brand_check, &was_added); + Variable* var = + 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; @@ -873,6 +871,8 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, VariableKind kind, bool* was_added, InitializationFlag init_flag) { DCHECK(!already_resolved_); + // Private methods should be declared with ClassScope::DeclarePrivateName() + DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode)); // This function handles VariableMode::kVar, VariableMode::kLet, and // VariableMode::kConst modes. VariableMode::kDynamic variables are // introduced during variable allocation, and VariableMode::kTemporary @@ -905,6 +905,8 @@ Variable* Scope::DeclareVariable( VariableMode mode, VariableKind kind, InitializationFlag init, bool* was_added, bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { + // Private methods should be declared with ClassScope::DeclarePrivateName() + DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode)); DCHECK(IsDeclaredVariableMode(mode)); DCHECK(!already_resolved_); DCHECK(!GetDeclarationScope()->is_being_lazily_parsed()); @@ -990,7 +992,8 @@ Variable* Scope::DeclareVariableName(const AstRawString* name, DCHECK(IsDeclaredVariableMode(mode)); DCHECK(!already_resolved_); DCHECK(GetDeclarationScope()->is_being_lazily_parsed()); - + // Private methods should be declared with ClassScope::DeclarePrivateName() + DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode)); if (mode == VariableMode::kVar && !is_declaration_scope()) { return GetDeclarationScope()->DeclareVariableName(name, mode, was_added, kind); @@ -1044,7 +1047,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, bool was_added; return cache->variables_.Declare( zone(), this, name, VariableMode::kDynamicGlobal, kind, - kCreatedInitialized, kNotAssigned, kNoBrandCheck, &was_added); + kCreatedInitialized, kNotAssigned, &was_added); // TODO(neis): Mark variable as maybe-assigned? } @@ -1243,7 +1246,7 @@ int Scope::ContextChainLengthUntilOutermostSloppyEval() const { if (!s->NeedsContext()) continue; length++; if (s->is_declaration_scope() && - s->AsDeclarationScope()->calls_sloppy_eval()) { + s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) { result = length; } } @@ -1384,9 +1387,10 @@ void Scope::CollectNonLocals(DeclarationScope* max_outer_scope, void Scope::AnalyzePartially(DeclarationScope* max_outer_scope, AstNodeFactory* ast_node_factory, - UnresolvedList* new_unresolved_list) { - this->ForEach([max_outer_scope, ast_node_factory, - new_unresolved_list](Scope* scope) { + UnresolvedList* new_unresolved_list, + bool maybe_in_arrowhead) { + this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list, + maybe_in_arrowhead](Scope* scope) { DCHECK_IMPLIES(scope->is_declaration_scope(), !scope->AsDeclarationScope()->was_lazily_parsed()); @@ -1399,7 +1403,8 @@ void Scope::AnalyzePartially(DeclarationScope* max_outer_scope, // 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()) { + if (!max_outer_scope->outer_scope()->is_script_scope() || + maybe_in_arrowhead) { VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); new_unresolved_list->Add(copy); } @@ -1434,6 +1439,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, sloppy_block_functions_.Clear(); rare_data_ = nullptr; has_rest_ = false; + function_ = nullptr; DCHECK_NE(zone_, ast_value_factory->zone()); zone_->ReleaseMemory(); @@ -1487,17 +1493,19 @@ void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) { } void DeclarationScope::AnalyzePartially(Parser* parser, - AstNodeFactory* ast_node_factory) { + AstNodeFactory* ast_node_factory, + bool maybe_in_arrowhead) { DCHECK(!force_eager_compilation_); UnresolvedList new_unresolved_list; if (!IsArrowFunction(function_kind_) && - (!outer_scope_->is_script_scope() || + (!outer_scope_->is_script_scope() || maybe_in_arrowhead || (preparse_data_builder_ != nullptr && preparse_data_builder_->HasInnerFunctions()))) { // 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. - Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list); + Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list, + maybe_in_arrowhead); // Migrate function_ to the right Zone. if (function_ != nullptr) { @@ -1596,10 +1604,6 @@ void PrintVar(int indent, Variable* var) { if (comma) PrintF(", "); PrintF("hole initialization elided"); } - if (var->requires_brand_check()) { - if (comma) PrintF(", "); - PrintF("requires brand check"); - } PrintF("\n"); } @@ -1676,7 +1680,8 @@ void Scope::Print(int n) { Indent(n1, "// strict mode scope\n"); } if (IsAsmModule()) Indent(n1, "// scope is an asm module\n"); - if (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval()) { + if (is_declaration_scope() && + AsDeclarationScope()->sloppy_eval_can_extend_vars()) { Indent(n1, "// scope calls sloppy 'eval'\n"); } if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) { @@ -1774,9 +1779,9 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { // Declare a new non-local. DCHECK(IsDynamicVariableMode(mode)); bool was_added; - Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE, - kCreatedInitialized, kNotAssigned, - kNoBrandCheck, &was_added); + Variable* var = + variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE, + kCreatedInitialized, kNotAssigned, &was_added); // Allocate it by giving it a dynamic lookup. var->AllocateTo(VariableLocation::LOOKUP, -1); return var; @@ -1814,7 +1819,18 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope, // We found a variable and we are done. (Even if there is an 'eval' in this // scope which introduces the same variable again, the resulting variable // remains the same.) - if (var != nullptr) { + // + // For sloppy eval though, we skip dynamic variable to avoid resolving to a + // variable when the variable and proxy are in the same eval execution. The + // variable is not available on subsequent lazy executions of functions in + // the eval, so this avoids inner functions from looking up different + // variables during eager and lazy compilation. + // + // TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy + // living in a different scope to the current one, or some other + // optimisation. + if (var != nullptr && + !(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) { if (mode == kParsedScope && force_context_allocation && !var->is_dynamic()) { var->ForceContextAllocation(); @@ -1829,8 +1845,9 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope, return LookupWith(proxy, scope, outer_scope_end, entry_point, force_context_allocation); } - if (V8_UNLIKELY(scope->is_declaration_scope() && - scope->AsDeclarationScope()->calls_sloppy_eval())) { + if (V8_UNLIKELY( + scope->is_declaration_scope() && + scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())) { return LookupSloppyEval(proxy, scope, outer_scope_end, entry_point, force_context_allocation); } @@ -1901,7 +1918,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, Scope* entry_point, bool force_context_allocation) { DCHECK(scope->is_declaration_scope() && - scope->AsDeclarationScope()->calls_sloppy_eval()); + scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()); // If we're compiling eval, it's possible that the outer scope is the first // ScopeInfo-backed scope. @@ -2065,7 +2082,7 @@ bool Scope::MustAllocate(Variable* var) { 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->SetMaybeAssigned(); + if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned(); } DCHECK(!var->has_forced_context_allocation() || var->is_used()); // Global variables do not need to be allocated. @@ -2081,11 +2098,14 @@ bool Scope::MustAllocateInContext(Variable* var) { // // Temporary variables are always stack-allocated. Catch-bound variables are // always context-allocated. - if (var->mode() == VariableMode::kTemporary) return false; + VariableMode mode = var->mode(); + if (mode == VariableMode::kTemporary) return false; if (is_catch_scope()) return true; - if ((is_script_scope() || is_eval_scope()) && - IsLexicalVariableMode(var->mode())) { - return true; + if (is_script_scope() || is_eval_scope()) { + if (IsLexicalVariableMode(mode) || + IsPrivateMethodOrAccessorVariableMode(mode)) { + return true; + } } return var->has_forced_context_allocation() || inner_scope_calls_eval_; } @@ -2248,9 +2268,9 @@ void Scope::AllocateVariablesRecursively() { scope->is_with_scope() || scope->is_module_scope() || scope->IsAsmModule() || scope->ForceContextForLanguageMode() || (scope->is_function_scope() && - scope->AsDeclarationScope()->calls_sloppy_eval()) || + scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) || (scope->is_block_scope() && scope->is_declaration_scope() && - scope->AsDeclarationScope()->calls_sloppy_eval()); + scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()); // 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. @@ -2326,15 +2346,28 @@ int Scope::ContextLocalCount() const { (is_function_var_in_context ? 1 : 0); } -Variable* ClassScope::DeclarePrivateName( - const AstRawString* name, RequiresBrandCheckFlag requires_brand_check, - bool* was_added) { +bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) { + switch (a) { + case VariableMode::kPrivateGetterOnly: + return b == VariableMode::kPrivateSetterOnly; + case VariableMode::kPrivateSetterOnly: + return b == VariableMode::kPrivateGetterOnly; + default: + return false; + } +} + +Variable* ClassScope::DeclarePrivateName(const AstRawString* name, + VariableMode mode, bool* was_added) { Variable* result = EnsureRareData()->private_name_map.Declare( - zone(), this, name, VariableMode::kConst, NORMAL_VARIABLE, + zone(), this, name, mode, NORMAL_VARIABLE, InitializationFlag::kNeedsInitialization, - MaybeAssignedFlag::kMaybeAssigned, requires_brand_check, was_added); + MaybeAssignedFlag::kMaybeAssigned, was_added); if (*was_added) { locals_.Add(result); + } else if (IsComplementaryAccessorPair(result->mode(), mode)) { + *was_added = true; + result->set_mode(VariableMode::kPrivateGetterAndSetter); } result->ForceContextAllocation(); return result; @@ -2416,22 +2449,20 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) { VariableMode mode; InitializationFlag init_flag; MaybeAssignedFlag maybe_assigned_flag; - RequiresBrandCheckFlag requires_brand_check; - int index = - ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, &init_flag, - &maybe_assigned_flag, &requires_brand_check); + int index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, + &init_flag, &maybe_assigned_flag); if (index < 0) { return nullptr; } - DCHECK_EQ(mode, VariableMode::kConst); + DCHECK(IsConstVariableMode(mode)); DCHECK_EQ(init_flag, InitializationFlag::kNeedsInitialization); DCHECK_EQ(maybe_assigned_flag, MaybeAssignedFlag::kMaybeAssigned); // Add the found private name to the map to speed up subsequent // lookups for the same name. bool was_added; - Variable* var = DeclarePrivateName(name, requires_brand_check, &was_added); + Variable* var = DeclarePrivateName(name, mode, &was_added); DCHECK(was_added); var->AllocateTo(VariableLocation::CONTEXT, index); return var; @@ -2450,7 +2481,9 @@ Variable* ClassScope::LookupPrivateName(VariableProxy* proxy) { if (var == nullptr && !class_scope->scope_info_.is_null()) { var = class_scope->LookupPrivateNameInScopeInfo(proxy->raw_name()); } - return var; + if (var != nullptr) { + return var; + } } return nullptr; } diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index 932d5c70b9..73e6e8fd89 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -5,6 +5,7 @@ #ifndef V8_AST_SCOPES_H_ #define V8_AST_SCOPES_H_ +#include <numeric> #include "src/ast/ast.h" #include "src/base/compiler-specific.h" #include "src/base/hashmap.h" @@ -13,6 +14,7 @@ #include "src/objects/function-kind.h" #include "src/objects/objects.h" #include "src/utils/pointer-with-payload.h" +#include "src/utils/utils.h" #include "src/zone/zone.h" namespace v8 { @@ -42,7 +44,6 @@ class VariableMap : public ZoneHashMap { VariableMode mode, VariableKind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag, - RequiresBrandCheckFlag requires_brand_check, bool* was_added); V8_EXPORT_PRIVATE Variable* Lookup(const AstRawString* name); @@ -111,8 +112,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { } void RestoreEvalFlag() { - outer_scope_and_calls_eval_->scope_calls_eval_ = - outer_scope_and_calls_eval_.GetPayload(); + if (outer_scope_and_calls_eval_.GetPayload()) { + // This recreates both calls_eval and sloppy_eval_can_extend_vars. + outer_scope_and_calls_eval_.GetPointer()->RecordEvalCall(); + } } void Reparent(DeclarationScope* new_parent); @@ -265,9 +268,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Inform the scope and outer scopes that the corresponding code contains an // eval call. - void RecordEvalCall() { - scope_calls_eval_ = true; - } + inline void RecordEvalCall(); void RecordInnerScopeEvalCall() { inner_scope_calls_eval_ = true; @@ -460,7 +461,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { int ContextChainLength(Scope* scope) const; // The number of contexts between this and the outermost context that has a - // sloppy eval call. One if this->calls_sloppy_eval(). + // sloppy eval call. One if this->sloppy_eval_can_extend_vars(). int ContextChainLengthUntilOutermostSloppyEval() const; // Find the closest class scope in the current scope and outer scopes. If no @@ -558,7 +559,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { MaybeAssignedFlag maybe_assigned_flag, bool* was_added) { Variable* result = variables_.Declare(zone, this, name, mode, kind, initialization_flag, - maybe_assigned_flag, kNoBrandCheck, was_added); + maybe_assigned_flag, was_added); if (*was_added) locals_.Add(result); return result; } @@ -610,7 +611,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // list along the way, so full resolution cannot be done afterwards. void AnalyzePartially(DeclarationScope* max_outer_scope, AstNodeFactory* ast_node_factory, - UnresolvedList* new_unresolved_list); + UnresolvedList* new_unresolved_list, + bool maybe_in_arrowhead); void CollectNonLocals(DeclarationScope* max_outer_scope, Isolate* isolate, ParseInfo* info, Handle<StringSet>* non_locals); @@ -703,9 +705,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // The language mode of this scope. STATIC_ASSERT(LanguageModeSize == 2); bool is_strict_ : 1; - // This scope or a nested catch scope or with scope contain an 'eval' call. At - // the 'eval' call site this scope is the declaration scope. - bool scope_calls_eval_ : 1; + // This scope contains an 'eval' call. + bool calls_eval_ : 1; + // The context associated with this scope can be extended by a sloppy eval + // called inside of it. + bool sloppy_eval_can_extend_vars_ : 1; // This scope's declarations might not be executed in order (e.g., switch). bool scope_nonlinear_ : 1; bool is_hidden_ : 1; @@ -753,11 +757,50 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { IsClassConstructor(function_kind()))); } - bool calls_sloppy_eval() const { - // TODO(delphick): Calculate this when setting and change the name of - // scope_calls_eval_. - return !is_script_scope() && scope_calls_eval_ && - is_sloppy(language_mode()); + // Inform the scope and outer scopes that the corresponding code contains an + // eval call. + void RecordDeclarationScopeEvalCall() { + calls_eval_ = true; + + // If this isn't a sloppy eval, we don't care about it. + if (language_mode() != LanguageMode::kSloppy) return; + + // Sloppy eval in script scopes can only introduce global variables anyway, + // so we don't care that it calls sloppy eval. + if (is_script_scope()) return; + + // Sloppy eval in a eval scope can only introduce variables into the outer + // (non-eval) declaration scope, not into this eval scope. + if (is_eval_scope()) { +#ifdef DEBUG + // One of three things must be true: + // 1. The outer non-eval declaration scope should already be marked as + // being extendable by sloppy eval, by the current sloppy eval rather + // than the inner one, + // 2. The outer non-eval declaration scope is a script scope and thus + // isn't extendable anyway, or + // 3. This is a debug evaluate and all bets are off. + DeclarationScope* outer_decl_scope = outer_scope()->GetDeclarationScope(); + while (outer_decl_scope->is_eval_scope()) { + outer_decl_scope = outer_decl_scope->GetDeclarationScope(); + } + if (outer_decl_scope->is_debug_evaluate_scope()) { + // Don't check anything. + // TODO(9662): Figure out where variables declared by an eval inside a + // debug-evaluate actually go. + } else if (!outer_decl_scope->is_script_scope()) { + DCHECK(outer_decl_scope->sloppy_eval_can_extend_vars_); + } +#endif + + return; + } + + sloppy_eval_can_extend_vars_ = true; + } + + bool sloppy_eval_can_extend_vars() const { + return sloppy_eval_can_extend_vars_; } bool was_lazily_parsed() const { return was_lazily_parsed_; } @@ -972,7 +1015,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // this records variables which cannot be resolved inside the Scope (we don't // yet know what they will resolve to since the outer Scopes are incomplete) // and recreates them with the correct Zone with ast_node_factory. - void AnalyzePartially(Parser* parser, AstNodeFactory* ast_node_factory); + void AnalyzePartially(Parser* parser, AstNodeFactory* ast_node_factory, + bool maybe_in_arrowhead); // Allocate ScopeInfos for top scope and any inner scopes that need them. // Does nothing if ScopeInfo is already allocated. @@ -1138,13 +1182,21 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { RareData* rare_data_ = nullptr; }; +void Scope::RecordEvalCall() { + calls_eval_ = true; + GetDeclarationScope()->RecordDeclarationScopeEvalCall(); + RecordInnerScopeEvalCall(); +} + Scope::Snapshot::Snapshot(Scope* scope) - : outer_scope_and_calls_eval_(scope, scope->scope_calls_eval_), + : outer_scope_and_calls_eval_(scope, scope->calls_eval_), top_inner_scope_(scope->inner_scope_), top_unresolved_(scope->unresolved_list_.end()), top_local_(scope->GetClosureScope()->locals_.end()) { // Reset in order to record eval calls during this Snapshot's lifetime. - outer_scope_and_calls_eval_.GetPointer()->scope_calls_eval_ = false; + outer_scope_and_calls_eval_.GetPointer()->calls_eval_ = false; + outer_scope_and_calls_eval_.GetPointer()->sloppy_eval_can_extend_vars_ = + false; } class ModuleScope final : public DeclarationScope { @@ -1175,8 +1227,7 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope { // Declare a private name in the private name map and add it to the // local variables of this scope. - Variable* DeclarePrivateName(const AstRawString* name, - RequiresBrandCheckFlag requires_brand_check, + Variable* DeclarePrivateName(const AstRawString* name, VariableMode mode, bool* was_added); void AddUnresolvedPrivateName(VariableProxy* proxy); diff --git a/deps/v8/src/ast/source-range-ast-visitor.cc b/deps/v8/src/ast/source-range-ast-visitor.cc index 2fcf151999..d171e30587 100644 --- a/deps/v8/src/ast/source-range-ast-visitor.cc +++ b/deps/v8/src/ast/source-range-ast-visitor.cc @@ -25,14 +25,6 @@ void SourceRangeAstVisitor::VisitBlock(Block* stmt) { } } -void SourceRangeAstVisitor::VisitSwitchStatement(SwitchStatement* stmt) { - AstTraversalVisitor::VisitSwitchStatement(stmt); - ZonePtrList<CaseClause>* clauses = stmt->cases(); - for (CaseClause* clause : *clauses) { - MaybeRemoveLastContinuationRange(clause->statements()); - } -} - void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) { AstTraversalVisitor::VisitFunctionLiteral(expr); ZonePtrList<Statement>* stmts = expr->body(); diff --git a/deps/v8/src/ast/source-range-ast-visitor.h b/deps/v8/src/ast/source-range-ast-visitor.h index 4ba5feb2d2..4ea36a947f 100644 --- a/deps/v8/src/ast/source-range-ast-visitor.h +++ b/deps/v8/src/ast/source-range-ast-visitor.h @@ -34,7 +34,6 @@ class SourceRangeAstVisitor final friend class AstTraversalVisitor<SourceRangeAstVisitor>; void VisitBlock(Block* stmt); - void VisitSwitchStatement(SwitchStatement* stmt); void VisitFunctionLiteral(FunctionLiteral* expr); bool VisitNode(AstNode* node); diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h index 7805fa20c8..1ff6f9f422 100644 --- a/deps/v8/src/ast/variables.h +++ b/deps/v8/src/ast/variables.h @@ -21,8 +21,7 @@ class Variable final : public ZoneObject { public: Variable(Scope* scope, const AstRawString* name, VariableMode mode, VariableKind kind, InitializationFlag initialization_flag, - MaybeAssignedFlag maybe_assigned_flag = kNotAssigned, - RequiresBrandCheckFlag requires_brand_check = kNoBrandCheck) + MaybeAssignedFlag maybe_assigned_flag = kNotAssigned) : scope_(scope), name_(name), local_if_not_shadowed_(nullptr), @@ -32,7 +31,6 @@ class Variable final : public ZoneObject { bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) | InitializationFlagField::encode(initialization_flag) | VariableModeField::encode(mode) | - RequiresBrandCheckField::encode(requires_brand_check) | IsUsedField::encode(false) | ForceContextAllocationField::encode(false) | ForceHoleInitializationField::encode(false) | @@ -58,6 +56,9 @@ class Variable final : public ZoneObject { Handle<String> name() const { return name_->string(); } const AstRawString* raw_name() const { return name_; } VariableMode mode() const { return VariableModeField::decode(bit_field_); } + void set_mode(VariableMode mode) { + bit_field_ = VariableModeField::update(bit_field_, mode); + } bool has_forced_context_allocation() const { return ForceContextAllocationField::decode(bit_field_); } @@ -72,6 +73,8 @@ class Variable final : public ZoneObject { return MaybeAssignedFlagField::decode(bit_field_); } void SetMaybeAssigned() { + if (mode() == VariableMode::kConst) return; + // If this variable is dynamically shadowing another variable, then that // variable could also be assigned (in the non-shadowing case). if (has_local_if_not_shadowed()) { @@ -80,22 +83,14 @@ class Variable final : public ZoneObject { if (!maybe_assigned()) { local_if_not_shadowed()->SetMaybeAssigned(); } - DCHECK(local_if_not_shadowed()->maybe_assigned()); + DCHECK_IMPLIES(local_if_not_shadowed()->mode() != VariableMode::kConst, + local_if_not_shadowed()->maybe_assigned()); } set_maybe_assigned(); } - RequiresBrandCheckFlag get_requires_brand_check_flag() const { - return RequiresBrandCheckField::decode(bit_field_); - } - bool requires_brand_check() const { - return get_requires_brand_check_flag() == kRequiresBrandCheck; - } - - void set_requires_brand_check() { - bit_field_ = - RequiresBrandCheckField::update(bit_field_, kRequiresBrandCheck); + return IsPrivateMethodOrAccessorVariableMode(mode()); } int initializer_position() { return initializer_position_; } @@ -125,7 +120,8 @@ class Variable final : public ZoneObject { // declaration time. Only returns valid results after scope analysis. bool binding_needs_init() const { DCHECK_IMPLIES(initialization_flag() == kNeedsInitialization, - IsLexicalVariableMode(mode())); + IsLexicalVariableMode(mode()) || + IsPrivateMethodOrAccessorVariableMode(mode())); DCHECK_IMPLIES(ForceHoleInitializationField::decode(bit_field_), initialization_flag() == kNeedsInitialization); @@ -149,7 +145,8 @@ class Variable final : public ZoneObject { // be required at runtime. void ForceHoleInitialization() { DCHECK_EQ(kNeedsInitialization, initialization_flag()); - DCHECK(IsLexicalVariableMode(mode())); + DCHECK(IsLexicalVariableMode(mode()) || + IsPrivateMethodOrAccessorVariableMode(mode())); bit_field_ = ForceHoleInitializationField::update(bit_field_, true); } @@ -243,25 +240,16 @@ class Variable final : public ZoneObject { bit_field_ = MaybeAssignedFlagField::update(bit_field_, kMaybeAssigned); } - class VariableModeField : public BitField16<VariableMode, 0, 3> {}; - class VariableKindField - : public BitField16<VariableKind, VariableModeField::kNext, 3> {}; - class LocationField - : public BitField16<VariableLocation, VariableKindField::kNext, 3> {}; - class ForceContextAllocationField - : public BitField16<bool, LocationField::kNext, 1> {}; - class IsUsedField - : public BitField16<bool, ForceContextAllocationField::kNext, 1> {}; - class InitializationFlagField - : public BitField16<InitializationFlag, IsUsedField::kNext, 1> {}; - class ForceHoleInitializationField - : public BitField16<bool, InitializationFlagField::kNext, 1> {}; - class MaybeAssignedFlagField - : public BitField16<MaybeAssignedFlag, - ForceHoleInitializationField::kNext, 1> {}; - class RequiresBrandCheckField - : public BitField16<RequiresBrandCheckFlag, MaybeAssignedFlagField::kNext, - 1> {}; + using VariableModeField = BitField16<VariableMode, 0, 4>; + using VariableKindField = VariableModeField::Next<VariableKind, 3>; + using LocationField = VariableKindField::Next<VariableLocation, 3>; + using ForceContextAllocationField = LocationField::Next<bool, 1>; + using IsUsedField = ForceContextAllocationField::Next<bool, 1>; + using InitializationFlagField = IsUsedField::Next<InitializationFlag, 1>; + using ForceHoleInitializationField = InitializationFlagField::Next<bool, 1>; + using MaybeAssignedFlagField = + ForceHoleInitializationField::Next<MaybeAssignedFlag, 1>; + Variable** next() { return &next_; } friend List; friend base::ThreadedListTraits<Variable>; |