Bug 1114580 - Change ESClassValue to an enum class. r=jorendorff
authorTom Schuster <evilpies@gmail.com>
Thu, 30 Jun 2016 00:04:56 +0200
changeset 303143 dc3e76c6750c8b67896d3d27740a13615e55f438
parent 303142 d806fac2c856f7c7f08049eb0eefbabba7283939
child 303144 119a365358d598305fba487f5eacd4945a458c3f
push id78990
push userevilpies@gmail.com
push dateWed, 29 Jun 2016 22:05:10 +0000
treeherdermozilla-inbound@dc3e76c6750c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1114580
milestone50.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 1114580 - Change ESClassValue to an enum class. r=jorendorff
dom/bindings/BindingUtils.h
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/Key.cpp
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperOwner.cpp
js/ipc/WrapperOwner.h
js/public/Class.h
js/public/Proxy.h
js/src/builtin/RegExp.cpp
js/src/ctypes/CTypes.cpp
js/src/jsapi-tests/testIteratorObject.cpp
js/src/jsapi.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jswrapper.h
js/src/proxy/BaseProxyHandler.cpp
js/src/proxy/DeadObjectProxy.cpp
js/src/proxy/DeadObjectProxy.h
js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
js/src/proxy/Proxy.cpp
js/src/proxy/Proxy.h
js/src/proxy/ScriptedProxyHandler.cpp
js/src/proxy/ScriptedProxyHandler.h
js/src/proxy/SecurityWrapper.cpp
js/src/proxy/Wrapper.cpp
js/src/vm/RegExpObject.h
js/src/vm/StructuredClone.cpp
js/src/vm/TypedArrayObject.cpp
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -236,22 +236,22 @@ UnwrapObject(JSObject* obj, U& value)
 }
 
 inline bool
 IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj,
                   bool* notDateOrRegExp)
 {
   MOZ_ASSERT(obj);
 
-  js::ESClassValue cls;
+  js::ESClass cls;
   if (!js::GetBuiltinClass(cx, obj, &cls)) {
     return false;
   }
 
-  *notDateOrRegExp = cls != js::ESClass_Date && cls != js::ESClass_RegExp;
+  *notDateOrRegExp = cls != js::ESClass::Date && cls != js::ESClass::RegExp;
   return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 IsObjectValueConvertibleToDictionary(JSContext* cx,
                                      JS::Handle<JS::Value> objVal,
                                      bool* convertible)
 {
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -106,21 +106,21 @@ IDBKeyRange::FromJSVal(JSContext* aCx,
     // undefined and null returns no IDBKeyRange.
     keyRange.forget(aKeyRange);
     return NS_OK;
   }
 
   JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
   bool isValidKey = aVal.isPrimitive();
   if (!isValidKey) {
-    js::ESClassValue cls;
+    js::ESClass cls;
     if (!js::GetBuiltinClass(aCx, obj, &cls)) {
       return NS_ERROR_UNEXPECTED;
     }
-    isValidKey = cls == js::ESClass_Array || cls == js::ESClass_Date;
+    isValidKey = cls == js::ESClass::Array || cls == js::ESClass::Date;
   }
   if (isValidKey) {
     // A valid key returns an 'only' IDBKeyRange.
     keyRange = new IDBKeyRange(nullptr, false, false, true);
 
     nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
     if (NS_FAILED(rv)) {
       return rv;
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -227,22 +227,22 @@ Key::EncodeJSValInternal(JSContext* aCx,
     }
     EncodeNumber(d, eFloat + aTypeOffset);
     return NS_OK;
   }
 
   if (aVal.isObject()) {
     JS::Rooted<JSObject*> obj(aCx, &aVal.toObject());
 
-    js::ESClassValue cls;
+    js::ESClass cls;
     if (!js::GetBuiltinClass(aCx, obj, &cls)) {
       IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
-    if (cls == js::ESClass_Array) {
+    if (cls == js::ESClass::Array) {
       aTypeOffset += eMaxType;
 
       if (aTypeOffset == eMaxType * kMaxArrayCollapse) {
         mBuffer.Append(aTypeOffset);
         aTypeOffset = 0;
       }
       NS_ASSERTION((aTypeOffset % eMaxType) == 0 &&
                    aTypeOffset < (eMaxType * kMaxArrayCollapse),
@@ -270,17 +270,17 @@ Key::EncodeJSValInternal(JSContext* aCx,
         aTypeOffset = 0;
       }
 
       mBuffer.Append(eTerminator + aTypeOffset);
 
       return NS_OK;
     }
 
-    if (cls == js::ESClass_Date) {
+    if (cls == js::ESClass::Date) {
       bool valid;
       if (!js::DateIsValid(aCx, obj, &valid)) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
       if (!valid)  {
         return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
       }
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -485,34 +485,34 @@ WrapperAnswer::RecvHasInstance(const Obj
 
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
                                    uint32_t* classValue)
 {
-    *classValue = js::ESClass_Other;
+    *classValue = uint32_t(js::ESClass::Other);
 
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
     JSContext* cx = jsapi.cx();
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(jsapi, rs);
 
     LOG("%s.getBuiltinClass()", ReceiverObj(objId));
 
-    js::ESClassValue cls;
+    js::ESClass cls;
     if (!js::GetBuiltinClass(cx, obj, &cls))
         return fail(jsapi, rs);
 
-    *classValue = cls;
+    *classValue = uint32_t(cls);
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvIsArray(const ObjectId& objId, ReturnStatus* rs,
                            uint32_t* ans)
 {
     *ans = uint32_t(IsArrayAnswer::NotArray);
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -121,18 +121,17 @@ class CPOWProxyHandler : public BaseProx
 
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                        MutableHandle<PropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                               AutoIdVector& props) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy,
                              MutableHandleValue v, bool* bp) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject obj,
-                                 js::ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject obj, js::ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject obj,
                          IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const override;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const override;
     virtual bool isCallable(JSObject* obj) const override;
     virtual bool isConstructor(JSObject* obj) const override;
@@ -724,33 +723,31 @@ WrapperOwner::hasInstance(JSContext* cx,
         return ipcfail(cx);
 
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
-CPOWProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                  js::ESClassValue* classValue) const
+CPOWProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
-    FORWARD(getBuiltinClass, (cx, proxy, classValue));
+    FORWARD(getBuiltinClass, (cx, proxy, cls));
 }
 
 bool
-WrapperOwner::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                              js::ESClassValue* classValue)
+WrapperOwner::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
 {
     ObjectId objId = idOf(proxy);
 
-    uint32_t cls = ESClass_Other;
+    uint32_t classValue = uint32_t(ESClass::Other);
     ReturnStatus status;
-    if (!SendGetBuiltinClass(objId, &status, &cls))
+    if (!SendGetBuiltinClass(objId, &status, &classValue))
         return ipcfail(cx);
-    *classValue = ESClassValue(cls);
+    *cls = ESClass(classValue);
 
     LOG_STACK();
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::isArray(JSContext* cx, HandleObject proxy,
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -49,17 +49,17 @@ class WrapperOwner : public virtual Java
 
     // SpiderMonkey extensions.
     bool getPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
                                JS::MutableHandle<JS::PropertyDescriptor> desc);
     bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
     bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::HandleObject proxy,
                                       JS::AutoIdVector& props);
     bool hasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp);
-    bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClassValue* classValue);
+    bool getBuiltinClass(JSContext* cx, JS::HandleObject proxy, js::ESClass* cls);
     bool isArray(JSContext* cx, JS::HandleObject proxy, JS::IsArrayAnswer* answer);
     const char* className(JSContext* cx, JS::HandleObject proxy);
     bool getPrototype(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleObject protop);
     bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary,
                                 JS::MutableHandleObject protop);
 
     bool regexp_toShared(JSContext* cx, JS::HandleObject proxy, js::RegExpGuard* g);
 
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -953,24 +953,36 @@ Valueify(const JSClass* c)
 {
     return (const Class*)c;
 }
 
 /**
  * Enumeration describing possible values of the [[Class]] internal property
  * value of objects.
  */
-enum ESClassValue {
-    ESClass_Object, ESClass_Array, ESClass_Number, ESClass_String,
-    ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_SharedArrayBuffer,
-    ESClass_Date, ESClass_Set, ESClass_Map, ESClass_Promise, ESClass_MapIterator,
-    ESClass_SetIterator,
+enum class ESClass {
+    Object,
+    Array,
+    Number,
+    String,
+    Boolean,
+    RegExp,
+    ArrayBuffer,
+    SharedArrayBuffer,
+    Date,
+    Set,
+    Map,
+    Promise,
+    MapIterator,
+    SetIterator,
+    Arguments,
+    Error,
 
     /** None of the above. */
-    ESClass_Other
+    Other
 };
 
 /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */
 bool
 Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp);
 
 #ifdef DEBUG
 JS_FRIEND_API(bool)
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -311,17 +311,17 @@ class JS_FRIEND_API(BaseProxyHandler)
                                        MutableHandle<PropertyDescriptor> desc) const;
     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const;
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                               AutoIdVector& props) const;
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const;
     virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const;
+                                 ESClass* cls) const;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const;
     virtual const char* className(JSContext* cx, HandleObject proxy) const;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const;
     virtual void trace(JSTracer* trc, JSObject* proxy) const;
     virtual void finalize(JSFreeOp* fop, JSObject* proxy) const;
     virtual void objectMoved(JSObject* proxy, const JSObject* old) const;
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -285,38 +285,38 @@ js::IsRegExp(JSContext* cx, HandleValue 
 
     /* Step 4. */
     if (!isRegExp.isUndefined()) {
         *result = ToBoolean(isRegExp);
         return true;
     }
 
     /* Steps 5-6. */
-    ESClassValue cls;
+    ESClass cls;
     if (!GetClassOfValue(cx, value, &cls))
         return false;
 
-    *result = cls == ESClass_RegExp;
+    *result = cls == ESClass::RegExp;
     return true;
 }
 
 /* ES6 B.2.5.1. */
 MOZ_ALWAYS_INLINE bool
 regexp_compile_impl(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
 
     Rooted<RegExpObject*> regexp(cx, &args.thisv().toObject().as<RegExpObject>());
 
     // Step 3.
     RootedValue patternValue(cx, args.get(0));
-    ESClassValue cls;
+    ESClass cls;
     if (!GetClassOfValue(cx, patternValue, &cls))
         return false;
-    if (cls == ESClass_RegExp) {
+    if (cls == ESClass::RegExp) {
         // Step 3a.
         if (args.hasDefined(1)) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NEWREGEXP_FLAGGED);
             return false;
         }
 
         // Beware!  |patternObj| might be a proxy into another compartment, so
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
@@ -400,20 +400,20 @@ js::regexp_construct(JSContext* cx, unsi
                 return true;
             }
         }
     }
 
     RootedValue patternValue(cx, args.get(0));
 
     // Step 4.
