Bug 1214508: SharedStubs - Part 6: Move the monitor stubs in to shared stub files, r=jandem
authorHannes Verschore <hv1989@gmail.com>
Tue, 17 Nov 2015 17:57:49 +0100
changeset 273020 26c7fea3fb16ec3cec1954e73f30efd5a627fd2b
parent 273019 8413cd50ac68e55a5e15a5515c9fdae4c4eabd3a
child 273021 b7ff5ed6cb4c33cea55919d653a91698ee1c70a9
push id29693
push usercbook@mozilla.com
push dateWed, 18 Nov 2015 13:50:33 +0000
treeherdermozilla-central@1d6155d7e6c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1214508
milestone45.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 1214508: SharedStubs - Part 6: Move the monitor stubs in to shared stub 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
@@ -334,379 +334,16 @@ ICWarmUpCounter_Fallback::Compiler::gene
     masm.jump(scratchReg);
 
     // No jitcode available, do nothing.
     masm.bind(&noCompiledCode);
     EmitReturnFromIC(masm);
     return true;
 }
 
-
-//
-// TypeMonitor_Fallback
-//
-
-bool
-ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, JSScript* script, HandleValue val)
-{
-    bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
-    MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
-
-    if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS) {
-        // TODO: if the TypeSet becomes unknown or has the AnyObject type,
-        // replace stubs with a single stub to handle these.
-        return true;
-    }
-
-    if (val.isPrimitive()) {
-        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;
-            }
-        }
-
-        ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
-        ICStub* stub = existingStub ? compiler.updateStub()
-                                    : compiler.getStub(compiler.getStubSpace(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(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(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)
-{
-    // 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 (stub->monitorsThis()) {
-        MOZ_ASSERT_IF(value.isMagic(), value.isMagic(JS_UNINITIALIZED_LEXICAL));
-    } else {
-        if (value.isMagic(JS_OPTIMIZED_OUT)) {
-            res.set(value);
-            return true;
-        }
-    }
-
-    RootedScript script(cx, frame->script());
-    jsbytecode* pc = stub->icEntry()->pc(script);
-    TypeFallbackICSpew(cx, stub, "TypeMonitor");
-
-    uint32_t argument;
-    if (stub->monitorsThis()) {
-        MOZ_ASSERT(pc == script->code());
-        if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
-            TypeScript::SetThis(cx, script, TypeSet::UnknownType());
-        else
-            TypeScript::SetThis(cx, script, value);
-    } else if (stub->monitorsArgument(&argument)) {
-        MOZ_ASSERT(pc == script->code());
-        TypeScript::SetArgument(cx, script, argument, value);
-    } else {
-        TypeScript::Monitor(cx, script, pc, value);
-    }
-
-    if (!stub->addMonitorStubForValue(cx, script, value))
-        return false;
-
-    // Copy input value to res.
-    res.set(value);
-    return true;
-}
-
-typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*,
-                                        HandleValue, MutableHandleValue);
-static const VMFunction DoTypeMonitorFallbackInfo =
-    FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback, TailCall);
-
-bool
-ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-    MOZ_ASSERT(R0 == JSReturnOperand);
-
-    // Restore the tail call register.
-    EmitRestoreTailCallReg(masm);
-
-    masm.pushValue(R0);
-    masm.push(ICStubReg);
-    pushFramePtr(masm, R0.scratchReg());
-
-    return tailCallVM(DoTypeMonitorFallbackInfo, masm);
-}
-
-bool
-ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    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);
-
-    // Currently, we will never generate primitive stub checks for object.  However,
-    // when we do get to the point where we want to collapse our monitor chains of
-    // objects and singletons down (when they get too long) to a generic "any object"
-    // in coordination with the typeset doing the same thing, this will need to
-    // be re-enabled.
-    /*
-    if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
-        masm.branchTestObject(Assembler::Equal, R0, &success);
-    */
-    MOZ_ASSERT(!(flags_ & TypeToFlag(JSVAL_TYPE_OBJECT)));
-
-    if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
-        masm.branchTestNull(Assembler::Equal, R0, &success);
-
-    EmitStubGuardFailure(masm);
-
-    masm.bind(&success);
-    EmitReturnFromIC(masm);
-    return true;
-}
-
-bool
-ICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    Label failure;
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    // 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);
-
-    EmitReturnFromIC(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
-ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
-{
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
-    Label failure;
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    // Guard on the object's ObjectGroup.
-    Register obj = masm.extractObject(R0, ExtractTemp0);
-    masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg());
-
-    Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
-    masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure);
-
-    EmitReturnFromIC(masm);
-
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
-ICUpdatedStub::addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
-                                     HandleId id, HandleValue val)
-{
-    if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS) {
-        // TODO: if the TypeSet becomes unknown or has the AnyObject type,
-        // replace stubs with a single stub to handle these.
-        return true;
-    }
-
-    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))
-        AddTypePropertyId(cx, obj, id, val);
-
-    if (val.isPrimitive()) {
-        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();
-                if (existingStub->containsType(type))
-                    return true;
-            }
-        }
-
-        ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type);
-        ICStub* stub = existingStub ? compiler.updateStub()
-                                    : compiler.getStub(compiler.getStubSpace(script));
-        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());
-
-        // Check for existing TypeUpdate stub.
-        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
-            if (iter->isTypeUpdate_SingleObject() &&
-                iter->toTypeUpdate_SingleObject()->object() == obj)
-            {
-                return true;
-            }
-        }
-
-        ICTypeUpdate_SingleObject::Compiler compiler(cx, obj);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(script));
-        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());
-
-        // Check for existing TypeUpdate stub.
-        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
-            if (iter->isTypeUpdate_ObjectGroup() &&
-                iter->toTypeUpdate_ObjectGroup()->group() == group)
-            {
-                return true;
-            }
-        }
-
-        ICTypeUpdate_ObjectGroup::Compiler compiler(cx, group);
-        ICStub* stub = compiler.getStub(compiler.getStubSpace(script));
-        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)
 {
     FallbackICSpew(cx, stub->getChainFallback(), "TypeUpdate(%s)",
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -50,366 +50,16 @@ class ICWarmUpCounter_Fallback : public 
 
         ICWarmUpCounter_Fallback* getStub(ICStubSpace* space) {
             return newStub<ICWarmUpCounter_Fallback>(space, getStubCode());
         }
     };
 };
 
 
