/* * Copyright (C) 2008-2019 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * Copyright (C) 2012 Igalia, S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "BytecodeGeneratorBase.h" #include "BytecodeStructs.h" #include "CodeBlock.h" #include "Instruction.h" #include "Interpreter.h" #include "JSAsyncGenerator.h" #include "JSBigInt.h" #include "JSGenerator.h" #include "JSTemplateObjectDescriptor.h" #include "Label.h" #include "LabelScope.h" #include "Nodes.h" #include "ParserError.h" #include "ProfileTypeBytecodeFlag.h" #include "RegisterID.h" #include "StaticPropertyAnalyzer.h" #include "SymbolTable.h" #include "UnlinkedCodeBlock.h" #include "UnlinkedCodeBlockGenerator.h" #include #include #include #include #include #include #include namespace JSC { class JSImmutableButterfly; class Identifier; class IndexedForInContext; class StructureForInContext; enum ExpectedFunction { NoExpectedFunction, ExpectObjectConstructor, ExpectArrayConstructor }; enum class EmitAwait { Yes, No }; enum class DebuggableCall { Yes, No }; enum class ThisResolutionType { Local, Scoped }; enum class LinkTimeConstant : int32_t; class CallArguments { public: CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0); RegisterID* thisRegister() { return m_argv[0].get(); } RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } unsigned stackOffset() { return -m_argv[0]->index() + CallFrame::headerSizeInRegisters; } unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; } ArgumentsNode* argumentsNode() { return m_argumentsNode; } private: ArgumentsNode* m_argumentsNode; Vector, 8, UnsafeVectorOverflow> m_argv; unsigned m_padding; }; class Variable { public: enum VariableKind { NormalVariable, SpecialVariable }; Variable() = default; Variable(const Identifier& ident) : m_ident(ident) , m_local(nullptr) , m_attributes(0) , m_kind(NormalVariable) // This is somewhat meaningless here for this kind of Variable. , m_symbolTableConstantIndex(0) // This is meaningless here for this kind of Variable. , m_isLexicallyScoped(false) { } Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind, int symbolTableConstantIndex, bool isLexicallyScoped) : m_ident(ident) , m_offset(offset) , m_local(local) , m_attributes(attributes) , m_kind(kind) , m_symbolTableConstantIndex(symbolTableConstantIndex) , m_isLexicallyScoped(isLexicallyScoped) { } // If it's unset, then it is a non-locally-scoped variable. If it is set, then it could be // a stack variable, a scoped variable in a local scope, or a variable captured in the // direct arguments object. bool isResolved() const { return !!m_offset; } int symbolTableConstantIndex() const { ASSERT(isResolved() && !isSpecial()); return m_symbolTableConstantIndex; } const Identifier& ident() const { return m_ident; } VarOffset offset() const { return m_offset; } bool isLocal() const { return m_offset.isStack(); } RegisterID* local() const { return m_local; } bool isReadOnly() const { return m_attributes & PropertyAttribute::ReadOnly; } bool isSpecial() const { return m_kind != NormalVariable; } bool isConst() const { return isReadOnly() && m_isLexicallyScoped; } void setIsReadOnly() { m_attributes |= PropertyAttribute::ReadOnly; } void dump(PrintStream&) const; bool operator==(const Variable& other) const { return m_ident == other.m_ident && m_offset == other.m_offset && m_local == other.m_local && m_attributes == other.m_attributes && m_kind == other.m_kind && m_symbolTableConstantIndex == other.m_symbolTableConstantIndex && m_isLexicallyScoped == other.m_isLexicallyScoped; } private: Identifier m_ident; VarOffset m_offset { }; RegisterID* m_local { nullptr }; unsigned m_attributes { 0 }; VariableKind m_kind { NormalVariable }; int m_symbolTableConstantIndex { 0 }; // This is meaningless here for this default NormalVariable kind of Variable. bool m_isLexicallyScoped { false }; }; // https://tc39.github.io/ecma262/#sec-completion-record-specification-type // // For the Break and Continue cases, instead of using the Break and Continue enum values // below, we use the unique jumpID of the break and continue statement as the encoding // for the CompletionType value. emitFinallyCompletion() uses this jumpID value later // to determine the appropriate jump target to jump to after executing the relevant finally // blocks. The jumpID is computed as: // jumpID = bytecodeOffset (of the break/continue node) + CompletionType::NumberOfTypes. // Hence, there won't be any collision between jumpIDs and CompletionType enums. enum class CompletionType : int { Normal, Throw, Return, NumberOfTypes }; inline CompletionType bytecodeOffsetToJumpID(unsigned offset) { int jumpIDAsInt = offset + static_cast(CompletionType::NumberOfTypes); ASSERT(jumpIDAsInt >= static_cast(CompletionType::NumberOfTypes)); return static_cast(jumpIDAsInt); } struct FinallyJump { FinallyJump(CompletionType jumpID, int targetLexicalScopeIndex, Label& targetLabel) : jumpID(jumpID) , targetLexicalScopeIndex(targetLexicalScopeIndex) , targetLabel(targetLabel) { } CompletionType jumpID; int targetLexicalScopeIndex; Ref