Bug 1479603 - [Part 10] Relocate the remaining Baseline-only stub code to BaselineIC files r=jandem
authorMatthew Gaudet <mgaudet@mozilla.com>
Tue, 21 Aug 2018 11:01:02 -0400
changeset 831138 370a45e8ea65c3fe50b9abd4651c525c18ab6934
parent 831137 b733b2488363f3f2bdd6e14cc9df1694f7f8ae3a
child 831139 5a2381311cedc81a16222f90b854675fa004c4db
push id118868
push userbmo:zjz@zjz.name
push dateFri, 24 Aug 2018 07:04:39 +0000
reviewersjandem
bugs1479603
milestone63.0a1
Bug 1479603 - [Part 10] Relocate the remaining Baseline-only stub code to BaselineIC files r=jandem
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/SharedIC.cpp
js/src/jit/SharedIC.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -257,16 +257,814 @@ ICWarmUpCounter_Fallback::Compiler::gene
     masm.jump(scratchReg);
 
     // No jitcode available, do nothing.
     masm.bind(&noCompiledCode);
     EmitReturnFromIC(masm);
     return true;
 }
 
+
+void
+ICFallbackStub::unlinkStub(Zone* zone, ICStub* prev, ICStub* stub)
+{
+    MOZ_ASSERT(stub->next());
+
+    // If stub is the last optimized stub, update lastStubPtrAddr.
+    if (stub->next() == this) {
+        MOZ_ASSERT(lastStubPtrAddr_ == stub->addressOfNext());
+        if (prev)
+            lastStubPtrAddr_ = prev->addressOfNext();
+        else
+            lastStubPtrAddr_ = icEntry()->addressOfFirstStub();
+        *lastStubPtrAddr_ = this;
+    } else {
+        if (prev) {
+            MOZ_ASSERT(prev->next() == stub);
+            prev->setNext(stub->next());
+        } else {
+            MOZ_ASSERT(icEntry()->firstStub() == stub);
+            icEntry()->setFirstStub(stub->next());
+        }
+    }
+
+    state_.trackUnlinkedStub();
+
+    if (zone->needsIncrementalBarrier()) {
+        // We are removing edges from ICStub to gcthings. Perform one final trace
+        // of the stub for incremental GC, as it must know about those edges.
+        stub->trace(zone->barrierTracer());
+    }
+
+    if (stub->makesGCCalls() && stub->isMonitored()) {
+        // This stub can make calls so we can return to it if it's on the stack.
+        // We just have to reset its firstMonitorStub_ field to avoid a stale
+        // pointer when purgeOptimizedStubs destroys all optimized monitor
+        // stubs (unlinked stubs won't be updated).
+        ICTypeMonitor_Fallback* monitorFallback =
+            toMonitoredFallbackStub()->maybeFallbackMonitorStub();
+        MOZ_ASSERT(monitorFallback);
+        stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);
+    }
+
+#ifdef DEBUG
+    // Poison stub code to ensure we don't call this stub again. However, if
+    // this stub can make calls, a pointer to it may be stored in a stub frame
+    // on the stack, so we can't touch the stubCode_ or GC will crash when
+    // tracing this pointer.
+    if (!stub->makesGCCalls())
+        stub->stubCode_ = (uint8_t*)0xbad;
+#endif
+}
+
+void
+ICFallbackStub::unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind)
+{
+    for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
+        if (iter->kind() == kind)
+            iter.unlink(cx);
+    }
+}
+
+void
+ICFallbackStub::discardStubs(JSContext* cx)
+{
+    for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++)
+        iter.unlink(cx);
+}
+
+void
+ICTypeMonitor_Fallback::resetMonitorStubChain(Zone* zone)
+{
+    if (zone->needsIncrementalBarrier()) {
+        // We are removing edges from monitored stubs to gcthings (JitCode).
+        // Perform one final trace of all monitor stubs for incremental GC,
+        // as it must know about those edges.
+        for (ICStub* s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next())
+            s->trace(zone->barrierTracer());
+    }
+
+    firstMonitorStub_ = this;
+    numOptimizedMonitorStubs_ = 0;
+
+    if (hasFallbackStub_) {
+        lastMonitorStubPtrAddr_ = nullptr;
+
+        // Reset firstMonitorStub_ field of all monitored stubs.
+        for (ICStubConstIterator iter = mainFallbackStub_->beginChainConst();
+             !iter.atEnd(); iter++)
+        {
+            if (!iter->isMonitored())
+                continue;
+            iter->toMonitoredStub()->resetFirstMonitorStub(this);
+        }
+    } else {
+        icEntry_->setFirstStub(this);
+        lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
+    }
+}
+
+void
+ICUpdatedStub::resetUpdateStubChain(Zone* zone)
+{
+    while (!firstUpdateStub_->isTypeUpdate_Fallback()) {
+        if (zone->needsIncrementalBarrier()) {
+            // We are removing edges from update stubs to gcthings (JitCode).
+            // Perform one final trace of all update stubs for incremental GC,
+            // as it must know about those edges.
+            firstUpdateStub_->trace(zone->barrierTracer());
+        }
+        firstUpdateStub_ = firstUpdateStub_->next();
+    }
+
+    numOptimizedStubs_ = 0;
+}
+
+ICMonitoredStub::ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub)
+  : ICStub(kind, ICStub::Monitored, stubCode),
+    firstMonitorStub_(firstMonitorStub)
+{
+    // In order to silence Coverity - null pointer dereference checker
+    MOZ_ASSERT(firstMonitorStub_);
+    // If the first monitored stub is a ICTypeMonitor_Fallback stub, then
+    // double check that _its_ firstMonitorStub is the same as this one.
+    MOZ_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),
+                  firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
+                     firstMonitorStub_);
+}
+
+bool
+ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx, JSScript* script)
+{
+    MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
+
+    ICTypeMonitor_Fallback::Compiler compiler(cx, this);
+    ICStubSpace* space = script->baselineScript()->fallbackStubSpace();
+    ICTypeMonitor_Fallback* stub = compiler.getStub(space);
+    if (!stub)
+        return false;
+    fallbackMonitorStub_ = stub;
+    return true;
+}
+
+bool
+ICMonitoredFallbackStub::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                                StackTypeSet* types, HandleValue val)
+{
+    ICTypeMonitor_Fallback* typeMonitorFallback = getFallbackMonitorStub(cx, frame->script());
+    if (!typeMonitorFallback)
+        return false;
+    return typeMonitorFallback->addMonitorStubForValue(cx, frame, types, val);
+}
+
+bool
+ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space)
+{
+    MOZ_ASSERT(firstUpdateStub_ == nullptr);
+
+    ICTypeUpdate_Fallback::Compiler compiler(cx);
+    ICTypeUpdate_Fallback* stub = compiler.getStub(space);
+    if (!stub)
+        return false;
+
+    firstUpdateStub_ = stub;
+    return true;
+}
+
+JitCode*
+ICStubCompiler::getStubCode()
+{
+    JitRealm* realm = cx->realm()->jitRealm();
+
+    // Check for existing cached stubcode.
+    uint32_t stubKey = getKey();
+    JitCode* stubCode = realm->getStubCode(stubKey);
+    if (stubCode)
+        return stubCode;
+
+    // Compile new stubcode.
+    JitContext jctx(cx, nullptr);
+    StackMacroAssembler masm;
+#ifndef JS_USE_LINK_REGISTER
+    // The first value contains the return addres,
+    // which we pull into ICTailCallReg for tail calls.
+    masm.adjustFrame(sizeof(intptr_t));
+#endif
+#ifdef JS_CODEGEN_ARM
+    masm.setSecondScratchReg(BaselineSecondScratchReg);
+#endif
+
+    if (!generateStubCode(masm))
+        return nullptr;
+    Linker linker(masm);
+    AutoFlushICache afc("getStubCode");
+    Rooted<JitCode*> newStubCode(cx, linker.newCode(cx, CodeKind::Baseline));
+    if (!newStubCode)
+        return nullptr;
+
+    // Cache newly compiled stubcode.
+    if (!realm->putStubCode(cx, stubKey, newStubCode))
+        return nullptr;
+
+    // After generating code, run postGenerateStubCode().  We must not fail
+    // after this point.
+    postGenerateStubCode(masm, newStubCode);
+
+    MOZ_ASSERT(entersStubFrame_ == ICStub::NonCacheIRStubMakesGCCalls(kind));
+    MOZ_ASSERT(!inStubFrame_);
+
+#ifdef JS_ION_PERF
+    writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC");
+#endif
+
+    return newStubCode;
+}
+
+bool
+ICStubCompiler::tailCallVM(const VMFunction& fun, MacroAssembler& masm)
+{
+    TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
+    MOZ_ASSERT(fun.expectTailCall == TailCall);
+    uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
+    EmitBaselineTailCallVM(code, masm, argSize);
+    return true;
+}
+
+bool
+ICStubCompiler::callVM(const VMFunction& fun, MacroAssembler& masm)
+{
+    MOZ_ASSERT(inStubFrame_);
+
+    TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
+    MOZ_ASSERT(fun.expectTailCall == NonTailCall);
+
+    EmitBaselineCallVM(code, masm);
+    return true;
+}
+
+void
+ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch)
+{
+    EmitBaselineEnterStubFrame(masm, scratch);
+#ifdef DEBUG
+    framePushedAtEnterStubFrame_ = masm.framePushed();
+#endif
+
+    MOZ_ASSERT(!inStubFrame_);
+    inStubFrame_ = true;
+
+#ifdef DEBUG
+    entersStubFrame_ = true;
+#endif
+}
+
+void
+ICStubCompiler::assumeStubFrame()
+{
+    MOZ_ASSERT(!inStubFrame_);
+    inStubFrame_ = true;
+
+#ifdef DEBUG
+    entersStubFrame_ = true;
+
+    // |framePushed| isn't tracked precisely in ICStubs, so simply assume it to
+    // be STUB_FRAME_SIZE so that assertions don't fail in leaveStubFrame.
+    framePushedAtEnterStubFrame_ = STUB_FRAME_SIZE;
+#endif
+}
+
+void
+ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon)
+{
+    MOZ_ASSERT(entersStubFrame_ && inStubFrame_);
+    inStubFrame_ = false;
+
+#ifdef DEBUG
+    masm.setFramePushed(framePushedAtEnterStubFrame_);
+    if (calledIntoIon)
+        masm.adjustFrame(sizeof(intptr_t)); // Calls into ion have this extra.
+#endif
+    EmitBaselineLeaveStubFrame(masm, calledIntoIon);
+}
+
+void
+ICStubCompiler::pushStubPayload(MacroAssembler& masm, Register scratch)
+{
+    if (inStubFrame_) {
+        masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
+        masm.pushBaselineFramePtr(scratch, scratch);
+    } else {
+        masm.pushBaselineFramePtr(BaselineFrameReg, scratch);
+    }
+}
+
+void
+ICStubCompiler::PushStubPayload(MacroAssembler& masm, Register scratch)
+{
+    pushStubPayload(masm, scratch);
+    masm.adjustFrame(sizeof(intptr_t));
+}
+
+//
+void
+BaselineScript::noteAccessedGetter(uint32_t pcOffset)
+{
+    ICEntry& entry = icEntryFromPCOffset(pcOffset);
+    ICFallbackStub* stub = entry.fallbackStub();
+
+    if (stub->isGetProp_Fallback())
+        stub->toGetProp_Fallback()->noteAccessedGetter();
+}
+
+// TypeMonitor_Fallback
+//
+
+bool
+ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                               StackTypeSet* types, HandleValue val)
+{
+    MOZ_ASSERT(types);
+
+    // Don't attach too many SingleObject/ObjectGroup stubs. If the value is a
+    // primitive or if we will attach an any-object stub, we can handle this
+    // with a single PrimitiveSet or AnyValue stub so we always optimize.
+    if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS &&
+        val.isObject() &&
+        !types->unknownObject())
+    {
+        return true;
+    }
+
+    bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
+    MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
+
+    if (types->unknown()) {
+        // The TypeSet got marked as unknown so attach a stub that always
+        // succeeds.
+
+        // Check for existing TypeMonitor_AnyValue stubs.
+        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
+            if (iter->isTypeMonitor_AnyValue())
+                return true;
+        }
+
+        // Discard existing stubs.
+        resetMonitorStubChain(cx->zone());
+        wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr);
+
+        ICTypeMonitor_AnyValue::Compiler compiler(cx);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
+        if (!stub) {
+            ReportOutOfMemory(cx);
+            return false;
+        }
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for any value", stub);
+        addOptimizedMonitorStub(stub);
+
+    } else if (val.isPrimitive() || types->unknownObject()) {
+        if (val.isMagic(JS_UNINITIALIZED_LEXICAL))
+            return true;
+        MOZ_ASSERT(!val.isMagic());
+        JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
+
+        // Check for existing TypeMonitor stub.
+        ICTypeMonitor_PrimitiveSet* existingStub = nullptr;
+        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
+            if (iter->isTypeMonitor_PrimitiveSet()) {
+                existingStub = iter->toTypeMonitor_PrimitiveSet();
+                if (existingStub->containsType(type))
+                    return true;
+            }
+        }
+
+        if (val.isObject()) {
+            // Check for existing SingleObject/ObjectGroup stubs and discard
+            // stubs if we find one. Ideally we would discard just these stubs,
+            // but unlinking individual type monitor stubs is somewhat
+            // complicated.
+            MOZ_ASSERT(types->unknownObject());
+            bool hasObjectStubs = false;
+            for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
+                if (iter->isTypeMonitor_SingleObject() || iter->isTypeMonitor_ObjectGroup()) {
+                    hasObjectStubs = true;
+                    break;
+                }
+            }
+            if (hasObjectStubs) {
+                resetMonitorStubChain(cx->zone());
+                wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr);
+                existingStub = nullptr;
+            }
+        }
+
+        ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
+        ICStub* stub = existingStub
+                       ? compiler.updateStub()
+                       : compiler.getStub(compiler.getStubSpace(frame->script()));
+        if (!stub) {
+            ReportOutOfMemory(cx);
+            return false;
+        }
+
+        JitSpew(JitSpew_BaselineIC, "  %s TypeMonitor stub %p for primitive type %d",
+                existingStub ? "Modified existing" : "Created new", stub, type);
+
+        if (!existingStub) {
+            MOZ_ASSERT(!hasStub(TypeMonitor_PrimitiveSet));
+            addOptimizedMonitorStub(stub);
+        }
+
+    } else if (val.toObject().isSingleton()) {
+        RootedObject obj(cx, &val.toObject());
+
+        // Check for existing TypeMonitor stub.
+        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
+            if (iter->isTypeMonitor_SingleObject() &&
+                iter->toTypeMonitor_SingleObject()->object() == obj)
+            {
+                return true;
+            }
+        }
+
+        ICTypeMonitor_SingleObject::Compiler compiler(cx, obj);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
+        if (!stub) {
+            ReportOutOfMemory(cx);
+            return false;
+        }
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for singleton %p",
+                stub, obj.get());
+
+        addOptimizedMonitorStub(stub);
+
+    } else {
+        RootedObjectGroup group(cx, val.toObject().group());
+
+        // Check for existing TypeMonitor stub.
+        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
+            if (iter->isTypeMonitor_ObjectGroup() &&
+                iter->toTypeMonitor_ObjectGroup()->group() == group)
+            {
+                return true;
+            }
+        }
+
+        ICTypeMonitor_ObjectGroup::Compiler compiler(cx, group);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
+        if (!stub) {
+            ReportOutOfMemory(cx);
+            return false;
+        }
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for ObjectGroup %p",
+                stub, group.get());
+
+        addOptimizedMonitorStub(stub);
+    }
+
+    bool firstMonitorStubAdded = wasDetachedMonitorChain && (numOptimizedMonitorStubs_ > 0);
+
+    if (firstMonitorStubAdded) {
+        // Was an empty monitor chain before, but a new stub was added.  This is the
+        // only time that any main stubs' firstMonitorStub fields need to be updated to
+        // refer to the newly added monitor stub.
+        ICStub* firstStub = mainFallbackStub_->icEntry()->firstStub();
+        for (ICStubConstIterator iter(firstStub); !iter.atEnd(); iter++) {
+            // Non-monitored stubs are used if the result has always the same type,
+            // e.g. a StringLength stub will always return int32.
+            if (!iter->isMonitored())
+                continue;
+
+            // Since we just added the first optimized monitoring stub, any
+            // existing main stub's |firstMonitorStub| MUST be pointing to the fallback
+            // monitor stub (i.e. this stub).
+            MOZ_ASSERT(iter->toMonitoredStub()->firstMonitorStub() == this);
+            iter->toMonitoredStub()->updateFirstMonitorStub(firstMonitorStub_);
+        }
+    }
+
+    return true;
+}
+
+static bool
+DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallback* stub,
+                      HandleValue value, MutableHandleValue res)
+{
+    JSScript* script = frame->script();
+    jsbytecode* pc = stub->icEntry()->pc(script);
+    TypeFallbackICSpew(cx, stub, "TypeMonitor");
+
+    // Copy input value to res.
+    res.set(value);
+
+    if (MOZ_UNLIKELY(value.isMagic())) {
+        // It's possible that we arrived here from bailing out of Ion, and that
+        // Ion proved that the value is dead and optimized out. In such cases,
+        // do nothing. However, it's also possible that we have an uninitialized
+        // this, in which case we should not look for other magic values.
+
+        if (value.whyMagic() == JS_OPTIMIZED_OUT) {
+            MOZ_ASSERT(!stub->monitorsThis());
+            return true;
+        }
+
+        // In derived class constructors (including nested arrows/eval), the
+        // |this| argument or GETALIASEDVAR can return the magic TDZ value.
+        MOZ_ASSERT(value.isMagic(JS_UNINITIALIZED_LEXICAL));
+        MOZ_ASSERT(frame->isFunctionFrame() || frame->isEvalFrame());
+        MOZ_ASSERT(stub->monitorsThis() ||
+                   *GetNextPc(pc) == JSOP_CHECKTHIS ||
+                   *GetNextPc(pc) == JSOP_CHECKTHISREINIT ||
+                   *GetNextPc(pc) == JSOP_CHECKRETURN);
+        if (stub->monitorsThis())
+            TypeScript::SetThis(cx, script, TypeSet::UnknownType());
+        else
+            TypeScript::Monitor(cx, script, pc, TypeSet::UnknownType());
+        return true;
+    }
+
+    StackTypeSet* types;
+    uint32_t argument;
+    if (stub->monitorsArgument(&argument)) {
+        MOZ_ASSERT(pc == script->code());
+        types = TypeScript::ArgTypes(script, argument);
+        TypeScript::SetArgument(cx, script, argument, value);
+    } else if (stub->monitorsThis()) {
+        MOZ_ASSERT(pc == script->code());
+        types = TypeScript::ThisTypes(script);
+        TypeScript::SetThis(cx, script, value);
+    } else {
+        types = TypeScript::BytecodeTypes(script, pc);
+        TypeScript::Monitor(cx, script, pc, types, value);
+    }
+
+    if (MOZ_UNLIKELY(stub->invalid()))
+        return true;
+
+    return stub->addMonitorStubForValue(cx, frame, types, value);
+}
+
+typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*,
+                                        HandleValue, MutableHandleValue);
+static const VMFunction DoTypeMonitorFallbackInfo =
+    FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback, "DoTypeMonitorFallback",
+                                          TailCall);
+
+bool
+ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    MOZ_ASSERT(R0 == JSReturnOperand);
+
+    // Restore the tail call register.
+    EmitRestoreTailCallReg(masm);
+
+    masm.pushValue(R0);
+    masm.push(ICStubReg);
+    masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
+
+    return tailCallVM(DoTypeMonitorFallbackInfo, masm);
+}
+
+bool
+ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    Label success;
+    if ((flags_ & TypeToFlag(JSVAL_TYPE_INT32)) && !(flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE)))
+        masm.branchTestInt32(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE))
+        masm.branchTestNumber(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_UNDEFINED))
+        masm.branchTestUndefined(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_BOOLEAN))
+        masm.branchTestBoolean(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
+        masm.branchTestString(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_SYMBOL))
+        masm.branchTestSymbol(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
+        masm.branchTestObject(Assembler::Equal, R0, &success);
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
+        masm.branchTestNull(Assembler::Equal, R0, &success);
+
+    EmitStubGuardFailure(masm);
+
+    masm.bind(&success);
+    EmitReturnFromIC(masm);
+    return true;
+}
+
+static void
+MaybeWorkAroundAmdBug(MacroAssembler& masm)
+{
+    // Attempt to work around an AMD bug (see bug 1034706 and bug 1281759), by
+    // inserting 32-bytes of NOPs.
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    if (CPUInfo::NeedAmdBugWorkaround()) {
+        masm.nop(9);
+        masm.nop(9);
+        masm.nop(9);
+        masm.nop(5);
+    }
+#endif
+}
+
+bool
+ICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    Label failure;
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+    MaybeWorkAroundAmdBug(masm);
+
+    // Guard on the object's identity.
+    Register obj = masm.extractObject(R0, ExtractTemp0);
+    Address expectedObject(ICStubReg, ICTypeMonitor_SingleObject::offsetOfObject());
+    masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure);
+    MaybeWorkAroundAmdBug(masm);
+
+    EmitReturnFromIC(masm);
+    MaybeWorkAroundAmdBug(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+bool
+ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    Label failure;
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+    MaybeWorkAroundAmdBug(masm);
+
+    // Guard on the object's ObjectGroup. No Spectre mitigations are needed
+    // here: we're just recording type information for Ion compilation and
+    // it's safe to speculatively return.
+    Register obj = masm.extractObject(R0, ExtractTemp0);
+    Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
+    masm.branchTestObjGroupNoSpectreMitigations(Assembler::NotEqual, obj, expectedGroup,
+                                                R1.scratchReg(), &failure);
+    MaybeWorkAroundAmdBug(masm);
+
+    EmitReturnFromIC(masm);
+    MaybeWorkAroundAmdBug(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+bool
+ICTypeMonitor_AnyValue::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    EmitReturnFromIC(masm);
+    return true;
+}
+
+bool
+ICUpdatedStub::addUpdateStubForValue(JSContext* cx, HandleScript outerScript, HandleObject obj,
+                                     HandleObjectGroup group, HandleId id, HandleValue val)
+{
+    EnsureTrackPropertyTypes(cx, obj, id);
+
+    // Make sure that undefined values are explicitly included in the property
+    // types for an object if generating a stub to write an undefined value.
+    if (val.isUndefined() && CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
+        MOZ_ASSERT(obj->group() == group);
+        AddTypePropertyId(cx, obj, id, val);
+    }
+
+    bool unknown = false, unknownObject = false;
+    AutoSweepObjectGroup sweep(group);
+    if (group->unknownProperties(sweep)) {
+        unknown = unknownObject = true;
+    } else {
+        if (HeapTypeSet* types = group->maybeGetProperty(sweep, id)) {
+            unknown = types->unknown();
+            unknownObject = types->unknownObject();
+        } else {
+            // We don't record null/undefined types for certain TypedObject
+            // properties. In these cases |types| is allowed to be nullptr
+            // without implying unknown types. See DoTypeUpdateFallback.
+            MOZ_ASSERT(obj->is<TypedObject>());
+            MOZ_ASSERT(val.isNullOrUndefined());
+        }
+    }
+    MOZ_ASSERT_IF(unknown, unknownObject);
+
+    // Don't attach too many SingleObject/ObjectGroup stubs unless we can
+    // replace them with a single PrimitiveSet or AnyValue stub.
+    if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS &&
+        val.isObject() &&
+        !unknownObject)
+    {
+        return true;
+    }
+
+    if (unknown) {
+        // Attach a stub that always succeeds. We should not have a
+        // TypeUpdate_AnyValue stub yet.
+        MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_AnyValue));
+
+        // Discard existing stubs.
+        resetUpdateStubChain(cx->zone());
+
+        ICTypeUpdate_AnyValue::Compiler compiler(cx);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
+        if (!stub)
+            return false;
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for any value", stub);
+        addOptimizedUpdateStub(stub);
+
+    } else if (val.isPrimitive() || unknownObject) {
+        JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
+
+        // Check for existing TypeUpdate stub.
+        ICTypeUpdate_PrimitiveSet* existingStub = nullptr;
+        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
+            if (iter->isTypeUpdate_PrimitiveSet()) {
+                existingStub = iter->toTypeUpdate_PrimitiveSet();
+                MOZ_ASSERT(!existingStub->containsType(type));
+            }
+        }
+
+        if (val.isObject()) {
+            // Discard existing ObjectGroup/SingleObject stubs.
+            resetUpdateStubChain(cx->zone());
+            if (existingStub)
+                addOptimizedUpdateStub(existingStub);
+        }
+
+        ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type);
+        ICStub* stub = existingStub ? compiler.updateStub()
+                                    : compiler.getStub(compiler.getStubSpace(outerScript));
+        if (!stub)
+            return false;
+        if (!existingStub) {
+            MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_PrimitiveSet));
+            addOptimizedUpdateStub(stub);
+        }
+
+        JitSpew(JitSpew_BaselineIC, "  %s TypeUpdate stub %p for primitive type %d",
+                existingStub ? "Modified existing" : "Created new", stub, type);
+
+    } else if (val.toObject().isSingleton()) {
+        RootedObject obj(cx, &val.toObject());
+
+#ifdef DEBUG
+        // We should not have a stub for this object.
+        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
+            MOZ_ASSERT_IF(iter->isTypeUpdate_SingleObject(),
+                          iter->toTypeUpdate_SingleObject()->object() != obj);
+        }
+#endif
+
+        ICTypeUpdate_SingleObject::Compiler compiler(cx, obj);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
+        if (!stub)
+            return false;
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for singleton %p", stub, obj.get());
+
+        addOptimizedUpdateStub(stub);
+
+    } else {
+        RootedObjectGroup group(cx, val.toObject().group());
+
+#ifdef DEBUG
+        // We should not have a stub for this group.
+        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
+            MOZ_ASSERT_IF(iter->isTypeUpdate_ObjectGroup(),
+                          iter->toTypeUpdate_ObjectGroup()->group() != group);
+        }
+#endif
+
+        ICTypeUpdate_ObjectGroup::Compiler compiler(cx, group);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
+        if (!stub)
+            return false;
+
+        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for ObjectGroup %p",
+                stub, group.get());
+
+        addOptimizedUpdateStub(stub);
+    }
+
+    return true;
+}
+
 //
 // TypeUpdate_Fallback
 //
 static bool
 DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, HandleValue objval,
                      HandleValue value)
 {
     // This can get called from optimized stubs. Therefore it is not allowed to gc.
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -20,16 +20,429 @@
 #include "vm/BytecodeUtil.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 #include "vm/UnboxedObject.h"
 
 namespace js {
 namespace jit {
 
+class ICFallbackStub : public ICStub
+{
+    friend class ICStubConstIterator;
+  protected:
+    // Fallback stubs need these fields to easily add new stubs to
+    // the linked list of stubs for an IC.
+
+    // The IC entry for this linked list of stubs.
+    ICEntry* icEntry_;
+
+    // The number of stubs kept in the IC entry.
+    ICState state_;
+
+    // A pointer to the location stub pointer that needs to be
+    // changed to add a new "last" stub immediately before the fallback
+    // stub.  This'll start out pointing to the icEntry's "firstStub_"
+    // field, and as new stubs are added, it'll point to the current
+    // last stub's "next_" field.
+    ICStub** lastStubPtrAddr_;
+
+    ICFallbackStub(Kind kind, JitCode* stubCode)
+      : ICStub(kind, ICStub::Fallback, stubCode),
+        icEntry_(nullptr),
+        state_(),
+        lastStubPtrAddr_(nullptr) {}
+
+    ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
+      : ICStub(kind, trait, stubCode),
+        icEntry_(nullptr),
+        state_(),
+        lastStubPtrAddr_(nullptr)
+    {
+        MOZ_ASSERT(trait == ICStub::Fallback ||
+                   trait == ICStub::MonitoredFallback);
+    }
+
+  public:
+    inline ICEntry* icEntry() const {
+        return icEntry_;
+    }
+
+    inline size_t numOptimizedStubs() const {
+        return state_.numOptimizedStubs();
+    }
+
+    void setInvalid() {
+        state_.setInvalid();
+    }
+
+    bool invalid() const {
+        return state_.invalid();
+    }
+
+    ICState& state() {
+        return state_;
+    }
+
+    // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is
+    // created since the stub is created at compile time, and we won't know the IC entry
+    // address until after compile when the JitScript is created.  This method
+    // allows these fields to be fixed up at that point.
+    void fixupICEntry(ICEntry* icEntry) {
+        MOZ_ASSERT(icEntry_ == nullptr);
+        MOZ_ASSERT(lastStubPtrAddr_ == nullptr);
+        icEntry_ = icEntry;
+        lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
+    }
+
+    // Add a new stub to the IC chain terminated by this fallback stub.
+    void addNewStub(ICStub* stub) {
+        MOZ_ASSERT(!invalid());
+        MOZ_ASSERT(*lastStubPtrAddr_ == this);
+        MOZ_ASSERT(stub->next() == nullptr);
+        stub->setNext(this);
+        *lastStubPtrAddr_ = stub;
+        lastStubPtrAddr_ = stub->addressOfNext();
+        state_.trackAttached();
+    }
+
+    ICStubConstIterator beginChainConst() const {
+        return ICStubConstIterator(icEntry_->firstStub());
+    }
+
+    ICStubIterator beginChain() {
+        return ICStubIterator(this);
+    }
+
+    bool hasStub(ICStub::Kind kind) const {
+        for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
+            if (iter->kind() == kind)
+                return true;
+        }
+        return false;
+    }
+
+    unsigned numStubsWithKind(ICStub::Kind kind) const {
+        unsigned count = 0;
+        for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
+            if (iter->kind() == kind)
+                count++;
+        }
+        return count;
+    }
+
+    void discardStubs(JSContext* cx);
+
+    void unlinkStub(Zone* zone, ICStub* prev, ICStub* stub);
+    void unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind);
+};
+
+// Base class for Trait::Regular CacheIR stubs
+class ICCacheIR_Regular : public ICStub
+{
+    const CacheIRStubInfo* stubInfo_;
+
+  public:
+    ICCacheIR_Regular(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
+      : ICStub(ICStub::CacheIR_Regular, stubCode),
+        stubInfo_(stubInfo)
+    {}
+
+    static ICCacheIR_Regular* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+                                    ICCacheIR_Regular& other);
+
+    void notePreliminaryObject() {
+        extra_ = 1;
+    }
+    bool hasPreliminaryObject() const {
+        return extra_;
+    }
+
+    const CacheIRStubInfo* stubInfo() const {
+        return stubInfo_;
+    }
+
+    uint8_t* stubDataStart();
+};
+
+// Monitored stubs are IC stubs that feed a single resulting value out to a
+// type monitor operation.
+class ICMonitoredStub : public ICStub
+{
+  protected:
+    // Pointer to the start of the type monitoring stub chain.
+    ICStub* firstMonitorStub_;
+
+    ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub);
+
+  public:
+    inline void updateFirstMonitorStub(ICStub* monitorStub) {
+        // This should only be called once: when the first optimized monitor stub
+        // is added to the type monitor IC chain.
+        MOZ_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback());
+        firstMonitorStub_ = monitorStub;
+    }
+    inline void resetFirstMonitorStub(ICStub* monitorFallback) {
+        MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback());
+        firstMonitorStub_ = monitorFallback;
+    }
+    inline ICStub* firstMonitorStub() const {
+        return firstMonitorStub_;
+    }
+
+    static inline size_t offsetOfFirstMonitorStub() {
+        return offsetof(ICMonitoredStub, firstMonitorStub_);
+    }
+};
+
+class ICCacheIR_Monitored : public ICMonitoredStub
+{
+    const CacheIRStubInfo* stubInfo_;
+
+  public:
+    ICCacheIR_Monitored(JitCode* stubCode, ICStub* firstMonitorStub,
+                        const CacheIRStubInfo* stubInfo)
+      : ICMonitoredStub(ICStub::CacheIR_Monitored, stubCode, firstMonitorStub),
+        stubInfo_(stubInfo)
+    {}
+
+    static ICCacheIR_Monitored* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+                                      ICCacheIR_Monitored& other);
+
+    void notePreliminaryObject() {
+        extra_ = 1;
+    }
+    bool hasPreliminaryObject() const {
+        return extra_;
+    }
+
+    const CacheIRStubInfo* stubInfo() const {
+        return stubInfo_;
+    }
+
+    uint8_t* stubDataStart();
+};
+
+// Updated stubs are IC stubs that use a TypeUpdate IC to track
+// the status of heap typesets that need to be updated.
+class ICUpdatedStub : public ICStub
+{
+  protected:
+    // Pointer to the start of the type updating stub chain.
+    ICStub* firstUpdateStub_;
+
+    static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+    uint32_t numOptimizedStubs_;
+
+    ICUpdatedStub(Kind kind, JitCode* stubCode)
+      : ICStub(kind, ICStub::Updated, stubCode),
+        firstUpdateStub_(nullptr),
+        numOptimizedStubs_(0)
+    {}
+
+  public:
+    MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space);
+
+    MOZ_MUST_USE bool addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
+                                            HandleObjectGroup group, HandleId id, HandleValue val);
+
+    void addOptimizedUpdateStub(ICStub* stub) {
+        if (firstUpdateStub_->isTypeUpdate_Fallback()) {
+            stub->setNext(firstUpdateStub_);
+            firstUpdateStub_ = stub;
+        } else {
+            ICStub* iter = firstUpdateStub_;
+            MOZ_ASSERT(iter->next() != nullptr);
+            while (!iter->next()->isTypeUpdate_Fallback())
+                iter = iter->next();
+            MOZ_ASSERT(iter->next()->next() == nullptr);
+            stub->setNext(iter->next());
+            iter->setNext(stub);
+        }
+
+        numOptimizedStubs_++;
+    }
+
+    inline ICStub* firstUpdateStub() const {
+        return firstUpdateStub_;
+    }
+
+    void resetUpdateStubChain(Zone* zone);
+
+    bool hasTypeUpdateStub(ICStub::Kind kind) {
+        ICStub* stub = firstUpdateStub_;
+        do {
+            if (stub->kind() == kind)
+                return true;
+
+            stub = stub->next();
+        } while (stub);
+
+        return false;
+    }
+
+    inline uint32_t numOptimizedStubs() const {
+        return numOptimizedStubs_;
+    }
+
+    static inline size_t offsetOfFirstUpdateStub() {
+        return offsetof(ICUpdatedStub, firstUpdateStub_);
+    }
+};
+
+class ICCacheIR_Updated : public ICUpdatedStub
+{
+    const CacheIRStubInfo* stubInfo_;
+    GCPtrObjectGroup updateStubGroup_;
+    GCPtrId updateStubId_;
+
+  public:
+    ICCacheIR_Updated(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
+      : ICUpdatedStub(ICStub::CacheIR_Updated, stubCode),
+        stubInfo_(stubInfo),
+        updateStubGroup_(nullptr),
+        updateStubId_(JSID_EMPTY)
+    {}
+
+    static ICCacheIR_Updated* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+                                    ICCacheIR_Updated& other);
+
+    GCPtrObjectGroup& updateStubGroup() {
+        return updateStubGroup_;
+    }
+    GCPtrId& updateStubId() {
+        return updateStubId_;
+    }
+
+    void notePreliminaryObject() {
+        extra_ = 1;
+    }
+    bool hasPreliminaryObject() const {
+        return extra_;
+    }
+
+    const CacheIRStubInfo* stubInfo() const {
+        return stubInfo_;
+    }
+
+    uint8_t* stubDataStart();
+};
+
+// Base class for stubcode compilers.
+class ICStubCompiler
+{
+    // Prevent GC in the middle of stub compilation.
+    js::gc::AutoSuppressGC suppressGC;
+
+  protected:
+    JSContext* cx;
+    ICStub::Kind kind;
+    bool inStubFrame_;
+
+#ifdef DEBUG
+    bool entersStubFrame_;
+    uint32_t framePushedAtEnterStubFrame_;
+#endif
+
+    // By default the stubcode key is just the kind.
+    virtual int32_t getKey() const {
+        return static_cast<int32_t>(kind) << 1;
+    }
+
+    virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
+    virtual void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> genCode) {}
+
+    JitCode* getStubCode();
+
+    ICStubCompiler(JSContext* cx, ICStub::Kind kind)
+      : suppressGC(cx), cx(cx), kind(kind), inStubFrame_(false)
+#ifdef DEBUG
+      , entersStubFrame_(false), framePushedAtEnterStubFrame_(0)
+#endif
+    {}
+
+    // Push a payload specialized per compiler needed to execute stubs.
+    void PushStubPayload(MacroAssembler& masm, Register scratch);
+    void pushStubPayload(MacroAssembler& masm, Register scratch);
+
+    // Emits a tail call to a VMFunction wrapper.
+    MOZ_MUST_USE bool tailCallVM(const VMFunction& fun, MacroAssembler& masm);
+
+    // Emits a normal (non-tail) call to a VMFunction wrapper.
+    MOZ_MUST_USE bool callVM(const VMFunction& fun, MacroAssembler& masm);
+
+    // A stub frame is used when a stub wants to call into the VM without
+    // performing a tail call. This is required for the return address
+    // to pc mapping to work.
+    void enterStubFrame(MacroAssembler& masm, Register scratch);
+    void assumeStubFrame();
+    void leaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false);
+
+  public:
+    static inline AllocatableGeneralRegisterSet availableGeneralRegs(size_t numInputs) {
+        AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+#if defined(JS_CODEGEN_ARM)
+        MOZ_ASSERT(!regs.has(BaselineStackReg));
+        MOZ_ASSERT(!regs.has(ICTailCallReg));
+        regs.take(BaselineSecondScratchReg);
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+        MOZ_ASSERT(!regs.has(BaselineStackReg));
+        MOZ_ASSERT(!regs.has(ICTailCallReg));
+        MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
+#elif defined(JS_CODEGEN_ARM64)
+        MOZ_ASSERT(!regs.has(PseudoStackPointer));
+        MOZ_ASSERT(!regs.has(RealStackPointer));
+        MOZ_ASSERT(!regs.has(ICTailCallReg));
+#else
+        MOZ_ASSERT(!regs.has(BaselineStackReg));
+#endif
+        regs.take(BaselineFrameReg);
+        regs.take(ICStubReg);
+#ifdef JS_CODEGEN_X64
+        regs.take(ExtractTemp0);
+        regs.take(ExtractTemp1);
+#endif
+
+        switch (numInputs) {
+          case 0:
+            break;
+          case 1:
+            regs.take(R0);
+            break;
+          case 2:
+            regs.take(R0);
+            regs.take(R1);
+            break;
+          default:
+            MOZ_CRASH("Invalid numInputs");
+        }
+
+        return regs;
+    }
+
+  protected:
+    template <typename T, typename... Args>
+    T* newStub(Args&&... args) {
+        return ICStub::New<T>(cx, std::forward<Args>(args)...);
+    }
+
+  public:
+    virtual ICStub* getStub(ICStubSpace* space) = 0;
+
+    static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* outerScript) {
+        if (makesGCCalls) {
+            return outerScript->baselineScript()->fallbackStubSpace();
+        }
+        return outerScript->zone()->jitZone()->optimizedStubSpace();
+    }
+    ICStubSpace* getStubSpace(JSScript* outerScript) {
+        return StubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind), outerScript);
+    }
+};
+
 // WarmUpCounter_Fallback
 
 // A WarmUpCounter IC chain has only the fallback stub.
 class ICWarmUpCounter_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     explicit ICWarmUpCounter_Fallback(JitCode* stubCode)