-// 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 {
-            return static_cast<int32_t>(engine_) |
-                  (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, Engine::Baseline),
-            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_ : 8;
-
-    // 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),
-        hasFallbackStub_(mainFallbackStub != nullptr),
-        argumentIndex_(argumentIndex)
-    { }
-
-    ICTypeMonitor_Fallback* thisFromCtor() {
-        return this;
-    }
-
-    void addOptimizedMonitorStub(ICStub* stub) {
-        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_;
-    }
-
-    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.
-    bool addMonitorStubForValue(JSContext* cx, JSScript* script, HandleValue val);
-
-    void resetMonitorStubChain(Zone* zone);
-
-    // Compiler for this stub kind.
-    class Compiler : public ICStubCompiler {
-        ICMonitoredFallbackStub* mainFallbackStub_;
-        uint32_t argumentIndex_;
-
-      protected:
-        bool generateStubCode(MacroAssembler& masm);
-
-      public:
-        Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
-            : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
-            mainFallbackStub_(mainFallbackStub),
-            argumentIndex_(BYTECODE_INDEX)
-        { }
-
-        Compiler(JSContext* cx, uint32_t argumentIndex)
-          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
-            mainFallbackStub_(nullptr),
-            argumentIndex_(argumentIndex)
-        { }
-
-        ICTypeMonitor_Fallback* getStub(ICStubSpace* space) {
-            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:
-        bool generateStubCode(MacroAssembler& masm);
-
-      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) {
-            MOZ_ASSERT(!existingStub_);
-            return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
-        }
-    };
-};
-
-class ICTypeMonitor_SingleObject : public ICStub
-{
-    friend class ICStubSpace;
-
-    HeapPtrObject obj_;
-
-    ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
-
-  public:
-    HeapPtrObject& object() {
-        return obj_;
-    }
-
-    static size_t offsetOfObject() {
-        return offsetof(ICTypeMonitor_SingleObject, obj_);
-    }
-
-    class Compiler : public ICStubCompiler {
-      protected:
-        HandleObject obj_;
-        bool generateStubCode(MacroAssembler& masm);
-
-      public:
-        Compiler(JSContext* cx, HandleObject obj)
-          : ICStubCompiler(cx, TypeMonitor_SingleObject, Engine::Baseline),
-            obj_(obj)
-        { }
-
-        ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) {
-            return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
-        }
-    };
-};
-
-class ICTypeMonitor_ObjectGroup : public ICStub
-{
-    friend class ICStubSpace;
-
-    HeapPtrObjectGroup group_;
-
-    ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
-
-  public:
-    HeapPtrObjectGroup& group() {
-        return group_;
-    }
-
-    static size_t offsetOfGroup() {
-        return offsetof(ICTypeMonitor_ObjectGroup, group_);
-    }
-
-    class Compiler : public ICStubCompiler {
-      protected:
-        HandleObjectGroup group_;
-        bool generateStubCode(MacroAssembler& masm);
-
-      public:
-        Compiler(JSContext* cx, HandleObjectGroup group)
-          : ICStubCompiler(cx, TypeMonitor_ObjectGroup, Engine::Baseline),
-            group_(group)
-        { }
-
-        ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) {
-            return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
-        }
-    };
-};
-
 // 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