-    ESClassValue cls;
+    ESClass cls;
     if (!GetClassOfValue(cx, patternValue, &cls))
         return false;
-    if (cls == ESClass_RegExp) {
+    if (cls == ESClass::RegExp) {
         // Beware!  |patternObj| might be a proxy into another compartment, so
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -3644,21 +3644,21 @@ ImplicitConvert(JSContext* cx,
 
         break;
       }
       default:
         return ConvError(cx, targetType, val, convType, funObj, argIndex,
                          arrObj, arrIndex);
       }
     } else {
-      ESClassValue cls;
+      ESClass cls;
       if (!GetClassOfValue(cx, val, &cls))
         return false;
 
-      if (cls == ESClass_Array) {
+      if (cls == ESClass::Array) {
         // Convert each element of the array by calling ImplicitConvert.
         uint32_t sourceLength;
         if (!JS_GetArrayLength(cx, valObj, &sourceLength) ||
             targetLength != size_t(sourceLength)) {
           MOZ_ASSERT(!funObj);
           return ArrayLengthMismatch(cx, targetLength, targetType,
                                      size_t(sourceLength), val, convType);
         }
@@ -3679,20 +3679,20 @@ ImplicitConvert(JSContext* cx,
 
           char* data = intermediate.get() + elementSize * i;
           if (!ImplicitConvert(cx, item, baseType, data, convType, nullptr,
                                funObj, argIndex, targetType, i))
             return false;
         }
 
         memcpy(buffer, intermediate.get(), arraySize);
-      } else if (cls == ESClass_ArrayBuffer || cls == ESClass_SharedArrayBuffer) {
+      } else if (cls == ESClass::ArrayBuffer || cls == ESClass::SharedArrayBuffer) {
         // Check that array is consistent with type, then
         // copy the array.
-        const bool bufferShared = cls == ESClass_SharedArrayBuffer;
+        const bool bufferShared = cls == ESClass::SharedArrayBuffer;
         uint32_t sourceLength = bufferShared ? JS_GetSharedArrayBufferByteLength(valObj)
             : JS_GetArrayBufferByteLength(valObj);
         size_t elementSize = CType::GetSize(baseType);
         size_t arraySize = elementSize * targetLength;
         if (arraySize != size_t(sourceLength)) {
           MOZ_ASSERT(!funObj);
           return ArrayLengthMismatch(cx, arraySize, targetType,
                                      size_t(sourceLength), val, convType);
--- a/js/src/jsapi-tests/testIteratorObject.cpp
+++ b/js/src/jsapi-tests/testIteratorObject.cpp
@@ -8,24 +8,24 @@ BEGIN_TEST(testIteratorObject)
 {
     using namespace js;
     JS::RootedValue result(cx);
 
     EVAL("new Map([['key1', 'value1'], ['key2', 'value2']]).entries()", &result);
 
     CHECK(result.isObject());
     JS::RootedObject obj1(cx, &result.toObject());
-    ESClassValue class1 = ESClass_Other;
+    ESClass class1 = ESClass::Other;
     CHECK(GetBuiltinClass(cx, obj1, &class1));
-    CHECK(class1 == ESClass_MapIterator);
+    CHECK(class1 == ESClass::MapIterator);
 
     EVAL("new Set(['value1', 'value2']).entries()", &result);
 
     CHECK(result.isObject());
     JS::RootedObject obj2(cx, &result.toObject());
-    ESClassValue class2 = ESClass_Other;
+    ESClass class2 = ESClass::Other;
     CHECK(GetBuiltinClass(cx, obj2, &class2));
-    CHECK(class2 == ESClass_SetIterator);
+    CHECK(class2 == ESClass::SetIterator);
 
     return true;
 }
 END_TEST(testIteratorObject)
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3217,21 +3217,21 @@ JS_NewArrayObject(JSContext* cx, size_t 
     return NewDenseFullyAllocatedArray(cx, length);
 }
 
 JS_PUBLIC_API(bool)
 JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, bool* isArray)
 {
     assertSameCompartment(cx, obj);
 
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
-    *isArray = cls == ESClass_Array;
+    *isArray = cls == ESClass::Array;
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_IsArrayObject(JSContext* cx, JS::HandleValue value, bool* isArray)
 {
     if (!value.isObject()) {
         *isArray = false;
@@ -5665,21 +5665,21 @@ JS::NewDateObject(JSContext* cx, JS::Cli
     return NewDateObjectMsec(cx, time);
 }
 
 JS_PUBLIC_API(bool)
 JS_ObjectIsDate(JSContext* cx, HandleObject obj, bool* isDate)
 {
     assertSameCompartment(cx, obj);
 
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
-    *isDate = cls == ESClass_Date;
+    *isDate = cls == ESClass::Date;
     return true;
 }
 
 /************************************************************************/
 
 /*
  * Regular Expressions.
  */
@@ -5769,21 +5769,21 @@ JS_ExecuteRegExpNoStatics(JSContext* cx,
                                rval);
 }
 
 JS_PUBLIC_API(bool)
 JS_ObjectIsRegExp(JSContext* cx, HandleObject obj, bool* isRegExp)
 {
     assertSameCompartment(cx, obj);
 
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
-    *isRegExp = cls == ESClass_RegExp;
+    *isRegExp = cls == ESClass::RegExp;
     return true;
 }
 
 JS_PUBLIC_API(unsigned)
 JS_GetRegExpFlags(JSContext* cx, HandleObject obj)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2922,22 +2922,22 @@ IsObject(HandleValue v)
 // ES6 20.3.4.41.
 MOZ_ALWAYS_INLINE bool
 date_toString_impl(JSContext* cx, const CallArgs& args)
 {
     // Step 1.
     RootedObject obj(cx, &args.thisv().toObject());
 
     // Step 2.
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
     double tv;
-    if (cls != ESClass_Date) {
+    if (cls != ESClass::Date) {
         // Step 2.
         tv = GenericNaN();
     } else {
         // Step 3.
         RootedValue unboxed(cx);
         if (!Unbox(cx, obj, &unboxed))
             return false;
 
@@ -3103,21 +3103,21 @@ static bool
 DateOneArgument(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(args.length() == 1);
 
     if (args.isConstructing()) {
         if (args[0].isObject()) {
             RootedObject obj(cx, &args[0].toObject());
 
-            ESClassValue cls;
+            ESClass cls;
             if (!GetBuiltinClass(cx, obj, &cls))
                 return false;
 
-            if (cls == ESClass_Date) {
+            if (cls == ESClass::Date) {
                 RootedValue unboxed(cx);
                 if (!Unbox(cx, obj, &unboxed))
                     return false;
 
                 return NewDateObject(cx, args, TimeClip(unboxed.toNumber()));
             }
         }
 
@@ -3314,41 +3314,41 @@ js::NewDateObject(JSContext* cx, int yea
     MOZ_ASSERT(mon < 12);
     double msec_time = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0.0));
     return NewDateObjectMsec(cx, TimeClip(UTC(msec_time)));
 }
 
 JS_FRIEND_API(bool)
 js::DateIsValid(JSContext* cx, HandleObject obj, bool* isValid)
 {
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
-    if (cls != ESClass_Date) {
+    if (cls != ESClass::Date) {
         *isValid = false;
         return true;
     }
 
     RootedValue unboxed(cx);
     if (!Unbox(cx, obj, &unboxed))
         return false;
 
     *isValid = !IsNaN(unboxed.toNumber());
     return true;
 }
 
 JS_FRIEND_API(bool)
 js::DateGetMsecSinceEpoch(JSContext* cx, HandleObject obj, double* msecsSinceEpoch)
 {
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(cx, obj, &cls))
         return false;
 
-    if (cls != ESClass_Date) {
+    if (cls != ESClass::Date) {
         *msecsSinceEpoch = 0;
         return true;
     }
 
     RootedValue unboxed(cx);
     if (!Unbox(cx, obj, &unboxed))
         return false;
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1017,23 +1017,23 @@ js::ValueToSourceForError(JSContext* cx,
 
     RootedString str(cx, JS_ValueToSource(cx, val));
     if (!str)
         return "<<error converting value to string>>";
 
     StringBuffer sb(cx);
     if (val.isObject()) {
         RootedObject valObj(cx, val.toObjectOrNull());
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(cx, valObj, &cls))
             return "<<error determining class of value>>";
         const char* s;
-        if (cls == ESClass_Array)
+        if (cls == ESClass::Array)
             s = "the array ";
-        else if (cls == ESClass_ArrayBuffer)
+        else if (cls == ESClass::ArrayBuffer)
             s = "the array buffer ";
         else if (JS_IsArrayBufferViewObject(valObj))
             s = "the typed array ";
         else
             s = "the object ";
         if (!sb.append(s, strlen(s)))
             return "<<error converting value to string>>";
     } else if (val.isNumber()) {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -261,51 +261,55 @@ JS_DefineFunctionsWithHelp(JSContext* cx
                 return false;
         }
     }
 
     return true;
 }
 
 JS_FRIEND_API(bool)
-js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClassValue* classValue)
+js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls)
 {
     if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
-        return Proxy::getBuiltinClass(cx, obj, classValue);
+        return Proxy::getBuiltinClass(cx, obj, cls);
 
     if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>())
-        *classValue = ESClass_Object;
+        *cls = ESClass::Object;
     else if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>())
-        *classValue = ESClass_Array;
+        *cls = ESClass::Array;
     else if (obj->is<NumberObject>())
-        *classValue = ESClass_Number;
+        *cls = ESClass::Number;
     else if (obj->is<StringObject>())
-        *classValue = ESClass_String;
+        *cls = ESClass::String;
     else if (obj->is<BooleanObject>())
-        *classValue = ESClass_Boolean;
+        *cls = ESClass::Boolean;
     else if (obj->is<RegExpObject>())
-        *classValue = ESClass_RegExp;
+        *cls = ESClass::RegExp;
     else if (obj->is<ArrayBufferObject>())
-        *classValue = ESClass_ArrayBuffer;
+        *cls = ESClass::ArrayBuffer;
     else if (obj->is<SharedArrayBufferObject>())
-        *classValue = ESClass_SharedArrayBuffer;
+        *cls = ESClass::SharedArrayBuffer;
     else if (obj->is<DateObject>())
-        *classValue = ESClass_Date;
+        *cls = ESClass::Date;
     else if (obj->is<SetObject>())
-        *classValue = ESClass_Set;
+        *cls = ESClass::Set;
     else if (obj->is<MapObject>())
-        *classValue = ESClass_Map;
+        *cls = ESClass::Map;
     else if (obj->is<PromiseObject>())
-        *classValue = ESClass_Promise;
+        *cls = ESClass::Promise;
     else if (obj->is<MapIteratorObject>())
-        *classValue = ESClass_MapIterator;
+        *cls = ESClass::MapIterator;
     else if (obj->is<SetIteratorObject>())
-        *classValue = ESClass_SetIterator;
+        *cls = ESClass::SetIterator;
+    else if (obj->is<ArgumentsObject>())
+        *cls = ESClass::Arguments;
+    else if (obj->is<ErrorObject>())
+        *cls = ESClass::Error;
     else
-        *classValue = ESClass_Other;
+        *cls = ESClass::Other;
 
     return true;
 }
 
 JS_FRIEND_API(const char*)
 js::ObjectClassName(JSContext* cx, HandleObject obj)
 {
     return GetObjectClassName(cx, obj);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -184,17 +184,17 @@ JS_InitializePropertiesFromCompatibleNat
                                                   JS::HandleObject src);
 
 extern JS_FRIEND_API(JSString*)
 JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj);
 
 namespace js {
 
 JS_FRIEND_API(bool)
-GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClassValue* classValue);
+GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls);
 
 JS_FRIEND_API(const char*)
 ObjectClassName(JSContext* cx, JS::HandleObject obj);
 
 JS_FRIEND_API(void)
 ReportOverRecursed(JSContext* maybecx);
 
 JS_FRIEND_API(bool)
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -805,29 +805,29 @@ GuessObjectGCKind(size_t numElements)
 static inline gc::AllocKind
 GuessArrayGCKind(size_t numElements)
 {
     if (numElements)
         return gc::GetGCArrayKind(numElements);
     return gc::AllocKind::OBJECT8;
 }
 
-// Returns ESClass_Other if the value isn't an object, or if the object
+// Returns ESClass::Other if the value isn't an object, or if the object
 // isn't of one of the enumerated classes.  Otherwise returns the appropriate
 // class.
 inline bool
-GetClassOfValue(JSContext* cx, HandleValue v, ESClassValue* classValue)
+GetClassOfValue(JSContext* cx, HandleValue v, ESClass* cls)
 {
     if (!v.isObject()) {
-        *classValue = ESClass_Other;
+        *cls = ESClass::Other;
         return true;
     }
 
     RootedObject obj(cx, &v.toObject());
-    return GetBuiltinClass(cx, obj, classValue);
+    return GetBuiltinClass(cx, obj, cls);
 }
 
 extern NativeObject*
 InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto,
           const Class* clasp, JSNative constructor, unsigned nargs,
           const JSPropertySpec* ps, const JSFunctionSpec* fs,
           const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
           NativeObject** ctorp = nullptr,
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -256,31 +256,31 @@ PreprocessValue(JSContext* cx, HandleObj
         if (!js::Call(cx, replacerVal, holder, arg0, vp, vp))
             return false;
     }
 
     /* Step 4. */
     if (vp.get().isObject()) {
         RootedObject obj(cx, &vp.get().toObject());
 
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(cx, obj, &cls))
             return false;
 
-        if (cls == ESClass_Number) {
+        if (cls == ESClass::Number) {
             double d;
             if (!ToNumber(cx, vp, &d))
                 return false;
             vp.setNumber(d);
-        } else if (cls == ESClass_String) {
+        } else if (cls == ESClass::String) {
             JSString* str = ToStringSlow<CanGC>(cx, vp);
             if (!str)
                 return false;
             vp.setString(str);
-        } else if (cls == ESClass_Boolean) {
+        } else if (cls == ESClass::Boolean) {
             if (!Unbox(cx, obj, vp))
                 return false;
         }
     }
 
     return true;
 }
 
@@ -652,21 +652,21 @@ js::Stringify(JSContext* cx, MutableHand
                         id = INT_TO_JSID(n);
                     } else {
                         if (!ValueToId<CanGC>(cx, item, &id))
                             return false;
                     }
                 } else {
                     bool shouldAdd = item.isString();
                     if (!shouldAdd) {
-                        ESClassValue cls;
+                        ESClass cls;
                         if (!GetClassOfValue(cx, item, &cls))
                             return false;
 
-                        shouldAdd = cls == ESClass_String || cls == ESClass_Number;
+                        shouldAdd = cls == ESClass::String || cls == ESClass::Number;
                     }
 
                     if (shouldAdd) {
                         /* Step 4b(iii)(5)(f). */
                         if (!ValueToId<CanGC>(cx, item, &id))
                             return false;
                     } else {
                         /* Step 4b(iii)(5)(g). */
@@ -686,26 +686,26 @@ js::Stringify(JSContext* cx, MutableHand
             replacer = nullptr;
         }
     }
 
     /* Step 5. */
     if (space.isObject()) {
         RootedObject spaceObj(cx, &space.toObject());
 
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(cx, spaceObj, &cls))
             return false;
 
-        if (cls == ESClass_Number) {
+        if (cls == ESClass::Number) {
             double d;
             if (!ToNumber(cx, space, &d))
                 return false;
             space = NumberValue(d);
-        } else if (cls == ESClass_String) {
+        } else if (cls == ESClass::String) {
             JSString* str = ToStringSlow<CanGC>(cx, space);
             if (!str)
                 return false;
             space = StringValue(str);
         }
     }
 
     StringBuffer gap(cx);
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -106,18 +106,17 @@ class JS_FRIEND_API(Wrapper) : public Ba
     virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
                         bool* bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                               AutoIdVector& props) const override;
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
                                  RegExpGuard* g) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
@@ -260,18 +259,17 @@ class JS_FRIEND_API(OpaqueCrossCompartme
 
     /* SpiderMonkey extensions. */
     virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
                                        MutableHandle<PropertyDescriptor> desc) const override;
     virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
                         bool* bp) const override;
     virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
                                               AutoIdVector& props) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
