|  | /* | 
|  | *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | 
|  | *  Copyright (C) 2001 Peter Kelly (pmk@post.com) | 
|  | *  Copyright (C) 2003-2019 Apple Inc. All rights reserved. | 
|  | *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) | 
|  | *  Copyright (C) 2007 Maks Orlovich | 
|  | *  Copyright (C) 2007 Eric Seidel <eric@webkit.org> | 
|  | * | 
|  | *  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 <wtf/MathExtras.h> | 
|  | #include <wtf/SmallSet.h> | 
|  |  | 
|  | 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<UniquedStringImpl*> 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>(!fallThroughMode); } | 
|  |  | 
|  | namespace DeclarationStacks { | 
|  | typedef Vector<FunctionMetadataNode*> 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<typename T> 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<int>(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<int>(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<Type>(m_type); } | 
|  | bool needsSuperBinding() const { return m_needsSuperBinding; } | 
|  | bool isClassProperty() const { return static_cast<ClassElementTag>(m_classElementTag) != ClassElementTag::No; } | 
|  | bool isStaticClassProperty() const { return static_cast<ClassElementTag>(m_classElementTag) == ClassElementTag::Static; } | 
|  | bool isInstanceClassProperty() const { return static_cast<ClassElementTag>(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<unsigned>(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<JSTextPosition>*, Vector<JSTextPosition>*); | 
|  |  | 
|  | 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<RegisterID>& thisValue); | 
|  | RegisterID* emitGetPropertyValue(BytecodeGenerator&, RegisterID* dst, RegisterID* base); | 
|  | RegisterID* emitPutProperty(BytecodeGenerator&, RegisterID* base, RegisterID* value, RefPtr<RegisterID>& 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 BaseDotNode, public ThrowableSubExpressionData { | 
|  | public: | 
|  | ShortCircuitReadModifyDotNode(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 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; } | 
|  | SourceID 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<ModuleScopeData>&&); | 
|  |  | 
|  | 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<ModuleScopeData>&&); | 
|  |  | 
|  | 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<ModuleScopeData>&&); | 
|  |  | 
|  | 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<ModuleScopeData> 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<ImportSpecifierNode*, 3> 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<ExportSpecifierNode*, 3> 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<unsigned>(privateBrandRequirement); } | 
|  | PrivateBrandRequirement privateBrandRequirement() { return static_cast<PrivateBrandRequirement>(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<LexicalScopeFeatures>(m_lexicalScopeFeatures); } | 
|  | SuperBinding superBinding() { return static_cast<SuperBinding>(m_superBinding); } | 
|  | ConstructorKind constructorKind() { return static_cast<ConstructorKind>(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<ModuleScopeData>&&); | 
|  |  | 
|  | 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<Identifier>&) 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<Identifier>&) const final; | 
|  | void bindValue(BytecodeGenerator&, RegisterID*) const final; | 
|  | RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*) final; | 
|  | void toString(StringBuilder&) const final; | 
|  |  | 
|  | Vector<Entry> 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<Identifier>&) 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<Entry> 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<Identifier>&) 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<Identifier>&) 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<Identifier>&) 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<DestructuringPatternNode*, ExpressionNode*> 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<std::pair<DestructuringPatternNode*, 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<ExpressionNode*, 8>& 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 |