Bug 1673553 part 34 - Replace JitScript's inlinedCompilations vector with a HashMap. r=iain,jonco

At this point JitScript::sweepTypes is only used to sweep the inlinedCompilations
Vector, a list of Ion/Warp compilations that inlined the script. This patch replaces
that with a HashMap per JitZone so that we can then remove the type sweeping mechanism
in the next patch.

This also moves the TI invalidation code into jit/. This can be cleaned up more later.

Differential Revision: https://phabricator.services.mozilla.com/D97579
This commit is contained in:
Jan de Mooij 2020-11-20 10:53:05 +00:00
Родитель 33fc7fee2e
Коммит b75bc546b1
15 изменённых файлов: 218 добавлений и 210 удалений

Просмотреть файл

@ -156,6 +156,24 @@ class GCVector {
} }
} }
bool traceWeak(JSTracer* trc) {
T* src = begin();
T* dst = begin();
while (src != end()) {
if (GCPolicy<T>::traceWeak(trc, src)) {
if (src != dst) {
*dst = std::move(*src);
}
dst++;
}
src++;
}
MOZ_ASSERT(dst <= end());
shrinkBy(end() - dst);
return !empty();
}
bool needsSweep() const { return !this->empty(); } bool needsSweep() const { return !this->empty(); }
void sweep() { void sweep() {

Просмотреть файл

@ -55,8 +55,9 @@
#include "gc/ZoneAllocator.h" // for ZoneAllocPolicy #include "gc/ZoneAllocator.h" // for ZoneAllocPolicy
#include "jit/BaselineDebugModeOSR.h" // for RecompileOnStackBaselineScriptsForDebugMode #include "jit/BaselineDebugModeOSR.h" // for RecompileOnStackBaselineScriptsForDebugMode
#include "jit/BaselineJIT.h" // for FinishDiscardBaselineScript #include "jit/BaselineJIT.h" // for FinishDiscardBaselineScript
#include "jit/Ion.h" // for JitContext #include "jit/Invalidation.h" // for RecompileInfoVector
#include "jit/JitScript.h" // for JitScript #include "jit/Ion.h" // for JitContext
#include "jit/JitScript.h" // for JitScript
#include "jit/JSJitFrameIter.h" // for InlineFrameIterator #include "jit/JSJitFrameIter.h" // for InlineFrameIterator
#include "jit/RematerializedFrame.h" // for RematerializedFrame #include "jit/RematerializedFrame.h" // for RematerializedFrame
#include "js/Conversions.h" // for ToBoolean, ToUint32 #include "js/Conversions.h" // for ToBoolean, ToUint32
@ -3129,13 +3130,14 @@ static inline void MarkJitScriptActiveIfObservable(
static bool AppendAndInvalidateScript(JSContext* cx, Zone* zone, static bool AppendAndInvalidateScript(JSContext* cx, Zone* zone,
JSScript* script, JSScript* script,
jit::RecompileInfoVector& invalid,
Vector<JSScript*>& scripts) { Vector<JSScript*>& scripts) {
// Enter the script's realm as addPendingRecompile attempts to // Enter the script's realm as AddPendingInvalidation attempts to
// cancel off-thread compilations, whose books are kept on the // cancel off-thread compilations, whose books are kept on the
// script's realm. // script's realm.
MOZ_ASSERT(script->zone() == zone); MOZ_ASSERT(script->zone() == zone);
AutoRealm ar(cx, script); AutoRealm ar(cx, script);
zone->types.addPendingRecompile(cx, script); AddPendingInvalidation(invalid, script);
return scripts.append(script); return scripts.append(script);
} }
@ -3153,10 +3155,10 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
// Iterate through observable scripts, invalidating their Ion scripts and // Iterate through observable scripts, invalidating their Ion scripts and
// appending them to a vector for discarding their baseline scripts later. // appending them to a vector for discarding their baseline scripts later.
{ {
AutoEnterAnalysis enter(fop, zone); RecompileInfoVector invalid;
if (JSScript* script = obs.singleScriptForZoneInvalidation()) { if (JSScript* script = obs.singleScriptForZoneInvalidation()) {
if (obs.shouldRecompileOrInvalidate(script)) { if (obs.shouldRecompileOrInvalidate(script)) {
if (!AppendAndInvalidateScript(cx, zone, script, scripts)) { if (!AppendAndInvalidateScript(cx, zone, script, invalid, scripts)) {
return false; return false;
} }
} }
@ -3168,12 +3170,13 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
} }
JSScript* script = base->asJSScript(); JSScript* script = base->asJSScript();
if (obs.shouldRecompileOrInvalidate(script)) { if (obs.shouldRecompileOrInvalidate(script)) {
if (!AppendAndInvalidateScript(cx, zone, script, scripts)) { if (!AppendAndInvalidateScript(cx, zone, script, invalid, scripts)) {
return false; return false;
} }
} }
} }
} }
Invalidate(cx, invalid);
} }
// Code below this point must be infallible to ensure the active bit of // Code below this point must be infallible to ensure the active bit of

