Bug 1225031 - get rid of the AnyTypedArray abstraction (updated). r=waldo
authorLars T Hansen <lhansen@mozilla.com>
Tue, 12 Jan 2016 14:47:51 +0100
changeset 314729 b7a4595a79011dc47a6ac00eee59969586cccbe9
parent 314728 d081f975bf1707be39ffeb08a59905cb6f3e2ee6
child 314730 22cef5fdb145f7ed4112fcfd2127c582d3c85d6f
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs1225031
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1225031 - get rid of the AnyTypedArray abstraction (updated). r=waldo
js/src/builtin/SIMD.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonCaches.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/RangeAnalysis.cpp
js/src/jit/SharedIC.h
js/src/jsarray.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/vm/NativeObject-inl.h
js/src/vm/NativeObject.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Shape-inl.h
js/src/vm/TypeInference.cpp
js/src/vm/TypedArrayCommon.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -1139,28 +1139,28 @@ template<class VElem, unsigned NumElem>
 static bool
 TypedArrayFromArgs(JSContext* cx, const CallArgs& args,
                    MutableHandleObject typedArray, int32_t* byteStart)
 {
     if (!args[0].isObject())
         return ErrorBadArgs(cx);
 
     JSObject& argobj = args[0].toObject();
-    if (!IsAnyTypedArray(&argobj))
+    if (!argobj.is<TypedArrayObject>())
         return ErrorBadArgs(cx);
 
     typedArray.set(&argobj);
 
     int32_t index;
     if (!ToInt32(cx, args[1], &index))
         return false;
 
-    *byteStart = index * AnyTypedArrayBytesPerElement(typedArray);
-    if (*byteStart < 0 ||
-        (uint32_t(*byteStart) + NumElem * sizeof(VElem)) > AnyTypedArrayByteLength(typedArray))
+    *byteStart = index * typedArray->as<TypedArrayObject>().bytesPerElement();
+    if (*byteStart < 0 || (uint32_t(*byteStart) + NumElem * sizeof(VElem)) >
+                          typedArray->as<TypedArrayObject>().byteLength())
     {
         // Keep in sync with AsmJS OnOutOfBounds function.
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
         return false;
     }
 
     return true;
 }
@@ -1183,17 +1183,18 @@ Load(JSContext* cx, unsigned argc, Value
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
     if (!typeDescr)
         return false;
 
     Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
     if (!result)
         return false;
 
-    SharedMem<Elem*> src = AnyTypedArrayViewData(typedArray).addBytes(byteStart).cast<Elem*>();
+    SharedMem<Elem*> src =
+        typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>();
     Elem* dst = reinterpret_cast<Elem*>(result->typedMem());
     jit::AtomicOperations::podCopySafeWhenRacy(SharedMem<Elem*>::unshared(dst), src, NumElem);
 
     args.rval().setObject(*result);
     return true;
 }
 
 template<class V, unsigned NumElem>
