Bug 1353359 part 4 - Use BindName IC in Ion and remove the old IonCache infrastructure. r=evilpie
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 14 Apr 2017 12:29:15 +0200
changeset 401308 c57012db4d11038ef44faf1aec1005eea5ea2438
parent 401307 a74790bf48bdf65890512ebde152b35803b3c063
child 401309 9379831bb9c3d9abfea7dbf8dd06dbdab1d81dc4
child 401388 20e85b5bd3429c3e7386b56fe6c6056d52219eb0
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie
bugs1353359
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1353359 part 4 - Use BindName IC in Ion and remove the old IonCache infrastructure. r=evilpie
js/src/gc/Verifier.cpp
js/src/gc/Zone.cpp
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jit/IonCacheIRCompiler.cpp
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/IonCode.h
js/src/jit/IonIC.cpp
js/src/jit/IonIC.h
js/src/jit/Lowering.cpp
js/src/jit/shared/CodeGenerator-shared.h
js/src/jit/shared/LIR-shared.h
js/src/jsgc.cpp
js/src/jsgc.h
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -241,17 +241,16 @@ gc::GCRuntime::startVerifyPreBarriers()
     }
 
     verifyPreData = trc;
     incrementalState = State::Mark;
     marker.start();
 
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         MOZ_ASSERT(!zone->usedByHelperThread());
-        PurgeJITCaches(zone);
         zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
         zone->arenas.purge();
     }
 
     return;
 
 oom:
     incrementalState = State::NotActive;
@@ -337,17 +336,16 @@ gc::GCRuntime::endVerifyPreBarriers()
     bool compartmentCreated = false;
 
     /* We need to disable barriers before tracing, which may invoke barriers. */
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         if (!zone->needsIncrementalBarrier())
             compartmentCreated = true;
 
         zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
-        PurgeJITCaches(zone);
     }
 
     /*
      * We need to bump gcNumber so that the methodjit knows that jitcode has
      * been discarded.
      */
     MOZ_ASSERT(trc->number == number);
     number++;
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -187,79 +187,77 @@ Zone::sweepWeakMaps()
 }
 
 void
 Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode)
 {
     if (!jitZone())
         return;
 
-    if (isPreservingCode()) {
-        PurgeJITCaches(this);
-    } else {
+    if (isPreservingCode())
+        return;
 
-        if (discardBaselineCode) {
+    if (discardBaselineCode) {
 #ifdef DEBUG
-            /* Assert no baseline scripts are marked as active. */
-            for (auto script = cellIter<JSScript>(); !script.done(); script.next())
-                MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
+        /* Assert no baseline scripts are marked as active. */
+        for (auto script = cellIter<JSScript>(); !script.done(); script.next())
+            MOZ_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active());
 #endif
 
-            /* Mark baseline scripts on the stack as active. */
-            jit::MarkActiveBaselineScripts(this);
-        }
+        /* Mark baseline scripts on the stack as active. */
+        jit::MarkActiveBaselineScripts(this);
+    }
 
-        /* Only mark OSI points if code is being discarded. */
-        jit::InvalidateAll(fop, this);
+    /* Only mark OSI points if code is being discarded. */
+    jit::InvalidateAll(fop, this);
 
-        for (auto script = cellIter<JSScript>(); !script.done(); script.next())  {
-            jit::FinishInvalidation(fop, script);
+    for (auto script = cellIter<JSScript>(); !script.done(); script.next())  {
+        jit::FinishInvalidation(fop, script);
 
-            /*
-             * Discard baseline script if it's not marked as active. Note that
-             * this also resets the active flag.
-             */
-            if (discardBaselineCode)
-                jit::FinishDiscardBaselineScript(fop, script);
+        /*
+         * Discard baseline script if it's not marked as active. Note that
+         * this also resets the active flag.
+         */
+        if (discardBaselineCode)
+            jit::FinishDiscardBaselineScript(fop, script);
 
-            /*
-             * Warm-up counter for scripts are reset on GC. After discarding code we
-             * need to let it warm back up to get information such as which
-             * opcodes are setting array holes or accessing getter properties.
-             */
-            script->resetWarmUpCounter();
-
-            /*
-             * Make it impossible to use the control flow graphs cached on the
-             * BaselineScript. They get deleted.
-             */
-            if (script->hasBaselineScript())
-                script->baselineScript()->setControlFlowGraph(nullptr);
-        }
+        /*
+         * Warm-up counter for scripts are reset on GC. After discarding code we
+         * need to let it warm back up to get information such as which
+         * opcodes are setting array holes or accessing getter properties.
+         */
+        script->resetWarmUpCounter();
 
         /*
-         * When scripts contains pointers to nursery things, the store buffer
-         * can contain entries that point into the optimized stub space. Since
-         * this method can be called outside the context of a GC, this situation
-         * could result in us trying to mark invalid store buffer entries.
-         *
-         * Defer freeing any allocated blocks until after the next minor GC.
+         * Make it impossible to use the control flow graphs cached on the
+         * BaselineScript. They get deleted.
          */
-        if (discardBaselineCode) {
-            jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this);
-            jitZone()->purgeIonCacheIRStubInfo();
-        }
+        if (script->hasBaselineScript())
+            script->baselineScript()->setControlFlowGraph(nullptr);
+    }
 
-        /*
-         * Free all control flow graphs that are cached on BaselineScripts.
-         * Assuming this happens on the active thread and all control flow
-         * graph reads happen on the active thread, this is safe.
-         */
-        jitZone()->cfgSpace()->lifoAlloc().freeAll();
+    /*
+     * When scripts contains pointers to nursery things, the store buffer
+     * can contain entries that point into the optimized stub space. Since
+     * this method can be called outside the context of a GC, this situation
+     * could result in us trying to mark invalid store buffer entries.
+     *
+     * Defer freeing any allocated blocks until after the next minor GC.
+     */
+    if (discardBaselineCode) {
+        jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(this);
+        jitZone()->purgeIonCacheIRStubInfo();
     }
+
+    /*
+     * Free all control flow graphs that are cached on BaselineScripts.
+     * Assuming this happens on the active thread and all control flow
+     * graph reads happen on the active thread, this is safe.
+     */
+    jitZone()->cfgSpace()->lifoAlloc().freeAll();
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 void
 JS::Zone::checkUniqueIdTableAfterMovingGC()
 {
     for (UniqueIdMap::Enum e(uniqueIds()); !e.empty(); e.popFront())
         js::gc::CheckGCThingAfterMovingGC(e.front().key());
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -2113,17 +2113,17 @@ bool
 CacheIRCompiler::emitLoadObjectResult()
 {
     AutoOutputRegister output(*this);
     Register obj = allocator.useRegister(masm, reader.objOperandId());
 
     if (output.hasValue())
         masm.tagValue(JSVAL_TYPE_OBJECT, obj, output.valueReg());
     else
-        MOZ_CRASH("NYI: Typed LoadObjectResult");
+        masm.mov(obj, output.typedReg().gpr());
 
     return true;
 }
 
 void
 CacheIRCompiler::emitStoreTypedObjectReferenceProp(ValueOperand val, ReferenceTypeDescr::Type type,
                                                    const Address& dest, Register scratch)
 {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -65,63 +65,16 @@ using mozilla::FloatingPoint;
 using mozilla::Maybe;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 using JS::GenericNaN;
 
 namespace js {
 namespace jit {
 
-// This out-of-line cache is used to do a double dispatch including it-self and
-// the wrapped IonCache.
-class OutOfLineUpdateCache :
-  public OutOfLineCodeBase<CodeGenerator>,
-  public IonCacheVisitor
-{
-  private:
-    LInstruction* lir_;
-    size_t cacheIndex_;
-    RepatchLabel entry_;
-
-  public:
-    OutOfLineUpdateCache(LInstruction* lir, size_t cacheIndex)
-      : lir_(lir),
-        cacheIndex_(cacheIndex)
-    { }
-
-    void bind(MacroAssembler* masm) {
-        // The binding of the initial jump is done in
-        // CodeGenerator::visitOutOfLineCache.
-    }
-
-    size_t getCacheIndex() const {
-        return cacheIndex_;
-    }
-    LInstruction* lir() const {
-        return lir_;
-    }
-    RepatchLabel& entry() {
-        return entry_;
-    }
-
-    void accept(CodeGenerator* codegen) {
-        codegen->visitOutOfLineCache(this);
-    }
-
-    // ICs' visit functions delegating the work to the CodeGen visit funtions.
-#define VISIT_CACHE_FUNCTION(op)                                        \
-    void visit##op##IC(CodeGenerator* codegen) {                        \
-        CodeGenerator::DataPtr<op##IC> ic(codegen, getCacheIndex());    \
-        codegen->visit##op##IC(this, ic);                        \
-    }
-
-    IONCACHE_KIND_LIST(VISIT_CACHE_FUNCTION)
-#undef VISIT_CACHE_FUNCTION
-};
-
 class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
 {
   private:
     LInstruction* lir_;
     size_t cacheIndex_;
     size_t cacheInfoIndex_;
 
   public:
@@ -146,43 +99,16 @@ class OutOfLineICFallback : public OutOf
         return lir_;
     }
 
     void accept(CodeGenerator* codegen) {
         codegen->visitOutOfLineICFallback(this);
     }
 };
 
-// This function is declared here because it needs to instantiate an
-// OutOfLineUpdateCache, but we want to keep it visible inside the
-// CodeGeneratorShared such as we can specialize inline caches in function of
-// the architecture.
-void
-CodeGeneratorShared::addCache(LInstruction* lir, size_t cacheIndex)
-{
-    if (cacheIndex == SIZE_MAX) {
-        masm.setOOM();
-        return;
-    }
-
-    DataPtr<IonCache> cache(this, cacheIndex);
-    MInstruction* mir = lir->mirRaw()->toInstruction();
-    if (mir->resumePoint())
-        cache->setScriptedLocation(mir->block()->info().script(),
-                                   mir->resumePoint()->pc());
-    else
-        cache->setIdempotent();
-
-    OutOfLineUpdateCache* ool = new(alloc()) OutOfLineUpdateCache(lir, cacheIndex);
-    addOutOfLineCode(ool, mir);
-
-    cache->emitInitialJump(masm, ool->entry());
-    masm.bind(ool->rejoin());
-}
-
 void
 CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
 {
     if (cacheIndex == SIZE_MAX) {
         masm.setOOM();
         return;
     }
 
@@ -203,29 +129,16 @@ CodeGeneratorShared::addIC(LInstruction*
 
     OutOfLineICFallback* ool = new(alloc()) OutOfLineICFallback(lir, cacheIndex, icInfo_.length() - 1);
     addOutOfLineCode(ool, mir);
 
     masm.bind(ool->rejoin());
     cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset()));
 }
 
-void
-CodeGenerator::visitOutOfLineCache(OutOfLineUpdateCache* ool)
-{
-    DataPtr<IonCache> cache(this, ool->getCacheIndex());
-
-    // Register the location of the OOL path in the IC.
-    cache->setFallbackLabel(masm.labelForPatch());
-    masm.bind(&ool->entry());
-
-    // Dispatch to ICs' accept functions.
-    cache->accept(this, ool);
-}
-
 typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue,
                                    MutableHandleValue);
 static const VMFunction IonGetPropertyICInfo =
     FunctionInfo<IonGetPropertyICFn>(IonGetPropertyIC::update, "IonGetPropertyIC::update");
 
 typedef bool (*IonSetPropertyICFn)(JSContext*, HandleScript, IonSetPropertyIC*, HandleObject,
                                    HandleValue, HandleValue);
 static const VMFunction IonSetPropertyICInfo =
