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 433137 370a45e8ea65c3fe50b9abd4651c525c18ab6934
parent 433136 b733b2488363f3f2bdd6e14cc9df1694f7f8ae3a
child 433138 5a2381311cedc81a16222f90b854675fa004c4db
push id34499
push usercsabou@mozilla.com
push dateThu, 23 Aug 2018 21:40:51 +0000
treeherdermozilla-central@49b70f7e6817 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1479603
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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 */