@@ -49,16 +462,436 @@ class ICWarmUpCounter_Fallback : public 
 
         ICWarmUpCounter_Fallback* getStub(ICStubSpace* space) override {
             return newStub<ICWarmUpCounter_Fallback>(space, getStubCode());
         }
     };
 };
 
 
+// Monitored fallback stubs - as the name implies.
+class ICMonitoredFallbackStub : public ICFallbackStub
+{
+  protected:
+    // Pointer to the fallback monitor stub. Created lazily by
+    // getFallbackMonitorStub if needed.
+    ICTypeMonitor_Fallback* fallbackMonitorStub_;
+
+    ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
+      : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
+        fallbackMonitorStub_(nullptr) {}
+
+  public:
+    MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, JSScript* script);
+    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                             StackTypeSet* types, HandleValue val);
+
+    ICTypeMonitor_Fallback* maybeFallbackMonitorStub() const {
+        return fallbackMonitorStub_;
+    }
+    ICTypeMonitor_Fallback* getFallbackMonitorStub(JSContext* cx, JSScript* script) {
+        if (!fallbackMonitorStub_ && !initMonitoringChain(cx, script))
+            return nullptr;
+        MOZ_ASSERT(fallbackMonitorStub_);
+        return fallbackMonitorStub_;
+    }
+
+    static inline size_t offsetOfFallbackMonitorStub() {
+        return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
+    }
+};
+
+// TypeCheckPrimitiveSetStub
+//   Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
+//   value's type falls within a set of primitive types.
+
+class TypeCheckPrimitiveSetStub : public ICStub
+{
+    friend class ICStubSpace;
+  protected:
+    inline static uint16_t TypeToFlag(JSValueType type) {
+        return 1u << static_cast<unsigned>(type);
+    }
+
+    inline static uint16_t ValidFlags() {
+        return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC);
+    }
+
+    TypeCheckPrimitiveSetStub(Kind kind, JitCode* stubCode, uint16_t flags)
+        : ICStub(kind, stubCode)
+    {
+        MOZ_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet);
+        MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
+        extra_ = flags;
+    }
+
+    TypeCheckPrimitiveSetStub* updateTypesAndCode(uint16_t flags, JitCode* code) {
+        MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
+        if (!code)
+            return nullptr;
+        extra_ = flags;
+        updateCode(code);
+        return this;
+    }
+
+  public:
+    uint16_t typeFlags() const {
+        return extra_;
+    }
+
+    bool containsType(JSValueType type) const {
+        MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
+        MOZ_ASSERT(type != JSVAL_TYPE_MAGIC);
+        return extra_ & TypeToFlag(type);
+    }
+
+    ICTypeMonitor_PrimitiveSet* toMonitorStub() {
+        return toTypeMonitor_PrimitiveSet();
+    }
+
+    ICTypeUpdate_PrimitiveSet* toUpdateStub() {
+        return toTypeUpdate_PrimitiveSet();
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        TypeCheckPrimitiveSetStub* existingStub_;
+        uint16_t flags_;
+
+        virtual int32_t getKey() const override {
+            return static_cast<int32_t>(kind) << 1 |
+                  (static_cast<int32_t>(flags_) << 17);
+        }
+
+      public:
+        Compiler(JSContext* cx, Kind kind, TypeCheckPrimitiveSetStub* existingStub,
+                 JSValueType type)
+          : ICStubCompiler(cx, kind),
+            existingStub_(existingStub),
+            flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type))
+        {
+            MOZ_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags());
+        }
+
+        TypeCheckPrimitiveSetStub* updateStub() {
+            MOZ_ASSERT(existingStub_);
+            return existingStub_->updateTypesAndCode(flags_, getStubCode());
+        }
+    };
+};
+
+// TypeMonitor
+
+// The TypeMonitor fallback stub is not always a regular fallback stub. When
+// used for monitoring the values pushed by a bytecode it doesn't hold a
+// pointer to the IC entry, but rather back to the main fallback stub for the
+// IC (from which a pointer to the IC entry can be retrieved). When monitoring
+// the types of 'this', arguments or other values with no associated IC, there
+// is no main fallback stub, and the IC entry is referenced directly.
+class ICTypeMonitor_Fallback : public ICStub
+{
+    friend class ICStubSpace;
+
+    static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+    // Pointer to the main fallback stub for the IC or to the main IC entry,
+    // depending on hasFallbackStub.
+    union {
+        ICMonitoredFallbackStub* mainFallbackStub_;
+        ICEntry* icEntry_;
+    };
+
+    // Pointer to the first monitor stub.
+    ICStub* firstMonitorStub_;
+
+    // Address of the last monitor stub's field pointing to this
+    // fallback monitor stub.  This will get updated when new
+    // monitor stubs are created and added.
+    ICStub** lastMonitorStubPtrAddr_;
+
+    // Count of optimized type monitor stubs in this chain.
+    uint32_t numOptimizedMonitorStubs_ : 7;
+
+    uint32_t invalid_ : 1;
+
+    // Whether this has a fallback stub referring to the IC entry.
+    bool hasFallbackStub_ : 1;
+
+    // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
+    // if this is monitoring the types of values pushed at some bytecode.
+    uint32_t argumentIndex_ : 23;
+
+    static const uint32_t BYTECODE_INDEX = (1 << 23) - 1;
+
+    ICTypeMonitor_Fallback(JitCode* stubCode, ICMonitoredFallbackStub* mainFallbackStub,
+                           uint32_t argumentIndex)
+      : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
+        mainFallbackStub_(mainFallbackStub),
+        firstMonitorStub_(thisFromCtor()),
+        lastMonitorStubPtrAddr_(nullptr),
+        numOptimizedMonitorStubs_(0),
+        invalid_(false),
+        hasFallbackStub_(mainFallbackStub != nullptr),
+        argumentIndex_(argumentIndex)
+    { }
+
+    ICTypeMonitor_Fallback* thisFromCtor() {
+        return this;
+    }
+
+    void addOptimizedMonitorStub(ICStub* stub) {
+        MOZ_ASSERT(!invalid());
+        stub->setNext(this);
+
+        MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
+                   (numOptimizedMonitorStubs_ || !hasFallbackStub_));
+
+        if (lastMonitorStubPtrAddr_)
+            *lastMonitorStubPtrAddr_ = stub;
+
+        if (numOptimizedMonitorStubs_ == 0) {
+            MOZ_ASSERT(firstMonitorStub_ == this);
+            firstMonitorStub_ = stub;
+        } else {
+            MOZ_ASSERT(firstMonitorStub_ != nullptr);
+        }
+
+        lastMonitorStubPtrAddr_ = stub->addressOfNext();
+        numOptimizedMonitorStubs_++;
+    }
+
+  public:
+    bool hasStub(ICStub::Kind kind) {
+        ICStub* stub = firstMonitorStub_;
+        do {
+            if (stub->kind() == kind)
+                return true;
+
+            stub = stub->next();
+        } while (stub);
+
+        return false;
+    }
+
+    inline ICFallbackStub* mainFallbackStub() const {
+        MOZ_ASSERT(hasFallbackStub_);
+        return mainFallbackStub_;
+    }
+
+    inline ICEntry* icEntry() const {
+        return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_;
+    }
+
+    inline ICStub* firstMonitorStub() const {
+        return firstMonitorStub_;
+    }
+
+    static inline size_t offsetOfFirstMonitorStub() {
+        return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_);
+    }
+
+    inline uint32_t numOptimizedMonitorStubs() const {
+        return numOptimizedMonitorStubs_;
+    }
+
+    void setInvalid() {
+        invalid_ = 1;
+    }
+
+    bool invalid() const {
+        return invalid_;
+    }
+
+    inline bool monitorsThis() const {
+        return argumentIndex_ == 0;
+    }
+
+    inline bool monitorsArgument(uint32_t* pargument) const {
+        if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) {
+            *pargument = argumentIndex_ - 1;
+            return true;
+        }
+        return false;
+    }
+
+    inline bool monitorsBytecode() const {
+        return argumentIndex_ == BYTECODE_INDEX;
+    }
+
+    // Fixup the IC entry as for a normal fallback stub, for this/arguments.
+    void fixupICEntry(ICEntry* icEntry) {
+        MOZ_ASSERT(!hasFallbackStub_);
+        MOZ_ASSERT(icEntry_ == nullptr);
+        MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
+        icEntry_ = icEntry;
+        lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
+    }
+
+    // Create a new monitor stub for the type of the given value, and
+    // add it to this chain.
+    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
+                                             StackTypeSet* types, HandleValue val);
+
+    void resetMonitorStubChain(Zone* zone);
+
+    // Compiler for this stub kind.
+    class Compiler : public ICStubCompiler {
+        ICMonitoredFallbackStub* mainFallbackStub_;
+        uint32_t argumentIndex_;
+
+      protected:
+        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+
+      public:
+        Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
+          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
+            mainFallbackStub_(mainFallbackStub),
+            argumentIndex_(BYTECODE_INDEX)
+        { }
+
+        Compiler(JSContext* cx, uint32_t argumentIndex)
+          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
+            mainFallbackStub_(nullptr),
+            argumentIndex_(argumentIndex)
+        { }
+
+        ICTypeMonitor_Fallback* getStub(ICStubSpace* space) override {
+            return newStub<ICTypeMonitor_Fallback>(space, getStubCode(), mainFallbackStub_,
+                                                       argumentIndex_);
+        }
+    };
+};
+
+class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub
+{
+    friend class ICStubSpace;
+
+    ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags)
+        : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags)
+    {}
+
+  public:
+    class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
+      protected:
+        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+
+      public:
+        Compiler(JSContext* cx, ICTypeMonitor_PrimitiveSet* existingStub,
+                 JSValueType type)
+          : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub,
+                                                type)
+        {}
+
+        ICTypeMonitor_PrimitiveSet* updateStub() {
+            TypeCheckPrimitiveSetStub* stub =
+                this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
+            if (!stub)
+                return nullptr;
+            return stub->toMonitorStub();
+        }
+
+        ICTypeMonitor_PrimitiveSet* getStub(ICStubSpace* space) override {
+            MOZ_ASSERT(!existingStub_);
+            return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
+        }
+    };
+};
+
+class ICTypeMonitor_SingleObject : public ICStub
+{
+    friend class ICStubSpace;
+
+    GCPtrObject obj_;
+
+    ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
+
+  public:
+    GCPtrObject& object() {
+        return obj_;
+    }
+
+    static size_t offsetOfObject() {
+        return offsetof(ICTypeMonitor_SingleObject, obj_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        HandleObject obj_;
+        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+
+      public:
+        Compiler(JSContext* cx, HandleObject obj)
+          : ICStubCompiler(cx, TypeMonitor_SingleObject),
+            obj_(obj)
+        { }
+
+        ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) override {
+            return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
+        }
+    };
+};
+
+class ICTypeMonitor_ObjectGroup : public ICStub
+{
+    friend class ICStubSpace;
+
+    GCPtrObjectGroup group_;
+
+    ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
+
+  public:
+    GCPtrObjectGroup& group() {
+        return group_;
+    }
+
+    static size_t offsetOfGroup() {
+        return offsetof(ICTypeMonitor_ObjectGroup, group_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        HandleObjectGroup group_;
+        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+
+      public:
+        Compiler(JSContext* cx, HandleObjectGroup group)
+          : ICStubCompiler(cx, TypeMonitor_ObjectGroup),
+            group_(group)
+        { }
+
+        ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) override {
+            return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
+        }
+    };
+};
+
+class ICTypeMonitor_AnyValue : public ICStub
+{
+    friend class ICStubSpace;
+
+    explicit ICTypeMonitor_AnyValue(JitCode* stubCode)
+      : ICStub(TypeMonitor_AnyValue, stubCode)
+    {}
+
+  public:
+    class Compiler : public ICStubCompiler {
+      protected:
+        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+
+      public:
+        explicit Compiler(JSContext* cx)
+          : ICStubCompiler(cx, TypeMonitor_AnyValue)
+        { }
+
+        ICTypeMonitor_AnyValue* getStub(ICStubSpace* space) override {
+            return newStub<ICTypeMonitor_AnyValue>(space, getStubCode());
+        }
+    };
+};
+
 // TypeUpdate
 
 extern const VMFunction DoTypeUpdateFallbackInfo;
 
 // The TypeUpdate fallback is not a regular fallback, since it just
 // forwards to a different entry point in the main fallback stub.
 class ICTypeUpdate_Fallback : public ICStub
 {
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -307,807 +307,11 @@ ICStub::trace(JSTracer* trc)
         TraceCacheIRStub(trc, this, stub->stubInfo());
         break;
       }
       default:
         break;
     }
 }
 