@@ -236,16 +149,20 @@ typedef bool (*IonGetNameICFn)(JSContext
 static const VMFunction IonGetNameICInfo =
     FunctionInfo<IonGetNameICFn>(IonGetNameIC::update, "IonGetNameIC::update");
 
 typedef bool (*IonHasOwnICFn)(JSContext*, HandleScript, IonHasOwnIC*, HandleValue, HandleValue,
                               int32_t*);
 static const VMFunction IonHasOwnICInfo =
     FunctionInfo<IonHasOwnICFn>(IonHasOwnIC::update, "IonHasOwnIC::update");
 
+typedef JSObject* (*IonBindNameICFn)(JSContext*, HandleScript, IonBindNameIC*, HandleObject);
+static const VMFunction IonBindNameICInfo =
+    FunctionInfo<IonBindNameICFn>(IonBindNameIC::update, "IonBindNameIC::update");
+
 void
 CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
 {
     LInstruction* lir = ool->lir();
     size_t cacheIndex = ool->cacheIndex();
     size_t cacheInfoIndex = ool->cacheInfoIndex();
 
     DataPtr<IonIC> ic(this, cacheIndex);
@@ -304,18 +221,34 @@ CodeGenerator::visitOutOfLineICFallback(
         callVM(IonGetNameICInfo, lir);
 
         StoreValueTo(getNameIC->output()).generate(this);
         restoreLiveIgnore(lir, StoreValueTo(getNameIC->output()).clobbered());
 
         masm.jump(ool->rejoin());
         return;
       }
+      case CacheKind::BindName: {
+        IonBindNameIC* bindNameIC = ic->asBindNameIC();
+
+        saveLive(lir);
+
+        pushArg(bindNameIC->environment());
+        icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
+        pushArg(ImmGCPtr(gen->info().script()));
+
+        callVM(IonBindNameICInfo, lir);
+
+        StoreRegisterTo(bindNameIC->output()).generate(this);
+        restoreLiveIgnore(lir, StoreRegisterTo(bindNameIC->output()).clobbered());
+
+        masm.jump(ool->rejoin());
+        return;
+      }
       case CacheKind::In:
-      case CacheKind::BindName:
         MOZ_CRASH("Baseline-specific for now");
       case CacheKind::HasOwn: {
         IonHasOwnIC* hasOwnIC = ic->asHasOwnIC();
 
         saveLive(lir);
 
         pushArg(hasOwnIC->id());
         pushArg(hasOwnIC->value());
@@ -9621,17 +9554,16 @@ CodeGenerator::generateWasm(wasm::SigIdD
     MOZ_ASSERT(!masm.failureLabel()->used());
     MOZ_ASSERT(snapshots_.listSize() == 0);
     MOZ_ASSERT(snapshots_.RVATableSize() == 0);
     MOZ_ASSERT(recovers_.size() == 0);
     MOZ_ASSERT(bailouts_.empty());
     MOZ_ASSERT(graph.numConstants() == 0);
     MOZ_ASSERT(safepointIndices_.empty());
     MOZ_ASSERT(osiIndices_.empty());
-    MOZ_ASSERT(cacheList_.empty());
     MOZ_ASSERT(icList_.empty());
     MOZ_ASSERT(safepoints_.size() == 0);
     MOZ_ASSERT(!scriptCounts_);
     return true;
 }
 
 bool
 CodeGenerator::generate()
@@ -9843,17 +9775,17 @@ CodeGenerator::link(JSContext* cx, Compi
         return false;
 
     IonScript* ionScript =
         IonScript::New(cx, recompileInfo,
                        graph.totalSlotCount(), argumentSlots, scriptFrameSize,
                        snapshots_.listSize(), snapshots_.RVATableSize(),
                        recovers_.size(), bailouts_.length(), graph.numConstants(),
                        safepointIndices_.length(), osiIndices_.length(),
-                       cacheList_.length(), icList_.length(), runtimeData_.length(),
+                       icList_.length(), runtimeData_.length(),
                        safepoints_.size(), patchableBackedges_.length(),
                        sharedStubs_.length(), optimizationLevel);
     if (!ionScript)
         return false;
     auto guardIonScript = mozilla::MakeScopeExit([&ionScript] {
         // Use js_free instead of IonScript::Destroy: the cache list and
         // backedge list are still uninitialized.
         js_free(ionScript);
@@ -10008,18 +9940,16 @@ CodeGenerator::link(JSContext* cx, Compi
         MOZ_ASSERT(entry.firstStub()->isFallback());
 
         entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
     }
 
     // for generating inline caches during the execution.
     if (runtimeData_.length())
         ionScript->copyRuntimeData(&runtimeData_[0]);
-    if (cacheList_.length())
-        ionScript->copyCacheEntries(&cacheList_[0], masm);
     if (icList_.length())
         ionScript->copyICEntries(&icList_[0], masm);
 
     for (size_t i = 0; i < icInfo_.length(); i++) {
         IonIC& ic = ionScript->getICFromIndex(i);
         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForJump),
                                            ImmPtr(ic.codeRawPtr()),
                                            ImmPtr((void*)-1));
@@ -10407,42 +10337,23 @@ CodeGenerator::visitGetPropertyCacheT(LG
 
     addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
                         ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
 }
 
 void
 CodeGenerator::visitBindNameCache(LBindNameCache* ins)
 {
+    LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register envChain = ToRegister(ins->environmentChain());
     Register output = ToRegister(ins->output());
-    BindNameIC cache(envChain, ins->mir()->name(), output);
-    cache.setProfilerLeavePC(ins->mir()->profilerLeavePc());
-
-    addCache(ins, allocateCache(cache));
-}
-
-typedef JSObject* (*BindNameICFn)(JSContext*, HandleScript, size_t, HandleObject);
-const VMFunction BindNameIC::UpdateInfo =
-    FunctionInfo<BindNameICFn>(BindNameIC::update, "BindNameIC::update");
-
-void
-CodeGenerator::visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr<BindNameIC>& ic)
-{
-    LInstruction* lir = ool->lir();
-    saveLive(lir);
-
-    pushArg(ic->environmentChainReg());
-    pushArg(Imm32(ool->getCacheIndex()));
-    pushArg(ImmGCPtr(gen->info().script()));
-    callVM(BindNameIC::UpdateInfo, lir);
-    StoreRegisterTo(ic->outputReg()).generate(this);
-    restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
-
-    masm.jump(ool->rejoin());
+    Register temp = ToRegister(ins->temp());
+
+    IonBindNameIC ic(liveRegs, envChain, output, temp);
+    addIC(ins, allocateIC(ic));
 }
 
 void
 CodeGenerator::visitHasOwnCache(LHasOwnCache* ins)
 {
     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
     TypedOrValueRegister value =
         toConstantOrRegister(ins, LHasOwnCache::Value, ins->mir()->value()->type()).reg();
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -407,30 +407,26 @@ class CodeGenerator final : public CodeG
 
     void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir);
     void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool);
     void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool);
 
     void loadJSScriptForBlock(MBasicBlock* block, Register reg);
     void loadOutermostJSScript(Register reg);
 
-    // Inline caches visitors.
-    void visitOutOfLineCache(OutOfLineUpdateCache* ool);
     void visitOutOfLineICFallback(OutOfLineICFallback* ool);
 
     void visitGetPropertyCacheV(LGetPropertyCacheV* ins);
     void visitGetPropertyCacheT(LGetPropertyCacheT* ins);
     void visitBindNameCache(LBindNameCache* ins);
     void visitCallSetProperty(LInstruction* ins);
     void visitSetPropertyCache(LSetPropertyCache* ins);
     void visitGetNameCache(LGetNameCache* ins);
     void visitHasOwnCache(LHasOwnCache* ins);
 
-    void visitBindNameIC(OutOfLineUpdateCache* ool, DataPtr<BindNameIC>& ic);
-
     void visitAssertRangeI(LAssertRangeI* ins);
     void visitAssertRangeD(LAssertRangeD* ins);
     void visitAssertRangeF(LAssertRangeF* ins);
     void visitAssertRangeV(LAssertRangeV* ins);
 
     void visitAssertResultV(LAssertResultV* ins);
     void visitAssertResultT(LAssertResultT* ins);
     void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -854,18 +854,16 @@ IonScript::IonScript()
     skipArgCheckEntryOffset_(0),
     invalidateEpilogueOffset_(0),
     invalidateEpilogueDataOffset_(0),
     numBailouts_(0),
     hasProfilingInstrumentation_(false),
     recompiling_(false),
     runtimeData_(0),
     runtimeSize_(0),
-    cacheIndex_(0),
-    cacheEntries_(0),
     icIndex_(0),
     icEntries_(0),
     safepointIndexOffset_(0),
     safepointIndexEntries_(0),
     safepointsStart_(0),
     safepointsSize_(0),
     frameSlots_(0),
     frameSize_(0),
@@ -888,17 +886,17 @@ IonScript::IonScript()
 }
 
 IonScript*
 IonScript::New(JSContext* cx, RecompileInfo recompileInfo,
                uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
                size_t snapshotsListSize, size_t snapshotsRVATableSize,
                size_t recoversSize, size_t bailoutEntries,
                size_t constants, size_t safepointIndices,
-               size_t osiIndices, size_t cacheEntries, size_t icEntries,
+               size_t osiIndices, size_t icEntries,
                size_t runtimeSize,  size_t safepointsSize,
                size_t backedgeEntries, size_t sharedStubEntries,
                OptimizationLevel optimizationLevel)
 {
     constexpr size_t DataAlignment = sizeof(void*);
 
     if (snapshotsListSize >= MAX_BUFFER_SIZE ||
         (bailoutEntries >= MAX_BUFFER_SIZE / sizeof(uint32_t)))
@@ -911,50 +909,44 @@ IonScript::New(JSContext* cx, RecompileI
     // *somewhere* and if their total overflowed there would be no memory left
     // at all.
     size_t paddedSnapshotsSize = AlignBytes(snapshotsListSize + snapshotsRVATableSize, DataAlignment);
     size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
     size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
     size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
     size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
     size_t paddedOsiIndicesSize = AlignBytes(osiIndices * sizeof(OsiIndex), DataAlignment);
-    size_t paddedCacheEntriesSize = AlignBytes(cacheEntries * sizeof(uint32_t), DataAlignment);
     size_t paddedICEntriesSize = AlignBytes(icEntries * sizeof(uint32_t), DataAlignment);
     size_t paddedRuntimeSize = AlignBytes(runtimeSize, DataAlignment);
     size_t paddedSafepointSize = AlignBytes(safepointsSize, DataAlignment);
     size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
     size_t paddedSharedStubSize = AlignBytes(sharedStubEntries * sizeof(IonICEntry), DataAlignment);
 
     size_t bytes = paddedSnapshotsSize +
                    paddedRecoversSize +
                    paddedBailoutSize +
                    paddedConstantsSize +
                    paddedSafepointIndicesSize +
                    paddedOsiIndicesSize +
-                   paddedCacheEntriesSize +
                    paddedICEntriesSize +
                    paddedRuntimeSize +
                    paddedSafepointSize +
                    paddedBackedgeSize +
                    paddedSharedStubSize;
     IonScript* script = cx->zone()->pod_malloc_with_extra<IonScript, uint8_t>(bytes);
     if (!script)
         return nullptr;
     new (script) IonScript();
 
     uint32_t offsetCursor = sizeof(IonScript);
 
     script->runtimeData_ = offsetCursor;
     script->runtimeSize_ = runtimeSize;
     offsetCursor += paddedRuntimeSize;
 
-    script->cacheIndex_ = offsetCursor;
-    script->cacheEntries_ = cacheEntries;
-    offsetCursor += paddedCacheEntriesSize;
-
     script->icIndex_ = offsetCursor;
     script->icEntries_ = icEntries;
     offsetCursor += paddedICEntriesSize;
 
     script->safepointIndexOffset_ = offsetCursor;
     script->safepointIndexEntries_ = safepointIndices;
     offsetCursor += paddedSafepointIndicesSize;
 
@@ -1023,19 +1015,16 @@ IonScript::trace(JSTracer* trc)
 
     // Mark all IC stub codes hanging off the IC stub entries.
     for (size_t i = 0; i < numSharedStubs(); i++) {
         IonICEntry& ent = sharedStubList()[i];
         ent.trace(trc);
     }
 
     // Trace caches so that the JSScript pointer can be updated if moved.
-    for (size_t i = 0; i < numCaches(); i++)
-        getCacheFromIndex(i).trace(trc);
-
     for (size_t i = 0; i < numICs(); i++)
         getICFromIndex(i).trace(trc);
 }
 
 /* static */ void
 IonScript::writeBarrierPre(Zone* zone, IonScript* ionScript)
 {
     if (zone->needsIncrementalBarrier())
@@ -1129,28 +1118,16 @@ IonScript::copyOsiIndices(const OsiIndex
 
 void
 IonScript::copyRuntimeData(const uint8_t* data)
 {
     memcpy(runtimeData(), data, runtimeSize());
 }
 
 void
-IonScript::copyCacheEntries(const uint32_t* caches, MacroAssembler& masm)
-{
-    memcpy(cacheIndex(), caches, numCaches() * sizeof(uint32_t));
-
-    // Jumps in the caches reflect the offset of those jumps in the compiled
-    // code, not the absolute positions of the jumps. Update according to the
-    // final code address now.
-    for (size_t i = 0; i < numCaches(); i++)
-        getCacheFromIndex(i).updateBaseAddress(method_, masm);
-}
-
-void
 IonScript::copyICEntries(const uint32_t* icEntries, MacroAssembler& masm)
 {
     memcpy(icIndex(), icEntries, numICs() * sizeof(uint32_t));
 
     // Jumps in the caches reflect the offset of those jumps in the compiled
     // code, not the absolute positions of the jumps. Update according to the
     // final code address now.
     for (size_t i = 0; i < numICs(); i++)
@@ -1327,35 +1304,16 @@ IonScript::purgeOptimizedStubs(Zone* zon
             MOZ_ASSERT(stub->allocatedInFallbackSpace());
             stub = stub->next();
         }
     }
 #endif
 }
 
 void
-IonScript::purgeCaches()
-{
-    // Don't reset any ICs if we're invalidated, otherwise, repointing the
-    // inline jump could overwrite an invalidation marker. These ICs can
-    // no longer run, however, the IC slow paths may be active on the stack.
-    // ICs therefore are required to check for invalidation before patching,
-    // to ensure the same invariant.
-    if (invalidated())
-        return;
-
-    if (numCaches() == 0)
-        return;
-
-    AutoWritableJitCode awjc(method());
-    for (size_t i = 0; i < numCaches(); i++)
-        getCacheFromIndex(i).reset(DontReprotect);
-}
-
-void
 IonScript::purgeICs(Zone* zone)
 {
     for (size_t i = 0; i < numICs(); i++)
         getICFromIndex(i).reset(zone);
 }
 
 void
 IonScript::unlinkFromRuntime(FreeOp* fop)
@@ -3117,17 +3075,16 @@ InvalidateActivation(FreeOp* fop, const 
         if (!invalidateAll && !script->ionScript()->invalidated())
             continue;
 
         IonScript* ionScript = script->ionScript();
 
         // Purge ICs before we mark this script as invalidated. This will
         // prevent lastJump_ from appearing to be a bogus pointer, just
         // in case anyone tries to read it.
-        ionScript->purgeCaches();
         ionScript->purgeICs(script->zone());
         ionScript->purgeOptimizedStubs(script->zone());
 
         // Clean up any pointers from elsewhere in the runtime to this IonScript
         // which is about to become disconnected from its JSScript.
         ionScript->unlinkFromRuntime(fop);
 
         // This frame needs to be invalidated. We do the following:
@@ -3526,23 +3483,16 @@ AutoFlushICache::~AutoFlushICache()
         ExecutableAllocator::cacheFlush((void*)start_, size_t(stop_ - start_));
 
     JitSpewCont(JitSpew_CacheFlush, "%s%s>", name_, start_ ? "" : " U");
     JitSpewFin(JitSpew_CacheFlush);
     cx->setAutoFlushICache(prev_);
 #endif
 }
 
-void
-jit::PurgeCaches(JSScript* script)
-{
-    if (script->hasIonScript())
-        script->ionScript()->purgeCaches();
-}
-
 size_t
 jit::SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t result = 0;
 
     if (script->hasIonScript())
         result += script->ionScript()->sizeOfIncludingThis(mallocSizeOf);
 
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -209,17 +209,16 @@ NumLocalsAndArgs(JSScript* script)
         num += fun->nargs();
     return num;
 }
 
 bool OffThreadCompilationAvailable(JSContext* cx);
 
 void ForbidCompilation(JSContext* cx, JSScript* script);
 
-void PurgeCaches(JSScript* script);
 size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf);
 void DestroyJitScripts(FreeOp* fop, JSScript* script);
 void TraceJitScripts(JSTracer* trc, JSScript* script);
 
 bool JitSupportsFloatingPoint();
 bool JitSupportsUnalignedAccesses();
 bool JitSupportsSimd();
 bool JitSupportsAtomics();
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -421,18 +421,31 @@ IonCacheIRCompiler::init()
 
         liveRegs_.emplace(ic->liveRegs());
         outputUnchecked_.emplace(output);
 
         MOZ_ASSERT(numInputs == 1);
         allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT);
         break;
       }