@@ -1210,17 +1211,18 @@ Store(JSContext* cx, unsigned argc, Valu
     RootedObject typedArray(cx);
     if (!TypedArrayFromArgs<Elem, NumElem>(cx, args, &typedArray, &byteStart))
         return false;
 
     if (!IsVectorObject<V>(args[2]))
         return ErrorBadArgs(cx);
 
     Elem* src = TypedObjectMemory<Elem*>(args[2]);
-    SharedMem<Elem*> dst = AnyTypedArrayViewData(typedArray).addBytes(byteStart).cast<Elem*>();
+    SharedMem<Elem*> dst =
+        typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>();
     js::jit::AtomicOperations::podCopySafeWhenRacy(dst, SharedMem<Elem*>::unshared(src), NumElem);
 
     args.rval().setObject(args[2].toObject());
     return true;
 }
 
 #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands)       \
 bool                                                               \
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1551,44 +1551,44 @@ PrimitiveArrayTypedObjectType(JSObject* 
     MOZ_ASSERT(IsPrimitiveArrayTypedObject(obj));
     TypeDescr& descr = obj->as<TypedObject>().typeDescr();
     return descr.as<ArrayTypeDescr>().elementType().as<ScalarTypeDescr>().type();
 }
 
 static Scalar::Type
 TypedThingElementType(JSObject* obj)
 {
-    return IsAnyTypedArray(obj)
-           ? AnyTypedArrayType(obj)
+    return obj->is<TypedArrayObject>()
+           ? obj->as<TypedArrayObject>().type()
            : PrimitiveArrayTypedObjectType(obj);
 }
 
 static bool
 TypedThingRequiresFloatingPoint(JSObject* obj)
 {
     Scalar::Type type = TypedThingElementType(obj);
     return type == Scalar::Uint32 ||
            type == Scalar::Float32 ||
            type == Scalar::Float64;
 }
 
 static bool
 IsNativeDenseElementAccess(HandleObject obj, HandleValue key)
 {
-    if (obj->isNative() && key.isInt32() && key.toInt32() >= 0 && !IsAnyTypedArray(obj.get()))
+    if (obj->isNative() && key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>())
         return true;
     return false;
 }
 
 static bool
 IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key)
 {
     if (!obj->isNative() && !obj->is<UnboxedArrayObject>())
         return false;
-    if (key.isInt32() && key.toInt32() >= 0 && !IsAnyTypedArray(obj.get()))
+    if (key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>())
         return true;
     return false;
 }
 
 static bool
 TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_Fallback* stub,
                      HandleValue lhs, HandleValue rhs, HandleValue res, bool* attached)
 {
@@ -1693,17 +1693,17 @@ TryAttachGetElemStub(JSContext* cx, JSSc
             return false;
 
         stub->addNewStub(unboxedStub);
         *attached = true;
         return true;
     }
 
     // Check for TypedArray[int] => Number and TypedObject[int] => Number accesses.
-    if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
+    if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) &&
         rhs.isNumber() &&
         res.isNumber() &&
         !TypedArrayGetElemStubExists(stub, obj))
     {
         if (!cx->runtime()->jitSupportsFloatingPoint &&
             (TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
         {
             return true;
@@ -2842,30 +2842,30 @@ DoSetElemFallback(JSContext* cx, Baselin
 
                 stub->addNewStub(newStub);
             }
         }
 
         return true;
     }
 
-    if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
+    if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) &&
         index.isNumber() &&
         rhs.isNumber())
     {
         if (!cx->runtime()->jitSupportsFloatingPoint &&
             (TypedThingRequiresFloatingPoint(obj) || index.isDouble()))
         {
             return true;
         }
 
         bool expectOutOfBounds;
         double idx = index.toNumber();
-        if (IsAnyTypedArray(obj)) {
-            expectOutOfBounds = (idx < 0 || idx >= double(AnyTypedArrayLength(obj)));
+        if (obj->is<TypedArrayObject>()) {
+            expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
         } else {
             // Typed objects throw on out of bounds accesses. Don't attach
             // a stub in this case.
             if (idx < 0 || idx >= double(obj->as<TypedObject>().length()))
                 return true;
             expectOutOfBounds = false;
 
             // Don't attach stubs if typed objects in the compartment might be
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8992,17 +8992,17 @@ IonBuilder::getElemTryDense(bool* emitte
     *emitted = true;
     return true;
 }
 
 JSObject*
 IonBuilder::getStaticTypedArrayObject(MDefinition* obj, MDefinition* index)
 {
     Scalar::Type arrayType;
-    if (!ElementAccessIsAnyTypedArray(constraints(), obj, index, &arrayType)) {
+    if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) {
         trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
         return nullptr;
     }
 
     if (!LIRGenerator::allowStaticTypedArrayAccesses()) {
         trackOptimizationOutcome(TrackedOutcome::Disabled);
         return nullptr;
     }
@@ -9037,17 +9037,17 @@ IonBuilder::getElemTryTypedStatic(bool* 
 {
     MOZ_ASSERT(*emitted == false);
 
     JSObject* tarrObj = getStaticTypedArrayObject(obj, index);
     if (!tarrObj)
         return true;
 
     // LoadTypedArrayElementStatic currently treats uint32 arrays as int32.
-    Scalar::Type viewType = AnyTypedArrayType(tarrObj);
+    Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
     if (viewType == Scalar::Uint32) {
         trackOptimizationOutcome(TrackedOutcome::StaticTypedArrayUint32);
         return true;
     }
 
     MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
     if (!ptr)
         return true;
@@ -9087,17 +9087,17 @@ IonBuilder::getElemTryTypedStatic(bool* 
 }
 
 bool
 IonBuilder::getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index)
 {
     MOZ_ASSERT(*emitted == false);
 
     Scalar::Type arrayType;
-    if (!ElementAccessIsAnyTypedArray(constraints(), obj, index, &arrayType)) {
+    if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) {
         trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
         return true;
     }
 
     // Emit typed getelem variant.
     if (!jsop_getelem_typed(obj, index, arrayType))
         return false;
 
@@ -9449,31 +9449,31 @@ IonBuilder::addTypedArrayLengthAndData(M
     JSObject* tarr = nullptr;
 
     if (obj->isConstantValue() && obj->constantValue().isObject())
         tarr = &obj->constantValue().toObject();
     else if (obj->resultTypeSet())
         tarr = obj->resultTypeSet()->maybeSingleton();
 
     if (tarr) {
-        SharedMem<void*> data = AnyTypedArrayViewData(tarr);
+        SharedMem<void*> data = tarr->as<TypedArrayObject>().viewDataEither();
         // Bug 979449 - Optimistically embed the elements and use TI to
         //              invalidate if we move them.
         bool isTenured = !tarr->runtimeFromMainThread()->gc.nursery.isInside(data);
         if (isTenured && tarr->isSingleton()) {
             // The 'data' pointer of TypedArrayObject can change in rare circumstances
             // (ArrayBufferObject::changeContents).
             TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarr);
             if (!tarrKey->unknownProperties()) {
                 if (tarr->is<TypedArrayObject>())
                     tarrKey->watchStateChangeForTypedArrayData(constraints());
 
                 obj->setImplicitlyUsedUnchecked();
 
-                int32_t len = AssertedCast<int32_t>(AnyTypedArrayLength(tarr));
+                int32_t len = AssertedCast<int32_t>(tarr->as<TypedArrayObject>().length());
                 *length = MConstant::New(alloc(), Int32Value(len));
                 current->add(*length);
 
                 if (index) {
                     if (checking == DoBoundsCheck)
                         *index = addBoundsCheck(*index, *length);
 
                     *elements = MConstantElements::New(alloc(), data);
@@ -9816,20 +9816,21 @@ IonBuilder::setElemTryTypedStatic(bool* 
                                   MDefinition* index, MDefinition* value)
 {
     MOZ_ASSERT(*emitted == false);
 
     JSObject* tarrObj = getStaticTypedArrayObject(object, index);
     if (!tarrObj)
         return true;
 
-    if (tarrObj->runtimeFromMainThread()->gc.nursery.isInside(AnyTypedArrayViewData(tarrObj)))
-        return true;
-
-    Scalar::Type viewType = AnyTypedArrayType(tarrObj);
+    SharedMem<void*> viewData = tarrObj->as<TypedArrayObject>().viewDataEither();
+    if (tarrObj->runtimeFromMainThread()->gc.nursery.isInside(viewData))
+        return true;
+
+    Scalar::Type viewType = tarrObj->as<TypedArrayObject>().type();
     MDefinition* ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
     if (!ptr)
         return true;
 
     // Emit StoreTypedArrayElementStatic.
 
     if (tarrObj->is<TypedArrayObject>()) {
         TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarrObj);
@@ -9860,17 +9861,17 @@ IonBuilder::setElemTryTypedStatic(bool* 
 
 bool
 IonBuilder::setElemTryTypedArray(bool* emitted, MDefinition* object,
                                  MDefinition* index, MDefinition* value)
 {
     MOZ_ASSERT(*emitted == false);
 
     Scalar::Type arrayType;
-    if (!ElementAccessIsAnyTypedArray(constraints(), object, index, &arrayType)) {
+    if (!ElementAccessIsTypedArray(constraints(), object, index, &arrayType)) {
         trackOptimizationOutcome(TrackedOutcome::AccessNotTypedArray);
         return true;
     }
 
     // Emit typed setelem variant.
     if (!jsop_setelem_typed(arrayType, object, index, value))
         return false;
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1615,17 +1615,17 @@ GetPropertyIC::tryAttachUnboxedArrayLeng
 
 bool
 GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
                                          HandleObject obj, HandleId id, bool* emitted)
 {
     MOZ_ASSERT(canAttachStub());
     MOZ_ASSERT(!*emitted);
 
-    if (!IsAnyTypedArray(obj))
+    if (!obj->is<TypedArrayObject>())
         return true;
 
     if (!JSID_IS_ATOM(id, cx->names().length))
         return true;
 
     if (hasTypedArrayLengthStub(obj))
         return true;
 
@@ -3973,17 +3973,17 @@ GetPropertyIC::tryAttachDenseElementHole
     return linkAndAttachStub(cx, masm, attacher, ion, "dense hole",
                              JS::TrackedOutcome::ICGetElemStub_DenseHole);
 }
 
 /* static */ bool
 GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval,
                                                    TypedOrValueRegister output)
 {
-    if (!IsAnyTypedArray(obj) && !obj->is<UnboxedArrayObject>())
+    if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
         return false;
 
     MOZ_ASSERT(idval.isInt32() || idval.isString());
 
     // Don't emit a stub if the access is out of bounds. We make to make
     // certain that we monitor the type coming out of the typed array when
     // we generate the stub. Out of bounds accesses will hit the fallback
     // path.
@@ -3991,23 +3991,23 @@ GetPropertyIC::canAttachTypedOrUnboxedAr
     if (idval.isInt32()) {
         index = idval.toInt32();
     } else {
         index = GetIndexFromString(idval.toString());
         if (index == UINT32_MAX)
             return false;
     }
 
-    if (IsAnyTypedArray(obj)) {
-        if (index >= AnyTypedArrayLength(obj))
+    if (obj->is<TypedArrayObject>()) {
+        if (index >= obj->as<TypedArrayObject>().length())
             return false;
 
         // The output register is not yet specialized as a float register, the only
         // way to accept float typed arrays for now is to return a Value type.
-        uint32_t arrayType = AnyTypedArrayType(obj);
+        uint32_t arrayType = obj->as<TypedArrayObject>().type();
         if (arrayType == Scalar::Float32 || arrayType == Scalar::Float64)
             return output.hasValue();
 
         return output.hasValue() || !output.typedReg().isFloat();
     }
 
     if (index >= obj->as<UnboxedArrayObject>().initializedLength())
         return false;
@@ -4087,31 +4087,31 @@ GenerateGetTypedOrUnboxedArrayElement(JS
         } else {
             MOZ_ASSERT(!index.reg().typedReg().isFloat());
             indexReg = index.reg().typedReg().gpr();
         }
     }
 
     Label popObjectAndFail;
 
-    if (IsAnyTypedArray(array)) {
+    if (array->is<TypedArrayObject>()) {
         // Guard on the initialized length.
         Address length(object, TypedArrayObject::lengthOffset());
         masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
 
         // Save the object register on the stack in case of failure.
         Register elementReg = object;
         masm.push(object);
 
         // Load elements vector.
         masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
 
         // Load the value. We use an invalid register because the destination
         // register is necessary a non double register.
-        Scalar::Type arrayType = AnyTypedArrayType(array);
+        Scalar::Type arrayType = array->as<TypedArrayObject>().type();
         int width = Scalar::byteSize(arrayType);
         BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
         if (output.hasValue()) {
             masm.loadFromTypedArray(arrayType, source, output.valueReg(), allowDoubleResult,
                                     elementReg, &popObjectAndFail);
         } else {
             masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail);
         }
@@ -4316,17 +4316,17 @@ IsDenseElementSetInlineable(JSObject* ob
 
     return true;
 }
 
 static bool
 IsTypedArrayElementSetInlineable(JSObject* obj, const Value& idval, const Value& value)
 {
     // Don't bother attaching stubs for assigning strings, objects or symbols.
-    return IsAnyTypedArray(obj) && idval.isInt32() &&
+    return obj->is<TypedArrayObject>() && idval.isInt32() &&
            !value.isString() && !value.isObject() && !value.isSymbol();
 }
 
 static void
 StoreDenseElement(MacroAssembler& masm, ConstantOrRegister value, Register elements,
                   BaseObjectElementIndex target)
 {
     // If the ObjectElements::CONVERT_DOUBLE_ELEMENTS flag is set, int32 values
@@ -4520,17 +4520,17 @@ static bool
 GenerateSetTypedArrayElement(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
                              HandleObject tarr, Register object, TypedOrValueRegister index,
                              ConstantOrRegister value, Register tempUnbox, Register temp,
                              FloatRegister tempDouble, FloatRegister tempFloat32)
 {
     Label failures, done, popObjectAndFail;
 
     // Guard on the shape.
-    Shape* shape = AnyTypedArrayShape(tarr);
+    Shape* shape = tarr->as<TypedArrayObject>().lastProperty();
     if (!shape)
         return false;
     masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
 
     // Ensure the index is an int32.
     Register indexReg;
     if (index.hasValue()) {
         ValueOperand val = index.valueReg();
@@ -4547,17 +4547,17 @@ GenerateSetTypedArrayElement(JSContext* 
     masm.unboxInt32(length, temp);
     masm.branch32(Assembler::BelowOrEqual, temp, indexReg, &done);
 
     // Load the elements vector.
     Register elements = temp;
     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elements);
 
     // Set the value.
-    Scalar::Type arrayType = AnyTypedArrayType(tarr);
+    Scalar::Type arrayType = tarr->as<TypedArrayObject>().type();
     int width = Scalar::byteSize(arrayType);
     BaseIndex target(elements, indexReg, ScaleFromElemWidth(width));
 
     if (arrayType == Scalar::Float32) {
         MOZ_ASSERT_IF(hasUnaliasedDouble(), tempFloat32 != InvalidFloatReg);
         FloatRegister tempFloat = hasUnaliasedDouble() ? tempFloat32 : tempDouble;
         if (!masm.convertConstantOrRegisterToFloat(cx, value, tempFloat, &failures))
             return false;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -3591,17 +3591,17 @@ SimdTypeToArrayElementType(SimdTypeDescr
 
 bool
 IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
                                     MDefinition** index, Scalar::Type* arrayType)
 {
     MDefinition* array = callInfo.getArg(0);
     *index = callInfo.getArg(1);
 
-    if (!ElementAccessIsAnyTypedArray(constraints(), array, *index, arrayType))
+    if (!ElementAccessIsTypedArray(constraints(), array, *index, arrayType))
         return false;
 
     MInstruction* indexAsInt32 = MToInt32::New(alloc(), *index);
     current->add(indexAsInt32);
     *index = indexAsInt32;
 
     MDefinition* indexForBoundsCheck = *index;
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4679,23 +4679,23 @@ InlinePropertyTable::buildTypeSetForFunc
             types->addType(TypeSet::ObjectType(entries_[i]->group), alloc);
     }
     return types;
 }
 
 SharedMem<void*>
 MLoadTypedArrayElementStatic::base() const
 {
-    return AnyTypedArrayViewData(someTypedArray_);
+    return someTypedArray_->as<TypedArrayObject>().viewDataEither();
 }
 
 size_t
 MLoadTypedArrayElementStatic::length() const
 {
-    return AnyTypedArrayByteLength(someTypedArray_);
+    return someTypedArray_->as<TypedArrayObject>().byteLength();
 }
 
 bool
 MLoadTypedArrayElementStatic::congruentTo(const MDefinition* ins) const
 {
     if (!ins->isLoadTypedArrayElementStatic())
         return false;
     const MLoadTypedArrayElementStatic* other = ins->toLoadTypedArrayElementStatic();
@@ -4708,32 +4708,32 @@ MLoadTypedArrayElementStatic::congruentT
     if (base() != other->base())
         return false;
     return congruentIfOperandsEqual(other);
 }
 
 SharedMem<void*>
 MStoreTypedArrayElementStatic::base() const
 {
-    return AnyTypedArrayViewData(someTypedArray_);
+    return someTypedArray_->as<TypedArrayObject>().viewDataEither();
 }
 
 bool
 MGetPropertyCache::allowDoubleResult() const
 {
     if (!resultTypeSet())
         return true;
 
     return resultTypeSet()->hasType(TypeSet::DoubleType());
 }
 
 size_t
 MStoreTypedArrayElementStatic::length() const
 {
-    return AnyTypedArrayByteLength(someTypedArray_);
+    return someTypedArray_->as<TypedArrayObject>().byteLength();
 }
 
 bool
 MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const
 {
     // Allow hoisting this instruction if the store does not write to a
     // slot read by this instruction.
 
@@ -4958,17 +4958,17 @@ jit::ElementAccessIsDenseNative(Compiler
         return false;
 
     TemporaryTypeSet* types = obj->resultTypeSet();
     if (!types)
         return false;
 
     // Typed arrays are native classes but do not have dense elements.
     const Class* clasp = types->getKnownClass(constraints);
-    return clasp && clasp->isNative() && !IsAnyTypedArrayClass(clasp);
+    return clasp && clasp->isNative() && !IsTypedArrayClass(clasp);
 }
 
 JSValueType
 jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
                              MDefinition* id)
 {
     if (obj->mightBeType(MIRType_String))
         return JSVAL_TYPE_MAGIC;
@@ -5004,19 +5004,19 @@ jit::UnboxedArrayElementType(CompilerCon
 
         key->watchStateChangeForUnboxedConvertedToNative(constraints);
     }
 
     return elementType;
 }
 
 bool
-jit::ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
-                                  MDefinition* obj, MDefinition* id,
-                                  Scalar::Type* arrayType)
+jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
+                               MDefinition* obj, MDefinition* id,
+                               Scalar::Type* arrayType)
 {
     if (obj->mightBeType(MIRType_String))
         return false;
 
     if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
         return false;
 
     TemporaryTypeSet* types = obj->resultTypeSet();
@@ -5407,17 +5407,17 @@ jit::ArrayPrototypeHasIndexedProperty(Io
 bool
 jit::TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types)
 {
     const Class* clasp = types->getKnownClass(builder->constraints());
 
     // Note: typed arrays have indexed properties not accounted for by type
     // information, though these are all in bounds and will be accounted for
     // by JIT paths.
-    if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp)))
+    if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsTypedArrayClass(clasp)))
         return true;
 
     if (types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_SPARSE_INDEXES))
         return true;
 
     JSObject* proto;
     if (!types->getCommonPrototype(builder->constraints(), &proto))
         return true;
@@ -5592,17 +5592,17 @@ jit::PropertyWriteNeedsTypeBarrier(TempA
     bool success = true;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
         TypeSet::ObjectKey* key = types->getObject(i);
         if (!key || key->unknownProperties())
             continue;
 
         // TI doesn't track TypedArray indexes and should never insert a type
         // barrier for them.
-        if (!name && IsAnyTypedArrayClass(key->clasp()))
+        if (!name && IsTypedArrayClass(key->clasp()))
             continue;
 
         jsid id = name ? NameToId(name) : JSID_VOID;
         HeapTypeSetKey property = key->property(id);
         if (!CanWriteProperty(alloc, constraints, property, *pvalue, implicitType)) {
             // Either pobj or pvalue needs to be modified to filter out the
             // types which the value could have but are not in the property,
             // or a VM call is required. A VM call is always required if pobj
@@ -5642,17 +5642,17 @@ jit::PropertyWriteNeedsTypeBarrier(TempA
     if (types->getObjectCount() <= 1)
         return true;
 
     TypeSet::ObjectKey* excluded = nullptr;
     for (size_t i = 0; i < types->getObjectCount(); i++) {
         TypeSet::ObjectKey* key = types->getObject(i);
         if (!key || key->unknownProperties())
             continue;
-        if (!name && IsAnyTypedArrayClass(key->clasp()))
+        if (!name && IsTypedArrayClass(key->clasp()))
             continue;
 
         jsid id = name ? NameToId(name) : JSID_VOID;
         HeapTypeSetKey property = key->property(id);
         if (CanWriteProperty(alloc, constraints, property, *pvalue, implicitType))
             continue;
 
         if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9823,17 +9823,17 @@ class MLoadTypedArrayElementStatic
                                              MDefinition* ptr, int32_t offset = 0,
                                              bool needsBoundsCheck = true)
     {
         return new(alloc) MLoadTypedArrayElementStatic(someTypedArray, ptr, offset,
                                                        needsBoundsCheck);
     }
 
     Scalar::Type accessType() const {
-        return AnyTypedArrayType(someTypedArray_);
+        return someTypedArray_->as<TypedArrayObject>().type();
     }
     SharedMem<void*> base() const;
     size_t length() const;
 
     MDefinition* ptr() const { return getOperand(0); }
     int32_t offset() const { return offset_; }
     void setOffset(int32_t offset) { offset_ = offset; }
     bool congruentTo(const MDefinition* ins) const override;
@@ -10060,17 +10060,17 @@ class MStoreTypedArrayElementHole
 class MStoreTypedArrayElementStatic :
     public MBinaryInstruction,
     public StoreUnboxedScalarBase,
     public StoreTypedArrayElementStaticPolicy::Data
 {
     MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
                                   int32_t offset, bool needsBoundsCheck)
         : MBinaryInstruction(ptr, v),
-          StoreUnboxedScalarBase(AnyTypedArrayType(someTypedArray)),
+          StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
           someTypedArray_(someTypedArray),
           offset_(offset), needsBoundsCheck_(needsBoundsCheck)
     {}
 
     CompilerObject someTypedArray_;
 
     // An offset to be encoded in the store instruction - taking advantage of the
     // addressing modes. This is only non-zero when the access is proven to be
@@ -14136,19 +14136,19 @@ MControlInstruction* MDefinition::toCont
 }
 
 // Helper functions used to decide how to build MIR.
 
 bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
                                 MDefinition* obj, MDefinition* id);
 JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
                                     MDefinition* id);
-bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
-                                  MDefinition* obj, MDefinition* id,
-                                  Scalar::Type* arrayType);
+bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
+                               MDefinition* obj, MDefinition* id,
+                               Scalar::Type* arrayType);
 bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
 bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
 bool ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
 MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
 BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
                                          CompilerConstraintList* constraints,
                                          TypeSet::ObjectKey* key, PropertyName* name,
                                          TemporaryTypeSet* observed, bool updateObserved);
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1714,19 +1714,19 @@ MLoadUnboxedScalar::computeRange(TempAll
     setRange(GetTypedArrayRange(alloc, readType()));
 }
 
 void
 MLoadTypedArrayElementStatic::computeRange(TempAllocator& alloc)
 {
     // We don't currently use MLoadTypedArrayElementStatic for uint32, so we
     // don't have to worry about it returning a value outside our type.
-    MOZ_ASSERT(AnyTypedArrayType(someTypedArray_) != Scalar::Uint32);
-
-    setRange(GetTypedArrayRange(alloc, AnyTypedArrayType(someTypedArray_)));
+    MOZ_ASSERT(someTypedArray_->as<TypedArrayObject>().type() != Scalar::Uint32);
+
+    setRange(GetTypedArrayRange(alloc, someTypedArray_->as<TypedArrayObject>().type()));
 }
 
 void
 MArrayLength::computeRange(TempAllocator& alloc)
 {
     // Array lengths can go up to UINT32_MAX, but we only create MArrayLength
     // nodes when the value is known to be int32 (see the
     // OBJECT_FLAG_LENGTH_OVERFLOW flag).
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -2113,17 +2113,17 @@ enum TypedThingLayout {
     Layout_TypedArray,
     Layout_OutlineTypedObject,
     Layout_InlineTypedObject
 };
 
 static inline TypedThingLayout
 GetTypedThingLayout(const Class* clasp)
 {
-    if (IsAnyTypedArrayClass(clasp))
+    if (IsTypedArrayClass(clasp))
         return Layout_TypedArray;
     if (IsOutlineTypedObjectClass(clasp))
         return Layout_OutlineTypedObject;
     if (IsInlineTypedObjectClass(clasp))
         return Layout_InlineTypedObject;
     MOZ_CRASH("Bad object class");
 }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -816,17 +816,17 @@ array_addProperty(JSContext* cx, HandleO
     return true;
 }
 
 static inline bool
 ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
 {
     return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) ||
            obj->isIndexed() ||
-           IsAnyTypedArray(obj) ||
+           obj->is<TypedArrayObject>() ||
            ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
                              obj->getClass(), INT_TO_JSID(0), obj);
 }
 
 bool
 js::ObjectMayHaveExtraIndexedProperties(JSObject* obj)
 {
     /*
@@ -2774,18 +2774,18 @@ GetIndexedPropertiesInRange(JSContext* c
         for (uint32_t i = begin; i < initLen && i < end; i++) {
             if (nativeObj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE))
                 continue;
             if (!indexes.append(i))
                 return false;
         }
 
         // Append typed array elements.
-        if (IsAnyTypedArray(pobj)) {
-            uint32_t len = AnyTypedArrayLength(pobj);
+        if (pobj->is<TypedArrayObject>()) {
+            uint32_t len = pobj->as<TypedArrayObject>().length();
             for (uint32_t i = begin; i < len && i < end; i++) {
                 if (!indexes.append(i))
                     return false;
             }
         }
 
         // Append sparse elements.
         if (pobj->isIndexed()) {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -191,18 +191,18 @@ EnumerateNativeProperties(JSContext* cx,
             } else {
                 /* Dense arrays never get so large that i would not fit into an integer id. */
                 if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props))
                     return false;
             }
         }
 
         /* Collect any typed array or shared typed array elements from this object. */
-        if (IsAnyTypedArray(pobj)) {
-            size_t len = AnyTypedArrayLength(pobj);
+        if (pobj->is<TypedArrayObject>()) {
+            size_t len = pobj->as<TypedArrayObject>().length();
             for (size_t i = 0; i < len; i++) {
                 if (!Enumerate(cx, pobj, INT_TO_JSID(i), /* enumerable = */ true, flags, ht, props))
                     return false;
             }
         }
 
         // Collect any sparse elements from this object.
         bool isIndexed = pobj->isIndexed();
@@ -777,17 +777,17 @@ CanCompareIterableObjectToCache(JSObject
 }
 
 static inline bool
 CanCacheIterableObject(JSContext* cx, JSObject* obj)
 {
     if (!CanCompareIterableObjectToCache(obj))
         return false;
     if (obj->isNative()) {
-        if (IsAnyTypedArray(obj) ||
+        if (obj->is<TypedArrayObject>() ||
             obj->hasUncacheableProto() ||
             obj->getOps()->enumerate ||
             obj->getClass()->enumerate ||
             obj->as<NativeObject>().containsPure(cx->names().iteratorIntrinsic))
         {
             return false;
         }
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -483,17 +483,19 @@ js::SetIntegrityLevel(JSContext* cx, Han
     if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &keys))
         return false;
 
     // PreventExtensions must sparsify dense objects, so we can assign to holes
     // without checks.
     MOZ_ASSERT_IF(obj->isNative(), obj->as<NativeObject>().getDenseCapacity() == 0);
 
     // Steps 8-9, loosely interpreted.
-    if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() && !IsAnyTypedArray(obj)) {
+    if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() &&
+        !obj->is<TypedArrayObject>())
+    {
         HandleNativeObject nobj = obj.as<NativeObject>();
 
         // Seal/freeze non-dictionary objects by constructing a new shape
         // hierarchy mirroring the original one, which can be shared if many
         // objects with the same structure are sealed/frozen. If we use the
         // generic path below then any non-empty object will be converted to
         // dictionary mode.
         RootedShape last(cx, EmptyShape::getInitialShape(cx, nobj->getClass(),
@@ -2277,20 +2279,20 @@ js::LookupPropertyPure(ExclusiveContext*
             /* Search for a native dense element, typed array element, or property. */
 
             if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
                 *objp = obj;
                 MarkDenseOrTypedArrayElementFound<NoGC>(propp);
                 return true;
             }
 
-            if (IsAnyTypedArray(obj)) {
+            if (obj->is<TypedArrayObject>()) {
                 uint64_t index;
                 if (IsTypedArrayIndex(id, &index)) {
-                    if (index < AnyTypedArrayLength(obj)) {
+                    if (index < obj->as<TypedArrayObject>().length()) {
                         *objp = obj;
                         MarkDenseOrTypedArrayElementFound<NoGC>(propp);
                     } else {
                         *objp = nullptr;
                         *propp = nullptr;
                     }
                     return true;
                 }
@@ -2804,17 +2806,17 @@ js::UnwatchGuts(JSContext* cx, JS::Handl
 }
 
 bool
 js::WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
 {
     if (WatchOp op = obj->getOps()->watch)
         return op(cx, obj, id, callable);
 
-    if (!obj->isNative() || IsAnyTypedArray(obj)) {
+    if (!obj->isNative() || obj->is<TypedArrayObject>()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_WATCH,
                              obj->getClass()->name);
         return false;
     }
 
     return WatchGuts(cx, obj, id, callable);
 }
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -397,17 +397,17 @@ CallResolveOp(JSContext* cx, HandleNativ
     MOZ_ASSERT_IF(obj->getClass()->mayResolve,
                   obj->getClass()->mayResolve(cx->names(), id, obj));
 
     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
         MarkDenseOrTypedArrayElementFound<CanGC>(propp);
         return true;
     }
 
-    MOZ_ASSERT(!IsAnyTypedArray(obj));
+    MOZ_ASSERT(!obj->is<TypedArrayObject>());
 
     propp.set(obj->lookup(cx, id));
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
 {
@@ -443,20 +443,20 @@ LookupOwnPropertyInline(ExclusiveContext
         MarkDenseOrTypedArrayElementFound<allowGC>(propp);
         *donep = true;
         return true;
     }
 
     // Check for a typed array element. Integer lookups always finish here
     // so that integer properties on the prototype are ignored even for out
     // of bounds accesses.
-    if (IsAnyTypedArray(obj)) {
+    if (obj->template is<TypedArrayObject>()) {
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
-            if (index < AnyTypedArrayLength(obj)) {
+            if (index < obj->template as<TypedArrayObject>().length()) {
                 MarkDenseOrTypedArrayElementFound<allowGC>(propp);
             } else {
                 propp.set(nullptr);
             }
             *donep = true;
             return true;
         }
     }
@@ -511,20 +511,20 @@ NativeLookupOwnPropertyNoResolve(Exclusi
 {
     // Check for a native dense element.
     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
         MarkDenseOrTypedArrayElementFound<CanGC>(result);
         return;
     }
 
     // Check for a typed array element.
-    if (IsAnyTypedArray(obj)) {
+    if (obj->is<TypedArrayObject>()) {
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
-            if (index < AnyTypedArrayLength(obj))
+            if (index < obj->as<TypedArrayObject>().length())
                 MarkDenseOrTypedArrayElementFound<CanGC>(result);
             else
                 result.set(nullptr);
             return;
         }
     }
 
     // Check for a native property.
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -44,17 +44,17 @@ HeapSlot* const js::emptyObjectElementsS
     reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
 
 
 #ifdef DEBUG
 
 bool
 NativeObject::canHaveNonEmptyElements()
 {
-    return !IsAnyTypedArray(this);
+    return !this->is<TypedArrayObject>();
 }
 
 #endif // DEBUG
 
 /* static */ bool
 ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr)
 {
     /*
@@ -1142,17 +1142,17 @@ AddOrChangeProperty(ExclusiveContext* cx
         return false;
 
     // Use dense storage for new indexed properties where possible.
     if (JSID_IS_INT(id) &&
         !desc.getter() &&
         !desc.setter() &&
         desc.attributes() == JSPROP_ENUMERATE &&
         (!obj->isIndexed() || !obj->containsPure(id)) &&
-        !IsAnyTypedArray(obj))
+        !obj->is<TypedArrayObject>())
     {
         uint32_t index = JSID_TO_INT(id);
         DenseElementResult edResult = obj->ensureDenseElements(cx, index, 1);
         if (edResult == DenseElementResult::Failure)
             return false;
         if (edResult == DenseElementResult::Success) {
             obj->setDenseElementWithType(cx, index, desc.value());
             if (!CallAddPropertyHookDense(cx, obj, index, desc.value()))
@@ -1322,17 +1322,17 @@ js::NativeDefineProperty(ExclusiveContex
         }
 
         // 9.4.2.1 step 3. Don't extend a fixed-length array.
         uint32_t index;
         if (IdIsIndex(id, &index)) {
             if (WouldDefinePastNonwritableLength(obj, index))
                 return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
         }
-    } else if (IsAnyTypedArray(obj)) {
+    } else if (obj->is<TypedArrayObject>()) {
         // 9.4.5.3 step 3. Indexed properties of typed arrays are special.
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
             if (!cx->shouldBeJSContext())
                 return false;
             return DefineTypedArrayElement(cx->asJSContext(), obj, index, desc_, result);
         }
     } else if (obj->is<ArgumentsObject>()) {
@@ -1453,33 +1453,33 @@ js::NativeDefineProperty(ExclusiveContex
             desc.setSetterObject(shape->setterObject());
         }
     } else if (desc.isDataDescriptor() != IsDataDescriptor(shapeAttrs)) {
         // Step 7.
         if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks)
             return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
         if (IsImplicitDenseOrTypedArrayElement(shape)) {
-            MOZ_ASSERT(!IsAnyTypedArray(obj));
+            MOZ_ASSERT(!obj->is<TypedArrayObject>());
             if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
                 return false;
             shape = obj->lookup(cx, id);
         }
 
         // Fill in desc fields with default values (steps 7.b.i and 7.c.i).
         CompletePropertyDescriptor(&desc);
     } else if (desc.isDataDescriptor()) {
         // Step 8.
         bool frozen = !IsConfigurable(shapeAttrs) && !IsWritable(shapeAttrs);
         if (frozen && desc.hasWritable() && desc.writable() && !skipRedefineChecks)
             return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
         if (frozen || !desc.hasValue()) {
             if (IsImplicitDenseOrTypedArrayElement(shape)) {
-                MOZ_ASSERT(!IsAnyTypedArray(obj));
+                MOZ_ASSERT(!obj->is<TypedArrayObject>());
                 if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
                     return false;
                 shape = obj->lookup(cx, id);
             }
 
             RootedValue currentValue(cx);
             if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
                 return false;
@@ -2188,29 +2188,27 @@ SetNonexistentProperty(JSContext* cx, Ha
 /*
  * Set an existing own property obj[index] that's a dense element or typed
  * array element.
  */
 static bool
 SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
                             ObjectOpResult& result)
 {
-    if (IsAnyTypedArray(obj)) {
+    if (obj->is<TypedArrayObject>()) {
         double d;
         if (!ToNumber(cx, v, &d))
             return false;
 
         // Silently do nothing for out-of-bounds sets, for consistency with
         // current behavior.  (ES6 currently says to throw for this in
         // strict mode code, so we may eventually need to change.)
-        uint32_t len = AnyTypedArrayLength(obj);
-        if (index < len) {
-            if (obj->is<TypedArrayObject>())
-                TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
-        }
+        uint32_t len = obj->as<TypedArrayObject>().length();
+        if (index < len)
+            TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
         return result.succeed();
     }
 
     if (WouldDefinePastNonwritableLength(obj, index))
         return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 
     if (!obj->maybeCopyElementsForWrite(cx))
         return false;
@@ -2400,17 +2398,17 @@ js::NativeDeleteProperty(JSContext* cx, 
     if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, result))
         return false;
     if (!result)
         return true;
 
     // Step 5.
     if (IsImplicitDenseOrTypedArrayElement(shape)) {
         // Typed array elements are non-configurable.
-        MOZ_ASSERT(!IsAnyTypedArray(obj));
+        MOZ_ASSERT(!obj->is<TypedArrayObject>());
 
         if (!obj->maybeCopyElementsForWrite(cx))
             return false;
 
         obj->setDenseElementHole(cx, JSID_TO_INT(id));
     } else {
         if (!obj->removeProperty(cx, id))
             return false;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1100,17 +1100,17 @@ CopyToDisjointArray(TypedArrayObject* ta
       }
 
       case Scalar::Uint8Clamped: {
         DisjointElements::copy(dest.cast<uint8_clamped*>(), src, srcType, count);
         break;
       }
 
       default:
-        MOZ_CRASH("setFromAnyTypedArray with a typed array with bogus type");
+        MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
     }
 }
 
 // |unsafeSrcCrossCompartment| is produced by |DangerouslyUnwrapTypedArray|,
 // counseling extreme caution when using it.  As directed by
 // |DangerouslyUnwrapTypedArray|, sigil this pointer and all variables derived
 // from it to counsel extreme caution here.
 void
@@ -1311,17 +1311,17 @@ intrinsic_IsConstructing(JSContext* cx, 
 }
 
 static bool
 intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
-    MOZ_ASSERT(IsAnyTypedArray(&args[0].toObject()));
+    MOZ_ASSERT(args[0].toObject().is<TypedArrayObject>());
 
     RootedObject object(cx, &args[0].toObject());
     JSProtoKey protoKey = StandardProtoKeyOrNull(object);
     MOZ_ASSERT(protoKey);
 
     // While it may seem like an invariant that in any compartment,
     // seeing a typed array object implies that the TypedArray constructor
     // for that type is initialized on the compartment's global, this is not
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -161,17 +161,17 @@ AutoRooterGetterSetter::AutoRooterGetter
 }
 
 static inline uint8_t
 GetShapeAttributes(JSObject* obj, Shape* shape)
 {
     MOZ_ASSERT(obj->isNative());
 
     if (IsImplicitDenseOrTypedArrayElement(shape)) {
-        if (IsAnyTypedArray(obj))
+        if (obj->is<TypedArrayObject>())
             return JSPROP_ENUMERATE | JSPROP_PERMANENT;
         return JSPROP_ENUMERATE;
     }
 
     return shape->attributes();
 }
 
 } /* namespace js */
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2461,17 +2461,17 @@ TemporaryTypeSet::propertyNeedsBarrier(C
 bool
 js::ClassCanHaveExtraProperties(const Class* clasp)
 {
     if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
         return false;
     return clasp->resolve
         || clasp->ops.lookupProperty
         || clasp->ops.getProperty
-        || IsAnyTypedArrayClass(clasp);
+        || IsTypedArrayClass(clasp);
 }
 
 void
 TypeZone::processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles)
 {
     MOZ_ASSERT(!recompiles.empty());
 
     /*
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -64,70 +64,16 @@ template<> struct TypeIDOfType<uint8_t> 
 template<> struct TypeIDOfType<int16_t> { static const Scalar::Type id = Scalar::Int16; };
 template<> struct TypeIDOfType<uint16_t> { static const Scalar::Type id = Scalar::Uint16; };
 template<> struct TypeIDOfType<int32_t> { static const Scalar::Type id = Scalar::Int32; };
 template<> struct TypeIDOfType<uint32_t> { static const Scalar::Type id = Scalar::Uint32; };
 template<> struct TypeIDOfType<float> { static const Scalar::Type id = Scalar::Float32; };
 template<> struct TypeIDOfType<double> { static const Scalar::Type id = Scalar::Float64; };
 template<> struct TypeIDOfType<uint8_clamped> { static const Scalar::Type id = Scalar::Uint8Clamped; };
 
-inline bool
-IsAnyTypedArray(JSObject* obj)
-{
-    return obj->is<TypedArrayObject>();
-}
-
-inline uint32_t
-AnyTypedArrayLength(JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().length();
-}
-
-inline Scalar::Type
-AnyTypedArrayType(JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().type();
-}
-
-inline Shape*
-AnyTypedArrayShape(JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().lastProperty();
-}
-
-inline SharedMem<void*>
-AnyTypedArrayViewData(const JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().viewDataEither();
-}
-
-inline uint32_t
-AnyTypedArrayBytesPerElement(const JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().bytesPerElement();
-}
-
-inline uint32_t
-AnyTypedArrayByteLength(const JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().byteLength();
-}
-
-inline bool
-AnyTypedArrayIsDetached(const JSObject* obj)
-{
-    return obj->as<TypedArrayObject>().isNeutered();
-}
-
-inline bool
-IsAnyTypedArrayClass(const Class* clasp)
-{
-    return IsTypedArrayClass(clasp);
-}
-
 class SharedOps
 {
   public:
     template<typename T>
     static T load(SharedMem<T*> addr) {
         return js::jit::AtomicOperations::loadSafeWhenRacy(addr);
     }
 
@@ -207,49 +153,51 @@ class ElementSpecific
 
   public:
     /*
      * Copy |source|'s elements into |target|, starting at |target[offset]|.
      * Act as if the assignments occurred from a fresh copy of |source|, in
      * case the two memory ranges overlap.
      */
     static bool
-    setFromAnyTypedArray(JSContext* cx,
-                         Handle<SomeTypedArray*> target, HandleObject source,
-                         uint32_t offset)
+    setFromTypedArray(JSContext* cx,
+                      Handle<SomeTypedArray*> target, HandleObject source,
+                      uint32_t offset)
     {
         MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
-                   "calling wrong setFromAnyTypedArray specialization");
+                   "calling wrong setFromTypedArray specialization");
 
         MOZ_ASSERT(offset <= target->length());
-        MOZ_ASSERT(AnyTypedArrayLength(source) <= target->length() - offset);
+        MOZ_ASSERT(source->as<TypedArrayObject>().length() <= target->length() - offset);
 
         if (source->is<SomeTypedArray>()) {
             Rooted<SomeTypedArray*> src(cx, source.as<SomeTypedArray>());
             if (SomeTypedArray::sameBuffer(target, src))
                 return setFromOverlappingTypedArray(cx, target, src, offset);
         }
 
-        SharedMem<T*> dest = AnyTypedArrayViewData(target).template cast<T*>() + offset;
-        uint32_t count = AnyTypedArrayLength(source);
+        SharedMem<T*> dest =
+            target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
+        uint32_t count = source->as<TypedArrayObject>().length();
 
-        if (AnyTypedArrayType(source) == target->type()) {
-            Ops::podCopy(dest, AnyTypedArrayViewData(source).template cast<T*>(), count);
+        if (source->as<TypedArrayObject>().type() == target->type()) {
+            Ops::podCopy(dest, source->as<TypedArrayObject>().viewDataEither().template cast<T*>(),
+                         count);
             return true;
         }
 
         // Inhibit unaligned accesses on ARM (bug 1097253, a compiler bug).
 #ifdef __arm__
 #  define JS_VOLATILE_ARM volatile
 #else
 #  define JS_VOLATILE_ARM
 #endif
 
         SharedMem<void*> data = Ops::extract(source.as<TypedArrayObject>());
-        switch (AnyTypedArrayType(source)) {
+        switch (source->as<TypedArrayObject>().type()) {
           case Scalar::Int8: {
             SharedMem<JS_VOLATILE_ARM int8_t*> src = data.cast<JS_VOLATILE_ARM int8_t*>();
             for (uint32_t i = 0; i < count; ++i)
                 Ops::store(dest++, T(Ops::load(src++)));
             break;
           }
           case Scalar::Uint8:
           case Scalar::Uint8Clamped: {
@@ -290,17 +238,17 @@ class ElementSpecific
           }
           case Scalar::Float64: {
             SharedMem<JS_VOLATILE_ARM double*> src = data.cast<JS_VOLATILE_ARM double*>();
             for (uint32_t i = 0; i < count; ++i)
                 Ops::store(dest++, T(Ops::load(src++)));
             break;
           }
           default:
-            MOZ_CRASH("setFromAnyTypedArray with a typed array with bogus type");
+            MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
         }
 
 #undef JS_VOLATILE_ARM
 
         return true;
     }
 
     /*
@@ -309,26 +257,27 @@ class ElementSpecific
      * typed array.
      */
     static bool
     setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
                          uint32_t len, uint32_t offset = 0)
     {
         MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
                    "target type and NativeType must match");
-        MOZ_ASSERT(!IsAnyTypedArray(source),
-                   "use setFromAnyTypedArray instead of this method");
+        MOZ_ASSERT(!source->is<TypedArrayObject>(),
+                   "use setFromTypedArray instead of this method");
 
         uint32_t i = 0;
         if (source->isNative()) {
             // Attempt fast-path infallible conversion of dense elements up to
             // the first potentially side-effectful lookup or conversion.
             uint32_t bound = Min(source->as<NativeObject>().getDenseInitializedLength(), len);
 
-            SharedMem<T*> dest = AnyTypedArrayViewData(target).template cast<T*>() + offset;
+            SharedMem<T*> dest =
+                target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
 
             MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE)),
                        "the following loop must abort on holes");
 
             const Value* srcValues = source->as<NativeObject>().getDenseElements();
             for (; i < bound; i++) {
                 if (!canConvertInfallibly(srcValues[i]))
                     break;
@@ -348,17 +297,20 @@ class ElementSpecific
             if (!valueToNative(cx, v, &n))
                 return false;
 
             len = Min(len, target->length());
             if (i >= len)
                 break;
 
             // Compute every iteration in case getElement/valueToNative is wacky.
-            Ops::store(AnyTypedArrayViewData(target).template cast<T*>() + offset + i, n);
+            SharedMem<T*> dest =
+                target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() +
+                offset + i;
+            Ops::store(dest, n);
         }
 
         return true;
     }
 
   private:
     static bool
     setFromOverlappingTypedArray(JSContext* cx,
@@ -370,31 +322,34 @@ class ElementSpecific
                    "calling wrong setFromTypedArray specialization");
         MOZ_ASSERT(SomeTypedArray::sameBuffer(target, source),
                    "the provided arrays don't actually overlap, so it's "
                    "undesirable to use this method");
 
         MOZ_ASSERT(offset <= target->length());
         MOZ_ASSERT(source->length() <= target->length() - offset);
 
-        SharedMem<T*> dest = AnyTypedArrayViewData(target).template cast<T*>() + offset;
+        SharedMem<T*> dest =
+            target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
         uint32_t len = source->length();
 
         if (source->type() == target->type()) {
-            Ops::podMove(dest, AnyTypedArrayViewData(source).template cast<T*>(), len);
+            SharedMem<T*> src =
+                source->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
+            Ops::podMove(dest, src, len);
             return true;
         }
 
         // Copy |source| in case it overlaps the target elements being set.
         size_t sourceByteLen = len * source->bytesPerElement();
         void* data = target->zone()->template pod_malloc<uint8_t>(sourceByteLen);
         if (!data)
             return false;
         Ops::memcpy(SharedMem<void*>::unshared(data),
-                    AnyTypedArrayViewData(source),
+                    source->template as<TypedArrayObject>().viewDataEither(),
                     sourceByteLen);
 
         switch (source->type()) {
           case Scalar::Int8: {
             int8_t* src = static_cast<int8_t*>(data);
             for (uint32_t i = 0; i < len; ++i)
                 Ops::store(dest++, T(*src++));
             break;
@@ -706,17 +661,18 @@ class TypedArrayMethods
         uint32_t viewByteLength = obj->byteLength();
         MOZ_ASSERT(byteSize <= viewByteLength);
         MOZ_ASSERT(byteDest <= viewByteLength);
         MOZ_ASSERT(byteSrc <= viewByteLength);
         MOZ_ASSERT(byteDest <= viewByteLength - byteSize);
         MOZ_ASSERT(byteSrc <= viewByteLength - byteSize);
 #endif
 
-        SharedMem<uint8_t*> data = AnyTypedArrayViewData(obj).template cast<uint8_t*>();
+        SharedMem<uint8_t*> data =
+            obj->template as<TypedArrayObject>().viewDataEither().template cast<uint8_t*>();
         SharedOps::memmove(data + byteDest, data + byteSrc, byteSize);
 
         // Step 19.
         args.rval().set(args.thisv());
         return true;
     }
 
     /* set(array[, offset]) */
@@ -741,23 +697,23 @@ class TypedArrayMethods
             if (offset < 0 || uint32_t(offset) > target->length()) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
                 return false;
             }
         }
 
         RootedObject arg0(cx, &args[0].toObject());
-        if (IsAnyTypedArray(arg0)) {
-            if (AnyTypedArrayLength(arg0) > target->length() - offset) {
+        if (arg0->is<TypedArrayObject>()) {
+            if (arg0->as<TypedArrayObject>().length() > target->length() - offset) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
 
-            if (!setFromAnyTypedArray(cx, target, arg0, offset))
+            if (!setFromTypedArray(cx, target, arg0, offset))
                 return false;
         } else {
             uint32_t len;
             if (!GetLengthProperty(cx, arg0, &len))
                 return false;
 
             if (uint32_t(offset) > target->length() || len > target->length() - offset) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
@@ -774,82 +730,82 @@ class TypedArrayMethods
 
     static bool
     setFromArrayLike(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source, uint32_t len,
                      uint32_t offset = 0)
     {
         MOZ_ASSERT(offset <= target->length());
         MOZ_ASSERT(len <= target->length() - offset);
 
-        if (IsAnyTypedArray(source))
-            return setFromAnyTypedArray(cx, target, source, offset);
+        if (source->is<TypedArrayObject>())
+            return setFromTypedArray(cx, target, source, offset);
 
         return setFromNonTypedArray(cx, target, source, len, offset);
     }
 
   private:
      static bool
-     setFromAnyTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
-                          uint32_t offset)
+     setFromTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
+                       uint32_t offset)
      {
-         MOZ_ASSERT(IsAnyTypedArray(source), "use setFromNonTypedArray");
+         MOZ_ASSERT(source->is<TypedArrayObject>(), "use setFromNonTypedArray");
 
          bool isShared = target->isSharedMemory() || source->as<TypedArrayObject>().isSharedMemory();
 
          switch (target->type()) {
            case Scalar::Int8:
              if (isShared)
-                 return ElementSpecific<Int8ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Int8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Uint8:
              if (isShared)
-                 return ElementSpecific<Uint8ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Uint8ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Uint8ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Int16:
              if (isShared)
-                 return ElementSpecific<Int16ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Int16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Int16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Uint16:
              if (isShared)
-                 return ElementSpecific<Uint16ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Uint16ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Uint16ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Int32:
              if (isShared)
-                 return ElementSpecific<Int32ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Int32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Int32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Uint32:
              if (isShared)
-                 return ElementSpecific<Uint32ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Uint32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Float32:
              if (isShared)
-                 return ElementSpecific<Float32ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Float32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Float32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Float64:
              if (isShared)
-                 return ElementSpecific<Float64ArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Float64ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Float64ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Uint8Clamped:
              if (isShared)
-                 return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromAnyTypedArray(cx, target, source, offset);
-             return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromAnyTypedArray(cx, target, source, offset);
+                 return ElementSpecific<Uint8ClampedArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+             return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
            case Scalar::Float32x4:
            case Scalar::Int32x4:
            case Scalar::MaxTypedArrayViewType:
              break;
          }
 
          MOZ_CRASH("nonsense target element type");
      }
 
     static bool
     setFromNonTypedArray(JSContext* cx, Handle<SomeTypedArray*> target, HandleObject source,
                          uint32_t len, uint32_t offset)
     {
-        MOZ_ASSERT(!IsAnyTypedArray(source), "use setFromAnyTypedArray");
+        MOZ_ASSERT(!source->is<TypedArrayObject>(), "use setFromTypedArray");
 
         bool isShared = target->isSharedMemory();
 
         switch (target->type()) {
           case Scalar::Int8:
             if (isShared)
                 return ElementSpecific<Int8ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
             return ElementSpecific<Int8ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -717,25 +717,25 @@ template<typename T>
 TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
                                        HandleObject newTarget /* = nullptr */)
 {
     // Allow nullptr newTarget for FriendAPI methods, which don't care about
     // subclassing.
     RootedObject proto(cx);
 
     uint32_t len;
-    if (IsAnyTypedArray(other)) {
+    if (other->is<TypedArrayObject>()) {
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
             return nullptr;
 
-        if (AnyTypedArrayIsDetached(other)) {
+        if (other->as<TypedArrayObject>().isNeutered()) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
             return nullptr;
         }
-        len = AnyTypedArrayLength(other);
+        len = other->as<TypedArrayObject>().length();
     } else {
         if (!GetLengthProperty(cx, other, &len))
             return nullptr;
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
             return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx);
@@ -2261,22 +2261,22 @@ js::StringIsTypedArrayIndex(const char16
 template bool
 js::StringIsTypedArrayIndex(const Latin1Char* s, size_t length, uint64_t* indexp);
 
 /* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */
 bool
 js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
                             Handle<PropertyDescriptor> desc, ObjectOpResult& result)
 {
-    MOZ_ASSERT(IsAnyTypedArray(obj));
+    MOZ_ASSERT(obj->is<TypedArrayObject>());
 
     // These are all substeps of 3.c.
     // Steps i-vi.
     // We (wrongly) ignore out of range defines with a value.
-    if (index >= AnyTypedArrayLength(obj))
+    if (index >= obj->as<TypedArrayObject>().length())
         return result.succeed();
 
     // Step vii.
     if (desc.isAccessorDescriptor())
         return result.fail(JSMSG_CANT_REDEFINE_PROP);
 
     // Step viii.
     if (desc.hasConfigurable() && desc.configurable())