| /* |
| * 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*, ExpressionNode*); |
| |
| private: |
| bool isImportNode() const final { return true; } |
| RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; |
| |
| ExpressionNode* m_expr; |
| ExpressionNode* m_option; |
| }; |
| |
| 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 ImportAssertionListNode final : public ParserArenaDeletable { |
| JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ImportAssertionListNode); |
| public: |
| using Assertions = Vector<std::tuple<const Identifier*, const Identifier*>, 3>; |
| |
| const Assertions& assertions() const { return m_assertions; } |
| void append(const Identifier& key, const Identifier& value) |
| { |
| m_assertions.append(std::tuple { &key, &value }); |
| } |
| |
| private: |
| Assertions m_assertions; |
| }; |
| |
| 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*, ImportAssertionListNode*); |
| |
| ImportSpecifierListNode* specifierList() const { return m_specifierList; } |
| ModuleNameNode* moduleName() const { return m_moduleName; } |
| ImportAssertionListNode* assertionList() const { return m_assertionList; } |
| |
| private: |
| void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; |
| void analyzeModule(ModuleAnalyzer&) final; |
| |
| ImportSpecifierListNode* m_specifierList; |
| ModuleNameNode* m_moduleName; |
| ImportAssertionListNode* m_assertionList; |
| }; |
| |
| class ExportAllDeclarationNode final : public ModuleDeclarationNode { |
| public: |
| ExportAllDeclarationNode(const JSTokenLocation&, ModuleNameNode*, ImportAssertionListNode*); |
| |
| ModuleNameNode* moduleName() const { return m_moduleName; } |
| ImportAssertionListNode* assertionList() const { return m_assertionList; } |
| |
| private: |
| void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; |
| void analyzeModule(ModuleAnalyzer&) final; |
| |
| ModuleNameNode* m_moduleName; |
| ImportAssertionListNode* m_assertionList; |
| }; |
| |
| 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*, ImportAssertionListNode*); |
| |
| ExportSpecifierListNode* specifierList() const { return m_specifierList; } |
| ModuleNameNode* moduleName() const { return m_moduleName; } |
| ImportAssertionListNode* assertionList() const { return m_assertionList; } |
| |
| private: |
| void emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final; |
| void analyzeModule(ModuleAnalyzer&) final; |
| ExportSpecifierListNode* m_specifierList; |
| ModuleNameNode* m_moduleName { nullptr }; |
| ImportAssertionListNode* m_assertionList { 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 |