Bug 1447442 - Part 5: Use template versions of NewBuiltinClassInstance and NewObjectWithClassProto instead of manual casting. r=jorendorff
authorAndré Bargull <andre.bargull@gmail.com>
Fri, 13 Apr 2018 02:26:00 -0700
changeset 413333 a5cdb5568e441dc8bd676ee93a94293b5c55493f
parent 413332 5965536457835e02ce0e412349ed00fe541ca661
child 413334 7a03a7e15320ca43339f40866a1ac982f87e5c5e
push id33843
push usernerli@mozilla.com
push dateSat, 14 Apr 2018 09:49:25 +0000
treeherdermozilla-central@37b8862d354e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1447442
milestone61.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 1447442 - Part 5: Use template versions of NewBuiltinClassInstance and NewObjectWithClassProto instead of manual casting. r=jorendorff
js/src/builtin/ModuleObject.cpp
js/src/builtin/String.cpp
js/src/builtin/Symbol.cpp
js/src/builtin/WeakMapObject.cpp
js/src/jsdate.cpp
js/src/jsfriendapi.cpp
js/src/jsnum.cpp
js/src/shell/OSObject.cpp
js/src/vm/AsyncIteration.cpp
js/src/vm/AsyncIteration.h
js/src/vm/Debugger.cpp
js/src/vm/DebuggerMemory.cpp
js/src/vm/GeneratorObject.cpp
js/src/vm/JSFunction.cpp
js/src/vm/JSObject-inl.h
js/src/vm/JSObject.cpp
js/src/vm/JSScript.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/StringObject-inl.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -144,21 +144,20 @@ ImportEntryObject::create(JSContext* cx,
                           HandleAtom localName,
                           uint32_t lineNumber,
                           uint32_t columnNumber)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateImportEntryPrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    ImportEntryObject* self = NewObjectWithGivenProto<ImportEntryObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedImportEntryObject self(cx, &obj->as<ImportEntryObject>());
     self->initReservedSlot(ModuleRequestSlot, StringValue(moduleRequest));
     self->initReservedSlot(ImportNameSlot, StringValue(importName));
     self->initReservedSlot(LocalNameSlot, StringValue(localName));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
 