-                                 ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject obj,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
 
     static const OpaqueCrossCompartmentWrapper singleton;
 };
 
@@ -302,18 +300,17 @@ class JS_FRIEND_API(SecurityWrapper) : p
     virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
                                    ObjectOpResult& result) const override;
     virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
                               ObjectOpResult& result) const override;
     virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
 
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
-                                 ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
 
     // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
     // against.
 
     virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -354,20 +354,19 @@ BaseProxyHandler::hasInstance(JSContext*
     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     RootedValue val(cx, ObjectValue(*proxy.get()));
     ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                      JSDVG_SEARCH_STACK, val, nullptr);
     return false;
 }
 
 bool
-BaseProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                  ESClassValue* classValue) const
+BaseProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
-    *classValue = ESClass_Other;
+    *cls = ESClass::Other;
     return true;
 }
 
 bool
 BaseProxyHandler::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer) const
 {
     *answer = IsArrayAnswer::NotArray;
     return true;
--- a/js/src/proxy/DeadObjectProxy.cpp
+++ b/js/src/proxy/DeadObjectProxy.cpp
@@ -110,18 +110,17 @@ bool
 DeadObjectProxy::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const
 {
     ReportDead(cx);
     return false;
 }
 
 bool
-DeadObjectProxy::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const
+DeadObjectProxy::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
     ReportDead(cx);
     return false;
 }
 
 bool
 DeadObjectProxy::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
 {
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -40,18 +40,17 @@ class DeadObjectProxy : public BaseProxy
 
     /* SpiderMonkey extensions. */
     // BaseProxyHandler::getPropertyDescriptor will throw by calling getOwnPropertyDescriptor.
     // BaseProxyHandler::enumerate will throw by calling ownKeys.
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
 
     static const char family;
     static const DeadObjectProxy singleton;
 };
--- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
+++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
@@ -156,19 +156,19 @@ bool
 OpaqueCrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
                                                             AutoIdVector& props) const
 {
     return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
 }
 
 bool
 OpaqueCrossCompartmentWrapper::getBuiltinClass(JSContext* cx, HandleObject wrapper,
-                                               ESClassValue* classValue) const
+                                    ESClass* cls) const
 {
-    *classValue = ESClass_Other;
+    *cls = ESClass::Other;
     return true;
 }
 
 bool
 OpaqueCrossCompartmentWrapper::isArray(JSContext* cx, HandleObject obj,
                                        JS::IsArrayAnswer* answer) const
 {
     *answer = JS::IsArrayAnswer::NotArray;
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -439,20 +439,20 @@ Proxy::hasInstance(JSContext* cx, Handle
     *bp = false; // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
     return proxy->as<ProxyObject>().handler()->hasInstance(cx, proxy, v, bp);
 }
 
 bool
-Proxy::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClassValue* classValue)
+Proxy::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
 {
     JS_CHECK_RECURSION(cx, return false);
-    return proxy->as<ProxyObject>().handler()->getBuiltinClass(cx, proxy, classValue);
+    return proxy->as<ProxyObject>().handler()->getBuiltinClass(cx, proxy, cls);
 }
 
 bool
 Proxy::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer)
 {
     return proxy->as<ProxyObject>().handler()->isArray(cx, proxy, answer);
 }
 
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -53,17 +53,17 @@ class Proxy
     static bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
                                       MutableHandle<PropertyDescriptor> desc);
     static bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
     static bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
                                              AutoIdVector& props);
     static bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                            const CallArgs& args);
     static bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp);