-void
-ICFallbackStub::unlinkStub(Zone* zone, ICStub* prev, ICStub* stub)
-{
-    MOZ_ASSERT(stub->next());
-
-    // If stub is the last optimized stub, update lastStubPtrAddr.
-    if (stub->next() == this) {
-        MOZ_ASSERT(lastStubPtrAddr_ == stub->addressOfNext());
-        if (prev)
-            lastStubPtrAddr_ = prev->addressOfNext();
-        else
-            lastStubPtrAddr_ = icEntry()->addressOfFirstStub();
-        *lastStubPtrAddr_ = this;
-    } else {
-        if (prev) {
-            MOZ_ASSERT(prev->next() == stub);
-            prev->setNext(stub->next());
-        } else {
-            MOZ_ASSERT(icEntry()->firstStub() == stub);
-            icEntry()->setFirstStub(stub->next());
-        }
-    }
-
-    state_.trackUnlinkedStub();
-
-    if (zone->needsIncrementalBarrier()) {
-        // We are removing edges from ICStub to gcthings. Perform one final trace
-        // of the stub for incremental GC, as it must know about those edges.
-        stub->trace(zone->barrierTracer());
-    }
-
-    if (stub->makesGCCalls() && stub->isMonitored()) {
-        // This stub can make calls so we can return to it if it's on the stack.
-        // We just have to reset its firstMonitorStub_ field to avoid a stale
-        // pointer when purgeOptimizedStubs destroys all optimized monitor
-        // stubs (unlinked stubs won't be updated).
-        ICTypeMonitor_Fallback* monitorFallback =
-            toMonitoredFallbackStub()->maybeFallbackMonitorStub();
-        MOZ_ASSERT(monitorFallback);
-        stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);
-    }
-
-#ifdef DEBUG
-    // Poison stub code to ensure we don't call this stub again. However, if
-    // this stub can make calls, a pointer to it may be stored in a stub frame
-    // on the stack, so we can't touch the stubCode_ or GC will crash when
-    // tracing this pointer.
-    if (!stub->makesGCCalls())
-        stub->stubCode_ = (uint8_t*)0xbad;
-#endif
-}
-
-void
-ICFallbackStub::unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind)
-{
-    for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
-        if (iter->kind() == kind)
-            iter.unlink(cx);
-    }
-}
-
-void
-ICFallbackStub::discardStubs(JSContext* cx)
-{
-    for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++)
-        iter.unlink(cx);
-}
-
-void
-ICTypeMonitor_Fallback::resetMonitorStubChain(Zone* zone)
-{
-    if (zone->needsIncrementalBarrier()) {
-        // We are removing edges from monitored stubs to gcthings (JitCode).
-        // Perform one final trace of all monitor stubs for incremental GC,
-        // as it must know about those edges.
-        for (ICStub* s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next())
-            s->trace(zone->barrierTracer());
-    }
-
-    firstMonitorStub_ = this;
-    numOptimizedMonitorStubs_ = 0;
-
-    if (hasFallbackStub_) {
-        lastMonitorStubPtrAddr_ = nullptr;
-
-        // Reset firstMonitorStub_ field of all monitored stubs.
-        for (ICStubConstIterator iter = mainFallbackStub_->beginChainConst();
-             !iter.atEnd(); iter++)
-        {
-            if (!iter->isMonitored())
-                continue;
-            iter->toMonitoredStub()->resetFirstMonitorStub(this);
-        }
-    } else {
-        icEntry_->setFirstStub(this);
-        lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
-    }
-}
-
-void
-ICUpdatedStub::resetUpdateStubChain(Zone* zone)
-{
-    while (!firstUpdateStub_->isTypeUpdate_Fallback()) {
-        if (zone->needsIncrementalBarrier()) {
-            // We are removing edges from update stubs to gcthings (JitCode).
-            // Perform one final trace of all update stubs for incremental GC,
-            // as it must know about those edges.
-            firstUpdateStub_->trace(zone->barrierTracer());
-        }
-        firstUpdateStub_ = firstUpdateStub_->next();
-    }
-
-    numOptimizedStubs_ = 0;
-}
-
-ICMonitoredStub::ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub)
-  : ICStub(kind, ICStub::Monitored, stubCode),
-    firstMonitorStub_(firstMonitorStub)
-{
-    // In order to silence Coverity - null pointer dereference checker
-    MOZ_ASSERT(firstMonitorStub_);
-    // If the first monitored stub is a ICTypeMonitor_Fallback stub, then
-    // double check that _its_ firstMonitorStub is the same as this one.
-    MOZ_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),
-                  firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
-                     firstMonitorStub_);
-}
-
-bool
-ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx, JSScript* script)
-{
-    MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
-
-    ICTypeMonitor_Fallback::Compiler compiler(cx, this);
-    ICStubSpace* space = script->baselineScript()->fallbackStubSpace();
-    ICTypeMonitor_Fallback* stub = compiler.getStub(space);
-    if (!stub)
-        return false;
-    fallbackMonitorStub_ = stub;
-    return true;
-}
-
-bool
-ICMonitoredFallbackStub::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
-                                                StackTypeSet* types, HandleValue val)
-{
-    ICTypeMonitor_Fallback* typeMonitorFallback = getFallbackMonitorStub(cx, frame->script());
-    if (!typeMonitorFallback)
-        return false;
-    return typeMonitorFallback->addMonitorStubForValue(cx, frame, types, val);
-}
-
-bool
-ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space)
-{
-    MOZ_ASSERT(firstUpdateStub_ == nullptr);
-
-    ICTypeUpdate_Fallback::Compiler compiler(cx);
-    ICTypeUpdate_Fallback* stub = compiler.getStub(space);
-    if (!stub)
-        return false;
-
-    firstUpdateStub_ = stub;
-    return true;
-}
-
-JitCode*
-ICStubCompiler::getStubCode()
-{
-    JitRealm* realm = cx->realm()->jitRealm();
-
-    // Check for existing cached stubcode.
-    uint32_t stubKey = getKey();
-    JitCode* stubCode = realm->getStubCode(stubKey);
-    if (stubCode)
-        return stubCode;
-
-    // Compile new stubcode.
-    JitContext jctx(cx, nullptr);
-    StackMacroAssembler masm;
-#ifndef JS_USE_LINK_REGISTER
-    // The first value contains the return addres,
-    // which we pull into ICTailCallReg for tail calls.
-    masm.adjustFrame(sizeof(intptr_t));
-#endif
-#ifdef JS_CODEGEN_ARM
-    masm.setSecondScratchReg(BaselineSecondScratchReg);
-#endif
-
-    if (!generateStubCode(masm))
-        return nullptr;
-    Linker linker(masm);
-    AutoFlushICache afc("getStubCode");
-    Rooted<JitCode*> newStubCode(cx, linker.newCode(cx, CodeKind::Baseline));
-    if (!newStubCode)
-        return nullptr;
-
-    // Cache newly compiled stubcode.
-    if (!realm->putStubCode(cx, stubKey, newStubCode))
-        return nullptr;
-
-    // After generating code, run postGenerateStubCode().  We must not fail
-    // after this point.
-    postGenerateStubCode(masm, newStubCode);
-
-    MOZ_ASSERT(entersStubFrame_ == ICStub::NonCacheIRStubMakesGCCalls(kind));
-    MOZ_ASSERT(!inStubFrame_);
-
-#ifdef JS_ION_PERF
-    writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC");
-#endif
-
-    return newStubCode;
-}
-
-bool
-ICStubCompiler::tailCallVM(const VMFunction& fun, MacroAssembler& masm)
-{
-    TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
-    MOZ_ASSERT(fun.expectTailCall == TailCall);
-    uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
-    EmitBaselineTailCallVM(code, masm, argSize);
-    return true;
-}
-
-bool
-ICStubCompiler::callVM(const VMFunction& fun, MacroAssembler& masm)
-{
-    MOZ_ASSERT(inStubFrame_);
-
-    TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
-    MOZ_ASSERT(fun.expectTailCall == NonTailCall);
-
-    EmitBaselineCallVM(code, masm);
-    return true;
-}
-
-void
-ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch)
-{
-    EmitBaselineEnterStubFrame(masm, scratch);
-#ifdef DEBUG
-    framePushedAtEnterStubFrame_ = masm.framePushed();
-#endif
-
-    MOZ_ASSERT(!inStubFrame_);
-    inStubFrame_ = true;
-
-#ifdef DEBUG
-    entersStubFrame_ = true;
-#endif
-}
-
-void
-ICStubCompiler::assumeStubFrame()
-{
-    MOZ_ASSERT(!inStubFrame_);
-    inStubFrame_ = true;
-
-#ifdef DEBUG
-    entersStubFrame_ = true;
-
-    // |framePushed| isn't tracked precisely in ICStubs, so simply assume it to
-    // be STUB_FRAME_SIZE so that assertions don't fail in leaveStubFrame.
-    framePushedAtEnterStubFrame_ = STUB_FRAME_SIZE;
-#endif
-}
-
-void
-ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon)
-{
-    MOZ_ASSERT(entersStubFrame_ && inStubFrame_);
-    inStubFrame_ = false;
-    
-#ifdef DEBUG
-    masm.setFramePushed(framePushedAtEnterStubFrame_);
-    if (calledIntoIon)
-        masm.adjustFrame(sizeof(intptr_t)); // Calls into ion have this extra.
-#endif
-    EmitBaselineLeaveStubFrame(masm, calledIntoIon);
-}
-
-void
-ICStubCompiler::pushStubPayload(MacroAssembler& masm, Register scratch)
-{
-    if (inStubFrame_) {
-        masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
-        masm.pushBaselineFramePtr(scratch, scratch);
-    } else {
-        masm.pushBaselineFramePtr(BaselineFrameReg, scratch);
-    }
-}
-
-void
-ICStubCompiler::PushStubPayload(MacroAssembler& masm, Register scratch)
-{
-    pushStubPayload(masm, scratch);
-    masm.adjustFrame(sizeof(intptr_t));
-}
-
-//
-void
-BaselineScript::noteAccessedGetter(uint32_t pcOffset)
-{
-    ICEntry& entry = icEntryFromPCOffset(pcOffset);
-    ICFallbackStub* stub = entry.fallbackStub();
-
-    if (stub->isGetProp_Fallback())
-        stub->toGetProp_Fallback()->noteAccessedGetter();
-}
-
-// TypeMonitor_Fallback
-//
-
-bool
-ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
-                                               StackTypeSet* types, HandleValue val)
-{
-    MOZ_ASSERT(types);
-
-    // Don't attach too many SingleObject/ObjectGroup stubs. If the value is a
-    // primitive or if we will attach an any-object stub, we can handle this
-    // with a single PrimitiveSet or AnyValue stub so we always optimize.
-    if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS &&
-        val.isObject() &&
-        !types->unknownObject())
-    {
-        return true;
-    }
-
-    bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
-    MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
-
-    if (types->unknown()) {
-        // The TypeSet got marked as unknown so attach a stub that always
-        // succeeds.
-
-        // Check for existing TypeMonitor_AnyValue stubs.
-        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
-            if (iter->isTypeMonitor_AnyValue())
-                return true;
-        }
-
-        // Discard existing stubs.
-        resetMonitorStubChain(cx->zone());
-        wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr);
-
-        ICTypeMonitor_AnyValue::Compiler compiler(cx);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
-        if (!stub) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for any value", stub);
-        addOptimizedMonitorStub(stub);
-
-    } else if (val.isPrimitive() || types->unknownObject()) {
-        if (val.isMagic(JS_UNINITIALIZED_LEXICAL))
-            return true;
-        MOZ_ASSERT(!val.isMagic());
-        JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
-
-        // Check for existing TypeMonitor stub.
-        ICTypeMonitor_PrimitiveSet* existingStub = nullptr;
-        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
-            if (iter->isTypeMonitor_PrimitiveSet()) {
-                existingStub = iter->toTypeMonitor_PrimitiveSet();
-                if (existingStub->containsType(type))
-                    return true;
-            }
-        }
-
-        if (val.isObject()) {
-            // Check for existing SingleObject/ObjectGroup stubs and discard
-            // stubs if we find one. Ideally we would discard just these stubs,
-            // but unlinking individual type monitor stubs is somewhat
-            // complicated.
-            MOZ_ASSERT(types->unknownObject());
-            bool hasObjectStubs = false;
-            for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
-                if (iter->isTypeMonitor_SingleObject() || iter->isTypeMonitor_ObjectGroup()) {
-                    hasObjectStubs = true;
-                    break;
-                }
-            }
-            if (hasObjectStubs) {
-                resetMonitorStubChain(cx->zone());
-                wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr);
-                existingStub = nullptr;
-            }
-        }
-
-        ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
-        ICStub* stub = existingStub
-                       ? compiler.updateStub()
-                       : compiler.getStub(compiler.getStubSpace(frame->script()));
-        if (!stub) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        JitSpew(JitSpew_BaselineIC, "  %s TypeMonitor stub %p for primitive type %d",
-                existingStub ? "Modified existing" : "Created new", stub, type);
-
-        if (!existingStub) {
-            MOZ_ASSERT(!hasStub(TypeMonitor_PrimitiveSet));
-            addOptimizedMonitorStub(stub);
-        }
-
-    } else if (val.toObject().isSingleton()) {
-        RootedObject obj(cx, &val.toObject());
-
-        // Check for existing TypeMonitor stub.
-        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
-            if (iter->isTypeMonitor_SingleObject() &&
-                iter->toTypeMonitor_SingleObject()->object() == obj)
-            {
-                return true;
-            }
-        }
-
-        ICTypeMonitor_SingleObject::Compiler compiler(cx, obj);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
-        if (!stub) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for singleton %p",
-                stub, obj.get());
-
-        addOptimizedMonitorStub(stub);
-
-    } else {
-        RootedObjectGroup group(cx, val.toObject().group());
-
-        // Check for existing TypeMonitor stub.
-        for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) {
-            if (iter->isTypeMonitor_ObjectGroup() &&
-                iter->toTypeMonitor_ObjectGroup()->group() == group)
-            {
-                return true;
-            }
-        }
-
-        ICTypeMonitor_ObjectGroup::Compiler compiler(cx, group);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script()));
-        if (!stub) {
-            ReportOutOfMemory(cx);
-            return false;
-        }
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeMonitor stub %p for ObjectGroup %p",
-                stub, group.get());
-
-        addOptimizedMonitorStub(stub);
-    }
-
-    bool firstMonitorStubAdded = wasDetachedMonitorChain && (numOptimizedMonitorStubs_ > 0);
-
-    if (firstMonitorStubAdded) {
-        // Was an empty monitor chain before, but a new stub was added.  This is the
-        // only time that any main stubs' firstMonitorStub fields need to be updated to
-        // refer to the newly added monitor stub.
-        ICStub* firstStub = mainFallbackStub_->icEntry()->firstStub();
-        for (ICStubConstIterator iter(firstStub); !iter.atEnd(); iter++) {
-            // Non-monitored stubs are used if the result has always the same type,
-            // e.g. a StringLength stub will always return int32.
-            if (!iter->isMonitored())
-                continue;
-
-            // Since we just added the first optimized monitoring stub, any
-            // existing main stub's |firstMonitorStub| MUST be pointing to the fallback
-            // monitor stub (i.e. this stub).
-            MOZ_ASSERT(iter->toMonitoredStub()->firstMonitorStub() == this);
-            iter->toMonitoredStub()->updateFirstMonitorStub(firstMonitorStub_);
-        }
-    }
-
-    return true;
-}
-
-static bool
-DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallback* stub,
-                      HandleValue value, MutableHandleValue res)
-{
-    JSScript* script = frame->script();
-    jsbytecode* pc = stub->icEntry()->pc(script);
-    TypeFallbackICSpew(cx, stub, "TypeMonitor");
-
-    // Copy input value to res.
-    res.set(value);
-
-    if (MOZ_UNLIKELY(value.isMagic())) {
-        // It's possible that we arrived here from bailing out of Ion, and that
-        // Ion proved that the value is dead and optimized out. In such cases,
-        // do nothing. However, it's also possible that we have an uninitialized
-        // this, in which case we should not look for other magic values.
-
-        if (value.whyMagic() == JS_OPTIMIZED_OUT) {
-            MOZ_ASSERT(!stub->monitorsThis());
-            return true;
-        }
-
-        // In derived class constructors (including nested arrows/eval), the
-        // |this| argument or GETALIASEDVAR can return the magic TDZ value.
-        MOZ_ASSERT(value.isMagic(JS_UNINITIALIZED_LEXICAL));
-        MOZ_ASSERT(frame->isFunctionFrame() || frame->isEvalFrame());
-        MOZ_ASSERT(stub->monitorsThis() ||
-                   *GetNextPc(pc) == JSOP_CHECKTHIS ||
-                   *GetNextPc(pc) == JSOP_CHECKTHISREINIT ||
-                   *GetNextPc(pc) == JSOP_CHECKRETURN);
-        if (stub->monitorsThis())
-            TypeScript::SetThis(cx, script, TypeSet::UnknownType());
-        else
-            TypeScript::Monitor(cx, script, pc, TypeSet::UnknownType());
-        return true;
-    }
-
-    StackTypeSet* types;
-    uint32_t argument;
-    if (stub->monitorsArgument(&argument)) {
-        MOZ_ASSERT(pc == script->code());
-        types = TypeScript::ArgTypes(script, argument);
-        TypeScript::SetArgument(cx, script, argument, value);
-    } else if (stub->monitorsThis()) {
-        MOZ_ASSERT(pc == script->code());
-        types = TypeScript::ThisTypes(script);
-        TypeScript::SetThis(cx, script, value);
-    } else {
-        types = TypeScript::BytecodeTypes(script, pc);
-        TypeScript::Monitor(cx, script, pc, types, value);
-    }
-
-    if (MOZ_UNLIKELY(stub->invalid()))
-        return true;
-
-    return stub->addMonitorStubForValue(cx, frame, types, value);
-}
-
-typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*,
-                                        HandleValue, MutableHandleValue);
-static const VMFunction DoTypeMonitorFallbackInfo =
-    FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback, "DoTypeMonitorFallback",
-                                          TailCall);
-
-bool
-ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(R0 == JSReturnOperand);
-
-    // Restore the tail call register.
-    EmitRestoreTailCallReg(masm);
-
-    masm.pushValue(R0);
-    masm.push(ICStubReg);
-    masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
-
-    return tailCallVM(DoTypeMonitorFallbackInfo, masm);
-}
-
-bool
-ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label success;
-    if ((flags_ & TypeToFlag(JSVAL_TYPE_INT32)) && !(flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE)))
-        masm.branchTestInt32(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE))
-        masm.branchTestNumber(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_UNDEFINED))
-        masm.branchTestUndefined(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_BOOLEAN))
-        masm.branchTestBoolean(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
-        masm.branchTestString(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_SYMBOL))
-        masm.branchTestSymbol(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
-        masm.branchTestObject(Assembler::Equal, R0, &success);
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
-        masm.branchTestNull(Assembler::Equal, R0, &success);
-
-    EmitStubGuardFailure(masm);
-
-    masm.bind(&success);
-    EmitReturnFromIC(masm);
-    return true;
-}
-
-static void
-MaybeWorkAroundAmdBug(MacroAssembler& masm)
-{
-    // Attempt to work around an AMD bug (see bug 1034706 and bug 1281759), by
-    // inserting 32-bytes of NOPs.
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    if (CPUInfo::NeedAmdBugWorkaround()) {
-        masm.nop(9);
-        masm.nop(9);
-        masm.nop(9);
-        masm.nop(5);
-    }
-#endif
-}
-
-bool
-ICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label failure;
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-    MaybeWorkAroundAmdBug(masm);
-
-    // Guard on the object's identity.
-    Register obj = masm.extractObject(R0, ExtractTemp0);
-    Address expectedObject(ICStubReg, ICTypeMonitor_SingleObject::offsetOfObject());
-    masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure);
-    MaybeWorkAroundAmdBug(masm);
-
-    EmitReturnFromIC(masm);
-    MaybeWorkAroundAmdBug(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
-ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    Label failure;
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-    MaybeWorkAroundAmdBug(masm);
-
-    // Guard on the object's ObjectGroup. No Spectre mitigations are needed
-    // here: we're just recording type information for Ion compilation and
-    // it's safe to speculatively return.
-    Register obj = masm.extractObject(R0, ExtractTemp0);
-    Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
-    masm.branchTestObjGroupNoSpectreMitigations(Assembler::NotEqual, obj, expectedGroup,
-                                                R1.scratchReg(), &failure);
-    MaybeWorkAroundAmdBug(masm);
-
-    EmitReturnFromIC(masm);
-    MaybeWorkAroundAmdBug(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
-ICTypeMonitor_AnyValue::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    EmitReturnFromIC(masm);
-    return true;
-}
-
-bool
-ICUpdatedStub::addUpdateStubForValue(JSContext* cx, HandleScript outerScript, HandleObject obj,
-                                     HandleObjectGroup group, HandleId id, HandleValue val)
-{
-    EnsureTrackPropertyTypes(cx, obj, id);
-
-    // Make sure that undefined values are explicitly included in the property
-    // types for an object if generating a stub to write an undefined value.
-    if (val.isUndefined() && CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
-        MOZ_ASSERT(obj->group() == group);
-        AddTypePropertyId(cx, obj, id, val);
-    }
-
-    bool unknown = false, unknownObject = false;
-    AutoSweepObjectGroup sweep(group);
-    if (group->unknownProperties(sweep)) {
-        unknown = unknownObject = true;
-    } else {
-        if (HeapTypeSet* types = group->maybeGetProperty(sweep, id)) {
-            unknown = types->unknown();
-            unknownObject = types->unknownObject();
-        } else {
-            // We don't record null/undefined types for certain TypedObject
-            // properties. In these cases |types| is allowed to be nullptr
-            // without implying unknown types. See DoTypeUpdateFallback.
-            MOZ_ASSERT(obj->is<TypedObject>());
-            MOZ_ASSERT(val.isNullOrUndefined());
-        }
-    }
-    MOZ_ASSERT_IF(unknown, unknownObject);
-
-    // Don't attach too many SingleObject/ObjectGroup stubs unless we can
-    // replace them with a single PrimitiveSet or AnyValue stub.
-    if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS &&
-        val.isObject() &&
-        !unknownObject)
-    {
-        return true;
-    }
-
-    if (unknown) {
-        // Attach a stub that always succeeds. We should not have a
-        // TypeUpdate_AnyValue stub yet.
-        MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_AnyValue));
-
-        // Discard existing stubs.
-        resetUpdateStubChain(cx->zone());
-
-        ICTypeUpdate_AnyValue::Compiler compiler(cx);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
-        if (!stub)
-            return false;
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for any value", stub);
-        addOptimizedUpdateStub(stub);
-
-    } else if (val.isPrimitive() || unknownObject) {
-        JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
-
-        // Check for existing TypeUpdate stub.
-        ICTypeUpdate_PrimitiveSet* existingStub = nullptr;
-        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
-            if (iter->isTypeUpdate_PrimitiveSet()) {
-                existingStub = iter->toTypeUpdate_PrimitiveSet();
-                MOZ_ASSERT(!existingStub->containsType(type));
-            }
-        }
-
-        if (val.isObject()) {
-            // Discard existing ObjectGroup/SingleObject stubs.
-            resetUpdateStubChain(cx->zone());
-            if (existingStub)
-                addOptimizedUpdateStub(existingStub);
-        }
-
-        ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type);
-        ICStub* stub = existingStub ? compiler.updateStub()
-                                    : compiler.getStub(compiler.getStubSpace(outerScript));
-        if (!stub)
-            return false;
-        if (!existingStub) {
-            MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_PrimitiveSet));
-            addOptimizedUpdateStub(stub);
-        }
-
-        JitSpew(JitSpew_BaselineIC, "  %s TypeUpdate stub %p for primitive type %d",
-                existingStub ? "Modified existing" : "Created new", stub, type);
-
-    } else if (val.toObject().isSingleton()) {
-        RootedObject obj(cx, &val.toObject());
-
-#ifdef DEBUG
-        // We should not have a stub for this object.
-        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
-            MOZ_ASSERT_IF(iter->isTypeUpdate_SingleObject(),
-                          iter->toTypeUpdate_SingleObject()->object() != obj);
-        }
-#endif
-
-        ICTypeUpdate_SingleObject::Compiler compiler(cx, obj);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
-        if (!stub)
-            return false;
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for singleton %p", stub, obj.get());
-
-        addOptimizedUpdateStub(stub);
-
-    } else {
-        RootedObjectGroup group(cx, val.toObject().group());
-
-#ifdef DEBUG
-        // We should not have a stub for this group.
-        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
-            MOZ_ASSERT_IF(iter->isTypeUpdate_ObjectGroup(),
-                          iter->toTypeUpdate_ObjectGroup()->group() != group);
-        }
-#endif
-
-        ICTypeUpdate_ObjectGroup::Compiler compiler(cx, group);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript));
-        if (!stub)
-            return false;
-
-        JitSpew(JitSpew_BaselineIC, "  Added TypeUpdate stub %p for ObjectGroup %p",
-                stub, group.get());
-
-        addOptimizedUpdateStub(stub);
-    }
-
-    return true;
-}
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -689,845 +689,12 @@ class ICStub
     // that these do not get purged, all stubs that can make calls are allocated
     // in the fallback stub space.
     bool allocatedInFallbackSpace() const {
         MOZ_ASSERT(next());
         return makesGCCalls();
     }
 };
 
