Merge m-c to inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 18 Oct 2018 20:51:18 -0400
changeset 490357 1f63ece13c07c287fad4f5684da002747705bdd1
parent 490356 5f7e9756a2efa098d8e0d0e3a4d4447da0d0f1fd (current diff)
parent 490355 6c55991a052eca284abb6d0a7980765e718e8f02 (diff)
child 490358 45e3efb5e07666bd7e6e7bb0c0db34aa2cd75b4a
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmerge
milestone64.0a1
Merge m-c to inbound. a=merge
js/src/builtin/Array.cpp
js/src/jit-test/tests/cacheir/bug1494537.js
taskcluster/ci/build/windows.yml
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -419,16 +419,19 @@ js::GetElementsWithAdder(JSContext* cx, 
         if (!adder->append(cx, val)) {
             return false;
         }
     }
 
     return true;
 }
 
+static bool
+ObjectMayHaveExtraIndexedProperties(JSObject* obj);
+
 static inline bool
 IsPackedArrayOrNoExtraIndexedProperties(JSObject* obj, uint64_t length)
 {
     return (IsPackedArray(obj) && obj->as<ArrayObject>().length() == length) ||
            !ObjectMayHaveExtraIndexedProperties(obj);
 }
 
 static bool
@@ -1054,18 +1057,18 @@ ObjectMayHaveExtraIndexedOwnProperties(J
                              obj->getClass(), INT_TO_JSID(0), obj);
 }
 
 /*
  * Whether obj may have indexed properties anywhere besides its dense
  * elements. This includes other indexed properties in its shape hierarchy, and
  * indexed properties or elements along its prototype chain.
  */
