2017-08-12 09:48:01 -07:00
/*
* Copyright ( C ) 2011 , 2013 - 2016 Apple Inc . All rights reserved .
*
* 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 .
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC . ` ` 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 INC . OR
* 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
# if ENABLE(DFG_JIT)
# include "DFGAbstractValue.h"
# include "DFGAvailabilityMap.h"
# include "DFGBranchDirection.h"
# include "DFGNode.h"
# include "DFGNodeAbstractValuePair.h"
# include "DFGStructureClobberState.h"
# include "Operands.h"
# include <wtf/Vector.h>
namespace JSC { namespace DFG {
class Graph ;
class InsertionSet ;
typedef Vector < BasicBlock * , 2 > PredecessorList ;
typedef Vector < Node * , 8 > BlockNodeList ;
2022-10-22 19:55:20 -07:00
DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER ( BasicBlock ) ;
2017-08-12 09:48:01 -07:00
struct BasicBlock : RefCounted < BasicBlock > {
2022-10-22 19:55:20 -07:00
WTF_MAKE_STRUCT_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER ( BasicBlock ) ;
2017-08-12 09:48:01 -07:00
BasicBlock (
2022-10-22 19:55:20 -07:00
BytecodeIndex bytecodeBegin , unsigned numArguments , unsigned numLocals , unsigned numTmps ,
2017-08-12 09:48:01 -07:00
float executionCount ) ;
~ BasicBlock ( ) ;
void ensureLocals ( unsigned newNumLocals ) ;
2022-10-22 19:55:20 -07:00
void ensureTmps ( unsigned newNumTmps ) ;
2017-08-12 09:48:01 -07:00
size_t size ( ) const { return m_nodes . size ( ) ; }
bool isEmpty ( ) const { return ! size ( ) ; }
Node * & at ( size_t i ) { return m_nodes [ i ] ; }
Node * at ( size_t i ) const { return m_nodes [ i ] ; }
Node * tryAt ( size_t i ) const
{
if ( i > = size ( ) )
return nullptr ;
return at ( i ) ;
}
Node * & operator [ ] ( size_t i ) { return at ( i ) ; }
Node * operator [ ] ( size_t i ) const { return at ( i ) ; }
2020-08-29 09:27:11 -04:00
Node * last ( ) const
{
RELEASE_ASSERT ( ! ! size ( ) ) ;
return at ( size ( ) - 1 ) ;
}
2017-08-12 09:48:01 -07:00
// Use this to find both the index of the terminal and the terminal itself in one go. May
// return a clear NodeAndIndex if the basic block currently lacks a terminal. That may happen
// in the middle of IR transformations within a phase but should never be the case in between
// phases.
//
// The reason why this is more than just "at(size() - 1)" is that we may place non-terminal
// liveness marking instructions after the terminal. This is supposed to happen infrequently
// but some basic blocks - most notably return blocks - will have liveness markers for all of
// the flushed variables right after the return.
//
// It turns out that doing this linear search is basically perf-neutral, so long as we force
// the method to be inlined. Hence the ALWAYS_INLINE.
ALWAYS_INLINE NodeAndIndex findTerminal ( ) const
{
size_t i = size ( ) ;
while ( i - - ) {
Node * node = at ( i ) ;
2020-08-29 09:27:11 -04:00
if ( node - > isTerminal ( ) )
2017-08-12 09:48:01 -07:00
return NodeAndIndex ( node , i ) ;
2020-08-29 09:27:11 -04:00
switch ( node - > op ( ) ) {
2017-08-12 09:48:01 -07:00
// The bitter end can contain Phantoms and the like. There will probably only be one or two nodes after the terminal. They are all no-ops and will not have any checked children.
case Check : // This is here because it's our universal no-op.
2020-08-29 09:27:11 -04:00
case CheckVarargs :
2017-08-12 09:48:01 -07:00
case Phantom :
case PhantomLocal :
case Flush :
break ;
default :
return NodeAndIndex ( ) ;
}
}
return NodeAndIndex ( ) ;
}
ALWAYS_INLINE Node * terminal ( ) const
{
return findTerminal ( ) . node ;
}
void resize ( size_t size ) { m_nodes . resize ( size ) ; }
void grow ( size_t size ) { m_nodes . grow ( size ) ; }
void append ( Node * node ) { m_nodes . append ( node ) ; }
void insertBeforeTerminal ( Node * node )
{
NodeAndIndex result = findTerminal ( ) ;
if ( ! result )
append ( node ) ;
else
m_nodes . insert ( result . index , node ) ;
}
2020-08-29 09:27:11 -04:00
void replaceTerminal ( Graph & , Node * ) ;
2017-08-12 09:48:01 -07:00
size_t numNodes ( ) const { return phis . size ( ) + size ( ) ; }
Node * node ( size_t i ) const
{
if ( i < phis . size ( ) )
return phis [ i ] ;
return at ( i - phis . size ( ) ) ;
}
bool isPhiIndex ( size_t i ) const { return i < phis . size ( ) ; }
bool isInPhis ( Node * node ) const ;
bool isInBlock ( Node * myNode ) const ;
BlockNodeList : : iterator begin ( ) { return m_nodes . begin ( ) ; }
BlockNodeList : : iterator end ( ) { return m_nodes . end ( ) ; }
unsigned numSuccessors ( ) { return terminal ( ) - > numSuccessors ( ) ; }
BasicBlock * & successor ( unsigned index )
{
return terminal ( ) - > successor ( index ) ;
}
BasicBlock * & successorForCondition ( bool condition )
{
return terminal ( ) - > successorForCondition ( condition ) ;
}
Node : : SuccessorsIterable successors ( )
{
return terminal ( ) - > successors ( ) ;
}
void removePredecessor ( BasicBlock * block ) ;
void replacePredecessor ( BasicBlock * from , BasicBlock * to ) ;
template < typename . . . Params >
Node * appendNode ( Graph & , SpeculatedType , Params . . . ) ;
template < typename . . . Params >
Node * appendNonTerminal ( Graph & , SpeculatedType , Params . . . ) ;
template < typename . . . Params >
Node * replaceTerminal ( Graph & , SpeculatedType , Params . . . ) ;
void dump ( PrintStream & out ) const ;
void didLink ( )
{
2022-10-22 19:55:20 -07:00
# if ASSERT_ENABLED
2017-08-12 09:48:01 -07:00
isLinked = true ;
# endif
}
// This value is used internally for block linking and OSR entry. It is mostly meaningless
// for other purposes due to inlining.
2022-10-22 19:55:20 -07:00
BytecodeIndex bytecodeBegin ;
2017-08-12 09:48:01 -07:00
BlockIndex index ;
2020-08-29 09:27:11 -04:00
StructureClobberState cfaStructureClobberStateAtHead ;
StructureClobberState cfaStructureClobberStateAtTail ;
BranchDirection cfaBranchDirection ;
2017-08-12 09:48:01 -07:00
bool cfaHasVisited ;
bool cfaShouldRevisit ;
2022-10-22 19:55:20 -07:00
bool cfaThinksShouldTryConstantFolding { false } ;
2017-08-12 09:48:01 -07:00
bool cfaDidFinish ;
2020-08-29 09:27:11 -04:00
bool intersectionOfCFAHasVisited ;
bool isOSRTarget ;
bool isCatchEntrypoint ;
2022-10-22 19:55:20 -07:00
# if ASSERT_ENABLED
2017-08-12 09:48:01 -07:00
bool isLinked ;
# endif
bool isReachable ;
Vector < Node * > phis ;
PredecessorList predecessors ;
Operands < Node * > variablesAtHead ;
Operands < Node * > variablesAtTail ;
Operands < AbstractValue > valuesAtHead ;
Operands < AbstractValue > valuesAtTail ;
// The intersection of assumptions we have made previously at the head of this block. Note
// that under normal circumstances, each time we run the CFA, we will get strictly more precise
// results. But we don't actually require this to be the case. It's fine for the CFA to loosen
// up for any odd reason. It's fine when this happens, because anything that the CFA proves
// must be true from that point forward, except if some registered watchpoint fires, in which
// case the code won't ever run. So, the CFA proving something less precise later on is just an
// outcome of the CFA being imperfect; the more precise thing that it had proved earlier is no
// less true.
//
// But for the purpose of OSR entry, we need to make sure that we remember what assumptions we
// had used for optimizing any given basic block. That's what this is for.
//
// It's interesting that we could use this to make the CFA more precise: all future CFAs could
// filter their results with this thing to sort of maintain maximal precision. Because we
// expect CFA to usually be monotonically more precise each time we run it to fixpoint, this
// would not be a productive optimization: it would make setting up a basic block more
// expensive and would only benefit bizarre pathological cases.
Operands < AbstractValue > intersectionOfPastValuesAtHead ;
float executionCount ;
struct SSAData {
WTF_MAKE_FAST_ALLOCATED ;
public :
void invalidate ( )
{
liveAtTail . clear ( ) ;
liveAtHead . clear ( ) ;
valuesAtHead . clear ( ) ;
valuesAtTail . clear ( ) ;
}
AvailabilityMap availabilityAtHead ;
AvailabilityMap availabilityAtTail ;
Vector < NodeFlowProjection > liveAtHead ;
Vector < NodeFlowProjection > liveAtTail ;
Vector < NodeAbstractValuePair > valuesAtHead ;
Vector < NodeAbstractValuePair > valuesAtTail ;
SSAData ( BasicBlock * ) ;
~ SSAData ( ) ;
} ;
std : : unique_ptr < SSAData > ssa ;
private :
friend class InsertionSet ;
BlockNodeList m_nodes ;
} ;
2020-08-29 09:27:11 -04:00
typedef Vector < BasicBlock * > BlockList ;
2017-08-12 09:48:01 -07:00
2022-10-22 19:55:20 -07:00
static inline BytecodeIndex getBytecodeBeginForBlock ( BasicBlock * * basicBlock )
2017-08-12 09:48:01 -07:00
{
return ( * basicBlock ) - > bytecodeBegin ;
}
2022-10-22 19:55:20 -07:00
static inline BasicBlock * blockForBytecodeIndex ( Vector < BasicBlock * > & linkingTargets , BytecodeIndex bytecodeBegin )
2017-08-12 09:48:01 -07:00
{
2022-10-22 19:55:20 -07:00
return * binarySearch < BasicBlock * , BytecodeIndex > ( linkingTargets , linkingTargets . size ( ) , bytecodeBegin , getBytecodeBeginForBlock ) ;
2017-08-12 09:48:01 -07:00
}
} } // namespace JSC::DFG
2022-10-22 19:55:20 -07:00
namespace WTF {
void printInternal ( PrintStream & , JSC : : DFG : : BasicBlock * ) ;
}
2017-08-12 09:48:01 -07:00
# endif // ENABLE(DFG_JIT)