-class ICFallbackStub : public ICStub
-{
-    friend class ICStubConstIterator;
-  protected:
-    // Fallback stubs need these fields to easily add new stubs to
-    // the linked list of stubs for an IC.
-
-    // The IC entry for this linked list of stubs.
-    ICEntry* icEntry_;
-
-    // The number of stubs kept in the IC entry.
-    ICState state_;
-
-    // A pointer to the location stub pointer that needs to be
-    // changed to add a new "last" stub immediately before the fallback
-    // stub.  This'll start out pointing to the icEntry's "firstStub_"
-    // field, and as new stubs are added, it'll point to the current
-    // last stub's "next_" field.
-    ICStub** lastStubPtrAddr_;
-
-    ICFallbackStub(Kind kind, JitCode* stubCode)
-      : ICStub(kind, ICStub::Fallback, stubCode),
-        icEntry_(nullptr),
-        state_(),
-        lastStubPtrAddr_(nullptr) {}
-
-    ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
-      : ICStub(kind, trait, stubCode),
-        icEntry_(nullptr),
-        state_(),
-        lastStubPtrAddr_(nullptr)
-    {
-        MOZ_ASSERT(trait == ICStub::Fallback ||
-                   trait == ICStub::MonitoredFallback);
-    }
-
-  public:
-    inline ICEntry* icEntry() const {
-        return icEntry_;
-    }
-
-    inline size_t numOptimizedStubs() const {
-        return state_.numOptimizedStubs();
-    }
-
-    void setInvalid() {
-        state_.setInvalid();
-    }
-
-    bool invalid() const {
-        return state_.invalid();
-    }
-
-    ICState& state() {
-        return state_;
-    }
-
-    // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is
-    // created since the stub is created at compile time, and we won't know the IC entry
-    // address until after compile when the JitScript is created.  This method
-    // allows these fields to be fixed up at that point.
-    void fixupICEntry(ICEntry* icEntry) {
-        MOZ_ASSERT(icEntry_ == nullptr);
-        MOZ_ASSERT(lastStubPtrAddr_ == nullptr);
-        icEntry_ = icEntry;
-        lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
-    }
-
-    // Add a new stub to the IC chain terminated by this fallback stub.
-    void addNewStub(ICStub* stub) {
-        MOZ_ASSERT(!invalid());
-        MOZ_ASSERT(*lastStubPtrAddr_ == this);
-        MOZ_ASSERT(stub->next() == nullptr);
-        stub->setNext(this);
-        *lastStubPtrAddr_ = stub;
-        lastStubPtrAddr_ = stub->addressOfNext();
-        state_.trackAttached();
-    }
-
-    ICStubConstIterator beginChainConst() const {
-        return ICStubConstIterator(icEntry_->firstStub());
-    }
-
-    ICStubIterator beginChain() {
-        return ICStubIterator(this);
-    }
-
-    bool hasStub(ICStub::Kind kind) const {
-        for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
-            if (iter->kind() == kind)
-                return true;
-        }
-        return false;
-    }
-
-    unsigned numStubsWithKind(ICStub::Kind kind) const {
-        unsigned count = 0;
-        for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
-            if (iter->kind() == kind)
-                count++;
-        }
-        return count;
-    }
-
-    void discardStubs(JSContext* cx);
-
-    void unlinkStub(Zone* zone, ICStub* prev, ICStub* stub);
-    void unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind);
-};
-
-// Base class for Trait::Regular CacheIR stubs
-class ICCacheIR_Regular : public ICStub
-{
-    const CacheIRStubInfo* stubInfo_;
-
-  public:
-    ICCacheIR_Regular(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
-      : ICStub(ICStub::CacheIR_Regular, stubCode),
-        stubInfo_(stubInfo)
-    {}
-
-    static ICCacheIR_Regular* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                    ICCacheIR_Regular& other);
-
-    void notePreliminaryObject() {
-        extra_ = 1;
-    }
-    bool hasPreliminaryObject() const {
-        return extra_;
-    }
-
-    const CacheIRStubInfo* stubInfo() const {
-        return stubInfo_;
-    }
-
-    uint8_t* stubDataStart();
-};
-
-// Monitored stubs are IC stubs that feed a single resulting value out to a
-// type monitor operation.
-class ICMonitoredStub : public ICStub
-{
-  protected:
-    // Pointer to the start of the type monitoring stub chain.
-    ICStub* firstMonitorStub_;
-
-    ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub);
-
-  public:
-    inline void updateFirstMonitorStub(ICStub* monitorStub) {
-        // This should only be called once: when the first optimized monitor stub
-        // is added to the type monitor IC chain.
-        MOZ_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback());
-        firstMonitorStub_ = monitorStub;
-    }
-    inline void resetFirstMonitorStub(ICStub* monitorFallback) {
-        MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback());
-        firstMonitorStub_ = monitorFallback;
-    }
-    inline ICStub* firstMonitorStub() const {
-        return firstMonitorStub_;
-    }
-
-    static inline size_t offsetOfFirstMonitorStub() {
-        return offsetof(ICMonitoredStub, firstMonitorStub_);
-    }
-};
-
-class ICCacheIR_Monitored : public ICMonitoredStub
-{
-    const CacheIRStubInfo* stubInfo_;
-
-  public:
-    ICCacheIR_Monitored(JitCode* stubCode, ICStub* firstMonitorStub,
-                        const CacheIRStubInfo* stubInfo)
-      : ICMonitoredStub(ICStub::CacheIR_Monitored, stubCode, firstMonitorStub),
-        stubInfo_(stubInfo)
-    {}
-
-    static ICCacheIR_Monitored* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                      ICCacheIR_Monitored& other);
-
-    void notePreliminaryObject() {
-        extra_ = 1;
-    }
-    bool hasPreliminaryObject() const {
-        return extra_;
-    }
-
-    const CacheIRStubInfo* stubInfo() const {
-        return stubInfo_;
-    }
-
-    uint8_t* stubDataStart();
-};
-
-// Updated stubs are IC stubs that use a TypeUpdate IC to track
-// the status of heap typesets that need to be updated.
-class ICUpdatedStub : public ICStub
-{
-  protected:
-    // Pointer to the start of the type updating stub chain.
-    ICStub* firstUpdateStub_;
-
-    static const uint32_t MAX_OPTIMIZED_STUBS = 8;
-    uint32_t numOptimizedStubs_;
-
-    ICUpdatedStub(Kind kind, JitCode* stubCode)
-      : ICStub(kind, ICStub::Updated, stubCode),
-        firstUpdateStub_(nullptr),
-        numOptimizedStubs_(0)
-    {}
-
-  public:
-    MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space);
-
-    MOZ_MUST_USE bool addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
-                                            HandleObjectGroup group, HandleId id, HandleValue val);
-
-    void addOptimizedUpdateStub(ICStub* stub) {
-        if (firstUpdateStub_->isTypeUpdate_Fallback()) {
-            stub->setNext(firstUpdateStub_);
-            firstUpdateStub_ = stub;
-        } else {
-            ICStub* iter = firstUpdateStub_;
-            MOZ_ASSERT(iter->next() != nullptr);
-            while (!iter->next()->isTypeUpdate_Fallback())
-                iter = iter->next();
-            MOZ_ASSERT(iter->next()->next() == nullptr);
-            stub->setNext(iter->next());
-            iter->setNext(stub);
-        }
-
-        numOptimizedStubs_++;
-    }
-
-    inline ICStub* firstUpdateStub() const {
-        return firstUpdateStub_;
-    }
-
-    void resetUpdateStubChain(Zone* zone);
-
-    bool hasTypeUpdateStub(ICStub::Kind kind) {
-        ICStub* stub = firstUpdateStub_;
-        do {
-            if (stub->kind() == kind)
-                return true;
-
-            stub = stub->next();
-        } while (stub);
-
-        return false;
-    }
-
-    inline uint32_t numOptimizedStubs() const {
-        return numOptimizedStubs_;
-    }
-
-    static inline size_t offsetOfFirstUpdateStub() {
-        return offsetof(ICUpdatedStub, firstUpdateStub_);
-    }
-};
-
-class ICCacheIR_Updated : public ICUpdatedStub
-{
-    const CacheIRStubInfo* stubInfo_;
-    GCPtrObjectGroup updateStubGroup_;
-    GCPtrId updateStubId_;
-
-  public:
-    ICCacheIR_Updated(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
-      : ICUpdatedStub(ICStub::CacheIR_Updated, stubCode),
-        stubInfo_(stubInfo),
-        updateStubGroup_(nullptr),
-        updateStubId_(JSID_EMPTY)
-    {}
-
-    static ICCacheIR_Updated* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
-                                    ICCacheIR_Updated& other);
-
-    GCPtrObjectGroup& updateStubGroup() {
-        return updateStubGroup_;
-    }
-    GCPtrId& updateStubId() {
-        return updateStubId_;
-    }
-
-    void notePreliminaryObject() {
-        extra_ = 1;
-    }
-    bool hasPreliminaryObject() const {
-        return extra_;
-    }
-
-    const CacheIRStubInfo* stubInfo() const {
-        return stubInfo_;
-    }
-
-    uint8_t* stubDataStart();
-};
-
-// Base class for stubcode compilers.
-class ICStubCompiler
-{
-    // Prevent GC in the middle of stub compilation.
-    js::gc::AutoSuppressGC suppressGC;
-
-  protected:
-    JSContext* cx;
-    ICStub::Kind kind;
-    bool inStubFrame_;
-
-#ifdef DEBUG
-    bool entersStubFrame_;
-    uint32_t framePushedAtEnterStubFrame_;
-#endif
-
-    // By default the stubcode key is just the kind.
-    virtual int32_t getKey() const {
-        return (static_cast<int32_t>(kind) << 1);
-    }
-
-    virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
-    virtual void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> genCode) {}
-
-    JitCode* getStubCode();
-
-    ICStubCompiler(JSContext* cx, ICStub::Kind kind)
-      : suppressGC(cx), cx(cx), kind(kind), inStubFrame_(false)
-#ifdef DEBUG
-      , entersStubFrame_(false), framePushedAtEnterStubFrame_(0)
-#endif
-    {}
-
-    // Push a payload specialized per compiler needed to execute stubs.
-    void PushStubPayload(MacroAssembler& masm, Register scratch);
-    void pushStubPayload(MacroAssembler& masm, Register scratch);
-
-    // Emits a tail call to a VMFunction wrapper.
-    MOZ_MUST_USE bool tailCallVM(const VMFunction& fun, MacroAssembler& masm);
-
-    // Emits a normal (non-tail) call to a VMFunction wrapper.
-    MOZ_MUST_USE bool callVM(const VMFunction& fun, MacroAssembler& masm);
-
-    // A stub frame is used when a stub wants to call into the VM without
-    // performing a tail call. This is required for the return address
-    // to pc mapping to work.
-    void enterStubFrame(MacroAssembler& masm, Register scratch);
-    void assumeStubFrame();
-    void leaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false);
-
-  public:
-    static inline AllocatableGeneralRegisterSet availableGeneralRegs(size_t numInputs) {
-        AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
-#if defined(JS_CODEGEN_ARM)
-        MOZ_ASSERT(!regs.has(BaselineStackReg));
-        MOZ_ASSERT(!regs.has(ICTailCallReg));
-        regs.take(BaselineSecondScratchReg);
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        MOZ_ASSERT(!regs.has(BaselineStackReg));
-        MOZ_ASSERT(!regs.has(ICTailCallReg));
-        MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
-#elif defined(JS_CODEGEN_ARM64)
-        MOZ_ASSERT(!regs.has(PseudoStackPointer));
-        MOZ_ASSERT(!regs.has(RealStackPointer));
-        MOZ_ASSERT(!regs.has(ICTailCallReg));
-#else
-        MOZ_ASSERT(!regs.has(BaselineStackReg));
-#endif
-        regs.take(BaselineFrameReg);
-        regs.take(ICStubReg);
-#ifdef JS_CODEGEN_X64
-        regs.take(ExtractTemp0);
-        regs.take(ExtractTemp1);
-#endif
-
-        switch (numInputs) {
-          case 0:
-            break;
-          case 1:
-            regs.take(R0);
-            break;
-          case 2:
-            regs.take(R0);
-            regs.take(R1);
-            break;
-          default:
-            MOZ_CRASH("Invalid numInputs");
-        }
-
-        return regs;
-    }
-
-  protected:
-    template <typename T, typename... Args>
-    T* newStub(Args&&... args) {
-        return ICStub::New<T>(cx, std::forward<Args>(args)...);
-    }
-
-  public:
-    virtual ICStub* getStub(ICStubSpace* space) = 0;
-
-    static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* outerScript) {
-        if (makesGCCalls) {
-            return outerScript->baselineScript()->fallbackStubSpace();
-        }
-        return outerScript->zone()->jitZone()->optimizedStubSpace();
-    }
-    ICStubSpace* getStubSpace(JSScript* outerScript) {
-        return StubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind), outerScript);
-    }
-};
-
-// Monitored fallback stubs - as the name implies.
-class ICMonitoredFallbackStub : public ICFallbackStub
-{
-  protected:
-    // Pointer to the fallback monitor stub. Created lazily by
-    // getFallbackMonitorStub if needed.
-    ICTypeMonitor_Fallback* fallbackMonitorStub_;
-
-    ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
-      : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
-        fallbackMonitorStub_(nullptr) {}
-
-  public:
-    MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, JSScript* script);
-    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
-                                             StackTypeSet* types, HandleValue val);
-
-    ICTypeMonitor_Fallback* maybeFallbackMonitorStub() const {
-        return fallbackMonitorStub_;
-    }
-    ICTypeMonitor_Fallback* getFallbackMonitorStub(JSContext* cx, JSScript* script) {
-        if (!fallbackMonitorStub_ && !initMonitoringChain(cx, script))
-            return nullptr;
-        MOZ_ASSERT(fallbackMonitorStub_);
-        return fallbackMonitorStub_;
-    }
-
-    static inline size_t offsetOfFallbackMonitorStub() {
-        return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
-    }
-};
-
-// TypeCheckPrimitiveSetStub
-//   Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
-//   value's type falls within a set of primitive types.
-
-class TypeCheckPrimitiveSetStub : public ICStub
-{
-    friend class ICStubSpace;
-  protected:
-    inline static uint16_t TypeToFlag(JSValueType type) {
-        return 1u << static_cast<unsigned>(type);
-    }
-
-    inline static uint16_t ValidFlags() {
-        return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC);
-    }
-
-    TypeCheckPrimitiveSetStub(Kind kind, JitCode* stubCode, uint16_t flags)
-        : ICStub(kind, stubCode)
-    {
-        MOZ_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet);
-        MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
-        extra_ = flags;
-    }
-
-    TypeCheckPrimitiveSetStub* updateTypesAndCode(uint16_t flags, JitCode* code) {
-        MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
-        if (!code)
-            return nullptr;
-        extra_ = flags;
-        updateCode(code);
-        return this;
-    }
-
-  public:
-    uint16_t typeFlags() const {
-        return extra_;
-    }
-
-    bool containsType(JSValueType type) const {
-        MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
-        MOZ_ASSERT(type != JSVAL_TYPE_MAGIC);
-        return extra_ & TypeToFlag(type);
-    }
-
-    ICTypeMonitor_PrimitiveSet* toMonitorStub() {
-        return toTypeMonitor_PrimitiveSet();
-    }
-
-    ICTypeUpdate_PrimitiveSet* toUpdateStub() {
-        return toTypeUpdate_PrimitiveSet();
-    }
-
-    class Compiler : public ICStubCompiler {
-      protected:
-        TypeCheckPrimitiveSetStub* existingStub_;
-        uint16_t flags_;
-
-        virtual int32_t getKey() const override {
-            return static_cast<int32_t>(kind) << 1 |
-                  (static_cast<int32_t>(flags_) << 17);
-        }
-
-      public:
-        Compiler(JSContext* cx, Kind kind, TypeCheckPrimitiveSetStub* existingStub,
-                 JSValueType type)
-          : ICStubCompiler(cx, kind),
-            existingStub_(existingStub),
-            flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type))
-        {
-            MOZ_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags());
-        }
-
-        TypeCheckPrimitiveSetStub* updateStub() {
-            MOZ_ASSERT(existingStub_);
-            return existingStub_->updateTypesAndCode(flags_, getStubCode());
-        }
-    };
-};
-
-// TypeMonitor
-
-// The TypeMonitor fallback stub is not always a regular fallback stub. When
-// used for monitoring the values pushed by a bytecode it doesn't hold a
-// pointer to the IC entry, but rather back to the main fallback stub for the
-// IC (from which a pointer to the IC entry can be retrieved). When monitoring
-// the types of 'this', arguments or other values with no associated IC, there
-// is no main fallback stub, and the IC entry is referenced directly.
-class ICTypeMonitor_Fallback : public ICStub
-{
-    friend class ICStubSpace;
-
-    static const uint32_t MAX_OPTIMIZED_STUBS = 8;
-
-    // Pointer to the main fallback stub for the IC or to the main IC entry,
-    // depending on hasFallbackStub.
-    union {
-        ICMonitoredFallbackStub* mainFallbackStub_;
-        ICEntry* icEntry_;
-    };
-
-    // Pointer to the first monitor stub.
-    ICStub* firstMonitorStub_;
-
-    // Address of the last monitor stub's field pointing to this
-    // fallback monitor stub.  This will get updated when new
-    // monitor stubs are created and added.
-    ICStub** lastMonitorStubPtrAddr_;
-
-    // Count of optimized type monitor stubs in this chain.
-    uint32_t numOptimizedMonitorStubs_ : 7;
-
-    uint32_t invalid_ : 1;
-
-    // Whether this has a fallback stub referring to the IC entry.
-    bool hasFallbackStub_ : 1;
-
-    // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
-    // if this is monitoring the types of values pushed at some bytecode.
-    uint32_t argumentIndex_ : 23;
-
-    static const uint32_t BYTECODE_INDEX = (1 << 23) - 1;
-
-    ICTypeMonitor_Fallback(JitCode* stubCode, ICMonitoredFallbackStub* mainFallbackStub,
-                           uint32_t argumentIndex)
-      : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
-        mainFallbackStub_(mainFallbackStub),
-        firstMonitorStub_(thisFromCtor()),
-        lastMonitorStubPtrAddr_(nullptr),
-        numOptimizedMonitorStubs_(0),
-        invalid_(false),
-        hasFallbackStub_(mainFallbackStub != nullptr),
-        argumentIndex_(argumentIndex)
-    { }
-
-    ICTypeMonitor_Fallback* thisFromCtor() {
-        return this;
-    }
-
-    void addOptimizedMonitorStub(ICStub* stub) {
-        MOZ_ASSERT(!invalid());
-        stub->setNext(this);
-
-        MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
-                   (numOptimizedMonitorStubs_ || !hasFallbackStub_));
-
-        if (lastMonitorStubPtrAddr_)
-            *lastMonitorStubPtrAddr_ = stub;
-
-        if (numOptimizedMonitorStubs_ == 0) {
-            MOZ_ASSERT(firstMonitorStub_ == this);
-            firstMonitorStub_ = stub;
-        } else {
-            MOZ_ASSERT(firstMonitorStub_ != nullptr);
-        }
-
-        lastMonitorStubPtrAddr_ = stub->addressOfNext();
-        numOptimizedMonitorStubs_++;
-    }
-
-  public:
-    bool hasStub(ICStub::Kind kind) {
-        ICStub* stub = firstMonitorStub_;
-        do {
-            if (stub->kind() == kind)
-                return true;
-
-            stub = stub->next();
-        } while (stub);
-
-        return false;
-    }
-
-    inline ICFallbackStub* mainFallbackStub() const {
-        MOZ_ASSERT(hasFallbackStub_);
-        return mainFallbackStub_;
-    }
-
-    inline ICEntry* icEntry() const {
-        return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_;
-    }
-
-    inline ICStub* firstMonitorStub() const {
-        return firstMonitorStub_;
-    }
-
-    static inline size_t offsetOfFirstMonitorStub() {
-        return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_);
-    }
-
-    inline uint32_t numOptimizedMonitorStubs() const {
-        return numOptimizedMonitorStubs_;
-    }
-
-    void setInvalid() {
-        invalid_ = 1;
-    }
-
-    bool invalid() const {
-        return invalid_;
-    }
-
-    inline bool monitorsThis() const {
-        return argumentIndex_ == 0;
-    }
-
-    inline bool monitorsArgument(uint32_t* pargument) const {
-        if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) {
-            *pargument = argumentIndex_ - 1;
-            return true;
-        }
-        return false;
-    }
-
-    inline bool monitorsBytecode() const {
-        return argumentIndex_ == BYTECODE_INDEX;
-    }
-
-    // Fixup the IC entry as for a normal fallback stub, for this/arguments.
-    void fixupICEntry(ICEntry* icEntry) {
-        MOZ_ASSERT(!hasFallbackStub_);
-        MOZ_ASSERT(icEntry_ == nullptr);
-        MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
-        icEntry_ = icEntry;
-        lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
-    }
-
-    // Create a new monitor stub for the type of the given value, and
-    // add it to this chain.
-    MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
-                                             StackTypeSet* types, HandleValue val);
-
-    void resetMonitorStubChain(Zone* zone);
-
-    // Compiler for this stub kind.
-    class Compiler : public ICStubCompiler {
-        ICMonitoredFallbackStub* mainFallbackStub_;
-        uint32_t argumentIndex_;
-
-      protected:
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
-          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
-            mainFallbackStub_(mainFallbackStub),
-            argumentIndex_(BYTECODE_INDEX)
-        { }
-
-        Compiler(JSContext* cx, uint32_t argumentIndex)
-          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
-            mainFallbackStub_(nullptr),
-            argumentIndex_(argumentIndex)
-        { }
-
-        ICTypeMonitor_Fallback* getStub(ICStubSpace* space) override {
-            return newStub<ICTypeMonitor_Fallback>(space, getStubCode(), mainFallbackStub_,
-                                                       argumentIndex_);
-        }
-    };
-};
-
-class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub
-{
-    friend class ICStubSpace;
-
-    ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags)
-        : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags)
-    {}
-
-  public:
-    class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
-      protected:
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        Compiler(JSContext* cx, ICTypeMonitor_PrimitiveSet* existingStub,
-                 JSValueType type)
-          : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub,
-                                                type)
-        {}
-
-        ICTypeMonitor_PrimitiveSet* updateStub() {
-            TypeCheckPrimitiveSetStub* stub =
-                this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
-            if (!stub)
-                return nullptr;
-            return stub->toMonitorStub();
-        }
-
-        ICTypeMonitor_PrimitiveSet* getStub(ICStubSpace* space) override {
-            MOZ_ASSERT(!existingStub_);
-            return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
-        }
-    };
-};
-
-class ICTypeMonitor_SingleObject : public ICStub
-{
-    friend class ICStubSpace;
-
-    GCPtrObject obj_;
-
-    ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
-
-  public:
-    GCPtrObject& object() {
-        return obj_;
-    }
-
-    static size_t offsetOfObject() {
-        return offsetof(ICTypeMonitor_SingleObject, obj_);
-    }
-
-    class Compiler : public ICStubCompiler {
-      protected:
-        HandleObject obj_;
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        Compiler(JSContext* cx, HandleObject obj)
-          : ICStubCompiler(cx, TypeMonitor_SingleObject),
-            obj_(obj)
-        { }
-
-        ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) override {
-            return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
-        }
-    };
-};
-
-class ICTypeMonitor_ObjectGroup : public ICStub
-{
-    friend class ICStubSpace;
-
-    GCPtrObjectGroup group_;
-
-    ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
-
-  public:
-    GCPtrObjectGroup& group() {
-        return group_;
-    }
-
-    static size_t offsetOfGroup() {
-        return offsetof(ICTypeMonitor_ObjectGroup, group_);
-    }
-
-    class Compiler : public ICStubCompiler {
-      protected:
-        HandleObjectGroup group_;
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        Compiler(JSContext* cx, HandleObjectGroup group)
-          : ICStubCompiler(cx, TypeMonitor_ObjectGroup),
-            group_(group)
-        { }
-
-        ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) override {
-            return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
-        }
-    };
-};
-
-class ICTypeMonitor_AnyValue : public ICStub
-{
-    friend class ICStubSpace;
-
-    explicit ICTypeMonitor_AnyValue(JitCode* stubCode)
-      : ICStub(TypeMonitor_AnyValue, stubCode)
-    {}
-
-  public:
-    class Compiler : public ICStubCompiler {
-      protected:
-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
-
-      public:
-        explicit Compiler(JSContext* cx)
-          : ICStubCompiler(cx, TypeMonitor_AnyValue)
-        { }
-
-        ICTypeMonitor_AnyValue* getStub(ICStubSpace* space) override {
-            return newStub<ICTypeMonitor_AnyValue>(space, getStubCode());
-        }
-    };
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_SharedIC_h */