+      case CacheKind::BindName: {
+        IonBindNameIC* ic = ic_->asBindNameIC();
+        Register output = ic->output();
+
+        available.add(output);
+        available.add(ic->temp());
+
+        liveRegs_.emplace(ic->liveRegs());
+        outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Object, AnyRegister(output)));
+
+        MOZ_ASSERT(numInputs == 1);
+        allocator.initInputLocation(0, ic->environment(), JSVAL_TYPE_OBJECT);
+        break;
+      }
       case CacheKind::In:
-      case CacheKind::BindName:
         MOZ_CRASH("Invalid cache");
       case CacheKind::HasOwn: {
         IonHasOwnIC* ic = ic_->asHasOwnIC();
         Register output = ic->output();
 
         available.add(output);
 
         liveRegs_.emplace(ic->liveRegs());
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -33,18 +33,16 @@
 #include "vm/Interpreter-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::tl::FloorLog2;
 
-typedef Rooted<TypedArrayObject*> RootedTypedArrayObject;
-
 void
 CodeLocationJump::repoint(JitCode* code, MacroAssembler* masm)
 {
     MOZ_ASSERT(state_ == Relative);
     size_t new_off = (size_t)raw_;
 #ifdef JS_SMALL_BRANCH
     size_t jumpTableEntryOffset = reinterpret_cast<size_t>(jumpTableEntry_);
 #endif
@@ -84,318 +82,16 @@ CodeLocationLabel::repoint(JitCode* code
 void
 CodeOffsetJump::fixup(MacroAssembler* masm)
 {
 #ifdef JS_SMALL_BRANCH
      jumpTableIndex_ = masm->actualIndex(jumpTableIndex_);
 #endif
 }
 
-const char*
-IonCache::CacheName(IonCache::Kind kind)
-{
-    static const char * const names[] =
-    {
-#define NAME(x) #x,
-        IONCACHE_KIND_LIST(NAME)
-#undef NAME
-    };
-    return names[kind];
-}
-
-const size_t IonCache::MAX_STUBS = 16;
-
-// Helper class which encapsulates logic to attach a stub to an IC by hooking
-// up rejoins and next stub jumps.
-//
-// The simplest stubs have a single jump to the next stub and look like the
-// following:
-//
-//    branch guard NEXTSTUB
-//    ... IC-specific code ...
-//    jump REJOIN
-//
-// This corresponds to:
-//
-//    attacher.branchNextStub(masm, ...);
-//    ... emit IC-specific code ...
-//    attacher.jumpRejoin(masm);
-//
-// Whether the stub needs multiple next stub jumps look like:
-//
-//   branch guard FAILURES
-//   ... IC-specific code ...
-//   branch another-guard FAILURES
-//   ... IC-specific code ...
-//   jump REJOIN
-//   FAILURES:
-//   jump NEXTSTUB
-//
-// This corresponds to:
-//
-//   Label failures;
-//   masm.branchX(..., &failures);
-//   ... emit IC-specific code ...
-//   masm.branchY(..., failures);
-//   ... emit more IC-specific code ...
-//   attacher.jumpRejoin(masm);
-//   masm.bind(&failures);
-//   attacher.jumpNextStub(masm);
-//
-// A convenience function |branchNextStubOrLabel| is provided in the case that
-// the stub sometimes has multiple next stub jumps and sometimes a single
-// one. If a non-nullptr label is passed in, a |branchPtr| will be made to
-// that label instead of a |branchPtrWithPatch| to the next stub.
-class IonCache::StubAttacher
-{
-  protected:
-    bool hasNextStubOffset_ : 1;
-    bool hasStubCodePatchOffset_ : 1;
-
-    IonCache& cache_;
-
-    CodeLocationLabel rejoinLabel_;
-    CodeOffsetJump nextStubOffset_;
-    CodeOffsetJump rejoinOffset_;
-    CodeOffset stubCodePatchOffset_;
-
-  public:
-    explicit StubAttacher(IonCache& cache)
-      : hasNextStubOffset_(false),
-        hasStubCodePatchOffset_(false),
-        cache_(cache),
-        rejoinLabel_(cache.rejoinLabel_),
-        nextStubOffset_(),
-        rejoinOffset_(),
-        stubCodePatchOffset_()
-    { }
-
-    // Value used instead of the JitCode self-reference of generated
-    // stubs. This value is needed for marking calls made inside stubs. This
-    // value would be replaced by the attachStub function after the allocation
-    // of the JitCode. The self-reference is used to keep the stub path alive
-    // even if the IonScript is invalidated or if the IC is flushed.
-    static const void* const STUB_ADDR;
-
-    template <class T1, class T2>
-    void branchNextStub(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2) {
-        MOZ_ASSERT(!hasNextStubOffset_);
-        RepatchLabel nextStub;
-        nextStubOffset_ = masm.branchPtrWithPatch(cond, op1, op2, &nextStub);
-        hasNextStubOffset_ = true;
-        masm.bind(&nextStub);
-    }
-
-    template <class T1, class T2>
-    void branchNextStubOrLabel(MacroAssembler& masm, Assembler::Condition cond, T1 op1, T2 op2,
-                               Label* label)
-    {
-        if (label != nullptr)
-            masm.branchPtr(cond, op1, op2, label);
-        else
-            branchNextStub(masm, cond, op1, op2);
-    }
-
-    void jumpRejoin(MacroAssembler& masm) {
-        RepatchLabel rejoin;
-        rejoinOffset_ = masm.jumpWithPatch(&rejoin);
-        masm.bind(&rejoin);
-    }
-
-    void jumpNextStub(MacroAssembler& masm) {
-        MOZ_ASSERT(!hasNextStubOffset_);
-        RepatchLabel nextStub;
-        nextStubOffset_ = masm.jumpWithPatch(&nextStub);
-        hasNextStubOffset_ = true;
-        masm.bind(&nextStub);
-    }
-
-    void pushStubCodePointer(MacroAssembler& masm) {
-        // Push the JitCode pointer for the stub we're generating.
-        // WARNING:
-        // WARNING: If JitCode ever becomes relocatable, the following code is incorrect.
-        // WARNING: Note that we're not marking the pointer being pushed as an ImmGCPtr.
-        // WARNING: This location will be patched with the pointer of the generated stub,
-        // WARNING: such as it can be marked when a call is made with this stub. Be aware
-        // WARNING: that ICs are not marked and so this stub will only be kept alive iff
-        // WARNING: it is on the stack at the time of the GC. No ImmGCPtr is needed as the
-        // WARNING: stubs are flushed on GC.
-        // WARNING:
-        MOZ_ASSERT(!hasStubCodePatchOffset_);
-        stubCodePatchOffset_ = masm.PushWithPatch(ImmPtr(STUB_ADDR));
-        hasStubCodePatchOffset_ = true;
-    }
-
-    void patchRejoinJump(MacroAssembler& masm, JitCode* code) {
-        rejoinOffset_.fixup(&masm);
-        CodeLocationJump rejoinJump(code, rejoinOffset_);
-        PatchJump(rejoinJump, rejoinLabel_);
-    }
-
-    void patchStubCodePointer(JitCode* code) {
-        if (hasStubCodePatchOffset_) {
-            Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, stubCodePatchOffset_),
-                                               ImmPtr(code), ImmPtr(STUB_ADDR));
-        }
-    }
-
-    void patchNextStubJump(MacroAssembler& masm, JitCode* code) {
-        // If this path is not taken, we are producing an entry which can no
-        // longer go back into the update function.
-        if (hasNextStubOffset_) {
-            nextStubOffset_.fixup(&masm);
-            CodeLocationJump nextStubJump(code, nextStubOffset_);
-            PatchJump(nextStubJump, cache_.fallbackLabel_);
-
-            // When the last stub fails, it fallback to the ool call which can
-            // produce a stub. Next time we generate a stub, we will patch the
-            // nextStub jump to try the new stub.
-            cache_.lastJump_ = nextStubJump;
-        }
-    }
-};
-
-const void* const IonCache::StubAttacher::STUB_ADDR = (void*)0xdeadc0de;
-
-void
-IonCache::emitInitialJump(MacroAssembler& masm, RepatchLabel& entry)
-{
-    initialJump_ = masm.jumpWithPatch(&entry);
-    lastJump_ = initialJump_;
-    Label label;
-    masm.bind(&label);
-    rejoinLabel_ = CodeOffset(label.offset());
-}
-
-void
-IonCache::attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
-                     Handle<JitCode*> code)
-{
-    MOZ_ASSERT(canAttachStub());
-    incrementStubCount();
-
-    // Patch the previous nextStubJump of the last stub, or the jump from the
-    // codeGen, to jump into the newly allocated code.
-    PatchJump(lastJump, CodeLocationLabel(code), Reprotect);
-}
-
-IonCache::LinkStatus
-IonCache::linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
-                   JitCode** code)
-{
-    Linker linker(masm);
-    *code = linker.newCode<CanGC>(cx, ION_CODE);
-    if (!*code)
-        return LINK_ERROR;
-
-    if (ion->invalidated())
-        return CACHE_FLUSHED;
-
-    // Update the success path to continue after the IC initial jump.
-    attacher.patchRejoinJump(masm, *code);
-
-    // Replace the STUB_ADDR constant by the address of the generated stub, such
-    // as it can be kept alive even if the cache is flushed (see
-    // MarkJitExitFrame).
-    attacher.patchStubCodePointer(*code);
-
-    // Update the failure path.
-    attacher.patchNextStubJump(masm, *code);
-
-    return LINK_GOOD;
-}
-
-bool
-IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher,
-                            IonScript* ion, const char* attachKind,
-                            JS::TrackedOutcome trackedOutcome)
-{
-    CodeLocationJump lastJumpBefore = lastJump_;
-    Rooted<JitCode*> code(cx);
-    {
-        // Need to exit the AutoFlushICache context to flush the cache
-        // before attaching the stub below.
-        AutoFlushICache afc("IonCache");
-        LinkStatus status = linkCode(cx, masm, attacher, ion, code.address());
-        if (status != LINK_GOOD)
-            return status != LINK_ERROR;
-    }
-
-    if (pc_) {
-        JitSpew(JitSpew_IonIC, "Cache %p(%s:%" PRIuSIZE "/%" PRIuSIZE ") generated %s %s stub at %p",
-                this, script_->filename(), script_->lineno(), script_->pcToOffset(pc_),
-                attachKind, CacheName(kind()), code->raw());
-    } else {
-        JitSpew(JitSpew_IonIC, "Cache %p generated %s %s stub at %p",
-                this, attachKind, CacheName(kind()), code->raw());
-    }
-
-#ifdef JS_ION_PERF
-    writePerfSpewerJitCodeProfile(code, "IonCache");
-#endif
-
-    attachStub(masm, attacher, lastJumpBefore, code);
-
-    // Add entry to native => bytecode mapping for this stub if needed.
-    if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
-        JitcodeGlobalEntry::IonCacheEntry entry;
-        entry.init(code, code->raw(), code->rawEnd(), rejoinAddress(), trackedOutcome);
-
-        // Add entry to the global table.
-        JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
-        if (!globalTable->addEntry(entry, cx->runtime())) {
-            entry.destroy();
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        // Mark the jitcode as having a bytecode map.
-        code->setHasBytecodeMap();
-    } else {
-        JitcodeGlobalEntry::DummyEntry entry;
-        entry.init(code, code->raw(), code->rawEnd());
-
-        // Add entry to the global table.
-        JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
-        if (!globalTable->addEntry(entry, cx->runtime())) {
-            entry.destroy();
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        // Mark the jitcode as having a bytecode map.
-        code->setHasBytecodeMap();
-    }
-
-    // Report masm OOM errors here, so all our callers can:
-    // return linkAndAttachStub(...);
-    if (masm.oom()) {
-        ReportOutOfMemory(cx);
-        return false;
-    }
-
-    return true;
-}
-
-void
-IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm)
-{
-    fallbackLabel_.repoint(code, &masm);
-    initialJump_.repoint(code, &masm);
-    lastJump_.repoint(code, &masm);
-    rejoinLabel_.repoint(code, &masm);
-}
-
-void
-IonCache::trace(JSTracer* trc)
-{
-    if (script_)
-        TraceManuallyBarrieredEdge(trc, &script_, "IonCache::script_");
-}
-
 void*
 jit::GetReturnAddressToIonCode(JSContext* cx)
 {
     JitFrameIterator iter(cx);
     MOZ_ASSERT(iter.type() == JitFrame_Exit,
                "An exit frame is expected as update functions are called with a VMFunction.");
 
     void* returnAddr = iter.returnAddress();
@@ -518,31 +214,16 @@ jit::ValueToNameOrSymbolId(JSContext* cx
         id.set(JSID_VOID);
         return true;
     }
 
     *nameOrSymbol = true;
     return true;
 }
 