-    static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClassValue* classValue);
+    static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
     static bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer);
     static const char* className(JSContext* cx, HandleObject proxy);
     static JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent);
     static bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g);
     static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);
 
     static bool watch(JSContext* cx, HandleObject proxy, HandleId id, HandleObject callable);
     static bool unwatch(JSContext* cx, HandleObject proxy, HandleId id);
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -1235,19 +1235,19 @@ bool
 ScriptedProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                                   bool* bp) const
 {
     return InstanceOfOperator(cx, proxy, v, bp);
 }
 
 bool
 ScriptedProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                      ESClassValue* classValue) const
+                                      ESClass* cls) const
 {
-    *classValue = ESClass_Other;
+    *cls = ESClass::Other;
     return true;
 }
 
 bool
 ScriptedProxyHandler::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     if (target)
--- a/js/src/proxy/ScriptedProxyHandler.h
+++ b/js/src/proxy/ScriptedProxyHandler.h
@@ -58,18 +58,17 @@ class ScriptedProxyHandler : public Base
         return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
     }
 
     // A scripted proxy should not be treated as generic in most contexts.
     virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                             const CallArgs& args) const override;
     virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
                              bool* bp) const override;
-    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
-                                 ESClassValue* classValue) const override;
+    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
     virtual bool isArray(JSContext* cx, HandleObject proxy,
                          JS::IsArrayAnswer* answer) const override;
     virtual const char* className(JSContext* cx, HandleObject proxy) const override;
     virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
                                    unsigned indent) const override;
     virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
                                  RegExpGuard* g) const override;
     virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -72,19 +72,19 @@ SecurityWrapper<Base>::isExtensible(JSCo
     // See above.
     *extensible = true;
     return true;
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::getBuiltinClass(JSContext* cx, HandleObject wrapper,
-                                       ESClassValue* classValue) const
+                                       ESClass* cls) const
 {
-    *classValue = ESClass_Other;
+    *cls = ESClass::Other;
     return true;
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
 {
     // This should ReportUnwrapDenied(cx), but bug 849730 disagrees.  :-(
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -233,20 +233,20 @@ Wrapper::hasInstance(JSContext* cx, Hand
                                 bool* bp) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return HasInstance(cx, target, v, bp);
 }
 
 bool
-Wrapper::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClassValue* classValue) const
+Wrapper::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return GetBuiltinClass(cx, target, classValue);
+    return GetBuiltinClass(cx, target, cls);
 }
 
 bool
 Wrapper::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const
 {
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return IsArray(cx, target, answer);
 }
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -504,17 +504,17 @@ class RegExpObject : public NativeObject
  * Parse regexp flags. Report an error and return false if an invalid
  * sequence of flags is encountered (repeat/invalid flag).
  *
  * N.B. flagStr must be rooted.
  */
 bool
 ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut);
 
