зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
33fc7fee2e
Коммит
b75bc546b1
|
@ -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(); }
|
||||
|
||||
void sweep() {
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "gc/ZoneAllocator.h" // for ZoneAllocPolicy
|
||||
#include "jit/BaselineDebugModeOSR.h" // for RecompileOnStackBaselineScriptsForDebugMode
|
||||
#include "jit/BaselineJIT.h" // for FinishDiscardBaselineScript
|
||||
#include "jit/Invalidation.h" // for RecompileInfoVector
|
||||
#include "jit/Ion.h" // for JitContext
|
||||
#include "jit/JitScript.h" // for JitScript
|
||||
#include "jit/JSJitFrameIter.h" // for InlineFrameIterator
|
||||
|
@ -3129,13 +3130,14 @@ static inline void MarkJitScriptActiveIfObservable(
|
|||
|
||||
static bool AppendAndInvalidateScript(JSContext* cx, Zone* zone,
|
||||
JSScript* script,
|
||||
jit::RecompileInfoVector& invalid,
|
||||
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
|
||||
// script's realm.
|
||||
MOZ_ASSERT(script->zone() == zone);
|
||||
AutoRealm ar(cx, script);
|
||||
zone->types.addPendingRecompile(cx, script);
|
||||
AddPendingInvalidation(invalid, script);
|
||||
return scripts.append(script);
|
||||
}
|
||||
|
||||
|
@ -3153,10 +3155,10 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
|
|||
// Iterate through observable scripts, invalidating their Ion scripts and
|
||||
// appending them to a vector for discarding their baseline scripts later.
|
||||
{
|
||||
AutoEnterAnalysis enter(fop, zone);
|
||||
RecompileInfoVector invalid;
|
||||
if (JSScript* script = obs.singleScriptForZoneInvalidation()) {
|
||||
if (obs.shouldRecompileOrInvalidate(script)) {
|
||||
if (!AppendAndInvalidateScript(cx, zone, script, scripts)) {
|
||||
if (!AppendAndInvalidateScript(cx, zone, script, invalid, scripts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3168,12 +3170,13 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
|
|||
}
|
||||
JSScript* script = base->asJSScript();
|
||||
if (obs.shouldRecompileOrInvalidate(script)) {
|
||||
if (!AppendAndInvalidateScript(cx, zone, script, scripts)) {
|
||||
if (!AppendAndInvalidateScript(cx, zone, script, invalid, scripts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Invalidate(cx, invalid);
|
||||
}
|
||||
|
||||
// Code below this point must be infallible to ensure the active bit of
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "gc/PublicIterators.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/JitZone.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/CalleeToken.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonScript.h"
|
||||
#include "jit/JitFrames.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/JitcodeMap.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
|
||||
// above.
|
||||
Invalidate(zone->types, cx->runtime()->defaultFreeOp(), invalid,
|
||||
Invalidate(cx, invalid,
|
||||
/* resetUses = */ true, /* cancelOffThread = */ false);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "jit/BaselineCodeGen.h"
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/InlineScriptTree.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/IonIC.h"
|
||||
#include "jit/IonOptimizationLevels.h"
|
||||
#include "jit/IonScript.h"
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include "jit/JitRealm.h"
|
||||
#include "jit/JitRuntime.h"
|
||||
#include "jit/JitSpewer.h"
|
||||
#include "jit/JitZone.h"
|
||||
#include "jit/Linker.h"
|
||||
#include "jit/Lowering.h"
|
||||
#include "jit/MIRGenerator.h"
|
||||
|
@ -11245,13 +11247,15 @@ bool CodeGenerator::generate() {
|
|||
return !masm.oom();
|
||||
}
|
||||
|
||||
static bool AddInlinedCompilations(HandleScript script,
|
||||
static bool AddInlinedCompilations(JSContext* cx, HandleScript script,
|
||||
IonCompilationId compilationId,
|
||||
const WarpSnapshot* snapshot,
|
||||
bool* isValid) {
|
||||
MOZ_ASSERT(!*isValid);
|
||||
RecompileInfo recompileInfo(script, compilationId);
|
||||
|
||||
JitZone* jitZone = cx->zone()->jitZone();
|
||||
|
||||
for (const auto* scriptSnapshot : snapshot->scripts()) {
|
||||
JSScript* inlinedScript = scriptSnapshot->script();
|
||||
if (inlinedScript == script) {
|
||||
|
@ -11269,9 +11273,7 @@ static bool AddInlinedCompilations(HandleScript script,
|
|||
return true;
|
||||
}
|
||||
|
||||
AutoSweepJitScript sweep(inlinedScript);
|
||||
if (!inlinedScript->jitScript()->addInlinedCompilation(sweep,
|
||||
recompileInfo)) {
|
||||
if (!jitZone->addInlinedCompilation(recompileInfo, inlinedScript)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -11325,7 +11327,7 @@ bool CodeGenerator::link(JSContext* cx, const WarpSnapshot* snapshot) {
|
|||
|
||||
// If an inlined script is invalidated (for example, by attaching
|
||||
// a debugger), we must also invalidate the parent IonScript.
|
||||
if (!AddInlinedCompilations(script, compilationId, snapshot, &isValid)) {
|
||||
if (!AddInlinedCompilations(cx, script, compilationId, snapshot, &isValid)) {
|
||||
return false;
|
||||
}
|
||||
if (!isValid) {
|
||||
|
|
|
@ -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/InlineScriptTree.h"
|
||||
#include "jit/InstructionReordering.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/IonAnalysis.h"
|
||||
#include "jit/IonCompileTask.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) {
|
||||
baselineCacheIRStubCodes_.traceWeak(trc);
|
||||
inlinedCompilations_.traceWeak(trc);
|
||||
}
|
||||
|
||||
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,
|
||||
const RecompileInfoVector& invalid, bool resetUses,
|
||||
bool cancelOffThread) {
|
||||
void jit::Invalidate(JSContext* cx, const RecompileInfoVector& invalid,
|
||||
bool resetUses, bool cancelOffThread) {
|
||||
JitSpew(JitSpew_IonInvalidate, "Start invalidation.");
|
||||
|
||||
// Add an invalidation reference to all invalidated IonScripts to indicate
|
||||
|
@ -2525,7 +2613,7 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
|
|||
CancelOffThreadIonCompile(info.script());
|
||||
}
|
||||
|
||||
IonScript* ionScript = info.maybeIonScriptToInvalidate(types);
|
||||
IonScript* ionScript = info.maybeIonScriptToInvalidate();
|
||||
if (!ionScript) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2546,7 +2634,7 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
|
|||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
JSFreeOp* fop = cx->defaultFreeOp();
|
||||
for (JitActivationIterator iter(cx); !iter.done(); ++iter) {
|
||||
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
|
||||
// until its last invalidated frame is destroyed.
|
||||
for (const RecompileInfo& info : invalid) {
|
||||
IonScript* ionScript = info.maybeIonScriptToInvalidate(types);
|
||||
IonScript* ionScript = info.maybeIonScriptToInvalidate();
|
||||
if (!ionScript) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2579,18 +2667,12 @@ void jit::Invalidate(TypeZone& types, JSFreeOp* fop,
|
|||
// Finally, null out jitScript->ionScript_ for IonScripts that are still on
|
||||
// the stack.
|
||||
for (const RecompileInfo& info : invalid) {
|
||||
if (IonScript* ionScript = info.maybeIonScriptToInvalidate(types)) {
|
||||
if (IonScript* ionScript = info.maybeIonScriptToInvalidate()) {
|
||||
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,
|
||||
const char* reason) {
|
||||
// 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);
|
||||
|
||||
// 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 LIRGraph;
|
||||
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
|
||||
// memory usage as most scripts are never Ion-compiled.
|
||||
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
|
||||
// object and decl env object (linked via the call object's enclosing
|
||||
// scope).
|
||||
|
@ -343,24 +337,6 @@ class alignas(uintptr_t) JitScript final : public TrailingArray {
|
|||
void setHadIonOSR() { flags_.hadIonOSR = true; }
|
||||
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(); }
|
||||
|
||||
bool active() const { return flags_.active; }
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "gc/Barrier.h"
|
||||
#include "jit/ExecutableAllocator.h"
|
||||
#include "jit/ICStubSpace.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "js/AllocPolicy.h"
|
||||
#include "js/GCHashTable.h"
|
||||
#include "js/HashTable.h"
|
||||
|
@ -98,6 +99,12 @@ class JitZone {
|
|||
// Executable allocator for all code except wasm code.
|
||||
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:
|
||||
void traceWeak(JSTracer* trc);
|
||||
|
||||
|
@ -140,11 +147,19 @@ class JitZone {
|
|||
|
||||
ExecutableAllocator& execAlloc() { return execAlloc_.ref(); }
|
||||
const ExecutableAllocator& execAlloc() const { return execAlloc_.ref(); }
|
||||
};
|
||||
|
||||
// Called from Zone::discardJitCode().
|
||||
void InvalidateAll(JSFreeOp* fop, JS::Zone* zone);
|
||||
void FinishInvalidation(JSFreeOp* fop, JSScript* script);
|
||||
MOZ_MUST_USE bool addInlinedCompilation(const RecompileInfo& info,
|
||||
JSScript* inlined);
|
||||
|
||||
RecompileInfoVector* maybeInlinedCompilations(JSScript* inlined) {
|
||||
auto p = inlinedCompilations_.lookup(inlined);
|
||||
return p ? &p->value() : nullptr;
|
||||
}
|
||||
|
||||
void removeInlinedCompilations(JSScript* inlined) {
|
||||
inlinedCompilations_.remove(inlined);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "frontend/StencilXdr.h" // frontend::StencilXdr::SharedData
|
||||
#include "gc/FreeOp.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Invalidation.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonScript.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
|
||||
// (including compilations inlining the script).
|
||||
if (jit::JitOptions.warpBuilder) {
|
||||
AutoEnterAnalysis enter(cx->runtime()->defaultFreeOp(), script->zone());
|
||||
script->zone()->types.addPendingRecompile(cx, script);
|
||||
jit::RecompileInfoVector invalid;
|
||||
AddPendingInvalidation(invalid, script);
|
||||
Invalidate(cx, invalid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/IonScript.h"
|
||||
#include "jit/JitScript.h"
|
||||
#include "jit/JitZone.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "util/DiagnosticAssertions.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
|
@ -43,43 +44,6 @@
|
|||
|
||||
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 {
|
||||
JS::Zone* zone;
|
||||
bool saved;
|
||||
|
@ -111,9 +75,6 @@ struct MOZ_RAII AutoEnterAnalysis {
|
|||
// Prevent GC activity in the middle of analysis.
|
||||
gc::AutoSuppressGC suppressGC;
|
||||
|
||||
// Pending recompilations to perform before execution of JIT code can resume.
|
||||
RecompileInfoVector pendingRecompiles;
|
||||
|
||||
// Prevent us from calling the objectMetadataCallback.
|
||||
js::AutoSuppressAllocationMetadataBuilder suppressMetadata;
|
||||
|
||||
|
@ -136,10 +97,6 @@ struct MOZ_RAII AutoEnterAnalysis {
|
|||
}
|
||||
|
||||
zone->types.activeAnalysis = nullptr;
|
||||
|
||||
if (!pendingRecompiles.empty()) {
|
||||
zone->types.processPendingRecompiles(freeOp, pendingRecompiles);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonAnalysis.h"
|
||||
#include "jit/JitZone.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "js/UniquePtr.h"
|
||||
|
@ -61,62 +62,6 @@ bool js::ClassCanHaveExtraProperties(const JSClass* 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
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -135,22 +80,6 @@ void JitScript::sweepTypes(const js::AutoSweepJitScript& sweep, Zone* zone) {
|
|||
setTypesGeneration(zone->types.generation);
|
||||
|
||||
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)
|
||||
|
|
|
@ -71,29 +71,6 @@ inline bool isInlinableCall(jsbytecode* pc);
|
|||
|
||||
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;
|
||||
|
||||
class TypeZone {
|
||||
|
@ -139,12 +116,6 @@ class TypeZone {
|
|||
void beginSweep();
|
||||
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; }
|
||||
void setSweepingTypes(bool sweeping) {
|
||||
MOZ_RELEASE_ASSERT(sweepingTypes != sweeping);
|
||||
|
|
Загрузка…
Ссылка в новой задаче