-void
-IonCache::disable()
-{
-    reset(Reprotect);
-    this->disabled_ = 1;
-}
-
-void
-IonCache::reset(ReprotectCode reprotect)
-{
-    this->stubCount_ = 0;
-    PatchJump(initialJump_, fallbackLabel_, reprotect);
-    lastJump_ = initialJump_;
-}
-
 bool
 jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
 {
     if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
         return false;
 
     if (!shape->hasSetterValue())
         return false;
@@ -637,176 +318,8 @@ jit::EmitIonStoreDenseElement(MacroAssem
     } else {
         MOZ_ASSERT(reg.type() == MIRType::Int32);
         masm.convertInt32ToDouble(reg.typedReg().gpr(), ScratchDoubleReg);
         masm.storeDouble(ScratchDoubleReg, target);
     }
 
     masm.bind(&done);
 }
-
-bool
-BindNameIC::attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
-                         HandleObject envChain)
-{
-    MOZ_ASSERT(envChain->is<GlobalObject>());
-
-    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
-    StubAttacher attacher(*this);
-
-    // Guard on the env chain.
-    attacher.branchNextStub(masm, Assembler::NotEqual, environmentChainReg(),
-                            ImmGCPtr(envChain));
-    masm.movePtr(ImmGCPtr(envChain), outputReg());
-
-    attacher.jumpRejoin(masm);
-
-    return linkAndAttachStub(cx, masm, attacher, ion, "global");
-}
-
-static inline void
-GenerateEnvironmentChainGuard(MacroAssembler& masm, JSObject* envObj,
-                              Register envObjReg, Shape* shape, Label* failures)
-{
-    if (envObj->is<CallObject>()) {
-        // We can skip a guard on the call object if the script's bindings are
-        // guaranteed to be immutable (and thus cannot introduce shadowing
-        // variables).
-        CallObject* callObj = &envObj->as<CallObject>();
-        JSFunction* fun = &callObj->callee();
-        // The function might have been relazified under rare conditions.
-        // In that case, we pessimistically create the guard, as we'd
-        // need to root various pointers to delazify,
-        if (fun->hasScript()) {
-            JSScript* script = fun->nonLazyScript();
-            if (!script->funHasExtensibleScope())
-                return;
-        }
-    } else if (envObj->is<GlobalObject>()) {
-        // If this is the last object on the scope walk, and the property we've
-        // found is not configurable, then we don't need a shape guard because
-        // the shape cannot be removed.
-        if (shape && !shape->configurable())
-            return;
-    }
-
-    Address shapeAddr(envObjReg, ShapedObject::offsetOfShape());
-    masm.branchPtr(Assembler::NotEqual, shapeAddr,
-                   ImmGCPtr(envObj->as<NativeObject>().lastProperty()), failures);
-}
-
-static void
-GenerateEnvironmentChainGuards(MacroAssembler& masm, JSObject* envChain, JSObject* holder,
-                               Register outputReg, Label* failures, bool skipLastGuard = false)
-{
-    JSObject* tobj = envChain;
-
-    // Walk up the env chain. Note that IsCacheableEnvironmentChain guarantees the
-    // |tobj == holder| condition terminates the loop.
-    while (true) {
-        MOZ_ASSERT(IsCacheableEnvironment(tobj) || tobj->is<GlobalObject>());
-
-        if (skipLastGuard && tobj == holder)
-            break;
-
-        GenerateEnvironmentChainGuard(masm, tobj, outputReg, nullptr, failures);
-
-        if (tobj == holder)
-            break;
-
-        // Load the next link.
-        tobj = &tobj->as<EnvironmentObject>().enclosingEnvironment();
-        masm.extractObject(Address(outputReg, EnvironmentObject::offsetOfEnclosingEnvironment()),
-                           outputReg);
-    }
-}
-
-bool
-BindNameIC::attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
-                            HandleObject envChain, HandleObject holder)
-{
-    MOZ_ASSERT(IsCacheableEnvironment(envChain));
-
-    MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
-    StubAttacher attacher(*this);
-
-    // Guard on the shape of the env chain.
-    Label failures;
-    attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
-                                   Address(environmentChainReg(), ShapedObject::offsetOfShape()),
-                                   ImmGCPtr(envChain->as<NativeObject>().lastProperty()),
-                                   holder != envChain ? &failures : nullptr);
-
-    if (holder != envChain) {
-        JSObject* parent = &envChain->as<EnvironmentObject>().enclosingEnvironment();
-        masm.extractObject(Address(environmentChainReg(),
-                                   EnvironmentObject::offsetOfEnclosingEnvironment()),
-                           outputReg());
-
-        GenerateEnvironmentChainGuards(masm, parent, holder, outputReg(), &failures);
-    } else {
-        masm.movePtr(environmentChainReg(), outputReg());
-    }
-
-    // At this point outputReg holds the object on which the property
-    // was found, so we're done.
-    attacher.jumpRejoin(masm);
-
-    // All failures flow to here, so there is a common point to patch.
-    if (holder != envChain) {
-        masm.bind(&failures);
-        attacher.jumpNextStub(masm);
-    }
-
-    return linkAndAttachStub(cx, masm, attacher, ion, "non-global");
-}
-
-static bool
-IsCacheableNonGlobalEnvironmentChain(JSObject* envChain, JSObject* holder)
-{
-    while (true) {
-        if (!IsCacheableEnvironment(envChain)) {
-            JitSpew(JitSpew_IonIC, "Non-cacheable object on env chain");
-            return false;
-        }
-
-        if (envChain == holder)
-            return true;
-
-        envChain = &envChain->as<EnvironmentObject>().enclosingEnvironment();
-        if (!envChain) {
-            JitSpew(JitSpew_IonIC, "env chain indirect hit");
-            return false;
-        }
-    }
-
-    MOZ_CRASH("Invalid env chain");
-}
-
-JSObject*
-BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
-                   HandleObject envChain)
-{
-    IonScript* ion = outerScript->ionScript();
-    BindNameIC& cache = ion->getCache(cacheIndex).toBindName();
-    HandlePropertyName name = cache.name();
-
-    RootedObject holder(cx);
-    if (!LookupNameUnqualified(cx, name, envChain, &holder))
-        return nullptr;
-
-    // Stop generating new stubs once we hit the stub count limit, see
-    // GetPropertyCache.
-    if (cache.canAttachStub()) {
-        if (envChain->is<GlobalObject>()) {
-            if (!cache.attachGlobal(cx, outerScript, ion, envChain))
-                return nullptr;
-        } else if (IsCacheableNonGlobalEnvironmentChain(envChain, holder)) {
-            if (!cache.attachNonGlobal(cx, outerScript, ion, envChain, holder))
-                return nullptr;
-        } else {
-            JitSpew(JitSpew_IonIC, "BINDNAME uncacheable env chain");
-        }
-    }
-
-    return holder;
-}
-
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -21,402 +21,16 @@
 #include "jit/shared/Assembler-shared.h"
 #include "js/TrackedOptimizationInfo.h"
 
 #include "vm/TypedArrayObject.h"
 
 namespace js {
 namespace jit {
 
-class LInstruction;
-
-#define IONCACHE_KIND_LIST(_)                                   \
-    _(BindName)
-
-// Forward declarations of Cache kinds.
-#define FORWARD_DECLARE(kind) class kind##IC;
-IONCACHE_KIND_LIST(FORWARD_DECLARE)
-#undef FORWARD_DECLARE
-
-class IonCacheVisitor
-{
-  public:
-#define VISIT_INS(op)                                               \
-    virtual void visit##op##IC(CodeGenerator* codegen) {            \
-        MOZ_CRASH("NYI: " #op "IC");                                \
-    }
-
-    IONCACHE_KIND_LIST(VISIT_INS)
-#undef VISIT_INS
-};
-
-// Common structure encoding the state of a polymorphic inline cache contained
-// in the code for an IonScript. IonCaches are used for polymorphic operations
-// where multiple implementations may be required.
-//
-// Roughly speaking, the cache initially jumps to an out of line fragment
-// which invokes a cache function to perform the operation. The cache function
-// may generate a stub to perform the operation in certain cases (e.g. a
-// particular shape for an input object) and attach the stub to existing
-// stubs, forming a daisy chain of tests for how to perform the operation in
-// different circumstances.
-//
-// Eventually, if too many stubs are generated the cache function may disable
-// the cache, by generating a stub to make a call and perform the operation
-// within the VM.
-//
-// The caches initially generate a patchable jump to an out of line call
-// to the cache function. Stubs are attached by appending: when attaching a
-// new stub, we patch the any failure conditions in last generated stub to
-// jump to the new stub. Failure conditions in the new stub jump to the cache
-// function which may generate new stubs.
-//
-//        Control flow               Pointers
-//      =======#                 ----.     .---->
-//             #                     |     |
-//             #======>              \-----/
-//
-// Initial state:
-//
-//  JIT Code
-// +--------+   .---------------.
-// |        |   |               |
-// |========|   v +----------+  |
-// |== IC ==|====>| Cache Fn |  |
-// |========|     +----------+  |
-// |        |<=#       #        |
-// |        |  #=======#        |
-// +--------+  Rejoin path      |
-//     |________                |
-//             |                |
-//     IC      |                |
-//   Entry     |                |
-// +------------+               |
-// | lastJump_  |---------------/
-// +------------+
-// |    ...     |
-// +------------+
-//
-// Attaching stubs:
-//
-//   Patch the jump pointed to by lastJump_ to jump to the new stub. Update
-//   lastJump_ to be the new stub's failure jump. The failure jump of the new
-//   stub goes to the fallback label, which is the cache function. In this
-//   fashion, new stubs are _appended_ to the chain of stubs, as lastJump_
-//   points to the _tail_ of the stub chain.
-//
-//  JIT Code
-// +--------+ #=======================#
-// |        | #                       v
-// |========| #   +----------+     +------+
-// |== IC ==|=#   | Cache Fn |<====| Stub |
-// |========|     +----------+  ^  +------+
-// |        |<=#      #         |     #
-// |        |  #======#=========|=====#
-// +--------+      Rejoin path  |
-//     |________                |
-//             |                |
-//     IC      |                |
-//   Entry     |                |
-// +------------+               |
-// | lastJump_  |---------------/
-// +------------+
-// |    ...     |
-// +------------+
-//
-// While calls may be made to the cache function and other VM functions, the
-// cache may still be treated as pure during optimization passes, such that
-// LICM and GVN may be performed on operations around the cache as if the
-// operation cannot reenter scripted code through an Invoke() or otherwise have
-// unexpected behavior. This restricts the sorts of stubs which the cache can
-// generate or the behaviors which called functions can have, and if a called
-// function performs a possibly impure operation then the operation will be
-// marked as such and the calling script will be recompiled.
-//
-// Similarly, despite the presence of functions and multiple stubs generated
-// for a cache, the cache itself may be marked as idempotent and become hoisted
-// or coalesced by LICM or GVN. This also constrains the stubs which can be
-// generated for the cache.
-//
-// * IonCache usage
-//
-// IonCache is the base structure of an inline cache, which generates code stubs
-// dynamically and attaches them to an IonScript.
-//
-// A cache must at least provide a static update function which will usualy have
-// a JSContext*, followed by the cache index. The rest of the arguments of the
-// update function are usualy corresponding to the register inputs of the cache,
-// as it must perform the same operation as any of the stubs that it might
-// produce. The update function call is handled by the visit function of
-// CodeGenerator corresponding to this IC.
-//
-// The CodeGenerator visit function, as opposed to other visit functions, has
-// two arguments. The first one is the OutOfLineUpdateCache which stores the LIR
-// instruction. The second one is the IC object.  This function would be called
-// once the IC is registered with the addCache function of CodeGeneratorShared.
-//
-// To register a cache, you must call the addCache function as follow:
-//
-//     MyCodeIC cache(inputReg1, inputValueReg2, outputReg);
-//     if (!addCache(lir, allocateCache(cache)))
-//         return false;
-//
-// Once the cache is allocated with the allocateCache function, any modification
-// made to the cache would be ignored.
-//
-// The addCache function will produce a patchable jump at the location where
-// it is called. This jump will execute generated stubs and fallback on the code
-// of the visitMyCodeIC function if no stub match.
-//
-//   Warning: As the addCache function fallback on a VMCall, calls to
-// addCache should not be in the same path as another VMCall or in the same
-// path of another addCache as this is not supported by the invalidation
-// procedure.
-class IonCache
-{
-  public:
-    class StubAttacher;
-
-    enum Kind {
-#   define DEFINE_CACHEKINDS(ickind) Cache_##ickind,
-        IONCACHE_KIND_LIST(DEFINE_CACHEKINDS)
-#   undef DEFINE_CACHEKINDS
-        Cache_Invalid
-    };
-
-    // Cache testing and cast.
-#   define CACHEKIND_CASTS(ickind)                                      \
-    bool is##ickind() const {                                           \
-        return kind() == Cache_##ickind;                                \
-    }                                                                   \
-    inline ickind##IC& to##ickind();                                    \
-    inline const ickind##IC& to##ickind() const;
-    IONCACHE_KIND_LIST(CACHEKIND_CASTS)
-#   undef CACHEKIND_CASTS
-
-    virtual Kind kind() const = 0;
-
-    virtual void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) = 0;
-
-  public:
-
-    static const char* CacheName(Kind kind);
-
-  protected:
-    bool pure_ : 1;
-    bool idempotent_ : 1;
-    bool disabled_ : 1;
-    size_t stubCount_ : 5;
-
-    CodeLocationLabel fallbackLabel_;
-
-    // Location of this operation, nullptr for idempotent caches.
-    JSScript* script_;
-    jsbytecode* pc_;
-
-    // Location to use when updating profiler pseudostack when leaving this
-    // IC code to enter a callee.
-    jsbytecode* profilerLeavePc_;
-
-    CodeLocationJump initialJump_;
-    CodeLocationJump lastJump_;
-    CodeLocationLabel rejoinLabel_;
-
-  private:
-    static const size_t MAX_STUBS;
-    void incrementStubCount() {
-        // The IC should stop generating stubs before wrapping stubCount.
-        stubCount_++;
-        MOZ_ASSERT(stubCount_);
-    }
-
-  public:
-
-    IonCache()
-      : pure_(false),
-        idempotent_(false),
-        disabled_(false),
-        stubCount_(0),
-        fallbackLabel_(),
-        script_(nullptr),
-        pc_(nullptr),
-        profilerLeavePc_(nullptr),
-        initialJump_(),
-        lastJump_(),
-        rejoinLabel_()
-    {
-    }
-
-    void disable();
-    inline bool isDisabled() const {
-        return disabled_;
-    }
-
-    // Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
-    // the location of the out-of-line update (slow) path.  This location will
-    // be set to the exitJump of the last generated stub.
-    void setFallbackLabel(CodeOffset fallbackLabel) {
-        fallbackLabel_ = fallbackLabel;
-    }
-
-    void setProfilerLeavePC(jsbytecode* pc) {
-        MOZ_ASSERT(pc != nullptr);
-        profilerLeavePc_ = pc;
-    }
-
-    // Get the address at which IC rejoins the mainline jitcode.
-    void* rejoinAddress() const {
-        return rejoinLabel_.raw();
-    }
-
-    void emitInitialJump(MacroAssembler& masm, RepatchLabel& entry);
-    void updateBaseAddress(JitCode* code, MacroAssembler& masm);
-
-    // Reset the cache around garbage collection.
-    virtual void reset(ReprotectCode reprotect);
-
-    bool canAttachStub() const {
-        return stubCount_ < MAX_STUBS;
-    }
-    bool empty() const {
-        return stubCount_ == 0;
-    }
-
-    enum LinkStatus {
-        LINK_ERROR,
-        CACHE_FLUSHED,
-        LINK_GOOD
-    };
-
-    // Use the Linker to link the generated code and check if any
-    // monitoring/allocation caused an invalidation of the running ion script,
-    // this function returns CACHE_FLUSHED. In case of allocation issue this
-    // function returns LINK_ERROR.
-    LinkStatus linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
-                        JitCode** code);
-
-    // Fixup variables and update jumps in the list of stubs.  Increment the
-    // number of attached stubs accordingly.
-    void attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
-                    Handle<JitCode*> code);
-
-    // Combine both linkStub and attachStub into one function. In addition, it
-    // produces a spew augmented with the attachKind string.
-    MOZ_MUST_USE bool linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher,
-                                        IonScript* ion, const char* attachKind,
-                                        JS::TrackedOutcome = JS::TrackedOutcome::ICOptStub_GenericSuccess);
-
-#ifdef DEBUG
-    bool isAllocated() {
-        return fallbackLabel_.isSet();
-    }
-#endif
-
-    bool pure() const {
-        return pure_;
-    }
-    bool idempotent() const {
-        return idempotent_;
-    }
-    void setIdempotent() {
-        MOZ_ASSERT(!idempotent_);
-        MOZ_ASSERT(!script_);
-        MOZ_ASSERT(!pc_);
-        idempotent_ = true;
-    }
-
-    void setScriptedLocation(JSScript* script, jsbytecode* pc) {
-        MOZ_ASSERT(!idempotent_);
-        script_ = script;
-        pc_ = pc;
-    }
-
-    void getScriptedLocation(MutableHandleScript pscript, jsbytecode** ppc) const {
-        pscript.set(script_);
-        *ppc = pc_;
-    }
-
-    jsbytecode* pc() const {
-        MOZ_ASSERT(pc_);
-        return pc_;
-    }
-
-    void trace(JSTracer* trc);
-};
-
-// Define the cache kind and pre-declare data structures used for calling inline
-// caches.
-#define CACHE_HEADER(ickind)                                        \
-    Kind kind() const {                                             \
-        return IonCache::Cache_##ickind;                            \
-    }                                                               \
-                                                                    \
-    void accept(CodeGenerator* codegen, IonCacheVisitor* visitor) { \
-        visitor->visit##ickind##IC(codegen);                        \
-    }                                                               \
-                                                                    \
-    static const VMFunction UpdateInfo;
-
-// Subclasses of IonCache for the various kinds of caches. These do not define
-// new data members; all caches must be of the same size.
-
-class BindNameIC : public IonCache
-{
-  protected:
-    Register environmentChain_;
-    PropertyName* name_;
-    Register output_;
-
-  public:
-    BindNameIC(Register envChain, PropertyName* name, Register output)
-      : environmentChain_(envChain),
-        name_(name),
-        output_(output)
-    {
-    }
-
-    CACHE_HEADER(BindName)
-
-    Register environmentChainReg() const {
-        return environmentChain_;
-    }
-    HandlePropertyName name() const {
-        return HandlePropertyName::fromMarkedLocation(&name_);
-    }
-    Register outputReg() const {
-        return output_;
-    }
-
-    MOZ_MUST_USE bool attachGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
-                                   HandleObject envChain);
-
-    MOZ_MUST_USE bool attachNonGlobal(JSContext* cx, HandleScript outerScript, IonScript* ion,
-                                      HandleObject envChain, HandleObject holder);
-
-    static JSObject*
-    update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, HandleObject envChain);
-};
-
-#undef CACHE_HEADER
-
-// Implement cache casts now that the compiler can see the inheritance.
-#define CACHE_CASTS(ickind)                                             \
-    ickind##IC& IonCache::to##ickind()                                  \
-    {                                                                   \
-        MOZ_ASSERT(is##ickind());                                       \
-        return *static_cast<ickind##IC*>(this);                        \
-    }                                                                   \
-    const ickind##IC& IonCache::to##ickind() const                      \
-    {                                                                   \
-        MOZ_ASSERT(is##ickind());                                       \
-        return *static_cast<const ickind##IC*>(this);                  \
-    }
-IONCACHE_KIND_LIST(CACHE_CASTS)
-#undef OPCODE_CASTS
-
 bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
 bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
                                                PropertyResult prop);
 
 bool IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
                                     bool* isTemporarilyUnoptimizable = nullptr);
 bool IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape);
 
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -163,20 +163,18 @@ class JitCode : public gc::TenuredCell
     static const JS::TraceKind TraceKind = JS::TraceKind::JitCode;
 };
 
 class SnapshotWriter;
 class RecoverWriter;
 class SafepointWriter;
 class SafepointIndex;
 class OsiIndex;