@@ -233,21 +232,20 @@ ExportEntryObject::create(JSContext* cx,
 {
     // Line and column numbers are optional for export entries since direct
     // entries are checked at parse time.
 
     RootedObject proto(cx, GlobalObject::getOrCreateExportEntryPrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    ExportEntryObject* self = NewObjectWithGivenProto<ExportEntryObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedExportEntryObject self(cx, &obj->as<ExportEntryObject>());
     self->initReservedSlot(ExportNameSlot, StringOrNullValue(maybeExportName));
     self->initReservedSlot(ModuleRequestSlot, StringOrNullValue(maybeModuleRequest));
     self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
     self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
@@ -302,21 +300,20 @@ RequestedModuleObject::create(JSContext*
                               HandleAtom moduleSpecifier,
                               uint32_t lineNumber,
                               uint32_t columnNumber)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateRequestedModulePrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    RequestedModuleObject* self = NewObjectWithGivenProto<RequestedModuleObject>(cx, proto);
+    if (!self)
         return nullptr;
 
-    RootedRequestedModuleObject self(cx, &obj->as<RequestedModuleObject>());
     self->initReservedSlot(ModuleSpecifierSlot, StringValue(moduleSpecifier));
     self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
     self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
     return self;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // IndirectBindingMap
@@ -766,22 +763,20 @@ ModuleObject::isInstance(HandleValue val
 
 /* static */ ModuleObject*
 ModuleObject::create(JSContext* cx)
 {
     RootedObject proto(cx, GlobalObject::getOrCreateModulePrototype(cx, cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    RootedModuleObject self(cx, NewObjectWithGivenProto<ModuleObject>(cx, proto));
+    if (!self)
         return nullptr;
 
-    RootedModuleObject self(cx, &obj->as<ModuleObject>());
-
     Zone* zone = cx->zone();
     IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>();
     if (!bindings) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     self->initReservedSlot(ImportBindingsSlot, PrivateValue(bindings));
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -3624,21 +3624,20 @@ StringObject::assignInitialShape(JSConte
 JSObject*
 js::InitStringClass(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->isNative());
 
     Handle<GlobalObject*> global = obj.as<GlobalObject>();
 
     Rooted<JSString*> empty(cx, cx->runtime()->emptyString);
-    RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &StringObject::class_));
+    Rooted<StringObject*> proto(cx, GlobalObject::createBlankPrototype<StringObject>(cx, global));
     if (!proto)
         return nullptr;
-    Handle<StringObject*> protoObj = proto.as<StringObject>();
-    if (!StringObject::init(cx, protoObj, empty))
+    if (!StringObject::init(cx, proto, empty))
         return nullptr;
 
     /* Now create the String function. */
     RootedFunction ctor(cx);
     ctor = GlobalObject::createConstructor(cx, StringConstructor, cx->names().String, 1,
                                            AllocKind::FUNCTION, &jit::JitInfo_String);
     if (!ctor)
         return nullptr;
@@ -3651,27 +3650,27 @@ js::InitStringClass(JSContext* cx, Handl
     {
         return nullptr;
     }
 
     // Create "trimLeft" as an alias for "trimStart".
     RootedValue trimFn(cx);
     RootedId trimId(cx, NameToId(cx->names().trimStart));
     RootedId trimAliasId(cx, NameToId(cx->names().trimLeft));
-    if (!NativeGetProperty(cx, protoObj, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, protoObj, trimAliasId, trimFn, 0))
+    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
+        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
     {
         return nullptr;
     }
 
     // Create "trimRight" as an alias for "trimEnd".
     trimId = NameToId(cx->names().trimEnd);
     trimAliasId = NameToId(cx->names().trimRight);
-    if (!NativeGetProperty(cx, protoObj, trimId, &trimFn) ||
-        !NativeDefineDataProperty(cx, protoObj, trimAliasId, trimFn, 0))
+    if (!NativeGetProperty(cx, proto, trimId, &trimFn) ||
+        !NativeDefineDataProperty(cx, proto, trimAliasId, trimFn, 0))
     {
         return nullptr;
     }
 
     /*
      * Define escape/unescape, the URI encode/decode functions, and maybe
      * uneval on the global object.
      */
--- a/js/src/builtin/Symbol.cpp
+++ b/js/src/builtin/Symbol.cpp
@@ -18,22 +18,21 @@ using namespace js;
 const Class SymbolObject::class_ = {
     "Symbol",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Symbol)
 };
 
 SymbolObject*
 SymbolObject::create(JSContext* cx, JS::HandleSymbol symbol)
 {
-    JSObject* obj = NewBuiltinClassInstance(cx, &class_);
+    SymbolObject* obj = NewBuiltinClassInstance<SymbolObject>(cx);
     if (!obj)
         return nullptr;
-    SymbolObject& symobj = obj->as<SymbolObject>();
-    symobj.setPrimitiveValue(symbol);
-    return &symobj;
+    obj->setPrimitiveValue(symbol);
+    return obj;
 }
 
 const JSPropertySpec SymbolObject::properties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec SymbolObject::methods[] = {
     JS_FN(js_toString_str, toString, 0, 0),
--- a/js/src/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -185,17 +185,17 @@ WeakCollection_finalize(FreeOp* fop, JSO
     MOZ_ASSERT(fop->maybeOnHelperThread());
     if (ObjectValueMap* map = obj->as<WeakCollectionObject>().getMap())
         fop->delete_(map);
 }
 
 JS_PUBLIC_API(JSObject*)
 JS::NewWeakMapObject(JSContext* cx)
 {
-    return NewBuiltinClassInstance(cx, &WeakMapObject::class_);
+    return NewBuiltinClassInstance<WeakMapObject>(cx);
 }
 
 JS_PUBLIC_API(bool)
 JS::IsWeakMapObject(JSObject* obj)
 {
     return obj->is<WeakMapObject>();
 }
 
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3314,20 +3314,20 @@ const Class DateObject::protoClass_ = {
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     JS_NULL_CLASS_OPS,
     &DateObjectClassSpec
 };
 
 JSObject*
 js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
+    DateObject* obj = NewObjectWithClassProto<DateObject>(cx, proto);
     if (!obj)
         return nullptr;
-    obj->as<DateObject>().setUTCTime(t);
+    obj->setUTCTime(t);
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
 js::NewDateObject(JSContext* cx, int year, int mon, int mday,
                   int hour, int min, int sec)
 {
     MOZ_ASSERT(mon < 12);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -125,18 +125,17 @@ JS_FRIEND_API(JSObject*)
 JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, HandleObject proto)
 {
     /*
      * Create our object with a null proto and then splice in the correct proto
      * after we setSingleton, so that we don't pollute the default
      * ObjectGroup attached to our proto with information about our object, since
      * we're not going to be using that ObjectGroup anyway.
      */
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, (const js::Class*)clasp, nullptr,
-                                                 SingletonObject));
+    RootedObject obj(cx, NewObjectWithGivenProto(cx, Valueify(clasp), nullptr, SingletonObject));
     if (!obj)
         return nullptr;
     if (!JS_SplicePrototype(cx, obj, proto))
         return nullptr;
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1195,21 +1195,21 @@ js::FinishRuntimeNumberState(JSRuntime* 
 
 JSObject*
 js::InitNumberClass(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->isNative());
 
     Handle<GlobalObject*> global = obj.as<GlobalObject>();
 
-    RootedObject numberProto(cx, GlobalObject::createBlankPrototype(cx, global,
-                                                                    &NumberObject::class_));
+    Rooted<NumberObject*> numberProto(cx);
+    numberProto = GlobalObject::createBlankPrototype<NumberObject>(cx, global);
     if (!numberProto)
         return nullptr;
-    numberProto->as<NumberObject>().setPrimitiveValue(0);
+    numberProto->setPrimitiveValue(0);
 
     RootedFunction ctor(cx);
     ctor = GlobalObject::createConstructor(cx, Number, cx->names().Number, 1);
     if (!ctor)
         return nullptr;
 
     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
         return nullptr;
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -399,24 +399,23 @@ class FileObject : public NativeObject
         FILE_SLOT = 0,
         NUM_SLOTS
     };
 
   public:
     static const js::Class class_;
 
     static FileObject* create(JSContext* cx, RCFile* file) {
-        JSObject* obj = js::NewObjectWithClassProto(cx, &class_, nullptr);
+        FileObject* obj = js::NewObjectWithClassProto<FileObject>(cx, nullptr);
         if (!obj)
             return nullptr;
 
-        FileObject* fileObj = &obj->as<FileObject>();
-        fileObj->setRCFile(file);
+        obj->setRCFile(file);
         file->acquire();
-        return fileObj;
+        return obj;
     }
 
     static void finalize(FreeOp* fop, JSObject* obj) {
         FileObject* fileObj = &obj->as<FileObject>();
         RCFile* file = fileObj->rcFile();
         if (file->release()) {
             fileObj->setRCFile(nullptr);
             fop->delete_(file);
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -43,18 +43,17 @@ WrappedAsyncGenerator(JSContext* cx, uns
     if (!args2.init(cx, argc))
         return false;
     for (size_t i = 0, len = argc; i < len; i++)
         args2[i].set(args[i]);
     if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
         return false;
 
     // Step 2.
-    Rooted<AsyncGeneratorObject*> asyncGenObj(
-        cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
+    AsyncGeneratorObject* asyncGenObj = AsyncGeneratorObject::create(cx, wrapped, generatorVal);
     if (!asyncGenObj)
         return false;
 
     // Step 3 (skipped).
     // Done in AsyncGeneratorObject::create and generator.
 
     // Step 4.
     args.rval().setObject(*asyncGenObj);
@@ -182,22 +181,21 @@ js::CreateAsyncFromSyncIterator(JSContex
 AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter, HandleValue nextMethod)
 {
     // Step 2.
     RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
                                                                                    cx->global()));
     if (!proto)
         return nullptr;
 
-    RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
-    if (!obj)
+    AsyncFromSyncIteratorObject* asyncIter =
+        NewObjectWithGivenProto<AsyncFromSyncIteratorObject>(cx, proto);
+    if (!asyncIter)
         return nullptr;
 
-    Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
-
     // Step 3.
     asyncIter->init(iter, nextMethod);
 
     // Step 4.
     return asyncIter;
 }
 
 // Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
@@ -258,54 +256,48 @@ AsyncGeneratorThrow(JSContext* cx, unsig
 }
 
 const Class AsyncGeneratorObject::class_ = {
     "AsyncGenerator",
     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
 };
 
 // ES 2017 draft 9.1.13.
-template <typename ProtoGetter>
-static JSObject*
-OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
-                              ProtoGetter protoGetter, const Class* clasp)
+// OrdinaryCreateFromConstructor specialized for AsyncGeneratorObjects.
+static AsyncGeneratorObject*
+OrdinaryCreateFromConstructorAsynGen(JSContext* cx, HandleFunction fun)
 {
     // Step 1 (skipped).
 
     // Step 2.
     RootedValue protoVal(cx);
     if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
         return nullptr;
 
     RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
     if (!proto) {
-        proto = protoGetter(cx, cx->global());
+        proto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, cx->global());
         if (!proto)
             return nullptr;
     }
 
     // Step 3.
-    return NewNativeObjectWithGivenProto(cx, clasp, proto);
+    return NewObjectWithGivenProto<AsyncGeneratorObject>(cx, proto);
 }
 
 /* static */ AsyncGeneratorObject*
 AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
 {
     MOZ_ASSERT(generatorVal.isObject());
     MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
 
-    RootedObject obj(
-        cx, OrdinaryCreateFromConstructor(cx, asyncGen,
-                                          GlobalObject::getOrCreateAsyncGeneratorPrototype,
-                                          &class_));
-    if (!obj)
+    AsyncGeneratorObject* asyncGenObj = OrdinaryCreateFromConstructorAsynGen(cx, asyncGen);
+    if (!asyncGenObj)
         return nullptr;
 
-    Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
-
     // Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
     // Step 6.
     asyncGenObj->setGenerator(generatorVal);
 
     // Step 7.
     asyncGenObj->setSuspendedStart();
 
     // Step 8.
@@ -386,21 +378,20 @@ const Class AsyncGeneratorRequest::class
     JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
 };
 
 // Async Iteration proposal 11.4.3.1.
 /* static */ AsyncGeneratorRequest*
 AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind,
                               HandleValue completionValue, HandleObject promise)
 {
-    RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
-    if (!obj)
+    AsyncGeneratorRequest* request = NewObjectWithGivenProto<AsyncGeneratorRequest>(cx, nullptr);
+    if (!request)
         return nullptr;
 
-    Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
     request->init(completionKind, completionValue, promise);
     return request;
 }
 
 // Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d-g.
 static MOZ_MUST_USE bool
 AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
                        HandleValue value)
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -57,20 +57,18 @@ class AsyncGeneratorRequest : public Nat
   private:
     enum AsyncGeneratorRequestSlots {
         Slot_CompletionKind = 0,
         Slot_CompletionValue,
         Slot_Promise,
         Slots,
     };
 
-    void init(CompletionKind completionKind, HandleValue completionValue,
-              HandleObject promise) {
-        setFixedSlot(Slot_CompletionKind,
-                     Int32Value(static_cast<int32_t>(completionKind)));
+    void init(CompletionKind completionKind, const Value& completionValue, JSObject* promise) {
+        setFixedSlot(Slot_CompletionKind, Int32Value(static_cast<int32_t>(completionKind)));
         setFixedSlot(Slot_CompletionValue, completionValue);
         setFixedSlot(Slot_Promise, ObjectValue(*promise));
     }
 
     void clearData() {
         setFixedSlot(Slot_CompletionValue, NullValue());
         setFixedSlot(Slot_Promise, NullValue());
     }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7493,30 +7493,28 @@ DebuggerFrame::initClass(JSContext* cx, 
     return InitClass(cx, dbgCtor, objProto, &class_, construct, 0, properties_,
                      methods_, nullptr, nullptr);
 }
 
 /* static */ DebuggerFrame*
 DebuggerFrame::create(JSContext* cx, HandleObject proto, const FrameIter& iter,
                       HandleNativeObject debugger)
 {
-    JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerFrame::class_, proto);
-    if (!obj)
+    DebuggerFrame* frame = NewObjectWithGivenProto<DebuggerFrame>(cx, proto);
+    if (!frame)
         return nullptr;
 
-    DebuggerFrame& frame = obj->as<DebuggerFrame>();
-
     FrameIter::Data* data = iter.copyData();
     if (!data)
         return nullptr;
-    frame.setPrivate(data);
-
-    frame.setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*debugger));
-
-    return &frame;
+    frame->setPrivate(data);
+
+    frame->setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*debugger));
+
+    return frame;
 }
 
 /* static */ bool
 DebuggerFrame::getCallee(JSContext* cx, HandleDebuggerFrame frame,
                          MutableHandleDebuggerObject result)
 {
     MOZ_ASSERT(frame->isLive());
 
@@ -8369,17 +8367,17 @@ DebuggerArguments_getArg(JSContext* cx, 
     return true;
 }
 
 /* static */ DebuggerArguments*
 DebuggerArguments::create(JSContext* cx, HandleObject proto, HandleDebuggerFrame frame)
 {
     AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
 
-    RootedNativeObject obj(cx, NewNativeObjectWithGivenProto(cx, &DebuggerArguments::class_, proto));
+    Rooted<DebuggerArguments*> obj(cx, NewObjectWithGivenProto<DebuggerArguments>(cx, proto));
     if (!obj)
         return nullptr;
 
     SetReservedSlot(obj, FRAME_SLOT, ObjectValue(*frame));
 
     MOZ_ASSERT(referent.numActualArgs() <= 0x7fffffff);
     unsigned fargc = referent.numActualArgs();
     RootedValue fargcVal(cx, Int32Value(fargc));
@@ -8402,17 +8400,17 @@ DebuggerArguments::create(JSContext* cx,
                                           JS_DATA_TO_FUNC_PTR(GetterOp, getobj.get()), nullptr,
                                           JSPROP_ENUMERATE | JSPROP_GETTER))
         {
             return nullptr;
         }
         getobj->setExtendedSlot(0, Int32Value(i));
     }
 