Просмотреть файл

@ -15,6 +15,7 @@
#include "gc/PublicIterators.h" #include "gc/PublicIterators.h"
#include "jit/BaselineIC.h" #include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/Invalidation.h"
#include "jit/Ion.h" #include "jit/Ion.h"
#include "jit/JitZone.h" #include "jit/JitZone.h"
#include "vm/Runtime.h" #include "vm/Runtime.h"

Просмотреть файл

@ -13,6 +13,7 @@
#include "jit/BaselineIC.h" #include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/CalleeToken.h" #include "jit/CalleeToken.h"
#include "jit/Invalidation.h"
#include "jit/Ion.h" #include "jit/Ion.h"
#include "jit/IonScript.h" #include "jit/IonScript.h"
#include "jit/JitFrames.h" #include "jit/JitFrames.h"

Просмотреть файл

@ -9,6 +9,7 @@
#include "jit/BaselineFrame.h" #include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h" #include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/Invalidation.h"
#include "jit/Ion.h" #include "jit/Ion.h"
#include "jit/JitcodeMap.h" #include "jit/JitcodeMap.h"
#include "jit/JitFrames.h" #include "jit/JitFrames.h"
@ -463,7 +464,7 @@ static bool InvalidateScriptsInZone(JSContext* cx, Zone* zone,
// No need to cancel off-thread Ion compiles again, we already did it // No need to cancel off-thread Ion compiles again, we already did it
// above. // above.
Invalidate(zone->types, cx->runtime()->defaultFreeOp(), invalid, Invalidate(cx, invalid,
/* resetUses = */ true, /* cancelOffThread = */ false); /* resetUses = */ true, /* cancelOffThread = */ false);
return true; return true;
} }

Просмотреть файл