-bool
-js::ObjectMayHaveExtraIndexedProperties(JSObject* obj)
+static bool
+ObjectMayHaveExtraIndexedProperties(JSObject* obj)
 {
     MOZ_ASSERT_IF(obj->hasDynamicPrototype(), !obj->isNative());
 
     if (ObjectMayHaveExtraIndexedOwnProperties(obj)) {
         return true;
     }
 
     do {
--- a/js/src/builtin/Array.h
+++ b/js/src/builtin/Array.h
@@ -191,19 +191,16 @@ ArrayConstructor(JSContext* cx, unsigned
 
 // Like Array constructor, but doesn't perform GetPrototypeFromConstructor.
 extern bool
 array_construct(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 IsCrossRealmArrayConstructor(JSContext* cx, const Value& v, bool* result);
 
-extern bool
-ObjectMayHaveExtraIndexedProperties(JSObject* obj);
-
 class MOZ_NON_TEMPORARY_CLASS ArraySpeciesLookup final
 {
     /*
      * An ArraySpeciesLookup holds the following:
      *
      *  Array.prototype (arrayProto_)
      *      To ensure that the incoming array has the standard proto.
      *
deleted file mode 100644
--- a/js/src/jit-test/tests/cacheir/bug1494537.js
+++ /dev/null
@@ -1,125 +0,0 @@
-setJitCompilerOption("ion.forceinlineCaches", 1);
-
-let offsets = [213, 559, 255, 515, 30, 507, 252, 329, 487, 7];
-
-function update_index(i, j) {
-    var offset = offsets[j % offsets.length];
-    return i + offset;
-}
-
-function compute_index(initial, count) {
-    for (var i = 0; i < count; i++) {
-        initial = update_index(initial, i);
-    }
-    return initial;
-}
-
-// This is written so that the IC added in the bug activates.
-function mutate_array(array, count, epsilon = 0) {
-    var index = 0;
-    for (var i = 0; i < count; i++) {
-        index = update_index(index, i);
-        array[index] = i + epsilon;
-    }
-    return array[offsets[0]+offsets[1]] === (1 + epsilon) &&
-           array[10] === undefined;
-}
-
-// Monomorphizing mutate_array to ensure we get the IC chains we want
-function create_variant(variant) {
-    var source = mutate_array.toString().replace("mutate_array", "mutate_array_"+variant);
-    return source;
-}
-
-function test_basic() {
-    eval(create_variant("basic"));
-    var x = [];
-
-    var count = 100;
-    assertEq(mutate_array_basic(x, count), true);
-    var end = compute_index(0, count);
-    assertEq(x[end], count - 1);
-    assertEq(x[end - 1], undefined);
-}
-
-// Ensure the IC respects frozen.
-function test_frozen() {
-    eval(create_variant("frozen"));
-    var x = [];
-    Object.freeze(x);
-
-    var count = 100;
-    assertEq(mutate_array_frozen(x, count), false);
-    assertEq(x.length, 0);
-
-    var end = compute_index(0, count);
-
-    var y = [];
-    assertEq(mutate_array_frozen(y, count), true);
-    assertEq(y[end], count - 1);
-    Object.freeze(y);
-
-    // After a mutated array is frozen, can't subsequently modify elements
-    assertEq(mutate_array_frozen(x, count, 10), false);
-    assertEq(y[end], count - 1);
-}
-
-// Let's make sure updates to the array happen as expected.
-function test_update() {
-    eval(create_variant("update"));
-
-    var x = [];
-    var count = 100;
-    assertEq(mutate_array_update(x, count), true);
-    var end = compute_index(0, count);
-    assertEq(x[end], count - 1);
-    assertEq(x[end - 1], undefined);
-
-    var epsilon = 2;
-    mutate_array_update(x, 200, epsilon);
-    assertEq(x[end], count -1 + epsilon)
-}
-
-// Elements may be non-writable, let us not write them.
-function test_nonwritable() {
-    eval(create_variant("nonwritable"));
-    var x = [];
-    var count = 100;
-    var index = compute_index(0, 10);
-    Object.defineProperty(x, index, {value: -10, writable: false});
-    mutate_array_nonwritable(x, count);
-    assertEq(x[index], -10);
-}
-
-// Random indices can get setters, let's make sure we honour those.
-function test_setter() {
-    eval(create_variant("setter"));
-    var x = [];
-    var count = 100;
-    var index = compute_index(0, 80);
-    var sigil = 0;
-    Object.defineProperty(x, index, {set(newVal) {sigil++; }});
-    mutate_array_setter(x, count);
-    assertEq(sigil, 1);
-    assertEq(x[index], undefined);
-}
-
-// Ensure indexes on the prototype don't break things;
-//
-function test_proto_indices() {
-    eval(create_variant("proto_indices"));
-    var x = [];
-    var count = 100;
-    var index = compute_index(0, 80);
-    x.__proto__[index] = "hello";
-    mutate_array_proto_indices(x, count);
-    assertEq(x.__proto__[index], "hello");
-    assertEq(x[index], 79);
-}
-
-test_basic();
-test_frozen();
-test_update();
-test_nonwritable();
-test_setter();
-test_proto_indices();
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -1875,43 +1875,16 @@ BaselineCacheIRCompiler::emitCallProxySe
         return false;
     }
 
     stubFrame.leave(masm);
     return true;
 }
 
 bool
-BaselineCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper()
-{
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    Register id = allocator.useRegister(masm, reader.int32OperandId());
-    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
-    bool strict = reader.readBool();
-    AutoScratchRegister scratch(allocator, masm);
-
-    allocator.discardStack(masm);
-
-    AutoStubFrame stubFrame(*this);
-    stubFrame.enter(masm, scratch);
-
-    masm.Push(Imm32(strict));
-    masm.Push(val);
-    masm.Push(id);
-    masm.Push(obj);
-
-    if (!callVM(masm, AddOrUpdateSparseElementHelperInfo)) {
-        return false;
-    }
-    stubFrame.leave(masm);
-    return true;
-}
-
-
-bool
 BaselineCacheIRCompiler::emitMegamorphicSetElement()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
     ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
     bool strict = reader.readBool();
 
     allocator.discardStack(masm);
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -3445,19 +3445,16 @@ SetPropIRGenerator::tryAttachStub()
                 return true;
             }
             if (tryAttachSetDenseElementHole(obj, objId, index, indexId, rhsValId)) {
                 return true;
             }
             if (tryAttachSetTypedElement(obj, objId, index, indexId, rhsValId)) {
                 return true;
             }
-            if (tryAttachAddOrUpdateSparseElement(obj, objId, index, indexId, rhsValId)) {
-                return true;
-            }
             return false;
         }
         return false;
     }
     return false;
 }
 
 static void
@@ -4064,99 +4061,16 @@ SetPropIRGenerator::tryAttachSetDenseEle
 
     // Type inference uses JSID_VOID for the element types.
     typeCheckInfo_.set(nobj->group(), JSID_VOID);
 
     trackAttached(isAdd ? "AddDenseElement" : "StoreDenseElementHole");
     return true;
 }
 
-// Add an IC for adding or updating a sparse array element.
-bool
-SetPropIRGenerator::tryAttachAddOrUpdateSparseElement(HandleObject obj, ObjOperandId objId,
-                                                      uint32_t index, Int32OperandId indexId,
-                                                      ValOperandId rhsId)
-{
-    JSOp op = JSOp(*pc_);
-    MOZ_ASSERT(IsPropertySetOp(op) || IsPropertyInitOp(op));
-
-    if (op != JSOP_SETELEM && op != JSOP_STRICTSETELEM) {
-        return false;
-    }
-
-    if (!obj->isNative()) {
-        return false;
-    }
-    RootedNativeObject nobj(cx_, &obj->as<NativeObject>());
-
-    // We cannot attach a stub to a non-extensible object
-    if (!nobj->isExtensible()) {
-        return false;
-    }
-
-    // Stub doesn't handle negative indices.
-    if (index > INT_MAX) {
-        return false;
-    }
-
-    // We also need to be past the end of the dense capacity, to ensure sparse.
-    if (index < nobj->getDenseInitializedLength()) {
-        return false;
-    }
-
-    // Only handle Array objects in this stub.
-    if (!nobj->is<ArrayObject>()) {
-        return false;
-    }
-    RootedArrayObject aobj(cx_, &obj->as<ArrayObject>());
-
-    // Don't attach if we're adding to an array with non-writable length.
-    bool isAdd = (index >= aobj->length());
-    if (isAdd && !aobj->lengthIsWritable()) {
-        return false;
-    }
-
-    // Indexed properties on the prototype chain aren't handled by the helper.
-    if (ObjectMayHaveExtraIndexedProperties(aobj->staticPrototype())) {
-        return false;
-    }
-
-    // Ensure we are still talking about an array class.
-    writer.guardClass(objId, GuardClassKind::Array);
-
-    // The helper we are going to call only applies to non-dense elements.
-    writer.guardIndexGreaterThanDenseInitLength(objId, indexId);
-
-    // Guard extensible: We may be trying to add a new element, and so we'd best
-    // be able to do so safely.
-    writer.guardIsExtensible(objId);
-
-    // Ensures we are able to efficiently able to map to an integral jsid.
-    writer.guardIndexIsNonNegative(indexId);
-
-    // Shape guard the prototype chain to avoid shadowing indexes from appearing.
-    // Dense elements may appear on the prototype chain (and prototypes may
-    // have a different notion of which elements are dense), but they can
-    // only be data properties, so our specialized Set handler is ok to bind
-    // to them.
-    ShapeGuardProtoChain(writer, obj, objId);
-
-    // Ensure that if we're adding an element to the object, the object's
-    // length is writable.
-    writer.guardIndexIsValidUpdateOrAdd(objId, indexId);
-
-    writer.callAddOrUpdateSparseElementHelper(objId, indexId, rhsId,
-                                              /* strict = */op == JSOP_STRICTSETELEM);
-    writer.returnFromIC();
-
-    trackAttached("AddOrUpdateSparseElement");
-    return true;
-}
-
-
 bool
 SetPropIRGenerator::tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId,
                                              uint32_t index, Int32OperandId indexId,
                                              ValOperandId rhsId)
 {
     if (!obj->is<TypedArrayObject>() && !IsPrimitiveArrayTypedObject(obj)) {
         return false;
     }
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -196,17 +196,16 @@ extern const char* const CacheKindNames[
     _(GuardIsInt32Index)                  \
     _(GuardType)                          \
     _(GuardShape)                         \
     _(GuardGroup)                         \
     _(GuardProto)                         \
     _(GuardClass)                         /* Guard an object class, per GuardClassKind */ \
     _(GuardAnyClass)                      /* Guard an arbitrary class for an object */ \
     _(GuardCompartment)                   \
-    _(GuardIsExtensible)                  \
     _(GuardIsNativeFunction)              \
     _(GuardIsNativeObject)                \
     _(GuardIsProxy)                       \
     _(GuardHasProxyHandler)               \
     _(GuardNotDOMProxy)                   \
     _(GuardSpecificObject)                \
     _(GuardSpecificAtom)                  \
     _(GuardSpecificSymbol)                \
@@ -218,19 +217,16 @@ extern const char* const CacheKindNames[
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(GuardAndGetIndexFromString)         \
     _(GuardAndGetNumberFromString)        \
     _(GuardAndGetIterator)                \
     _(GuardHasGetterSetter)               \
     _(GuardGroupHasUnanalyzedNewScript)   \
     _(GuardIndexIsNonNegative)            \
-    _(GuardIndexGreaterThanDenseCapacity) \
-    _(GuardIndexGreaterThanArrayLength)   \
-    _(GuardIndexIsValidUpdateOrAdd)       \
     _(GuardIndexGreaterThanDenseInitLength) \
     _(GuardTagNotEqual)                   \
     _(GuardXrayExpandoShapeAndDefaultProto) \
     _(GuardFunctionPrototype)             \
     _(GuardNoAllocationMetadataBuilder)   \
     _(GuardObjectGroupNotPretenured)      \
     _(LoadStackValue)                     \
     _(LoadObject)                         \
@@ -266,17 +262,16 @@ extern const char* const CacheKindNames[
     _(ArrayPush)                          \
     _(ArrayJoinResult)                    \
     _(StoreTypedElement)                  \
     _(CallNativeSetter)                   \
     _(CallScriptedSetter)                 \
     _(CallSetArrayLength)                 \
     _(CallProxySet)                       \
     _(CallProxySetByValue)                \
-    _(CallAddOrUpdateSparseElementHelper) \
     _(CallInt32ToString)                  \
     _(CallNumberToString)                 \
                                           \
     /* The *Result ops load a value into the cache's result register. */ \
     _(LoadFixedSlotResult)                \
     _(LoadDynamicSlotResult)              \
     _(LoadUnboxedPropertyResult)          \
     _(LoadTypedObjectResult)              \
@@ -765,19 +760,16 @@ class MOZ_RAII CacheIRWriter : public JS
     void guardCompartment(ObjOperandId obj, JSObject* global, JS::Compartment* compartment) {
         assertSameCompartment(global);
         writeOpWithOperandId(CacheOp::GuardCompartment, obj);
         // Add a reference to a global in the compartment to keep it alive.
         addStubField(uintptr_t(global), StubField::Type::JSObject);
         // Use RawWord, because compartments never move and it can't be GCed.
         addStubField(uintptr_t(compartment), StubField::Type::RawWord);
     }
-    void guardIsExtensible(ObjOperandId obj) {
-        writeOpWithOperandId(CacheOp::GuardIsExtensible, obj);
-    }
     void guardNoDetachedTypedObjects() {
         writeOp(CacheOp::GuardNoDetachedTypedObjects);
     }
     void guardFrameHasNoArgumentsObject() {
         writeOp(CacheOp::GuardFrameHasNoArgumentsObject);
     }
 
     Int32OperandId guardAndGetIndexFromString(StringOperandId str) {
@@ -814,28 +806,16 @@ class MOZ_RAII CacheIRWriter : public JS
 
     void guardIndexIsNonNegative(Int32OperandId index) {
         writeOpWithOperandId(CacheOp::GuardIndexIsNonNegative, index);
     }
     void guardIndexGreaterThanDenseInitLength(ObjOperandId obj, Int32OperandId index) {
         writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseInitLength, obj);
         writeOperandId(index);
     }
-    void guardIndexGreaterThanDenseCapacity(ObjOperandId obj, Int32OperandId index) {
-        writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseCapacity, obj);
-        writeOperandId(index);
-    }
-    void guardIndexGreaterThanArrayLength(ObjOperandId obj, Int32OperandId index) {
-        writeOpWithOperandId(CacheOp::GuardIndexGreaterThanArrayLength, obj);
-        writeOperandId(index);
-    }
-    void guardIndexIsValidUpdateOrAdd(ObjOperandId obj, Int32OperandId index) {
-        writeOpWithOperandId(CacheOp::GuardIndexIsValidUpdateOrAdd, obj);
-        writeOperandId(index);
-    }
     void guardTagNotEqual(ValueTagOperandId lhs, ValueTagOperandId rhs) {
         writeOpWithOperandId(CacheOp::GuardTagNotEqual, lhs);
         writeOperandId(rhs);
     }
 
     void loadFrameCalleeResult() {
         writeOp(CacheOp::LoadFrameCalleeResult);
     }
@@ -1056,22 +1036,16 @@ class MOZ_RAII CacheIRWriter : public JS
         buffer_.writeByte(uint32_t(strict));
     }
     void callProxySetByValue(ObjOperandId obj, ValOperandId id, ValOperandId rhs, bool strict) {
         writeOpWithOperandId(CacheOp::CallProxySetByValue, obj);
         writeOperandId(id);
         writeOperandId(rhs);
         buffer_.writeByte(uint32_t(strict));
     }
-    void callAddOrUpdateSparseElementHelper(ObjOperandId obj, Int32OperandId id, ValOperandId rhs, bool strict) {
-        writeOpWithOperandId(CacheOp::CallAddOrUpdateSparseElementHelper, obj);
-        writeOperandId(id);
-        writeOperandId(rhs);
-        buffer_.writeByte(uint32_t(strict));
-    }
     StringOperandId callInt32ToString(Int32OperandId id) {
         StringOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::CallInt32ToString, id);
         writeOperandId(res);
         return res;
     }
     StringOperandId callNumberToString(ValOperandId id) {
         StringOperandId res(nextOperandId_++);
@@ -1774,20 +1748,16 @@ class MOZ_RAII SetPropIRGenerator : publ
     bool tryAttachSetDenseElement(HandleObject obj, ObjOperandId objId, uint32_t index,
                                   Int32OperandId indexId, ValOperandId rhsId);
     bool tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId, uint32_t index,
                                   Int32OperandId indexId, ValOperandId rhsId);
 
     bool tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId objId, uint32_t index,
                                       Int32OperandId indexId, ValOperandId rhsId);
 
-    bool tryAttachAddOrUpdateSparseElement(HandleObject obj, ObjOperandId objId, uint32_t index,
-                                           Int32OperandId indexId, ValOperandId rhsId);
-
-
     bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
                                ValOperandId rhsId, bool handleDOMProxies);
     bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id,
                                    ValOperandId rhsId);
     bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id,
                                      ValOperandId rhsId);
     bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId, HandleId id,
                                   ValOperandId rhsId);
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1730,45 +1730,16 @@ CacheIRCompiler::emitGuardClass()
         masm.branchTestObjClassNoSpectreMitigations(Assembler::NotEqual, obj, clasp, scratch,
                                                     failure->label());
     }
 
     return true;
 }
 
 bool