-    return &obj->as<DebuggerArguments>();
+    return obj;
 }
 
 /* static */ bool
 DebuggerFrame::argumentsGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGGER_FRAME(cx, argc, vp, "get arguments", args, frame);
 
     RootedDebuggerArguments result(cx);
@@ -9801,25 +9799,24 @@ DebuggerObject::initClass(JSContext* cx,
     return objectProto;
 }
 
 /* static */ DebuggerObject*
 DebuggerObject::create(JSContext* cx, HandleObject proto, HandleObject referent,
                        HandleNativeObject debugger)
 {
     NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
-    JSObject* obj = NewObjectWithGivenProto(cx, &DebuggerObject::class_, proto, newKind);
+    DebuggerObject* obj = NewObjectWithGivenProto<DebuggerObject>(cx, proto, newKind);
     if (!obj)
         return nullptr;
 
-    DebuggerObject& object = obj->as<DebuggerObject>();
-    object.setPrivateGCThing(referent);
-    object.setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
-
-    return &object;
+    obj->setPrivateGCThing(referent);
+    obj->setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
+
+    return obj;
 }
 
 bool
 DebuggerObject::isCallable() const
 {
     return referent()->isCallable();
 }
 
@@ -11046,25 +11043,24 @@ DebuggerEnvironment::initClass(JSContext
                      properties_, methods_, nullptr, nullptr);
 }
 
 /* static */ DebuggerEnvironment*
 DebuggerEnvironment::create(JSContext* cx, HandleObject proto, HandleObject referent,
                             HandleNativeObject debugger)
 {
     NewObjectKind newKind = IsInsideNursery(referent) ? GenericObject : TenuredObject;
-    RootedObject obj(cx, NewObjectWithGivenProto(cx, &DebuggerEnvironment::class_, proto, newKind));
+    DebuggerEnvironment* obj = NewObjectWithGivenProto<DebuggerEnvironment>(cx, proto, newKind);
     if (!obj)
         return nullptr;
 
-    DebuggerEnvironment& environment = obj->as<DebuggerEnvironment>();
-    environment.setPrivateGCThing(referent);
-    environment.setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
-
-    return &environment;
+    obj->setPrivateGCThing(referent);
+    obj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger));
+
+    return obj;
 }
 
 /* static */ DebuggerEnvironmentType
 DebuggerEnvironment::type() const
 {
     /* Don't bother switching compartments just to check env's type. */
     if (IsDeclarative(referent()))
         return DebuggerEnvironmentType::Declarative;
--- a/js/src/vm/DebuggerMemory.cpp
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -35,24 +35,24 @@ using mozilla::Forward;
 using mozilla::Maybe;
 using mozilla::Nothing;
 
 /* static */ DebuggerMemory*
 DebuggerMemory::create(JSContext* cx, Debugger* dbg)
 {
     Value memoryProtoValue = dbg->object->getReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO);
     RootedObject memoryProto(cx, &memoryProtoValue.toObject());
-    RootedNativeObject memory(cx, NewNativeObjectWithGivenProto(cx, &class_, memoryProto));
+    Rooted<DebuggerMemory*> memory(cx, NewObjectWithGivenProto<DebuggerMemory>(cx, memoryProto));
     if (!memory)
         return nullptr;
 
     dbg->object->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_INSTANCE, ObjectValue(*memory));
     memory->setReservedSlot(JSSLOT_DEBUGGER, ObjectValue(*dbg->object));
 