-class IonCache;
 class IonIC;
 struct PatchableBackedgeInfo;
-struct CacheLocation;
 
 // An IonScript attaches Ion-generated information to a JSScript.
 struct IonScript
 {
   private:
     // Code pointer containing the actual method.
     PreBarrieredJitCode method_;
 
@@ -212,22 +210,16 @@ struct IonScript
     uint32_t recompiling_;
 
     // Any kind of data needed by the runtime, these can be either cache
     // information or profiling info.
     uint32_t runtimeData_;
     uint32_t runtimeSize_;
 
     // State for polymorphic caches in the compiled code. All caches are stored
-    // in the runtimeData buffer and indexed by the cacheIndex which gives a
-    // relative offset in the runtimeData array.
-    uint32_t cacheIndex_;
-    uint32_t cacheEntries_;
-
-    // State for polymorphic caches in the compiled code. All caches are stored
     // in the runtimeData buffer and indexed by the icIndex which gives a
     // relative offset in the runtimeData array.
     uint32_t icIndex_;
     uint32_t icEntries_;
 
     // Map code displacement to safepoint / OSI-patch-delta.
     uint32_t safepointIndexOffset_;
     uint32_t safepointIndexEntries_;
@@ -317,19 +309,16 @@ struct IonScript
         return (SafepointIndex*) &bottomBuffer()[safepointIndexOffset_];
     }
     const OsiIndex* osiIndices() const {
         return const_cast<IonScript*>(this)->osiIndices();
     }
     OsiIndex* osiIndices() {
         return (OsiIndex*) &bottomBuffer()[osiIndexOffset_];
     }