-CacheIRCompiler::emitGuardIsExtensible()
-{
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    AutoScratchRegister scratch(allocator, masm);
-
-    FailurePath* failure;
-    if (!addFailurePath(&failure)) {
-        return false;
-    }
-
-    Address shape(obj, ShapedObject::offsetOfShape());
-    masm.loadPtr(shape, scratch);
-
-    Address baseShape(scratch, Shape::offsetOfBaseShape());
-    masm.loadPtr(baseShape, scratch);
-
-    Address baseShapeFlags(scratch, BaseShape::offsetOfFlags());
-    masm.loadPtr(baseShapeFlags, scratch);
-
-    masm.and32(Imm32(js::BaseShape::NOT_EXTENSIBLE), scratch);
-
-    // Spectre-style checks are not needed here because we do not
-    // interpret data based on this check.
-    masm.branch32(Assembler::Equal, scratch, Imm32(js::BaseShape::NOT_EXTENSIBLE),
-                  failure->label());
-    return true;
-}
-
-bool
 CacheIRCompiler::emitGuardIsNativeFunction()
 {
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     JSNative nativeFunc = reinterpret_cast<JSNative>(reader.pointer());
     AutoScratchRegister scratch(allocator, masm);
 
     FailurePath* failure;
     if (!addFailurePath(&failure)) {
@@ -2860,110 +2831,27 @@ CacheIRCompiler::emitGuardIndexGreaterTh
     FailurePath* failure;
     if (!addFailurePath(&failure)) {
         return false;
     }
 
     // Load obj->elements.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
-    // Ensure index >= initLength.
+    // Ensure index >= capacity.
     Label outOfBounds;
     Address capacity(scratch, ObjectElements::offsetOfInitializedLength());
     masm.spectreBoundsCheck32(index, capacity, scratch2, &outOfBounds);
     masm.jump(failure->label());
     masm.bind(&outOfBounds);
 
     return true;
 }
 
 bool
-CacheIRCompiler::emitGuardIndexGreaterThanDenseCapacity()
-{
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    Register index = allocator.useRegister(masm, reader.int32OperandId());
-    AutoScratchRegister scratch(allocator, masm);
-    AutoScratchRegister scratch2(allocator, masm);
-
-    FailurePath* failure;
-    if (!addFailurePath(&failure)) {
-        return false;
-    }
-
-    // Load obj->elements.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
-
-    // Ensure index >= capacity.
-    Label outOfBounds;
-    Address capacity(scratch, ObjectElements::offsetOfCapacity());
-    masm.spectreBoundsCheck32(index, capacity, scratch2, &outOfBounds);
-    masm.jump(failure->label());
-    masm.bind(&outOfBounds);
-
-    return true;
-}
-
-bool
-CacheIRCompiler::emitGuardIndexGreaterThanArrayLength()
-{
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    Register index = allocator.useRegister(masm, reader.int32OperandId());
-    AutoScratchRegister scratch(allocator, masm);
-    AutoScratchRegister scratch2(allocator, masm);
-
-    FailurePath* failure;
-    if (!addFailurePath(&failure)) {
-        return false;
-    }
-
-    // Load obj->elements.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
-
-    // Ensure index >= length;
-    Label outOfBounds;
-    Address length(scratch, ObjectElements::offsetOfLength());
-    masm.spectreBoundsCheck32(index, length, scratch2, &outOfBounds);
-    masm.jump(failure->label());
-    masm.bind(&outOfBounds);
-    return true;
-}
-
-bool
-CacheIRCompiler::emitGuardIndexIsValidUpdateOrAdd()
-{
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    Register index = allocator.useRegister(masm, reader.int32OperandId());
-    AutoScratchRegister scratch(allocator, masm);
-    AutoScratchRegister scratch2(allocator, masm);
-
-    FailurePath* failure;
-    if (!addFailurePath(&failure)) {
-        return false;
-    }
-
-    // Load obj->elements.
-    masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
-
-    Label success;
-
-    // If length is writable, branch to &success.  All indices are writable.
-    Address flags(scratch, ObjectElements::offsetOfFlags());
-    masm.branchTest32(Assembler::Zero, flags,
-                      Imm32(ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH),
-                      &success);
-
-    // Otherwise, ensure index is in bounds.
-    Address length(scratch, ObjectElements::offsetOfLength());
-    masm.spectreBoundsCheck32(index, length, scratch2,
-                              /* failure = */ failure->label());
-    masm.bind(&success);
-    return true;
-}
-
-bool
 CacheIRCompiler::emitGuardTagNotEqual()
 {
     Register lhs = allocator.useRegister(masm, reader.valueTagOperandId());
     Register rhs = allocator.useRegister(masm, reader.valueTagOperandId());
 
     FailurePath* failure;
     if (!addFailurePath(&failure)) {
         return false;
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -27,34 +27,30 @@ namespace jit {
     _(GuardIsString)                      \
     _(GuardIsSymbol)                      \
     _(GuardIsNumber)                      \
     _(GuardIsInt32)                       \
     _(GuardIsInt32Index)                  \
     _(GuardType)                          \
     _(GuardClass)                         \
     _(GuardGroupHasUnanalyzedNewScript)   \
-    _(GuardIsExtensible)                  \
     _(GuardIsNativeFunction)              \
     _(GuardFunctionPrototype)             \
     _(GuardIsNativeObject)                \
     _(GuardIsProxy)                       \
     _(GuardNotDOMProxy)                   \
     _(GuardSpecificInt32Immediate)        \
     _(GuardMagicValue)                    \
     _(GuardNoUnboxedExpando)              \
     _(GuardAndLoadUnboxedExpando)         \
     _(GuardNoDetachedTypedObjects)        \
     _(GuardNoDenseElements)               \
     _(GuardAndGetNumberFromString)        \
     _(GuardAndGetIndexFromString)         \
     _(GuardIndexIsNonNegative)            \
-    _(GuardIndexGreaterThanDenseCapacity) \
-    _(GuardIndexGreaterThanArrayLength)   \
-    _(GuardIndexIsValidUpdateOrAdd)       \
     _(GuardIndexGreaterThanDenseInitLength) \
     _(GuardTagNotEqual)                   \
     _(GuardXrayExpandoShapeAndDefaultProto)\
     _(GuardNoAllocationMetadataBuilder)   \
     _(GuardObjectGroupNotPretenured)      \
     _(LoadObject)                         \
     _(LoadProto)                          \
     _(LoadEnclosingEnvironment)           \
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -2261,38 +2261,16 @@ IonCacheIRCompiler::emitCallProxySetByVa
     masm.Push(val);
     masm.Push(idVal);
     masm.Push(obj);
 
     return callVM(masm, ProxySetPropertyByValueInfo);
 }
 
 bool
-IonCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper()
-{
-    AutoSaveLiveRegisters save(*this);
-
-    Register obj = allocator.useRegister(masm, reader.objOperandId());
-    Register id = allocator.useRegister(masm, reader.int32OperandId());
-    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
-    bool strict = reader.readBool();
-
-    Label done;
-    prepareVMCall(masm, save);
-
-    masm.Push(Imm32(strict));
-    masm.Push(val);
-    masm.Push(id);
-    masm.Push(obj);
-
-    return callVM(masm, AddOrUpdateSparseElementHelperInfo);
-}
-
-
-bool
 IonCacheIRCompiler::emitMegamorphicSetElement()
 {
     AutoSaveLiveRegisters save(*this);
 
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     ConstantOrRegister idVal = allocator.useConstantOrRegister(masm, reader.valOperandId());
     ConstantOrRegister val = allocator.useConstantOrRegister(masm, reader.valOperandId());
     bool strict = reader.readBool();
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -2067,15 +2067,10 @@ const VMFunction ProxyHasInfo = Function
 typedef bool (*ProxyHasOwnFn)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
 const VMFunction ProxyHasOwnInfo = FunctionInfo<ProxyHasOwnFn>(ProxyHasOwn, "ProxyHasOwn");
 
 typedef bool (*NativeGetElementFn)(JSContext*, HandleNativeObject, HandleValue, int32_t,
                                    MutableHandleValue);
 const VMFunction NativeGetElementInfo =
     FunctionInfo<NativeGetElementFn>(NativeGetElement, "NativeGetProperty");
 
-typedef bool (*AddOrUpdateSparseElementHelperFn)(JSContext* cx, HandleArrayObject obj,
-                                                 int32_t int_id, HandleValue v, bool strict);
-const VMFunction AddOrUpdateSparseElementHelperInfo =
-    FunctionInfo<AddOrUpdateSparseElementHelperFn>(AddOrUpdateSparseElementHelper, "AddOrUpdateSparseElementHelper");
-
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -977,17 +977,15 @@ extern const VMFunction ProxyGetProperty
 extern const VMFunction ProxyGetPropertyByValueInfo;
 extern const VMFunction ProxySetPropertyInfo;
 extern const VMFunction ProxySetPropertyByValueInfo;
 extern const VMFunction ProxyHasInfo;
 extern const VMFunction ProxyHasOwnInfo;
 
 extern const VMFunction NativeGetElementInfo;
 
-extern const VMFunction AddOrUpdateSparseElementHelperInfo;
-
 // TailCall VMFunctions
 extern const VMFunction DoConcatStringObjectInfo;
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2102,58 +2102,16 @@ DefineNonexistentProperty(JSContext* cx,
         if (!AddDataProperty(cx, obj, id, v)) {
             return false;
         }
     }
 
     return result.succeed();
 }
 
-bool
-js::AddOrUpdateSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
-                                   HandleValue v, bool strict)
-{
-    MOZ_ASSERT(INT_FITS_IN_JSID(int_id));
-    RootedId id(cx, INT_TO_JSID(int_id));
-
-    // This helper doesn't handle the case where the index may be in the dense elements
-    MOZ_ASSERT(int_id >= 0);
-    MOZ_ASSERT(uint32_t(int_id) >= obj->getDenseInitializedLength());
-
-    // First decide if this is an add or an update. Because the IC guards have
-    // already ensured this exists exterior to the dense array range, and the
-    // prototype checks have ensured there are no indexes on the prototype, we
-    // can use the shape lineage to find the element if it exists:
-    RootedShape shape(cx, obj->lastProperty()->search(cx, id));
-
-    // If we didn't find the shape, we're on the add path: delegate to
-    // AddSparseElement:
-    if (shape == nullptr) {
-        Rooted<PropertyDescriptor> desc(cx);
-        desc.setDataDescriptor(v, JSPROP_ENUMERATE);
-        desc.assertComplete();
-
-        return AddOrChangeProperty<IsAddOrChange::Add>(cx, obj, id, desc);
-    }
-
-    // At this point we're updating a property: See SetExistingProperty
-    if (shape->writable() && shape->isDataProperty()) {
-        // While all JSID_INT properties use a single TI entry,
-        // nothing yet has inspected the updated value so we *must* use setSlotWithType().
-        obj->setSlotWithType(cx, shape, v, /* overwriting = */ true);
-        return true;
-    }
-
-    // We don't know exactly what this object looks like, hit the slowpath.
-    RootedValue receiver(cx, ObjectValue(*obj));
-    JS::ObjectOpResult result;
-    return SetProperty(cx, obj, id, v, receiver, result) &&
-           result.checkStrictErrorOrWarning(cx, obj, id, strict);
-}
-
 
 /*** [[HasProperty]] *****************************************************************************/
 
 // ES6 draft rev31 9.1.7.1 OrdinaryHasProperty
 bool
 js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp)
 {
     RootedNativeObject pobj(cx, obj);
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1617,20 +1617,16 @@ NativeGetElement(JSContext* cx, HandleNa
 bool
 SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
                       ObjectOpResult& result);
 
 bool
 SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
                    HandleValue receiver, ObjectOpResult& result);
 
-bool
-AddOrUpdateSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
-                               HandleValue v, bool strict);
-
 /*
  * Indicates whether an assignment operation is qualified (`x.y = 0`) or
  * unqualified (`y = 0`). In strict mode, the latter is an error if no such
  * variable already exists.
  *
  * Used as an argument to NativeSetProperty.
  */
 enum QualifiedBool {
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1154,20 +1154,18 @@ class Shape : public gc::TenuredCell
 
     MOZ_ALWAYS_INLINE Shape* search(JSContext* cx, jsid id);
     MOZ_ALWAYS_INLINE Shape* searchLinear(jsid id);
 
     void fixupAfterMovingGC();
     void fixupGetterSetterForBarrier(JSTracer* trc);
     void updateBaseShapeAfterMovingGC();
 
+#ifdef DEBUG
     // For JIT usage.
-    static inline size_t offsetOfBaseShape() { return offsetof(Shape, base_); }
-
-#ifdef DEBUG
     static inline size_t offsetOfImmutableFlags() { return offsetof(Shape, immutableFlags); }
     static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
 #endif
 
   private:
     void fixupDictionaryShapeAfterMovingGC();
     void fixupShapeTreeAfterMovingGC();
 
--- a/js/src/vm/ShapedObject.h
+++ b/js/src/vm/ShapedObject.h
@@ -6,18 +6,16 @@
 
 #ifndef vm_ShapedObject_h
 #define vm_ShapedObject_h
 
 #include "vm/JSObject.h"
 
 namespace js {
 
-namespace jit { class CacheIRCompiler; }
-
 /*
  * Shaped objects are a variant of JSObject that use a GCPtrShape for their
  * |shapeOrExpando_| field. All objects that point to a js::Shape as their
  * |shapeOrExpando_| field should use this as their subclass.
  *
  * NOTE: shape()->getObjectClass() must equal getClass().
  */
 class ShapedObject : public JSObject
@@ -55,18 +53,16 @@ class ShapedObject : public JSObject
     static JSObject* fromShapeFieldPointer(uintptr_t p) {
         return reinterpret_cast<JSObject*>(p - ShapedObject::offsetOfShape());
     }
 
   private:
     // See JSObject::offsetOfGroup() comment.
     friend class js::jit::MacroAssembler;
 
-    friend class js::jit::CacheIRCompiler;
-
     static constexpr size_t offsetOfShape() {
         static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape),
                       "shadow shape must match actual shape");
         return offsetOfShapeOrExpando();
     }
 };
 
 } // namespace js