-/* Assuming GetBuiltinClass(obj) is ESClass_RegExp, return a RegExpShared for obj. */
+/* Assuming GetBuiltinClass(obj) is ESClass::RegExp, return a RegExpShared for obj. */
 inline bool
 RegExpToShared(JSContext* cx, HandleObject obj, RegExpGuard* g)
 {
     if (obj->is<RegExpObject>())
         return obj->as<RegExpObject>().getShared(cx, g);
 
     return Proxy::regexp_toShared(cx, obj, g);
 }
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1000,20 +1000,20 @@ JSStructuredCloneWriter::traverseObject(
 
     /* Push obj and count to the stack. */
     if (!objs.append(ObjectValue(*obj)) || !counts.append(properties.length()))
         return false;
 
     checkStack();
 
     /* Write the header for obj. */
-    ESClassValue cls;
+    ESClass cls;
     if (!GetBuiltinClass(context(), obj, &cls))
         return false;
-    return out.writePair(cls == ESClass_Array ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
+    return out.writePair(cls == ESClass::Array ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
 }
 
 bool
 JSStructuredCloneWriter::traverseMap(HandleObject obj)
 {
     Rooted<GCVector<Value>> newEntries(context(), GCVector<Value>(context()));
     {
         // If there is no wrapper, the compartment munging is a no-op.
@@ -1189,61 +1189,61 @@ JSStructuredCloneWriter::startWrite(Hand
         RootedObject obj(context(), &v.toObject());
 
         bool backref;
         if (!startObject(obj, &backref))
             return false;
         if (backref)
             return true;
 
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(context(), obj, &cls))
             return false;
 
-        if (cls == ESClass_RegExp) {
+        if (cls == ESClass::RegExp) {
             RegExpGuard re(context());
             if (!RegExpToShared(context(), obj, &re))
                 return false;
             return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
                    writeString(SCTAG_STRING, re->getSource());
-        } else if (cls == ESClass_Date) {
+        } else if (cls == ESClass::Date) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(unboxed.toNumber());
         } else if (JS_IsTypedArrayObject(obj)) {
             return writeTypedArray(obj);
         } else if (JS_IsDataViewObject(obj)) {
             return writeDataView(obj);
         } else if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) {
             return writeArrayBuffer(obj);
         } else if (JS_IsSharedArrayBufferObject(obj)) {
             return writeSharedArrayBuffer(obj);
-        } else if (cls == ESClass_Object) {
+        } else if (cls == ESClass::Object) {
             return traverseObject(obj);
-        } else if (cls == ESClass_Array) {
+        } else if (cls == ESClass::Array) {
             return traverseObject(obj);
-        } else if (cls == ESClass_Boolean) {
+        } else if (cls == ESClass::Boolean) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return out.writePair(SCTAG_BOOLEAN_OBJECT, unboxed.toBoolean());
-        } else if (cls == ESClass_Number) {
+        } else if (cls == ESClass::Number) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return out.writePair(SCTAG_NUMBER_OBJECT, 0) && out.writeDouble(unboxed.toNumber());
-        } else if (cls == ESClass_String) {
+        } else if (cls == ESClass::String) {
             RootedValue unboxed(context());
             if (!Unbox(context(), obj, &unboxed))
                 return false;
             return writeString(SCTAG_STRING_OBJECT, unboxed.toString());
-        } else if (cls == ESClass_Map) {
+        } else if (cls == ESClass::Map) {
             return traverseMap(obj);
-        } else if (cls == ESClass_Set) {
+        } else if (cls == ESClass::Set) {
             return traverseSet(obj);
         } else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
             return traverseSavedFrame(obj);
         }
 
         if (callbacks && callbacks->write)
             return callbacks->write(context(), this, obj, closure);
         /* else fall through */
