MarkingConstraintSet.cpp [plain text]
#include "config.h"
#include "MarkingConstraintSet.h"
#include "Options.h"
#include <wtf/TimeWithDynamicClockType.h>
namespace JSC {
class MarkingConstraintSet::ExecutionContext {
public:
ExecutionContext(MarkingConstraintSet& set, SlotVisitor& visitor, MonotonicTime timeout)
: m_set(set)
, m_visitor(visitor)
, m_timeout(timeout)
{
}
bool didVisitSomething() const
{
return m_didVisitSomething;
}
bool shouldTimeOut() const
{
return didVisitSomething() && hasElapsed(m_timeout);
}
bool drain(BitVector& unexecuted)
{
for (size_t index : unexecuted) {
execute(index);
unexecuted.clear(index);
if (shouldTimeOut())
return false;
}
return true;
}
bool didExecute(size_t index) const { return m_executed.get(index); }
void execute(size_t index)
{
m_set.m_set[index]->execute(m_visitor, m_didVisitSomething, m_timeout);
m_executed.set(index);
}
private:
MarkingConstraintSet& m_set;
SlotVisitor& m_visitor;
MonotonicTime m_timeout;
BitVector m_executed;
bool m_didVisitSomething { false };
};
MarkingConstraintSet::MarkingConstraintSet()
{
}
MarkingConstraintSet::~MarkingConstraintSet()
{
}
void MarkingConstraintSet::didStartMarking()
{
m_unexecutedRoots.clearAll();
m_unexecutedOutgrowths.clearAll();
for (auto& constraint : m_set) {
constraint->resetStats();
switch (constraint->volatility()) {
case ConstraintVolatility::GreyedByExecution:
m_unexecutedRoots.set(constraint->index());
break;
case ConstraintVolatility::GreyedByMarking:
m_unexecutedOutgrowths.set(constraint->index());
break;
case ConstraintVolatility::SeldomGreyed:
break;
}
}
m_iteration = 1;
}
void MarkingConstraintSet::add(CString abbreviatedName, CString name, Function<void(SlotVisitor&, const VisitingTimeout&)> function, ConstraintVolatility volatility)
{
add(std::make_unique<MarkingConstraint>(WTFMove(abbreviatedName), WTFMove(name), WTFMove(function), volatility));
}
void MarkingConstraintSet::add(
CString abbreviatedName, CString name,
Function<void(SlotVisitor&, const VisitingTimeout&)> executeFunction,
Function<double(SlotVisitor&)> quickWorkEstimateFunction,
ConstraintVolatility volatility)
{
add(std::make_unique<MarkingConstraint>(WTFMove(abbreviatedName), WTFMove(name), WTFMove(executeFunction), WTFMove(quickWorkEstimateFunction), volatility));
}
void MarkingConstraintSet::add(
std::unique_ptr<MarkingConstraint> constraint)
{
constraint->m_index = m_set.size();
m_ordered.append(constraint.get());
if (constraint->volatility() == ConstraintVolatility::GreyedByMarking)
m_outgrowths.append(constraint.get());
m_set.append(WTFMove(constraint));
}
bool MarkingConstraintSet::executeConvergence(SlotVisitor& visitor, MonotonicTime timeout)
{
bool result = executeConvergenceImpl(visitor, timeout);
if (Options::logGC())
dataLog(" ");
return result;
}
bool MarkingConstraintSet::isWavefrontAdvancing(SlotVisitor& visitor)
{
for (MarkingConstraint* outgrowth : m_outgrowths) {
if (outgrowth->workEstimate(visitor))
return true;
}
return false;
}
bool MarkingConstraintSet::executeConvergenceImpl(SlotVisitor& visitor, MonotonicTime timeout)
{
ExecutionContext executionContext(*this, visitor, timeout);
unsigned iteration = m_iteration++;
if (Options::logGC())
dataLog("i#", iteration, ":");
if (!executionContext.drain(m_unexecutedRoots))
return false;
if (iteration == 1)
return false;
if (!executionContext.drain(m_unexecutedOutgrowths))
return false;
bool isWavefrontAdvancing = this->isWavefrontAdvancing(visitor);
std::sort(
m_ordered.begin(), m_ordered.end(),
[&] (MarkingConstraint* a, MarkingConstraint* b) -> bool {
auto volatilityScore = [] (MarkingConstraint* constraint) -> unsigned {
return constraint->volatility() == ConstraintVolatility::GreyedByMarking ? 1 : 0;
};
unsigned aVolatilityScore = volatilityScore(a);
unsigned bVolatilityScore = volatilityScore(b);
if (aVolatilityScore != bVolatilityScore) {
if (isWavefrontAdvancing)
return aVolatilityScore > bVolatilityScore;
else
return aVolatilityScore < bVolatilityScore;
}
double aWorkEstimate = a->workEstimate(visitor);
double bWorkEstimate = b->workEstimate(visitor);
if (aWorkEstimate != bWorkEstimate)
return aWorkEstimate > bWorkEstimate;
return a->volatility() > b->volatility();
});
for (MarkingConstraint* constraint : m_ordered) {
size_t i = constraint->index();
if (executionContext.didExecute(i))
continue;
executionContext.execute(i);
if (executionContext.didVisitSomething())
return false;
}
return true;
}
void MarkingConstraintSet::executeAll(SlotVisitor& visitor)
{
bool didVisitSomething = false;
for (auto& constraint : m_set)
constraint->execute(visitor, didVisitSomething, MonotonicTime::infinity());
if (Options::logGC())
dataLog(" ");
}
}