-    uint32_t* cacheIndex() {
-        return (uint32_t*) &bottomBuffer()[cacheIndex_];
-    }
     uint32_t* icIndex() {
         return (uint32_t*) &bottomBuffer()[icIndex_];
     }
     uint8_t* runtimeData() {
         return  &bottomBuffer()[runtimeData_];
     }
     PatchableBackedge* backedgeList() {
         return (PatchableBackedge*) &bottomBuffer()[backedgeList_];
@@ -348,17 +337,17 @@ struct IonScript
         MOZ_ASSERT(fallbackStubSpace_.isEmpty());
     }
 
     static IonScript* New(JSContext* cx, RecompileInfo recompileInfo,
                           uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
                           size_t snapshotsListSize, size_t snapshotsRVATableSize,
                           size_t recoversSize, size_t bailoutEntries,
                           size_t constants, size_t safepointIndexEntries,
-                          size_t osiIndexEntries, size_t cacheEntries, size_t icEntries,
+                          size_t osiIndexEntries, size_t icEntries,
                           size_t runtimeSize, size_t safepointsSize,
                           size_t backedgeEntries, size_t sharedStubEntries,
                           OptimizationLevel optimizationLevel);
     static void Trace(JSTracer* trc, IonScript* script);
     static void Destroy(FreeOp* fop, IonScript* script);
 
     static inline size_t offsetOfMethod() {
         return offsetof(IonScript, method_);
@@ -496,28 +485,17 @@ struct IonScript
     }
     const SafepointIndex* getSafepointIndex(uint32_t disp) const;
     const SafepointIndex* getSafepointIndex(uint8_t* retAddr) const {
         MOZ_ASSERT(containsCodeAddress(retAddr));
         return getSafepointIndex(retAddr - method()->raw());
     }
     const OsiIndex* getOsiIndex(uint32_t disp) const;
     const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
