зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset ab845ce2e822 (bug 1837192) for causing spidermonkey build bustages. CLOSED TREE
This commit is contained in:
Родитель
9c7a1ae2e1
Коммит
804da488b4
|
@ -1655,12 +1655,6 @@ static void InvalidateAfterBailout(JSContext* cx, HandleScript outerScript,
|
|||
return;
|
||||
}
|
||||
|
||||
// Record a invalidation for this script in the jit hints map
|
||||
if (cx->runtime()->jitRuntime()->hasJitHintsMap()) {
|
||||
JitHintsMap* jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
|
||||
jitHints->recordInvalidation(outerScript);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!outerScript->ionScript()->invalidated());
|
||||
|
||||
JitSpew(JitSpew_BaselineBailouts, "Invalidating due to %s", reason);
|
||||
|
|
|
@ -1476,7 +1476,7 @@ bool BaselineCompilerCodeGen::emitWarmUpCounterIncrement() {
|
|||
|
||||
const OptimizationInfo* info =
|
||||
IonOptimizations.get(OptimizationLevel::Normal);
|
||||
uint32_t warmUpThreshold = info->compilerWarmUpThreshold(cx, script, pc);
|
||||
uint32_t warmUpThreshold = info->compilerWarmUpThreshold(script, pc);
|
||||
masm.branch32(Assembler::LessThan, countReg, Imm32(warmUpThreshold), &done);
|
||||
|
||||
// Don't trigger Warp compilations from trial-inlined scripts.
|
||||
|
|
|
@ -14161,12 +14161,6 @@ bool CodeGenerator::link(JSContext* cx, const WarpSnapshot* snapshot) {
|
|||
vtune::MarkScript(code, script, "ion");
|
||||
#endif
|
||||
|
||||
// Set a Ion counter hint for this script.
|
||||
if (cx->runtime()->jitRuntime()->hasJitHintsMap()) {
|
||||
JitHintsMap* jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
|
||||
jitHints->recordIonCompilation(script);
|
||||
}
|
||||
|
||||
// for marking during GC.
|
||||
if (safepointIndices_.length()) {
|
||||
ionScript->copySafepointIndices(&safepointIndices_[0]);
|
||||
|
|
|
@ -1858,7 +1858,7 @@ static MethodStatus Compile(JSContext* cx, HandleScript script,
|
|||
}
|
||||
|
||||
OptimizationLevel optimizationLevel =
|
||||
IonOptimizations.levelForScript(cx, script, osrPc);
|
||||
IonOptimizations.levelForScript(script, osrPc);
|
||||
if (optimizationLevel == OptimizationLevel::DontCompile) {
|
||||
return Method_Skipped;
|
||||
}
|
||||
|
|
|
@ -59,8 +59,7 @@ void OptimizationInfo::initWasmOptimizationInfo() {
|
|||
sink_ = false;
|
||||
}
|
||||
|
||||
uint32_t OptimizationInfo::compilerWarmUpThreshold(JSContext* cx,
|
||||
JSScript* script,
|
||||
uint32_t OptimizationInfo::compilerWarmUpThreshold(JSScript* script,
|
||||
jsbytecode* pc) const {
|
||||
MOZ_ASSERT(pc == nullptr || pc == script->code() ||
|
||||
JSOp(*pc) == JSOp::LoopHead);
|
||||
|
@ -69,21 +68,12 @@ uint32_t OptimizationInfo::compilerWarmUpThreshold(JSContext* cx,
|
|||
// wrong. See bug 1602681.
|
||||
MOZ_ASSERT_IF(pc && JSOp(*pc) == JSOp::LoopHead, pc > script->code());
|
||||
|
||||
uint32_t warmUpThreshold = baseCompilerWarmUpThreshold();
|
||||
|
||||
// If an Ion counter hint is present, override the threshold.
|
||||
if (cx->runtime()->jitRuntime()->hasJitHintsMap()) {
|
||||
JitHintsMap* jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
|
||||
uint32_t hintThreshold;
|
||||
if (jitHints->getIonThresholdHint(script, hintThreshold)) {
|
||||
warmUpThreshold = hintThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
if (pc == script->code()) {
|
||||
pc = nullptr;
|
||||
}
|
||||
|
||||
uint32_t warmUpThreshold = baseCompilerWarmUpThreshold();
|
||||
|
||||
// If the script is too large to compile on the main thread, we can still
|
||||
// compile it off thread. In these cases, increase the warm-up counter
|
||||
// threshold to improve the compilation's type information and hopefully
|
||||
|
@ -112,12 +102,11 @@ uint32_t OptimizationInfo::compilerWarmUpThreshold(JSContext* cx,
|
|||
return warmUpThreshold + loopDepth * (baseCompilerWarmUpThreshold() / 10);
|
||||
}
|
||||
|
||||
uint32_t OptimizationInfo::recompileWarmUpThreshold(JSContext* cx,
|
||||
JSScript* script,
|
||||
uint32_t OptimizationInfo::recompileWarmUpThreshold(JSScript* script,
|
||||
jsbytecode* pc) const {
|
||||
MOZ_ASSERT(pc == script->code() || JSOp(*pc) == JSOp::LoopHead);
|
||||
|
||||
uint32_t threshold = compilerWarmUpThreshold(cx, script, pc);
|
||||
uint32_t threshold = compilerWarmUpThreshold(script, pc);
|
||||
if (JSOp(*pc) != JSOp::LoopHead || JitOptions.eagerIonCompilation()) {
|
||||
return threshold;
|
||||
}
|
||||
|
@ -138,12 +127,10 @@ OptimizationLevelInfo::OptimizationLevelInfo() {
|
|||
infos_[OptimizationLevel::Wasm].initWasmOptimizationInfo();
|
||||
}
|
||||
|
||||
OptimizationLevel OptimizationLevelInfo::levelForScript(JSContext* cx,
|
||||
JSScript* script,
|
||||
OptimizationLevel OptimizationLevelInfo::levelForScript(JSScript* script,
|
||||
jsbytecode* pc) const {
|
||||
const OptimizationInfo* info = get(OptimizationLevel::Normal);
|
||||
if (script->getWarmUpCount() <
|
||||
info->compilerWarmUpThreshold(cx, script, pc)) {
|
||||
if (script->getWarmUpCount() < info->compilerWarmUpThreshold(script, pc)) {
|
||||
return OptimizationLevel::DontCompile;
|
||||
}
|
||||
|
||||
|
|
|
@ -124,11 +124,10 @@ class OptimizationInfo {
|
|||
return inlineNative_ && !JitOptions.disableInlining;
|
||||
}
|
||||
|
||||
uint32_t compilerWarmUpThreshold(JSContext* cx, JSScript* script,
|
||||
uint32_t compilerWarmUpThreshold(JSScript* script,
|
||||
jsbytecode* pc = nullptr) const;
|
||||
|
||||
uint32_t recompileWarmUpThreshold(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc) const;
|
||||
uint32_t recompileWarmUpThreshold(JSScript* script, jsbytecode* pc) const;
|
||||
|
||||
bool gvnEnabled() const { return gvn_ && !JitOptions.disableGvn; }
|
||||
|
||||
|
@ -192,7 +191,7 @@ class OptimizationLevelInfo {
|
|||
return &infos_[level];
|
||||
}
|
||||
|
||||
OptimizationLevel levelForScript(JSContext* cx, JSScript* script,
|
||||
OptimizationLevel levelForScript(JSScript* script,
|
||||
jsbytecode* pc = nullptr) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,12 +20,12 @@ inline JitHintsMap::ScriptKey JitHintsMap::getScriptKey(
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline void JitHintsMap::incrementBaselineEntryCount() {
|
||||
inline void JitHintsMap::incrementEntryCount() {
|
||||
// Clear the cache if we've exceeded the false positivity rate
|
||||
// calculated by MaxEntries.
|
||||
if (++baselineEntryCount_ > MaxEntries_) {
|
||||
baselineHintMap_.clear();
|
||||
baselineEntryCount_ = 0;
|
||||
if (++entryCount_ > MaxEntries_) {
|
||||
map_.clear();
|
||||
entryCount_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,20 +36,20 @@ inline void JitHintsMap::setEagerBaselineHint(JSScript* script) {
|
|||
}
|
||||
|
||||
// If the entry already exists, don't increment entryCount.
|
||||
if (baselineHintMap_.mightContain(key)) {
|
||||
if (map_.mightContain(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment entry count, and possibly clear the cache.
|
||||
incrementBaselineEntryCount();
|
||||
incrementEntryCount();
|
||||
|
||||
script->setNoEagerBaselineHint(false);
|
||||
baselineHintMap_.add(key);
|
||||
map_.add(key);
|
||||
}
|
||||
|
||||
inline bool JitHintsMap::mightHaveEagerBaselineHint(JSScript* script) const {
|
||||
if (ScriptKey key = getScriptKey(script)) {
|
||||
return baselineHintMap_.mightContain(key);
|
||||
return map_.mightContain(key);
|
||||
}
|
||||
script->setNoEagerBaselineHint(true);
|
||||
return false;
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/JitHints-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
JitHintsMap::~JitHintsMap() {
|
||||
while (!ionHintQueue_.isEmpty()) {
|
||||
IonHint* e = ionHintQueue_.popFirst();
|
||||
js_delete(e);
|
||||
}
|
||||
ionHintMap_.clear();
|
||||
}
|
||||
|
||||
JitHintsMap::IonHint* JitHintsMap::addIonHint(ScriptKey key,
|
||||
ScriptToHintMap::AddPtr& p) {
|
||||
if (ionHintMap_.count() >= IonHintCacheSize) {
|
||||
IonHint* h = ionHintQueue_.popFirst();
|
||||
ionHintMap_.remove(h->key());
|
||||
js_delete(h);
|
||||
}
|
||||
|
||||
IonHint* hint = js_new<IonHint>(key);
|
||||
if (!hint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ionHintMap_.add(p, key, hint)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ionHintQueue_.insertBack(hint);
|
||||
return hint;
|
||||
}
|
||||
|
||||
void JitHintsMap::updateAsRecentlyUsed(IonHint* hint) {
|
||||
hint->remove();
|
||||
ionHintQueue_.insertBack(hint);
|
||||
}
|
||||
|
||||
bool JitHintsMap::recordIonCompilation(JSScript* script) {
|
||||
ScriptKey key = getScriptKey(script);
|
||||
if (!key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto p = ionHintMap_.lookupForAdd(key);
|
||||
IonHint* hint = nullptr;
|
||||
if (p) {
|
||||
// Don't modify existing threshold values.
|
||||
hint = p->value();
|
||||
updateAsRecentlyUsed(hint);
|
||||
} else {
|
||||
hint = addIonHint(key, p);
|
||||
if (!hint) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JitHintsMap::getIonThresholdHint(JSScript* script,
|
||||
uint32_t& thresholdOut) {
|
||||
ScriptKey key = getScriptKey(script);
|
||||
if (key) {
|
||||
auto p = ionHintMap_.lookup(key);
|
||||
if (p) {
|
||||
IonHint* hint = p->value();
|
||||
updateAsRecentlyUsed(hint);
|
||||
thresholdOut = hint->threshold();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void JitHintsMap::recordInvalidation(JSScript* script) {
|
||||
ScriptKey key = getScriptKey(script);
|
||||
if (key) {
|
||||
auto p = ionHintMap_.lookup(key);
|
||||
if (p) {
|
||||
p->value()->incThreshold(InvalidationThresholdIncrement);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,102 +8,29 @@
|
|||
#define jit_JitHints_h
|
||||
|
||||
#include "mozilla/BloomFilter.h"
|
||||
#include "mozilla/HashTable.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "vm/JSScript.h"
|
||||
|
||||
namespace js::jit {
|
||||
|
||||
/*
|
||||
* The JitHintsMap implements a BitBloomFilter to track whether or not a script,
|
||||
* identified by filename+sourceStart, has been baseline compiled before in the
|
||||
* same process. This can occur frequently during navigations.
|
||||
*
|
||||
* [SMDOC] JitHintsMap
|
||||
*
|
||||
* The Jit hints map is an in process cache used to collect Baseline and Ion
|
||||
* JIT hints to try and skip as much of the warmup as possible and jump
|
||||
* straight into those tiers. Whenever a script enters one of these tiers
|
||||
* a hint is recorded in this cache using the script's filename+sourceStart
|
||||
* value, and if we ever encounter this script again later, e.g. during a
|
||||
* navigation, then we try to eagerly compile it into baseline and ion
|
||||
* based on its previous execution history.
|
||||
* The bloom filter allows us to have very efficient storage and lookup costs,
|
||||
* at the expense of occasional false positives. The number of entries added
|
||||
* to the bloom filter is monitored in order to try and keep the false
|
||||
* positivity rate below 1%. If the entry count exceeds MaxEntries_, which
|
||||
* indicates the false positivity rate may exceed 1.5%, then the filter is
|
||||
* completely cleared to reset the cache.
|
||||
*/
|
||||
|
||||
class JitHintsMap {
|
||||
// ScriptKey is a hash on the filename+sourceStart.
|
||||
using ScriptKey = HashNumber;
|
||||
ScriptKey getScriptKey(JSScript* script) const;
|
||||
|
||||
/* Ion Hints
|
||||
* -------------------------------------------------------------------------
|
||||
* This implementation uses a combination of a HashMap and PriorityQueue
|
||||
* to store a threshold value for each script that has been Ion compiled.
|
||||
* The PriorityQueue is used to track the least recently used entries so
|
||||
* that the cache does not exceed |IonHintCacheSize| entries.
|
||||
*
|
||||
* After a script has entered Ion the first time, an eager threshold hint
|
||||
* value of |JitOptions.trialInliningWarmUpThreshold+50| is set and if that
|
||||
* script is bailout invalidated, the threshold value is incremented by
|
||||
* |InvalidationThresholdIncrement| up to a maximum value of
|
||||
* |JitOptions.normalIonWarmUpThreshold|.
|
||||
*
|
||||
*/
|
||||
class IonHint : public mozilla::LinkedListElement<IonHint> {
|
||||
ScriptKey key_ = 0;
|
||||
uint32_t threshold_ = 0;
|
||||
|
||||
public:
|
||||
explicit IonHint(ScriptKey key) {
|
||||
key_ = key;
|
||||
threshold_ = IonHintEagerThresholdValue();
|
||||
}
|
||||
|
||||
uint32_t threshold() { return threshold_; }
|
||||
|
||||
void incThreshold(uint32_t inc) {
|
||||
uint32_t newThreshold = threshold() + inc;
|
||||
threshold_ = (newThreshold > JitOptions.normalIonWarmUpThreshold)
|
||||
? JitOptions.normalIonWarmUpThreshold
|
||||
: newThreshold;
|
||||
}
|
||||
|
||||
ScriptKey key() {
|
||||
MOZ_ASSERT(key_ != 0, "Should have valid key.");
|
||||
return key_;
|
||||
}
|
||||
};
|
||||
|
||||
using ScriptToHintMap =
|
||||
HashMap<ScriptKey, IonHint*, js::DefaultHasher<ScriptKey>,
|
||||
js::SystemAllocPolicy>;
|
||||
using IonHintPriorityQueue = mozilla::LinkedList<IonHint>;
|
||||
|
||||
static constexpr uint32_t InvalidationThresholdIncrement = 500;
|
||||
static constexpr uint32_t IonHintCacheSize = 5000;
|
||||
static constexpr uint32_t InitialIonHintThresholdModifier = 50;
|
||||
|
||||
static uint32_t IonHintEagerThresholdValue() {
|
||||
return JitOptions.trialInliningWarmUpThreshold +
|
||||
InitialIonHintThresholdModifier;
|
||||
}
|
||||
|
||||
ScriptToHintMap ionHintMap_;
|
||||
IonHintPriorityQueue ionHintQueue_;
|
||||
|
||||
/* Baseline Hints
|
||||
* --------------------------------------------------------------------------
|
||||
* This implementation uses a BitBloomFilter to track whether or not a script
|
||||
* has been baseline compiled before in the same process. This can occur
|
||||
* frequently during navigations.
|
||||
*
|
||||
* The bloom filter allows us to have very efficient storage and lookup costs,
|
||||
* at the expense of occasional false positives. Using a bloom filter also
|
||||
* allows us to have many more entries at minimal memory and allocation cost.
|
||||
* The number of entries added to the bloom filter is monitored in order to
|
||||
* try and keep the false positivity rate below 1%. If the entry count
|
||||
* exceeds MaxEntries_, which indicates the false positivity rate may exceed
|
||||
* 1.5%, then the filter is completely cleared to reset the cache.
|
||||
*/
|
||||
static constexpr uint32_t EagerBaselineCacheSize_ = 16;
|
||||
mozilla::BitBloomFilter<EagerBaselineCacheSize_, ScriptKey> baselineHintMap_;
|
||||
static constexpr uint32_t CacheSize_ = 16;
|
||||
mozilla::BitBloomFilter<CacheSize_, ScriptKey> map_;
|
||||
|
||||
/*
|
||||
* MaxEntries_ is the approximate entry count for which the
|
||||
|
@ -112,25 +39,17 @@ class JitHintsMap {
|
|||
* MaxEntries_ = floor(m / (-k / ln(1-exp(ln(p) / k))))
|
||||
*/
|
||||
static constexpr uint32_t MaxEntries_ = 4281;
|
||||
static_assert(EagerBaselineCacheSize_ == 16 && MaxEntries_ == 4281,
|
||||
static_assert(CacheSize_ == 16 && MaxEntries_ == 4281,
|
||||
"MaxEntries should be recalculated for given CacheSize.");
|
||||
|
||||
uint32_t baselineEntryCount_ = 0;
|
||||
void incrementBaselineEntryCount();
|
||||
uint32_t entryCount_ = 0;
|
||||
|
||||
void updateAsRecentlyUsed(IonHint* hint);
|
||||
IonHint* addIonHint(ScriptKey key, ScriptToHintMap::AddPtr& p);
|
||||
ScriptKey getScriptKey(JSScript* script) const;
|
||||
void incrementEntryCount();
|
||||
|
||||
public:
|
||||
~JitHintsMap();
|
||||
|
||||
void setEagerBaselineHint(JSScript* script);
|
||||
bool mightHaveEagerBaselineHint(JSScript* script) const;
|
||||
|
||||
bool recordIonCompilation(JSScript* script);
|
||||
bool getIonThresholdHint(JSScript* script, uint32_t& thresholdOut);
|
||||
|
||||
void recordInvalidation(JSScript* script);
|
||||
};
|
||||
|
||||
} // namespace js::jit
|
||||
|
|
|
@ -52,7 +52,6 @@ UNIFIED_SOURCES += [
|
|||
"JitcodeMap.cpp",
|
||||
"JitContext.cpp",
|
||||
"JitFrames.cpp",
|
||||
"JitHints.cpp",
|
||||
"JitOptions.cpp",
|
||||
"JitScript.cpp",
|
||||
"JitSpewer.cpp",
|
||||
|
|
Загрузка…
Ссылка в новой задаче