diff --git a/js/public/GCVector.h b/js/public/GCVector.h index fafe4b4f493a..1304d2a781c0 100644 --- a/js/public/GCVector.h +++ b/js/public/GCVector.h @@ -156,6 +156,24 @@ class GCVector { } } + bool traceWeak(JSTracer* trc) { + T* src = begin(); + T* dst = begin(); + while (src != end()) { + if (GCPolicy::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() { diff --git a/js/src/debugger/Debugger.cpp b/js/src/debugger/Debugger.cpp index 770b8835485c..e0447fec3d5e 100644 --- a/js/src/debugger/Debugger.cpp +++ b/js/src/debugger/Debugger.cpp @@ -55,8 +55,9 @@ #include "gc/ZoneAllocator.h" // for ZoneAllocPolicy #include "jit/BaselineDebugModeOSR.h" // for RecompileOnStackBaselineScriptsForDebugMode #include "jit/BaselineJIT.h" // for FinishDiscardBaselineScript -#include "jit/Ion.h" // for JitContext -#include "jit/JitScript.h" // for JitScript +#include "jit/Invalidation.h" // for RecompileInfoVector +#include "jit/Ion.h" // for JitContext +#include "jit/JitScript.h" // for JitScript #include "jit/JSJitFrameIter.h" // for InlineFrameIterator #include "jit/RematerializedFrame.h" // for RematerializedFrame #include "js/Conversions.h" // for ToBoolean, ToUint32 @@ -3129,13 +3130,14 @@ static inline void MarkJitScriptActiveIfObservable( static bool AppendAndInvalidateScript(JSContext* cx, Zone* zone, JSScript* script, + jit::RecompileInfoVector& invalid, Vector& 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 diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index d4c2be390022..36b6f1de5b71 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -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" diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index af2abe24852c..da25b4d8efd3 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -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" diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index 1745c4af44d0..9764b43b0a1c 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -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; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index d5a208710106..63eb48715d7d 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -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) { diff --git a/js/src/jit/Invalidation.h b/js/src/jit/Invalidation.h new file mode 100644 index 000000000000..a4c458673a0f --- /dev/null +++ b/js/src/jit/Invalidation.h @@ -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; + +// 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 */ diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 044642152799..b649714d8b9b 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -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 diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index befc0597681a..37ea1e86fabd 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -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; diff --git a/js/src/jit/JitScript.h b/js/src/jit/JitScript.h index 54d5783ff51c..6bbf6a1f6d0f 100644 --- a/js/src/jit/JitScript.h +++ b/js/src/jit/JitScript.h @@ -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; } diff --git a/js/src/jit/JitZone.h b/js/src/jit/JitZone.h index bdbc0ce0d85d..e41e9bf0f4fc 100644 --- a/js/src/jit/JitZone.h +++ b/js/src/jit/JitZone.h @@ -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 execAlloc_; + // HashMap that maps scripts to compilations inlining those scripts. + using InlinedScriptMap = + GCHashMap, RecompileInfoVector, + MovableCellHasher>, 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 diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index 4400d3852772..60fcb68db700 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -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); } /* diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index b72808307359..62d6466b072e 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -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: diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index a73697dd9905..112f4953edfa 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -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) diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 3d64c089e04e..6cc936c99f6f 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -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 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);