2017-08-12 16:48:01 +00:00
/*
2020-08-29 13:27:11 +00:00
* Copyright ( C ) 2008 - 2019 Apple Inc . All rights reserved .
2017-08-12 16:48:01 +00:00
* Copyright ( C ) 2008 Cameron Zwarich < cwzwarich @ uwaterloo . ca >
* 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
2022-10-23 02:55:20 +00:00
# include "BytecodeGeneratorBase.h"
# include "BytecodeStructs.h"
2017-08-12 16:48:01 +00:00
# include "CodeBlock.h"
# include "Instruction.h"
# include "Interpreter.h"
2022-10-23 02:55:20 +00:00
# include "JSAsyncGenerator.h"
2020-08-29 13:27:11 +00:00
# include "JSBigInt.h"
2022-10-23 02:55:20 +00:00
# include "JSGenerator.h"
2020-08-29 13:27:11 +00:00
# include "JSTemplateObjectDescriptor.h"
2017-08-12 16:48:01 +00:00
# include "Label.h"
# include "LabelScope.h"
# include "Nodes.h"
# include "ParserError.h"
2020-08-29 13:27:11 +00:00
# include "ProfileTypeBytecodeFlag.h"
2017-08-12 16:48:01 +00:00
# include "RegisterID.h"
# include "StaticPropertyAnalyzer.h"
# include "SymbolTable.h"
# include "UnlinkedCodeBlock.h"
2022-10-23 02:55:20 +00:00
# include "UnlinkedCodeBlockGenerator.h"
2017-08-12 16:48:01 +00:00
# include <functional>
2018-01-03 05:16:05 +00:00
# include <wtf/CheckedArithmetic.h>
2020-08-29 13:27:11 +00:00
# include <wtf/HashFunctions.h>
# include <wtf/Optional.h>
2017-08-12 16:48:01 +00:00
# include <wtf/SegmentedVector.h>
# include <wtf/SetForScope.h>
# include <wtf/Vector.h>
namespace JSC {
2020-08-29 13:27:11 +00:00
class JSImmutableButterfly ;
2017-08-12 16:48:01 +00:00
class Identifier ;
2020-08-29 13:27:11 +00:00
class IndexedForInContext ;
class StructureForInContext ;
2017-08-12 16:48:01 +00:00
enum ExpectedFunction {
NoExpectedFunction ,
ExpectObjectConstructor ,
ExpectArrayConstructor
} ;
2020-08-29 13:27:11 +00:00
enum class EmitAwait { Yes , No } ;
2017-08-12 16:48:01 +00:00
enum class DebuggableCall { Yes , No } ;
enum class ThisResolutionType { Local , Scoped } ;
2022-10-23 02:55:20 +00:00
enum class LinkTimeConstant : int32_t ;
2017-08-12 16:48:01 +00:00
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 < RefPtr < RegisterID > , 8 , UnsafeVectorOverflow > m_argv ;
unsigned m_padding ;
} ;
2022-10-23 02:55:20 +00:00
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 } ;
} ;
2018-01-03 05:16:05 +00:00
// 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 ,
2020-08-29 13:27:11 +00:00
Return ,
2018-01-03 05:16:05 +00:00
NumberOfTypes
} ;
inline CompletionType bytecodeOffsetToJumpID ( unsigned offset )
{
int jumpIDAsInt = offset + static_cast < int > ( CompletionType : : NumberOfTypes ) ;
ASSERT ( jumpIDAsInt > = static_cast < int > ( CompletionType : : NumberOfTypes ) ) ;
return static_cast < CompletionType > ( jumpIDAsInt ) ;
}
struct FinallyJump {
FinallyJump ( CompletionType jumpID , int targetLexicalScopeIndex , Label & targetLabel )
: jumpID ( jumpID )
, targetLexicalScopeIndex ( targetLexicalScopeIndex )
, targetLabel ( targetLabel )
{ }
CompletionType jumpID ;
int targetLexicalScopeIndex ;
Ref < Label > targetLabel ;
} ;
2020-08-29 13:27:11 +00:00
class FinallyContext {
public :
2018-01-03 05:16:05 +00:00
FinallyContext ( ) { }
2020-08-29 13:27:11 +00:00
FinallyContext ( BytecodeGenerator & , Label & finallyLabel ) ;
2018-01-03 05:16:05 +00:00
FinallyContext * outerContext ( ) const { return m_outerContext ; }
Label * finallyLabel ( ) const { return m_finallyLabel ; }
2020-08-29 13:27:11 +00:00
RegisterID * completionTypeRegister ( ) const { return m_completionRecord . typeRegister . get ( ) ; }
RegisterID * completionValueRegister ( ) const { return m_completionRecord . valueRegister . get ( ) ; }
2018-01-03 05:16:05 +00:00
uint32_t numberOfBreaksOrContinues ( ) const { return m_numberOfBreaksOrContinues . unsafeGet ( ) ; }
void incNumberOfBreaksOrContinues ( ) { m_numberOfBreaksOrContinues + + ; }
bool handlesReturns ( ) const { return m_handlesReturns ; }
void setHandlesReturns ( ) { m_handlesReturns = true ; }
void registerJump ( CompletionType jumpID , int lexicalScopeIndex , Label & targetLabel )
{
m_jumps . append ( FinallyJump ( jumpID , lexicalScopeIndex , targetLabel ) ) ;
}
size_t numberOfJumps ( ) const { return m_jumps . size ( ) ; }
FinallyJump & jumps ( size_t i ) { return m_jumps [ i ] ; }
private :
FinallyContext * m_outerContext { nullptr } ;
Label * m_finallyLabel { nullptr } ;
Checked < uint32_t , WTF : : CrashOnOverflow > m_numberOfBreaksOrContinues ;
bool m_handlesReturns { false } ;
Vector < FinallyJump > m_jumps ;
2020-08-29 13:27:11 +00:00
struct {
RefPtr < RegisterID > typeRegister ;
RefPtr < RegisterID > valueRegister ;
} m_completionRecord ;
2017-08-12 16:48:01 +00:00
} ;
struct ControlFlowScope {
2018-01-03 05:16:05 +00:00
typedef uint8_t Type ;
enum {
Label ,
Finally
} ;
2020-08-29 13:27:11 +00:00
ControlFlowScope ( Type type , int lexicalScopeIndex , FinallyContext * finallyContext = nullptr )
2018-01-03 05:16:05 +00:00
: type ( type )
, lexicalScopeIndex ( lexicalScopeIndex )
2020-08-29 13:27:11 +00:00
, finallyContext ( finallyContext )
2018-01-03 05:16:05 +00:00
{ }
bool isLabelScope ( ) const { return type = = Label ; }
bool isFinallyScope ( ) const { return type = = Finally ; }
Type type ;
int lexicalScopeIndex ;
2020-08-29 13:27:11 +00:00
FinallyContext * finallyContext ;
2017-08-12 16:48:01 +00:00
} ;
class ForInContext : public RefCounted < ForInContext > {
WTF_MAKE_FAST_ALLOCATED ;
WTF_MAKE_NONCOPYABLE ( ForInContext ) ;
public :
2020-08-29 13:27:11 +00:00
virtual ~ ForInContext ( ) = default ;
bool isValid ( ) const { return m_isValid ; }
void invalidate ( ) { m_isValid = false ; }
enum class Type : uint8_t {
IndexedForIn ,
StructureForIn
} ;
Type type ( ) const { return m_type ; }
bool isIndexedForInContext ( ) const { return m_type = = Type : : IndexedForIn ; }
bool isStructureForInContext ( ) const { return m_type = = Type : : StructureForIn ; }
IndexedForInContext & asIndexedForInContext ( )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
ASSERT ( isIndexedForInContext ( ) ) ;
return * reinterpret_cast < IndexedForInContext * > ( this ) ;
2017-08-12 16:48:01 +00:00
}
2020-08-29 13:27:11 +00:00
StructureForInContext & asStructureForInContext ( )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
ASSERT ( isStructureForInContext ( ) ) ;
return * reinterpret_cast < StructureForInContext * > ( this ) ;
2017-08-12 16:48:01 +00:00
}
2020-08-29 13:27:11 +00:00
RegisterID * local ( ) const { return m_localRegister . get ( ) ; }
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
protected :
ForInContext ( RegisterID * localRegister , Type type , unsigned bodyBytecodeStartOffset )
: m_localRegister ( localRegister )
, m_type ( type )
, m_bodyBytecodeStartOffset ( bodyBytecodeStartOffset )
{ }
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
unsigned bodyBytecodeStartOffset ( ) const { return m_bodyBytecodeStartOffset ; }
2022-10-23 02:55:20 +00:00
void finalize ( BytecodeGenerator & , UnlinkedCodeBlockGenerator * , unsigned bodyBytecodeEndOffset ) ;
2017-08-12 16:48:01 +00:00
private :
RefPtr < RegisterID > m_localRegister ;
2020-08-29 13:27:11 +00:00
bool m_isValid { true } ;
Type m_type ;
unsigned m_bodyBytecodeStartOffset ;
2017-08-12 16:48:01 +00:00
} ;
class StructureForInContext : public ForInContext {
2020-08-29 13:27:11 +00:00
using Base = ForInContext ;
2017-08-12 16:48:01 +00:00
public :
2020-08-29 13:27:11 +00:00
using GetInst = std : : tuple < unsigned , int > ;
2022-10-23 02:55:20 +00:00
using InInst = GetInst ;
using HasOwnPropertyJumpInst = std : : tuple < unsigned , unsigned > ;
2018-01-03 05:16:05 +00:00
2022-10-23 02:55:20 +00:00
StructureForInContext ( RegisterID * localRegister , RegisterID * indexRegister , RegisterID * propertyRegister , RegisterID * enumeratorRegister , Optional < Variable > baseVariable , unsigned bodyBytecodeStartOffset )
2020-08-29 13:27:11 +00:00
: ForInContext ( localRegister , Type : : StructureForIn , bodyBytecodeStartOffset )
2017-08-12 16:48:01 +00:00
, m_indexRegister ( indexRegister )
, m_propertyRegister ( propertyRegister )
, m_enumeratorRegister ( enumeratorRegister )
2022-10-23 02:55:20 +00:00
, m_baseVariable ( baseVariable )
2017-08-12 16:48:01 +00:00
{
}
RegisterID * index ( ) const { return m_indexRegister . get ( ) ; }
RegisterID * property ( ) const { return m_propertyRegister . get ( ) ; }
RegisterID * enumerator ( ) const { return m_enumeratorRegister . get ( ) ; }
2022-10-23 02:55:20 +00:00
const Optional < Variable > & baseVariable ( ) const { return m_baseVariable ; }
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
void addGetInst ( unsigned instIndex , int propertyRegIndex )
2018-01-03 05:16:05 +00:00
{
2020-08-29 13:27:11 +00:00
m_getInsts . append ( GetInst { instIndex , propertyRegIndex } ) ;
2018-01-03 05:16:05 +00:00
}
2022-10-23 02:55:20 +00:00
void addInInst ( unsigned instIndex , int propertyRegIndex )
{
m_inInsts . append ( InInst { instIndex , propertyRegIndex } ) ;
}
void addHasOwnPropertyJump ( unsigned branchInstIndex , unsigned genericPathTarget )
{
m_hasOwnPropertyJumpInsts . append ( HasOwnPropertyJumpInst { branchInstIndex , genericPathTarget } ) ;
}
void finalize ( BytecodeGenerator & , UnlinkedCodeBlockGenerator * , unsigned bodyBytecodeEndOffset ) ;
2018-01-03 05:16:05 +00:00
2017-08-12 16:48:01 +00:00
private :
RefPtr < RegisterID > m_indexRegister ;
RefPtr < RegisterID > m_propertyRegister ;
RefPtr < RegisterID > m_enumeratorRegister ;
2022-10-23 02:55:20 +00:00
Optional < Variable > m_baseVariable ;
2018-01-03 05:16:05 +00:00
Vector < GetInst > m_getInsts ;
2022-10-23 02:55:20 +00:00
Vector < InInst > m_inInsts ;
Vector < HasOwnPropertyJumpInst > m_hasOwnPropertyJumpInsts ;
2017-08-12 16:48:01 +00:00
} ;
class IndexedForInContext : public ForInContext {
2020-08-29 13:27:11 +00:00
using Base = ForInContext ;
2017-08-12 16:48:01 +00:00
public :
2020-08-29 13:27:11 +00:00
IndexedForInContext ( RegisterID * localRegister , RegisterID * indexRegister , unsigned bodyBytecodeStartOffset )
: ForInContext ( localRegister , Type : : IndexedForIn , bodyBytecodeStartOffset )
2017-08-12 16:48:01 +00:00
, m_indexRegister ( indexRegister )
{
}
RegisterID * index ( ) const { return m_indexRegister . get ( ) ; }
2022-10-23 02:55:20 +00:00
void finalize ( BytecodeGenerator & , UnlinkedCodeBlockGenerator * , unsigned bodyBytecodeEndOffset ) ;
2018-01-03 05:16:05 +00:00
void addGetInst ( unsigned instIndex , int propertyIndex ) { m_getInsts . append ( { instIndex , propertyIndex } ) ; }
2017-08-12 16:48:01 +00:00
private :
RefPtr < RegisterID > m_indexRegister ;
2018-01-03 05:16:05 +00:00
Vector < std : : pair < unsigned , int > > m_getInsts ;
2017-08-12 16:48:01 +00:00
} ;
struct TryData {
2018-01-03 05:16:05 +00:00
Ref < Label > target ;
2017-08-12 16:48:01 +00:00
HandlerType handlerType ;
} ;
struct TryContext {
2018-01-03 05:16:05 +00:00
Ref < Label > start ;
2017-08-12 16:48:01 +00:00
TryData * tryData ;
} ;
struct TryRange {
2018-01-03 05:16:05 +00:00
Ref < Label > start ;
Ref < Label > end ;
2017-08-12 16:48:01 +00:00
TryData * tryData ;
} ;
2022-10-23 02:55:20 +00:00
struct JSGeneratorTraits {
using OpcodeTraits = JSOpcodeTraits ;
using OpcodeID = : : JSC : : OpcodeID ;
using OpNop = : : JSC : : OpNop ;
using CodeBlock = std : : unique_ptr < UnlinkedCodeBlockGenerator > ;
static constexpr OpcodeID opcodeForDisablingOptimizations = op_end ;
} ;
class BytecodeGenerator : public BytecodeGeneratorBase < JSGeneratorTraits > {
2017-08-12 16:48:01 +00:00
WTF_MAKE_FAST_ALLOCATED ;
WTF_MAKE_NONCOPYABLE ( BytecodeGenerator ) ;
2020-08-29 13:27:11 +00:00
friend class FinallyContext ;
friend class IndexedForInContext ;
friend class StructureForInContext ;
2022-10-23 02:55:20 +00:00
friend class StrictModeScope ;
template < typename OldOpType , typename TupleType >
friend void rewriteOp ( BytecodeGenerator & , TupleType & ) ;
2017-08-12 16:48:01 +00:00
public :
typedef DeclarationStacks : : FunctionStack FunctionStack ;
2022-10-23 02:55:20 +00:00
BytecodeGenerator ( VM & , ProgramNode * , UnlinkedProgramCodeBlock * , OptionSet < CodeGenerationMode > , const RefPtr < TDZEnvironmentLink > & , ECMAMode ) ;
BytecodeGenerator ( VM & , FunctionNode * , UnlinkedFunctionCodeBlock * , OptionSet < CodeGenerationMode > , const RefPtr < TDZEnvironmentLink > & , ECMAMode ) ;
BytecodeGenerator ( VM & , EvalNode * , UnlinkedEvalCodeBlock * , OptionSet < CodeGenerationMode > , const RefPtr < TDZEnvironmentLink > & , ECMAMode ) ;
BytecodeGenerator ( VM & , ModuleProgramNode * , UnlinkedModuleProgramCodeBlock * , OptionSet < CodeGenerationMode > , const RefPtr < TDZEnvironmentLink > & , ECMAMode ) ;
2017-08-12 16:48:01 +00:00
~ BytecodeGenerator ( ) ;
2022-10-23 02:55:20 +00:00
VM & vm ( ) const { return m_vm ; }
2017-08-12 16:48:01 +00:00
ParserArena & parserArena ( ) const { return m_scopeNode - > parserArena ( ) ; }
2022-10-23 02:55:20 +00:00
const CommonIdentifiers & propertyNames ( ) const { return * m_vm . propertyNames ; }
2017-08-12 16:48:01 +00:00
bool isConstructor ( ) const { return m_codeBlock - > isConstructor ( ) ; }
DerivedContextType derivedContextType ( ) const { return m_derivedContextType ; }
bool usesArrowFunction ( ) const { return m_scopeNode - > usesArrowFunction ( ) ; }
bool needsToUpdateArrowFunctionContext ( ) const { return m_needsToUpdateArrowFunctionContext ; }
bool usesEval ( ) const { return m_scopeNode - > usesEval ( ) ; }
bool usesThis ( ) const { return m_scopeNode - > usesThis ( ) ; }
ConstructorKind constructorKind ( ) const { return m_codeBlock - > constructorKind ( ) ; }
SuperBinding superBinding ( ) const { return m_codeBlock - > superBinding ( ) ; }
JSParserScriptMode scriptMode ( ) const { return m_codeBlock - > scriptMode ( ) ; }
2022-10-23 02:55:20 +00:00
NeedsClassFieldInitializer needsClassFieldInitializer ( ) const { return m_codeBlock - > needsClassFieldInitializer ( ) ; }
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
template < typename Node , typename UnlinkedCodeBlock >
2022-10-23 02:55:20 +00:00
static ParserError generate ( VM & vm , Node * node , const SourceCode & sourceCode , UnlinkedCodeBlock * unlinkedCodeBlock , OptionSet < CodeGenerationMode > codeGenerationMode , const RefPtr < TDZEnvironmentLink > & parentScopeTDZVariables , ECMAMode ecmaMode )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
MonotonicTime before ;
if ( UNLIKELY ( Options : : reportBytecodeCompileTimes ( ) ) )
before = MonotonicTime : : now ( ) ;
2017-08-12 16:48:01 +00:00
DeferGC deferGC ( vm . heap ) ;
2022-10-23 02:55:20 +00:00
auto bytecodeGenerator = makeUnique < BytecodeGenerator > ( vm , node , unlinkedCodeBlock , codeGenerationMode , parentScopeTDZVariables , ecmaMode ) ;
2020-08-29 13:27:11 +00:00
auto result = bytecodeGenerator - > generate ( ) ;
if ( UNLIKELY ( Options : : reportBytecodeCompileTimes ( ) ) ) {
MonotonicTime after = MonotonicTime : : now ( ) ;
dataLogLn ( result . isValid ( ) ? " Failed to compile # " : " Compiled # " , CodeBlockHash ( sourceCode , unlinkedCodeBlock - > isConstructor ( ) ? CodeForConstruct : CodeForCall ) , " into bytecode " , bytecodeGenerator - > instructions ( ) . size ( ) , " instructions in " , ( after - before ) . milliseconds ( ) , " ms. " ) ;
}
return result ;
2017-08-12 16:48:01 +00:00
}
bool isArgumentNumber ( const Identifier & , int ) ;
Variable variable ( const Identifier & , ThisResolutionType = ThisResolutionType : : Local ) ;
enum ExistingVariableMode { VerifyExisting , IgnoreExisting } ;
void createVariable ( const Identifier & , VarKind , SymbolTable * , ExistingVariableMode = VerifyExisting ) ; // Creates the variable, or asserts that the already-created variable is sufficiently compatible.
// Returns the register storing "this"
RegisterID * thisRegister ( ) { return & m_thisRegister ; }
RegisterID * argumentsRegister ( ) { return m_argumentsRegister ; }
RegisterID * newTarget ( )
{
2022-10-23 02:55:20 +00:00
ASSERT ( m_newTargetRegister ) ;
2017-08-12 16:48:01 +00:00
return m_newTargetRegister ;
}
RegisterID * scopeRegister ( ) { return m_scopeRegister ; }
RegisterID * generatorRegister ( ) { return m_generatorRegister ; }
2022-10-23 02:55:20 +00:00
RegisterID * promiseRegister ( ) { return m_promiseRegister ; }
2017-08-12 16:48:01 +00:00
// The same as newTemporary(), but this function returns "suggestion" if
// "suggestion" is a temporary. This function is helpful in situations
// where you've put "suggestion" in a RefPtr, but you'd like to allow
// the next instruction to overwrite it anyway.
RegisterID * newTemporaryOr ( RegisterID * suggestion ) { return suggestion - > isTemporary ( ) ? suggestion : newTemporary ( ) ; }
// Functions for handling of dst register
RegisterID * ignoredResult ( ) { return & m_ignoredResultRegister ; }
// This will be allocated in the temporary region of registers, but it will
// not be marked as a temporary. This will ensure that finalDestination() does
// not overwrite a block scope variable that it mistakes as a temporary. These
// registers can be (and are) reclaimed when the lexical scope they belong to
// is no longer on the symbol table stack.
RegisterID * newBlockScopeVariable ( ) ;
// Returns a place to write intermediate values of an operation
// which reuses dst if it is safe to do so.
RegisterID * tempDestination ( RegisterID * dst )
{
return ( dst & & dst ! = ignoredResult ( ) & & dst - > isTemporary ( ) ) ? dst : newTemporary ( ) ;
}
// Returns the place to write the final output of an operation.
2022-10-23 02:55:20 +00:00
RegisterID * finalDestination ( RegisterID * originalDst , RegisterID * tempDst = nullptr )
2017-08-12 16:48:01 +00:00
{
if ( originalDst & & originalDst ! = ignoredResult ( ) )
return originalDst ;
ASSERT ( tempDst ! = ignoredResult ( ) ) ;
if ( tempDst & & tempDst - > isTemporary ( ) )
return tempDst ;
return newTemporary ( ) ;
}
RegisterID * destinationForAssignResult ( RegisterID * dst )
{
if ( dst & & dst ! = ignoredResult ( ) )
return dst - > isTemporary ( ) ? dst : newTemporary ( ) ;
2022-10-23 02:55:20 +00:00
return nullptr ;
2017-08-12 16:48:01 +00:00
}
// Moves src to dst if dst is not null and is different from src, otherwise just returns src.
2020-08-29 13:27:11 +00:00
RegisterID * move ( RegisterID * dst , RegisterID * src )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
return dst = = ignoredResult ( ) ? nullptr : ( dst & & dst ! = src ) ? emitMove ( dst , src ) : src ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
Ref < LabelScope > newLabelScope ( LabelScope : : Type , const Identifier * = nullptr ) ;
2017-08-12 16:48:01 +00:00
void emitNode ( RegisterID * dst , StatementNode * n )
{
SetForScope < bool > tailPositionPoisoner ( m_inTailPosition , false ) ;
return emitNodeInTailPosition ( dst , n ) ;
}
void emitNodeInTailPosition ( RegisterID * dst , StatementNode * n )
{
// Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
ASSERT ( ! dst | | dst = = ignoredResult ( ) | | ! dst - > isTemporary ( ) | | dst - > refCount ( ) ) ;
2022-10-23 02:55:20 +00:00
if ( UNLIKELY ( ! m_vm . isSafeToRecurse ( ) ) ) {
2017-08-12 16:48:01 +00:00
emitThrowExpressionTooDeepException ( ) ;
return ;
}
if ( UNLIKELY ( n - > needsDebugHook ( ) ) )
emitDebugHook ( n ) ;
n - > emitBytecode ( * this , dst ) ;
}
2020-08-29 13:27:11 +00:00
ALWAYS_INLINE unsigned addMetadataFor ( OpcodeID opcodeID )
{
return m_codeBlock - > metadata ( ) . addEntry ( opcodeID ) ;
}
2017-08-12 16:48:01 +00:00
void emitNode ( StatementNode * n )
{
emitNode ( nullptr , n ) ;
}
void emitNodeInTailPosition ( StatementNode * n )
{
emitNodeInTailPosition ( nullptr , n ) ;
}
RegisterID * emitNode ( RegisterID * dst , ExpressionNode * n )
{
SetForScope < bool > tailPositionPoisoner ( m_inTailPosition , false ) ;
return emitNodeInTailPosition ( dst , n ) ;
}
RegisterID * emitNodeInTailPosition ( RegisterID * dst , ExpressionNode * n )
{
// Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
ASSERT ( ! dst | | dst = = ignoredResult ( ) | | ! dst - > isTemporary ( ) | | dst - > refCount ( ) ) ;
2022-10-23 02:55:20 +00:00
if ( UNLIKELY ( ! m_vm . isSafeToRecurse ( ) ) )
2017-08-12 16:48:01 +00:00
return emitThrowExpressionTooDeepException ( ) ;
if ( UNLIKELY ( n - > needsDebugHook ( ) ) )
emitDebugHook ( n ) ;
return n - > emitBytecode ( * this , dst ) ;
}
RegisterID * emitNode ( ExpressionNode * n )
{
return emitNode ( nullptr , n ) ;
}
RegisterID * emitNodeInTailPosition ( ExpressionNode * n )
{
return emitNodeInTailPosition ( nullptr , n ) ;
}
2022-10-23 02:55:20 +00:00
RegisterID * emitDefineClassElements ( PropertyListNode * n , RegisterID * constructor , RegisterID * prototype , Vector < JSTextPosition > & instanceFieldLocations , Vector < JSTextPosition > & staticFieldLocations )
2020-08-29 13:27:11 +00:00
{
ASSERT ( constructor - > refCount ( ) & & prototype - > refCount ( ) ) ;
2022-10-23 02:55:20 +00:00
if ( UNLIKELY ( ! m_vm . isSafeToRecurse ( ) ) )
2020-08-29 13:27:11 +00:00
return emitThrowExpressionTooDeepException ( ) ;
if ( UNLIKELY ( n - > needsDebugHook ( ) ) )
emitDebugHook ( n ) ;
2022-10-23 02:55:20 +00:00
return n - > emitBytecode ( * this , constructor , prototype , & instanceFieldLocations , & staticFieldLocations ) ;
2020-08-29 13:27:11 +00:00
}
2018-01-03 05:16:05 +00:00
RegisterID * emitNodeForProperty ( RegisterID * dst , ExpressionNode * node )
{
if ( node - > isString ( ) ) {
2020-08-29 13:27:11 +00:00
if ( Optional < uint32_t > index = parseIndex ( static_cast < StringNode * > ( node ) - > value ( ) ) )
2018-01-03 05:16:05 +00:00
return emitLoad ( dst , jsNumber ( index . value ( ) ) ) ;
}
return emitNode ( dst , node ) ;
}
RegisterID * emitNodeForProperty ( ExpressionNode * n )
{
return emitNodeForProperty ( nullptr , n ) ;
}
void emitNodeInConditionContext ( ExpressionNode * n , Label & trueTarget , Label & falseTarget , FallThroughMode fallThroughMode )
2017-08-12 16:48:01 +00:00
{
2022-10-23 02:55:20 +00:00
if ( UNLIKELY ( ! m_vm . isSafeToRecurse ( ) ) ) {
2017-08-12 16:48:01 +00:00
emitThrowExpressionTooDeepException ( ) ;
return ;
}
n - > emitBytecodeInConditionContext ( * this , trueTarget , falseTarget , fallThroughMode ) ;
}
void emitExpressionInfo ( const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd )
{
ASSERT ( divot . offset > = divotStart . offset ) ;
ASSERT ( divotEnd . offset > = divot . offset ) ;
2022-10-23 02:55:20 +00:00
if ( m_isBuiltinFunction )
return ;
2017-08-12 16:48:01 +00:00
int sourceOffset = m_scopeNode - > source ( ) . startOffset ( ) ;
unsigned firstLine = m_scopeNode - > source ( ) . firstLine ( ) . oneBasedInt ( ) ;
int divotOffset = divot . offset - sourceOffset ;
int startOffset = divot . offset - divotStart . offset ;
int endOffset = divotEnd . offset - divot . offset ;
unsigned line = divot . line ;
ASSERT ( line > = firstLine ) ;
line - = firstLine ;
int lineStart = divot . lineStartOffset ;
if ( lineStart > sourceOffset )
lineStart - = sourceOffset ;
else
lineStart = 0 ;
if ( divotOffset < lineStart )
return ;
unsigned column = divotOffset - lineStart ;
unsigned instructionOffset = instructions ( ) . size ( ) ;
2022-10-23 02:55:20 +00:00
m_codeBlock - > addExpressionInfo ( instructionOffset , divotOffset , startOffset , endOffset , line , column ) ;
2017-08-12 16:48:01 +00:00
}
ALWAYS_INLINE bool leftHandSideNeedsCopy ( bool rightHasAssignments , bool rightIsPure )
{
return ( m_codeType ! = FunctionCode | | rightHasAssignments ) & & ! rightIsPure ;
}
2018-01-03 05:16:05 +00:00
ALWAYS_INLINE RefPtr < RegisterID > emitNodeForLeftHandSide ( ExpressionNode * n , bool rightHasAssignments , bool rightIsPure )
2017-08-12 16:48:01 +00:00
{
if ( leftHandSideNeedsCopy ( rightHasAssignments , rightIsPure ) ) {
2018-01-03 05:16:05 +00:00
RefPtr < RegisterID > dst = newTemporary ( ) ;
2017-08-12 16:48:01 +00:00
emitNode ( dst . get ( ) , n ) ;
return dst ;
}
return emitNode ( n ) ;
}
2018-01-03 05:16:05 +00:00
ALWAYS_INLINE RefPtr < RegisterID > emitNodeForLeftHandSideForProperty ( ExpressionNode * n , bool rightHasAssignments , bool rightIsPure )
{
if ( leftHandSideNeedsCopy ( rightHasAssignments , rightIsPure ) ) {
RefPtr < RegisterID > dst = newTemporary ( ) ;
emitNodeForProperty ( dst . get ( ) , n ) ;
return dst ;
}
return emitNodeForProperty ( n ) ;
}
2017-08-12 16:48:01 +00:00
void hoistSloppyModeFunctionIfNecessary ( const Identifier & functionName ) ;
2022-10-23 02:55:20 +00:00
StructureForInContext * findStructureForInContext ( RegisterID * property ) ;
2017-08-12 16:48:01 +00:00
private :
void emitTypeProfilerExpressionInfo ( const JSTextPosition & startDivot , const JSTextPosition & endDivot ) ;
public :
// This doesn't emit expression info. If using this, make sure you shouldn't be emitting text offset.
void emitProfileType ( RegisterID * registerToProfile , ProfileTypeBytecodeFlag ) ;
// These variables are associated with variables in a program. They could be Locals, LocalClosureVar, or ClosureVar.
void emitProfileType ( RegisterID * registerToProfile , const Variable & , const JSTextPosition & startDivot , const JSTextPosition & endDivot ) ;
void emitProfileType ( RegisterID * registerToProfile , ProfileTypeBytecodeFlag , const JSTextPosition & startDivot , const JSTextPosition & endDivot ) ;
// These are not associated with variables and don't have a global id.
void emitProfileType ( RegisterID * registerToProfile , const JSTextPosition & startDivot , const JSTextPosition & endDivot ) ;
void emitProfileControlFlow ( int ) ;
RegisterID * emitLoadArrowFunctionLexicalEnvironment ( const Identifier & ) ;
RegisterID * ensureThis ( ) ;
void emitLoadThisFromArrowFunctionLexicalEnvironment ( ) ;
RegisterID * emitLoadNewTargetFromArrowFunctionLexicalEnvironment ( ) ;
2018-01-03 05:16:05 +00:00
unsigned addConstantIndex ( ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitLoad ( RegisterID * dst , bool ) ;
RegisterID * emitLoad ( RegisterID * dst , const Identifier & ) ;
RegisterID * emitLoad ( RegisterID * dst , JSValue , SourceCodeRepresentation = SourceCodeRepresentation : : Other ) ;
2018-01-03 05:16:05 +00:00
RegisterID * emitLoad ( RegisterID * dst , IdentifierSet & excludedList ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
template < typename UnaryOp , typename = std : : enable_if_t < UnaryOp : : opcodeID ! = op_negate > >
RegisterID * emitUnaryOp ( RegisterID * dst , RegisterID * src )
{
UnaryOp : : emit ( this , dst , src ) ;
return dst ;
}
2022-10-23 02:55:20 +00:00
RegisterID * emitUnaryOp ( OpcodeID , RegisterID * dst , RegisterID * src , ResultType ) ;
2020-08-29 13:27:11 +00:00
template < typename BinaryOp >
std : : enable_if_t <
BinaryOp : : opcodeID ! = op_add
& & BinaryOp : : opcodeID ! = op_mul
& & BinaryOp : : opcodeID ! = op_sub
& & BinaryOp : : opcodeID ! = op_div ,
RegisterID * >
emitBinaryOp ( RegisterID * dst , RegisterID * src1 , RegisterID * src2 , OperandTypes )
{
BinaryOp : : emit ( this , dst , src1 , src2 ) ;
return dst ;
}
template < typename BinaryOp >
std : : enable_if_t <
BinaryOp : : opcodeID = = op_add
| | BinaryOp : : opcodeID = = op_mul
| | BinaryOp : : opcodeID = = op_sub
| | BinaryOp : : opcodeID = = op_div ,
RegisterID * >
emitBinaryOp ( RegisterID * dst , RegisterID * src1 , RegisterID * src2 , OperandTypes types )
{
BinaryOp : : emit ( this , dst , src1 , src2 , types ) ;
return dst ;
}
2017-08-12 16:48:01 +00:00
RegisterID * emitBinaryOp ( OpcodeID , RegisterID * dst , RegisterID * src1 , RegisterID * src2 , OperandTypes ) ;
2020-08-29 13:27:11 +00:00
template < typename EqOp >
RegisterID * emitEqualityOp ( RegisterID * dst , RegisterID * src1 , RegisterID * src2 )
{
if ( ! emitEqualityOpImpl ( dst , src1 , src2 ) )
EqOp : : emit ( this , dst , src1 , src2 ) ;
return dst ;
}
bool emitEqualityOpImpl ( RegisterID * dst , RegisterID * src1 , RegisterID * src2 ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitCreateThis ( RegisterID * dst ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitCreatePromise ( RegisterID * dst , RegisterID * newTarget , bool isInternalPromise ) ;
RegisterID * emitCreateGenerator ( RegisterID * dst , RegisterID * newTarget ) ;
RegisterID * emitCreateAsyncGenerator ( RegisterID * dst , RegisterID * newTarget ) ;
RegisterID * emitCreateArgumentsButterfly ( RegisterID * dst ) ;
RegisterID * emitInstanceFieldInitializationIfNeeded ( RegisterID * dst , RegisterID * constructor , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd ) ;
2017-08-12 16:48:01 +00:00
void emitTDZCheck ( RegisterID * target ) ;
bool needsTDZCheck ( const Variable & ) ;
void emitTDZCheckIfNecessary ( const Variable & , RegisterID * target , RegisterID * scope ) ;
void liftTDZCheckIfPossible ( const Variable & ) ;
RegisterID * emitNewObject ( RegisterID * dst ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitNewPromise ( RegisterID * dst , bool isInternalPromise ) ;
RegisterID * emitNewGenerator ( RegisterID * dst ) ;
2020-08-29 13:27:11 +00:00
RegisterID * emitNewArray ( RegisterID * dst , ElementNode * , unsigned length , IndexingType recommendedIndexingType ) ; // stops at first elision
RegisterID * emitNewArrayBuffer ( RegisterID * dst , JSImmutableButterfly * , IndexingType recommendedIndexingType ) ;
// FIXME: new_array_with_spread should use an array allocation profile and take a recommendedIndexingType
2017-08-12 16:48:01 +00:00
RegisterID * emitNewArrayWithSpread ( RegisterID * dst , ElementNode * ) ;
RegisterID * emitNewArrayWithSize ( RegisterID * dst , RegisterID * length ) ;
RegisterID * emitNewFunction ( RegisterID * dst , FunctionMetadataNode * ) ;
RegisterID * emitNewFunctionExpression ( RegisterID * dst , FuncExprNode * ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitNewDefaultConstructor ( RegisterID * dst , ConstructorKind , const Identifier & name , const Identifier & ecmaName , const SourceCode & classSource , NeedsClassFieldInitializer ) ;
RegisterID * emitNewClassFieldInitializerFunction ( RegisterID * dst , Vector < JSTextPosition > & & classFieldLocations , bool isDerived ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitNewArrowFunctionExpression ( RegisterID * , ArrowFuncExprNode * ) ;
RegisterID * emitNewMethodDefinition ( RegisterID * dst , MethodDefinitionNode * ) ;
RegisterID * emitNewRegExp ( RegisterID * dst , RegExp * ) ;
2022-10-23 02:55:20 +00:00
bool shouldSetFunctionName ( ExpressionNode * ) ;
void emitSetFunctionName ( RegisterID * value , RegisterID * name ) ;
void emitSetFunctionName ( RegisterID * value , const Identifier & ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
RegisterID * moveLinkTimeConstant ( RegisterID * dst , LinkTimeConstant ) ;
RegisterID * moveEmptyValue ( RegisterID * dst ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
RegisterID * emitToNumber ( RegisterID * dst , RegisterID * src ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitToNumeric ( RegisterID * dst , RegisterID * src ) ;
2020-08-29 13:27:11 +00:00
RegisterID * emitToString ( RegisterID * dst , RegisterID * src ) ;
RegisterID * emitToObject ( RegisterID * dst , RegisterID * src , const Identifier & message ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitInc ( RegisterID * srcDst ) ;
RegisterID * emitDec ( RegisterID * srcDst ) ;
RegisterID * emitOverridesHasInstance ( RegisterID * dst , RegisterID * constructor , RegisterID * hasInstanceValue ) ;
RegisterID * emitInstanceOf ( RegisterID * dst , RegisterID * value , RegisterID * basePrototype ) ;
RegisterID * emitInstanceOfCustom ( RegisterID * dst , RegisterID * value , RegisterID * constructor , RegisterID * hasInstanceValue ) ;
2020-08-29 13:27:11 +00:00
RegisterID * emitTypeOf ( RegisterID * dst , RegisterID * src ) ;
RegisterID * emitInByVal ( RegisterID * dst , RegisterID * property , RegisterID * base ) ;
RegisterID * emitInById ( RegisterID * dst , RegisterID * base , const Identifier & property ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitTryGetById ( RegisterID * dst , RegisterID * base , const Identifier & property ) ;
RegisterID * emitGetById ( RegisterID * dst , RegisterID * base , const Identifier & property ) ;
RegisterID * emitGetById ( RegisterID * dst , RegisterID * base , RegisterID * thisVal , const Identifier & property ) ;
2020-08-29 13:27:11 +00:00
RegisterID * emitDirectGetById ( RegisterID * dst , RegisterID * base , const Identifier & property ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitPutById ( RegisterID * base , const Identifier & property , RegisterID * value ) ;
RegisterID * emitPutById ( RegisterID * base , RegisterID * thisValue , const Identifier & property , RegisterID * value ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitDirectPutById ( RegisterID * base , const Identifier & property , RegisterID * value ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitDeleteById ( RegisterID * dst , RegisterID * base , const Identifier & ) ;
RegisterID * emitGetByVal ( RegisterID * dst , RegisterID * base , RegisterID * property ) ;
RegisterID * emitGetByVal ( RegisterID * dst , RegisterID * base , RegisterID * thisValue , RegisterID * property ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitGetPrototypeOf ( RegisterID * dst , RegisterID * value ) ;
RegisterID * emitDirectSetPrototypeOf ( RegisterID * base , RegisterID * prototype ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitPutByVal ( RegisterID * base , RegisterID * property , RegisterID * value ) ;
RegisterID * emitPutByVal ( RegisterID * base , RegisterID * thisValue , RegisterID * property , RegisterID * value ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitDirectGetByVal ( RegisterID * dst , RegisterID * base , RegisterID * property ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitDirectPutByVal ( RegisterID * base , RegisterID * property , RegisterID * value ) ;
RegisterID * emitDeleteByVal ( RegisterID * dst , RegisterID * base , RegisterID * property ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitGetInternalField ( RegisterID * dst , RegisterID * base , unsigned index ) ;
RegisterID * emitPutInternalField ( RegisterID * base , unsigned index , RegisterID * value ) ;
RegisterID * emitDefinePrivateField ( RegisterID * base , RegisterID * property , RegisterID * value ) ;
RegisterID * emitPrivateFieldPut ( RegisterID * base , RegisterID * property , RegisterID * value ) ;
2020-08-29 13:27:11 +00:00
void emitSuperSamplerBegin ( ) ;
void emitSuperSamplerEnd ( ) ;
RegisterID * emitIdWithProfile ( RegisterID * src , SpeculatedType profile ) ;
2018-01-03 05:16:05 +00:00
void emitUnreachable ( ) ;
2017-08-12 16:48:01 +00:00
void emitPutGetterById ( RegisterID * base , const Identifier & property , unsigned propertyDescriptorOptions , RegisterID * getter ) ;
void emitPutSetterById ( RegisterID * base , const Identifier & property , unsigned propertyDescriptorOptions , RegisterID * setter ) ;
void emitPutGetterSetter ( RegisterID * base , const Identifier & property , unsigned attributes , RegisterID * getter , RegisterID * setter ) ;
void emitPutGetterByVal ( RegisterID * base , RegisterID * property , unsigned propertyDescriptorOptions , RegisterID * getter ) ;
void emitPutSetterByVal ( RegisterID * base , RegisterID * property , unsigned propertyDescriptorOptions , RegisterID * setter ) ;
RegisterID * emitGetArgument ( RegisterID * dst , int32_t index ) ;
// Initialize object with generator fields (@generatorThis, @generatorNext, @generatorState, @generatorFrame)
void emitPutGeneratorFields ( RegisterID * nextFunction ) ;
2020-08-29 13:27:11 +00:00
void emitPutAsyncGeneratorFields ( RegisterID * nextFunction ) ;
2017-08-12 16:48:01 +00:00
ExpectedFunction expectedFunctionForIdentifier ( const Identifier & ) ;
RegisterID * emitCall ( RegisterID * dst , RegisterID * func , ExpectedFunction , CallArguments & , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
RegisterID * emitCallInTailPosition ( RegisterID * dst , RegisterID * func , ExpectedFunction , CallArguments & , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
RegisterID * emitCallEval ( RegisterID * dst , RegisterID * func , CallArguments & , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
RegisterID * emitCallVarargs ( RegisterID * dst , RegisterID * func , RegisterID * thisRegister , RegisterID * arguments , RegisterID * firstFreeRegister , int32_t firstVarArgOffset , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
RegisterID * emitCallVarargsInTailPosition ( RegisterID * dst , RegisterID * func , RegisterID * thisRegister , RegisterID * arguments , RegisterID * firstFreeRegister , int32_t firstVarArgOffset , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
RegisterID * emitCallForwardArgumentsInTailPosition ( RegisterID * dst , RegisterID * func , RegisterID * thisRegister , RegisterID * firstFreeRegister , int32_t firstVarArgOffset , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
enum PropertyDescriptorOption {
PropertyConfigurable = 1 ,
PropertyWritable = 1 < < 1 ,
PropertyEnumerable = 1 < < 2 ,
} ;
void emitCallDefineProperty ( RegisterID * newObj , RegisterID * propertyNameRegister ,
RegisterID * valueRegister , RegisterID * getterRegister , RegisterID * setterRegister , unsigned options , const JSTextPosition & ) ;
2022-10-23 02:55:20 +00:00
void emitGenericEnumeration ( ThrowableExpressionData * enumerationNode , ExpressionNode * subjectNode , const ScopedLambda < void ( BytecodeGenerator & , RegisterID * ) > & callBack , ForOfNode * = nullptr , RegisterID * forLoopSymbolTable = nullptr ) ;
2020-08-29 13:27:11 +00:00
void emitEnumeration ( ThrowableExpressionData * enumerationNode , ExpressionNode * subjectNode , const ScopedLambda < void ( BytecodeGenerator & , RegisterID * ) > & callBack , ForOfNode * = nullptr , RegisterID * forLoopSymbolTable = nullptr ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitGetTemplateObject ( RegisterID * dst , TaggedTemplateNode * ) ;
2018-01-03 05:16:05 +00:00
RegisterID * emitGetGlobalPrivate ( RegisterID * dst , const Identifier & property ) ;
2017-08-12 16:48:01 +00:00
2018-01-03 05:16:05 +00:00
enum class ReturnFrom { Normal , Finally } ;
RegisterID * emitReturn ( RegisterID * src , ReturnFrom = ReturnFrom : : Normal ) ;
2020-08-29 13:27:11 +00:00
RegisterID * emitEnd ( RegisterID * src ) ;
2017-08-12 16:48:01 +00:00
2018-01-03 05:16:05 +00:00
RegisterID * emitConstruct ( RegisterID * dst , RegisterID * func , RegisterID * lazyThis , ExpectedFunction , CallArguments & , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitStrcat ( RegisterID * dst , RegisterID * src , int count ) ;
void emitToPrimitive ( RegisterID * dst , RegisterID * src ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitToPropertyKey ( RegisterID * dst , RegisterID * src ) ;
2017-08-12 16:48:01 +00:00
ResolveType resolveType ( ) ;
RegisterID * emitResolveConstantLocal ( RegisterID * dst , const Variable & ) ;
RegisterID * emitResolveScope ( RegisterID * dst , const Variable & ) ;
RegisterID * emitGetFromScope ( RegisterID * dst , RegisterID * scope , const Variable & , ResolveMode ) ;
RegisterID * emitPutToScope ( RegisterID * scope , const Variable & , RegisterID * value , ResolveMode , InitializationMode ) ;
2018-01-03 05:16:05 +00:00
RegisterID * emitResolveScopeForHoistingFuncDeclInEval ( RegisterID * dst , const Identifier & ) ;
2017-08-12 16:48:01 +00:00
RegisterID * initializeVariable ( const Variable & , RegisterID * value ) ;
void emitLoopHint ( ) ;
2018-01-03 05:16:05 +00:00
void emitJump ( Label & target ) ;
void emitJumpIfTrue ( RegisterID * cond , Label & target ) ;
void emitJumpIfFalse ( RegisterID * cond , Label & target ) ;
void emitJumpIfNotFunctionCall ( RegisterID * cond , Label & target ) ;
void emitJumpIfNotFunctionApply ( RegisterID * cond , Label & target ) ;
2022-10-23 02:55:20 +00:00
unsigned emitWideJumpIfNotFunctionHasOwnProperty ( RegisterID * cond , Label & target ) ;
void recordHasOwnStructurePropertyInForInLoop ( StructureForInContext & , unsigned branchOffset , Label & genericPath ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
template < typename BinOp , typename JmpOp >
bool fuseCompareAndJump ( RegisterID * cond , Label & target , bool swapOperands = false ) ;
template < typename UnaryOp , typename JmpOp >
bool fuseTestAndJmp ( RegisterID * cond , Label & target ) ;
2017-08-12 16:48:01 +00:00
void emitEnter ( ) ;
2018-01-03 05:16:05 +00:00
void emitCheckTraps ( ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
RegisterID * emitHasEnumerableIndexedProperty ( RegisterID * dst , RegisterID * base , RegisterID * propertyName ) ;
RegisterID * emitHasEnumerableStructureProperty ( RegisterID * dst , RegisterID * base , RegisterID * propertyName , RegisterID * enumerator ) ;
RegisterID * emitHasEnumerableProperty ( RegisterID * dst , RegisterID * base , RegisterID * propertyName ) ;
RegisterID * emitHasOwnStructureProperty ( RegisterID * dst , RegisterID * base , RegisterID * propertyName , RegisterID * enumerator ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitGetPropertyEnumerator ( RegisterID * dst , RegisterID * base ) ;
RegisterID * emitGetEnumerableLength ( RegisterID * dst , RegisterID * base ) ;
RegisterID * emitGetStructurePropertyEnumerator ( RegisterID * dst , RegisterID * base , RegisterID * length ) ;
RegisterID * emitGetGenericPropertyEnumerator ( RegisterID * dst , RegisterID * base , RegisterID * length , RegisterID * structureEnumerator ) ;
RegisterID * emitEnumeratorStructurePropertyName ( RegisterID * dst , RegisterID * enumerator , RegisterID * index ) ;
RegisterID * emitEnumeratorGenericPropertyName ( RegisterID * dst , RegisterID * enumerator , RegisterID * index ) ;
RegisterID * emitToIndexString ( RegisterID * dst , RegisterID * index ) ;
RegisterID * emitIsCellWithType ( RegisterID * dst , RegisterID * src , JSType ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitIsGenerator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSGeneratorType ) ; }
RegisterID * emitIsAsyncGenerator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSAsyncGeneratorType ) ; }
2017-08-12 16:48:01 +00:00
RegisterID * emitIsJSArray ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , ArrayType ) ; }
2022-10-23 02:55:20 +00:00
RegisterID * emitIsPromise ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSPromiseType ) ; }
2017-08-12 16:48:01 +00:00
RegisterID * emitIsProxyObject ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , ProxyObjectType ) ; }
RegisterID * emitIsRegExpObject ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , RegExpObjectType ) ; }
RegisterID * emitIsMap ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSMapType ) ; }
RegisterID * emitIsSet ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSSetType ) ; }
2022-10-23 02:55:20 +00:00
RegisterID * emitIsStringIterator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSStringIteratorType ) ; }
RegisterID * emitIsArrayIterator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSArrayIteratorType ) ; }
RegisterID * emitIsMapIterator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSMapIteratorType ) ; }
RegisterID * emitIsSetIterator ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , JSSetIteratorType ) ; }
2017-08-12 16:48:01 +00:00
RegisterID * emitIsObject ( RegisterID * dst , RegisterID * src ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitIsCallable ( RegisterID * dst , RegisterID * src ) ;
RegisterID * emitIsConstructor ( RegisterID * dst , RegisterID * src ) ;
2018-01-03 05:16:05 +00:00
RegisterID * emitIsNumber ( RegisterID * dst , RegisterID * src ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitIsNull ( RegisterID * dst , RegisterID * src ) { return emitEqualityOp < OpStricteq > ( dst , src , emitLoad ( nullptr , jsNull ( ) ) ) ; }
RegisterID * emitIsUndefined ( RegisterID * dst , RegisterID * src ) { return emitEqualityOp < OpStricteq > ( dst , src , emitLoad ( nullptr , jsUndefined ( ) ) ) ; }
2020-08-29 13:27:11 +00:00
RegisterID * emitIsUndefinedOrNull ( RegisterID * dst , RegisterID * src ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitIsEmpty ( RegisterID * dst , RegisterID * src ) ;
RegisterID * emitIsDerivedArray ( RegisterID * dst , RegisterID * src ) { return emitIsCellWithType ( dst , src , DerivedArrayType ) ; }
void emitRequireObjectCoercible ( RegisterID * value , const String & error ) ;
2022-10-23 02:55:20 +00:00
void emitIteratorOpen ( RegisterID * iterator , RegisterID * nextOrIndex , RegisterID * symbolIterator , CallArguments & iterable , const ThrowableExpressionData * ) ;
void emitIteratorNext ( RegisterID * done , RegisterID * value , RegisterID * iterable , RegisterID * nextOrIndex , CallArguments & iterator , const ThrowableExpressionData * ) ;
RegisterID * emitGetGenericIterator ( RegisterID * , ThrowableExpressionData * ) ;
RegisterID * emitGetAsyncIterator ( RegisterID * , ThrowableExpressionData * ) ;
RegisterID * emitIteratorGenericNext ( RegisterID * dst , RegisterID * nextMethod , RegisterID * iterator , const ThrowableExpressionData * node , JSC : : EmitAwait = JSC : : EmitAwait : : No ) ;
RegisterID * emitIteratorGenericNextWithValue ( RegisterID * dst , RegisterID * nextMethod , RegisterID * iterator , RegisterID * value , const ThrowableExpressionData * node ) ;
void emitIteratorGenericClose ( RegisterID * iterator , const ThrowableExpressionData * node , EmitAwait = EmitAwait : : No ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitRestParameter ( RegisterID * result , unsigned numParametersToSkip ) ;
bool emitReadOnlyExceptionIfNeeded ( const Variable & ) ;
// Start a try block. 'start' must have been emitted.
2018-01-03 05:16:05 +00:00
TryData * pushTry ( Label & start , Label & handlerLabel , HandlerType ) ;
2017-08-12 16:48:01 +00:00
// End a try block. 'end' must have been emitted.
2018-01-03 05:16:05 +00:00
void popTry ( TryData * , Label & end ) ;
2020-08-29 13:27:11 +00:00
void emitOutOfLineCatchHandler ( RegisterID * thrownValueRegister , RegisterID * completionTypeRegister , TryData * ) ;
void emitOutOfLineFinallyHandler ( RegisterID * exceptionRegister , RegisterID * completionTypeRegister , TryData * ) ;
2018-01-03 05:16:05 +00:00
private :
2022-10-23 02:55:20 +00:00
static constexpr int CurrentLexicalScopeIndex = - 2 ;
static constexpr int OutermostLexicalScopeIndex = - 1 ;
2018-01-03 05:16:05 +00:00
int currentLexicalScopeIndex ( ) const
{
int size = static_cast < int > ( m_lexicalScopeStack . size ( ) ) ;
ASSERT ( static_cast < size_t > ( size ) = = m_lexicalScopeStack . size ( ) ) ;
ASSERT ( size > = 0 ) ;
if ( ! size )
return OutermostLexicalScopeIndex ;
return size - 1 ;
}
2020-08-29 13:27:11 +00:00
void emitOutOfLineExceptionHandler ( RegisterID * exceptionRegister , RegisterID * thrownValueRegister , RegisterID * completionTypeRegister , TryData * ) ;
2018-01-03 05:16:05 +00:00
public :
void restoreScopeRegister ( ) ;
void restoreScopeRegister ( int lexicalScopeIndex ) ;
int labelScopeDepthToLexicalScopeIndex ( int labelScopeDepth ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
void emitThrow ( RegisterID * ) ;
RegisterID * emitArgumentCount ( RegisterID * ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
void emitThrowStaticError ( ErrorTypeWithExtension , RegisterID * ) ;
void emitThrowStaticError ( ErrorTypeWithExtension , const Identifier & message ) ;
2017-08-12 16:48:01 +00:00
void emitThrowReferenceError ( const String & message ) ;
void emitThrowTypeError ( const String & message ) ;
void emitThrowTypeError ( const Identifier & message ) ;
void emitThrowRangeError ( const Identifier & message ) ;
void emitThrowOutOfMemoryError ( ) ;
void emitPushCatchScope ( VariableEnvironment & ) ;
void emitPopCatchScope ( VariableEnvironment & ) ;
2020-08-29 13:27:11 +00:00
void emitAwait ( RegisterID * ) ;
2017-08-12 16:48:01 +00:00
void emitGetScope ( ) ;
RegisterID * emitPushWithScope ( RegisterID * objectScope ) ;
void emitPopWithScope ( ) ;
void emitPutThisToArrowFunctionContextScope ( ) ;
void emitPutNewTargetToArrowFunctionContextScope ( ) ;
void emitPutDerivedConstructorToArrowFunctionContextScope ( ) ;
RegisterID * emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment ( ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitLoadDerivedConstructor ( ) ;
2017-08-12 16:48:01 +00:00
void emitDebugHook ( DebugHookType , const JSTextPosition & ) ;
void emitDebugHook ( DebugHookType , unsigned line , unsigned charOffset , unsigned lineStart ) ;
void emitDebugHook ( StatementNode * ) ;
void emitDebugHook ( ExpressionNode * ) ;
void emitWillLeaveCallFrameDebugHook ( ) ;
2020-08-29 13:27:11 +00:00
void emitLoad ( RegisterID * completionTypeRegister , CompletionType type )
2018-01-03 05:16:05 +00:00
{
2020-08-29 13:27:11 +00:00
emitLoad ( completionTypeRegister , JSValue ( static_cast < int > ( type ) ) ) ;
2018-01-03 05:16:05 +00:00
}
2020-08-29 13:27:11 +00:00
template < typename CompareOp >
void emitJumpIf ( RegisterID * completionTypeRegister , CompletionType , Label & jumpTarget ) ;
2018-01-03 05:16:05 +00:00
bool emitJumpViaFinallyIfNeeded ( int targetLabelScopeDepth , Label & jumpTarget ) ;
bool emitReturnViaFinallyIfNeeded ( RegisterID * returnRegister ) ;
2020-08-29 13:27:11 +00:00
void emitFinallyCompletion ( FinallyContext & , Label & normalCompletionLabel ) ;
2018-01-03 05:16:05 +00:00
public :
2020-08-29 13:27:11 +00:00
void pushFinallyControlFlowScope ( FinallyContext & ) ;
void popFinallyControlFlowScope ( ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
void pushOptionalChainTarget ( ) ;
void popOptionalChainTarget ( ) ;
void popOptionalChainTarget ( RegisterID * dst , bool isDelete ) ;
void emitOptionalCheck ( RegisterID * src ) ;
2017-08-12 16:48:01 +00:00
void pushIndexedForInScope ( RegisterID * local , RegisterID * index ) ;
void popIndexedForInScope ( RegisterID * local ) ;
2022-10-23 02:55:20 +00:00
void pushStructureForInScope ( RegisterID * local , RegisterID * index , RegisterID * property , RegisterID * enumerator , Optional < Variable > base ) ;
2017-08-12 16:48:01 +00:00
void popStructureForInScope ( RegisterID * local ) ;
2020-08-29 13:27:11 +00:00
LabelScope * breakTarget ( const Identifier & ) ;
LabelScope * continueTarget ( const Identifier & ) ;
2017-08-12 16:48:01 +00:00
void beginSwitch ( RegisterID * , SwitchInfo : : SwitchType ) ;
2018-01-03 05:16:05 +00:00
void endSwitch ( uint32_t clauseCount , const Vector < Ref < Label > , 8 > & , ExpressionNode * * , Label & defaultLabel , int32_t min , int32_t range ) ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
void emitYieldPoint ( RegisterID * , JSAsyncGenerator : : AsyncGeneratorSuspendReason ) ;
2017-08-12 16:48:01 +00:00
void emitGeneratorStateLabel ( ) ;
void emitGeneratorStateChange ( int32_t state ) ;
2022-10-23 02:55:20 +00:00
RegisterID * emitYield ( RegisterID * argument , JSAsyncGenerator : : AsyncGeneratorSuspendReason = JSAsyncGenerator : : AsyncGeneratorSuspendReason : : Yield ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitDelegateYield ( RegisterID * argument , ThrowableExpressionData * ) ;
2022-10-23 02:55:20 +00:00
RegisterID * generatorStateRegister ( ) { return & m_parameters [ static_cast < int32_t > ( JSGenerator : : GeneratorArgument : : State ) ] ; }
RegisterID * generatorValueRegister ( ) { return & m_parameters [ static_cast < int32_t > ( JSGenerator : : GeneratorArgument : : Value ) ] ; }
RegisterID * generatorResumeModeRegister ( ) { return & m_parameters [ static_cast < int32_t > ( JSGenerator : : GeneratorArgument : : ResumeMode ) ] ; }
RegisterID * generatorFrameRegister ( ) { return & m_parameters [ static_cast < int32_t > ( JSGenerator : : GeneratorArgument : : Frame ) ] ; }
2017-08-12 16:48:01 +00:00
CodeType codeType ( ) const { return m_codeType ; }
2020-08-29 13:27:11 +00:00
bool shouldBeConcernedWithCompletionValue ( ) const { return m_codeType ! = FunctionCode ; }
bool shouldEmitDebugHooks ( ) const { return m_codeGenerationMode . contains ( CodeGenerationMode : : Debugger ) & & ! m_isBuiltinFunction ; }
bool shouldEmitTypeProfilerHooks ( ) const { return m_codeGenerationMode . contains ( CodeGenerationMode : : TypeProfiler ) ; }
bool shouldEmitControlFlowProfilerHooks ( ) const { return m_codeGenerationMode . contains ( CodeGenerationMode : : ControlFlowProfiler ) ; }
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
ECMAMode ecmaMode ( ) const { return m_ecmaMode ; }
void setUsesCheckpoints ( ) { m_codeBlock - > setHasCheckpoints ( ) ; }
2017-08-12 16:48:01 +00:00
SourceParseMode parseMode ( ) const { return m_codeBlock - > parseMode ( ) ; }
bool isBuiltinFunction ( ) const { return m_isBuiltinFunction ; }
OpcodeID lastOpcodeID ( ) const { return m_lastOpcodeID ; }
bool isDerivedConstructorContext ( ) { return m_derivedContextType = = DerivedContextType : : DerivedConstructorContext ; }
bool isDerivedClassContext ( ) { return m_derivedContextType = = DerivedContextType : : DerivedMethodContext ; }
bool isArrowFunction ( ) { return m_codeBlock - > isArrowFunction ( ) ; }
enum class TDZCheckOptimization { Optimize , DoNotOptimize } ;
enum class NestedScopeType { IsNested , IsNotNested } ;
private :
enum class TDZRequirement { UnderTDZ , NotUnderTDZ } ;
enum class ScopeType { CatchScope , LetConstScope , FunctionNameScope } ;
enum class ScopeRegisterType { Var , Block } ;
void pushLexicalScopeInternal ( VariableEnvironment & , TDZCheckOptimization , NestedScopeType , RegisterID * * constantSymbolTableResult , TDZRequirement , ScopeType , ScopeRegisterType ) ;
void initializeBlockScopedFunctions ( VariableEnvironment & , FunctionStack & , RegisterID * constantSymbolTable ) ;
void popLexicalScopeInternal ( VariableEnvironment & ) ;
template < typename LookUpVarKindFunctor >
bool instantiateLexicalVariables ( const VariableEnvironment & , SymbolTable * , ScopeRegisterType , LookUpVarKindFunctor ) ;
void emitPrefillStackTDZVariables ( const VariableEnvironment & , SymbolTable * ) ;
RegisterID * emitGetParentScope ( RegisterID * dst , RegisterID * scope ) ;
void emitPushFunctionNameScope ( const Identifier & property , RegisterID * value , bool isCaptured ) ;
void emitNewFunctionExpressionCommon ( RegisterID * , FunctionMetadataNode * ) ;
bool isNewTargetUsedInInnerArrowFunction ( ) ;
bool isArgumentsUsedInInnerArrowFunction ( ) ;
2020-08-29 13:27:11 +00:00
void emitToThis ( ) ;
RegisterID * emitMove ( RegisterID * dst , RegisterID * src ) ;
2022-10-23 02:55:20 +00:00
public :
void disablePeepholeOptimization ( ) { m_lastOpcodeID = op_end ; }
private :
2020-08-29 13:27:11 +00:00
bool canDoPeepholeOptimization ( ) const { return m_lastOpcodeID ! = op_end ; }
2017-08-12 16:48:01 +00:00
public :
2018-01-03 05:16:05 +00:00
bool isSuperUsedInInnerArrowFunction ( ) ;
2017-08-12 16:48:01 +00:00
bool isSuperCallUsedInInnerArrowFunction ( ) ;
bool isThisUsedInInnerArrowFunction ( ) ;
void pushLexicalScope ( VariableEnvironmentNode * , TDZCheckOptimization , NestedScopeType = NestedScopeType : : IsNotNested , RegisterID * * constantSymbolTableResult = nullptr , bool shouldInitializeBlockScopedFunctions = true ) ;
void popLexicalScope ( VariableEnvironmentNode * ) ;
void prepareLexicalScopeForNextForLoopIteration ( VariableEnvironmentNode * , RegisterID * loopSymbolTable ) ;
int labelScopeDepth ( ) const ;
2018-01-03 05:16:05 +00:00
UnlinkedArrayProfile newArrayProfile ( ) ;
2017-08-12 16:48:01 +00:00
private :
ParserError generate ( ) ;
Variable variableForLocalEntry ( const Identifier & , const SymbolTableEntry & , int symbolTableConstantIndex , bool isLexicallyScoped ) ;
2020-08-29 13:27:11 +00:00
RegisterID * kill ( RegisterID * dst )
2017-08-12 16:48:01 +00:00
{
2020-08-29 13:27:11 +00:00
m_staticPropertyAnalyzer . kill ( dst ) ;
return dst ;
2017-08-12 16:48:01 +00:00
}
void retrieveLastUnaryOp ( int & dstIndex , int & srcIndex ) ;
2020-08-29 13:27:11 +00:00
ALWAYS_INLINE void rewind ( ) ;
2017-08-12 16:48:01 +00:00
void allocateAndEmitScope ( ) ;
2020-08-29 13:27:11 +00:00
template < typename JumpOp >
void setTargetForJumpInstruction ( InstructionStream : : MutableRef & , int target ) ;
using BigIntMapEntry = std : : tuple < UniquedStringImpl * , uint8_t , bool > ;
using NumberMap = HashMap < double , JSValue > ;
using IdentifierStringMap = HashMap < UniquedStringImpl * , JSString * , IdentifierRepHash > ;
2022-10-23 02:55:20 +00:00
using IdentifierBigIntMap = HashMap < BigIntMapEntry , JSValue > ;
2020-08-29 13:27:11 +00:00
using TemplateObjectDescriptorSet = HashSet < Ref < TemplateObjectDescriptor > > ;
using TemplateDescriptorMap = HashMap < uint64_t , JSTemplateObjectDescriptor * , WTF : : IntHash < uint64_t > , WTF : : UnsignedWithZeroKeyHashTraits < uint64_t > > ;
2017-08-12 16:48:01 +00:00
// Helper for emitCall() and emitConstruct(). This works because the set of
// expected functions have identical behavior for both call and construct
// (i.e. "Object()" is identical to "new Object()").
2018-01-03 05:16:05 +00:00
ExpectedFunction emitExpectedFunctionSnippet ( RegisterID * dst , RegisterID * func , ExpectedFunction , CallArguments & , Label & done ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
template < typename CallOp >
RegisterID * emitCall ( RegisterID * dst , RegisterID * func , ExpectedFunction , CallArguments & , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
RegisterID * emitCallIterator ( RegisterID * iterator , RegisterID * argument , ThrowableExpressionData * ) ;
2017-08-12 16:48:01 +00:00
// Initializes the stack form the parameter; does nothing for the symbol table.
RegisterID * initializeNextParameter ( ) ;
UniquedStringImpl * visibleNameForParameter ( DestructuringPatternNode * ) ;
RegisterID & registerFor ( VirtualRegister reg )
{
if ( reg . isLocal ( ) )
return m_calleeLocals [ reg . toLocal ( ) ] ;
if ( reg . offset ( ) = = CallFrameSlot : : callee )
return m_calleeRegister ;
ASSERT ( m_parameters . size ( ) ) ;
return m_parameters [ reg . toArgument ( ) ] ;
}
bool hasConstant ( const Identifier & ) const ;
unsigned addConstant ( const Identifier & ) ;
RegisterID * addConstantValue ( JSValue , SourceCodeRepresentation = SourceCodeRepresentation : : Other ) ;
RegisterID * addConstantEmptyValue ( ) ;
UnlinkedFunctionExecutable * makeFunction ( FunctionMetadataNode * metadata )
{
DerivedContextType newDerivedContextType = DerivedContextType : : None ;
2022-10-23 02:55:20 +00:00
NeedsClassFieldInitializer needsClassFieldInitializer = metadata - > isConstructorAndNeedsClassFieldInitializer ( ) ? NeedsClassFieldInitializer : : Yes : NeedsClassFieldInitializer : : No ;
2018-01-03 05:16:05 +00:00
if ( SourceParseModeSet ( SourceParseMode : : ArrowFunctionMode , SourceParseMode : : AsyncArrowFunctionMode , SourceParseMode : : AsyncArrowFunctionBodyMode ) . contains ( metadata - > parseMode ( ) ) ) {
2022-10-23 02:55:20 +00:00
if ( constructorKind ( ) = = ConstructorKind : : Extends | | isDerivedConstructorContext ( ) ) {
2017-08-12 16:48:01 +00:00
newDerivedContextType = DerivedContextType : : DerivedConstructorContext ;
2022-10-23 02:55:20 +00:00
needsClassFieldInitializer = m_codeBlock - > needsClassFieldInitializer ( ) ;
}
2017-08-12 16:48:01 +00:00
else if ( m_codeBlock - > isClassContext ( ) | | isDerivedClassContext ( ) )
newDerivedContextType = DerivedContextType : : DerivedMethodContext ;
}
2022-10-23 02:55:20 +00:00
auto optionalVariablesUnderTDZ = getVariablesUnderTDZ ( ) ;
2017-08-12 16:48:01 +00:00
// FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
// https://bugs.webkit.org/show_bug.cgi?id=151547
SourceParseMode parseMode = metadata - > parseMode ( ) ;
ConstructAbility constructAbility = constructAbilityForParseMode ( parseMode ) ;
if ( parseMode = = SourceParseMode : : MethodMode & & metadata - > constructorKind ( ) ! = ConstructorKind : : None )
constructAbility = ConstructAbility : : CanConstruct ;
2022-10-23 02:55:20 +00:00
return UnlinkedFunctionExecutable : : create ( m_vm , m_scopeNode - > source ( ) , metadata , isBuiltinFunction ( ) ? UnlinkedBuiltinFunction : UnlinkedNormalFunction , constructAbility , scriptMode ( ) , WTFMove ( optionalVariablesUnderTDZ ) , newDerivedContextType , needsClassFieldInitializer ) ;
2017-08-12 16:48:01 +00:00
}
2022-10-23 02:55:20 +00:00
RefPtr < TDZEnvironmentLink > getVariablesUnderTDZ ( ) ;
2017-08-12 16:48:01 +00:00
RegisterID * emitConstructVarargs ( RegisterID * dst , RegisterID * func , RegisterID * thisRegister , RegisterID * arguments , RegisterID * firstFreeRegister , int32_t firstVarArgOffset , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
2020-08-29 13:27:11 +00:00
template < typename CallOp >
RegisterID * emitCallVarargs ( RegisterID * dst , RegisterID * func , RegisterID * thisRegister , RegisterID * arguments , RegisterID * firstFreeRegister , int32_t firstVarArgOffset , const JSTextPosition & divot , const JSTextPosition & divotStart , const JSTextPosition & divotEnd , DebuggableCall ) ;
2017-08-12 16:48:01 +00:00
void emitLogShadowChickenPrologueIfNecessary ( ) ;
void emitLogShadowChickenTailIfNecessary ( ) ;
void initializeParameters ( FunctionParameters & ) ;
void initializeVarLexicalEnvironment ( int symbolTableConstantIndex , SymbolTable * functionSymbolTable , bool hasCapturedVariables ) ;
2020-08-29 13:27:11 +00:00
void initializeDefaultParameterValuesAndSetupFunctionScopeStack ( FunctionParameters & , bool isSimpleParameterList , FunctionNode * , SymbolTable * , int symbolTableConstantIndex , const ScopedLambda < bool ( UniquedStringImpl * ) > & captures , bool shouldCreateArgumentsVariableInParameterScope ) ;
2017-08-12 16:48:01 +00:00
void initializeArrowFunctionContextScopeIfNeeded ( SymbolTable * functionSymbolTable = nullptr , bool canReuseLexicalEnvironment = false ) ;
2018-01-03 05:16:05 +00:00
bool needsDerivedConstructorInArrowFunctionLexicalEnvironment ( ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
enum class TDZNecessityLevel {
NotNeeded ,
Optimize ,
DoNotOptimize
} ;
typedef HashMap < RefPtr < UniquedStringImpl > , TDZNecessityLevel , IdentifierRepHash > TDZMap ;
2017-08-12 16:48:01 +00:00
public :
JSString * addStringConstant ( const Identifier & ) ;
2020-08-29 13:27:11 +00:00
JSValue addBigIntConstant ( const Identifier & , uint8_t radix , bool sign ) ;
RegisterID * addTemplateObjectConstant ( Ref < TemplateObjectDescriptor > & & , int ) ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
const InstructionStream & instructions ( ) const { return m_writer ; }
2017-08-12 16:48:01 +00:00
RegisterID * emitThrowExpressionTooDeepException ( ) ;
2022-10-23 02:55:20 +00:00
using TDZStackEntry = std : : pair < TDZMap , RefPtr < TDZEnvironmentLink > > ;
2020-08-29 13:27:11 +00:00
class PreservedTDZStack {
private :
2022-10-23 02:55:20 +00:00
Vector < TDZStackEntry > m_preservedTDZStack ;
2020-08-29 13:27:11 +00:00
friend class BytecodeGenerator ;
} ;
void preserveTDZStack ( PreservedTDZStack & ) ;
void restoreTDZStack ( const PreservedTDZStack & ) ;
template < typename Func >
void withWriter ( InstructionStreamWriter & writer , const Func & fn )
{
auto prevLastOpcodeID = m_lastOpcodeID ;
auto prevLastInstruction = m_lastInstruction ;
m_writer . swap ( writer ) ;
2022-10-23 02:55:20 +00:00
disablePeepholeOptimization ( ) ;
2020-08-29 13:27:11 +00:00
m_lastInstruction = m_writer . ref ( ) ;
fn ( ) ;
m_writer . swap ( writer ) ;
m_lastOpcodeID = prevLastOpcodeID ;
m_lastInstruction = prevLastInstruction ;
}
2017-08-12 16:48:01 +00:00
private :
2020-08-29 13:27:11 +00:00
OptionSet < CodeGenerationMode > m_codeGenerationMode ;
2017-08-12 16:48:01 +00:00
struct LexicalScopeStackEntry {
SymbolTable * m_symbolTable ;
RegisterID * m_scope ;
bool m_isWithScope ;
int m_symbolTableConstantIndex ;
} ;
Vector < LexicalScopeStackEntry > m_lexicalScopeStack ;
2020-08-29 13:27:11 +00:00
2022-10-23 02:55:20 +00:00
RefPtr < TDZEnvironmentLink > m_cachedParentTDZ ;
Vector < TDZStackEntry > m_TDZStack ;
2020-08-29 13:27:11 +00:00
Optional < size_t > m_varScopeLexicalScopeStackIndex ;
2017-08-12 16:48:01 +00:00
void pushTDZVariables ( const VariableEnvironment & , TDZCheckOptimization , TDZRequirement ) ;
ScopeNode * const m_scopeNode ;
// Some of these objects keep pointers to one another. They are arranged
// to ensure a sane destruction order that avoids references to freed memory.
HashSet < RefPtr < UniquedStringImpl > , IdentifierRepHash > m_functions ;
RegisterID m_ignoredResultRegister ;
RegisterID m_thisRegister ;
RegisterID m_calleeRegister ;
RegisterID * m_scopeRegister { nullptr } ;
RegisterID * m_topMostScope { nullptr } ;
RegisterID * m_argumentsRegister { nullptr } ;
RegisterID * m_lexicalEnvironmentRegister { nullptr } ;
RegisterID * m_generatorRegister { nullptr } ;
RegisterID * m_emptyValueRegister { nullptr } ;
RegisterID * m_newTargetRegister { nullptr } ;
RegisterID * m_isDerivedConstuctor { nullptr } ;
2022-10-23 02:55:20 +00:00
HashMap < LinkTimeConstant , RegisterID * , WTF : : IntHash < LinkTimeConstant > , WTF : : StrongEnumHashTraits < LinkTimeConstant > > m_linkTimeConstantRegisters ;
2017-08-12 16:48:01 +00:00
RegisterID * m_arrowFunctionContextLexicalEnvironmentRegister { nullptr } ;
2022-10-23 02:55:20 +00:00
RegisterID * m_promiseRegister { nullptr } ;
2017-08-12 16:48:01 +00:00
2018-01-03 05:16:05 +00:00
FinallyContext * m_currentFinallyContext { nullptr } ;
2017-08-12 16:48:01 +00:00
SegmentedVector < RegisterID , 32 > m_parameters ;
2018-01-03 05:16:05 +00:00
SegmentedVector < LabelScope , 32 > m_labelScopes ;
2022-10-23 02:55:20 +00:00
SegmentedVector < RegisterID , 32 > m_constantPoolRegisters ;
2018-01-03 05:16:05 +00:00
unsigned m_finallyDepth { 0 } ;
2020-08-29 13:27:11 +00:00
unsigned m_localScopeDepth { 0 } ;
2017-08-12 16:48:01 +00:00
const CodeType m_codeType ;
2020-08-29 13:27:11 +00:00
unsigned localScopeDepth ( ) const ;
2017-08-12 16:48:01 +00:00
void pushLocalControlFlowScope ( ) ;
void popLocalControlFlowScope ( ) ;
2018-01-03 05:16:05 +00:00
// FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it.
// https://bugs.webkit.org/show_bug.cgi?id=165980
SegmentedVector < ControlFlowScope , 16 > m_controlFlowScopeStack ;
2017-08-12 16:48:01 +00:00
Vector < SwitchInfo > m_switchContextStack ;
2018-01-03 05:16:05 +00:00
Vector < Ref < ForInContext > > m_forInContextStack ;
2017-08-12 16:48:01 +00:00
Vector < TryContext > m_tryContextStack ;
unsigned m_yieldPoints { 0 } ;
Strong < SymbolTable > m_generatorFrameSymbolTable ;
int m_generatorFrameSymbolTableIndex { 0 } ;
2018-01-03 05:16:05 +00:00
enum FunctionVariableType : uint8_t { NormalFunctionVariable , TopLevelFunctionVariable } ;
2017-08-12 16:48:01 +00:00
Vector < std : : pair < FunctionMetadataNode * , FunctionVariableType > > m_functionsToInitialize ;
bool m_needToInitializeArguments { false } ;
RestParameterNode * m_restParameter { nullptr } ;
Vector < TryRange > m_tryRanges ;
SegmentedVector < TryData , 8 > m_tryData ;
2022-10-23 02:55:20 +00:00
Vector < Ref < Label > > m_optionalChainTargetStack ;
2017-08-12 16:48:01 +00:00
int m_nextConstantOffset { 0 } ;
typedef HashMap < FunctionMetadataNode * , unsigned > FunctionOffsetMap ;
FunctionOffsetMap m_functionOffsets ;
// Constant pool
IdentifierMap m_identifierMap ;
typedef HashMap < EncodedJSValueWithRepresentation , unsigned , EncodedJSValueWithRepresentationHash , EncodedJSValueWithRepresentationHashTraits > JSValueMap ;
JSValueMap m_jsValueMap ;
IdentifierStringMap m_stringMap ;
2020-08-29 13:27:11 +00:00
IdentifierBigIntMap m_bigIntMap ;
TemplateObjectDescriptorSet m_templateObjectDescriptorSet ;
TemplateDescriptorMap m_templateDescriptorMap ;
2017-08-12 16:48:01 +00:00
2020-08-29 13:27:11 +00:00
StaticPropertyAnalyzer m_staticPropertyAnalyzer ;
2017-08-12 16:48:01 +00:00
2022-10-23 02:55:20 +00:00
VM & m_vm ;
2017-08-12 16:48:01 +00:00
bool m_usesExceptions { false } ;
bool m_expressionTooDeep { false } ;
bool m_isBuiltinFunction { false } ;
bool m_usesNonStrictEval { false } ;
bool m_inTailPosition { false } ;
2022-10-23 02:55:20 +00:00
bool m_needsToUpdateArrowFunctionContext : 1 ;
ECMAMode m_ecmaMode ;
2017-08-12 16:48:01 +00:00
DerivedContextType m_derivedContextType { DerivedContextType : : None } ;
2020-08-29 13:27:11 +00:00
struct CatchEntry {
TryData * tryData ;
VirtualRegister exceptionRegister ;
VirtualRegister thrownValueRegister ;
VirtualRegister completionTypeRegister ;
} ;
Vector < CatchEntry > m_exceptionHandlersToEmit ;
2022-10-23 02:55:20 +00:00
struct {
JSTextPosition position ;
DebugHookType type { DidExecuteProgram } ;
} m_lastDebugHook ;
} ;
class StrictModeScope : private SetForScope < ECMAMode > {
public :
StrictModeScope ( BytecodeGenerator & generator )
: SetForScope ( generator . m_ecmaMode , ECMAMode : : strict ( ) )
{
}
2017-08-12 16:48:01 +00:00
} ;
} // namespace JSC
namespace WTF {
void printInternal ( PrintStream & , JSC : : Variable : : VariableKind ) ;
} // namespace WTF