-    inline IonCache& getCacheFromIndex(uint32_t index) {
-        MOZ_ASSERT(index < cacheEntries_);
-        uint32_t offset = cacheIndex()[index];
-        return getCache(offset);
-    }
-    inline IonCache& getCache(uint32_t offset) {
-        MOZ_ASSERT(offset < runtimeSize_);
-        return *(IonCache*) &runtimeData()[offset];
-    }
-    size_t numCaches() const {
-        return cacheEntries_;
-    }
+
     IonIC& getICFromIndex(uint32_t index) {
         MOZ_ASSERT(index < icEntries_);
         uint32_t offset = icIndex()[index];
         return getIC(offset);
     }
     inline IonIC& getIC(uint32_t offset) {
         MOZ_ASSERT(offset < runtimeSize_);
         return *(IonIC*) &runtimeData()[offset];
@@ -529,32 +507,26 @@ struct IonScript
         return (IonICEntry*) &bottomBuffer()[sharedStubList_];
     }
     size_t numSharedStubs() const {
         return sharedStubEntries_;
     }
     size_t runtimeSize() const {
         return runtimeSize_;
     }
-    CacheLocation* getCacheLocs(uint32_t locIndex) {
-        MOZ_ASSERT(locIndex < runtimeSize_);
-        return (CacheLocation*) &runtimeData()[locIndex];
-    }
     void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect);
-    void purgeCaches();
     void purgeICs(Zone* zone);
     void unlinkFromRuntime(FreeOp* fop);
     void copySnapshots(const SnapshotWriter* writer);
     void copyRecovers(const RecoverWriter* writer);
     void copyBailoutTable(const SnapshotOffset* table);
     void copyConstants(const Value* vp);
     void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm);
     void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm);
     void copyRuntimeData(const uint8_t* data);
-    void copyCacheEntries(const uint32_t* caches, MacroAssembler& masm);
     void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
     void copySafepoints(const SafepointWriter* writer);
     void copyPatchableBackedges(JSContext* cx, JitCode* code,
                                 PatchableBackedgeInfo* backedges,
                                 MacroAssembler& masm);
 
     bool invalidated() const {
         return invalidationCount_ != 0;
--- a/js/src/jit/IonIC.cpp
+++ b/js/src/jit/IonIC.cpp
@@ -41,18 +41,19 @@ IonIC::scratchRegisterForEntryJump()
         TypedOrValueRegister output = asGetPropertyIC()->output();
         return output.hasValue() ? output.valueReg().scratchReg() : output.typedReg().gpr();
       }
       case CacheKind::SetProp:
       case CacheKind::SetElem:
         return asSetPropertyIC()->temp();
       case CacheKind::GetName:
         return asGetNameIC()->temp();
+      case CacheKind::BindName:
+        return asBindNameIC()->temp();
       case CacheKind::In:
-      case CacheKind::BindName:
         MOZ_CRASH("Baseline-specific for now");
       case CacheKind::HasOwn:
         return asHasOwnIC()->output();
     }
 
     MOZ_CRASH("Invalid kind");
 }
 
@@ -281,23 +282,22 @@ IonSetPropertyIC::update(JSContext* cx, 
     return true;
 }
 
 /* static */ bool
 IonGetNameIC::update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic,
                      HandleObject envChain, MutableHandleValue res)
 {
     IonScript* ionScript = outerScript->ionScript();
+    jsbytecode* pc = ic->pc();
+    RootedPropertyName name(cx, ic->script()->getName(pc));
 
     if (ic->state().maybeTransition())
         ic->discardStubs(cx->zone());
 
-    jsbytecode* pc = ic->pc();
-    RootedPropertyName name(cx, ic->script()->getName(pc));
-
     if (ic->state().canAttachStub()) {
         bool attached = false;
         RootedScript script(cx, ic->script());
         GetNameIRGenerator gen(cx, script, pc, ic->state().mode(), envChain, name);
         if (gen.tryAttachStub())
             ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
 
         if (!attached)
@@ -319,16 +319,45 @@ IonGetNameIC::update(JSContext* cx, Hand
     }
 
     // No need to call TypeScript::Monitor, IonBuilder always inserts a type
     // barrier after GetName ICs.
 
     return true;
 }
 
+/* static */ JSObject*
+IonBindNameIC::update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic,
+                      HandleObject envChain)
+{
+    IonScript* ionScript = outerScript->ionScript();
+    jsbytecode* pc = ic->pc();
+    RootedPropertyName name(cx, ic->script()->getName(pc));
+
+    if (ic->state().maybeTransition())
+        ic->discardStubs(cx->zone());
+
+    if (ic->state().canAttachStub()) {
+        bool attached = false;
+        RootedScript script(cx, ic->script());
+        BindNameIRGenerator gen(cx, script, pc, ic->state().mode(), envChain, name);
+        if (gen.tryAttachStub())
+            ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
+
+        if (!attached)
+            ic->state().trackNotAttached();
+    }
+
+    RootedObject holder(cx);
+    if (!LookupNameUnqualified(cx, name, envChain, &holder))
+        return nullptr;
+
+    return holder;
+}
+
 /* static */ bool
 IonHasOwnIC::update(JSContext* cx, HandleScript outerScript, IonHasOwnIC* ic,
                     HandleValue val, HandleValue idVal, int32_t* res)
 {
     IonScript* ionScript = outerScript->ionScript();
 
     if (ic->state().maybeTransition())
         ic->discardStubs(cx->zone());
--- a/js/src/jit/IonIC.h
+++ b/js/src/jit/IonIC.h
@@ -54,16 +54,17 @@ class IonICStub
         next_ = nullptr;
         stubInfo_ = nullptr;
     }
 };
 
 class IonGetPropertyIC;
 class IonSetPropertyIC;
 class IonGetNameIC;
