mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-04-12 20:08:13 +00:00
174 lines
6.3 KiB
C++
174 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) 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. 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 INC. 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.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "DFGStoreBarrierClusteringPhase.h"
|
|
|
|
#if ENABLE(DFG_JIT)
|
|
|
|
#include "DFGDoesGC.h"
|
|
#include "DFGGraph.h"
|
|
#include "DFGInsertionSet.h"
|
|
#include "DFGMayExit.h"
|
|
#include "DFGPhase.h"
|
|
#include "JSCJSValueInlines.h"
|
|
#include <wtf/FastBitVector.h>
|
|
|
|
namespace JSC { namespace DFG {
|
|
|
|
namespace {
|
|
|
|
class StoreBarrierClusteringPhase : public Phase {
|
|
public:
|
|
StoreBarrierClusteringPhase(Graph& graph)
|
|
: Phase(graph, "store barrier fencing")
|
|
, m_insertionSet(graph)
|
|
{
|
|
}
|
|
|
|
bool run()
|
|
{
|
|
size_t maxSize = 0;
|
|
for (BasicBlock* block : m_graph.blocksInNaturalOrder())
|
|
maxSize = std::max(maxSize, block->size());
|
|
m_barrierPoints.resize(maxSize);
|
|
|
|
for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
|
|
size_t blockSize = block->size();
|
|
doBlock(block);
|
|
m_barrierPoints.clearRange(0, blockSize);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
// This summarizes everything we need to remember about a barrier.
|
|
struct ChildAndOrigin {
|
|
ChildAndOrigin() { }
|
|
|
|
ChildAndOrigin(Node* child, CodeOrigin semanticOrigin)
|
|
: child(child)
|
|
, semanticOrigin(semanticOrigin)
|
|
{
|
|
}
|
|
|
|
Node* child { nullptr };
|
|
CodeOrigin semanticOrigin;
|
|
};
|
|
|
|
void doBlock(BasicBlock* block)
|
|
{
|
|
ASSERT(m_barrierPoints.isEmpty());
|
|
|
|
// First identify the places where we would want to place all of the barriers based on a
|
|
// backwards analysis. We use the futureGC flag to tell us if we had seen a GC. Since this
|
|
// is a backwards analysis, when we get to a node, futureGC tells us if a GC will happen
|
|
// in the future after that node.
|
|
bool futureGC = true;
|
|
for (unsigned nodeIndex = block->size(); nodeIndex--;) {
|
|
Node* node = block->at(nodeIndex);
|
|
|
|
// This is a backwards analysis, so exits require conservatism. If we exit, then there
|
|
// probably will be a GC in the future! If we needed to then we could lift that
|
|
// requirement by either (1) having a StoreBarrierHint that tells OSR exit to barrier that
|
|
// value or (2) automatically barriering any DFG-live Node on OSR exit. Either way, it
|
|
// would be weird because it would create a new root for OSR availability analysis. I
|
|
// don't have evidence that it would be worth it.
|
|
if (doesGC(m_graph, node) || mayExit(m_graph, node) != DoesNotExit) {
|
|
futureGC = true;
|
|
continue;
|
|
}
|
|
|
|
if (node->isStoreBarrier() && futureGC) {
|
|
m_barrierPoints[nodeIndex] = true;
|
|
futureGC = false;
|
|
}
|
|
}
|
|
|
|
// Now we run forward and collect the barriers. When we hit a barrier point, insert all of
|
|
// them with a fence.
|
|
for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
|
|
Node* node = block->at(nodeIndex);
|
|
if (!node->isStoreBarrier())
|
|
continue;
|
|
|
|
DFG_ASSERT(m_graph, node, !node->origin.wasHoisted);
|
|
DFG_ASSERT(m_graph, node, node->child1().useKind() == KnownCellUse, node->op(), node->child1().useKind());
|
|
|
|
NodeOrigin origin = node->origin;
|
|
m_neededBarriers.append(ChildAndOrigin(node->child1().node(), origin.semantic));
|
|
node->remove(m_graph);
|
|
|
|
if (!m_barrierPoints[nodeIndex])
|
|
continue;
|
|
|
|
std::sort(
|
|
m_neededBarriers.begin(), m_neededBarriers.end(),
|
|
[&] (const ChildAndOrigin& a, const ChildAndOrigin& b) -> bool {
|
|
return a.child < b.child;
|
|
});
|
|
removeRepeatedElements(
|
|
m_neededBarriers,
|
|
[&] (const ChildAndOrigin& a, const ChildAndOrigin& b) -> bool{
|
|
return a.child == b.child;
|
|
});
|
|
for (auto iter = m_neededBarriers.begin(); iter != m_neededBarriers.end(); ++iter) {
|
|
Node* child = iter->child;
|
|
CodeOrigin semanticOrigin = iter->semanticOrigin;
|
|
|
|
NodeType type;
|
|
if (iter == m_neededBarriers.begin())
|
|
type = FencedStoreBarrier;
|
|
else
|
|
type = StoreBarrier;
|
|
|
|
m_insertionSet.insertNode(
|
|
nodeIndex, SpecNone, type, origin.withSemantic(semanticOrigin),
|
|
Edge(child, KnownCellUse));
|
|
}
|
|
m_neededBarriers.shrink(0);
|
|
}
|
|
|
|
m_insertionSet.execute(block);
|
|
}
|
|
|
|
InsertionSet m_insertionSet;
|
|
FastBitVector m_barrierPoints;
|
|
Vector<ChildAndOrigin> m_neededBarriers;
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
bool performStoreBarrierClustering(Graph& graph)
|
|
{
|
|
return runPhase<StoreBarrierClusteringPhase>(graph);
|
|
}
|
|
|
|
} } // namespace JSC::DFG
|
|
|
|
#endif // ENABLE(DFG_JIT)
|
|
|