-    return &memory->as<DebuggerMemory>();
+    return memory;
 }
 
 Debugger*
 DebuggerMemory::getDebugger()
 {
     const Value& dbgVal = getReservedSlot(JSSLOT_DEBUGGER);
     return Debugger::fromJSObject(&dbgVal.toObject());
 }
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -31,30 +31,28 @@ GeneratorObject::create(JSContext* cx, A
     if (!GetProperty(cx, fun, fun, cx->names().prototype, &pval))
         return nullptr;
     RootedObject proto(cx, pval.isObject() ? &pval.toObject() : nullptr);
     if (!proto) {
         proto = GlobalObject::getOrCreateGeneratorObjectPrototype(cx, global);
         if (!proto)
             return nullptr;
     }
-    RootedNativeObject obj(cx,
-                           NewNativeObjectWithGivenProto(cx, &GeneratorObject::class_, proto));
-    if (!obj)
+    Rooted<GeneratorObject*> genObj(cx, NewObjectWithGivenProto<GeneratorObject>(cx, proto));
+    if (!genObj)
         return nullptr;
 
-    GeneratorObject* genObj = &obj->as<GeneratorObject>();
     genObj->setCallee(*frame.callee());
     genObj->setNewTarget(frame.newTarget());
     genObj->setEnvironmentChain(*frame.environmentChain());
     if (frame.script()->needsArgsObj())
         genObj->setArgsObj(frame.argsObj());
     genObj->clearExpressionStack();
 
-    return obj;
+    return genObj;
 }
 
 bool
 GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
                          Value* vp, unsigned nvalues)
 {
     MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
 
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -2136,21 +2136,20 @@ NewFunctionClone(JSContext* cx, HandleFu
 {
     RootedObject cloneProto(cx, proto);
     if (!proto && (fun->isGenerator() || fun->isAsync())) {
         cloneProto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
         if (!cloneProto)
             return nullptr;
     }
 
-    JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
-                                                 allocKind, newKind);
-    if (!cloneobj)
+    RootedFunction clone(cx);
+    clone = NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
+    if (!clone)
         return nullptr;
-    RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
     // JSFunction::HAS_INFERRED_NAME can be set at compile-time and at
     // runtime. In the latter case we should actually clear the flag before
     // cloning the function, but since we can't differentiate between both
     // cases here, we'll end up with a momentarily incorrect function name.
     // This will be fixed up in SetFunctionNameIfNoOwnName(), which should
     // happen through JSOP_SETFUNNAME directly after JSOP_LAMBDA.
     constexpr uint16_t NonCloneableFlags = JSFunction::EXTENDED |
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -619,29 +619,39 @@ NewObjectWithGivenTaggedProto(JSContext*
 {
     JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind,
                                                   initialShapeFlags);
     return obj ? &obj->as<T>() : nullptr;
 }
 
 template <typename T>
 inline T*
+NewObjectWithGivenTaggedProto(JSContext* cx, Handle<TaggedProto> proto,
+                              gc::AllocKind allocKind, NewObjectKind newKind = GenericObject,
+                              uint32_t initialShapeFlags = 0)
+{
+    JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, allocKind, newKind,
+                                                  initialShapeFlags);
+    return obj ? &obj->as<T>() : nullptr;
+}
+
+template <typename T>
+inline T*
 NewObjectWithNullTaggedProto(JSContext* cx, NewObjectKind newKind = GenericObject,
                              uint32_t initialShapeFlags = 0)
 {
     Handle<TaggedProto> nullProto = AsTaggedProto(nullptr);
     return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
 }
 
 inline JSObject*
 NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
-                        gc::AllocKind allocKind, NewObjectKind newKind)
+                        gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
 {
-    return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind,
-                                         newKind);
+    return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind, newKind);
 }
 
 inline JSObject*
 NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
                         NewObjectKind newKind = GenericObject)
 {
     return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), newKind);
 }
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -993,17 +993,17 @@ CreateThisForFunctionWithGroup(JSContext
 
         return res;
     }
 
     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
 
     if (newKind == SingletonObject) {
         Rooted<TaggedProto> protoRoot(cx, group->proto());
-        return NewObjectWithGivenTaggedProto(cx, &PlainObject::class_, protoRoot, allocKind, newKind);
+        return NewObjectWithGivenTaggedProto<PlainObject>(cx, protoRoot, allocKind, newKind);
     }
     return NewObjectWithGroup<PlainObject>(cx, group, allocKind, newKind);
 }
 
 JSObject*
 js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
                                    HandleObject proto, NewObjectKind newKind /* = GenericObject */)
 {
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1362,20 +1362,19 @@ const Class ScriptSourceObject::class_ =
     JSCLASS_IS_ANONYMOUS |
     JSCLASS_FOREGROUND_FINALIZE,
     &ScriptSourceObjectClassOps
 };
 
 ScriptSourceObject*
 ScriptSourceObject::create(JSContext* cx, ScriptSource* source)
 {
-    RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr));
-    if (!object)
+    RootedScriptSource sourceObject(cx, NewObjectWithGivenProto<ScriptSourceObject>(cx, nullptr));
+    if (!sourceObject)
         return nullptr;