+class IonBindNameIC;
 class IonHasOwnIC;
 
 class IonIC
 {
     // This either points at the OOL path for the fallback path, or the code for
     // the first stub.
     uint8_t* codeRaw_;
 
@@ -140,16 +141,20 @@ class IonIC
     IonSetPropertyIC* asSetPropertyIC() {
         MOZ_ASSERT(kind_ == CacheKind::SetProp || kind_ == CacheKind::SetElem);
         return (IonSetPropertyIC*)this;
     }
     IonGetNameIC* asGetNameIC() {
         MOZ_ASSERT(kind_ == CacheKind::GetName);
         return (IonGetNameIC*)this;
     }
+    IonBindNameIC* asBindNameIC() {
+        MOZ_ASSERT(kind_ == CacheKind::BindName);
+        return (IonBindNameIC*)this;
+    }
     IonHasOwnIC* asHasOwnIC() {
         MOZ_ASSERT(kind_ == CacheKind::HasOwn);
         return (IonHasOwnIC*)this;
     }
 
     void updateBaseAddress(JitCode* code, MacroAssembler& masm);
 
     // Returns the Register to use as scratch when entering IC stubs. This
@@ -275,16 +280,42 @@ class IonGetNameIC : public IonIC
     ValueOperand output() const { return output_; }
     Register temp() const { return temp_; }
     LiveRegisterSet liveRegs() const { return liveRegs_; }
 
     static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonGetNameIC* ic,
                                     HandleObject envChain, MutableHandleValue res);
 };
 
+class IonBindNameIC : public IonIC
+{
+    LiveRegisterSet liveRegs_;
+
+    Register environment_;
+    Register output_;
+    Register temp_;
+
+  public:
+    IonBindNameIC(LiveRegisterSet liveRegs, Register environment, Register output, Register temp)
+      : IonIC(CacheKind::BindName),
+        liveRegs_(liveRegs),
+        environment_(environment),
+        output_(output),
+        temp_(temp)
+    { }
+
+    Register environment() const { return environment_; }
+    Register output() const { return output_; }
+    Register temp() const { return temp_; }
+    LiveRegisterSet liveRegs() const { return liveRegs_; }
+
+    static JSObject* update(JSContext* cx, HandleScript outerScript, IonBindNameIC* ic,
+                            HandleObject envChain);
+};
+
 class IonHasOwnIC : public IonIC
 {
     LiveRegisterSet liveRegs_;
 
     TypedOrValueRegister value_;
     TypedOrValueRegister id_;
     Register output_;
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3812,17 +3812,17 @@ LIRGenerator::visitSetPropertyPolymorphi
 }
 
 void
 LIRGenerator::visitBindNameCache(MBindNameCache* ins)
 {
     MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Object);
 
-    LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()));
+    LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()), temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitCallBindVar(MCallBindVar* ins)
 {
     MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -22,17 +22,16 @@
 #include "jit/VMFunctions.h"
 
 namespace js {
 namespace jit {
 
 class OutOfLineCode;
 class CodeGenerator;
 class MacroAssembler;
-class IonCache;
 class IonIC;
 
 template <class ArgSeq, class StoreOutputTo>
 class OutOfLineCallVM;
 
 class OutOfLineTruncateSlow;
 class OutOfLineWasmTruncateCheck;
 
@@ -97,19 +96,16 @@ class CodeGeneratorShared : public LElem
     js::Vector<OsiIndex, 0, SystemAllocPolicy> osiIndices_;
 
     // Mapping from bailout table ID to an offset in the snapshot buffer.
     js::Vector<SnapshotOffset, 0, SystemAllocPolicy> bailouts_;
 
     // Allocated data space needed at runtime.
     js::Vector<uint8_t, 0, SystemAllocPolicy> runtimeData_;
 
-    // Vector of information about generated polymorphic inline caches.
-    js::Vector<uint32_t, 0, SystemAllocPolicy> cacheList_;
-
     // Vector mapping each IC index to its offset in runtimeData_.
     js::Vector<uint32_t, 0, SystemAllocPolicy> icList_;
 
     // IC data we need at compile-time. Discarded after creating the IonScript.
     struct CompileTimeICInfo {
         CodeOffset icOffsetForJump;
         CodeOffset icOffsetForPush;
     };
@@ -284,33 +280,16 @@ class CodeGeneratorShared : public LElem
     MOZ_MUST_USE
     bool allocateData(size_t size, size_t* offset) {
         MOZ_ASSERT(size % sizeof(void*) == 0);
         *offset = runtimeData_.length();
         masm.propagateOOM(runtimeData_.appendN(0, size));
         return !masm.oom();
     }
 
-    // Ensure the cache is an IonCache while expecting the size of the derived
-    // class. We only need the cache list at GC time. Everyone else can just take
-    // runtimeData offsets.
-    template <typename T>
-    inline size_t allocateCache(const T& cache) {
-        static_assert(mozilla::IsBaseOf<IonCache, T>::value, "T must inherit from IonCache");
-        size_t index;
-        masm.propagateOOM(allocateData(sizeof(mozilla::AlignedStorage2<T>), &index));
-        masm.propagateOOM(cacheList_.append(index));
-        if (masm.oom())
-            return SIZE_MAX;
-        // Use the copy constructor on the allocated space.
-        MOZ_ASSERT(index == cacheList_.back());
-        new (&runtimeData_[index]) T(cache);
-        return index;
-    }
-
     template <typename T>
     inline size_t allocateIC(const T& cache) {
         static_assert(mozilla::IsBaseOf<IonIC, T>::value, "T must inherit from IonIC");
         size_t index;
         masm.propagateOOM(allocateData(sizeof(mozilla::AlignedStorage2<T>), &index));
         masm.propagateOOM(icList_.append(index));
         masm.propagateOOM(icInfo_.append(CompileTimeICInfo()));
         if (masm.oom())
@@ -492,17 +471,16 @@ class CodeGeneratorShared : public LElem
     }
 
     void callVM(const VMFunction& f, LInstruction* ins, const Register* dynStack = nullptr);
 
     template <class ArgSeq, class StoreOutputTo>
     inline OutOfLineCode* oolCallVM(const VMFunction& fun, LInstruction* ins, const ArgSeq& args,
                                     const StoreOutputTo& out);
 
-    void addCache(LInstruction* lir, size_t cacheIndex);
     void addIC(LInstruction* lir, size_t cacheIndex);
 
     ReciprocalMulConstants computeDivisionConstants(uint32_t d, int maxLog);
 
   protected:
     bool generatePrologue();
     bool generateEpilogue();
 
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -6845,27 +6845,31 @@ class LSetPropertyPolymorphicT : public 
     const MSetPropertyPolymorphic* mir() const {
         return mir_->toSetPropertyPolymorphic();
     }
     const char* extraName() const {
         return StringFromMIRType(valueType_);
     }
 };
 
-class LBindNameCache : public LInstructionHelper<1, 1, 0>
+class LBindNameCache : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(BindNameCache)
 
-    explicit LBindNameCache(const LAllocation& envChain) {
+    LBindNameCache(const LAllocation& envChain, const LDefinition& temp) {
         setOperand(0, envChain);
+        setTemp(0, temp);
     }
     const LAllocation* environmentChain() {
         return getOperand(0);
     }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
     const MBindNameCache* mir() const {
         return mir_->toBindNameCache();
     }
 };
 
 class LCallBindVar : public LInstructionHelper<1, 1, 0>
 {
   public:
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -7239,24 +7239,16 @@ js::ReleaseAllJITCode(FreeOp* fop)
     JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
     for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
         zone->setPreservingCode(false);
         zone->discardJitCode(fop);
     }
 }
 
 void
-js::PurgeJITCaches(Zone* zone)
-{
-    /* Discard Ion caches. */
-    for (auto script = zone->cellIter<JSScript>(); !script.done(); script.next())
-        jit::PurgeCaches(script);
-}
-
-void
 ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind)
 {
     ArenaLists::BackgroundFinalizeState* bfs = &backgroundFinalizeState(thingKind);
     switch (*bfs) {
       case BFS_DONE:
         break;
       default:
         MOZ_ASSERT_UNREACHABLE("Background finalization in progress, but it should not be.");
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1400,18 +1400,15 @@ struct MOZ_RAII AutoDisableCompactingGC
 {
     explicit AutoDisableCompactingGC(JSContext* cx);
     ~AutoDisableCompactingGC();
 
   private:
     JSContext* cx;
 };
 
-void
-PurgeJITCaches(JS::Zone* zone);
-
 // This is the same as IsInsideNursery, but not inlined.
 bool
 UninlinedIsInsideNursery(const gc::Cell* cell);
 
 } /* namespace js */
 
 #endif /* jsgc_h */