@@ -4480,10 +4480,372 @@ ICGetProp_DOMProxyShadowed::ICGetProp_DO
 ICGetProp_DOMProxyShadowed::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
                                   ICGetProp_DOMProxyShadowed& other)
 {
     return New<ICGetProp_DOMProxyShadowed>(cx, space, other.jitCode(), firstMonitorStub,
                                            other.shape_, other.proxyHandler_, other.name_,
                                            other.pcOffset_);
 }
 
+//
+// TypeMonitor_Fallback
+//
+
+bool
+ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, JSScript* script, HandleValue val)
+{
+    bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
+    MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
+
+    if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS) {
+        // TODO: if the TypeSet becomes unknown or has the AnyObject type,
+        // replace stubs with a single stub to handle these.
+        return true;
+    }
+
+    if (val.isPrimitive()) {
+        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;
+            }
+        }
+
+        ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
+        ICStub* stub = existingStub ? compiler.updateStub()
+                                    : compiler.getStub(compiler.getStubSpace(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(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(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)
+{
+    // 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 (stub->monitorsThis()) {
+        MOZ_ASSERT_IF(value.isMagic(), value.isMagic(JS_UNINITIALIZED_LEXICAL));
+    } else {
+        if (value.isMagic(JS_OPTIMIZED_OUT)) {
+            res.set(value);
+            return true;
+        }
+    }
+
+    RootedScript script(cx, frame->script());
+    jsbytecode* pc = stub->icEntry()->pc(script);
+    TypeFallbackICSpew(cx, stub, "TypeMonitor");
+
+    uint32_t argument;
+    if (stub->monitorsThis()) {
+        MOZ_ASSERT(pc == script->code());
+        if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
+            TypeScript::SetThis(cx, script, TypeSet::UnknownType());
+        else
+            TypeScript::SetThis(cx, script, value);
+    } else if (stub->monitorsArgument(&argument)) {
+        MOZ_ASSERT(pc == script->code());
+        TypeScript::SetArgument(cx, script, argument, value);
+    } else {
+        TypeScript::Monitor(cx, script, pc, value);
+    }
+
+    if (!stub->addMonitorStubForValue(cx, script, value))
+        return false;
+
+    // Copy input value to res.
+    res.set(value);
+    return true;
+}
+
+typedef bool (*DoTypeMonitorFallbackFn)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*,
+                                        HandleValue, MutableHandleValue);
+static const VMFunction DoTypeMonitorFallbackInfo =
+    FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback, TailCall);
+
+bool
+ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    MOZ_ASSERT(engine_ == Engine::Baseline);
+    MOZ_ASSERT(R0 == JSReturnOperand);
+
+    // Restore the tail call register.
+    EmitRestoreTailCallReg(masm);
+
+    masm.pushValue(R0);
+    masm.push(ICStubReg);
+    pushFramePtr(masm, R0.scratchReg());
+
+    return tailCallVM(DoTypeMonitorFallbackInfo, masm);
+}
+
+bool
+ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    MOZ_ASSERT(engine_ == Engine::Baseline);
+
+    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);
+
+    // Currently, we will never generate primitive stub checks for object.  However,
+    // when we do get to the point where we want to collapse our monitor chains of
+    // objects and singletons down (when they get too long) to a generic "any object"
+    // in coordination with the typeset doing the same thing, this will need to
+    // be re-enabled.
+    /*
+    if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
+        masm.branchTestObject(Assembler::Equal, R0, &success);
+    */
+    MOZ_ASSERT(!(flags_ & TypeToFlag(JSVAL_TYPE_OBJECT)));
+
+    if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
+        masm.branchTestNull(Assembler::Equal, R0, &success);
+
+    EmitStubGuardFailure(masm);
+
+    masm.bind(&success);
+    EmitReturnFromIC(masm);
+    return true;
+}
+
+bool
+ICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    MOZ_ASSERT(engine_ == Engine::Baseline);
+
+    Label failure;
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+
+    // 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);
+
+    EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+bool
+ICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
+{
+    MOZ_ASSERT(engine_ == Engine::Baseline);
+
+    Label failure;
+    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
+
+    // Guard on the object's ObjectGroup.
+    Register obj = masm.extractObject(R0, ExtractTemp0);
+    masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), R1.scratchReg());
+
+    Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup());
+    masm.branchPtr(Assembler::NotEqual, expectedGroup, R1.scratchReg(), &failure);
+
+    EmitReturnFromIC(masm);
+
+    masm.bind(&failure);
+    EmitStubGuardFailure(masm);
+    return true;
+}
+
+bool
+ICUpdatedStub::addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
+                                     HandleId id, HandleValue val)
+{
+    if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS) {
+        // TODO: if the TypeSet becomes unknown or has the AnyObject type,
+        // replace stubs with a single stub to handle these.
+        return true;
+    }
+
+    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))
+        AddTypePropertyId(cx, obj, id, val);
+
+    if (val.isPrimitive()) {
+        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();
+                if (existingStub->containsType(type))
+                    return true;
+            }
+        }
+
+        ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type);
+        ICStub* stub = existingStub ? compiler.updateStub()
+                                    : compiler.getStub(compiler.getStubSpace(script));
+        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());
+
+        // Check for existing TypeUpdate stub.
+        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
+            if (iter->isTypeUpdate_SingleObject() &&
+                iter->toTypeUpdate_SingleObject()->object() == obj)
+            {
+                return true;
+            }
+        }
+
+        ICTypeUpdate_SingleObject::Compiler compiler(cx, obj);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(script));
+        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());
+
+        // Check for existing TypeUpdate stub.
+        for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) {
+            if (iter->isTypeUpdate_ObjectGroup() &&
+                iter->toTypeUpdate_ObjectGroup()->group() == group)
+            {
+                return true;
+            }
+        }
+
+        ICTypeUpdate_ObjectGroup::Compiler compiler(cx, group);
+        ICStub* stub = compiler.getStub(compiler.getStubSpace(script));
+        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
@@ -1103,16 +1103,367 @@ class ICMultiStubCompiler : public ICStu
               (static_cast<int32_t>(kind) << 1) |
               (static_cast<int32_t>(op) << 17);
     }
 
     ICMultiStubCompiler(JSContext* cx, ICStub::Kind kind, JSOp op, Engine engine)
       : ICStubCompiler(cx, kind, engine), op(op) {}
 };
 