@ -35,6 +35,7 @@
#include "jit/BaselineCodeGen.h" #include "jit/BaselineCodeGen.h"
#include "jit/CompileInfo.h" #include "jit/CompileInfo.h"
#include "jit/InlineScriptTree.h" #include "jit/InlineScriptTree.h"
#include "jit/Invalidation.h"
#include "jit/IonIC.h" #include "jit/IonIC.h"
#include "jit/IonOptimizationLevels.h" #include "jit/IonOptimizationLevels.h"
#include "jit/IonScript.h" #include "jit/IonScript.h"
@ -43,6 +44,7 @@
#include "jit/JitRealm.h" #include "jit/JitRealm.h"
#include "jit/JitRuntime.h" #include "jit/JitRuntime.h"
#include "jit/JitSpewer.h" #include "jit/JitSpewer.h"
#include "jit/JitZone.h"
#include "jit/Linker.h" #include "jit/Linker.h"
#include "jit/Lowering.h" #include "jit/Lowering.h"
#include "jit/MIRGenerator.h" #include "jit/MIRGenerator.h"
@ -11245,13 +11247,15 @@ bool CodeGenerator::generate() {
return !masm.oom(); return !masm.oom();
} }
static bool AddInlinedCompilations(HandleScript script, static bool AddInlinedCompilations(JSContext* cx, HandleScript script,
IonCompilationId compilationId, IonCompilationId compilationId,
const WarpSnapshot* snapshot, const WarpSnapshot* snapshot,
bool* isValid) { bool* isValid) {
MOZ_ASSERT(!*isValid); MOZ_ASSERT(!*isValid);
RecompileInfo recompileInfo(script, compilationId); RecompileInfo recompileInfo(script, compilationId);
JitZone* jitZone = cx->zone()->jitZone();
for (const auto* scriptSnapshot : snapshot->scripts()) { for (const auto* scriptSnapshot : snapshot->scripts()) {
JSScript* inlinedScript = scriptSnapshot->script(); JSScript* inlinedScript = scriptSnapshot->script();
if (inlinedScript == script) { if (inlinedScript == script) {
@ -11269,9 +11273,7 @@ static bool AddInlinedCompilations(HandleScript script,
return true; return true;
} }
AutoSweepJitScript sweep(inlinedScript); if (!jitZone->addInlinedCompilation(recompileInfo, inlinedScript)) {
if (!inlinedScript->jitScript()->addInlinedCompilation(sweep,
recompileInfo)) {
return false; return false;
} }
} }
@ -11325,7 +11327,7 @@ bool CodeGenerator::link(JSContext* cx, const WarpSnapshot* snapshot) {
// If an inlined script is invalidated (for example, by attaching // If an inlined script is invalidated (for example, by attaching
// a debugger), we must also invalidate the parent IonScript. // a debugger), we must also invalidate the parent IonScript.
if (!AddInlinedCompilations(script, compilationId, snapshot, &isValid)) { if (!AddInlinedCompilations(cx, script, compilationId, snapshot, &isValid)) {
return false; return false;
} }
if (!isValid) { if (!isValid) {

59
js/src/jit/Invalidation.h Normal file
Просмотреть файл

@ -0,0 +1,59 @@
/* -*- 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/. */
#ifndef jit_Invalidation_h
#define jit_Invalidation_h
#include "jit/IonTypes.h"
#include "js/AllocPolicy.h"
#include "js/GCVector.h"
namespace js {
namespace jit {
class IonScript;
class RecompileInfo {
JSScript* script_;
IonCompilationId id_;
public:
RecompileInfo(JSScript* script, IonCompilationId id)
: script_(script), id_(id) {}
JSScript* script() const { return script_; }
IonScript* maybeIonScriptToInvalidate() const;
bool traceWeak(JSTracer* trc);
bool operator==(const RecompileInfo& other) const {
return script_ == other.script_ && id_ == other.id_;
}
};
// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a
// single IonScript doesn't require an allocation.
using RecompileInfoVector = JS::GCVector<RecompileInfo, 1, SystemAllocPolicy>;
// Called from Zone::discardJitCode().
void InvalidateAll(JSFreeOp* fop, JS::Zone* zone);
void FinishInvalidation(JSFreeOp* fop, JSScript* script);
// Add compilations involving |script| (outer script or inlined) to the vector.
void AddPendingInvalidation(jit::RecompileInfoVector& invalid,
JSScript* script);
// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(JSContext* cx, const RecompileInfoVector& invalid,
bool resetUses = true, bool cancelOffThread = true);
void Invalidate(JSContext* cx, JSScript* script, bool resetUses = true,
bool cancelOffThread = true);
} // namespace jit
} // namespace js
#endif /* jit_Invalidation_h */

Просмотреть файл

@ -31,6 +31,7 @@
#include "jit/FoldLinearArithConstants.h" #include "jit/FoldLinearArithConstants.h"
#include "jit/InlineScriptTree.h" #include "jit/InlineScriptTree.h"
#include "jit/InstructionReordering.h" #include "jit/InstructionReordering.h"
#include "jit/Invalidation.h"
#include "jit/IonAnalysis.h" #include "jit/IonAnalysis.h"
#include "jit/IonCompileTask.h" #include "jit/IonCompileTask.h"
#include "jit/IonIC.h" #include "jit/IonIC.h"
@ -451,8 +452,96 @@ void JitRealm::traceWeak(JSTracer* trc, JS::Realm* realm) {
} }
} }
bool JitZone::addInlinedCompilation(const RecompileInfo& info,
JSScript* inlined) {
MOZ_ASSERT(inlined != info.script());
auto p = inlinedCompilations_.lookupForAdd(inlined);
if (p) {
auto& compilations = p->value();
if (!compilations.empty() && compilations.back() == info) {
return true;
}
return compilations.append(info);
}
RecompileInfoVector compilations;
if (!compilations.append(info)) {
return false;
}
return inlinedCompilations_.add(p, inlined, std::move(compilations));
}
void jit::AddPendingInvalidation(RecompileInfoVector& invalid,
JSScript* script) {
MOZ_ASSERT(script);
CancelOffThreadIonCompile(script);
// Let the script warm up again before attempting another compile.
script->resetWarmUpCounterToDelayIonCompilation();
JitScript* jitScript = script->maybeJitScript();
if (!jitScript) {
return;
}
auto addPendingInvalidation = [&invalid](const RecompileInfo& info) {
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!invalid.append(info)) {
// BUG 1536159: For diagnostics, compute the size of the failed
// allocation. This presumes the vector growth strategy is to double. This
// is only used for crash reporting so not a problem if we get it wrong.
size_t allocSize = 2 * sizeof(RecompileInfo) * invalid.capacity();
oomUnsafe.crash(allocSize, "Could not update RecompileInfoVector");
}
};
// Trigger invalidation of the IonScript.
if (jitScript->hasIonScript()) {
RecompileInfo info(script, jitScript->ionScript()->compilationId());
addPendingInvalidation(info);
}
// Trigger invalidation of any callers inlining this script.
auto* inlinedCompilations =
script->zone()->jitZone()->maybeInlinedCompilations(script);
if (inlinedCompilations) {
for (const RecompileInfo& info : *inlinedCompilations) {
addPendingInvalidation(info);
}
script->zone()->jitZone()->removeInlinedCompilations(script);
}
}
IonScript* RecompileInfo::maybeIonScriptToInvalidate() const {
// Make sure this is not called under CodeGenerator::link (before the
// IonScript is created).
MOZ_ASSERT_IF(script_->zone()->types.currentCompilationId(),
script_->zone()->types.currentCompilationId().ref() != id_);
if (!script_->hasIonScript() ||
script_->ionScript()->compilationId() != id_) {
return nullptr;
}
return script_->ionScript();
}
bool RecompileInfo::traceWeak(JSTracer* trc) {
// Sweep the RecompileInfo if either the script is dead or the IonScript has
// been invalidated.
if (!TraceManuallyBarrieredWeakEdge(trc, &script_, "RecompileInfo::script")) {
return false;
}
return maybeIonScriptToInvalidate() != nullptr;
}
void JitZone::traceWeak(JSTracer* trc) { void JitZone::traceWeak(JSTracer* trc) {
baselineCacheIRStubCodes_.traceWeak(trc); baselineCacheIRStubCodes_.traceWeak(trc);
inlinedCompilations_.traceWeak(trc);
} }
size_t JitRealm::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t JitRealm::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
@ -2512,9 +2601,8 @@ static void ClearIonScriptAfterInvalidation(JSContext* cx, JSScript* script,
} }
} }
void jit::Invalidate(TypeZone& types, JSFreeOp* fop, void jit::Invalidate(JSContext* cx, const RecompileInfoVector& invalid,
const RecompileInfoVector& invalid, bool resetUses, bool resetUses, bool cancelOffThread) {
bool cancelOffThread) {
JitSpew(JitSpew_IonInvalidate, "Start invalidation."); JitSpew(JitSpew_IonInvalidate, "Start invalidation.");
// Add an invalidation reference to all invalidated IonScripts to indicate // Add an invalidation reference to all invalidated IonScripts to indicate
@ -2525,7 +2613,7 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
CancelOffThreadIonCompile(info.script()); CancelOffThreadIonCompile(info.script());
} }
IonScript* ionScript = info.maybeIonScriptToInvalidate(types); IonScript* ionScript = info.maybeIonScriptToInvalidate();
if (!ionScript) { if (!ionScript) {
continue; continue;
} }
@ -2546,7 +2634,7 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
return; return;
} }
JSContext* cx = TlsContext.get(); JSFreeOp* fop = cx->defaultFreeOp();
for (JitActivationIterator iter(cx); !iter.done(); ++iter) { for (JitActivationIterator iter(cx); !iter.done(); ++iter) {
InvalidateActivation(fop, iter, false); InvalidateActivation(fop, iter, false);
} }
@ -2555,7 +2643,7 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
// IonScript will be immediately destroyed. Otherwise, it will be held live // IonScript will be immediately destroyed. Otherwise, it will be held live
// until its last invalidated frame is destroyed. // until its last invalidated frame is destroyed.
for (const RecompileInfo& info : invalid) { for (const RecompileInfo& info : invalid) {
IonScript* ionScript = info.maybeIonScriptToInvalidate(types); IonScript* ionScript = info.maybeIonScriptToInvalidate();
if (!ionScript) { if (!ionScript) {
continue; continue;
} }
@ -2579,18 +2667,12 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
// Finally, null out jitScript->ionScript_ for IonScripts that are still on // Finally, null out jitScript->ionScript_ for IonScripts that are still on
// the stack. // the stack.
for (const RecompileInfo& info : invalid) { for (const RecompileInfo& info : invalid) {
if (IonScript* ionScript = info.maybeIonScriptToInvalidate(types)) { if (IonScript* ionScript = info.maybeIonScriptToInvalidate()) {
ClearIonScriptAfterInvalidation(cx, info.script(), ionScript, resetUses); ClearIonScriptAfterInvalidation(cx, info.script(), ionScript, resetUses);
} }
} }
} }
void jit::Invalidate(JSContext* cx, const RecompileInfoVector& invalid,
bool resetUses, bool cancelOffThread) {
jit::Invalidate(cx->zone()->types, cx->runtime()->defaultFreeOp(), invalid,
resetUses, cancelOffThread);
}
void jit::IonScript::invalidate(JSContext* cx, JSScript* script, bool resetUses, void jit::IonScript::invalidate(JSContext* cx, JSScript* script, bool resetUses,
const char* reason) { const char* reason) {
// Note: we could short circuit here if we already invalidated this // Note: we could short circuit here if we already invalidated this

Просмотреть файл

@ -66,15 +66,6 @@ MethodStatus CanEnterIon(JSContext* cx, RunState& state);
MethodStatus Recompile(JSContext* cx, HandleScript script, bool force); MethodStatus Recompile(JSContext* cx, HandleScript script, bool force);
// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(TypeZone& types, JSFreeOp* fop,
const RecompileInfoVector& invalid, bool resetUses = true,
bool cancelOffThread = true);
void Invalidate(JSContext* cx, const RecompileInfoVector& invalid,
bool resetUses = true, bool cancelOffThread = true);
void Invalidate(JSContext* cx, JSScript* script, bool resetUses = true,
bool cancelOffThread = true);
class MIRGenerator; class MIRGenerator;
class LIRGraph; class LIRGraph;
class CodeGenerator; class CodeGenerator;

Просмотреть файл

@ -245,12 +245,6 @@ class alignas(uintptr_t) JitScript final : public TrailingArray {
// analyzed by IonBuilder. This is done lazily to improve performance and // analyzed by IonBuilder. This is done lazily to improve performance and
// memory usage as most scripts are never Ion-compiled. // memory usage as most scripts are never Ion-compiled.
struct CachedIonData { struct CachedIonData {
// The freeze constraints added to stack type sets will only directly
// invalidate the script containing those stack type sets. This Vector
// contains compilations that inlined this script, so we can invalidate
// them as well.
RecompileInfoVector inlinedCompilations_;
// For functions with a call object, template objects to use for the call // For functions with a call object, template objects to use for the call
// object and decl env object (linked via the call object's enclosing // object and decl env object (linked via the call object's enclosing
// scope). // scope).
@ -343,24 +337,6 @@ class alignas(uintptr_t) JitScript final : public TrailingArray {
void setHadIonOSR() { flags_.hadIonOSR = true; } void setHadIonOSR() { flags_.hadIonOSR = true; }
bool hadIonOSR() const { return flags_.hadIonOSR; } bool hadIonOSR() const { return flags_.hadIonOSR; }
RecompileInfoVector* maybeInlinedCompilations(
const js::AutoSweepJitScript& sweep) {
MOZ_ASSERT(sweep.jitScript() == this);
if (!hasCachedIonData()) {
return nullptr;
}
return &cachedIonData().inlinedCompilations_;
}
MOZ_MUST_USE bool addInlinedCompilation(const js::AutoSweepJitScript& sweep,
RecompileInfo info) {
MOZ_ASSERT(sweep.jitScript() == this);
auto& inlinedCompilations = cachedIonData().inlinedCompilations_;
if (!inlinedCompilations.empty() && inlinedCompilations.back() == info) {
return true;
}
return inlinedCompilations.append(info);
}
uint32_t numICEntries() const { return icScript_.numICEntries(); } uint32_t numICEntries() const { return icScript_.numICEntries(); }
bool active() const { return flags_.active; } bool active() const { return flags_.active; }

Просмотреть файл

@ -19,6 +19,7 @@
#include "gc/Barrier.h" #include "gc/Barrier.h"
#include "jit/ExecutableAllocator.h" #include "jit/ExecutableAllocator.h"
#include "jit/ICStubSpace.h" #include "jit/ICStubSpace.h"
#include "jit/Invalidation.h"
#include "js/AllocPolicy.h" #include "js/AllocPolicy.h"
#include "js/GCHashTable.h" #include "js/GCHashTable.h"
#include "js/HashTable.h" #include "js/HashTable.h"
@ -98,6 +99,12 @@ class JitZone {
// Executable allocator for all code except wasm code. // Executable allocator for all code except wasm code.
MainThreadData<ExecutableAllocator> execAlloc_; MainThreadData<ExecutableAllocator> execAlloc_;
// HashMap that maps scripts to compilations inlining those scripts.
using InlinedScriptMap =
GCHashMap<WeakHeapPtr<BaseScript*>, RecompileInfoVector,
MovableCellHasher<WeakHeapPtr<BaseScript*>>, SystemAllocPolicy>;
InlinedScriptMap inlinedCompilations_;
public: public:
void traceWeak(JSTracer* trc); void traceWeak(JSTracer* trc);
@ -140,11 +147,19 @@ class JitZone {
ExecutableAllocator& execAlloc() { return execAlloc_.ref(); } ExecutableAllocator& execAlloc() { return execAlloc_.ref(); }
const ExecutableAllocator& execAlloc() const { return execAlloc_.ref(); } const ExecutableAllocator& execAlloc() const { return execAlloc_.ref(); }
};
// Called from Zone::discardJitCode(). MOZ_MUST_USE bool addInlinedCompilation(const RecompileInfo& info,
void InvalidateAll(JSFreeOp* fop, JS::Zone* zone); JSScript* inlined);
void FinishInvalidation(JSFreeOp* fop, JSScript* script);
RecompileInfoVector* maybeInlinedCompilations(JSScript* inlined) {
auto p = inlinedCompilations_.lookup(inlined);
return p ? &p->value() : nullptr;
}
void removeInlinedCompilations(JSScript* inlined) {
inlinedCompilations_.remove(inlined);
}
};
} // namespace jit } // namespace jit
} // namespace js } // namespace js

Просмотреть файл

@ -39,6 +39,7 @@
#include "frontend/StencilXdr.h" // frontend::StencilXdr::SharedData #include "frontend/StencilXdr.h" // frontend::StencilXdr::SharedData
#include "gc/FreeOp.h" #include "gc/FreeOp.h"
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/Invalidation.h"
#include "jit/Ion.h" #include "jit/Ion.h"
#include "jit/IonScript.h" #include "jit/IonScript.h"
#include "jit/JitCode.h" #include "jit/JitCode.h"
@ -4753,8 +4754,9 @@ void JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script) {
// Warp code depends on the NeedsArgsObj flag so invalidate the script // Warp code depends on the NeedsArgsObj flag so invalidate the script
// (including compilations inlining the script). // (including compilations inlining the script).
if (jit::JitOptions.warpBuilder) { if (jit::JitOptions.warpBuilder) {
AutoEnterAnalysis enter(cx->runtime()->defaultFreeOp(), script->zone()); jit::RecompileInfoVector invalid;
script->zone()->types.addPendingRecompile(cx, script); AddPendingInvalidation(invalid, script);
Invalidate(cx, invalid);
} }
/* /*

Просмотреть файл

@ -22,6 +22,7 @@
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/IonScript.h" #include "jit/IonScript.h"
#include "jit/JitScript.h" #include "jit/JitScript.h"
#include "jit/JitZone.h"
#include "js/HeapAPI.h" #include "js/HeapAPI.h"
#include "util/DiagnosticAssertions.h" #include "util/DiagnosticAssertions.h"
#include "vm/ArrayObject.h" #include "vm/ArrayObject.h"
@ -43,43 +44,6 @@
namespace js { namespace js {
/////////////////////////////////////////////////////////////////////
// RecompileInfo
/////////////////////////////////////////////////////////////////////
jit::IonScript* RecompileInfo::maybeIonScriptToInvalidate(
const TypeZone& zone) const {
MOZ_ASSERT(script_->zone() == zone.zone());
// Make sure this is not called under CodeGenerator::link (before the
// IonScript is created).
MOZ_ASSERT_IF(zone.currentCompilationId(),
zone.currentCompilationId().ref() != id_);
if (!script_->hasIonScript() ||
script_->ionScript()->compilationId() != id_) {
return nullptr;
}
return script_->ionScript();
}
inline bool RecompileInfo::shouldSweep(const TypeZone& zone) {
if (IsAboutToBeFinalizedUnbarriered(&script_)) {
return true;
}
MOZ_ASSERT(script_->zone() == zone.zone());
// Don't sweep if we're called under CodeGenerator::link, before the
// IonScript is created.
if (zone.currentCompilationId() && zone.currentCompilationId().ref() == id_) {
return false;
}
return maybeIonScriptToInvalidate(zone) == nullptr;
}
class MOZ_RAII AutoSuppressAllocationMetadataBuilder { class MOZ_RAII AutoSuppressAllocationMetadataBuilder {
JS::Zone* zone; JS::Zone* zone;
bool saved; bool saved;
@ -111,9 +75,6 @@ struct MOZ_RAII AutoEnterAnalysis {
// Prevent GC activity in the middle of analysis. // Prevent GC activity in the middle of analysis.
gc::AutoSuppressGC suppressGC; gc::AutoSuppressGC suppressGC;
// Pending recompilations to perform before execution of JIT code can resume.
RecompileInfoVector pendingRecompiles;
// Prevent us from calling the objectMetadataCallback. // Prevent us from calling the objectMetadataCallback.
js::AutoSuppressAllocationMetadataBuilder suppressMetadata; js::AutoSuppressAllocationMetadataBuilder suppressMetadata;
@ -136,10 +97,6 @@ struct MOZ_RAII AutoEnterAnalysis {
} }
zone->types.activeAnalysis = nullptr; zone->types.activeAnalysis = nullptr;
if (!pendingRecompiles.empty()) {
zone->types.processPendingRecompiles(freeOp, pendingRecompiles);
}
} }
private: private:

Просмотреть файл

@ -24,6 +24,7 @@
#include "jit/BaselineJIT.h" #include "jit/BaselineJIT.h"
#include "jit/Ion.h" #include "jit/Ion.h"
#include "jit/IonAnalysis.h" #include "jit/IonAnalysis.h"
#include "jit/JitZone.h"
#include "js/MemoryMetrics.h" #include "js/MemoryMetrics.h"
#include "js/ScalarType.h" // js::Scalar::Type #include "js/ScalarType.h" // js::Scalar::Type
#include "js/UniquePtr.h" #include "js/UniquePtr.h"
@ -61,62 +62,6 @@ bool js::ClassCanHaveExtraProperties(const JSClass* clasp) {
clasp->getOpsGetProperty() || IsTypedArrayClass(clasp); clasp->getOpsGetProperty() || IsTypedArrayClass(clasp);
} }
void TypeZone::processPendingRecompiles(JSFreeOp* fop,
RecompileInfoVector& recompiles) {
MOZ_ASSERT(!recompiles.empty());
// Steal the list of scripts to recompile, to make sure we don't try to
// recursively recompile them. Note: the move constructor will not reset the
// length if the Vector is using inline storage, so we also use clear().
RecompileInfoVector pending(std::move(recompiles));
recompiles.clear();
jit::Invalidate(*this, fop, pending);
MOZ_ASSERT(recompiles.empty());
}
void TypeZone::addPendingRecompile(JSContext* cx, const RecompileInfo& info) {
AutoEnterOOMUnsafeRegion oomUnsafe;
RecompileInfoVector& vector =
cx->zone()->types.activeAnalysis->pendingRecompiles;
if (!vector.append(info)) {
// BUG 1536159: For diagnostics, compute the size of the failed allocation.
// This presumes the vector growth strategy is to double. This is only used
// for crash reporting so not a problem if we get it wrong.
size_t allocSize = 2 * sizeof(RecompileInfo) * vector.capacity();
oomUnsafe.crash(allocSize, "Could not update pendingRecompiles");
}
}
void TypeZone::addPendingRecompile(JSContext* cx, JSScript* script) {
MOZ_ASSERT(script);
CancelOffThreadIonCompile(script);
// Let the script warm up again before attempting another compile.
script->resetWarmUpCounterToDelayIonCompilation();
if (JitScript* jitScript = script->maybeJitScript()) {
// Trigger recompilation of the IonScript.
if (jitScript->hasIonScript()) {
addPendingRecompile(
cx, RecompileInfo(script, jitScript->ionScript()->compilationId()));
}
// Trigger recompilation of any callers inlining this script.
AutoSweepJitScript sweep(script);
RecompileInfoVector* inlinedCompilations =
jitScript->maybeInlinedCompilations(sweep);
if (inlinedCompilations) {
for (const RecompileInfo& info : *inlinedCompilations) {
addPendingRecompile(cx, info);
}
inlinedCompilations->clearAndFree();
}
}
}
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// Tracing // Tracing
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@ -135,22 +80,6 @@ void JitScript::sweepTypes(const js::AutoSweepJitScript& sweep, Zone* zone) {
setTypesGeneration(zone->types.generation); setTypesGeneration(zone->types.generation);
AssertGCStateForSweep(zone); AssertGCStateForSweep(zone);
TypeZone& types = zone->types;
// Sweep the inlinedCompilations Vector.
if (maybeInlinedCompilations(sweep)) {
RecompileInfoVector& inlinedCompilations = *maybeInlinedCompilations(sweep);
size_t dest = 0;
for (size_t i = 0; i < inlinedCompilations.length(); i++) {
if (inlinedCompilations[i].shouldSweep(types)) {
continue;
}
inlinedCompilations[dest] = inlinedCompilations[i];
dest++;
}
inlinedCompilations.shrinkTo(dest);
}
} }
TypeZone::TypeZone(Zone* zone) TypeZone::TypeZone(Zone* zone)

Просмотреть файл

@ -71,29 +71,6 @@ inline bool isInlinableCall(jsbytecode* pc);
bool ClassCanHaveExtraProperties(const JSClass* clasp); bool ClassCanHaveExtraProperties(const JSClass* clasp);
class RecompileInfo {
JSScript* script_;
IonCompilationId id_;
public:
RecompileInfo(JSScript* script, IonCompilationId id)
: script_(script), id_(id) {}
JSScript* script() const { return script_; }
inline jit::IonScript* maybeIonScriptToInvalidate(const TypeZone& zone) const;
inline bool shouldSweep(const TypeZone& zone);
bool operator==(const RecompileInfo& other) const {
return script_ == other.script_ && id_ == other.id_;
}
};
// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a
// single IonScript doesn't require an allocation.
typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector;
struct AutoEnterAnalysis; struct AutoEnterAnalysis;
class TypeZone { class TypeZone {
@ -139,12 +116,6 @@ class TypeZone {
void beginSweep(); void beginSweep();
void endSweep(JSRuntime* rt); void endSweep(JSRuntime* rt);
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
void addPendingRecompile(JSContext* cx, JSScript* script);
void processPendingRecompiles(JSFreeOp* fop, RecompileInfoVector& recompiles);
bool isSweepingTypes() const { return sweepingTypes; } bool isSweepingTypes() const { return sweepingTypes; }
void setSweepingTypes(bool sweeping) { void setSweepingTypes(bool sweeping) {
MOZ_RELEASE_ASSERT(sweepingTypes != sweeping); MOZ_RELEASE_ASSERT(sweepingTypes != sweeping);