/* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003-2009, 2013, 2015-2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef Nodes_h #define Nodes_h #include "Error.h" #include "JITCode.h" #include "Opcode.h" #include "ParserArena.h" #include "ParserTokens.h" #include "ResultType.h" #include "SourceCode.h" #include "SymbolTable.h" #include "VariableEnvironment.h" #include #include namespace JSC { class ArgumentListNode; class BytecodeGenerator; class FunctionMetadataNode; class FunctionParameters; class Label; class PropertyListNode; class ReadModifyResolveNode; class RegisterID; class JSScope; class ScopeNode; class ModuleAnalyzer; typedef SmallPtrSet UniquedStringImplPtrSet; enum Operator { OpEqual, OpPlusEq, OpMinusEq, OpMultEq, OpDivEq, OpPlusPlus, OpMinusMinus, OpAndEq, OpXOrEq, OpOrEq, OpModEq, OpLShift, OpRShift, OpURShift }; enum LogicalOperator { OpLogicalAnd, OpLogicalOr }; enum FallThroughMode { FallThroughMeansTrue = 0, FallThroughMeansFalse = 1 }; inline FallThroughMode invert(FallThroughMode fallThroughMode) { return static_cast(!fallThroughMode); } namespace DeclarationStacks { typedef Vector FunctionStack; } struct SwitchInfo { enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString }; uint32_t bytecodeOffset; SwitchType switchType; }; enum class AssignmentContext { DeclarationStatement, ConstDeclarationStatement, AssignmentExpression }; class ParserArenaFreeable { public: // ParserArenaFreeable objects are 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. void* operator new(size_t, ParserArena&); }; class ParserArenaRoot { WTF_MAKE_FAST_ALLOCATED; 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; } protected: JSTextPosition m_position; int m_endOffset; }; class ExpressionNode : public Node { protected: ExpressionNode(const JSTokenLocation&, ResultType = ResultType::unknownType()); public: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0; virtual bool isNumber() const { return false; } virtual bool isString() 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 isAssignmentLocation() const { return isLocation(); } virtual bool isResolveNode() const { return false; } virtual bool isBracketAccessorNode() const { return false; } virtual bool isDotAccessorNode() const { return false; } virtual bool isDestructuringNode() 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 isSpreadExpression() const { return false; } virtual bool isSuperNode() const { return false; } virtual bool isNewTarget() const { return false; } virtual bool isBytecodeIntrinsicNode() const { return false; } virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, FallThroughMode); virtual ExpressionNode* stripUnaryPlus() { return this; } ResultType resultDescriptor() const { return m_resultType; } private: ResultType m_resultType; }; class StatementNode : public Node { protected: StatementNode(const JSTokenLocation&); public: virtual void emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0; void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset); unsigned lastLine() const { return m_lastLine; } StatementNode* next() { return m_next; } void setNext(StatementNode* next) { m_next = next; } virtual bool isEmptyStatement() 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 isBlock() const { return false; } virtual bool isFuncDeclNode() const { return false; } virtual bool isModuleDeclarationNode() const { return false; } protected: StatementNode* m_next; int m_lastLine; }; class VariableEnvironmentNode : public ParserArenaDeletable { public: typedef DeclarationStacks::FunctionStack FunctionStack; VariableEnvironmentNode() { } 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* = 0) override; void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override; }; class NullNode : public ConstantNode { public: NullNode(const JSTokenLocation&); private: bool isNull() const override { return true; } JSValue jsValue(BytecodeGenerator&) const override { return jsNull(); } }; class BooleanNode : public ConstantNode { public: BooleanNode(const JSTokenLocation&, bool value); bool value() { return m_value; } private: bool isBoolean() const override { return true; } JSValue jsValue(BytecodeGenerator&) const override { 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* = 0) 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 : public DoubleNode { public: IntegerNode(const JSTokenLocation&, double value); bool isIntegerNode() const final { return true; } }; class StringNode : public ConstantNode { public: StringNode(const JSTokenLocation&, const Identifier&); const Identifier& value() { return m_value; } private: bool isString() const override { return true; } JSValue jsValue(BytecodeGenerator&) const override; const Identifier& m_value; }; class ThrowableExpressionData { public: ThrowableExpressionData() : m_divot(-1, -1, -1) , m_divotStart(-1, -1, -1) , m_divotEnd(-1, -1, -1) { } ThrowableExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end) : m_divot(divot) , m_divotStart(start) , m_divotEnd(end) { ASSERT(m_divot.offset >= m_divot.lineStartOffset); ASSERT(m_divotStart.offset >= m_divotStart.lineStartOffset); ASSERT(m_divotEnd.offset >= m_divotEnd.lineStartOffset); } void setExceptionSourceCode(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) { ASSERT(divot.offset >= divot.lineStartOffset); ASSERT(divotStart.offset >= divotStart.lineStartOffset); ASSERT(divotEnd.offset >= divotEnd.lineStartOffset); m_divot = divot; m_divotStart = divotStart; m_divotEnd = divotEnd; } const JSTextPosition& divot() const { return m_divot; } const JSTextPosition& divotStart() const { return m_divotStart; } const JSTextPosition& divotEnd() const { return m_divotEnd; } protected: RegisterID* emitThrowReferenceError(BytecodeGenerator&, const String& message); private: JSTextPosition m_divot; JSTextPosition m_divotStart; JSTextPosition m_divotEnd; }; class ThrowableSubExpressionData : public ThrowableExpressionData { public: ThrowableSubExpressionData() : m_subexpressionDivotOffset(0) , m_subexpressionEndOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } ThrowableSubExpressionData(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) : ThrowableExpressionData(divot, divotStart, divotEnd) , m_subexpressionDivotOffset(0) , m_subexpressionEndOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset) { ASSERT(subexpressionDivot.offset <= divot().offset); // Overflow means we can't do this safely, so just point at the primary divot, // divotLine, or divotLineStart. if ((divot() - subexpressionDivot.offset) & ~0xFFFF) return; if ((divot().line - subexpressionDivot.line) & ~0xFFFF) return; if ((divot().lineStartOffset - subexpressionDivot.lineStartOffset) & ~0xFFFF) return; if ((divotEnd() - subexpressionOffset) & ~0xFFFF) return; m_subexpressionDivotOffset = divot() - subexpressionDivot.offset; m_subexpressionEndOffset = divotEnd() - subexpressionOffset; m_subexpressionLineOffset = divot().line - subexpressionDivot.line; m_subexpressionLineStartOffset = divot().lineStartOffset - subexpressionDivot.lineStartOffset; } JSTextPosition subexpressionDivot() { int newLine = divot().line - m_subexpressionLineOffset; int newOffset = divot().offset - m_subexpressionDivotOffset; int newLineStartOffset = divot().lineStartOffset - m_subexpressionLineStartOffset; return JSTextPosition(newLine, newOffset, newLineStartOffset); } JSTextPosition subexpressionStart() { return divotStart(); } JSTextPosition subexpressionEnd() { return divotEnd() - static_cast(m_subexpressionEndOffset); } protected: uint16_t m_subexpressionDivotOffset; uint16_t m_subexpressionEndOffset; uint16_t m_subexpressionLineOffset; uint16_t m_subexpressionLineStartOffset; }; class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData { public: ThrowablePrefixedSubExpressionData() : m_subexpressionDivotOffset(0) , m_subexpressionStartOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } ThrowablePrefixedSubExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end) : ThrowableExpressionData(divot, start, end) , m_subexpressionDivotOffset(0) , m_subexpressionStartOffset(0) , m_subexpressionLineOffset(0) , m_subexpressionLineStartOffset(0) { } void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset) { ASSERT(subexpressionDivot.offset >= divot().offset); // Overflow means we can't do this safely, so just point at the primary divot, // divotLine, or divotLineStart. if ((subexpressionDivot.offset - divot()) & ~0xFFFF) return; if ((subexpressionDivot.line - divot().line) & ~0xFFFF) return; if ((subexpressionDivot.lineStartOffset - divot().lineStartOffset) & ~0xFFFF) return; if ((subexpressionOffset - divotStart()) & ~0xFFFF) return; m_subexpressionDivotOffset = subexpressionDivot.offset - divot(); m_subexpressionStartOffset = subexpressionOffset - divotStart(); m_subexpressionLineOffset = subexpressionDivot.line - divot().line; m_subexpressionLineStartOffset = subexpressionDivot.lineStartOffset - divot().lineStartOffset; } JSTextPosition subexpressionDivot() { int newLine = divot().line + m_subexpressionLineOffset; int newOffset = divot().offset + m_subexpressionDivotOffset; int newLineStartOffset = divot().lineStartOffset + m_subexpressionLineStartOffset; return JSTextPosition(newLine, newOffset, newLineStartOffset); } JSTextPosition subexpressionStart() { return divotStart() + static_cast(m_subexpressionStartOffset); } JSTextPosition subexpressionEnd() { return divotEnd(); } protected: uint16_t m_subexpressionDivotOffset; uint16_t m_subexpressionStartOffset; uint16_t m_subexpressionLineOffset; uint16_t m_subexpressionLineStartOffset; }; class TemplateExpressionListNode : 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 : 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* = 0) override; const Identifier& m_cooked; const Identifier& m_raw; }; class TemplateStringListNode : 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 : 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* = 0) override; TemplateStringListNode* m_templateStrings; TemplateExpressionListNode* m_templateExpressions; }; class TaggedTemplateNode : public ExpressionNode, public ThrowableExpressionData { public: TaggedTemplateNode(const JSTokenLocation&, ExpressionNode*, TemplateLiteralNode*); TemplateLiteralNode* templateLiteral() const { return m_templateLiteral; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_tag; TemplateLiteralNode* m_templateLiteral; }; class RegExpNode : public ExpressionNode, public ThrowableExpressionData { public: RegExpNode(const JSTokenLocation&, const Identifier& pattern, const Identifier& flags); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_pattern; const Identifier& m_flags; }; class ThisNode : public ExpressionNode { public: ThisNode(const JSTokenLocation&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class SuperNode final : public ExpressionNode { public: SuperNode(const JSTokenLocation&); private: bool isSuperNode() const override { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class NewTargetNode final : public ExpressionNode { public: NewTargetNode(const JSTokenLocation&); private: bool isNewTarget() const final { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ResolveNode : public ExpressionNode { public: ResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& start); const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isPure(BytecodeGenerator&) const override; bool isLocation() const override { return true; } bool isResolveNode() const override { return true; } const Identifier& m_ident; JSTextPosition m_start; }; class ElementNode : 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; int m_elision; ExpressionNode* m_node; }; class ArrayNode : public ExpressionNode { public: ArrayNode(const JSTokenLocation&, int elision); ArrayNode(const JSTokenLocation&, ElementNode*); ArrayNode(const JSTokenLocation&, int elision, ElementNode*); bool isArrayLiteral() const override { return true; } ArgumentListNode* toArgumentList(ParserArena&, int, int) const; ElementNode* elements() const { ASSERT(isSimpleArray()); return m_element; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isSimpleArray() const override; ElementNode* m_element; int m_elision; bool m_optional; }; class PropertyNode : public ParserArenaFreeable { public: enum Type { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16 }; enum PutType { Unknown, KnownDirect }; PropertyNode(const Identifier&, ExpressionNode*, Type, PutType, SuperBinding, bool isClassProperty); PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, PutType, SuperBinding, bool isClassProperty); ExpressionNode* expressionName() const { return m_expression; } const Identifier* name() const { return m_name; } Type type() const { return static_cast(m_type); } bool needsSuperBinding() const { return m_needsSuperBinding; } bool isClassProperty() const { return m_isClassProperty; } PutType putType() const { return static_cast(m_putType); } private: friend class PropertyListNode; const Identifier* m_name; ExpressionNode* m_expression; ExpressionNode* m_assign; unsigned m_type : 5; unsigned m_needsSuperBinding : 1; unsigned m_putType : 1; unsigned m_isClassProperty: 1; }; class PropertyListNode : public ExpressionNode { public: PropertyListNode(const JSTokenLocation&, PropertyNode*); PropertyListNode(const JSTokenLocation&, PropertyNode*, PropertyListNode*); bool hasStaticallyNamedProperty(const Identifier& propName); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&); PropertyNode* m_node; PropertyListNode* m_next; }; class ObjectLiteralNode : public ExpressionNode { public: ObjectLiteralNode(const JSTokenLocation&); ObjectLiteralNode(const JSTokenLocation&, PropertyListNode*); bool isObjectLiteral() const override { return true; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; PropertyListNode* m_list; }; class BracketAccessorNode : 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* = 0) override; bool isLocation() const override { return true; } bool isBracketAccessorNode() const override { return true; } ExpressionNode* m_base; ExpressionNode* m_subscript; bool m_subscriptHasAssignments; }; class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData { public: DotAccessorNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&); ExpressionNode* base() const { return m_base; } const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isLocation() const override { return true; } bool isDotAccessorNode() const override { return true; } ExpressionNode* m_base; const Identifier& m_ident; }; class SpreadExpressionNode : public ExpressionNode, public ThrowableExpressionData { public: SpreadExpressionNode(const JSTokenLocation&, ExpressionNode*); ExpressionNode* expression() const { return m_expression; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isSpreadExpression() const override { return true; } ExpressionNode* m_expression; }; class ArgumentListNode : public ExpressionNode { public: ArgumentListNode(const JSTokenLocation&, ExpressionNode*); ArgumentListNode(const JSTokenLocation&, ArgumentListNode*, ExpressionNode*); ArgumentListNode* m_next; ExpressionNode* m_expr; private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ArgumentsNode : public ParserArenaFreeable { public: ArgumentsNode(); ArgumentsNode(ArgumentListNode*); ArgumentListNode* m_listNode; }; class NewExprNode : public ExpressionNode, public ThrowableExpressionData { public: NewExprNode(const JSTokenLocation&, ExpressionNode*); NewExprNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; ArgumentsNode* m_args; }; class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData { public: EvalFunctionCallNode(const JSTokenLocation&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ArgumentsNode* m_args; }; class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData { public: FunctionCallValueNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; ArgumentsNode* m_args; }; class FunctionCallResolveNode : 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* = 0) override; const Identifier& m_ident; ArgumentsNode* m_args; }; class FunctionCallBracketNode : 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* = 0) override; ExpressionNode* m_base; ExpressionNode* m_subscript; ArgumentsNode* m_args; bool m_subscriptHasAssignments; }; class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData { public: FunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; protected: ExpressionNode* m_base; const Identifier& m_ident; ArgumentsNode* m_args; }; class BytecodeIntrinsicNode : public ExpressionNode, public ThrowableExpressionData { public: enum class Type { Constant, Function }; typedef RegisterID* (BytecodeIntrinsicNode::* EmitterType)(BytecodeGenerator&, RegisterID*); BytecodeIntrinsicNode(Type, const JSTokenLocation&, EmitterType, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); bool isBytecodeIntrinsicNode() const override { return true; } Type type() const { return m_type; } EmitterType emitter() const { return m_emitter; } 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* = 0) override; Type m_type; EmitterType m_emitter; const Identifier& m_ident; ArgumentsNode* m_args; }; class CallFunctionCallDotNode : public FunctionCallDotNode { public: CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ApplyFunctionCallDotNode : public FunctionCallDotNode { public: ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData { public: DeleteResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class DeleteBracketNode : 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* = 0) override; ExpressionNode* m_base; ExpressionNode* m_subscript; }; class DeleteDotNode : 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* = 0) override; ExpressionNode* m_base; const Identifier& m_ident; }; class DeleteValueNode : public ExpressionNode { public: DeleteValueNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class VoidNode : public ExpressionNode { public: VoidNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class TypeOfResolveNode : public ExpressionNode { public: TypeOfResolveNode(const JSTokenLocation&, const Identifier&); const Identifier& identifier() const { return m_ident; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class TypeOfValueNode : public ExpressionNode { public: TypeOfValueNode(const JSTokenLocation&, ExpressionNode*); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 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* = 0) override; virtual RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = 0); virtual RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = 0); virtual RegisterID* emitDot(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_expr; Operator m_operator; }; class PostfixNode : public PrefixNode { public: PostfixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = 0) override; RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = 0) override; RegisterID* emitDot(BytecodeGenerator&, RegisterID* = 0) override; }; class UnaryOpNode : public ExpressionNode { public: UnaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode*, OpcodeID); protected: ExpressionNode* expr() { return m_expr; } const ExpressionNode* expr() const { return m_expr; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; OpcodeID opcodeID() const { return m_opcodeID; } ExpressionNode* m_expr; OpcodeID m_opcodeID; }; class UnaryPlusNode : public UnaryOpNode { public: UnaryPlusNode(const JSTokenLocation&, ExpressionNode*); private: ExpressionNode* stripUnaryPlus() override { return expr(); } }; class NegateNode : public UnaryOpNode { public: NegateNode(const JSTokenLocation&, ExpressionNode*); }; class BitwiseNotNode : public ExpressionNode { public: BitwiseNotNode(const JSTokenLocation&, ExpressionNode*); protected: ExpressionNode* expr() { return m_expr; } const ExpressionNode* expr() const { return m_expr; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class LogicalNotNode : public UnaryOpNode { public: LogicalNotNode(const JSTokenLocation&, ExpressionNode*); private: void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override; }; 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& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0); void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override; ExpressionNode* lhs() { return m_expr1; }; ExpressionNode* rhs() { return m_expr2; }; private: void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression); RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; protected: OpcodeID opcodeID() const { return m_opcodeID; } protected: ExpressionNode* m_expr1; ExpressionNode* m_expr2; private: OpcodeID m_opcodeID; protected: bool m_rightHasAssignments; }; class MultNode : public BinaryOpNode { public: MultNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class DivNode : public BinaryOpNode { public: DivNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class ModNode : public BinaryOpNode { public: ModNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class AddNode : public BinaryOpNode { public: AddNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); bool isAdd() const override { return true; } }; class SubNode : public BinaryOpNode { public: SubNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); bool isSubtract() const override { return true; } }; class LeftShiftNode : public BinaryOpNode { public: LeftShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class RightShiftNode : public BinaryOpNode { public: RightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class UnsignedRightShiftNode : public BinaryOpNode { public: UnsignedRightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class LessNode : public BinaryOpNode { public: LessNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class GreaterNode : public BinaryOpNode { public: GreaterNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class LessEqNode : public BinaryOpNode { public: LessEqNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class GreaterEqNode : 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* = 0) override; }; class InstanceOfNode : public ThrowableBinaryOpNode { public: InstanceOfNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class InNode : public ThrowableBinaryOpNode { public: InNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class EqualNode : public BinaryOpNode { public: EqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class NotEqualNode : public BinaryOpNode { public: NotEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class StrictEqualNode : public BinaryOpNode { public: StrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class NotStrictEqualNode : public BinaryOpNode { public: NotStrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitAndNode : public BinaryOpNode { public: BitAndNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitOrNode : public BinaryOpNode { public: BitOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; class BitXOrNode : public BinaryOpNode { public: BitXOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); }; // m_expr1 && m_expr2, m_expr1 || m_expr2 class LogicalOpNode : public ExpressionNode { public: LogicalOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override; ExpressionNode* m_expr1; ExpressionNode* m_expr2; LogicalOperator m_operator; }; // The ternary operator, "m_logical ? m_expr1 : m_expr2" class ConditionalNode : public ExpressionNode { public: ConditionalNode(const JSTokenLocation&, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_logical; ExpressionNode* m_expr1; ExpressionNode* m_expr2; }; class ReadModifyResolveNode : 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* = 0) override; const Identifier& m_ident; ExpressionNode* m_right; Operator m_operator; bool m_rightHasAssignments; }; class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData { public: AssignResolveNode(const JSTokenLocation&, const Identifier&, ExpressionNode* right, AssignmentContext); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; ExpressionNode* m_right; AssignmentContext m_assignmentContext; }; class ReadModifyBracketNode : 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* = 0) override; ExpressionNode* m_base; ExpressionNode* m_subscript; ExpressionNode* m_right; unsigned m_operator : 30; bool m_subscriptHasAssignments : 1; bool m_rightHasAssignments : 1; }; class AssignBracketNode : 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* = 0) override; ExpressionNode* m_base; ExpressionNode* m_subscript; ExpressionNode* m_right; bool m_subscriptHasAssignments : 1; bool m_rightHasAssignments : 1; }; class AssignDotNode : public ExpressionNode, public ThrowableExpressionData { public: AssignDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_base; const Identifier& m_ident; ExpressionNode* m_right; bool m_rightHasAssignments; }; class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData { public: ReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_base; const Identifier& m_ident; ExpressionNode* m_right; unsigned m_operator : 31; bool m_rightHasAssignments : 1; }; class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData { public: AssignErrorNode(const JSTokenLocation&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; 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 override { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; CommaNode* m_next; }; class SourceElements final : public ParserArenaFreeable { public: SourceElements(); void append(StatementNode*); StatementNode* singleStatement() const; StatementNode* lastStatement() const; void emitBytecode(BytecodeGenerator&, RegisterID* destination); void analyzeModule(ModuleAnalyzer&); private: StatementNode* m_head; StatementNode* m_tail; }; class BlockNode : public StatementNode, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; BlockNode(const JSTokenLocation&, SourceElements*, VariableEnvironment&, FunctionStack&&); StatementNode* singleStatement() const; StatementNode* lastStatement() const; private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isBlock() const override { return true; } SourceElements* m_statements; }; class EmptyStatementNode : public StatementNode { public: EmptyStatementNode(const JSTokenLocation&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isEmptyStatement() const override { return true; } }; class DebuggerStatementNode : public StatementNode { public: DebuggerStatementNode(const JSTokenLocation&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ExprStatementNode : public StatementNode { public: ExprStatementNode(const JSTokenLocation&, ExpressionNode*); ExpressionNode* expr() const { return m_expr; } private: bool isExprStatement() const override { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class DeclarationStatement : public StatementNode { public: DeclarationStatement(const JSTokenLocation&, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class EmptyVarExpression : public ExpressionNode { public: EmptyVarExpression(const JSTokenLocation&, const Identifier&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class EmptyLetExpression : public ExpressionNode { public: EmptyLetExpression(const JSTokenLocation&, const Identifier&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class IfElseNode : public StatementNode { public: IfElseNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool tryFoldBreakAndContinue(BytecodeGenerator&, StatementNode* ifBlock, Label*& trueTarget, FallThroughMode&); ExpressionNode* m_condition; StatementNode* m_ifBlock; StatementNode* m_elseBlock; }; class DoWhileNode : public StatementNode { public: DoWhileNode(const JSTokenLocation&, StatementNode*, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; StatementNode* m_statement; ExpressionNode* m_expr; }; class WhileNode : public StatementNode { public: WhileNode(const JSTokenLocation&, ExpressionNode*, StatementNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; StatementNode* m_statement; }; class ForNode : public StatementNode, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; ForNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode*, VariableEnvironment&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr1; ExpressionNode* m_expr2; ExpressionNode* m_expr3; StatementNode* m_statement; }; class DestructuringPatternNode; class EnumerationNode : public StatementNode, public ThrowableExpressionData, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&); protected: ExpressionNode* m_lexpr; ExpressionNode* m_expr; StatementNode* m_statement; }; class ForInNode : public EnumerationNode { public: ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&); private: RegisterID* tryGetBoundLocal(BytecodeGenerator&); void emitLoopHeader(BytecodeGenerator&, RegisterID* propertyName); void emitMultiLoopBytecode(BytecodeGenerator&, RegisterID* dst); void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ForOfNode : public EnumerationNode { public: ForOfNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; class ContinueNode : public StatementNode, public ThrowableExpressionData { public: ContinueNode(const JSTokenLocation&, const Identifier&); Label* trivialTarget(BytecodeGenerator&); private: bool isContinue() const override { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class BreakNode : public StatementNode, public ThrowableExpressionData { public: BreakNode(const JSTokenLocation&, const Identifier&); Label* trivialTarget(BytecodeGenerator&); private: bool isBreak() const override { return true; } void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_ident; }; class ReturnNode : public StatementNode, public ThrowableExpressionData { public: ReturnNode(const JSTokenLocation&, ExpressionNode* value); ExpressionNode* value() { return m_value; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isReturnNode() const override { return true; } ExpressionNode* m_value; }; class WithNode : public StatementNode { public: WithNode(const JSTokenLocation&, ExpressionNode*, StatementNode*, const JSTextPosition& divot, uint32_t expressionLength); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; StatementNode* m_statement; JSTextPosition m_divot; uint32_t m_expressionLength; }; class LabelNode : public StatementNode, public ThrowableExpressionData { public: LabelNode(const JSTokenLocation&, const Identifier& name, StatementNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; const Identifier& m_name; StatementNode* m_statement; }; class ThrowNode : public StatementNode, public ThrowableExpressionData { public: ThrowNode(const JSTokenLocation&, ExpressionNode*); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_expr; }; class TryNode : public StatementNode, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; TryNode(const JSTokenLocation&, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; StatementNode* m_tryBlock; DestructuringPatternNode* m_catchPattern; StatementNode* m_catchBlock; StatementNode* m_finallyBlock; }; class ScopeNode : public StatementNode, public ParserArenaRoot, public VariableEnvironmentNode { public: ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, bool inStrictContext); ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, const SourceCode&, SourceElements*, VariableEnvironment&, FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants); using ParserArenaRoot::operator new; const SourceCode& source() const { return m_source; } const String& sourceURL() const { return m_source.provider()->url(); } intptr_t sourceID() const { return m_source.providerID(); } int startLine() const { return m_startLineNumber; } int startStartOffset() const { return m_startStartOffset; } int startLineStartOffset() const { return m_startLineStartOffset; } void setFeatures(CodeFeatures features) { m_features = features; } CodeFeatures features() { return m_features; } 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_features & StrictModeFeature; } void setUsesArguments() { m_features |= ArgumentsFeature; } 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); } 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; void emitStatementsBytecode(BytecodeGenerator&, RegisterID* destination); void analyzeModule(ModuleAnalyzer&); protected: int m_startLineNumber; unsigned m_startStartOffset; unsigned m_startLineStartOffset; private: CodeFeatures m_features; InnerArrowFunctionCodeFeatures m_innerArrowFunctionCodeFeatures; SourceCode m_source; VariableEnvironment m_varDeclarations; UniquedStringImplPtrSet m_sloppyModeHoistedFunctions; int m_numConstants; SourceElements* m_statements; }; class ProgramNode : public ScopeNode { public: ProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants); unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } static const bool scopeIsFunction = false; private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; unsigned m_startColumn; unsigned m_endColumn; }; class EvalNode : public ScopeNode { public: EvalNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants); ALWAYS_INLINE unsigned startColumn() const { return 0; } unsigned endColumn() const { return m_endColumn; } static const bool scopeIsFunction = false; private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; unsigned m_endColumn; }; class ModuleProgramNode : public ScopeNode { public: ModuleProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, FunctionParameters*, const SourceCode&, CodeFeatures, InnerArrowFunctionCodeFeatures, int numConstants); unsigned startColumn() const { return m_startColumn; } unsigned endColumn() const { return m_endColumn; } static const bool scopeIsFunction = false; private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; unsigned m_startColumn; unsigned m_endColumn; }; class ModuleNameNode : public Node { public: ModuleNameNode(const JSTokenLocation&, const Identifier& moduleName); const Identifier& moduleName() { return m_moduleName; } private: const Identifier& m_moduleName; }; class ImportSpecifierNode : 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 : public ParserArenaDeletable { public: typedef Vector Specifiers; const Specifiers& specifiers() const { return m_specifiers; } void append(ImportSpecifierNode* specifier) { m_specifiers.append(specifier); } private: Specifiers m_specifiers; }; class ModuleDeclarationNode : public StatementNode { public: virtual void analyzeModule(ModuleAnalyzer&) = 0; virtual bool isModuleDeclarationNode() const { return true; } protected: ModuleDeclarationNode(const JSTokenLocation&); }; class ImportDeclarationNode : public ModuleDeclarationNode { public: ImportDeclarationNode(const JSTokenLocation&, ImportSpecifierListNode*, ModuleNameNode*); ImportSpecifierListNode* specifierList() const { return m_specifierList; } ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void analyzeModule(ModuleAnalyzer&) override; ImportSpecifierListNode* m_specifierList; ModuleNameNode* m_moduleName; }; class ExportAllDeclarationNode : public ModuleDeclarationNode { public: ExportAllDeclarationNode(const JSTokenLocation&, ModuleNameNode*); ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void analyzeModule(ModuleAnalyzer&) override; ModuleNameNode* m_moduleName; }; class ExportDefaultDeclarationNode : 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* = 0) override; void analyzeModule(ModuleAnalyzer&) override; StatementNode* m_declaration; const Identifier& m_localName; }; class ExportLocalDeclarationNode : public ModuleDeclarationNode { public: ExportLocalDeclarationNode(const JSTokenLocation&, StatementNode*); const StatementNode& declaration() const { return *m_declaration; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void analyzeModule(ModuleAnalyzer&) override; StatementNode* m_declaration; }; class ExportSpecifierNode : 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 : public ParserArenaDeletable { public: typedef Vector Specifiers; const Specifiers& specifiers() const { return m_specifiers; } void append(ExportSpecifierNode* specifier) { m_specifiers.append(specifier); } private: Specifiers m_specifiers; }; class ExportNamedDeclarationNode : public ModuleDeclarationNode { public: ExportNamedDeclarationNode(const JSTokenLocation&, ExportSpecifierListNode*, ModuleNameNode*); ExportSpecifierListNode* specifierList() const { return m_specifierList; } ModuleNameNode* moduleName() const { return m_moduleName; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; void analyzeModule(ModuleAnalyzer&) override; ExportSpecifierListNode* m_specifierList; ModuleNameNode* m_moduleName { nullptr }; }; class FunctionParameters : public ParserArenaDeletable { public: FunctionParameters(); ALWAYS_INLINE unsigned size() const { return m_patterns.size(); } ALWAYS_INLINE std::pair at(unsigned index) { return m_patterns[index]; } ALWAYS_INLINE void append(DestructuringPatternNode* pattern, ExpressionNode* defaultValue) { ASSERT(pattern); m_patterns.append(std::make_pair(pattern, defaultValue)); } private: Vector, 3> m_patterns; }; class FunctionMetadataNode final : public Node, public ParserArenaDeletable { public: using ParserArenaDeletable::operator new; FunctionMetadataNode( ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext, ConstructorKind, SuperBinding, unsigned, SourceParseMode, bool isArrowFunctionBodyExpression); 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 setInferredName(const Identifier& inferredName) { ASSERT(!inferredName.isNull()); m_inferredName = inferredName; } const Identifier& inferredName() { return m_inferredName.isEmpty() ? m_ident : m_inferredName; } 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; } bool isInStrictContext() const { return m_isInStrictContext; } SuperBinding superBinding() { return static_cast(m_superBinding); } ConstructorKind constructorKind() { return static_cast(m_constructorKind); } 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; } protected: Identifier m_ident; Identifier m_ecmaName; Identifier m_inferredName; FunctionMode m_functionMode; 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; SourceParseMode m_parseMode; unsigned m_isInStrictContext : 1; unsigned m_superBinding : 1; unsigned m_constructorKind : 2; unsigned m_isArrowFunctionBodyExpression : 1; }; 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, InnerArrowFunctionCodeFeatures, int numConstants); FunctionParameters* parameters() const { return m_parameters; } void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 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 const 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; } 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* = 0) override; bool isFuncExprNode() const override { return true; } }; class ArrowFuncExprNode : public BaseFuncExprNode { public: ArrowFuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isArrowFuncExprNode() const override { return true; } }; class MethodDefinitionNode : public FuncExprNode { public: MethodDefinitionNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; }; 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* = 0) override; ExpressionNode* m_argument; bool m_delegate; }; class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; ClassExprNode(const JSTokenLocation&, const Identifier&, const SourceCode& classSource, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpresssion, ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods); 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_staticMethods ? m_staticMethods->hasStaticallyNamedProperty(propName) : false; } private: RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; bool isClassExprNode() const override { return true; } SourceCode m_classSource; const Identifier& m_name; const Identifier* m_ecmaName; ExpressionNode* m_constructorExpression; ExpressionNode* m_classHeritage; PropertyListNode* m_instanceMethods; PropertyListNode* m_staticMethods; }; class DestructuringPatternNode : public ParserArenaFreeable { public: virtual ~DestructuringPatternNode() { } virtual void collectBoundIdentifiers(Vector&) const = 0; virtual void bindValue(BytecodeGenerator&, RegisterID* source) const = 0; virtual void toString(StringBuilder&) const = 0; virtual bool isBindingNode() const { return false; } virtual bool isRestParameter() const { return false; } virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return 0; } protected: DestructuringPatternNode(); }; class ArrayPatternNode : public DestructuringPatternNode, public ThrowableExpressionData, public ParserArenaDeletable { public: using ParserArenaDeletable::operator new; ArrayPatternNode(); enum class BindingType { Elision, Element, RestElement }; void appendIndex(BindingType bindingType, const JSTokenLocation&, DestructuringPatternNode* node, ExpressionNode* defaultValue) { m_targetPatterns.append({ bindingType, node, defaultValue }); } private: struct Entry { BindingType bindingType; DestructuringPatternNode* pattern; ExpressionNode* defaultValue; }; void collectBoundIdentifiers(Vector&) const override; void bindValue(BytecodeGenerator&, RegisterID*) const override; RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*) override; void toString(StringBuilder&) const override; Vector m_targetPatterns; }; class ObjectPatternNode : public DestructuringPatternNode, public ParserArenaDeletable { public: using ParserArenaDeletable::operator new; ObjectPatternNode(); void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DestructuringPatternNode* pattern, ExpressionNode* defaultValue) { m_targetPatterns.append(Entry{ identifier, nullptr, wasString, pattern, defaultValue }); } void appendEntry(const JSTokenLocation&, ExpressionNode* propertyExpression, DestructuringPatternNode* pattern, ExpressionNode* defaultValue) { m_targetPatterns.append(Entry{ Identifier(), propertyExpression, false, pattern, defaultValue }); } private: void collectBoundIdentifiers(Vector&) const override; void bindValue(BytecodeGenerator&, RegisterID*) const override; void toString(StringBuilder&) const override; struct Entry { const Identifier& propertyName; ExpressionNode* propertyExpression; bool wasString; DestructuringPatternNode* pattern; ExpressionNode* defaultValue; }; Vector m_targetPatterns; }; class BindingNode : 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; } private: void collectBoundIdentifiers(Vector&) const override; void bindValue(BytecodeGenerator&, RegisterID*) const override; void toString(StringBuilder&) const override; bool isBindingNode() const override { return true; } JSTextPosition m_divotStart; JSTextPosition m_divotEnd; const Identifier& m_boundProperty; AssignmentContext m_bindingContext; }; class RestParameterNode : public DestructuringPatternNode { public: RestParameterNode(const Identifier& boundProperty, unsigned numParametersToSkip, const JSTextPosition& start, const JSTextPosition& end); bool isRestParameter() const override { return true; } void emit(BytecodeGenerator&); const Identifier& name() const { return m_name; } private: void collectBoundIdentifiers(Vector&) const override; void bindValue(BytecodeGenerator&, RegisterID*) const override; void toString(StringBuilder&) const override; const Identifier& m_name; unsigned m_numParametersToSkip; JSTextPosition m_divotStart; // "f" in "...foo" JSTextPosition m_divotEnd; }; class AssignmentElementNode : 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; } private: void collectBoundIdentifiers(Vector&) const override; void bindValue(BytecodeGenerator&, RegisterID*) const override; void toString(StringBuilder&) const override; JSTextPosition m_divotStart; JSTextPosition m_divotEnd; ExpressionNode* m_assignmentTarget; }; class DestructuringAssignmentNode : public ExpressionNode { public: DestructuringAssignmentNode(const JSTokenLocation&, DestructuringPatternNode*, ExpressionNode*); DestructuringPatternNode* bindings() { return m_bindings; } private: bool isAssignmentLocation() const override { return true; } bool isDestructuringNode() const override { return true; } RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; DestructuringPatternNode* m_bindings; ExpressionNode* m_initializer; }; class FuncDeclNode : public StatementNode { public: FuncDeclNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&); bool isFuncDeclNode() const override { return true; } FunctionMetadataNode* metadata() { return m_metadata; } private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; FunctionMetadataNode* m_metadata; }; class ClassDeclNode final : public StatementNode { public: ClassDeclNode(const JSTokenLocation&, ExpressionNode* classExpression); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; ExpressionNode* m_classDeclaration; }; class CaseClauseNode : public ParserArenaFreeable { public: CaseClauseNode(ExpressionNode*, SourceElements* = 0); 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 : 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; }; class CaseBlockNode : public ParserArenaFreeable { public: CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2); void emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* destination); private: SwitchInfo::SwitchType tryTableSwitch(Vector& literalVector, int32_t& min_num, int32_t& max_num); static const size_t s_tableSwitchMinimum = 3; ClauseListNode* m_list1; CaseClauseNode* m_defaultClause; ClauseListNode* m_list2; }; class SwitchNode : public StatementNode, public VariableEnvironmentNode { public: using ParserArenaDeletable::operator new; SwitchNode(const JSTokenLocation&, ExpressionNode*, CaseBlockNode*, VariableEnvironment&, FunctionStack&&); private: void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 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 #endif // Nodes_h