Browse Source

some stuff from the wip branch

Frank-Rainer Grahl 9 months ago
parent
commit
f773222b6f

+ 1048 - 0
mozilla-release/patches/1420910-1-60a1.patch

@@ -0,0 +1,1048 @@
+# HG changeset patch
+# User Matthew Gaudet <mgaudet@mozilla.com>
+# Date 1513117305 21600
+# Node ID 5d6cc408dfd9228ad0529ba718b5e8a2a4889df1
+# Parent  df48514c0f80ce5be2a8c37ca0935d481838242c
+Bug 1420910: Convert the Baseline InstanceOf IC to CacheIR r=jandem
+
+This is the preliminary patch to convert the Baseline InstanceOf
+IC to CacheIR, which will later allow us to add support to IonMonkey
+
+diff --git a/js/src/jit-test/tests/cacheir/bug1420910.js b/js/src/jit-test/tests/cacheir/bug1420910.js
+new file mode 100644
+--- /dev/null
++++ b/js/src/jit-test/tests/cacheir/bug1420910.js
+@@ -0,0 +1,35 @@
++// Testing InstanceOf IC.
++
++Array.prototype.sum = function() {
++    return this.reduce(( acc, cur ) => acc + cur, 0);
++}
++
++
++Iters = 20;
++
++function resultArray(fn, obj) {
++    res = new Array();
++    for (var x = 0; x < Iters; x++) {
++        res.push(fn(obj) ? 1 : 0);
++    }
++    return res;
++}
++
++// Ensure alteration of .prototype invalidates IC
++function basic() {};
++
++protoA = { prop1: "1"};
++basic.prototype = protoA;
++
++io1 = x => { return x instanceof basic; }
++
++var x = new basic();
++beforePrototypeModification = resultArray(io1,x).sum(); //Attach and test IC
++assertEq(beforePrototypeModification,Iters);
++
++basic.prototype = {}; // Invalidate IC
++afterPrototypeModification  = resultArray(io1,x).sum(); //Test
++assertEq(afterPrototypeModification,0);
++
++//Primitive LHS returns false.
++assertEq(resultArray(io1,0).sum(),0);
+\ No newline at end of file
+diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp
+--- a/js/src/jit/BaselineCacheIRCompiler.cpp
++++ b/js/src/jit/BaselineCacheIRCompiler.cpp
+@@ -452,16 +452,44 @@ BaselineCacheIRCompiler::emitGuardXrayEx
+         masm.branchTestObject(Assembler::Equal, expandoAddress, failure->label());
+         masm.bind(&done);
+     }
+ 
+     return true;
+ }
+ 
+ bool
++BaselineCacheIRCompiler::emitGuardFunctionPrototype()
++{
++    Register obj = allocator.useRegister(masm, reader.objOperandId());
++    Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
++
++    // Allocate registers before the failure path to make sure they're registered
++    // by addFailurePath.
++    AutoScratchRegister scratch1(allocator, masm);
++    AutoScratchRegister scratch2(allocator, masm);
++
++    FailurePath* failure;
++    if (!addFailurePath(&failure))
++        return false;
++
++     // Guard on the .prototype object.
++    masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
++    masm.load32(Address(stubAddress(reader.stubOffset())), scratch2);
++    BaseValueIndex prototypeSlot(scratch1, scratch2);
++    masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
++    masm.unboxObject(prototypeSlot, scratch1);
++    masm.branchPtr(Assembler::NotEqual,
++                   prototypeObject,
++                   scratch1, failure->label());
++
++    return true;
++}
++
++bool
+ BaselineCacheIRCompiler::emitLoadFixedSlotResult()
+ {
+     AutoOutputRegister output(*this);
+     Register obj = allocator.useRegister(masm, reader.objOperandId());
+     AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
+ 
+     masm.load32(stubAddress(reader.stubOffset()), scratch);
+     masm.loadValue(BaseIndex(obj, scratch, TimesOne), output.valueReg());
+@@ -2078,16 +2106,17 @@ BaselineCacheIRCompiler::init(CacheKind 
+         allocator.initInputLocation(0, R0);
+         break;
+       case CacheKind::Compare:
+       case CacheKind::GetElem:
+       case CacheKind::GetPropSuper:
+       case CacheKind::SetProp:
+       case CacheKind::In:
+       case CacheKind::HasOwn:
++      case CacheKind::InstanceOf:
+         MOZ_ASSERT(numInputs == 2);
+         allocator.initInputLocation(0, R0);
+         allocator.initInputLocation(1, R1);
+         break;
+       case CacheKind::GetElemSuper:
+         MOZ_ASSERT(numInputs == 3);
+         allocator.initInputLocation(0, BaselineFrameSlot(0));
+         allocator.initInputLocation(1, R0);
+diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
+--- a/js/src/jit/BaselineIC.cpp
++++ b/js/src/jit/BaselineIC.cpp
+@@ -4287,56 +4287,44 @@ ICIteratorClose_Fallback::Compiler::gene
+ }
+ 
+ //
+ // InstanceOf_Fallback
+ //
+ 
+ static bool
+ TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
+-                        HandleFunction fun, bool* attached)
++                        HandleValue lhs, HandleValue rhs, bool* attached)
+ {
+     MOZ_ASSERT(!*attached);
+-    if (fun->isBoundFunction())
+-        return true;
+-
+-    // If the user has supplied their own @@hasInstance method we shouldn't
+-    // clobber it.
+-    if (!js::FunctionHasDefaultHasInstance(fun, cx->wellKnownSymbols()))
+-        return true;
+-
+-    // Refuse to optimize any function whose [[Prototype]] isn't
+-    // Function.prototype.
+-    if (!fun->hasStaticPrototype() || fun->hasUncacheableProto())
+-        return true;
+-
+-    Value funProto = cx->global()->getPrototype(JSProto_Function);
+-    if (funProto.isObject() && fun->staticPrototype() != &funProto.toObject())
+-        return true;
+-
+-    Shape* shape = fun->lookupPure(cx->names().prototype);
+-    if (!shape || !shape->isDataProperty())
+-        return true;
+-
+-    uint32_t slot = shape->slot();
+-    MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
+-
+-    if (!fun->getSlot(slot).isObject())
+-        return true;
+-
+-    JSObject* protoObject = &fun->getSlot(slot).toObject();
+-
+-    JitSpew(JitSpew_BaselineIC, "  Generating InstanceOf(Function) stub");
+-    ICInstanceOf_Function::Compiler compiler(cx, fun->lastProperty(), protoObject, slot);
+-    ICStub* newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
+-    if (!newStub)
+-        return false;
+-
+-    stub->addNewStub(newStub);
+-    *attached = true;
++    FallbackICSpew(cx, stub, "InstanceOf");
++
++    if (stub->state().maybeTransition())
++        stub->discardStubs(cx);
++
++    if (stub->state().canAttachStub()) {
++        RootedScript script(cx, frame->script());
++        jsbytecode* pc = stub->icEntry()->pc(script);
++
++        ICStubEngine engine = ICStubEngine::Baseline;
++        InstanceOfIRGenerator gen(cx, script, pc, stub->state().mode(),
++                                  lhs,
++                                  rhs);
++
++        if (gen.tryAttachStub()) {
++            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
++                                                        BaselineCacheIRStubKind::Regular,
++                                                        engine, script, stub, attached);
++            if (newStub)
++                JitSpew(JitSpew_BaselineIC, "  Attached InstanceOf CacheIR stub, attached is now %d", *attached);
++        }
++        if (!attached)
++            stub->state().trackNotAttached();
++    }
++
+     return true;
+ }
+ 
+ static bool
+ DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
+                      HandleValue lhs, HandleValue rhs, MutableHandleValue res)
+ {
+     FallbackICSpew(cx, stub, "InstanceOf");
+@@ -4357,22 +4345,18 @@ DoInstanceOfFallback(JSContext* cx, Base
+         stub->noteUnoptimizableAccess();
+         return true;
+     }
+ 
+     // For functions, keep track of the |prototype| property in type information,
+     // for use during Ion compilation.
+     EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
+ 
+-    if (stub->numOptimizedStubs() >= ICInstanceOf_Fallback::MAX_OPTIMIZED_STUBS)
+-        return true;
+-
+-    RootedFunction fun(cx, &obj->as<JSFunction>());
+     bool attached = false;
+-    if (!TryAttachInstanceOfStub(cx, frame, stub, fun, &attached))
++    if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, rhs, &attached))
+         return false;
+     if (!attached)
+         stub->noteUnoptimizableAccess();
+     return true;
+ }
+ 
+ typedef bool (*DoInstanceOfFallbackFn)(JSContext*, BaselineFrame*, ICInstanceOf_Fallback*,
+                                        HandleValue, HandleValue, MutableHandleValue);
+@@ -4394,92 +4378,16 @@ ICInstanceOf_Fallback::Compiler::generat
+     masm.pushValue(R1);
+     masm.pushValue(R0);
+     masm.push(ICStubReg);
+     pushStubPayload(masm, R0.scratchReg());
+ 
+     return tailCallVM(DoInstanceOfFallbackInfo, masm);
+ }
+ 
+-bool
+-ICInstanceOf_Function::Compiler::generateStubCode(MacroAssembler& masm)
+-{
+-    MOZ_ASSERT(engine_ == Engine::Baseline);
+-
+-    Label failure;
+-
+-    // Ensure RHS is an object.
+-    masm.branchTestObject(Assembler::NotEqual, R1, &failure);
+-    Register rhsObj = masm.extractObject(R1, ExtractTemp0);
+-
+-    // Allow using R1's type register as scratch. We have to restore it when
+-    // we want to jump to the next stub.
+-    Label failureRestoreR1;
+-    AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
+-    regs.takeUnchecked(rhsObj);
+-
+-    Register scratch1 = regs.takeAny();
+-    Register scratch2 = regs.takeAny();
+-
+-    // Shape guard.
+-    masm.loadPtr(Address(ICStubReg, ICInstanceOf_Function::offsetOfShape()), scratch1);
+-    masm.branchTestObjShape(Assembler::NotEqual, rhsObj, scratch1, &failureRestoreR1);
+-
+-    // Guard on the .prototype object.
+-    masm.loadPtr(Address(rhsObj, NativeObject::offsetOfSlots()), scratch1);
+-    masm.load32(Address(ICStubReg, ICInstanceOf_Function::offsetOfSlot()), scratch2);
+-    BaseValueIndex prototypeSlot(scratch1, scratch2);
+-    masm.branchTestObject(Assembler::NotEqual, prototypeSlot, &failureRestoreR1);
+-    masm.unboxObject(prototypeSlot, scratch1);
+-    masm.branchPtr(Assembler::NotEqual,
+-                   Address(ICStubReg, ICInstanceOf_Function::offsetOfPrototypeObject()),
+-                   scratch1, &failureRestoreR1);
+-
+-    // If LHS is a primitive, return false.
+-    Label returnFalse, returnTrue;
+-    masm.branchTestObject(Assembler::NotEqual, R0, &returnFalse);
+-
+-    // LHS is an object. Load its proto.
+-    masm.unboxObject(R0, scratch2);
+-    masm.loadObjProto(scratch2, scratch2);
+-
+-    {
+-        // Walk the proto chain until we either reach the target object,
+-        // nullptr or LazyProto.
+-        Label loop;
+-        masm.bind(&loop);
+-
+-        masm.branchPtr(Assembler::Equal, scratch2, scratch1, &returnTrue);
+-        masm.branchTestPtr(Assembler::Zero, scratch2, scratch2, &returnFalse);
+-
+-        MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
+-        masm.branchPtr(Assembler::Equal, scratch2, ImmWord(1), &failureRestoreR1);
+-
+-        masm.loadObjProto(scratch2, scratch2);
+-        masm.jump(&loop);
+-    }
+-
+-    EmitReturnFromIC(masm);
+-
+-    masm.bind(&returnFalse);
+-    masm.moveValue(BooleanValue(false), R0);
+-    EmitReturnFromIC(masm);
+-
+-    masm.bind(&returnTrue);
+-    masm.moveValue(BooleanValue(true), R0);
+-    EmitReturnFromIC(masm);
+-
+-    masm.bind(&failureRestoreR1);
+-    masm.tagValue(JSVAL_TYPE_OBJECT, rhsObj, R1);
+-
+-    masm.bind(&failure);
+-    EmitStubGuardFailure(masm);
+-    return true;
+-}
+-
+ //
+ // TypeOf_Fallback
+ //
+ 
+ static bool
+ DoTypeOfFallback(JSContext* cx, BaselineFrame* frame, ICTypeOf_Fallback* stub, HandleValue val,
+                  MutableHandleValue res)
+ {
+@@ -4662,24 +4570,16 @@ ICTypeUpdate_ObjectGroup::ICTypeUpdate_O
+ ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value)
+   : ICStub(GetIntrinsic_Constant, stubCode),
+     value_(value)
+ { }
+ 
+ ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
+ { }
+ 
+-ICInstanceOf_Function::ICInstanceOf_Function(JitCode* stubCode, Shape* shape,
+-                                             JSObject* prototypeObj, uint32_t slot)
+-  : ICStub(InstanceOf_Function, stubCode),
+-    shape_(shape),
+-    prototypeObj_(prototypeObj),
+-    slot_(slot)
+-{ }
+-
+ ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
+                                  JSFunction* callee, JSObject* templateObject,
+                                  uint32_t pcOffset)
+   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
+     callee_(callee),
+     templateObject_(templateObject),
+     pcOffset_(pcOffset)
+ { }
+diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h
+--- a/js/src/jit/BaselineIC.h
++++ b/js/src/jit/BaselineIC.h
+@@ -1449,17 +1449,16 @@ class ICInstanceOf_Fallback : public ICF
+ 
+     explicit ICInstanceOf_Fallback(JitCode* stubCode)
+       : ICFallbackStub(ICStub::InstanceOf_Fallback, stubCode)
+     { }
+ 
+     static const uint16_t UNOPTIMIZABLE_ACCESS_BIT = 0x1;
+ 
+   public:
+-    static const uint32_t MAX_OPTIMIZED_STUBS = 4;
+ 
+     void noteUnoptimizableAccess() {
+         extra_ |= UNOPTIMIZABLE_ACCESS_BIT;
+     }
+     bool hadUnoptimizableAccess() const {
+         return extra_ & UNOPTIMIZABLE_ACCESS_BIT;
+     }
+ 
+@@ -1473,69 +1472,16 @@ class ICInstanceOf_Fallback : public ICF
+         { }
+ 
+         ICStub* getStub(ICStubSpace* space) override {
+             return newStub<ICInstanceOf_Fallback>(space, getStubCode());
+         }
+     };
+ };
+ 
+-class ICInstanceOf_Function : public ICStub
+-{
+-    friend class ICStubSpace;
+-
+-    GCPtrShape shape_;
+-    GCPtrObject prototypeObj_;
+-    uint32_t slot_;
+-
+-    ICInstanceOf_Function(JitCode* stubCode, Shape* shape, JSObject* prototypeObj, uint32_t slot);
+-
+-  public:
+-    GCPtrShape& shape() {
+-        return shape_;
+-    }
+-    GCPtrObject& prototypeObject() {
+-        return prototypeObj_;
+-    }
+-    uint32_t slot() const {
+-        return slot_;
+-    }
+-    static size_t offsetOfShape() {
+-        return offsetof(ICInstanceOf_Function, shape_);
+-    }
+-    static size_t offsetOfPrototypeObject() {
+-        return offsetof(ICInstanceOf_Function, prototypeObj_);
+-    }
+-    static size_t offsetOfSlot() {
+-        return offsetof(ICInstanceOf_Function, slot_);
+-    }
+-
+-    class Compiler : public ICStubCompiler {
+-        RootedShape shape_;
+-        RootedObject prototypeObj_;
+-        uint32_t slot_;
+-
+-      protected:
+-        MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
+-
+-      public:
+-        Compiler(JSContext* cx, Shape* shape, JSObject* prototypeObj, uint32_t slot)
+-          : ICStubCompiler(cx, ICStub::InstanceOf_Function, Engine::Baseline),
+-            shape_(cx, shape),
+-            prototypeObj_(cx, prototypeObj),
+-            slot_(slot)
+-        {}
+-
+-        ICStub* getStub(ICStubSpace* space) override {
+-            return newStub<ICInstanceOf_Function>(space, getStubCode(), shape_, prototypeObj_,
+-                                                  slot_);
+-        }
+-    };
+-};
+-
+ // TypeOf
+ //      JSOP_TYPEOF
+ //      JSOP_TYPEOFEXPR
+ class ICTypeOf_Fallback : public ICFallbackStub
+ {
+     friend class ICStubSpace;
+ 
+     explicit ICTypeOf_Fallback(JitCode* stubCode)
+diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp
+--- a/js/src/jit/BaselineInspector.cpp
++++ b/js/src/jit/BaselineInspector.cpp
+@@ -1378,32 +1378,54 @@ BaselineInspector::expectedPropertyAcces
+     return (type == MIRType::None) ? MIRType::Value : type;
+ }
+ 
+ bool
+ BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
+                                   JSObject** prototypeObject)
+ {
+     MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
+-
+     if (!hasBaselineScript())
+         return false;
+ 
+     const ICEntry& entry = icEntryFromPC(pc);
++    ICStub* firstStub = entry.firstStub();
+ 
+-    ICStub* stub = entry.firstStub();
+-    if (!stub->isInstanceOf_Function() ||
+-        !stub->next()->isInstanceOf_Fallback() ||
+-        stub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
+-    {
++    // Ensure singleton instanceof stub
++    if (!firstStub->next() ||
++        !firstStub->isCacheIR_Regular() ||
++        !firstStub->next()->isInstanceOf_Fallback() ||
++         firstStub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
++         {
++             return false;
++         }
++
++    ICCacheIR_Regular* stub = entry.firstStub()->toCacheIR_Regular();
++    CacheIRReader reader(stub->stubInfo());
++
++    ObjOperandId rhsId = ObjOperandId(1);
++    ObjOperandId resId = ObjOperandId(2);
++
++    if (!reader.matchOp(CacheOp::GuardIsObject, rhsId))
+         return false;
+-    }
++
++    if (!reader.matchOp(CacheOp::GuardShape, rhsId))
++        return false;
+ 
+-    ICInstanceOf_Function* optStub = stub->toInstanceOf_Function();
+-    *shape = optStub->shape();
+-    *prototypeObject = optStub->prototypeObject();
+-    *slot = optStub->slot();
++    *shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
++
++    if (!reader.matchOp(CacheOp::LoadObject, resId))
++        return false;
++
++    *prototypeObject = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
+ 
+     if (IsInsideNursery(*prototypeObject))
+         return false;
+ 
++    if (!reader.matchOp(CacheOp::GuardFunctionPrototype, rhsId))
++        return false;
++
++    reader.skip(); // Skip over the protoID;
++
++    *slot = stub->stubInfo()->getStubRawWord(stub, reader.stubOffset());
++
+     return true;
+ }
+diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
+--- a/js/src/jit/CacheIR.cpp
++++ b/js/src/jit/CacheIR.cpp
+@@ -4201,16 +4201,123 @@ SetPropIRGenerator::tryAttachAddSlotStub
+         }
+     }
+     writer.returnFromIC();
+ 
+     typeCheckInfo_.set(oldGroup, id);
+     return true;
+ }
+ 
++InstanceOfIRGenerator::InstanceOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
++                                            ICState::Mode mode, HandleValue lhs, HandleValue rhs)
++  : IRGenerator(cx, script, pc, CacheKind::InstanceOf, mode),
++    lhsVal_(lhs),
++    rhsVal_(rhs)
++{ }
++
++bool
++InstanceOfIRGenerator::tryAttachStub()
++{
++    MOZ_ASSERT(cacheKind_ == CacheKind::InstanceOf);
++    AutoAssertNoPendingException aanpe(cx_);
++    RootedFunction fun(cx_, &rhsVal_.toObject().as<JSFunction>());
++
++    if (fun->isBoundFunction()) {
++        trackNotAttached();
++        return false;
++    }
++
++    // If the user has supplied their own @@hasInstance method we shouldn't
++    // clobber it.
++    if (!js::FunctionHasDefaultHasInstance(fun, cx_->wellKnownSymbols())) {
++        trackNotAttached();
++        return false;
++    }
++
++    // Refuse to optimize any function whose [[Prototype]] isn't
++    // Function.prototype.
++    if (!fun->hasStaticPrototype() || fun->hasUncacheableProto()) {
++        trackNotAttached();
++        return false;
++    }
++
++    Value funProto = cx_->global()->getPrototype(JSProto_Function);
++    if (!funProto.isObject() || fun->staticPrototype() != &funProto.toObject()) {
++        trackNotAttached();
++        return false;
++    }
++
++    // Ensure that the function's prototype slot is the same.
++    Shape* shape = fun->lookupPure(cx_->names().prototype);
++    if (!shape || !shape->isDataProperty()) {
++        trackNotAttached();
++        return false;
++    }
++
++    uint32_t slot = shape->slot();
++
++    MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
++    if (!fun->getSlot(slot).isObject()) {
++        trackNotAttached();
++        return false;
++    }
++
++    JSObject* prototypeObject = &fun->getSlot(slot).toObject();
++
++    // Abstract Objects
++    ValOperandId lhs(writer.setInputOperandId(0));
++    ValOperandId rhs(writer.setInputOperandId(1));
++
++    ObjOperandId rhsId = writer.guardIsObject(rhs);
++    writer.guardShape(rhsId, fun->lastProperty());
++
++    // Load prototypeObject into the cache -- consumed twice in the IC
++    ObjOperandId protoId = writer.loadObject(prototypeObject);
++    // Ensure that rhs[slot] == prototypeObject.
++    writer.guardFunctionPrototype(rhsId, slot, protoId);
++
++    // Needn't guard LHS is object, because the actual stub can handle that
++    // and correctly return false.
++    writer.loadInstanceOfObjectResult(lhs, protoId, slot);
++    writer.returnFromIC();
++    trackAttached("InstanceOf");
++    return true;
++}
++
++void
++InstanceOfIRGenerator::trackAttached(const char* name)
++{
++#ifdef JS_CACHEIR_SPEW
++    CacheIRSpewer& sp = CacheIRSpewer::singleton();
++    if (sp.enabled()) {
++        LockGuard<Mutex> guard(sp.lock());
++        sp.beginCache(guard, *this);
++        sp.valueProperty(guard, "lhs", lhsVal_);
++        sp.valueProperty(guard, "rhs", rhsVal_);
++        sp.attached(guard, name);
++        sp.endCache(guard);
++    }
++#endif
++}
++
++void
++InstanceOfIRGenerator::trackNotAttached()
++{
++#ifdef JS_CACHEIR_SPEW
++    CacheIRSpewer& sp = CacheIRSpewer::singleton();
++    if (sp.enabled()) {
++        LockGuard<Mutex> guard(sp.lock());
++        sp.beginCache(guard, *this);
++        sp.valueProperty(guard, "lhs", lhsVal_);
++        sp.valueProperty(guard, "rhs", rhsVal_);
++        sp.endCache(guard);
++    }
++#endif
++}
++
+ TypeOfIRGenerator::TypeOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
+                                      ICState::Mode mode, HandleValue value)
+   : IRGenerator(cx, script, pc, CacheKind::TypeOf, mode),
+     val_(value)
+ { }
+ 
+ bool
+ TypeOfIRGenerator::tryAttachStub()
+diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h
+--- a/js/src/jit/CacheIR.h
++++ b/js/src/jit/CacheIR.h
+@@ -143,16 +143,17 @@ class TypedOperandId : public OperandId
+     _(GetPropSuper)         \
+     _(GetElemSuper)         \
+     _(SetProp)              \
+     _(SetElem)              \
+     _(BindName)             \
+     _(In)                   \
+     _(HasOwn)               \
+     _(TypeOf)               \
++    _(InstanceOf)           \
+     _(GetIterator)          \
+     _(Compare)              \
+     _(Call)
+ 
+ enum class CacheKind : uint8_t
+ {
+ #define DEFINE_KIND(kind) kind,
+     CACHE_IR_KINDS(DEFINE_KIND)
+@@ -190,16 +191,17 @@ extern const char* CacheKindNames[];
+     _(GuardNoUnboxedExpando)              \
+     _(GuardAndLoadUnboxedExpando)         \
+     _(GuardAndGetIndexFromString)         \
+     _(GuardAndGetIterator)                \
+     _(GuardHasGetterSetter)               \
+     _(GuardGroupHasUnanalyzedNewScript)   \
+     _(GuardIndexIsNonNegative)            \
+     _(GuardXrayExpandoShapeAndDefaultProto) \
++    _(GuardFunctionPrototype)             \
+     _(LoadStackValue)                     \
+     _(LoadObject)                         \
+     _(LoadProto)                          \
+     _(LoadEnclosingEnvironment)           \
+     _(LoadWrapperTarget)                  \
+                                           \
+     _(MegamorphicLoadSlotResult)          \
+     _(MegamorphicLoadSlotByValueResult)   \
+@@ -259,16 +261,17 @@ extern const char* CacheKindNames[];
+     _(CallNativeGetterResult)             \
+     _(CallProxyGetResult)                 \
+     _(CallProxyGetByValueResult)          \
+     _(CallProxyHasPropResult)             \
+     _(CallObjectHasSparseElementResult)   \
+     _(LoadUndefinedResult)                \
+     _(LoadBooleanResult)                  \
+     _(LoadStringResult)                   \
++    _(LoadInstanceOfObjectResult)         \
+     _(LoadTypeOfObjectResult)             \
+                                           \
+     _(CallStringSplitResult)              \
+                                           \
+     _(CompareStringResult)                \
+     _(CompareObjectResult)                \
+     _(CompareSymbolResult)                \
+                                           \
+@@ -546,16 +549,22 @@ class MOZ_RAII CacheIRWriter : public JS
+         guardShape(obj, shape);
+     }
+     void guardXrayExpandoShapeAndDefaultProto(ObjOperandId obj, JSObject* shapeWrapper) {
+         assertSameCompartment(shapeWrapper);
+         writeOpWithOperandId(CacheOp::GuardXrayExpandoShapeAndDefaultProto, obj);
+         buffer_.writeByte(uint32_t(!!shapeWrapper));
+         addStubField(uintptr_t(shapeWrapper), StubField::Type::JSObject);
+     }
++    // Guard rhs[slot] == prototypeObject
++    void guardFunctionPrototype(ObjOperandId rhs, uint32_t slot, ObjOperandId protoId) {
++        writeOpWithOperandId(CacheOp::GuardFunctionPrototype, rhs);
++        writeOperandId(protoId);
++        addStubField(slot, StubField::Type::RawWord);
++    }
+   private:
+     // Use (or create) a specialization below to clarify what constaint the
+     // group guard is implying.
+     void guardGroup(ObjOperandId obj, ObjectGroup* group) {
+         writeOpWithOperandId(CacheOp::GuardGroup, obj);
+         addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
+     }
+   public:
+@@ -1031,20 +1040,24 @@ class MOZ_RAII CacheIRWriter : public JS
+     }
+     void loadEnvironmentDynamicSlotResult(ObjOperandId obj, size_t offset) {
+         writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
+         addStubField(offset, StubField::Type::RawWord);
+     }
+     void loadObjectResult(ObjOperandId obj) {
+         writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
+     }
++    void loadInstanceOfObjectResult(ValOperandId lhs, ObjOperandId protoId, uint32_t slot) {
++        writeOp(CacheOp::LoadInstanceOfObjectResult);
++        writeOperandId(lhs);
++        writeOperandId(protoId);
++    }
+     void loadTypeOfObjectResult(ObjOperandId obj) {
+         writeOpWithOperandId(CacheOp::LoadTypeOfObjectResult, obj);
+     }
+-
+     void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
+         writeOp(CacheOp::CallStringSplitResult);
+         writeOperandId(str);
+         writeOperandId(sep);
+         addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
+     }
+ 
+     void compareStringResult(uint32_t op, StringOperandId lhs, StringOperandId rhs) {
+@@ -1102,16 +1115,19 @@ class MOZ_RAII CacheIRReader
+     explicit CacheIRReader(const CacheIRStubInfo* stubInfo);
+ 
+     bool more() const { return buffer_.more(); }
+ 
+     CacheOp readOp() {
+         return CacheOp(buffer_.readByte());
+     }
+ 
++    // Skip data not currently used.
++    void skip() { buffer_.readByte(); }
++
+     ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
+     ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
+     StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
+     SymbolOperandId symbolOperandId() { return SymbolOperandId(buffer_.readByte()); }
+     Int32OperandId int32OperandId() { return Int32OperandId(buffer_.readByte()); }
+ 
+     uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
+     GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
+@@ -1524,16 +1540,30 @@ class MOZ_RAII HasPropIRGenerator : publ
+   public:
+     // NOTE: Argument order is PROPERTY, OBJECT
+     HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
+                        ICState::Mode mode, HandleValue idVal, HandleValue val);
+ 
+     bool tryAttachStub();
+ };
+ 
++class MOZ_RAII InstanceOfIRGenerator : public IRGenerator
++{
++    HandleValue lhsVal_;
++    HandleValue rhsVal_;
++
++    void trackAttached(const char* name);
++    void trackNotAttached();
++  public:
++    InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
++                          HandleValue, HandleValue);
++
++    bool tryAttachStub();
++};
++
+ class MOZ_RAII TypeOfIRGenerator : public IRGenerator
+ {
+     HandleValue val_;
+ 
+     bool tryAttachPrimitive(ValOperandId valId);
+     bool tryAttachObject(ValOperandId valId);
+ 
+   public:
+diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
+--- a/js/src/jit/CacheIRCompiler.cpp
++++ b/js/src/jit/CacheIRCompiler.cpp
+@@ -858,16 +858,23 @@ CacheIRStubInfo::copyStubData(ICStub* sr
+ 
+ template <typename T>
+ static GCPtr<T>*
+ AsGCPtr(uintptr_t* ptr)
+ {
+     return reinterpret_cast<GCPtr<T>*>(ptr);
+ }
+ 
++uintptr_t
++CacheIRStubInfo::getStubRawWord(ICStub* stub, uint32_t offset) const {
++    uint8_t* stubData = (uint8_t*)stub + stubDataOffset_;
++    MOZ_ASSERT(uintptr_t(stubData) % sizeof(uintptr_t) == 0);
++    return *(uintptr_t*)(stubData + offset);
++}
++
+ template<class Stub, class T>
+ GCPtr<T>&
+ CacheIRStubInfo::getStubField(Stub* stub, uint32_t offset) const
+ {
+     uint8_t* stubData = (uint8_t*)stub + stubDataOffset_;
+     MOZ_ASSERT(uintptr_t(stubData) % sizeof(uintptr_t) == 0);
+ 
+     return *AsGCPtr<T>((uintptr_t*)(stubData + offset));
+@@ -2626,8 +2633,55 @@ CacheIRCompiler::emitCallObjectHasSparse
+     masm.jump(failure->label());
+ 
+     masm.bind(&ok);
+     masm.setFramePushed(framePushed);
+     masm.loadTypedOrValue(Address(masm.getStackPointer(), 0), output);
+     masm.adjustStack(sizeof(Value));
+     return true;
+ }
++
++bool
++CacheIRCompiler::emitLoadInstanceOfObjectResult()
++{
++    AutoOutputRegister output(*this);
++    ValueOperand lhs = allocator.useValueRegister(masm, reader.valOperandId());
++    Register proto = allocator.useRegister(masm, reader.objOperandId());
++
++    AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
++
++    FailurePath* failure;
++    if (!addFailurePath(&failure))
++        return false;
++
++    Label returnFalse, returnTrue, done;
++    masm.branchTestObject(Assembler::NotEqual, lhs, &returnFalse);
++
++    // LHS is an object. Load its proto.
++    masm.unboxObject(lhs, scratch);
++    masm.loadObjProto(scratch, scratch);
++    {
++        // Walk the proto chain until we either reach the target object,
++        // nullptr or LazyProto.
++        Label loop;
++        masm.bind(&loop);
++
++        masm.branchPtr(Assembler::Equal, scratch, proto, &returnTrue);
++        masm.branchTestPtr(Assembler::Zero, scratch, scratch, &returnFalse);
++
++        MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
++        masm.branchPtr(Assembler::Equal, scratch, ImmWord(1), failure->label());
++
++        masm.loadObjProto(scratch, scratch);
++        masm.jump(&loop);
++    }
++
++
++    masm.bind(&returnFalse);
++    EmitStoreBoolean(masm, false, output);
++    masm.jump(&done);
++
++    masm.bind(&returnTrue);
++    EmitStoreBoolean(masm, true, output);
++    //fallthrough
++    masm.bind(&done);
++    return true;
++}
+\ No newline at end of file
+diff --git a/js/src/jit/CacheIRCompiler.h b/js/src/jit/CacheIRCompiler.h
+--- a/js/src/jit/CacheIRCompiler.h
++++ b/js/src/jit/CacheIRCompiler.h
+@@ -42,16 +42,17 @@ namespace jit {
+     _(LoadUndefinedResult)                \
+     _(LoadBooleanResult)                  \
+     _(LoadInt32ArrayLengthResult)         \
+     _(LoadArgumentsObjectLengthResult)    \
+     _(LoadFunctionLengthResult)           \
+     _(LoadStringLengthResult)             \
+     _(LoadStringCharResult)               \
+     _(LoadArgumentsObjectArgResult)       \
++    _(LoadInstanceOfObjectResult)         \
+     _(LoadDenseElementResult)             \
+     _(LoadDenseElementHoleResult)         \
+     _(LoadDenseElementExistsResult)       \
+     _(LoadDenseElementHoleExistsResult)   \
+     _(LoadTypedElementExistsResult)       \
+     _(LoadTypedElementResult)             \
+     _(LoadObjectResult)                   \
+     _(LoadTypeOfObjectResult)             \
+@@ -707,16 +708,18 @@ class CacheIRStubInfo
+     template <class Stub, class T>
+     js::GCPtr<T>& getStubField(Stub* stub, uint32_t field) const;
+ 
+     template <class T>
+     js::GCPtr<T>& getStubField(ICStub* stub, uint32_t field) const {
+         return getStubField<ICStub, T>(stub, field);
+     }
+ 
++    uintptr_t getStubRawWord(ICStub* stub, uint32_t field) const;
++
+     void copyStubData(ICStub* src, ICStub* dest) const;
+ };
+ 
+ template <typename T>
+ void TraceCacheIRStub(JSTracer* trc, T* stub, const CacheIRStubInfo* stubInfo);
+ 
+ } // namespace jit
+ } // namespace js
+diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
+--- a/js/src/jit/CodeGenerator.cpp
++++ b/js/src/jit/CodeGenerator.cpp
+@@ -329,16 +329,17 @@ CodeGenerator::visitOutOfLineICFallback(
+         restoreLiveIgnore(lir, StoreRegisterTo(hasOwnIC->output()).clobbered());
+ 
+         masm.jump(ool->rejoin());
+         return;
+       }
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
++      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+     MOZ_CRASH();
+ }
+ 
+ StringObject*
+ MNewStringObject::templateObj() const
+ {
+diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp
+--- a/js/src/jit/IonCacheIRCompiler.cpp
++++ b/js/src/jit/IonCacheIRCompiler.cpp
+@@ -529,16 +529,17 @@ IonCacheIRCompiler::init()
+         MOZ_ASSERT(numInputs == 2);
+         allocator.initInputLocation(0, ic->id());
+         allocator.initInputLocation(1, ic->value());
+         break;
+       }
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
++      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+ 
+     if (liveRegs_)
+         liveFloatRegs_ = LiveFloatRegisterSet(liveRegs_->fpus());
+ 
+     allocator.initAvailableRegs(available);
+     allocator.initAvailableRegsAfterSpill();
+@@ -847,16 +848,45 @@ IonCacheIRCompiler::emitGuardXrayExpando
+         masm.branchTestObject(Assembler::Equal, expandoAddress, failure->label());
+         masm.bind(&done);
+     }
+ 
+     return true;
+ }
+ 
+ bool
++IonCacheIRCompiler::emitGuardFunctionPrototype()
++{
++    Register obj = allocator.useRegister(masm, reader.objOperandId());
++    Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
++
++    // Allocate registers before the failure path to make sure they're registered
++    // by addFailurePath.
++    AutoScratchRegister scratch1(allocator, masm);
++    AutoScratchRegister scratch2(allocator, masm);
++
++    FailurePath* failure;
++    if (!addFailurePath(&failure))
++        return false;
++
++     // Guard on the .prototype object.
++    masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
++    uintptr_t slot =  readStubWord(reader.stubOffset(), StubField::Type::RawWord);
++    masm.move32(Imm32(slot), scratch2);
++    BaseValueIndex prototypeSlot(scratch1, scratch2);
++    masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
++    masm.unboxObject(prototypeSlot, scratch1);
++    masm.branchPtr(Assembler::NotEqual,
++                   prototypeObject,
++                   scratch1, failure->label());
++
++    return true;
++}
++
++bool
+ IonCacheIRCompiler::emitLoadFixedSlotResult()
+ {
+     AutoOutputRegister output(*this);
+     Register obj = allocator.useRegister(masm, reader.objOperandId());
+     int32_t offset = int32StubField(reader.stubOffset());
+     masm.loadTypedOrValue(Address(obj, offset), output);
+     return true;
+ }
+diff --git a/js/src/jit/IonIC.cpp b/js/src/jit/IonIC.cpp
+--- a/js/src/jit/IonIC.cpp
++++ b/js/src/jit/IonIC.cpp
+@@ -56,16 +56,17 @@ IonIC::scratchRegisterForEntryJump()
+         return asInIC()->temp();
+       case CacheKind::HasOwn:
+         return asHasOwnIC()->output();
+       case CacheKind::GetIterator:
+         return asGetIteratorIC()->temp1();
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
++      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+ 
+     MOZ_CRASH("Invalid kind");
+ }
+ 
+ void
+ IonIC::discardStubs(Zone* zone)
+diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp
+--- a/js/src/jit/SharedIC.cpp
++++ b/js/src/jit/SharedIC.cpp
+@@ -292,22 +292,16 @@ ICStub::trace(JSTracer* trc)
+         TraceEdge(trc, &updateStub->group(), "baseline-update-group");
+         break;
+       }
+       case ICStub::GetIntrinsic_Constant: {
+         ICGetIntrinsic_Constant* constantStub = toGetIntrinsic_Constant();
+         TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
+         break;
+       }
+-      case ICStub::InstanceOf_Function: {
+-        ICInstanceOf_Function* instanceofStub = toInstanceOf_Function();
+-        TraceEdge(trc, &instanceofStub->shape(), "baseline-instanceof-fun-shape");
+-        TraceEdge(trc, &instanceofStub->prototypeObject(), "baseline-instanceof-fun-prototype");
+-        break;
+-      }
+       case ICStub::NewArray_Fallback: {
+         ICNewArray_Fallback* stub = toNewArray_Fallback();
+         TraceNullableEdge(trc, &stub->templateObject(), "baseline-newarray-template");
+         TraceEdge(trc, &stub->templateGroup(), "baseline-newarray-template-group");
+         break;
+       }
+       case ICStub::NewObject_Fallback: {
+         ICNewObject_Fallback* stub = toNewObject_Fallback();

+ 658 - 0
mozilla-release/patches/1420910-2-60a1.patch

@@ -0,0 +1,658 @@
+# HG changeset patch
+# User Matthew Gaudet <mgaudet@mozilla.com>
+# Date 1515784027 18000
+# Node ID af6fb4b32a61f661e9f6e83117166a9dbc7553dd
+# Parent  bb29bd2947679ead4657b1971e784c606ff8b19a
+Bug 1420910: Add InstanceOf inline cache to IonMonkey r=jandem
+
+Install an inline cache for some of the instanceof calls in IonMonkey that
+would otherwise hit the interpreter.
+
+diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
+--- a/js/src/jit/BaselineIC.cpp
++++ b/js/src/jit/BaselineIC.cpp
+@@ -4287,17 +4287,17 @@ ICIteratorClose_Fallback::Compiler::gene
+ }
+ 
+ //
+ // InstanceOf_Fallback
+ //
+ 
+ static bool
+ TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
+-                        HandleValue lhs, HandleValue rhs, bool* attached)
++                        HandleValue lhs, HandleObject rhs, bool* attached)
+ {
+     MOZ_ASSERT(!*attached);
+     FallbackICSpew(cx, stub, "InstanceOf");
+ 
+     if (stub->state().maybeTransition())
+         stub->discardStubs(cx);
+ 
+     if (stub->state().canAttachStub()) {
+@@ -4346,17 +4346,17 @@ DoInstanceOfFallback(JSContext* cx, Base
+         return true;
+     }
+ 
+     // For functions, keep track of the |prototype| property in type information,
+     // for use during Ion compilation.
+     EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
+ 
+     bool attached = false;
+-    if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, rhs, &attached))
++    if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, obj, &attached))
+         return false;
+     if (!attached)
+         stub->noteUnoptimizableAccess();
+     return true;
+ }
+ 
+ typedef bool (*DoInstanceOfFallbackFn)(JSContext*, BaselineFrame*, ICInstanceOf_Fallback*,
+                                        HandleValue, HandleValue, MutableHandleValue);
+diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
+--- a/js/src/jit/CacheIR.cpp
++++ b/js/src/jit/CacheIR.cpp
+@@ -4202,28 +4202,35 @@ SetPropIRGenerator::tryAttachAddSlotStub
+     }
+     writer.returnFromIC();
+ 
+     typeCheckInfo_.set(oldGroup, id);
+     return true;
+ }
+ 
+ InstanceOfIRGenerator::InstanceOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
+-                                            ICState::Mode mode, HandleValue lhs, HandleValue rhs)
++                                            ICState::Mode mode, HandleValue lhs, HandleObject rhs)
+   : IRGenerator(cx, script, pc, CacheKind::InstanceOf, mode),
+     lhsVal_(lhs),
+-    rhsVal_(rhs)
++    rhsObj_(rhs)
+ { }
+ 
+ bool
+ InstanceOfIRGenerator::tryAttachStub()
+ {
+     MOZ_ASSERT(cacheKind_ == CacheKind::InstanceOf);
+     AutoAssertNoPendingException aanpe(cx_);
+-    RootedFunction fun(cx_, &rhsVal_.toObject().as<JSFunction>());
++
++    // Ensure RHS is a function -- could be a Proxy, which the IC isn't prepared to handle.
++    if (!rhsObj_->is<JSFunction>()) {
++        trackNotAttached();
++        return false;
++    }
++
++    HandleFunction fun = rhsObj_.as<JSFunction>();
+ 
+     if (fun->isBoundFunction()) {
+         trackNotAttached();
+         return false;
+     }
+ 
+     // If the user has supplied their own @@hasInstance method we shouldn't
+     // clobber it.
+@@ -4286,33 +4293,33 @@ void
+ InstanceOfIRGenerator::trackAttached(const char* name)
+ {
+ #ifdef JS_CACHEIR_SPEW
+     CacheIRSpewer& sp = CacheIRSpewer::singleton();
+     if (sp.enabled()) {
+         LockGuard<Mutex> guard(sp.lock());
+         sp.beginCache(guard, *this);
+         sp.valueProperty(guard, "lhs", lhsVal_);
+-        sp.valueProperty(guard, "rhs", rhsVal_);
++        sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
+         sp.attached(guard, name);
+         sp.endCache(guard);
+     }
+ #endif
+ }
+ 
+ void
+ InstanceOfIRGenerator::trackNotAttached()
+ {
+ #ifdef JS_CACHEIR_SPEW
+     CacheIRSpewer& sp = CacheIRSpewer::singleton();
+     if (sp.enabled()) {
+         LockGuard<Mutex> guard(sp.lock());
+         sp.beginCache(guard, *this);
+         sp.valueProperty(guard, "lhs", lhsVal_);
+-        sp.valueProperty(guard, "rhs", rhsVal_);
++        sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
+         sp.endCache(guard);
+     }
+ #endif
+ }
+ 
+ TypeOfIRGenerator::TypeOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
+                                      ICState::Mode mode, HandleValue value)
+   : IRGenerator(cx, script, pc, CacheKind::TypeOf, mode),
+diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h
+--- a/js/src/jit/CacheIR.h
++++ b/js/src/jit/CacheIR.h
+@@ -1543,23 +1543,23 @@ class MOZ_RAII HasPropIRGenerator : publ
+                        ICState::Mode mode, HandleValue idVal, HandleValue val);
+ 
+     bool tryAttachStub();
+ };
+ 
+ class MOZ_RAII InstanceOfIRGenerator : public IRGenerator
+ {
+     HandleValue lhsVal_;
+-    HandleValue rhsVal_;
++    HandleObject rhsObj_;
+ 
+     void trackAttached(const char* name);
+     void trackNotAttached();
+   public:
+     InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
+-                          HandleValue, HandleValue);
++                          HandleValue, HandleObject);
+ 
+     bool tryAttachStub();
+ };
+ 
+ class MOZ_RAII TypeOfIRGenerator : public IRGenerator
+ {
+     HandleValue val_;
+ 
+diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
+--- a/js/src/jit/CodeGenerator.cpp
++++ b/js/src/jit/CodeGenerator.cpp
+@@ -168,16 +168,22 @@ static const VMFunction IonBindNameICInf
+ typedef JSObject* (*IonGetIteratorICFn)(JSContext*, HandleScript, IonGetIteratorIC*, HandleValue);
+ static const VMFunction IonGetIteratorICInfo =
+     FunctionInfo<IonGetIteratorICFn>(IonGetIteratorIC::update, "IonGetIteratorIC::update");
+ 
+ typedef bool (*IonInICFn)(JSContext*, HandleScript, IonInIC*, HandleValue, HandleObject, bool*);
+ static const VMFunction IonInICInfo =
+     FunctionInfo<IonInICFn>(IonInIC::update, "IonInIC::update");
+ 
++
++typedef bool (*IonInstanceOfICFn)(JSContext*, HandleScript, IonInstanceOfIC*,
++                         HandleValue lhs, HandleObject rhs, bool* res);
++static const VMFunction IonInstanceOfInfo =
++    FunctionInfo<IonInstanceOfICFn>(IonInstanceOfIC::update, "IonInstanceOfIC::update");
++
+ void
+ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
+ {
+     LInstruction* lir = ool->lir();
+     size_t cacheIndex = ool->cacheIndex();
+     size_t cacheInfoIndex = ool->cacheInfoIndex();
+ 
+     DataPtr<IonIC> ic(this, cacheIndex);
+@@ -326,20 +332,37 @@ CodeGenerator::visitOutOfLineICFallback(
+         callVM(IonHasOwnICInfo, lir);
+ 
+         StoreRegisterTo(hasOwnIC->output()).generate(this);
+         restoreLiveIgnore(lir, StoreRegisterTo(hasOwnIC->output()).clobbered());
+ 
+         masm.jump(ool->rejoin());
+         return;
+       }
++      case CacheKind::InstanceOf: {
++        IonInstanceOfIC* hasInstanceOfIC = ic->asInstanceOfIC();
++
++        saveLive(lir);
++
++        pushArg(hasInstanceOfIC->rhs());
++        pushArg(hasInstanceOfIC->lhs());
++        icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
++        pushArg(ImmGCPtr(gen->info().script()));
++
++        callVM(IonInstanceOfInfo, lir);
++
++        StoreRegisterTo(hasInstanceOfIC->output()).generate(this);
++        restoreLiveIgnore(lir, StoreRegisterTo(hasInstanceOfIC->output()).clobbered());
++
++        masm.jump(ool->rejoin());
++        return;
++      }
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
+-      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+     MOZ_CRASH();
+ }
+ 
+ StringObject*
+ MNewStringObject::templateObj() const
+ {
+@@ -11609,25 +11632,26 @@ CodeGenerator::emitInstanceOf(LInstructi
+     masm.bind(&done);
+     masm.bind(ool->rejoin());
+ }
+ 
+ typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
+ static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
+ 
+ void
+-CodeGenerator::visitCallInstanceOf(LCallInstanceOf* ins)
+-{
+-    ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
++CodeGenerator::visitInstanceOfCache(LInstanceOfCache* ins)
++{
++    // The Lowering ensures that RHS is an object, and that LHS is a value.
++    LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
++    TypedOrValueRegister lhs = TypedOrValueRegister(ToValue(ins, LInstanceOfCache::LHS));
+     Register rhs = ToRegister(ins->rhs());
+-    MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
+-
+-    pushArg(lhs);
+-    pushArg(rhs);
+-    callVM(HasInstanceInfo, ins);
++    Register output = ToRegister(ins->output());
++
++    IonInstanceOfIC ic(liveRegs, lhs, rhs, output);
++    addIC(ins, allocateIC(ic));
+ }
+ 
+ void
+ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
+ {
+     const Register JSContextReg = ToRegister(ins->getJSContextReg());
+     const Register ObjectReg = ToRegister(ins->getObjectReg());
+     const Register PrivateReg = ToRegister(ins->getPrivReg());
+diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
+--- a/js/src/jit/CodeGenerator.h
++++ b/js/src/jit/CodeGenerator.h
+@@ -366,17 +366,17 @@ class CodeGenerator final : public CodeG
+     void visitCallDeleteElement(LCallDeleteElement* lir);
+     void visitBitNotV(LBitNotV* lir);
+     void visitBitOpV(LBitOpV* lir);
+     void emitInstanceOf(LInstruction* ins, JSObject* prototypeObject);
+     void visitInCache(LInCache* ins);
+     void visitInArray(LInArray* ins);
+     void visitInstanceOfO(LInstanceOfO* ins);
+     void visitInstanceOfV(LInstanceOfV* ins);
+-    void visitCallInstanceOf(LCallInstanceOf* ins);
++    void visitInstanceOfCache(LInstanceOfCache* ins);
+     void visitGetDOMProperty(LGetDOMProperty* lir);
+     void visitGetDOMMemberV(LGetDOMMemberV* lir);
+     void visitGetDOMMemberT(LGetDOMMemberT* lir);
+     void visitSetDOMProperty(LSetDOMProperty* lir);
+     void visitCallDOMNative(LCallDOMNative* lir);
+     void visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir);
+     void visitCallBindVar(LCallBindVar* lir);
+     enum CallableOrConstructor {
+diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
+--- a/js/src/jit/IonBuilder.cpp
++++ b/js/src/jit/IonBuilder.cpp
+@@ -13169,17 +13169,17 @@ IonBuilder::jsop_instanceof()
+             return Ok();
+ 
+         MInstanceOf* ins = MInstanceOf::New(alloc(), obj, protoObject);
+         current->add(ins);
+         current->push(ins);
+         return resumeAfter(ins);
+     } while (false);
+ 
+-    MCallInstanceOf* ins = MCallInstanceOf::New(alloc(), obj, rhs);
++    MInstanceOfCache* ins = MInstanceOfCache::New(alloc(), obj, rhs);
+ 
+     current->add(ins);
+     current->push(ins);
+ 
+     return resumeAfter(ins);
+ }
+ 
+ AbortReasonOr<Ok>
+diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp
+--- a/js/src/jit/IonCacheIRCompiler.cpp
++++ b/js/src/jit/IonCacheIRCompiler.cpp
+@@ -526,20 +526,32 @@ IonCacheIRCompiler::init()
+         liveRegs_.emplace(ic->liveRegs());
+         outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Boolean, AnyRegister(output)));
+ 
+         MOZ_ASSERT(numInputs == 2);
+         allocator.initInputLocation(0, ic->id());
+         allocator.initInputLocation(1, ic->value());
+         break;
+       }
++      case CacheKind::InstanceOf: {
++        IonInstanceOfIC* ic = ic_->asInstanceOfIC();
++        Register output = ic->output();
++        available.add(output);
++        liveRegs_.emplace(ic->liveRegs());
++        outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Boolean, AnyRegister(output)));
++
++        MOZ_ASSERT(numInputs == 2);
++        allocator.initInputLocation(0, ic->lhs());
++        allocator.initInputLocation(1, TypedOrValueRegister(MIRType::Object,
++                                                            AnyRegister(ic->rhs())));
++        break;
++      }
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
+-      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+ 
+     if (liveRegs_)
+         liveFloatRegs_ = LiveFloatRegisterSet(liveRegs_->fpus());
+ 
+     allocator.initAvailableRegs(available);
+     allocator.initAvailableRegsAfterSpill();
+diff --git a/js/src/jit/IonIC.cpp b/js/src/jit/IonIC.cpp
+--- a/js/src/jit/IonIC.cpp
++++ b/js/src/jit/IonIC.cpp
+@@ -53,20 +53,21 @@ IonIC::scratchRegisterForEntryJump()
+       case CacheKind::BindName:
+         return asBindNameIC()->temp();
+       case CacheKind::In:
+         return asInIC()->temp();
+       case CacheKind::HasOwn:
+         return asHasOwnIC()->output();
+       case CacheKind::GetIterator:
+         return asGetIteratorIC()->temp1();
++      case CacheKind::InstanceOf:
++        return asInstanceOfIC()->output();
+       case CacheKind::Call:
+       case CacheKind::Compare:
+       case CacheKind::TypeOf:
+-      case CacheKind::InstanceOf:
+         MOZ_CRASH("Unsupported IC");
+     }
+ 
+     MOZ_CRASH("Invalid kind");
+ }
+ 
+ void
+ IonIC::discardStubs(Zone* zone)
+@@ -479,16 +480,42 @@ IonInIC::update(JSContext* cx, HandleScr
+             ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
+ 
+         if (!attached)
+             ic->state().trackNotAttached();
+     }
+ 
+     return OperatorIn(cx, key, obj, res);
+ }
++/* static */ bool
++IonInstanceOfIC::update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
++                        HandleValue lhs, HandleObject rhs, bool* res)
++{
++    IonScript* ionScript = outerScript->ionScript();
++
++    if (ic->state().maybeTransition())
++        ic->discardStubs(cx->zone());
++
++    if (ic->state().canAttachStub()) {
++        bool attached = false;
++        RootedScript script(cx, ic->script());
++        jsbytecode* pc = ic->pc();
++
++        InstanceOfIRGenerator gen(cx, script, pc, ic->state().mode(),
++                                  lhs, rhs);
++
++        if (gen.tryAttachStub())
++            ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
++
++        if (!attached)
++            ic->state().trackNotAttached();
++    }
++
++    return HasInstance(cx, rhs, lhs, res);
++}
+ 
+ uint8_t*
+ IonICStub::stubDataStart()
+ {
+     return reinterpret_cast<uint8_t*>(this) + stubInfo_->stubDataOffset();
+ }
+ 
+ void
+diff --git a/js/src/jit/IonIC.h b/js/src/jit/IonIC.h
+--- a/js/src/jit/IonIC.h
++++ b/js/src/jit/IonIC.h
+@@ -59,16 +59,17 @@ class IonICStub
+ class IonGetPropertyIC;
+ class IonSetPropertyIC;
+ class IonGetPropSuperIC;
+ class IonGetNameIC;
+ class IonBindNameIC;
+ class IonGetIteratorIC;
+ class IonHasOwnIC;
+ class IonInIC;
++class IonInstanceOfIC;
+ 
+ class IonIC
+ {
+     // This either points at the OOL path for the fallback path, or the code for
+     // the first stub.
+     uint8_t* codeRaw_;
+ 
+     // The first optimized stub, or nullptr.
+@@ -162,16 +163,20 @@ class IonIC
+     IonHasOwnIC* asHasOwnIC() {
+         MOZ_ASSERT(kind_ == CacheKind::HasOwn);
+         return (IonHasOwnIC*)this;
+     }
+     IonInIC* asInIC() {
+         MOZ_ASSERT(kind_ == CacheKind::In);
+         return (IonInIC*)this;
+     }
++    IonInstanceOfIC* asInstanceOfIC() {
++        MOZ_ASSERT(kind_ == CacheKind::InstanceOf);
++        return (IonInstanceOfIC*)this;
++    }
+ 
+     void updateBaseAddress(JitCode* code, MacroAssembler& masm);
+ 
+     // Returns the Register to use as scratch when entering IC stubs. This
+     // should either be an output register or a temp.
+     Register scratchRegisterForEntryJump();
+ 
+     void trace(JSTracer* trc);
+@@ -436,12 +441,41 @@ class IonInIC : public IonIC
+     Register output() const { return output_; }
+     Register temp() const { return temp_; }
+     LiveRegisterSet liveRegs() const { return liveRegs_; }
+ 
+     static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonInIC* ic,
+                                     HandleValue key, HandleObject obj, bool* res);
+ };
+ 
++class IonInstanceOfIC : public IonIC
++{
++    LiveRegisterSet liveRegs_;
++
++    TypedOrValueRegister lhs_;
++    Register rhs_;
++    Register output_;
++
++    public:
++
++    IonInstanceOfIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, Register rhs,
++                    Register output)
++      : IonIC(CacheKind::InstanceOf),
++        liveRegs_(liveRegs),
++        lhs_(lhs),
++        rhs_(rhs),
++        output_(output)
++    { }
++
++    LiveRegisterSet liveRegs() const { return liveRegs_; }
++    TypedOrValueRegister lhs() const { return lhs_; }
++    Register rhs() const { return rhs_; }
++    Register output() const { return output_; }
++
++    // This signature mimics that of TryAttachInstanceOfStub in baseline
++    static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
++                                    HandleValue lhs, HandleObject rhs, bool* attached);
++};
++
+ } // namespace jit
+ } // namespace js
+ 
+ #endif /* jit_IonIC_h */
+diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
+--- a/js/src/jit/Lowering.cpp
++++ b/js/src/jit/Lowering.cpp
+@@ -4334,27 +4334,27 @@ LIRGenerator::visitInstanceOf(MInstanceO
+     } else {
+         LInstanceOfV* lir = new(alloc()) LInstanceOfV(useBox(lhs));
+         define(lir, ins);
+         assignSafepoint(lir, ins);
+     }
+ }
+ 
+ void
+-LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
++LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins)
+ {
+     MDefinition* lhs = ins->lhs();
+     MDefinition* rhs = ins->rhs();
+ 
+     MOZ_ASSERT(lhs->type() == MIRType::Value);
+     MOZ_ASSERT(rhs->type() == MIRType::Object);
+ 
+-    LCallInstanceOf* lir = new(alloc()) LCallInstanceOf(useBoxAtStart(lhs),
+-                                                        useRegisterAtStart(rhs));
+-    defineReturn(lir, ins);
++    LInstanceOfCache* lir = new(alloc()) LInstanceOfCache(useBox(lhs),
++                                                          useRegister(rhs));
++    define(lir, ins);
+     assignSafepoint(lir, ins);
+ }
+ 
+ void
+ LIRGenerator::visitIsArray(MIsArray* ins)
+ {
+     MOZ_ASSERT(ins->type() == MIRType::Boolean);
+ 
+diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
+--- a/js/src/jit/Lowering.h
++++ b/js/src/jit/Lowering.h
+@@ -289,17 +289,17 @@ class LIRGenerator : public LIRGenerator
+     void visitSetFrameArgument(MSetFrameArgument* ins);
+     void visitRunOncePrologue(MRunOncePrologue* ins);
+     void visitRest(MRest* ins);
+     void visitThrow(MThrow* ins);
+     void visitInCache(MInCache* ins);
+     void visitInArray(MInArray* ins);
+     void visitHasOwnCache(MHasOwnCache* ins);
+     void visitInstanceOf(MInstanceOf* ins);
+-    void visitCallInstanceOf(MCallInstanceOf* ins);
++    void visitInstanceOfCache(MInstanceOfCache* ins);
+     void visitIsCallable(MIsCallable* ins);
+     void visitIsConstructor(MIsConstructor* ins);
+     void visitIsArray(MIsArray* ins);
+     void visitIsTypedArray(MIsTypedArray* ins);
+     void visitIsObject(MIsObject* ins);
+     void visitHasClass(MHasClass* ins);
+     void visitObjectClassToString(MObjectClassToString* ins);
+     void visitWasmAddOffset(MWasmAddOffset* ins);
+diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
+--- a/js/src/jit/MIR.h
++++ b/js/src/jit/MIR.h
+@@ -12912,28 +12912,28 @@ class MInstanceOf
+     }
+ 
+     bool appendRoots(MRootList& roots) const override {
+         return roots.append(protoObj_);
+     }
+ };
+ 
+ // Implementation for instanceof operator with unknown rhs.
+-class MCallInstanceOf
++class MInstanceOfCache
+   : public MBinaryInstruction,
+     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
+ {
+-    MCallInstanceOf(MDefinition* obj, MDefinition* proto)
++    MInstanceOfCache(MDefinition* obj, MDefinition* proto)
+       : MBinaryInstruction(classOpcode, obj, proto)
+     {
+         setResultType(MIRType::Boolean);
+     }
+ 
+   public:
+-    INSTRUCTION_HEADER(CallInstanceOf)
++    INSTRUCTION_HEADER(InstanceOfCache)
+     TRIVIAL_NEW_WRAPPERS
+ };
+ 
+ class MArgumentsLength : public MNullaryInstruction
+ {
+     MArgumentsLength()
+       : MNullaryInstruction(classOpcode)
+     {
+diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
+--- a/js/src/jit/MOpcodes.h
++++ b/js/src/jit/MOpcodes.h
+@@ -270,17 +270,17 @@ namespace jit {
+     _(Rest)                                                                 \
+     _(Floor)                                                                \
+     _(Ceil)                                                                 \
+     _(Round)                                                                \
+     _(NearbyInt)                                                            \
+     _(InCache)                                                              \
+     _(HasOwnCache)                                                          \
+     _(InstanceOf)                                                           \
+-    _(CallInstanceOf)                                                       \
++    _(InstanceOfCache)                                                      \
+     _(InterruptCheck)                                                       \
+     _(GetDOMProperty)                                                       \
+     _(GetDOMMember)                                                         \
+     _(SetDOMProperty)                                                       \
+     _(IsConstructor)                                                        \
+     _(IsCallable)                                                           \
+     _(IsArray)                                                              \
+     _(IsTypedArray)                                                         \
+diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
+--- a/js/src/jit/shared/LIR-shared.h
++++ b/js/src/jit/shared/LIR-shared.h
+@@ -8021,21 +8021,21 @@ class LInstanceOfV : public LInstruction
+ 
+     const LAllocation* lhs() {
+         return getOperand(LHS);
+     }
+ 
+     static const size_t LHS = 0;
+ };
+ 
+-class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
+-{
+-  public:
+-    LIR_HEADER(CallInstanceOf)
+-    LCallInstanceOf(const LBoxAllocation& lhs, const LAllocation& rhs) {
++class LInstanceOfCache : public LInstructionHelper<1, BOX_PIECES+1, 0>
++{
++  public:
++    LIR_HEADER(InstanceOfCache)
++    LInstanceOfCache(const LBoxAllocation& lhs, const LAllocation& rhs) {
+         setBoxOperand(LHS, lhs);
+         setOperand(RHS, rhs);
+     }
+ 
+     const LDefinition* output() {
+         return this->getDef(0);
+     }
+     const LAllocation* lhs() {
+diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h
+--- a/js/src/jit/shared/LOpcodes-shared.h
++++ b/js/src/jit/shared/LOpcodes-shared.h
+@@ -378,17 +378,17 @@
+     _(RoundF)                       \
+     _(NearbyInt)                    \
+     _(NearbyIntF)                   \
+     _(InCache)                      \
+     _(InArray)                      \
+     _(HasOwnCache)                  \
+     _(InstanceOfO)                  \
+     _(InstanceOfV)                  \
+-    _(CallInstanceOf)               \
++    _(InstanceOfCache)              \
+     _(InterruptCheck)               \
+     _(Rotate)                       \
+     _(RotateI64)                    \
+     _(GetDOMProperty)               \
+     _(GetDOMMemberV)                \
+     _(GetDOMMemberT)                \
+     _(SetDOMProperty)               \
+     _(CallDOMNative)                \

+ 81 - 0
mozilla-release/patches/1424978-60a1.patch

@@ -0,0 +1,81 @@
+# HG changeset patch
+# User yuyin <yuyin-hf@loongson.cn>
+# Date 1513123440 -7200
+# Node ID 7da8287a6c2af02ae7cc908bec78b42b55b1c102
+# Parent  580404a82ac374117121c5d7854c9bcaf27209d8
+Bug 1424978 MIPS: Fix some function implement. r=lth
+
+diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
++++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+@@ -325,19 +325,26 @@ MacroAssemblerMIPSShared::ma_addu(Regist
+ {
+     ma_addu(rd, rd, imm);
+ }
+ 
+ template <typename L>
+ void
+ MacroAssemblerMIPSShared::ma_addTestCarry(Register rd, Register rs, Register rt, L overflow)
+ {
+-    as_addu(rd, rs, rt);
+-    as_sltu(SecondScratchReg, rd, rs);
+-    ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
++    if (rd != rs) {
++        as_addu(rd, rs, rt);
++        as_sltu(SecondScratchReg, rd, rs);
++        ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
++    } else {
++        ma_move(SecondScratchReg, rs);
++        as_addu(rd, rs, rt);
++        as_sltu(SecondScratchReg, rd, SecondScratchReg);
++        ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
++    }
+ }
+ 
+ template void
+ MacroAssemblerMIPSShared::ma_addTestCarry<Label*>(Register rd, Register rs,
+                                                   Register rt, Label* overflow);
+ template void
+ MacroAssemblerMIPSShared::ma_addTestCarry<wasm::OldTrapDesc>(Register rd, Register rs, Register rt,
+                                                              wasm::OldTrapDesc overflow);
+@@ -706,17 +713,17 @@ MacroAssemblerMIPSShared::ma_store(Imm32
+ void
+ MacroAssemblerMIPSShared::ma_store_unaligned(const wasm::MemoryAccessDesc& access, Register data, const BaseIndex& dest, Register temp,
+                                              LoadStoreSize size, LoadStoreExtension extension)
+ {
+     MOZ_ASSERT(MOZ_LITTLE_ENDIAN, "Wasm-only; wasm is disabled on big-endian.");
+     int16_t lowOffset, hiOffset;
+     Register base;
+ 
+-    asMasm().computeEffectiveAddress(dest, SecondScratchReg);
++    asMasm().computeScaledAddress(dest, SecondScratchReg);
+ 
+     if (Imm16::IsInSignedRange(dest.offset) && Imm16::IsInSignedRange(dest.offset + size / 8 - 1)) {
+         base = SecondScratchReg;
+         lowOffset = Imm16(dest.offset).encode();
+         hiOffset = Imm16(dest.offset + size / 8 - 1).encode();
+     } else {
+         ma_li(ScratchRegister, Imm32(dest.offset));
+         asMasm().addPtr(SecondScratchReg, ScratchRegister);
+diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp
+--- a/js/src/jit/mips64/Trampoline-mips64.cpp
++++ b/js/src/jit/mips64/Trampoline-mips64.cpp
+@@ -60,18 +60,16 @@ struct EnterJITRegs
+     uint64_t s0;
+     // Save reg_vp(a7) on stack, use it after call jit code.
+     uint64_t a7;
+ };
+ 
+ static void
+ GenerateReturn(MacroAssembler& masm, int returnCode)
+ {
+-    MOZ_ASSERT(masm.framePushed() == sizeof(EnterJITRegs));
+-
+     if (isLoongson()) {
+         // Restore non-volatile registers
+         masm.as_ld(s0, StackPointer, offsetof(EnterJITRegs, s0));
+         masm.as_gslq(s1, s2, StackPointer, offsetof(EnterJITRegs, s2));
+         masm.as_gslq(s3, s4, StackPointer, offsetof(EnterJITRegs, s4));
+         masm.as_gslq(s5, s6, StackPointer, offsetof(EnterJITRegs, s6));
+         masm.as_gslq(s7, fp, StackPointer, offsetof(EnterJITRegs, fp));
+         masm.as_ld(ra, StackPointer, offsetof(EnterJITRegs, ra));

+ 11 - 11
mozilla-release/patches/1429206-3no2-60a1.patch

@@ -2,7 +2,7 @@
 # User Jason Orendorff <jorendorff@mozilla.com>
 # Date 1518458617 21600
 # Node ID eabb74b1c3bd181ff74c9d41003bc2b9aee6fe68
-# Parent  edf4f3b8a0be0911bfa346604c77b51b93f1d4e7
+# Parent  08ba879bf6c3b06c917658816360662293aaaaf8
 Bug 1429206 - Part 3: Rename jsobj* -> vm/JSObject*. r=jandem.
 
 diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py
@@ -68,13 +68,13 @@ diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h
  #include "threading/ConditionVariable.h"
 +#include "vm/JSObject.h"
  #include "vm/MutexIDs.h"
+ #include "vm/NativeObject.h"
  
  namespace js {
  
- class AtomicsObject : public JSObject
+ class AtomicsObject : public NativeObject
  {
    public:
-     static const Class class_;
 diff --git a/js/src/builtin/DataViewObject.cpp b/js/src/builtin/DataViewObject.cpp
 --- a/js/src/builtin/DataViewObject.cpp
 +++ b/js/src/builtin/DataViewObject.cpp
@@ -1312,7 +1312,7 @@ diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.c
 diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
 --- a/js/src/jsapi.cpp
 +++ b/js/src/jsapi.cpp
-@@ -25,17 +25,16 @@
+@@ -28,17 +28,16 @@
  #include "jscntxt.h"
  #include "jsdate.h"
  #include "jsexn.h"
@@ -1330,7 +1330,7 @@ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
  #include "jsutil.h"
  #include "jsweakmap.h"
  #include "jswrapper.h"
-@@ -71,16 +70,17 @@
+@@ -74,16 +73,17 @@
  #include "vm/AsyncFunction.h"
  #include "vm/AsyncIteration.h"
  #include "vm/DateObject.h"
@@ -2333,7 +2333,7 @@ diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp
 diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
 --- a/js/src/shell/js.cpp
 +++ b/js/src/shell/js.cpp
-@@ -47,17 +47,16 @@
+@@ -50,17 +50,16 @@
  # include <unistd.h>
  #endif
  
@@ -2351,7 +2351,7 @@ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
  # include "jswin.h"
  #endif
  #include "jswrapper.h"
-@@ -88,32 +87,33 @@
+@@ -95,32 +94,33 @@
  #include "threading/LockGuard.h"
  #include "threading/Thread.h"
  #include "vm/ArgumentsObject.h"
@@ -2657,8 +2657,9 @@ diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
  #include "gc/Tracer.h"
  #include "js/RootingAPI.h"
  #include "js/UniquePtr.h"
- #include "vm/NativeObject.h"
+ #include "vm/ArrayObject.h"
 +#include "vm/JSObject.h"
+ #include "vm/NativeObject.h"
  
  namespace js {
  
@@ -2666,7 +2667,6 @@ diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
   * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
   * given pc in a script. We use the script->code pointer to tag the cache,
   * instead of the script address itself, so that source notes are always found
-  * by offset from the bytecode with which they were generated.
 diff --git a/js/src/vm/CallNonGenericMethod.cpp b/js/src/vm/CallNonGenericMethod.cpp
 --- a/js/src/vm/CallNonGenericMethod.cpp
 +++ b/js/src/vm/CallNonGenericMethod.cpp
@@ -3078,7 +3078,7 @@ rename to js/src/vm/JSObject-inl.h
  
  #include "builtin/MapObject.h"
  #include "builtin/TypedObject.h"
-@@ -917,9 +917,9 @@ JSObject::constructHook() const
+@@ -904,9 +904,9 @@ JSObject::constructHook() const
      if (is<js::ProxyObject>()) {
          const js::ProxyObject& p = as<js::ProxyObject>();
          if (p.handler()->isConstructor(const_cast<JSObject*>(this)))
@@ -3137,7 +3137,7 @@ rename to js/src/vm/JSObject.h
   * ordered property names, called the map; and a dense vector of property
   * values, called slots.  The map/slot pointer pair is GC'ed, while the map
   * is reference counted and the slot vector is malloc'ed.
-@@ -1311,9 +1311,9 @@ IsObjectValueInCompartment(const Value& 
+@@ -1329,9 +1329,9 @@ IsObjectValueInCompartment(const Value& 
      if (!v.isObject())
          return true;
      return v.toObject().compartment() == comp;

+ 3 - 4
mozilla-release/patches/1429206-5-60a1.patch

@@ -2,7 +2,7 @@
 # User Jason Orendorff <jorendorff@mozilla.com>
 # Date 1518462436 21600
 # Node ID 711c111e333087942d9e5c7310a342ddffbcfabb
-# Parent  25b578f4d271a6e85240a1579dd1b1e2201044d9
+# Parent  63247f5cccd63df6871e9e9ed22a804a7ba9253d
 Bug 1429206 - Part 5: Rename jsscript* -> vm/JSScript*. r=jandem.
 
 diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py
@@ -1601,10 +1601,10 @@ diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
  #include "gc/Tracer.h"
  #include "js/RootingAPI.h"
  #include "js/UniquePtr.h"
-+#include "vm/JSObject.h"
+ #include "vm/ArrayObject.h"
+ #include "vm/JSObject.h"
 +#include "vm/JSScript.h"
  #include "vm/NativeObject.h"
--#include "vm/JSObject.h"
  
  namespace js {
  
@@ -1612,7 +1612,6 @@ diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
   * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
   * given pc in a script. We use the script->code pointer to tag the cache,
   * instead of the script address itself, so that source notes are always found
-  * by offset from the bytecode with which they were generated.
 diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp
 --- a/js/src/vm/CodeCoverage.cpp
 +++ b/js/src/vm/CodeCoverage.cpp

+ 3 - 3
mozilla-release/patches/1429206-8-60a1.patch

@@ -2,7 +2,7 @@
 # User Jason Orendorff <jorendorff@mozilla.com>
 # Date 1518471436 21600
 # Node ID 0054d892b106cfc60874dc1662a7278c74108b03
-# Parent  162b578f2123aac1cff877d0fc295dc8df5524b2
+# Parent  2a4a9afbb9fc0dce08205eb251513fda5ee2ba28
 Bug 1429206 - Part 8: Rename jsatom* -> vm/JSAtom*. r=jandem.
 
 diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h
@@ -687,8 +687,7 @@ diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
 diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
 --- a/js/src/vm/Caches.h
 +++ b/js/src/vm/Caches.h
-@@ -9,16 +9,17 @@
- 
+@@ -10,16 +10,17 @@
  #include "jsbytecode.h"
  #include "jsmath.h"
  
@@ -696,6 +695,7 @@ diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
  #include "gc/Tracer.h"
  #include "js/RootingAPI.h"
  #include "js/UniquePtr.h"
+ #include "vm/ArrayObject.h"
 +#include "vm/JSAtom.h"
  #include "vm/JSObject.h"
  #include "vm/JSScript.h"

+ 31 - 0
mozilla-release/patches/1433597-60a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User Gary Kwong <gary@rumblingedge.com>
+# Date 1516978680 -7200
+# Node ID 65bdc8a9edbd001bffb50756f5fce3262e0e9ee8
+# Parent  b1c8ba93a6c2f5e9179c8ff252ba7e049558e408
+Bug 1433597 - Remove unused --wasm-check-bce flag, r=luke
+
+diff --git a/js/src/tests/lib/jittests.py b/js/src/tests/lib/jittests.py
+--- a/js/src/tests/lib/jittests.py
++++ b/js/src/tests/lib/jittests.py
+@@ -254,19 +254,16 @@ class JitTest:
+                         if options.wasm_enabled:
+                             test.test_also.append(['--no-wasm-baseline'])
+                     elif name == 'test-also-no-wasm-ion':
+                         if options.wasm_enabled:
+                             test.test_also.append(['--no-wasm-ion'])
+                     elif name == 'test-also-wasm-tiering':
+                         if options.wasm_enabled:
+                             test.test_also.append(['--test-wasm-await-tier2'])
+-                    elif name == 'test-also-wasm-check-bce':
+-                        if options.wasm_enabled:
+-                            test.test_also.append(['--wasm-check-bce'])
+                     elif name.startswith('test-also='):
+                         test.test_also.append([name[len('test-also='):]])
+                     elif name.startswith('test-join='):
+                         test.test_join.append([name[len('test-join='):]])
+                     elif name == 'module':
+                         test.is_module = True
+                     elif name == 'crash':
+                         test.expect_crash = True
+

+ 134 - 0
mozilla-release/patches/1433837-1-60a1.patch

@@ -0,0 +1,134 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1517163780 -7200
+#      Sun Jan 28 20:23:00 2018 +0200
+# Node ID e52e7ff7148a48d0ee939bff62064d6736c3458a
+# Parent  bbe2a0b1c8ff4f3b92ae7c6d3505c1ef63f31ba9
+Bug 1433837 - Objects that are isNative should extend NativeObject r=jandem
+MozReview-Commit-ID: E3p4j45xnc7
+
+diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h
+--- a/js/src/builtin/AtomicsObject.h
++++ b/js/src/builtin/AtomicsObject.h
+@@ -9,20 +9,21 @@
+ 
+ #include "mozilla/Maybe.h"
+ #include "mozilla/TimeStamp.h"
+ 
+ #include "jsobj.h"
+ 
+ #include "threading/ConditionVariable.h"
+ #include "vm/MutexIDs.h"
++#include "vm/NativeObject.h"
+ 
+ namespace js {
+ 
+-class AtomicsObject : public JSObject
++class AtomicsObject : public NativeObject
+ {
+   public:
+     static const Class class_;
+     static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
+     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
+ };
+ 
+ MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
+diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h
+--- a/js/src/builtin/TypedObject.h
++++ b/js/src/builtin/TypedObject.h
+@@ -747,17 +747,17 @@ class InlineTransparentTypedObject : pub
+ // Class for an opaque typed object with inline data and no array buffer.
+ class InlineOpaqueTypedObject : public InlineTypedObject
+ {
+   public:
+     static const Class class_;
+ };
+ 
+ // Class for the global SIMD object.
+-class SimdObject : public JSObject
++class SimdObject : public NativeObject
+ {
+   public:
+     static const Class class_;
+     static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
+     static MOZ_MUST_USE bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId,
+                                      bool* resolved);
+ };
+ 
+diff --git a/js/src/jsiter.h b/js/src/jsiter.h
+--- a/js/src/jsiter.h
++++ b/js/src/jsiter.h
+@@ -127,26 +127,26 @@ class PropertyIteratorObject : public Na
+ 
+     size_t sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const;
+ 
+   private:
+     static void trace(JSTracer* trc, JSObject* obj);
+     static void finalize(FreeOp* fop, JSObject* obj);
+ };
+ 
+-class ArrayIteratorObject : public JSObject
++class ArrayIteratorObject : public NativeObject
+ {
+   public:
+     static const Class class_;
+ };
+ 
+ ArrayIteratorObject*
+ NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
+ 
+-class StringIteratorObject : public JSObject
++class StringIteratorObject : public NativeObject
+ {
+   public:
+     static const Class class_;
+ };
+ 
+ StringIteratorObject*
+ NewStringIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
+ 
+diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp
+--- a/js/src/shell/OSObject.cpp
++++ b/js/src/shell/OSObject.cpp
+@@ -389,17 +389,18 @@ bool
+ RCFile::release()
+ {
+     if (--numRefs)
+         return false;
+     this->close();
+     return true;
+ }
+ 
+-class FileObject : public JSObject {
++class FileObject : public NativeObject
++{
+     enum : uint32_t {
+         FILE_SLOT = 0,
+         NUM_SLOTS
+     };
+ 
+   public:
+     static const js::Class class_;
+ 
+diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
+--- a/js/src/vm/ArrayBufferObject.h
++++ b/js/src/vm/ArrayBufferObject.h
+@@ -430,17 +430,17 @@ bool CreateWasmBuffer(JSContext* cx, con
+                       MutableHandleArrayBufferObjectMaybeShared buffer);
+ 
+ /*
+  * ArrayBufferViewObject
+  *
+  * Common definitions shared by all array buffer views.
+  */
+ 
+-class ArrayBufferViewObject : public JSObject
++class ArrayBufferViewObject : public NativeObject
+ {
+   public:
+     static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);
+ 
+     void notifyBufferDetached(JSContext* cx, void* newData);
+ 
+ #ifdef DEBUG
+     bool isSharedMemory();

+ 148 - 0
mozilla-release/patches/1433837-2-60a1.patch

@@ -0,0 +1,148 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1517163900 -7200
+#      Sun Jan 28 20:25:00 2018 +0200
+# Node ID 794dda2e9f2edd93adc5ce42ebb4447b8e399410
+# Parent  2f5e31ee0c582d39d8f10db6cc978229a439e608
+Bug 1433837 - Delay MetadataBuilder for UnboxedObject and TypedObject r=jandem
+Avoid NewObjectMetadata hook while OutlineTypedObjects have a
+uninitialized owner pointer.
+
+MozReview-Commit-ID: Hn0HmnEUmz5
+
+diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
+--- a/js/src/builtin/TypedObject.cpp
++++ b/js/src/builtin/TypedObject.cpp
+@@ -1441,16 +1441,18 @@ OutlineTypedObject::createUnattachedWith
+                                               const Class* clasp,
+                                               HandleTypeDescr descr,
+                                               int32_t length,
+                                               gc::InitialHeap heap)
+ {
+     MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ ||
+                clasp == &OutlineOpaqueTypedObject::class_);
+ 
++    AutoSetNewObjectMetadata metadata(cx);
++
+     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp,
+                                                              TaggedProto(&descr->typedProto()),
+                                                              descr));
+     if (!group)
+         return nullptr;
+ 
+     NewObjectKind newKind = (heap == gc::TenuredHeap) ? TenuredObject : GenericObject;
+     OutlineTypedObject* obj = NewObjectWithGroup<OutlineTypedObject>(cx, group,
+@@ -2217,17 +2219,17 @@ const ObjectOps TypedObject::objectOps_ 
+     TypedObject::obj_getProperty,
+     TypedObject::obj_setProperty,
+     TypedObject::obj_getOwnPropertyDescriptor,
+     TypedObject::obj_deleteProperty,
+     nullptr,   /* getElements */
+     nullptr, /* thisValue */
+ };
+ 
+-#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, Moved, flag)   \
++#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, Moved)        \
+     static const ClassOps Name##ClassOps = {             \
+         nullptr,        /* addProperty */                \
+         nullptr,        /* delProperty */                \
+         nullptr,        /* enumerate   */                \
+         TypedObject::obj_newEnumerate,                   \
+         nullptr,        /* resolve     */                \
+         nullptr,        /* mayResolve  */                \
+         nullptr,        /* finalize    */                \
+@@ -2237,39 +2239,36 @@ const ObjectOps TypedObject::objectOps_ 
+         Trace,                                           \
+     };                                                   \
+     static const ClassExtension Name##ClassExt = {       \
+         nullptr,        /* weakmapKeyDelegateOp */       \
+         Moved           /* objectMovedOp */              \
+     };                                                   \
+     const Class Name::class_ = {                         \
+         # Name,                                          \
+-        Class::NON_NATIVE | flag,                        \
++        Class::NON_NATIVE |                              \
++            JSCLASS_DELAY_METADATA_BUILDER,              \
+         &Name##ClassOps,                                 \
+         JS_NULL_CLASS_SPEC,                              \
+         &Name##ClassExt,                                 \
+         &TypedObject::objectOps_                         \
+     }
+ 
+ DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject,
+                       OutlineTypedObject::obj_trace,
+-                      nullptr,
+-                      0);
++                      nullptr);
+ DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject,
+                       OutlineTypedObject::obj_trace,
+-                      nullptr,
+-                      0);
++                      nullptr);
+ DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject,
+                       InlineTypedObject::obj_trace,
+-                      InlineTypedObject::obj_moved,
+-                      JSCLASS_DELAY_METADATA_BUILDER);
++                      InlineTypedObject::obj_moved);
+ DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject,
+                       InlineTypedObject::obj_trace,
+-                      InlineTypedObject::obj_moved,
+-                      JSCLASS_DELAY_METADATA_BUILDER);
++                      InlineTypedObject::obj_moved);
+ 
+ static int32_t
+ LengthForType(TypeDescr& descr)
+ {
+     switch (descr.kind()) {
+       case type::Scalar:
+       case type::Reference:
+       case type::Struct:
+@@ -2407,20 +2406,18 @@ TypedObject::create(JSContext* cx, js::g
+         return cx->alreadyReportedOOM();
+ 
+     TypedObject* tobj = static_cast<TypedObject*>(obj);
+     tobj->group_.init(group);
+     tobj->initShape(shape);
+ 
+     tobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
+ 
+-    if (clasp->shouldDelayMetadataBuilder())
+-        cx->compartment()->setObjectPendingMetadata(cx, tobj);
+-    else
+-        tobj = SetNewObjectMetadata(cx, tobj);
++    MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
++    cx->compartment()->setObjectPendingMetadata(cx, tobj);
+ 
+     js::gc::TraceCreateObject(tobj);
+ 
+     return tobj;
+ }
+ 
+ /******************************************************************************
+  * Intrinsics
+diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
+--- a/js/src/vm/UnboxedObject.cpp
++++ b/js/src/vm/UnboxedObject.cpp
+@@ -624,20 +624,18 @@ UnboxedObject::createInternal(JSContext*
+ 
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
+     uobj->group_.init(group);
+ 
+-    if (clasp->shouldDelayMetadataBuilder())
+-        cx->compartment()->setObjectPendingMetadata(cx, uobj);
+-    else
+-        uobj = SetNewObjectMetadata(cx, uobj);
++    MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
++    cx->compartment()->setObjectPendingMetadata(cx, uobj);
+ 
+     js::gc::TraceCreateObject(uobj);
+ 
+     return uobj;
+ }
+ 
+ /* static */
+ UnboxedPlainObject*

+ 492 - 0
mozilla-release/patches/1433837-3-60a1.patch

@@ -0,0 +1,492 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1517164260 -7200
+#      Sun Jan 28 20:31:00 2018 +0200
+# Node ID 9cbb0f5c50c6b19f00654a169e6eeccc40c37468
+# Parent  2fb51710f8787d013ec77be4f8dfaaa5a120ae56
+Bug 1433837 - Cleanup JSObject initialization nits r=jandem
+Make JSObject initializations more consistent accross different types.
+
+MozReview-Commit-ID: Ixbr1bfM0hj
+
+diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
+--- a/js/src/builtin/TypedObject.cpp
++++ b/js/src/builtin/TypedObject.cpp
+@@ -2401,21 +2401,19 @@ TypedObject::create(JSContext* cx, js::g
+     const js::Class* clasp = group->clasp();
+     MOZ_ASSERT(::IsTypedObjectClass(clasp));
+ 
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     TypedObject* tobj = static_cast<TypedObject*>(obj);
+-    tobj->group_.init(group);
++    tobj->initGroup(group);
+     tobj->initShape(shape);
+ 
+-    tobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
+-
+     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
+     cx->compartment()->setObjectPendingMetadata(cx, tobj);
+ 
+     js::gc::TraceCreateObject(tobj);
+ 
+     return tobj;
+ }
+ 
+diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp
+--- a/js/src/gc/Allocator.cpp
++++ b/js/src/gc/Allocator.cpp
+@@ -33,17 +33,17 @@ js::Allocate(JSContext* cx, AllocKind ki
+     MOZ_ASSERT(IsObjectAllocKind(kind));
+     size_t thingSize = Arena::thingSize(kind);
+ 
+     MOZ_ASSERT(thingSize == Arena::thingSize(kind));
+     MOZ_ASSERT(thingSize >= sizeof(JSObject_Slots0));
+     static_assert(sizeof(JSObject_Slots0) >= MinCellSize,
+                   "All allocations must be at least the allocator-imposed minimum size.");
+ 
+-    MOZ_ASSERT_IF(nDynamicSlots != 0, clasp->isNative() || clasp->isProxy());
++    MOZ_ASSERT_IF(nDynamicSlots != 0, clasp->isNative());
+ 
+     // Off-thread alloc cannot trigger GC or make runtime assertions.
+     if (cx->helperThread()) {
+         JSObject* obj = GCRuntime::tryNewTenuredObject<NoGC>(cx, kind, thingSize, nDynamicSlots);
+         if (MOZ_UNLIKELY(allowGC && !obj))
+             ReportOutOfMemory(cx);
+         return obj;
+     }
+diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
+--- a/js/src/gc/Nursery.cpp
++++ b/js/src/gc/Nursery.cpp
+@@ -262,35 +262,35 @@ js::Nursery::leaveZealMode() {
+         MOZ_ASSERT(isEmpty());
+         setCurrentChunk(0);
+         setStartPosition();
+     }
+ }
+ #endif // JS_GC_ZEAL
+ 
+ JSObject*
+-js::Nursery::allocateObject(JSContext* cx, size_t size, size_t numDynamic, const js::Class* clasp)
++js::Nursery::allocateObject(JSContext* cx, size_t size, size_t nDynamicSlots, const js::Class* clasp)
+ {
+     /* Ensure there's enough space to replace the contents with a RelocationOverlay. */
+     MOZ_ASSERT(size >= sizeof(RelocationOverlay));
+ 
+     /* Sanity check the finalizer. */
+     MOZ_ASSERT_IF(clasp->hasFinalize(), CanNurseryAllocateFinalizedClass(clasp) ||
+                                         clasp->isProxy());
+ 
+     /* Make the object allocation. */
+     JSObject* obj = static_cast<JSObject*>(allocate(size));
+     if (!obj)
+         return nullptr;
+ 
+     /* If we want external slots, add them. */
+     HeapSlot* slots = nullptr;
+-    if (numDynamic) {
++    if (nDynamicSlots) {
+         MOZ_ASSERT(clasp->isNative());
+-        slots = static_cast<HeapSlot*>(allocateBuffer(cx->zone(), numDynamic * sizeof(HeapSlot)));
++        slots = static_cast<HeapSlot*>(allocateBuffer(cx->zone(), nDynamicSlots * sizeof(HeapSlot)));
+         if (!slots) {
+             /*
+              * It is safe to leave the allocated object uninitialized, since we
+              * do not visit unallocated things in the nursery.
+              */
+             return nullptr;
+         }
+     }
+diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
+--- a/js/src/jit/MacroAssembler.cpp
++++ b/js/src/jit/MacroAssembler.cpp
+@@ -1320,18 +1320,18 @@ MacroAssembler::initGCSlots(Register obj
+ void
+ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
+                             bool initContents, bool convertDoubleElements)
+ {
+     // Fast initialization of an empty object returned by allocateObject().
+ 
+     storePtr(ImmGCPtr(templateObj->group()), Address(obj, JSObject::offsetOfGroup()));
+ 
+-    if (Shape* shape = templateObj->maybeShape())
+-        storePtr(ImmGCPtr(shape), Address(obj, ShapedObject::offsetOfShape()));
++    if (templateObj->is<ShapedObject>())
++        storePtr(ImmGCPtr(templateObj->maybeShape()), Address(obj, ShapedObject::offsetOfShape()));
+ 
+     MOZ_ASSERT_IF(convertDoubleElements, templateObj->is<ArrayObject>());
+ 
+     if (templateObj->isNative()) {
+         NativeObject* ntemplate = &templateObj->as<NativeObject>();
+         MOZ_ASSERT_IF(!ntemplate->denseElementsAreCopyOnWrite(), !ntemplate->hasDynamicElements());
+ 
+         // If the object has dynamic slots, the slots member has already been
+@@ -1399,17 +1399,18 @@ MacroAssembler::initGCThing(Register obj
+         while (nbytes) {
+             uintptr_t value = *(uintptr_t*)(memory + offset);
+             storePtr(ImmWord(value),
+                      Address(obj, InlineTypedObject::offsetOfDataStart() + offset));
+             nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t);
+             offset += sizeof(uintptr_t);
+         }
+     } else if (templateObj->is<UnboxedPlainObject>()) {
+-        storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
++        MOZ_ASSERT(!templateObj->as<UnboxedPlainObject>().maybeExpando());
++        storePtr(ImmPtr(nullptr), Address(obj, UnboxedPlainObject::offsetOfExpando()));
+         if (initContents)
+             initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
+     } else {
+         MOZ_CRASH("Unknown object");
+     }
+ 
+ #ifdef JS_GC_TRACE
+     RegisterSet regs = RegisterSet::Volatile();
+diff --git a/js/src/jsobj.h b/js/src/jsobj.h
+--- a/js/src/jsobj.h
++++ b/js/src/jsobj.h
+@@ -123,16 +123,20 @@ class JSObject : public js::gc::Cell
+         MOZ_ASSERT(!hasLazyGroup());
+         return groupRaw();
+     }
+ 
+     js::ObjectGroup* groupRaw() const {
+         return group_;
+     }
+ 
++    void initGroup(js::ObjectGroup* group) {
++        group_.init(group);
++    }
++
+     /*
+      * Whether this is the only object which has its specified group. This
+      * object will have its group constructed lazily as needed by analysis.
+      */
+     bool isSingleton() const {
+         return group_->singleton();
+     }
+ 
+@@ -150,17 +154,16 @@ class JSObject : public js::gc::Cell
+     inline js::Shape* maybeShape() const;
+     inline js::Shape* ensureShape(JSContext* cx);
+ 
+     // Set the initial slots and elements of an object. These pointers are only
+     // valid for native objects, but during initialization are set for all
+     // objects. For non-native objects, these must not be dynamically allocated
+     // pointers which leak when the non-native object finishes initialization.
+     inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
+-    inline void setInitialElementsMaybeNonNative(js::HeapSlot* elements);
+ 
+     enum GenerateShape {
+         GENERATE_NONE,
+         GENERATE_SHAPE
+     };
+ 
+     static bool setFlags(JSContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags,
+                          GenerateShape generateShape = GENERATE_NONE);
+diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h
+--- a/js/src/jsobjinlines.h
++++ b/js/src/jsobjinlines.h
+@@ -398,22 +398,16 @@ SetNewObjectMetadata(JSContext* cx, T* o
+ } // namespace js
+ 
+ inline void
+ JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot* slots)
+ {
+     static_cast<js::NativeObject*>(this)->slots_ = slots;
+ }
+ 
+-inline void
+-JSObject::setInitialElementsMaybeNonNative(js::HeapSlot* elements)
+-{
+-    static_cast<js::NativeObject*>(this)->elements_ = elements;
+-}
+-
+ inline js::GlobalObject&
+ JSObject::global() const
+ {
+     /*
+      * The global is read-barriered so that it is kept live by access through
+      * the JSCompartment. When accessed through a JSObject, however, the global
+      * will be already be kept live by the black JSObject's parent pointer, so
+      * does not need to be read-barriered.
+diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h
+--- a/js/src/vm/ArrayObject-inl.h
++++ b/js/src/vm/ArrayObject-inl.h
+@@ -32,39 +32,42 @@ ArrayObject::setLength(JSContext* cx, ui
+     getElementsHeader()->length = length;
+ }
+ 
+ /* static */ inline ArrayObject*
+ ArrayObject::createArrayInternal(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
+                                  HandleShape shape, HandleObjectGroup group,
+                                  AutoSetNewObjectMetadata&)
+ {
+-    // Create a new array and initialize everything except for its elements.
++    const js::Class* clasp = group->clasp();
+     MOZ_ASSERT(shape && group);
+-    MOZ_ASSERT(group->clasp() == shape->getObjectClass());
+-    MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
+-    MOZ_ASSERT_IF(group->clasp()->hasFinalize(), heap == gc::TenuredHeap);
++    MOZ_ASSERT(clasp == shape->getObjectClass());
++    MOZ_ASSERT(clasp == &ArrayObject::class_);
++    MOZ_ASSERT_IF(clasp->hasFinalize(), heap == gc::TenuredHeap);
+     MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
+                   heap == js::gc::TenuredHeap);
+-    MOZ_ASSERT(group->clasp()->shouldDelayMetadataBuilder());
+ 
+     // Arrays can use their fixed slots to store elements, so can't have shapes
+     // which allow named properties to be stored in the fixed slots.
+     MOZ_ASSERT(shape->numFixedSlots() == 0);
+ 
+-    size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), group->clasp());
+-    JSObject* obj = Allocate<JSObject>(cx, kind, nDynamicSlots, heap, group->clasp());
++    size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), clasp);
++    JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
+     if (!obj)
+         return nullptr;
+ 
+-    static_cast<ArrayObject*>(obj)->shape_.init(shape);
+-    static_cast<ArrayObject*>(obj)->group_.init(group);
++    ArrayObject* aobj = static_cast<ArrayObject*>(obj);
++    aobj->initGroup(group);
++    aobj->initShape(shape);
++    // NOTE: Slots are created and assigned internally by Allocate<JSObject>.
+ 
+-    cx->compartment()->setObjectPendingMetadata(cx, obj);
+-    return &obj->as<ArrayObject>();
++    MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
++    cx->compartment()->setObjectPendingMetadata(cx, aobj);
++
++    return aobj;
+ }
+ 
+ /* static */ inline ArrayObject*
+ ArrayObject::finishCreateArray(ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata)
+ {
+     size_t span = shape->slotSpan();
+     if (span)
+         obj->initializeSlotRange(0, span);
+diff --git a/js/src/vm/Caches-inl.h b/js/src/vm/Caches-inl.h
+--- a/js/src/vm/Caches-inl.h
++++ b/js/src/vm/Caches-inl.h
+@@ -55,17 +55,18 @@ NewObjectCache::newObjectFromHit(JSConte
+     MOZ_ASSERT(!group->hasUnanalyzedPreliminaryObjects());
+ 
+     if (group->shouldPreTenure())
+         heap = gc::TenuredHeap;
+ 
+     if (cx->runtime()->gc.upcomingZealousGC())
+         return nullptr;
+ 
+-    NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind, 0,
++    NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind,
++                                                                            /* nDynamicSlots = */ 0,
+                                                                             heap, group->clasp()));
+     if (!obj)
+         return nullptr;
+ 
+     copyCachedToObject(obj, templateObj, entry->kind);
+ 
+     if (group->clasp()->shouldDelayMetadataBuilder())
+         cx->compartment()->setObjectPendingMetadata(cx, obj);
+diff --git a/js/src/vm/Caches.h b/js/src/vm/Caches.h
+--- a/js/src/vm/Caches.h
++++ b/js/src/vm/Caches.h
+@@ -11,16 +11,17 @@
+ #include "jsmath.h"
+ #include "jsobj.h"
+ #include "jsscript.h"
+ 
+ #include "frontend/SourceNotes.h"
+ #include "gc/Tracer.h"
+ #include "js/RootingAPI.h"
+ #include "js/UniquePtr.h"
++#include "vm/ArrayObject.h"
+ #include "vm/NativeObject.h"
+ 
+ namespace js {
+ 
+ /*
+  * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
+  * given pc in a script. We use the script->code pointer to tag the cache,
+  * instead of the script address itself, so that source notes are always found
+@@ -194,16 +195,19 @@ class NewObjectCache
+     }
+ 
+     void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
+               NativeObject* obj) {
+         MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
+         MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
+         Entry* entry = &entries[entry_];
+ 
++        MOZ_ASSERT(!obj->hasDynamicSlots());
++        MOZ_ASSERT(obj->hasEmptyElements() || obj->is<ArrayObject>());
++
+         entry->clasp = clasp;
+         entry->key = key;
+         entry->kind = kind;
+ 
+         entry->nbytes = gc::Arena::thingSize(kind);
+         js_memcpy(&entry->templateObject, obj, entry->nbytes);
+     }
+ 
+diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
+--- a/js/src/vm/NativeObject-inl.h
++++ b/js/src/vm/NativeObject-inl.h
+@@ -529,24 +529,23 @@ NativeObject::create(JSContext* cx, js::
+ 
+     size_t nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
+ 
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     NativeObject* nobj = static_cast<NativeObject*>(obj);
+-    nobj->group_.init(group);
++    nobj->initGroup(group);
+     nobj->initShape(shape);
+-
+-    // Note: slots are created and assigned internally by Allocate<JSObject>.
+-    nobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
++    // NOTE: Slots are created and assigned internally by Allocate<JSObject>.
++    nobj->setEmptyElements();
+ 
+     if (clasp->hasPrivate())
+-        nobj->privateRef(shape->numFixedSlots()) = nullptr;
++        nobj->initPrivate(nullptr);
+ 
+     if (size_t span = shape->slotSpan())
+         nobj->initializeSlotRange(0, span);
+ 
+     // JSFunction's fixed slots expect POD-style initialization.
+     if (clasp->isJSFunction()) {
+         MOZ_ASSERT(kind == js::gc::AllocKind::FUNCTION ||
+                    kind == js::gc::AllocKind::FUNCTION_EXTENDED);
+diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
+--- a/js/src/vm/NativeObject.h
++++ b/js/src/vm/NativeObject.h
+@@ -1317,16 +1317,20 @@ class NativeObject : public ShapedObject
+                       "slots will hold the ObjectElements header");
+         return &fixedSlots()[2];
+     }
+ 
+ #ifdef DEBUG
+     bool canHaveNonEmptyElements();
+ #endif
+ 
++    void setEmptyElements() {
++        elements_ = emptyObjectElements;
++    }
++
+     void setFixedElements(uint32_t numShifted = 0) {
+         MOZ_ASSERT(canHaveNonEmptyElements());
+         elements_ = fixedElements() + numShifted;
+     }
+ 
+     inline bool hasDynamicElements() const {
+         /*
+          * Note: for objects with zero fixed slots this could potentially give
+diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp
+--- a/js/src/vm/ProxyObject.cpp
++++ b/js/src/vm/ProxyObject.cpp
+@@ -185,22 +185,22 @@ ProxyObject::create(JSContext* cx, const
+             return cx->alreadyReportedOOM();
+ 
+         comp->newProxyCache.add(group, shape);
+     }
+ 
+     gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
+     debugCheckNewObject(group, shape, allocKind, heap);
+ 
+-    JSObject* obj = js::Allocate<JSObject>(cx, allocKind, /* numDynamicSlots = */ 0, heap, clasp);
++    JSObject* obj = js::Allocate<JSObject>(cx, allocKind, /* nDynamicSlots = */ 0, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     ProxyObject* pobj = static_cast<ProxyObject*>(obj);
+-    pobj->group_.init(group);
++    pobj->initGroup(group);
+     pobj->initShape(shape);
+ 
+     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
+     cx->compartment()->setObjectPendingMetadata(cx, pobj);
+ 
+     js::gc::TraceCreateObject(pobj);
+ 
+     return pobj;
+diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
+--- a/js/src/vm/UnboxedObject.cpp
++++ b/js/src/vm/UnboxedObject.cpp
+@@ -622,17 +622,17 @@ UnboxedObject::createInternal(JSContext*
+ 
+     debugCheckNewObject(group, /* shape = */ nullptr, kind, heap);
+ 
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
+-    uobj->group_.init(group);
++    uobj->initGroup(group);
+ 
+     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
+     cx->compartment()->setObjectPendingMetadata(cx, uobj);
+ 
+     js::gc::TraceCreateObject(uobj);
+ 
+     return uobj;
+ }
+@@ -644,44 +644,43 @@ UnboxedPlainObject::create(JSContext* cx
+     AutoSetNewObjectMetadata metadata(cx);
+ 
+     MOZ_ASSERT(group->clasp() == &class_);
+     gc::AllocKind allocKind = group->unboxedLayout().getAllocKind();
+     gc::InitialHeap heap = GetInitialHeap(newKind, &class_);
+ 
+     MOZ_ASSERT(newKind != SingletonObject);
+ 
+-    UnboxedObject* res_;
+-    JS_TRY_VAR_OR_RETURN_NULL(cx, res_, createInternal(cx, allocKind, heap, group));
+-    UnboxedPlainObject* res = &res_->as<UnboxedPlainObject>();
++    JSObject* obj;
++    JS_TRY_VAR_OR_RETURN_NULL(cx, obj, createInternal(cx, allocKind, heap, group));
+ 
+-    // Overwrite the dummy shape which was written to the object's expando field.
+-    res->initExpando();
++    UnboxedPlainObject* uobj = static_cast<UnboxedPlainObject*>(obj);
++    uobj->initExpando();
+ 
+     // Initialize reference fields of the object. All fields in the object will
+     // be overwritten shortly, but references need to be safe for the GC.
+-    const int32_t* list = res->layout().traceList();
++    const int32_t* list = uobj->layout().traceList();
+     if (list) {
+-        uint8_t* data = res->data();
++        uint8_t* data = uobj->data();
+         while (*list != -1) {
+             GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
+             heap->init(cx->names().empty);
+             list++;
+         }
+         list++;
+         while (*list != -1) {
+             GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list);
+             heap->init(nullptr);
+             list++;
+         }
+         // Unboxed objects don't have Values to initialize.
+         MOZ_ASSERT(*(list + 1) == -1);
+     }
+ 
+-    return res;
++    return uobj;
+ }
+ 
+ /* static */ JSObject*
+ UnboxedPlainObject::createWithProperties(JSContext* cx, HandleObjectGroup group,
+                                          NewObjectKind newKind, IdValuePair* properties)
+ {
+     MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject);
+ 

+ 240 - 0
mozilla-release/patches/1433837-4-60a1.patch

@@ -0,0 +1,240 @@
+# HG changeset patch
+# User Ted Campbell <tcampbell@mozilla.com>
+# Date 1517206800 -7200
+#      Mon Jan 29 08:20:00 2018 +0200
+# Node ID b1c8ba93a6c2f5e9179c8ff252ba7e049558e408
+# Parent  02d1cc075ba1f31d70255bbc939c43d47fb5a20d
+Bug 1433837 - Cleanup JSObject slots_ initialization r=jandem
+js::Allocate<JSObject> now only sets slots_ if nDynamicSlots is
+non-zero. This avoids spurious writes for other types and is now
+consistent with JIT code.
+
+MozReview-Commit-ID: 3spPMFj7Fxz
+
+diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp
+--- a/js/src/gc/Allocator.cpp
++++ b/js/src/gc/Allocator.cpp
+@@ -114,20 +114,22 @@ GCRuntime::tryNewTenuredObject(JSContext
+                 ReportOutOfMemory(cx);
+             return nullptr;
+         }
+         Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots);
+     }
+ 
+     JSObject* obj = tryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize);
+ 
+-    if (obj)
+-        obj->setInitialSlotsMaybeNonNative(slots);
+-    else
++    if (obj) {
++        if (nDynamicSlots)
++            static_cast<NativeObject*>(obj)->initSlots(slots);
++    } else {
+         js_free(slots);
++    }
+ 
+     return obj;
+ }
+ 
+ template <typename T, AllowGC allowGC /* = CanGC */>
+ T*
+ js::Allocate(JSContext* cx)
+ {
+diff --git a/js/src/gc/Allocator.h b/js/src/gc/Allocator.h
+--- a/js/src/gc/Allocator.h
++++ b/js/src/gc/Allocator.h
+@@ -16,17 +16,18 @@ struct Class;
+ 
+ // Allocate a new GC thing. After a successful allocation the caller must
+ // fully initialize the thing before calling any function that can potentially
+ // trigger GC. This will ensure that GC tracing never sees junk values stored
+ // in the partially initialized thing.
+ //
+ // Note that JSObject allocation must use the longer signature below that
+ // includes slot, heap, and finalizer information in support of various
+-// object-specific optimizations.
++// object-specific optimizations. If dynamic slots are requested they will be
++// allocated and the pointer stored directly in |NativeObject::slots_|.
+ template <typename T, AllowGC allowGC = CanGC>
+ T*
+ Allocate(JSContext* cx);
+ 
+ template <typename, AllowGC allowGC = CanGC>
+ JSObject*
+ Allocate(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots, gc::InitialHeap heap,
+          const Class* clasp);
+diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
+--- a/js/src/gc/Nursery.cpp
++++ b/js/src/gc/Nursery.cpp
+@@ -290,18 +290,21 @@ js::Nursery::allocateObject(JSContext* c
+             /*
+              * It is safe to leave the allocated object uninitialized, since we
+              * do not visit unallocated things in the nursery.
+              */
+             return nullptr;
+         }
+     }
+ 
+-    /* Always initialize the slots field to match the JIT behavior. */
+-    obj->setInitialSlotsMaybeNonNative(slots);
++    /* Store slots pointer directly in new object. If no dynamic slots were
++     * requested, caller must initialize slots_ field itself as needed. We
++     * don't know if the caller was a native object or not. */
++    if (nDynamicSlots)
++        static_cast<NativeObject*>(obj)->initSlots(slots);
+ 
+     TraceNurseryAlloc(obj, size);
+     return obj;
+ }
+ 
+ void*
+ js::Nursery::allocate(size_t size)
+ {
+diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
+--- a/js/src/jit/MacroAssembler.cpp
++++ b/js/src/jit/MacroAssembler.cpp
+@@ -990,16 +990,18 @@ MacroAssembler::allocateObject(Register 
+     checkAllocatorState(fail);
+ 
+     if (shouldNurseryAllocate(allocKind, initialHeap))
+         return nurseryAllocate(result, temp, allocKind, nDynamicSlots, initialHeap, fail);
+ 
+     if (!nDynamicSlots)
+         return freeListAllocate(result, temp, allocKind, fail);
+ 
++    // Only NativeObject can have nDynamicSlots > 0 and reach here.
++
+     callMallocStub(nDynamicSlots * sizeof(GCPtrValue), temp, fail);
+ 
+     Label failAlloc;
+     Label success;
+ 
+     push(temp);
+     freeListAllocate(result, temp, allocKind, &failAlloc);
+ 
+diff --git a/js/src/jsobj.h b/js/src/jsobj.h
+--- a/js/src/jsobj.h
++++ b/js/src/jsobj.h
+@@ -149,22 +149,16 @@ class JSObject : public js::gc::Cell
+     }
+ 
+     JSCompartment* compartment() const { return group_->compartment(); }
+     JSCompartment* maybeCompartment() const { return compartment(); }
+ 
+     inline js::Shape* maybeShape() const;
+     inline js::Shape* ensureShape(JSContext* cx);
+ 
+-    // Set the initial slots and elements of an object. These pointers are only
+-    // valid for native objects, but during initialization are set for all
+-    // objects. For non-native objects, these must not be dynamically allocated
+-    // pointers which leak when the non-native object finishes initialization.
+-    inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
+-
+     enum GenerateShape {
+         GENERATE_NONE,
+         GENERATE_SHAPE
+     };
+ 
+     static bool setFlags(JSContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags,
+                          GenerateShape generateShape = GENERATE_NONE);
+     inline bool hasAllFlags(js::BaseShape::Flag flags) const;
+diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h
+--- a/js/src/jsobjinlines.h
++++ b/js/src/jsobjinlines.h
+@@ -392,22 +392,16 @@ SetNewObjectMetadata(JSContext* cx, T* o
+         }
+     }
+ 
+     return obj;
+ }
+ 
+ } // namespace js
+ 
+-inline void
+-JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot* slots)
+-{
+-    static_cast<js::NativeObject*>(this)->slots_ = slots;
+-}
+-
+ inline js::GlobalObject&
+ JSObject::global() const
+ {
+     /*
+      * The global is read-barriered so that it is kept live by access through
+      * the JSCompartment. When accessed through a JSObject, however, the global
+      * will be already be kept live by the black JSObject's parent pointer, so
+      * does not need to be read-barriered.
+diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h
+--- a/js/src/vm/ArrayObject-inl.h
++++ b/js/src/vm/ArrayObject-inl.h
+@@ -52,17 +52,19 @@ ArrayObject::createArrayInternal(JSConte
+     size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), clasp);
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
+     if (!obj)
+         return nullptr;
+ 
+     ArrayObject* aobj = static_cast<ArrayObject*>(obj);
+     aobj->initGroup(group);
+     aobj->initShape(shape);
+-    // NOTE: Slots are created and assigned internally by Allocate<JSObject>.
++    // NOTE: Dynamic slots are created internally by Allocate<JSObject>.
++    if (!nDynamicSlots)
++        aobj->initSlots(nullptr);
+ 
+     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
+     cx->compartment()->setObjectPendingMetadata(cx, aobj);
+ 
+     return aobj;
+ }
+ 
+ /* static */ inline ArrayObject*
+diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
+--- a/js/src/vm/NativeObject-inl.h
++++ b/js/src/vm/NativeObject-inl.h
+@@ -531,17 +531,19 @@ NativeObject::create(JSContext* cx, js::
+ 
+     JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
+     if (!obj)
+         return cx->alreadyReportedOOM();
+ 
+     NativeObject* nobj = static_cast<NativeObject*>(obj);
+     nobj->initGroup(group);
+     nobj->initShape(shape);
+-    // NOTE: Slots are created and assigned internally by Allocate<JSObject>.
++    // NOTE: Dynamic slots are created internally by Allocate<JSObject>.
++    if (!nDynamicSlots)
++        nobj->initSlots(nullptr);
+     nobj->setEmptyElements();
+ 
+     if (clasp->hasPrivate())
+         nobj->initPrivate(nullptr);
+ 
+     if (size_t span = shape->slotSpan())
+         nobj->initializeSlotRange(0, span);
+ 
+diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
+--- a/js/src/vm/NativeObject.h
++++ b/js/src/vm/NativeObject.h
+@@ -675,16 +675,22 @@ class NativeObject : public ShapedObject
+      */
+     static const uint32_t SLOT_CAPACITY_MIN = 8;
+ 
+     HeapSlot* fixedSlots() const {
+         return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(NativeObject));
+     }
+ 
+   public:
++
++    /* Object allocation may directly initialize slots so this is public. */
++    void initSlots(HeapSlot* slots) {
++        slots_ = slots;
++    }
++
+     static MOZ_MUST_USE bool generateOwnShape(JSContext* cx, HandleNativeObject obj,
+                                               Shape* newShape = nullptr)
+     {
+         return replaceWithNewEquivalentShape(cx, obj, obj->lastProperty(), newShape);
+     }
+ 
+     static MOZ_MUST_USE bool reshapeForShadowedProp(JSContext* cx, HandleNativeObject obj);
+     static MOZ_MUST_USE bool reshapeForProtoMutation(JSContext* cx, HandleNativeObject obj);

+ 11 - 11
mozilla-release/patches/1566141-7-72a1.patch

@@ -3,7 +3,7 @@
 # Date 1573577859 0
 #      Tue Nov 12 16:57:39 2019 +0000
 # Node ID ddc6fa7e24f2eb5e96e0e0215a943b06d4607b95
-# Parent  1be45deba7398df8d0fdf042c28d1444932a940f
+# Parent  3d81999d8a280a9ea84c92468730b8e24b4da1bb
 Bug 1566141 - implement nullish coalescence in ion monkey r=jandem
 
 Differential Revision: https://phabricator.services.mozilla.com/D51640
@@ -11,7 +11,7 @@ Differential Revision: https://phabricator.services.mozilla.com/D51640
 diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
 --- a/js/src/jit/CodeGenerator.cpp
 +++ b/js/src/jit/CodeGenerator.cpp
-@@ -12053,16 +12053,32 @@ CodeGenerator::visitIsObject(LIsObject* 
+@@ -12117,16 +12117,32 @@ CodeGenerator::visitIsObject(LIsObject* 
  
  void
  CodeGenerator::visitIsObjectAndBranch(LIsObjectAndBranch* ins)
@@ -47,7 +47,7 @@ diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
 diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
 --- a/js/src/jit/CodeGenerator.h
 +++ b/js/src/jit/CodeGenerator.h
-@@ -388,16 +388,17 @@ class CodeGenerator final : public CodeG
+@@ -390,16 +390,17 @@ class CodeGenerator final : public CodeG
      void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
      void visitIsConstructor(LIsConstructor* lir);
      void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
@@ -86,7 +86,7 @@ diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
        case JSOP_TABLESWITCH:
        case JSOP_CASE:
        case JSOP_DEFAULT:
-@@ -2959,25 +2960,35 @@ IonBuilder::jsop_dup2()
+@@ -2962,25 +2963,35 @@ IonBuilder::jsop_dup2()
      current->pushSlot(lhsSlot);
      current->pushSlot(rhsSlot);
      return Ok();
@@ -419,7 +419,7 @@ diff --git a/js/src/jit/IonControlFlow.h b/js/src/jit/IonControlFlow.h
 diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
 --- a/js/src/jit/Lowering.cpp
 +++ b/js/src/jit/Lowering.cpp
-@@ -4399,16 +4399,24 @@ LIRGenerator::visitIsObject(MIsObject* i
+@@ -4432,16 +4432,24 @@ LIRGenerator::visitIsObject(MIsObject* i
      }
  
      MDefinition* opd = ins->input();
@@ -447,10 +447,10 @@ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
 diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
 --- a/js/src/jit/Lowering.h
 +++ b/js/src/jit/Lowering.h
-@@ -293,16 +293,17 @@ class LIRGenerator : public LIRGenerator
+@@ -295,16 +295,17 @@ class LIRGenerator : public LIRGenerator
      void visitHasOwnCache(MHasOwnCache* ins);
      void visitInstanceOf(MInstanceOf* ins);
-     void visitCallInstanceOf(MCallInstanceOf* ins);
+     void visitInstanceOfCache(MInstanceOfCache* ins);
      void visitIsCallable(MIsCallable* ins);
      void visitIsConstructor(MIsConstructor* ins);
      void visitIsArray(MIsArray* ins);
@@ -468,7 +468,7 @@ diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
 diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
 --- a/js/src/jit/MIR.h
 +++ b/js/src/jit/MIR.h
-@@ -13520,16 +13520,35 @@ class MIsObject
+@@ -13640,16 +13640,35 @@ class MIsObject
      bool congruentTo(const MDefinition* ins) const override {
          return congruentIfOperandsEqual(ins);
      }
@@ -507,7 +507,7 @@ diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
 diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
 --- a/js/src/jit/MOpcodes.h
 +++ b/js/src/jit/MOpcodes.h
-@@ -278,16 +278,17 @@ namespace jit {
+@@ -280,16 +280,17 @@ namespace jit {
      _(GetDOMProperty)                                                       \
      _(GetDOMMember)                                                         \
      _(SetDOMProperty)                                                       \
@@ -528,7 +528,7 @@ diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
 diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
 --- a/js/src/jit/shared/LIR-shared.h
 +++ b/js/src/jit/shared/LIR-shared.h
-@@ -8132,16 +8132,28 @@ class LIsObjectAndBranch : public LContr
+@@ -8175,16 +8175,28 @@ class LIsObjectAndBranch : public LContr
      MBasicBlock* ifTrue() const {
          return getSuccessor(0);
      }
@@ -560,7 +560,7 @@ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
 diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h
 --- a/js/src/jit/shared/LOpcodes-shared.h
 +++ b/js/src/jit/shared/LOpcodes-shared.h
-@@ -393,16 +393,17 @@
+@@ -395,16 +395,17 @@
      _(IsCallableO)                  \
      _(IsCallableV)                  \
      _(IsConstructor)                \

+ 8 - 0
mozilla-release/patches/series

@@ -744,6 +744,14 @@ servo-19881-60a1.patch
 1432552-4-60a1.patch
 1433402-60a1.patch
 1426519-1only-PARTIAL-60a1.patch
+1420910-1-60a1.patch
+1420910-2-60a1.patch
+1424978-60a1.patch
+1433837-1-60a1.patch
+1433837-2-60a1.patch
+1433837-3-60a1.patch
+1433837-4-60a1.patch
+1433597-60a1.patch
 1433497-60a1.patch
 1430817-1-60a1.patch
 1430817-2-60a1.patch