blob: e39cac43a22612cb46a522074bc0bca7e0c83948 [file] [log] [blame]
/*
* Copyright (C) 2011, 2013, 2014 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.
*/
#ifndef DFGBasicBlock_h
#define DFGBasicBlock_h
#if ENABLE(DFG_JIT)
#include "DFGAbstractValue.h"
#include "DFGAvailability.h"
#include "DFGAvailabilityMap.h"
#include "DFGBranchDirection.h"
#include "DFGFlushedAt.h"
#include "DFGNode.h"
#include "DFGNodeOrigin.h"
#include "DFGStructureClobberState.h"
#include "Operands.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
class Graph;
class InsertionSet;
typedef Vector<BasicBlock*, 2> PredecessorList;
typedef Vector<Node*, 8> BlockNodeList;
struct BasicBlock : RefCounted<BasicBlock> {
BasicBlock(
unsigned bytecodeBegin, unsigned numArguments, unsigned numLocals,
float executionCount);
~BasicBlock();
void ensureLocals(unsigned newNumLocals);
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*& operator[](size_t i) { return at(i); }
Node* operator[](size_t i) const { return at(i); }
Node* last() const { return at(size() - 1); }
Node* takeLast() { return m_nodes.takeLast(); }
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 insertBeforeLast(Node* node)
{
append(last());
at(size() - 2) = node;
}
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(); }
Node* firstOriginNode();
NodeOrigin firstOrigin();
unsigned numSuccessors() { return last()->numSuccessors(); }
BasicBlock*& successor(unsigned index)
{
return last()->successor(index);
}
BasicBlock*& successorForCondition(bool condition)
{
return last()->successorForCondition(condition);
}
class SuccessorsIterable {
public:
SuccessorsIterable()
: m_block(nullptr)
{
}
SuccessorsIterable(BasicBlock* block)
: m_block(block)
{
}
class iterator {
public:
iterator()
: m_block(nullptr)
, m_index(UINT_MAX)
{
}
iterator(BasicBlock* block, unsigned index)
: m_block(block)
, m_index(index)
{
}
BasicBlock* operator*()
{
return m_block->successor(m_index);
}
iterator& operator++()
{
m_index++;
return *this;
}
bool operator==(const iterator& other) const
{
return m_index == other.m_index;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
BasicBlock* m_block;
unsigned m_index;
};
iterator begin()
{
return iterator(m_block, 0);
}
iterator end()
{
return iterator(m_block, m_block->numSuccessors());
}
private:
BasicBlock* m_block;
};
SuccessorsIterable successors()
{
return SuccessorsIterable(this);
}
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...);
void dump(PrintStream& out) const;
void didLink()
{
#if !ASSERT_DISABLED
isLinked = true;
#endif
}
// This value is used internally for block linking and OSR entry. It is mostly meaningless
// for other purposes due to inlining.
unsigned bytecodeBegin;
BlockIndex index;
bool isOSRTarget;
bool cfaHasVisited;
bool cfaShouldRevisit;
bool cfaFoundConstants;
bool cfaDidFinish;
StructureClobberState cfaStructureClobberStateAtHead;
StructureClobberState cfaStructureClobberStateAtTail;
BranchDirection cfaBranchDirection;
#if !ASSERT_DISABLED
bool isLinked;
#endif
bool isReachable;
Vector<Node*> phis;
PredecessorList predecessors;
Operands<Node*, NodePointerTraits> variablesAtHead;
Operands<Node*, NodePointerTraits> 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;
bool intersectionOfCFAHasVisited;
float executionCount;
// These fields are reserved for NaturalLoops.
static const unsigned numberOfInnerMostLoopIndices = 2;
unsigned innerMostLoopIndices[numberOfInnerMostLoopIndices];
struct SSAData {
AvailabilityMap availabilityAtHead;
AvailabilityMap availabilityAtTail;
HashSet<Node*> liveAtHead;
HashSet<Node*> liveAtTail;
HashMap<Node*, AbstractValue> valuesAtHead;
HashMap<Node*, AbstractValue> valuesAtTail;
SSAData(BasicBlock*);
~SSAData();
};
std::unique_ptr<SSAData> ssa;
private:
friend class InsertionSet;
BlockNodeList m_nodes;
};
typedef Vector<BasicBlock*, 5> BlockList;
struct UnlinkedBlock {
BasicBlock* m_block;
bool m_needsNormalLinking;
bool m_needsEarlyReturnLinking;
UnlinkedBlock() { }
explicit UnlinkedBlock(BasicBlock* block)
: m_block(block)
, m_needsNormalLinking(true)
, m_needsEarlyReturnLinking(false)
{
}
};
static inline unsigned getBytecodeBeginForBlock(BasicBlock** basicBlock)
{
return (*basicBlock)->bytecodeBegin;
}
static inline BasicBlock* blockForBytecodeOffset(Vector<BasicBlock*>& linkingTargets, unsigned bytecodeBegin)
{
return *binarySearch<BasicBlock*, unsigned>(linkingTargets, linkingTargets.size(), bytecodeBegin, getBytecodeBeginForBlock);
}
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
#endif // DFGBasicBlock_h