@@ -1309,21 +1309,21 @@ JSStructuredCloneWriter::transferOwnersh
         uint64_t extraData;
 
 #if DEBUG
         SCInput::getPair(point, &tag, (uint32_t*) &ownership);
         MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_PENDING_ENTRY);
         MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED);
 #endif
 
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(context(), obj, &cls))
             return false;
 
-        if (cls == ESClass_ArrayBuffer) {
+        if (cls == ESClass::ArrayBuffer) {
             // The current setup of the array buffer inheritance hierarchy doesn't
             // lend itself well to generic manipulation via proxies.
             Rooted<ArrayBufferObject*> arrayBuffer(context(), &CheckedUnwrap(obj)->as<ArrayBufferObject>());
             size_t nbytes = arrayBuffer->byteLength();
 
             // Structured cloning currently only has optimizations for mapped
             // and malloc'd buffers, not asm.js-ified buffers.
             bool hasStealableContents = arrayBuffer->hasStealableContents() &&
@@ -1336,17 +1336,17 @@ JSStructuredCloneWriter::transferOwnersh
 
             content = bufContents.data();
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
             if (bufContents.kind() == ArrayBufferObject::MAPPED)
                 ownership = JS::SCTAG_TMO_MAPPED_DATA;
             else
                 ownership = JS::SCTAG_TMO_ALLOC_DATA;
             extraData = nbytes;
-        } else if (cls == ESClass_SharedArrayBuffer) {
+        } else if (cls == ESClass::SharedArrayBuffer) {
             Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
             SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
 
             // Avoids a race condition where the parent thread frees the buffer
             // before the child has accepted the transferable.
             rawbuf->addReference();
 
             tag = SCTAG_TRANSFER_MAP_SHARED_BUFFER;
@@ -1383,29 +1383,29 @@ JSStructuredCloneWriter::write(HandleVal
         RootedObject obj(context(), &objs.back().toObject());
         AutoCompartment ac(context(), obj);
         if (counts.back()) {
             counts.back()--;
             RootedValue key(context(), entries.back());
             entries.popBack();
             checkStack();
 
-            ESClassValue cls;
+            ESClass cls;
             if (!GetBuiltinClass(context(), obj, &cls))
                 return false;
 
-            if (cls == ESClass_Map) {
+            if (cls == ESClass::Map) {
                 counts.back()--;
                 RootedValue val(context(), entries.back());
                 entries.popBack();
                 checkStack();
 
                 if (!startWrite(key) || !startWrite(val))
                     return false;
-            } else if (cls == ESClass_Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
+            } else if (cls == ESClass::Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
                 if (!startWrite(key))
                     return false;
             } else {
                 RootedId id(context());
                 if (!ValueToId<CanGC>(context(), key, &id))
                   return false;
                 MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -527,20 +527,20 @@ class TypedArrayObjectTemplate : public 
     fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt) {
         return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, nullptr);
     }
 
     static JSObject*
     fromBufferWithProto(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt,
                         HandleObject proto)
     {
-        ESClassValue cls;
+        ESClass cls;
         if (!GetBuiltinClass(cx, bufobj, &cls))
             return nullptr;
-        if (cls != ESClass_ArrayBuffer && cls != ESClass_SharedArrayBuffer) {
+        if (cls != ESClass::ArrayBuffer && cls != ESClass::SharedArrayBuffer) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr;
         }
 
         MOZ_ASSERT(IsArrayBuffer(bufobj) || IsSharedArrayBuffer(bufobj) || bufobj->is<ProxyObject>());
         if (bufobj->is<ProxyObject>()) {
             /*
              * Normally, NonGenericMethodGuard handles the case of transparent