-    RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
 
     source->incref();    // The matching decref is in ScriptSourceObject::finalize.
     sourceObject->initReservedSlot(SOURCE_SLOT, PrivateValue(source));
 
     // The remaining slots should eventually be populated by a call to
     // initFromOptions. Poison them until that point.
     sourceObject->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC));
     sourceObject->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -561,22 +561,17 @@ SavedFrame::create(JSContext* cx)
     // accidentally cause O(n^2) behavior.
     SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks());
 
     RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
     if (!proto)
         return nullptr;
     assertSameCompartment(cx, proto);
 
-    RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto,
-                                                      TenuredObject));
-    if (!frameObj)
-        return nullptr;
-
-    return &frameObj->as<SavedFrame>();
+    return NewObjectWithGivenProto<SavedFrame>(cx, proto, TenuredObject);
 }
 
 bool
 SavedFrame::isSelfHosted(JSContext* cx)
 {
     JSAtom* source = getSource();
     return source == cx->names().selfHosted;
 }
--- a/js/src/vm/StringObject-inl.h
+++ b/js/src/vm/StringObject-inl.h
@@ -27,20 +27,19 @@ StringObject::init(JSContext* cx, Handle
     obj->setStringThis(str);
 
     return true;
 }
 
 /* static */ inline StringObject*
 StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+    Rooted<StringObject*> obj(cx, NewObjectWithClassProto<StringObject>(cx, proto, newKind));
     if (!obj)
         return nullptr;
-    Rooted<StringObject*> strobj(cx, &obj->as<StringObject>());
-    if (!StringObject::init(cx, strobj, str))
+    if (!StringObject::init(cx, obj, str))
         return nullptr;
-    return strobj;
+    return obj;
 }
 
 } // namespace js
 
 #endif /* vm_StringObject_inl_h */
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -398,17 +398,17 @@ class TypedArrayObjectTemplate : public 
         }
     }
 
     static TypedArrayObject*
     makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
     {
         MOZ_ASSERT(proto);
 
-        JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
+        JSObject* obj = NewObjectWithGivenProto(cx, instanceClass(), proto, allocKind);
         return obj ? &obj->as<TypedArrayObject>() : nullptr;
     }
 
     static TypedArrayObject*
     makeTypedInstance(JSContext* cx, CreateSingleton createSingleton, gc::AllocKind allocKind)
     {
         const Class* clasp = instanceClass();
         if (createSingleton == CreateSingleton::Yes) {