+// 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 {
+            return static_cast<int32_t>(engine_) |
+                  (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, Engine::Baseline),
+            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_ : 8;
+
+    // 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),
+        hasFallbackStub_(mainFallbackStub != nullptr),
+        argumentIndex_(argumentIndex)
+    { }
+
+    ICTypeMonitor_Fallback* thisFromCtor() {
+        return this;
+    }
+
+    void addOptimizedMonitorStub(ICStub* stub) {
+        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_;
+    }
+
+    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.
+    bool addMonitorStubForValue(JSContext* cx, JSScript* script, HandleValue val);
+
+    void resetMonitorStubChain(Zone* zone);
+
+    // Compiler for this stub kind.
+    class Compiler : public ICStubCompiler {
+        ICMonitoredFallbackStub* mainFallbackStub_;
+        uint32_t argumentIndex_;
+
+      protected:
+        bool generateStubCode(MacroAssembler& masm);
+
+      public:
+        Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
+            : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
+            mainFallbackStub_(mainFallbackStub),
+            argumentIndex_(BYTECODE_INDEX)
+        { }
+
+        Compiler(JSContext* cx, uint32_t argumentIndex)
+          : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
+            mainFallbackStub_(nullptr),
+            argumentIndex_(argumentIndex)
+        { }
+
+        ICTypeMonitor_Fallback* getStub(ICStubSpace* space) {
+            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:
+        bool generateStubCode(MacroAssembler& masm);
+
+      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) {
+            MOZ_ASSERT(!existingStub_);
+            return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
+        }
+    };
+};
+
+class ICTypeMonitor_SingleObject : public ICStub
+{
+    friend class ICStubSpace;
+
+    HeapPtrObject obj_;
+
+    ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
+
+  public:
+    HeapPtrObject& object() {
+        return obj_;
+    }
+
+    static size_t offsetOfObject() {
+        return offsetof(ICTypeMonitor_SingleObject, obj_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        HandleObject obj_;
+        bool generateStubCode(MacroAssembler& masm);
+
+      public:
+        Compiler(JSContext* cx, HandleObject obj)
+          : ICStubCompiler(cx, TypeMonitor_SingleObject, Engine::Baseline),
+            obj_(obj)
+        { }
+
+        ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) {
+            return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
+        }
+    };
+};
+
+class ICTypeMonitor_ObjectGroup : public ICStub
+{
+    friend class ICStubSpace;
+
+    HeapPtrObjectGroup group_;
+
+    ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
+
+  public:
+    HeapPtrObjectGroup& group() {
+        return group_;
+    }
+
+    static size_t offsetOfGroup() {
+        return offsetof(ICTypeMonitor_ObjectGroup, group_);
+    }
+
+    class Compiler : public ICStubCompiler {
+      protected:
+        HandleObjectGroup group_;
+        bool generateStubCode(MacroAssembler& masm);
+
+      public:
+        Compiler(JSContext* cx, HandleObjectGroup group)
+          : ICStubCompiler(cx, TypeMonitor_ObjectGroup, Engine::Baseline),
+            group_(group)
+        { }
+
+        ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) {
+            return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
+        }
+    };
+};
+
+
 // BinaryArith
 //      JSOP_ADD, JSOP_SUB, JSOP_MUL, JOP_DIV, JSOP_MOD
 //      JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
 //      JSOP_LSH, JSOP_RSH, JSOP_URSH
 
 class ICBinaryArith_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;