--- a/taskcluster/ci/build/windows.yml
+++ b/taskcluster/ci/build/windows.yml
@@ -244,17 +244,17 @@ win32-nightly/opt:
     shipping-phase: build
     shipping-product: firefox
     treeherder:
         platform: windows2012-32/opt
         symbol: N
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
     worker:
-        max-run-time: 7200
+        max-run-time: 10800
         env:
             TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win32/releng.manifest"
     run:
         using: mozharness
         actions: [build, check-test]
         options: [append-env-variables-from-configs]
         script: mozharness/scripts/fx_desktop_build.py
         config:
@@ -283,17 +283,17 @@ win64-nightly/opt:
     shipping-phase: build
     shipping-product: firefox
     treeherder:
         platform: windows2012-64/opt
         symbol: N
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
     worker:
-        max-run-time: 7200
+        max-run-time: 10800
         env:
             TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win64/releng.manifest"
     run:
         using: mozharness
         actions: [build, check-test]
         options: [append-env-variables-from-configs]
         script: mozharness/scripts/fx_desktop_build.py
         config:
@@ -688,17 +688,17 @@ win32-devedition-nightly/opt:
     shipping-phase: build
     shipping-product: devedition
     treeherder:
         platform: windows2012-32-devedition/opt
         symbol: N
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
     worker:
-        max-run-time: 7200
+        max-run-time: 10800
         env:
             TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win32/releng.manifest"
     run:
         using: mozharness
         script: mozharness/scripts/fx_desktop_build.py
         options: [enable-pgo, append-env-variables-from-configs]
         config:
             - builds/releng_base_firefox.py
@@ -728,17 +728,17 @@ win64-devedition-nightly/opt:
     shipping-phase: build
     shipping-product: devedition
     treeherder:
         platform: windows2012-64-devedition/opt
         symbol: N
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
     worker:
-        max-run-time: 7200
+        max-run-time: 10800
         env:
             TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win64/releng.manifest"
     run:
         using: mozharness
         options: [append-env-variables-from-configs]
         script: mozharness/scripts/fx_desktop_build.py
         config:
             - builds/releng_base_firefox.py