See More

/* * Copyright (C) 1999-2000 Harri Porten ([email protected]) * Copyright (C) 2001 Peter Kelly ([email protected]) * Copyright (C) 2003-2019 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich ([email protected]) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #pragma once #include "BytecodeIntrinsicRegistry.h" #include "JITCode.h" #include "Label.h" #include "ParserArena.h" #include "ParserModes.h" #include "ParserTokens.h" #include "ResultType.h" #include "SourceCode.h" #include "SymbolTable.h" #include "VariableEnvironment.h" #include #include namespace JSC { enum OpcodeID : unsigned; class ArgumentListNode; class BytecodeGenerator; class FunctionMetadataNode; class FunctionParameters; class ModuleAnalyzer; class ModuleScopeData; class PropertyListNode; class ReadModifyResolveNode; class RegisterID; class ScopeNode; typedef SmallSet UniquedStringImplPtrSet; enum class Operator : uint8_t { Equal, PlusEq, MinusEq, MultEq, DivEq, PlusPlus, MinusMinus, BitAndEq, BitXOrEq, BitOrEq, ModEq, PowEq, CoalesceEq, OrEq, AndEq, LShift, RShift, URShift }; enum class LogicalOperator : uint8_t { And, Or }; enum FallThroughMode : uint8_t { FallThroughMeansTrue = 0, FallThroughMeansFalse = 1 }; inline FallThroughMode invert(FallThroughMode fallThroughMode) { return static_cast(!fallThroughMode); } namespace DeclarationStacks { typedef Vector FunctionStack; } struct SwitchInfo { enum SwitchType : uint8_t { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString }; uint32_t bytecodeOffset; SwitchType switchType; }; enum class AssignmentContext : uint8_t { DeclarationStatement, ConstDeclarationStatement, AssignmentExpression }; class ParserArenaFreeable { public: // ParserArenaFreeable objects are freed when the arena is deleted. // Destructors are not called. Clients must not call delete on such objects. void* operator new(size_t, ParserArena&); }; class ParserArenaDeletable { public: virtual ~ParserArenaDeletable() { } // ParserArenaDeletable objects are deleted when the arena is deleted. // Clients must not call delete directly on such objects. template void* operator new(size_t, ParserArena&); }; #define JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED_IMPL(__classToNew) \ void* operator new(size_t size, ParserArena& parserArena) \ { \ return ParserArenaDeletable::operator new<__classToNew>(size, parserArena); \ } #define JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(__classToNew) \ public: \ JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED_IMPL(__classToNew) \ private: \ typedef int __thisIsHereToForceASemicolonAfterThisMacro UNUSED_TYPE_ALIAS DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(ParserArenaRoot); class ParserArenaRoot { WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(ParserArenaRoot); protected: ParserArenaRoot(ParserArena&); public: ParserArena& parserArena() { return m_arena; } virtual ~ParserArenaRoot() { } protected: ParserArena m_arena; }; class Node : public ParserArenaFreeable { protected: Node(const JSTokenLocation&); public: virtual ~Node() { } int firstLine() const { return m_position.line; } int startOffset() const { return m_position.offset; } int endOffset() const { return m_endOffset; } int lineStartOffset() const { return m_position.lineStartOffset; } const JSTextPosition& position() const { return m_position; } void setEndOffset(int offset) { m_endOffset = offset; } void setStartOffset(int offset) { m_position.offset = offset; } bool needsDebugHook() const { return m_needsDebugHook; } void setNeedsDebugHook() { m_needsDebugHook = true; } protected: JSTextPosition m_position; int m_endOffset { -1 }; bool m_needsDebugHook { false }; }; class ExpressionNode : public Node { protected: ExpressionNode(const JSTokenLocation&, ResultType = ResultType::unknownType()); public: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = nullptr) = 0; virtual bool isNumber() const { return false; } virtual bool isString() const { return false; } virtual bool isBigInt() const { return false; } virtual bool isObjectLiteral() const { return false; } virtual bool isArrayLiteral() const { return false; } virtual bool isNull() const { return false; } virtual bool isPure(BytecodeGenerator&) const { return false; } virtual bool isConstant() const { return false; } virtual bool isLocation() const { return false; } virtual bool isPrivateLocation() const { return false; } virtual bool isAssignmentLocation() const { return isLocation(); } virtual bool isResolveNode() const { return false; } virtual bool isAssignResolveNode() const { return false; } virtual bool isBracketAccessorNode() const { return false; } virtual bool isDotAccessorNode() const { return false; } virtual bool isDestructuringNode() const { return false; } virtual bool isBaseFuncExprNode() const { return false; } virtual bool isFuncExprNode() const { return false; } virtual bool isArrowFuncExprNode() const { return false; } virtual bool isClassExprNode() const { return false; } virtual bool isCommaNode() const { return false; } virtual bool isSimpleArray() const { return false; } virtual bool isAdd() const { return false; } virtual bool isSubtract() const { return false; } virtual bool isBoolean() const { return false; } virtual bool isThisNode() const { return false; } virtual bool isSpreadExpression() const { return false; } virtual bool isSuperNode() const { return false; } virtual bool isImportNode() const { return false; } virtual bool isMetaProperty() const { return false; } virtual bool isNewTarget() const { return false; } virtual bool isImportMeta() const { return false; } virtual bool isBytecodeIntrinsicNode() const { return false; } virtual bool isBinaryOpNode() const { return false; } virtual bool isFunctionCall() const { return false; } virtual bool isDeleteNode() const { return false; } virtual bool isOptionalChain() const { return false; } virtual bool isPrivateIdentifier() const { return false; } virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode); virtual ExpressionNode* stripUnaryPlus() { return this; } ResultType resultDescriptor() const { return m_resultType; } bool isOnlyChildOfStatement() const { return m_isOnlyChildOfStatement; } void setIsOnlyChildOfStatement() { m_isOnlyChildOfStatement = true; } bool isOptionalChainBase() const { return m_isOptionalChainBase; } void setIsOptionalChainBase() { m_isOptionalChainBase = true; } private: ResultType m_resultType; bool m_isOnlyChildOfStatement { false }; bool m_isOptionalChainBase { false }; }; class StatementNode : public Node { protected: StatementNode(const JSTokenLocation&); public: virtual void emitBytecode(BytecodeGenerator&, RegisterID* destination = nullptr) = 0; void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset); unsigned lastLine() const { return m_lastLine; } StatementNode* next() const { return m_next; } void setNext(StatementNode* next) { m_next = next; } virtual bool hasCompletionValue() const { return true; } virtual bool hasEarlyBreakOrContinue() const { return false; } virtual bool isEmptyStatement() const { return false; } virtual bool isDebuggerStatement() const { return false; } virtual bool isFunctionNode() const { return false; } virtual bool isReturnNode() const { return false; } virtual bool isExprStatement() const { return false; } virtual bool isBreak() const { return false; } virtual bool isContinue() const { return false; } virtual bool isLabel() const { return false; } virtual bool isBlock() const { return false; } virtual bool isFuncDeclNode() const { return false; } virtual bool isModuleDeclarationNode() const { return false; } virtual bool isForOfNode() const { return false; } virtual bool isDefineFieldNode() const { return false; } protected: int m_lastLine { -1 }; StatementNode* m_next { nullptr }; }; class VariableEnvironmentNode : public ParserArenaDeletable { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(VariableEnvironmentNode); public: typedef DeclarationStacks::FunctionStack FunctionStack; VariableEnvironmentNode() = default; VariableEnvironmentNode(VariableEnvironment&& lexicalDeclaredVariables); VariableEnvironmentNode(VariableEnvironment&& lexicalDeclaredVariables, FunctionStack&&); VariableEnvironment& lexicalVariables() { return m_lexicalVariables; } FunctionStack& functionStack() { return m_functionStack; } protected: VariableEnvironment m_lexicalVariables; FunctionStack m_functionStack; }; class ConstantNode : public ExpressionNode { public: ConstantNode(const JSTokenLocation&, ResultType); bool isPure(BytecodeGenerator&) const override { return true; } bool isConstant() const override { return true; } virtual JSValue jsValue(BytecodeGenerator&) const = 0; private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; void emitBytecodeInConditionContext(BytecodeGenerator&, Label& trueTarget, Label& falseTarget, FallThroughMode) override; }; class NullNode final : public ConstantNode { public: NullNode(const JSTokenLocation&); private: bool isNull() const final { return true; } JSValue jsValue(BytecodeGenerator&) const final { return jsNull(); } }; class BooleanNode final : public ConstantNode { public: BooleanNode(const JSTokenLocation&, bool value); bool value() { return m_value; } private: bool isBoolean() const final { return true; } JSValue jsValue(BytecodeGenerator&) const final { return jsBoolean(m_value); } bool m_value; }; class NumberNode : public ConstantNode { public: NumberNode(const JSTokenLocation&, double value); double value() const { return m_value; } virtual bool isIntegerNode() const = 0; RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; private: bool isNumber() const final { return true; } JSValue jsValue(BytecodeGenerator&) const override { return jsNumber(m_value); } double m_value; }; class DoubleNode : public NumberNode { public: DoubleNode(const JSTokenLocation&, double value); private: bool isIntegerNode() const override { return false; } }; // An integer node represent a number represented as an integer (e.g. 42 instead of 42., 42.0, 42e0) class IntegerNode final : public DoubleNode { public: IntegerNode(const JSTokenLocation&, double value); bool isIntegerNode() const final { return true; } }; class StringNode final : public ConstantNode { public: StringNode(const JSTokenLocation&, const Identifier&); const Identifier& value() { return m_value; } private: bool isString() const final { return true; } JSValue jsValue(BytecodeGenerator&) const final; const Identifier& m_value; }; class BigIntNode final : public ConstantNode { public: BigIntNode(const JSTokenLocation&, const Identifier&, uint8_t radix); BigIntNode(const JSTokenLocation&, const Identifier&, uint8_t radix, bool sign); const Identifier& value() { return m_value; } const Identifier& identifier() const { return m_value; } uint8_t radix() const { return m_radix; } bool sign() const { return m_sign; } private: bool isBigInt() const final { return true; } JSValue jsValue(BytecodeGenerator&) const final; const Identifier& m_value; const uint8_t m_radix; const bool m_sign; }; class ThrowableExpressionData { public: ThrowableExpressionData() = default; ThrowableExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end) : m_divot(divot) , m_divotStart(start) , m_divotEnd(end) { checkConsistency(); } void setExceptionSourceCode(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) { m_divot = divot; m_divotStart = divotStart; m_divotEnd = divotEnd; checkConsistency(); } const JSTextPosition& divot() const { return m_divot; } const JSTextPosition& divotStart() const { return m_divotStart; } const JSTextPosition& divotEnd() const { return m_divotEnd; } void checkConsistency() const { ASSERT(m_divot.offset >= m_divot.lineStartOffset); ASSERT(m_divotStart.offset >= m_divotStart.lineStartOffset); ASSERT(m_divotEnd.offset >= m_divotEnd.lineStartOffset); ASSERT(m_divot.offset >= m_divotStart.offset); ASSERT(m_divotEnd.offset >= m_divot.offset); } protected: RegisterID* emitThrowReferenceError(BytecodeGenerator&, const String& message, RegisterID* dst = nullptr); private: JSTextPosition m_divot; JSTextPosition m_divotStart; JSTextPosition m_divotEnd; }; class ThrowableSubExpressionData : public ThrowableExpressionData { public: ThrowableSubExpressionData() : m_subexpressionDivotOffset(0) , m_subexpressionEndOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } ThrowableSubExpressionData(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) : ThrowableExpressionData(divot, divotStart, divotEnd) , m_subexpressionDivotOffset(0) , m_subexpressionEndOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset) { ASSERT(subexpressionDivot.offset <= divot().offset); // Overflow means we can't do this safely, so just point at the primary divot, // divotLine, or divotLineStart. if ((divot() - subexpressionDivot.offset) & ~0xFFFF) return; if ((divot().line - subexpressionDivot.line) & ~0xFFFF) return; if ((divot().lineStartOffset - subexpressionDivot.lineStartOffset) & ~0xFFFF) return; if ((divotEnd() - subexpressionOffset) & ~0xFFFF) return; m_subexpressionDivotOffset = divot() - subexpressionDivot.offset; m_subexpressionEndOffset = divotEnd() - subexpressionOffset; m_subexpressionLineOffset = divot().line - subexpressionDivot.line; m_subexpressionLineStartOffset = divot().lineStartOffset - subexpressionDivot.lineStartOffset; } JSTextPosition subexpressionDivot() { int newLine = divot().line - m_subexpressionLineOffset; int newOffset = divot().offset - m_subexpressionDivotOffset; int newLineStartOffset = divot().lineStartOffset - m_subexpressionLineStartOffset; return JSTextPosition(newLine, newOffset, newLineStartOffset); } JSTextPosition subexpressionStart() { return divotStart(); } JSTextPosition subexpressionEnd() { return divotEnd() - static_cast(m_subexpressionEndOffset); } protected: uint16_t m_subexpressionDivotOffset; uint16_t m_subexpressionEndOffset; uint16_t m_subexpressionLineOffset; uint16_t m_subexpressionLineStartOffset; }; class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData { public: ThrowablePrefixedSubExpressionData() : m_subexpressionDivotOffset(0) , m_subexpressionStartOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } ThrowablePrefixedSubExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end) : ThrowableExpressionData(divot, start, end) , m_subexpressionDivotOffset(0) , m_subexpressionStartOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset) { ASSERT(subexpressionDivot.offset >= divot().offset); // Overflow means we can't do this safely, so just point at the primary divot, // divotLine, or divotLineStart. if ((subexpressionDivot.offset - divot()) & ~0xFFFF) return; if ((subexpressionDivot.line - divot().line) & ~0xFFFF) return; if ((subexpressionDivot.lineStartOffset - divot().lineStartOffset) & ~0xFFFF) return; if ((subexpressionOffset - divotStart()) & ~0xFFFF) return; m_subexpressionDivotOffset = subexpressionDivot.offset - divot(); m_subexpressionStartOffset = subexpressionOffset - divotStart(); m_subexpressionLineOffset = subexpressionDivot.line - divot().line; m_subexpressionLineStartOffset = subexpressionDivot.lineStartOffset - divot().lineStartOffset; } JSTextPosition subexpressionDivot() { int newLine = divot().line + m_subexpressionLineOffset; int newOffset = divot().offset + m_subexpressionDivotOffset; int newLineStartOffset = divot().lineStartOffset + m_subexpressionLineStartOffset; return JSTextPosition(newLine, newOffset, newLineStartOffset); } JSTextPosition subexpressionStart() { return divotStart() + static_cast(m_subexpressionStartOffset); } JSTextPosition subexpressionEnd() { return divotEnd(); } protected: uint16_t m_subexpressionDivotOffset; uint16_t m_subexpressionStartOffset; uint16_t m_subexpressionLineOffset; uint16_t m_subexpressionLineStartOffset; }; class TemplateExpressionListNode final : public ParserArenaFreeable { public: TemplateExpressionListNode(ExpressionNode*); TemplateExpressionListNode(TemplateExpressionListNode*, ExpressionNode*); ExpressionNode* value() { return m_node; } TemplateExpressionListNode* next() { return m_next; } private: TemplateExpressionListNode* m_next { nullptr }; ExpressionNode* m_node { nullptr }; }; class TemplateStringNode final : public ExpressionNode { public: TemplateStringNode(const JSTokenLocation&, const Identifier* cooked, const Identifier* raw); const Identifier* cooked() { return m_cooked; } const Identifier* raw() { return m_raw; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier* m_cooked; const Identifier* m_raw; }; class TemplateStringListNode final : public ParserArenaFreeable { public: TemplateStringListNode(TemplateStringNode*); TemplateStringListNode(TemplateStringListNode*, TemplateStringNode*); TemplateStringNode* value() { return m_node; } TemplateStringListNode* next() { return m_next; } private: TemplateStringListNode* m_next { nullptr }; TemplateStringNode* m_node { nullptr }; }; class TemplateLiteralNode final : public ExpressionNode { public: TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*); TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*, TemplateExpressionListNode*); TemplateStringListNode* templateStrings() const { return m_templateStrings; } TemplateExpressionListNode* templateExpressions() const { return m_templateExpressions; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; TemplateStringListNode* m_templateStrings; TemplateExpressionListNode* m_templateExpressions; }; class TaggedTemplateNode final : public ExpressionNode, public ThrowableExpressionData { public: TaggedTemplateNode(const JSTokenLocation&, ExpressionNode*, TemplateLiteralNode*); TemplateLiteralNode* templateLiteral() const { return m_templateLiteral; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_tag; TemplateLiteralNode* m_templateLiteral; }; class RegExpNode final : public ExpressionNode, public ThrowableExpressionData { public: RegExpNode(const JSTokenLocation&, const Identifier& pattern, const Identifier& flags); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_pattern; const Identifier& m_flags; }; class ThisNode final : public ExpressionNode { public: ThisNode(const JSTokenLocation&); private: bool isThisNode() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class SuperNode final : public ExpressionNode { public: SuperNode(const JSTokenLocation&); private: bool isSuperNode() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class ImportNode final : public ExpressionNode, public ThrowableExpressionData { public: ImportNode(const JSTokenLocation&, ExpressionNode*); private: bool isImportNode() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class MetaPropertyNode : public ExpressionNode { public: MetaPropertyNode(const JSTokenLocation&); private: bool isMetaProperty() const final { return true; } }; class NewTargetNode final : public MetaPropertyNode { public: NewTargetNode(const JSTokenLocation&); private: bool isNewTarget() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class ImportMetaNode final : public MetaPropertyNode { public: ImportMetaNode(const JSTokenLocation&, ExpressionNode*); private: bool isImportMeta() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class ResolveNode final : public ExpressionNode { public: ResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& start); const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isPure(BytecodeGenerator&) const final; bool isLocation() const final { return true; } bool isResolveNode() const final { return true; } const Identifier& m_ident; JSTextPosition m_start; }; // Dummy expression to hold the LHS of `#x in obj`. class PrivateIdentifierNode final : public ExpressionNode { public: PrivateIdentifierNode(const JSTokenLocation&, const Identifier&); const Identifier& value() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final { RELEASE_ASSERT_NOT_REACHED(); } bool isPrivateIdentifier() const final { return true; } const Identifier& m_ident; }; class ElementNode final : public ParserArenaFreeable { public: ElementNode(int elision, ExpressionNode*); ElementNode(ElementNode*, int elision, ExpressionNode*); int elision() const { return m_elision; } ExpressionNode* value() { return m_node; } ElementNode* next() { return m_next; } private: ElementNode* m_next { nullptr }; ExpressionNode* m_node; int m_elision; }; class ArrayNode final : public ExpressionNode { public: ArrayNode(const JSTokenLocation&, int elision); ArrayNode(const JSTokenLocation&, ElementNode*); ArrayNode(const JSTokenLocation&, int elision, ElementNode*); bool isArrayLiteral() const final { return true; } ArgumentListNode* toArgumentList(ParserArena&, int, int) const; ElementNode* elements() const { return m_element; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isSimpleArray() const final; ElementNode* m_element; int m_elision; }; enum class ClassElementTag : uint8_t { No, Instance, Static, LastTag }; class PropertyNode final : public ParserArenaFreeable { public: enum Type : uint16_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, PrivateField = 64, PrivateMethod = 128, PrivateSetter = 256, PrivateGetter = 512 }; PropertyNode(const Identifier&, ExpressionNode*, Type, SuperBinding, ClassElementTag); PropertyNode(ExpressionNode*, Type, SuperBinding, ClassElementTag); PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, SuperBinding, ClassElementTag); PropertyNode(const Identifier&, ExpressionNode* propertyName, ExpressionNode*, Type, SuperBinding, ClassElementTag); ExpressionNode* expressionName() const { return m_expression; } const Identifier* name() const { return m_name; } Type type() const { return static_cast(m_type); } bool needsSuperBinding() const { return m_needsSuperBinding; } bool isClassProperty() const { return static_cast(m_classElementTag) != ClassElementTag::No; } bool isStaticClassProperty() const { return static_cast(m_classElementTag) == ClassElementTag::Static; } bool isInstanceClassProperty() const { return static_cast(m_classElementTag) == ClassElementTag::Instance; } bool isClassField() const { return isClassProperty() && !needsSuperBinding(); } bool isInstanceClassField() const { return isInstanceClassProperty() && !needsSuperBinding(); } bool isStaticClassField() const { return isStaticClassProperty() && !needsSuperBinding(); } bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; } bool isPrivate() const { return m_type & (PrivateField | PrivateMethod | PrivateGetter | PrivateSetter); } bool hasComputedName() const { return m_expression; } bool isComputedClassField() const { return isClassField() && hasComputedName(); } void setIsOverriddenByDuplicate() { m_isOverriddenByDuplicate = true; } ALWAYS_INLINE static bool isUnderscoreProtoSetter(VM& vm, const PropertyNode& node) { return isUnderscoreProtoSetter(vm, node.name(), node.type(), node.needsSuperBinding(), node.isClassProperty()); } ALWAYS_INLINE static bool isUnderscoreProtoSetter(VM& vm, const Identifier* name, Type type, bool needsSuperBinding, bool isClassProperty) { return name && *name == vm.propertyNames->underscoreProto && type == Type::Constant && !needsSuperBinding && !isClassProperty; } private: friend class PropertyListNode; const Identifier* m_name; ExpressionNode* m_expression; ExpressionNode* m_assign; unsigned m_type : 10; unsigned m_needsSuperBinding : 1; static_assert(1 << 2 > static_cast(ClassElementTag::LastTag), "ClassElementTag shouldn't use more than two bits"); unsigned m_classElementTag : 2; unsigned m_isOverriddenByDuplicate : 1; }; class PropertyListNode final : public ExpressionNode { public: PropertyListNode(const JSTokenLocation&, PropertyNode*); PropertyListNode(const JSTokenLocation&, PropertyNode*, PropertyListNode*); bool hasStaticallyNamedProperty(const Identifier& propName); bool isComputedClassField() const { return m_node->isComputedClassField(); } bool isInstanceClassField() const { return m_node->isInstanceClassField(); } bool hasInstanceFields() const; bool isStaticClassField() const { return m_node->isStaticClassField(); } void setHasPrivateAccessors(bool hasPrivateAccessors) { m_hasPrivateAccessors = hasPrivateAccessors; } bool hasPrivateAccessors() const { return m_hasPrivateAccessors; } static bool shouldCreateLexicalScopeForClass(PropertyListNode*); RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector*, Vector*); void emitDeclarePrivateFieldNames(BytecodeGenerator&, RegisterID* scope); private: RegisterID* emitBytecode(BytecodeGenerator& generator, RegisterID* dst = nullptr) final { return emitBytecode(generator, dst, nullptr, nullptr, nullptr); } void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&); void emitSaveComputedFieldName(BytecodeGenerator&, PropertyNode&); PropertyNode* m_node; PropertyListNode* m_next { nullptr }; bool m_hasPrivateAccessors { false }; }; class ObjectLiteralNode final : public ExpressionNode { public: ObjectLiteralNode(const JSTokenLocation&); ObjectLiteralNode(const JSTokenLocation&, PropertyListNode*); bool isObjectLiteral() const final { return true; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; PropertyListNode* m_list; }; class BracketAccessorNode final : public ExpressionNode, public ThrowableExpressionData { public: BracketAccessorNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments); ExpressionNode* base() const { return m_base; } ExpressionNode* subscript() const { return m_subscript; } bool subscriptHasAssignments() const { return m_subscriptHasAssignments; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isLocation() const final { return true; } bool isBracketAccessorNode() const final { return true; } ExpressionNode* m_base; ExpressionNode* m_subscript; bool m_subscriptHasAssignments; }; enum class DotType { Name, PrivateMember }; class BaseDotNode : public ExpressionNode { public: BaseDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType); ExpressionNode* base() const { return m_base; } const Identifier& identifier() const { return m_ident; } DotType type() const { return m_type; } bool isPrivateMember() const { return m_type == DotType::PrivateMember; } RegisterID* emitGetPropertyValue(BytecodeGenerator&, RegisterID* dst, RegisterID* base, RefPtr& thisValue); RegisterID* emitGetPropertyValue(BytecodeGenerator&, RegisterID* dst, RegisterID* base); RegisterID* emitPutProperty(BytecodeGenerator&, RegisterID* base, RegisterID* value, RefPtr& thisValue); RegisterID* emitPutProperty(BytecodeGenerator&, RegisterID* base, RegisterID* value); protected: ExpressionNode* m_base; const Identifier& m_ident; DotType m_type; }; class DotAccessorNode final : public BaseDotNode, public ThrowableExpressionData { public: DotAccessorNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType); ExpressionNode* base() const { return m_base; } const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isLocation() const final { return true; } bool isPrivateLocation() const override { return m_type == DotType::PrivateMember; } bool isDotAccessorNode() const final { return true; } }; class SpreadExpressionNode final : public ExpressionNode, public ThrowableExpressionData { public: SpreadExpressionNode(const JSTokenLocation&, ExpressionNode*); ExpressionNode* expression() const { return m_expression; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isSpreadExpression() const final { return true; } ExpressionNode* m_expression; }; class ObjectSpreadExpressionNode final : public ExpressionNode, public ThrowableExpressionData { public: ObjectSpreadExpressionNode(const JSTokenLocation&, ExpressionNode*); ExpressionNode* expression() const { return m_expression; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expression; }; class ArgumentListNode final : public ExpressionNode { public: ArgumentListNode(const JSTokenLocation&, ExpressionNode*); ArgumentListNode(const JSTokenLocation&, ArgumentListNode*, ExpressionNode*); ArgumentListNode* m_next { nullptr }; ExpressionNode* m_expr; private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class ArgumentsNode final : public ParserArenaFreeable { public: ArgumentsNode(); ArgumentsNode(ArgumentListNode*, bool hasAssignments); bool hasAssignments() const { return m_hasAssignments; } ArgumentListNode* m_listNode; private: bool m_hasAssignments { false }; }; class NewExprNode final : public ExpressionNode, public ThrowableExpressionData { public: NewExprNode(const JSTokenLocation&, ExpressionNode*); NewExprNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; ArgumentsNode* m_args; }; class EvalFunctionCallNode final : public ExpressionNode, public ThrowableExpressionData { public: EvalFunctionCallNode(const JSTokenLocation&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionCall() const final { return true; } ArgumentsNode* m_args; }; class FunctionCallValueNode final : public ExpressionNode, public ThrowableExpressionData { public: FunctionCallValueNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionCall() const final { return true; } ExpressionNode* m_expr; ArgumentsNode* m_args; }; class FunctionCallResolveNode final : public ExpressionNode, public ThrowableExpressionData { public: FunctionCallResolveNode(const JSTokenLocation&, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionCall() const final { return true; } const Identifier& m_ident; ArgumentsNode* m_args; }; class FunctionCallBracketNode final : public ExpressionNode, public ThrowableSubExpressionData { public: FunctionCallBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionCall() const final { return true; } ExpressionNode* m_base; ExpressionNode* m_subscript; ArgumentsNode* m_args; bool m_subscriptHasAssignments; }; class FunctionCallDotNode : public BaseDotNode, public ThrowableSubExpressionData { public: FunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; protected: bool isFunctionCall() const override { return true; } ArgumentsNode* m_args; }; class BytecodeIntrinsicNode final : public ExpressionNode, public ThrowableExpressionData { public: enum class Type : uint8_t { Constant, Function }; BytecodeIntrinsicNode(Type, const JSTokenLocation&, BytecodeIntrinsicRegistry::Entry, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); bool isBytecodeIntrinsicNode() const final { return true; } Type type() const { return m_type; } BytecodeIntrinsicRegistry::Entry entry() const { return m_entry; } const Identifier& identifier() const { return m_ident; } #define JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS(name) RegisterID* emit_intrinsic_##name(BytecodeGenerator&, RegisterID*); JSC_COMMON_BYTECODE_INTRINSIC_FUNCTIONS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS) JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS) #undef JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionCall() const final { return m_type == Type::Function; } BytecodeIntrinsicRegistry::Entry m_entry; const Identifier& m_ident; ArgumentsNode* m_args; Type m_type; }; class CallFunctionCallDotNode final : public FunctionCallDotNode { public: CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; size_t m_distanceToInnermostCallOrApply; }; class ApplyFunctionCallDotNode final : public FunctionCallDotNode { public: ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; size_t m_distanceToInnermostCallOrApply; }; class HasOwnPropertyFunctionCallDotNode final : public FunctionCallDotNode { public: HasOwnPropertyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class DeleteResolveNode final : public ExpressionNode, public ThrowableExpressionData { public: DeleteResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isDeleteNode() const final { return true; } const Identifier& m_ident; }; class DeleteBracketNode final : public ExpressionNode, public ThrowableExpressionData { public: DeleteBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isDeleteNode() const final { return true; } ExpressionNode* m_base; ExpressionNode* m_subscript; }; class DeleteDotNode final : public ExpressionNode, public ThrowableExpressionData { public: DeleteDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isDeleteNode() const final { return true; } ExpressionNode* m_base; const Identifier& m_ident; }; class DeleteValueNode final : public ExpressionNode { public: DeleteValueNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isDeleteNode() const final { return true; } ExpressionNode* m_expr; }; class VoidNode final : public ExpressionNode { public: VoidNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class TypeOfResolveNode final : public ExpressionNode { public: TypeOfResolveNode(const JSTokenLocation&, const Identifier&); const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; }; class TypeOfValueNode final : public ExpressionNode { public: TypeOfValueNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class PrefixNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { public: PrefixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); protected: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; virtual RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = nullptr); virtual RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = nullptr); virtual RegisterID* emitDot(BytecodeGenerator&, RegisterID* = nullptr); ExpressionNode* m_expr; Operator m_operator; }; class PostfixNode final : public PrefixNode { public: PostfixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = nullptr) final; RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = nullptr) final; RegisterID* emitDot(BytecodeGenerator&, RegisterID* = nullptr) final; }; class UnaryOpNode : public ExpressionNode { public: UnaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode*, OpcodeID); protected: ExpressionNode* expr() { return m_expr; } const ExpressionNode* expr() const { return m_expr; } OpcodeID opcodeID() const { return m_opcodeID; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; ExpressionNode* m_expr; OpcodeID m_opcodeID; }; class UnaryPlusNode final : public UnaryOpNode { public: UnaryPlusNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* stripUnaryPlus() final { return expr(); } }; class NegateNode final : public UnaryOpNode { public: NegateNode(const JSTokenLocation&, ExpressionNode*); }; class BitwiseNotNode final : public UnaryOpNode { public: BitwiseNotNode(const JSTokenLocation&, ExpressionNode*); }; class LogicalNotNode final : public UnaryOpNode { public: LogicalNotNode(const JSTokenLocation&, ExpressionNode*); private: void emitBytecodeInConditionContext(BytecodeGenerator&, Label& trueTarget, Label& falseTarget, FallThroughMode) final; }; class BinaryOpNode : public ExpressionNode { public: BinaryOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); BinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); RegisterID* emitStrcat(BytecodeGenerator&, RegisterID* destination, RegisterID* lhs = nullptr, ReadModifyResolveNode* emitExpressionInfoForMe = nullptr); void emitBytecodeInConditionContext(BytecodeGenerator&, Label& trueTarget, Label& falseTarget, FallThroughMode) override; ExpressionNode* lhs() { return m_expr1; }; ExpressionNode* rhs() { return m_expr2; }; bool isBinaryOpNode() const override { return true; } private: enum class UInt32Result : uint8_t { UInt32, Constant, }; void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression); RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; protected: OpcodeID opcodeID() const { return m_opcodeID; } protected: bool m_rightHasAssignments; bool m_shouldToUnsignedResult { true }; private: OpcodeID m_opcodeID; protected: ExpressionNode* m_expr1; ExpressionNode* m_expr2; }; class PowNode final : public BinaryOpNode { public: PowNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class MultNode final : public BinaryOpNode { public: MultNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class DivNode final : public BinaryOpNode { public: DivNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class ModNode final : public BinaryOpNode { public: ModNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class AddNode final : public BinaryOpNode { public: AddNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); bool isAdd() const final { return true; } }; class SubNode final : public BinaryOpNode { public: SubNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); bool isSubtract() const final { return true; } }; class LeftShiftNode final : public BinaryOpNode { public: LeftShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class RightShiftNode final : public BinaryOpNode { public: RightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class UnsignedRightShiftNode final : public BinaryOpNode { public: UnsignedRightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class LessNode final : public BinaryOpNode { public: LessNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class GreaterNode final : public BinaryOpNode { public: GreaterNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class LessEqNode final : public BinaryOpNode { public: LessEqNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class GreaterEqNode final : public BinaryOpNode { public: GreaterEqNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData { public: ThrowableBinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); ThrowableBinaryOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; }; class InstanceOfNode final : public ThrowableBinaryOpNode { public: InstanceOfNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class InNode final : public ThrowableBinaryOpNode { public: InNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class EqualNode final : public BinaryOpNode { public: EqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class NotEqualNode final : public BinaryOpNode { public: NotEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class StrictEqualNode final : public BinaryOpNode { public: StrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class NotStrictEqualNode final : public BinaryOpNode { public: NotStrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitAndNode final : public BinaryOpNode { public: BitAndNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitOrNode final : public BinaryOpNode { public: BitOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitXOrNode final : public BinaryOpNode { public: BitXOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; // m_expr1 && m_expr2, m_expr1 || m_expr2 class LogicalOpNode final : public ExpressionNode { public: LogicalOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void emitBytecodeInConditionContext(BytecodeGenerator&, Label& trueTarget, Label& falseTarget, FallThroughMode) final; LogicalOperator m_operator; ExpressionNode* m_expr1; ExpressionNode* m_expr2; }; class CoalesceNode final : public ExpressionNode { public: CoalesceNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr1; ExpressionNode* m_expr2; bool m_hasAbsorbedOptionalChain; }; class OptionalChainNode final : public ExpressionNode { public: OptionalChainNode(const JSTokenLocation&, ExpressionNode*, bool); void setExpr(ExpressionNode* expr) { m_expr = expr; } ExpressionNode* expr() const { return m_expr; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isOptionalChain() const final { return true; } ExpressionNode* m_expr; bool m_isOutermost; }; // The ternary operator, "m_logical ? m_expr1 : m_expr2" class ConditionalNode final : public ExpressionNode { public: ConditionalNode(const JSTokenLocation&, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_logical; ExpressionNode* m_expr1; ExpressionNode* m_expr2; }; class ReadModifyResolveNode final : public ExpressionNode, public ThrowableExpressionData { public: ReadModifyResolveNode(const JSTokenLocation&, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; ExpressionNode* m_right; Operator m_operator; bool m_rightHasAssignments; }; class ShortCircuitReadModifyResolveNode final : public ExpressionNode, public ThrowableExpressionData { public: ShortCircuitReadModifyResolveNode(const JSTokenLocation&, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; ExpressionNode* m_right; Operator m_operator; bool m_rightHasAssignments; }; class AssignResolveNode final : public ExpressionNode, public ThrowableExpressionData { public: AssignResolveNode(const JSTokenLocation&, const Identifier&, ExpressionNode* right, AssignmentContext); bool isAssignResolveNode() const final { return true; } const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; ExpressionNode* m_right; AssignmentContext m_assignmentContext; }; class ReadModifyBracketNode final : public ExpressionNode, public ThrowableSubExpressionData { public: ReadModifyBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_base; ExpressionNode* m_subscript; ExpressionNode* m_right; Operator m_operator; bool m_subscriptHasAssignments : 1; bool m_rightHasAssignments : 1; }; class ShortCircuitReadModifyBracketNode final : public ExpressionNode, public ThrowableSubExpressionData { public: ShortCircuitReadModifyBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_base; ExpressionNode* m_subscript; ExpressionNode* m_right; Operator m_operator; bool m_subscriptHasAssignments : 1; bool m_rightHasAssignments : 1; }; class AssignBracketNode final : public ExpressionNode, public ThrowableExpressionData { public: AssignBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_base; ExpressionNode* m_subscript; ExpressionNode* m_right; bool m_subscriptHasAssignments : 1; bool m_rightHasAssignments : 1; }; class AssignDotNode final : public BaseDotNode, public ThrowableExpressionData { public: AssignDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_right; bool m_rightHasAssignments; }; class ReadModifyDotNode final : public BaseDotNode, public ThrowableSubExpressionData { public: ReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_right; Operator m_operator; bool m_rightHasAssignments : 1; }; class ShortCircuitReadModifyDotNode final : public ExpressionNode, public ThrowableSubExpressionData { public: ShortCircuitReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_base; const Identifier& m_ident; ExpressionNode* m_right; Operator m_operator; bool m_rightHasAssignments : 1; }; class AssignErrorNode final : public ExpressionNode, public ThrowableExpressionData { public: AssignErrorNode(const JSTokenLocation&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class CommaNode final : public ExpressionNode { public: CommaNode(const JSTokenLocation&, ExpressionNode*); void setNext(CommaNode* next) { m_next = next; } CommaNode* next() { return m_next; } private: bool isCommaNode() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; CommaNode* m_next { nullptr }; }; class SourceElements final : public ParserArenaFreeable { public: SourceElements(); void append(StatementNode*); StatementNode* singleStatement() const; StatementNode* lastStatement() const; bool hasCompletionValue() const; bool hasEarlyBreakOrContinue() const; void emitBytecode(BytecodeGenerator&, RegisterID* destination); void analyzeModule(ModuleAnalyzer&); private: StatementNode* m_head { nullptr }; StatementNode* m_tail { nullptr }; }; class BlockNode final : public StatementNode, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(BlockNode); public: BlockNode(const JSTokenLocation&, SourceElements*, VariableEnvironment&&, FunctionStack&&); StatementNode* singleStatement() const; StatementNode* lastStatement() const; private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool hasCompletionValue() const final; bool hasEarlyBreakOrContinue() const final; bool isBlock() const final { return true; } SourceElements* m_statements; }; class EmptyStatementNode final : public StatementNode { public: EmptyStatementNode(const JSTokenLocation&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool hasCompletionValue() const final { return false; } bool isEmptyStatement() const final { return true; } }; class DebuggerStatementNode final : public StatementNode { public: DebuggerStatementNode(const JSTokenLocation&); bool hasCompletionValue() const final { return false; } bool isDebuggerStatement() const final { return true; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class ExprStatementNode final : public StatementNode { public: ExprStatementNode(const JSTokenLocation&, ExpressionNode*); ExpressionNode* expr() const { return m_expr; } private: bool isExprStatement() const final { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class DeclarationStatement final : public StatementNode { public: DeclarationStatement(const JSTokenLocation&, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool hasCompletionValue() const final { return false; } ExpressionNode* m_expr; }; class EmptyVarExpression final : public ExpressionNode { public: EmptyVarExpression(const JSTokenLocation&, const Identifier&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; }; class EmptyLetExpression final : public ExpressionNode { public: EmptyLetExpression(const JSTokenLocation&, const Identifier&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; }; class IfElseNode final : public StatementNode { public: IfElseNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool tryFoldBreakAndContinue(BytecodeGenerator&, StatementNode* ifBlock, Label*& trueTarget, FallThroughMode&); ExpressionNode* m_condition; StatementNode* m_ifBlock; StatementNode* m_elseBlock; }; class DoWhileNode final : public StatementNode { public: DoWhileNode(const JSTokenLocation&, StatementNode*, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; StatementNode* m_statement; ExpressionNode* m_expr; }; class WhileNode final : public StatementNode { public: WhileNode(const JSTokenLocation&, ExpressionNode*, StatementNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; StatementNode* m_statement; }; class ForNode final : public StatementNode, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ForNode); public: ForNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode*, VariableEnvironment&&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr1; ExpressionNode* m_expr2; ExpressionNode* m_expr3; StatementNode* m_statement; }; class DestructuringPatternNode; class EnumerationNode : public StatementNode, public ThrowableExpressionData, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(EnumerationNode); public: EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&&); ExpressionNode* lexpr() const { return m_lexpr; } ExpressionNode* expr() const { return m_expr; } protected: ExpressionNode* m_lexpr; ExpressionNode* m_expr; StatementNode* m_statement; }; class ForInNode final : public EnumerationNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ForInNode); public: ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&&); private: RegisterID* tryGetBoundLocal(BytecodeGenerator&); void emitLoopHeader(BytecodeGenerator&, RegisterID* propertyName); void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class ForOfNode final : public EnumerationNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ForOfNode); public: ForOfNode(bool, const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&&); bool isForOfNode() const final { return true; } bool isForAwait() const { return m_isForAwait; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const bool m_isForAwait; }; class ContinueNode final : public StatementNode, public ThrowableExpressionData { public: ContinueNode(const JSTokenLocation&, const Identifier&); Label* trivialTarget(BytecodeGenerator&); private: bool hasCompletionValue() const final { return false; } bool isContinue() const final { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; }; class BreakNode final : public StatementNode, public ThrowableExpressionData { public: BreakNode(const JSTokenLocation&, const Identifier&); Label* trivialTarget(BytecodeGenerator&); private: bool hasCompletionValue() const final { return false; } bool isBreak() const final { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_ident; }; class ReturnNode final : public StatementNode, public ThrowableExpressionData { public: ReturnNode(const JSTokenLocation&, ExpressionNode* value); ExpressionNode* value() { return m_value; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isReturnNode() const final { return true; } ExpressionNode* m_value; }; class WithNode final : public StatementNode { public: WithNode(const JSTokenLocation&, ExpressionNode*, StatementNode*, const JSTextPosition& divot, uint32_t expressionLength); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; StatementNode* m_statement; JSTextPosition m_divot; uint32_t m_expressionLength; }; class LabelNode final : public StatementNode, public ThrowableExpressionData { public: LabelNode(const JSTokenLocation&, const Identifier& name, StatementNode*); bool isLabel() const final { return true; } private: bool hasCompletionValue() const final { return m_statement->hasCompletionValue(); } void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; const Identifier& m_name; StatementNode* m_statement; }; class ThrowNode final : public StatementNode, public ThrowableExpressionData { public: ThrowNode(const JSTokenLocation&, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; }; class TryNode final : public StatementNode, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(TryNode); public: TryNode(const JSTokenLocation&, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, VariableEnvironment&& catchEnvironment, StatementNode* finallyBlock); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; StatementNode* m_tryBlock; DestructuringPatternNode* m_catchPattern; StatementNode* m_catchBlock; StatementNode* m_finallyBlock; }; class ScopeNode : public StatementNode, public ParserArenaRoot, public VariableEnvironmentNode { public: // ScopeNode is never directly instantiate. The life-cycle of its derived classes are // managed using std::unique_ptr. Hence, though ScopeNode extends VariableEnvironmentNode, // which in turn extends ParserArenaDeletable, we don't want to use ParserArenaDeletable's // new for allocation. using ParserArenaRoot::operator new; ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, LexicalScopeFeatures); ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, const SourceCode&, SourceElements*, VariableEnvironment&&, FunctionStack&&, VariableEnvironment&&, UniquedStringImplPtrSet&&, CodeFeatures, LexicalScopeFeatures, InnerArrowFunctionCodeFeatures, int numConstants); const SourceCode& source() const { return m_source; } intptr_t sourceID() const { return m_source.providerID(); } int startLine() const { return m_startLineNumber; } int startStartOffset() const { return m_startStartOffset; } int startLineStartOffset() const { return m_startLineStartOffset; } CodeFeatures features() { return m_features; } LexicalScopeFeatures lexicalScopeFeatures() { return m_lexicalScopeFeatures; } InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures() { return m_innerArrowFunctionCodeFeatures; } bool doAnyInnerArrowFunctionsUseAnyFeature() { return m_innerArrowFunctionCodeFeatures != NoInnerArrowFunctionFeatures; } bool doAnyInnerArrowFunctionsUseArguments() { return m_innerArrowFunctionCodeFeatures & ArgumentsInnerArrowFunctionFeature; } bool doAnyInnerArrowFunctionsUseSuperCall() { return m_innerArrowFunctionCodeFeatures & SuperCallInnerArrowFunctionFeature; } bool doAnyInnerArrowFunctionsUseSuperProperty() { return m_innerArrowFunctionCodeFeatures & SuperPropertyInnerArrowFunctionFeature; } bool doAnyInnerArrowFunctionsUseEval() { return m_innerArrowFunctionCodeFeatures & EvalInnerArrowFunctionFeature; } bool doAnyInnerArrowFunctionsUseThis() { return m_innerArrowFunctionCodeFeatures & ThisInnerArrowFunctionFeature; } bool doAnyInnerArrowFunctionsUseNewTarget() { return m_innerArrowFunctionCodeFeatures & NewTargetInnerArrowFunctionFeature; } bool usesEval() const { return m_features & EvalFeature; } bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); } bool usesArrowFunction() const { return m_features & ArrowFunctionFeature; } bool isStrictMode() const { return m_lexicalScopeFeatures & StrictModeLexicalFeature; } bool usesThis() const { return m_features & ThisFeature; } bool usesSuperCall() const { return m_features & SuperCallFeature; } bool usesSuperProperty() const { return m_features & SuperPropertyFeature; } bool usesNewTarget() const { return m_features & NewTargetFeature; } bool needsActivation() const { return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature)); } bool hasCapturedVariables() const { return m_varDeclarations.hasCapturedVariables(); } bool captures(UniquedStringImpl* uid) { return m_varDeclarations.captures(uid); } bool captures(const Identifier& ident) { return captures(ident.impl()); } bool hasSloppyModeHoistedFunction(UniquedStringImpl* uid) const { return m_sloppyModeHoistedFunctions.contains(uid); } bool usesNonSimpleParameterList() const { return m_features & NonSimpleParameterListFeature; } bool needsNewTargetRegisterForThisScope() const { return usesSuperCall() || usesNewTarget(); } VariableEnvironment& varDeclarations() { return m_varDeclarations; } int neededConstants() { // We may need 2 more constants than the count given by the parser, // because of the various uses of jsUndefined() and jsNull(). return m_numConstants + 2; } StatementNode* singleStatement() const; bool hasCompletionValue() const override; bool hasEarlyBreakOrContinue() const override; void emitStatementsBytecode(BytecodeGenerator&, RegisterID* destination); void analyzeModule(ModuleAnalyzer&); protected: int m_startLineNumber; unsigned m_startStartOffset; unsigned m_startLineStartOffset; private: CodeFeatures m_features; LexicalScopeFeatures m_lexicalScopeFeatures; InnerArrowFunctionCodeFeatures m_innerArrowFunctionCodeFeatures; SourceCode m_source; VariableEnvironment m_varDeclarations; UniquedStringImplPtrSet m_sloppyModeHoistedFunctions; int m_numConstants; SourceElements* m_statements; }; class ProgramNode final : public ScopeNode { public: ProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&&, FunctionStack&&, VariableEnvironment&&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, LexicalScopeFeatures, InnerArrowFunctionCodeFeatures, int numConstants, RefPtr&&); unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } static constexpr bool scopeIsFunction = false; private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; unsigned m_startColumn; unsigned m_endColumn; }; class EvalNode final : public ScopeNode { public: EvalNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&&, FunctionStack&&, VariableEnvironment&&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, LexicalScopeFeatures, InnerArrowFunctionCodeFeatures, int numConstants, RefPtr&&); ALWAYS_INLINE unsigned startColumn() const { return 0; } unsigned endColumn() const { return m_endColumn; } static constexpr bool scopeIsFunction = false; private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; unsigned m_endColumn; }; class ModuleProgramNode final : public ScopeNode { public: ModuleProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&&, FunctionStack&&, VariableEnvironment&&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, LexicalScopeFeatures, InnerArrowFunctionCodeFeatures, int numConstants, RefPtr&&); unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } bool usesAwait() const { return m_usesAwait; } static constexpr bool scopeIsFunction = false; ModuleScopeData& moduleScopeData() { return m_moduleScopeData; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; unsigned m_startColumn; unsigned m_endColumn; bool m_usesAwait; Ref m_moduleScopeData; }; class ModuleNameNode final : public Node { public: ModuleNameNode(const JSTokenLocation&, const Identifier& moduleName); const Identifier& moduleName() { return m_moduleName; } private: const Identifier& m_moduleName; }; class ImportSpecifierNode final : public Node { public: ImportSpecifierNode(const JSTokenLocation&, const Identifier& importedName, const Identifier& localName); const Identifier& importedName() { return m_importedName; } const Identifier& localName() { return m_localName; } private: const Identifier& m_importedName; const Identifier& m_localName; }; class ImportSpecifierListNode final : public ParserArenaDeletable { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ImportSpecifierListNode); public: typedef Vector Specifiers; const Specifiers& specifiers() const { return m_specifiers; } void append(ImportSpecifierNode* specifier) { m_specifiers.append(specifier); } private: Specifiers m_specifiers; }; class ModuleDeclarationNode : public StatementNode { public: virtual void analyzeModule(ModuleAnalyzer&) = 0; bool hasCompletionValue() const override { return false; } bool isModuleDeclarationNode() const override { return true; } protected: ModuleDeclarationNode(const JSTokenLocation&); }; class ImportDeclarationNode final : public ModuleDeclarationNode { public: ImportDeclarationNode(const JSTokenLocation&, ImportSpecifierListNode*, ModuleNameNode*); ImportSpecifierListNode* specifierList() const { return m_specifierList; } ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void analyzeModule(ModuleAnalyzer&) final; ImportSpecifierListNode* m_specifierList; ModuleNameNode* m_moduleName; }; class ExportAllDeclarationNode final : public ModuleDeclarationNode { public: ExportAllDeclarationNode(const JSTokenLocation&, ModuleNameNode*); ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void analyzeModule(ModuleAnalyzer&) final; ModuleNameNode* m_moduleName; }; class ExportDefaultDeclarationNode final : public ModuleDeclarationNode { public: ExportDefaultDeclarationNode(const JSTokenLocation&, StatementNode*, const Identifier& localName); const StatementNode& declaration() const { return *m_declaration; } const Identifier& localName() const { return m_localName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void analyzeModule(ModuleAnalyzer&) final; StatementNode* m_declaration; const Identifier& m_localName; }; class ExportLocalDeclarationNode final : public ModuleDeclarationNode { public: ExportLocalDeclarationNode(const JSTokenLocation&, StatementNode*); const StatementNode& declaration() const { return *m_declaration; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void analyzeModule(ModuleAnalyzer&) final; StatementNode* m_declaration; }; class ExportSpecifierNode final : public Node { public: ExportSpecifierNode(const JSTokenLocation&, const Identifier& localName, const Identifier& exportedName); const Identifier& exportedName() { return m_exportedName; } const Identifier& localName() { return m_localName; } private: const Identifier& m_localName; const Identifier& m_exportedName; }; class ExportSpecifierListNode final : public ParserArenaDeletable { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ExportSpecifierListNode); public: typedef Vector Specifiers; const Specifiers& specifiers() const { return m_specifiers; } void append(ExportSpecifierNode* specifier) { m_specifiers.append(specifier); } private: Specifiers m_specifiers; }; class ExportNamedDeclarationNode final : public ModuleDeclarationNode { public: ExportNamedDeclarationNode(const JSTokenLocation&, ExportSpecifierListNode*, ModuleNameNode*); ExportSpecifierListNode* specifierList() const { return m_specifierList; } ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; void analyzeModule(ModuleAnalyzer&) final; ExportSpecifierListNode* m_specifierList; ModuleNameNode* m_moduleName { nullptr }; }; class FunctionMetadataNode final : public ParserArenaDeletable, public Node { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(FunctionMetadataNode); public: FunctionMetadataNode( ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, int functionKeywordStart, int functionNameStart, int parametersStart, LexicalScopeFeatures, ConstructorKind, SuperBinding, unsigned parameterCount, SourceParseMode, bool isArrowFunctionBodyExpression); FunctionMetadataNode( const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, int functionKeywordStart, int functionNameStart, int parametersStart, LexicalScopeFeatures, ConstructorKind, SuperBinding, unsigned parameterCount, SourceParseMode, bool isArrowFunctionBodyExpression); void dump(PrintStream&) const; void finishParsing(const SourceCode&, const Identifier&, FunctionMode); void overrideName(const Identifier& ident) { m_ident = ident; } const Identifier& ident() { return m_ident; } void setEcmaName(const Identifier& ecmaName) { m_ecmaName = ecmaName; } const Identifier& ecmaName() { return m_ident.isEmpty() ? m_ecmaName : m_ident; } void setPrivateBrandRequirement(PrivateBrandRequirement privateBrandRequirement) { m_privateBrandRequirement = static_cast(privateBrandRequirement); } PrivateBrandRequirement privateBrandRequirement() { return static_cast(m_privateBrandRequirement); } FunctionMode functionMode() { return m_functionMode; } int functionNameStart() const { return m_functionNameStart; } int functionKeywordStart() const { return m_functionKeywordStart; } int parametersStart() const { return m_parametersStart; } unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } unsigned parameterCount() const { return m_parameterCount; } SourceParseMode parseMode() const { return m_parseMode; } void setEndPosition(JSTextPosition); const SourceCode& source() const { return m_source; } const SourceCode& classSource() const { return m_classSource; } void setClassSource(const SourceCode& source) { m_classSource = source; } int startStartOffset() const { return m_startStartOffset; } LexicalScopeFeatures lexicalScopeFeatures() const { return static_cast(m_lexicalScopeFeatures); } SuperBinding superBinding() { return static_cast(m_superBinding); } ConstructorKind constructorKind() { return static_cast(m_constructorKind); } bool isConstructorAndNeedsClassFieldInitializer() const { return m_needsClassFieldInitializer; } void setNeedsClassFieldInitializer(bool value) { ASSERT(!value || constructorKind() != ConstructorKind::None); m_needsClassFieldInitializer = value; } bool isArrowFunctionBodyExpression() const { return m_isArrowFunctionBodyExpression; } void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset) { m_lastLine = lastLine; m_position = JSTextPosition(firstLine, startOffset, lineStartOffset); ASSERT(m_position.offset >= m_position.lineStartOffset); } unsigned lastLine() const { return m_lastLine; } bool operator==(const FunctionMetadataNode&) const; bool operator!=(const FunctionMetadataNode& other) const { return !(*this == other); } public: unsigned m_lexicalScopeFeatures : 4; unsigned m_superBinding : 1; unsigned m_constructorKind : 2; unsigned m_needsClassFieldInitializer : 1; unsigned m_isArrowFunctionBodyExpression : 1; unsigned m_privateBrandRequirement : 1; SourceParseMode m_parseMode; FunctionMode m_functionMode; Identifier m_ident; Identifier m_ecmaName; unsigned m_startColumn; unsigned m_endColumn; int m_functionKeywordStart; int m_functionNameStart; int m_parametersStart; SourceCode m_source; SourceCode m_classSource; int m_startStartOffset; unsigned m_parameterCount; int m_lastLine { 0 }; }; class FunctionNode final : public ScopeNode { public: FunctionNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&&, FunctionStack&&, VariableEnvironment&&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, LexicalScopeFeatures, InnerArrowFunctionCodeFeatures, int numConstants, RefPtr&&); FunctionParameters* parameters() const { return m_parameters; } void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isFunctionNode() const final { return true; } void finishParsing(const Identifier&, FunctionMode); const Identifier& ident() { return m_ident; } FunctionMode functionMode() const { return m_functionMode; } unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } static constexpr bool scopeIsFunction = true; private: Identifier m_ident; FunctionMode m_functionMode; FunctionParameters* m_parameters; unsigned m_startColumn; unsigned m_endColumn; }; class BaseFuncExprNode : public ExpressionNode { public: FunctionMetadataNode* metadata() { return m_metadata; } bool isBaseFuncExprNode() const override { return true; } protected: BaseFuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&, FunctionMode); FunctionMetadataNode* m_metadata; }; class FuncExprNode : public BaseFuncExprNode { public: FuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); protected: FuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&, FunctionMode); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override; bool isFuncExprNode() const override { return true; } }; class ArrowFuncExprNode final : public BaseFuncExprNode { public: ArrowFuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isArrowFuncExprNode() const final { return true; } }; class MethodDefinitionNode final : public FuncExprNode { public: MethodDefinitionNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; }; class YieldExprNode final : public ExpressionNode, public ThrowableExpressionData { public: YieldExprNode(const JSTokenLocation&, ExpressionNode* argument, bool delegate); ExpressionNode* argument() const { return m_argument; } bool delegate() const { return m_delegate; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_argument; bool m_delegate; }; class AwaitExprNode final : public ExpressionNode, public ThrowableExpressionData { public: AwaitExprNode(const JSTokenLocation&, ExpressionNode* argument); ExpressionNode* argument() const { return m_argument; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_argument; }; class DefineFieldNode final : public StatementNode { public: enum class Type { Name, PrivateName, ComputedName }; DefineFieldNode(const JSTokenLocation&, const Identifier*, ExpressionNode*, Type); private: void emitBytecode(BytecodeGenerator&, RegisterID* destination = nullptr) final; bool isDefineFieldNode() const final { return true; } const Identifier* m_ident; ExpressionNode* m_assign; Type m_type; }; class ClassExprNode final : public ExpressionNode, public ThrowableExpressionData, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ClassExprNode); public: ClassExprNode(const JSTokenLocation&, const Identifier&, const SourceCode& classSource, VariableEnvironment&& classHeadEnvironment, VariableEnvironment&& classEnvironment, ExpressionNode* constructorExpresssion, ExpressionNode* parentClass, PropertyListNode* classElements); const Identifier& name() { return m_name; } const Identifier& ecmaName() { return m_ecmaName ? *m_ecmaName : m_name; } void setEcmaName(const Identifier& name) { m_ecmaName = m_name.isNull() ? &name : &m_name; } bool hasStaticProperty(const Identifier& propName) { return m_classElements ? m_classElements->hasStaticallyNamedProperty(propName) : false; } bool hasInstanceFields() const { return m_classElements ? m_classElements->hasInstanceFields() : false; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool isClassExprNode() const final { return true; } VariableEnvironment m_classHeadEnvironment; SourceCode m_classSource; const Identifier& m_name; const Identifier* m_ecmaName; ExpressionNode* m_constructorExpression; ExpressionNode* m_classHeritage; PropertyListNode* m_classElements; bool m_needsLexicalScope; }; class DestructuringPatternNode : public ParserArenaFreeable { public: virtual ~DestructuringPatternNode() { } virtual void collectBoundIdentifiers(Vector&) const = 0; virtual void bindValue(BytecodeGenerator&, RegisterID* source) const = 0; virtual void toString(StringBuilder&) const = 0; virtual bool isBindingNode() const { return false; } virtual bool isAssignmentElementNode() const { return false; } virtual bool isRestParameter() const { return false; } virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return nullptr; } virtual RegisterID* writableDirectBindingIfPossible(BytecodeGenerator&) const { return nullptr; } virtual void finishDirectBindingAssignment(BytecodeGenerator&) const { } protected: DestructuringPatternNode(); }; class ArrayPatternNode final : public DestructuringPatternNode, public ParserArenaDeletable, public ThrowableExpressionData { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ArrayPatternNode); public: ArrayPatternNode(); enum class BindingType : uint8_t { Elision, Element, RestElement }; void appendIndex(BindingType bindingType, const JSTokenLocation&, DestructuringPatternNode* node, ExpressionNode* defaultValue) { m_targetPatterns.append({ bindingType, node, defaultValue }); } private: struct Entry { BindingType bindingType; DestructuringPatternNode* pattern; ExpressionNode* defaultValue; }; void collectBoundIdentifiers(Vector&) const final; void bindValue(BytecodeGenerator&, RegisterID*) const final; RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*) final; void toString(StringBuilder&) const final; Vector m_targetPatterns; }; class ObjectPatternNode final : public DestructuringPatternNode, public ParserArenaDeletable, public ThrowableExpressionData { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ObjectPatternNode); public: ObjectPatternNode(); enum class BindingType : uint8_t { Element, RestElement }; void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DestructuringPatternNode* pattern, ExpressionNode* defaultValue, BindingType bindingType) { m_targetPatterns.append(Entry{ identifier, nullptr, wasString, pattern, defaultValue, bindingType }); } void appendEntry(VM& vm, const JSTokenLocation&, ExpressionNode* propertyExpression, DestructuringPatternNode* pattern, ExpressionNode* defaultValue, BindingType bindingType) { m_targetPatterns.append(Entry{ vm.propertyNames->nullIdentifier, propertyExpression, false, pattern, defaultValue, bindingType }); } void setContainsRestElement(bool containsRestElement) { m_containsRestElement = containsRestElement; } void setContainsComputedProperty(bool containsComputedProperty) { m_containsComputedProperty = containsComputedProperty; } private: void collectBoundIdentifiers(Vector&) const final; void bindValue(BytecodeGenerator&, RegisterID*) const final; void toString(StringBuilder&) const final; struct Entry { const Identifier& propertyName; ExpressionNode* propertyExpression; bool wasString; DestructuringPatternNode* pattern; ExpressionNode* defaultValue; BindingType bindingType; }; bool m_containsRestElement { false }; bool m_containsComputedProperty { false }; Vector m_targetPatterns; }; class BindingNode final: public DestructuringPatternNode { public: BindingNode(const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end, AssignmentContext); const Identifier& boundProperty() const { return m_boundProperty; } const JSTextPosition& divotStart() const { return m_divotStart; } const JSTextPosition& divotEnd() const { return m_divotEnd; } RegisterID* writableDirectBindingIfPossible(BytecodeGenerator&) const final; void finishDirectBindingAssignment(BytecodeGenerator&) const; private: void collectBoundIdentifiers(Vector&) const final; void bindValue(BytecodeGenerator&, RegisterID*) const final; void toString(StringBuilder&) const final; bool isBindingNode() const final { return true; } JSTextPosition m_divotStart; JSTextPosition m_divotEnd; const Identifier& m_boundProperty; AssignmentContext m_bindingContext; }; class RestParameterNode final : public DestructuringPatternNode { public: RestParameterNode(DestructuringPatternNode*, unsigned numParametersToSkip); bool isRestParameter() const final { return true; } void emit(BytecodeGenerator&); private: void collectBoundIdentifiers(Vector&) const final; void bindValue(BytecodeGenerator&, RegisterID*) const final; void toString(StringBuilder&) const final; DestructuringPatternNode* m_pattern; unsigned m_numParametersToSkip; }; class AssignmentElementNode final : public DestructuringPatternNode { public: AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end); const ExpressionNode* assignmentTarget() { return m_assignmentTarget; } const JSTextPosition& divotStart() const { return m_divotStart; } const JSTextPosition& divotEnd() const { return m_divotEnd; } RegisterID* writableDirectBindingIfPossible(BytecodeGenerator&) const final; void finishDirectBindingAssignment(BytecodeGenerator&) const; private: void collectBoundIdentifiers(Vector&) const final; void bindValue(BytecodeGenerator&, RegisterID*) const final; void toString(StringBuilder&) const final; bool isAssignmentElementNode() const final { return true; } JSTextPosition m_divotStart; JSTextPosition m_divotEnd; ExpressionNode* m_assignmentTarget; }; class DestructuringAssignmentNode final : public ExpressionNode { public: DestructuringAssignmentNode(const JSTokenLocation&, DestructuringPatternNode*, ExpressionNode*); DestructuringPatternNode* bindings() { return m_bindings; } private: bool isAssignmentLocation() const final { return true; } bool isDestructuringNode() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; DestructuringPatternNode* m_bindings; ExpressionNode* m_initializer; }; class FunctionParameters final : public ParserArenaDeletable { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(FunctionParameters); public: FunctionParameters(); ALWAYS_INLINE unsigned size() const { return m_patterns.size(); } ALWAYS_INLINE std::pair at(unsigned index) { return m_patterns[index]; } ALWAYS_INLINE void append(DestructuringPatternNode* pattern, ExpressionNode* defaultValue) { ASSERT(pattern); // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation // This implements IsSimpleParameterList in the Ecma 2015 spec. // If IsSimpleParameterList is false, we will create a strict-mode like arguments object. // IsSimpleParameterList is false if the argument list contains any default parameter values, // a rest parameter, or any destructuring patterns. // If we do have default parameters, destructuring parameters, or a rest parameter, our parameters will be allocated in a different scope. bool hasDefaultParameterValue = defaultValue; bool isSimpleParameter = !hasDefaultParameterValue && pattern->isBindingNode(); m_isSimpleParameterList &= isSimpleParameter; m_patterns.append(std::make_pair(pattern, defaultValue)); } ALWAYS_INLINE bool isSimpleParameterList() const { return m_isSimpleParameterList; } private: Vector<:pair expressionnode>, 3> m_patterns; bool m_isSimpleParameterList { true }; }; class FuncDeclNode final : public StatementNode { public: FuncDeclNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); bool hasCompletionValue() const final { return false; } bool isFuncDeclNode() const final { return true; } FunctionMetadataNode* metadata() { return m_metadata; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; FunctionMetadataNode* m_metadata; }; class ClassDeclNode final : public StatementNode { public: ClassDeclNode(const JSTokenLocation&, ExpressionNode* classExpression); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; bool hasCompletionValue() const final { return false; } ExpressionNode* m_classDeclaration; }; class CaseClauseNode final : public ParserArenaFreeable { public: CaseClauseNode(ExpressionNode*, SourceElements* = nullptr); ExpressionNode* expr() const { return m_expr; } void emitBytecode(BytecodeGenerator&, RegisterID* destination); void setStartOffset(int offset) { m_startOffset = offset; } private: ExpressionNode* m_expr; SourceElements* m_statements; int m_startOffset; }; class ClauseListNode final : public ParserArenaFreeable { public: ClauseListNode(CaseClauseNode*); ClauseListNode(ClauseListNode*, CaseClauseNode*); CaseClauseNode* getClause() const { return m_clause; } ClauseListNode* getNext() const { return m_next; } private: CaseClauseNode* m_clause; ClauseListNode* m_next { nullptr }; }; class CaseBlockNode final : public ParserArenaFreeable { public: CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2); void emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* destination); private: SwitchInfo::SwitchType tryTableSwitch(Vector& literalVector, int32_t& min_num, int32_t& max_num); static constexpr size_t s_tableSwitchMinimum = 3; ClauseListNode* m_list1; CaseClauseNode* m_defaultClause; ClauseListNode* m_list2; }; class SwitchNode final : public StatementNode, public VariableEnvironmentNode { JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(SwitchNode); public: SwitchNode(const JSTokenLocation&, ExpressionNode*, CaseBlockNode*, VariableEnvironment&&, FunctionStack&&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; ExpressionNode* m_expr; CaseBlockNode* m_block; }; struct ElementList { ElementNode* head; ElementNode* tail; }; struct PropertyList { PropertyListNode* head; PropertyListNode* tail; }; struct ArgumentList { ArgumentListNode* head; ArgumentListNode* tail; }; struct ClauseList { ClauseListNode* head; ClauseListNode* tail; }; } // namespace JSC