Backed out 20 changesets (bug 1055472) for Linux64 cgc failures and an apparent crash in the cpp test test_audio on OS X 10.6 debug
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 19 Nov 2015 20:01:07 -0800
changeset 273465 652bd59cdb5153cac5a7d1720ccd546862130144
parent 273464 80dc69d21994a554b3041c5ebc7f5572e4a42c09
child 273466 b140ad795489ac08d282a06300fd9619727dbdb7
push id16334
push usercbook@mozilla.com
push dateFri, 20 Nov 2015 13:35:22 +0000
treeherderfx-team@0947ebd84fec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1055472
milestone45.0a1
backs outedd1c18b5a5b78ab1d0a32fd5d195f321c7e03fe
41be086be0e814c60ab3ae3a498f877e81815af1
6ed32cadfc3126c34644ee37658b6a752b477d44
2f0b0b246e25f83fd88a7b06fa91945a16645097
33d5c8ef947c3949346f1b779e93d23b7cc7949a
74dca890ec34f7d2e364725326ed48e13703ab3c
b4a4144b96fa7c3908c2fc3ca5d4bf22072fbf2b
9dd0b1fff545d01bc487c843f17c3650fb37ac99
31c41d6a16ab03f1a068365e6dfdfa1859894890
bf8f9604c34fdc3f63472d57307da9119ba91156
69bf1faa9d85c7efdbda56571c72e9b7be58cf88
284934443cd34f159942256429fec6dcb910629a
65d962413c98659e3a06de96e481b845913bead4
94135702e1b51d1811b0735c672f60227eac1503
1509efcfa6290ef8926f83ec8b04b945a891ef74
c7180ea9dfa43936cd2089eebb6923b0c5086e9a
a47a3ce6f35efede61f6b1b8ef8188ffa05e33de
9b4f7a838a661d526dc020cbf11695655e1525cb
e5f593ea362c6d27507969582864cba5cfbcd94d
8ec3005245c107cb24b6b096564ec295064c7ce2
Backed out 20 changesets (bug 1055472) for Linux64 cgc failures and an apparent crash in the cpp test test_audio on OS X 10.6 debug CLOSED TREE Backed out changeset edd1c18b5a5b (bug 1055472) Backed out changeset 41be086be0e8 (bug 1055472) Backed out changeset 6ed32cadfc31 (bug 1055472) Backed out changeset 2f0b0b246e25 (bug 1055472) Backed out changeset 33d5c8ef947c (bug 1055472) Backed out changeset 74dca890ec34 (bug 1055472) Backed out changeset b4a4144b96fa (bug 1055472) Backed out changeset 9dd0b1fff545 (bug 1055472) Backed out changeset 31c41d6a16ab (bug 1055472) Backed out changeset bf8f9604c34f (bug 1055472) Backed out changeset 69bf1faa9d85 (bug 1055472) Backed out changeset 284934443cd3 (bug 1055472) Backed out changeset 65d962413c98 (bug 1055472) Backed out changeset 94135702e1b5 (bug 1055472) Backed out changeset 1509efcfa629 (bug 1055472) Backed out changeset c7180ea9dfa4 (bug 1055472) Backed out changeset a47a3ce6f35e (bug 1055472) Backed out changeset 9b4f7a838a66 (bug 1055472) Backed out changeset e5f593ea362c (bug 1055472) Backed out changeset 8ec3005245c1 (bug 1055472)
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/builtin/Object.cpp
js/src/builtin/RegExp.cpp
js/src/builtin/WeakMapObject.cpp
js/src/builtin/WeakSetObject.cpp
js/src/builtin/WeakSetObject.h
js/src/gc/Marking.cpp
js/src/gc/Tracer.h
js/src/jit-test/tests/TypedObject/bug976697.js
js/src/jit-test/tests/baseline/arraySubclassPropertyLookup.js
js/src/jit/BaselineIC.cpp
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsbool.cpp
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsstr.cpp
js/src/tests/ecma_6/Class/boundFunctionSubclassing.js
js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js
js/src/tests/ecma_6/Class/superCallBaseInvoked.js
js/src/tests/ecma_6/DataView/detach-after-construction.js
js/src/tests/ecma_6/Reflect/construct.js
js/src/tests/ecma_6/RegExp/constructor-ordering-2.js
js/src/tests/ecma_6/RegExp/constructor-ordering.js
js/src/tests/ecma_6/TypedArray/constructor-non-detached.js
js/src/tests/js1_5/Error/constructor-ordering.js
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/BooleanObject-inl.h
js/src/vm/BooleanObject.h
js/src/vm/ErrorObject.cpp
js/src/vm/ErrorObject.h
js/src/vm/Interpreter.cpp
js/src/vm/NumberObject-inl.h
js/src/vm/NumberObject.h
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/SelfHosting.cpp
js/src/vm/StringObject-inl.h
js/src/vm/StringObject.h
js/src/vm/TypedArrayCommon.h
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -216,17 +216,17 @@ MapIteratorObject::next(JSContext* cx, H
     return false;
 }
 
 
 /*** Map *****************************************************************************************/
 
 const Class MapObject::class_ = {
     "Map",
-    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_PRIVATE | 
     JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
     nullptr, // addProperty
     nullptr, // delProperty
     nullptr, // getProperty
     nullptr, // setProperty
     nullptr, // enumerate
     nullptr, // resolve
     nullptr, // mayResolve
@@ -407,30 +407,31 @@ MapObject::set(JSContext* cx, HandleObje
         ReportOutOfMemory(cx);
         return false;
     }
     WriteBarrierPost(cx->runtime(), map, key.value());
     return true;
 }
 
 MapObject*
-MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
+MapObject::create(JSContext* cx)
 {
-    auto map = cx->make_unique<ValueMap>(cx->runtime());
+    Rooted<MapObject*> obj(cx, NewBuiltinClassInstance<MapObject>(cx));
+    if (!obj)
+        return nullptr;
+
+    ValueMap* map = cx->new_<ValueMap>(cx->runtime());
     if (!map || !map->init()) {
+        js_delete(map);
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
-    MapObject* mapObj = NewObjectWithClassProto<MapObject>(cx,  proto);
-    if (!mapObj)
-        return nullptr;
-
-    mapObj->setPrivate(map.release());
-    return mapObj;
+    obj->setPrivate(map);
+    return obj;
 }
 
 void
 MapObject::finalize(FreeOp* fop, JSObject* obj)
 {
     if (ValueMap* map = obj->as<MapObject>().getData())
         fop->delete_(map);
 }
@@ -438,22 +439,17 @@ MapObject::finalize(FreeOp* fop, JSObjec
 bool
 MapObject::construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!ThrowIfNotConstructing(cx, args, "Map"))
         return false;
 
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    Rooted<MapObject*> obj(cx, MapObject::create(cx, proto));
+    Rooted<MapObject*> obj(cx, MapObject::create(cx));
     if (!obj)
         return false;
 
     if (!args.get(0).isNullOrUndefined()) {
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().set, &adderVal))
             return false;
 
@@ -1063,29 +1059,29 @@ SetObject::add(JSContext* cx, HandleObje
         ReportOutOfMemory(cx);
         return false;
     }
     WriteBarrierPost(cx->runtime(), set, key.value());
     return true;
 }
 
 SetObject*
-SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
+SetObject::create(JSContext* cx)
 {
-    auto set = cx->make_unique<ValueSet>(cx->runtime());
+    SetObject* obj = NewBuiltinClassInstance<SetObject>(cx);
+    if (!obj)
+        return nullptr;
+
+    ValueSet* set = cx->new_<ValueSet>(cx->runtime());
     if (!set || !set->init()) {
+        js_delete(set);
         ReportOutOfMemory(cx);
         return nullptr;
     }
-
-    SetObject* obj = NewObjectWithClassProto<SetObject>(cx, proto);
-    if (!obj)
-        return nullptr;
-
-    obj->setPrivate(set.release());
+    obj->setPrivate(set);
     return obj;
 }
 
 void
 SetObject::mark(JSTracer* trc, JSObject* obj)
 {
     SetObject* setobj = static_cast<SetObject*>(obj);
     if (ValueSet* set = setobj->getData()) {
@@ -1105,22 +1101,17 @@ SetObject::finalize(FreeOp* fop, JSObjec
 bool
 SetObject::construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!ThrowIfNotConstructing(cx, args, "Set"))
         return false;
 
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    Rooted<SetObject*> obj(cx, SetObject::create(cx, proto));
+    Rooted<SetObject*> obj(cx, SetObject::create(cx));
     if (!obj)
         return false;
 
     if (!args.get(0).isNullOrUndefined()) {
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().add, &adderVal))
             return false;
 
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -87,17 +87,17 @@ class MapObject : public NativeObject {
 
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
     static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
                                             JS::AutoValueVector* entries);
     static bool entries(JSContext* cx, unsigned argc, Value* vp);
     static bool has(JSContext* cx, unsigned argc, Value* vp);
-    static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
+    static MapObject* create(JSContext* cx);
 
     // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
     // interfaces, etc.)
     static uint32_t size(JSContext *cx, HandleObject obj);
     static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
     static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
     static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
 
@@ -176,17 +176,17 @@ class SetObject : public NativeObject {
 
     static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
     static bool values(JSContext *cx, unsigned argc, Value *vp);
     static bool add(JSContext *cx, HandleObject obj, HandleValue key);
     static bool has(JSContext *cx, unsigned argc, Value *vp);
 
     // Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
     // interfaces, etc.)
-    static SetObject* create(JSContext *cx, HandleObject proto = nullptr);
+    static SetObject* create(JSContext *cx);
     static uint32_t size(JSContext *cx, HandleObject obj);
     static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
     static bool clear(JSContext *cx, HandleObject obj);
     static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
     static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval);
 
   private:
     static const JSPropertySpec properties[];
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -28,22 +28,17 @@ using mozilla::ArrayLength;
 using mozilla::UniquePtr;
 
 bool
 js::obj_construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject obj(cx, nullptr);
-    if (args.isConstructing() && (&args.newTarget().toObject() != &args.callee())) {
-        RootedObject newTarget(cx, &args.newTarget().toObject());
-        obj = CreateThis(cx, &PlainObject::class_, newTarget);
-        if (!obj)
-            return false;
-    } else if (args.length() > 0 && !args[0].isNullOrUndefined()) {
+    if (args.length() > 0 && !args[0].isNullOrUndefined()) {
         obj = ToObject(cx, args[0]);
         if (!obj)
             return false;
     } else {
         /* Make an object whether this was called with 'new' or not. */
         if (!NewObjectScriptedCall(cx, &obj))
             return false;
     }
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -180,17 +180,17 @@ RegExpInitialize(JSContext* cx, Handle<R
     if (staticsUse == UseRegExpStatics) {
         RegExpStatics* res = cx->global()->getRegExpStatics(cx);
         if (!res)
             return false;
         flags = RegExpFlag(flags | res->getFlags());
     }
 
     /* Steps 11-15. */
-    if (!RegExpObject::initFromAtom(cx, obj, pattern, flags))
+    if (!InitializeRegExp(cx, obj, pattern, flags))
         return false;
 
     /* Step 16. */
     return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 IsRegExpObject(HandleValue v)
@@ -263,17 +263,17 @@ regexp_compile_impl(JSContext* cx, const
             if (!RegExpToShared(cx, patternObj, &g))
                 return false;
 
             sourceAtom = g->getSource();
             flags = g->getFlags();
         }
 
         // Step 5.
-        if (!RegExpObject::initFromAtom(cx, regexp, sourceAtom, flags))
+        if (!InitializeRegExp(cx, regexp, sourceAtom, flags))
             return false;
 
         args.rval().setObject(*regexp);
         return true;
     }
 
     // Step 4.
     RootedValue P(cx, patternValue);
@@ -302,21 +302,21 @@ js::regexp_construct(JSContext* cx, unsi
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1-2.
     bool patternIsRegExp;
     if (!IsRegExp(cx, args.get(0), &patternIsRegExp))
         return false;
 
+    if (args.isConstructing()) {
+        // XXX Step 3!
+    } else {
+        // XXX Step 4a
 
-    // We can delay step 3 and step 4a until later, during
-    // GetPrototypeFromCallableConstructor calls. Accessing the new.target
-    // and the callee from the stack is unobservable.
-    if (!args.isConstructing()) {
         // Step 4b.
         if (patternIsRegExp && !args.hasDefined(1)) {
             RootedObject patternObj(cx, &args[0].toObject());
 
             // Steps 4b.i-ii.
             RootedValue patternConstructor(cx);
             if (!GetProperty(cx, patternObj, patternObj, cx->names().constructor, &patternConstructor))
                 return false;
@@ -336,53 +336,49 @@ js::regexp_construct(JSContext* cx, unsi
     if (!GetClassOfValue(cx, patternValue, &cls))
         return false;
     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());
 
-        // Step 5
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
             // Step 5.a.
             RegExpGuard g(cx);
             if (!RegExpToShared(cx, patternObj, &g))
                 return false;
             sourceAtom = g->getSource();
 
             if (!args.hasDefined(1)) {
                 // Step 5b.
                 flags = g->getFlags();
+            } else {
+                // Step 5c.
+                // XXX We shouldn't be converting to string yet!  This must
+                //     come *after* the .constructor access in step 8.
+                flags = RegExpFlag(0);
+                RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
+                if (!flagStr)
+                    return false;
+                if (!ParseRegExpFlags(cx, flagStr, &flags))
+                    return false;
             }
         }
 
         // Steps 8-9.
-        RootedObject proto(cx);
-        if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
-            return false;
-
-        Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
+        // XXX Note bug in step 5c, with respect to step 8.
+        Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
         if (!regexp)
             return false;
 
         // Step 10.
-        if (args.hasDefined(1)) {
-            // Step 5c / 21.2.3.2.2 RegExpInitialize step 5.
-            flags = RegExpFlag(0);
-            RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
-            if (!flagStr)
-                return false;
-            if (!ParseRegExpFlags(cx, flagStr, &flags))
-                return false;
-        }
-
-        if (!RegExpObject::initFromAtom(cx, regexp, sourceAtom, flags))
+        if (!InitializeRegExp(cx, regexp, sourceAtom, flags))
             return false;
 
         args.rval().setObject(*regexp);
         return true;
     }
 
     RootedValue P(cx);
     RootedValue F(cx);
@@ -403,21 +399,17 @@ js::regexp_construct(JSContext* cx, unsi
         }
     } else {
         // Steps 7a-b.
         P = patternValue;
         F = args.get(1);
     }
 
     // Steps 8-9.
-    RootedObject proto(cx);
-    if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
-        return false;
-
-    Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
+    Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
     if (!regexp)
         return false;
 
     // Step 10.
     if (!RegExpInitialize(cx, regexp, P, F, UseRegExpStatics))
         return false;
 
     args.rval().setObject(*regexp);
@@ -704,19 +696,17 @@ js::CreateRegExpPrototype(JSContext* cx,
     MOZ_ASSERT(key == JSProto_RegExp);
 
     Rooted<RegExpObject*> proto(cx, cx->global()->createBlankPrototype<RegExpObject>(cx));
     if (!proto)
         return nullptr;
     proto->NativeObject::setPrivate(nullptr);
 
     RootedAtom source(cx, cx->names().empty);
-    if (!RegExpObject::initFromAtom(cx, proto, source, RegExpFlag(0)))
-        return nullptr;
-    return proto;
+    return InitializeRegExp(cx, proto, source, RegExpFlag(0));
 }
 
 static bool
 ReportLastIndexNonwritable(JSContext* cx)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_READ_ONLY, "\"lastIndex\"");
     return false;
 }
--- a/js/src/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -311,18 +311,17 @@ static bool
 WeakMap_construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // ES6 draft rev 31 (15 Jan 2015) 23.3.1.1 step 1.
     if (!ThrowIfNotConstructing(cx, args, "WeakMap"))
         return false;
 
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    RootedObject obj(cx, CreateThis(cx, &WeakMapObject::class_, newTarget));
+    RootedObject obj(cx, NewBuiltinClassInstance(cx, &WeakMapObject::class_));
     if (!obj)
         return false;
 
     // Steps 5-6, 11.
     if (!args.get(0).isNullOrUndefined()) {
         // Steps 7a-b.
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().set, &adderVal))
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -56,48 +56,43 @@ WeakSetObject::initClass(JSContext* cx, 
         !GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakSet, ctor, proto))
     {
         return nullptr;
     }
     return proto;
 }
 
 WeakSetObject*
-WeakSetObject::create(JSContext* cx, HandleObject proto /* = nullptr */)
+WeakSetObject::create(JSContext* cx)
 {
-    RootedObject map(cx, NewBuiltinClassInstance<WeakMapObject>(cx));
-    if (!map)
+    Rooted<WeakSetObject*> obj(cx, NewBuiltinClassInstance<WeakSetObject>(cx));
+    if (!obj)
         return nullptr;
 
-    WeakSetObject* obj = NewObjectWithClassProto<WeakSetObject>(cx, proto);
-    if (!obj)
+    RootedObject map(cx, JS::NewWeakMapObject(cx));
+    if (!map)
         return nullptr;
 
     obj->setReservedSlot(WEAKSET_MAP_SLOT, ObjectValue(*map));
     return obj;
 }
 
 bool
 WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
 {
+    Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx));
+    if (!obj)
+        return false;
+
     // Based on our "Set" implementation instead of the more general ES6 steps.
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!ThrowIfNotConstructing(cx, args, "WeakSet"))
         return false;
 
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
-    if (!obj)
-        return false;
-
     if (!args.get(0).isNullOrUndefined()) {
         RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
 
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().add, &adderVal))
             return false;
 
         if (!IsCallable(adderVal))
--- a/js/src/builtin/WeakSetObject.h
+++ b/js/src/builtin/WeakSetObject.h
@@ -18,17 +18,17 @@ class WeakSetObject : public NativeObjec
 
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
   private:
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
 
-    static WeakSetObject* create(JSContext* cx, HandleObject proto = nullptr);
+    static WeakSetObject* create(JSContext* cx);
     static bool construct(JSContext* cx, unsigned argc, Value* vp);
 };
 
 extern JSObject*
 InitWeakSetClass(JSContext* cx, HandleObject obj);
 
 } // namespace js
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -422,39 +422,25 @@ void
 js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
 {
     AssertRootMarkingPhase(trc);
     DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
 
 template <typename T>
 void
-js::TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
-{
-    TraceRoot(trc, thingp->unsafeGet(), name);
-}
-
-template <typename T>
-void
 js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
 {
     AssertRootMarkingPhase(trc);
     if (InternalGCMethods<T>::isMarkableTaggedPointer(*thingp))
         DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
 
 template <typename T>
 void
-js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
-{
-    TraceNullableRoot(trc, thingp->unsafeGet(), name);
-}
-
-template <typename T>
-void
 js::TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
 {
     JS::AutoTracingIndex index(trc);
     for (auto i : MakeRange(len)) {
         if (InternalGCMethods<T>::isMarkable(vec[i].get()))
             DispatchToTracer(trc, ConvertToBase(vec[i].unsafeUnbarrieredForTracing()), name);
         ++index;
     }
@@ -474,19 +460,17 @@ js::TraceRootRange(JSTracer* trc, size_t
 }
 
 // Instantiate a copy of the Tracing templates for each derived type.
 #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \
     template void js::TraceEdge<type>(JSTracer*, WriteBarrieredBase<type>*, const char*); \
     template void js::TraceManuallyBarrieredEdge<type>(JSTracer*, type*, const char*); \
     template void js::TraceWeakEdge<type>(JSTracer*, WeakRef<type>*, const char*); \
     template void js::TraceRoot<type>(JSTracer*, type*, const char*); \
-    template void js::TraceRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
     template void js::TraceNullableRoot<type>(JSTracer*, type*, const char*); \
-    template void js::TraceNullableRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
     template void js::TraceRange<type>(JSTracer*, size_t, WriteBarrieredBase<type>*, const char*); \
     template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
 FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
 #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
 
 template <typename T>
 void
 js::TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, T* dst,
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -58,30 +58,22 @@ TraceEdge(JSTracer* trc, WriteBarrieredB
 
 // Trace through a "root" edge. These edges are the initial edges in the object
 // graph traversal. Root edges are asserted to only be traversed in the initial
 // phase of a GC.
 template <typename T>
 void
 TraceRoot(JSTracer* trc, T* thingp, const char* name);
 
-template <typename T>
-void
-TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
-
 // Idential to TraceRoot, except that this variant will not crash if |*thingp|
 // is null.
 template <typename T>
 void
 TraceNullableRoot(JSTracer* trc, T* thingp, const char* name);
 
-template <typename T>
-void
-TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
-
 // Like TraceEdge, but for edges that do not use one of the automatic barrier
 // classes and, thus, must be treated specially for moving GC. This method is
 // separate from TraceEdge to make accidental use of such edges more obvious.
 template <typename T>
 void
 TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name);
 
 // Visits a WeakRef, but does not trace its referents. If *thingp is not marked
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug976697.js
@@ -0,0 +1,15 @@
+// Test that instantiating a typed array on top of a neutered buffer
+// doesn't trip any asserts.
+//
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+x = new ArrayBuffer();
+neuter(x, "same-data");
+new Uint32Array(x);
+gc();
+
+x = new ArrayBuffer();
+neuter(x, "change-data");
+new Uint32Array(x);
+gc();
deleted file mode 100644
--- a/js/src/jit-test/tests/baseline/arraySubclassPropertyLookup.js
+++ /dev/null
@@ -1,17 +0,0 @@
-function f(v, expected) {
-  assertEq(v.prop, expected);
-};
-
-class SubArrayA extends Array {
-}
-class SubArrayB extends Array {
-}
-SubArrayA.prototype.prop = "A";
-SubArrayB.prototype.prop = "B";
-
-var a = new SubArrayA();
-var b = new SubArrayB();
-for (let i = 0; i < 10; i++) {
-  f(a, "A");
-  f(b, "B");
-}
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5703,17 +5703,17 @@ GetTemplateObjectForNative(JSContext* cx
         res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject));
         if (!res)
             return false;
         return true;
     }
 
     if (native == StringConstructor) {
         RootedString emptyString(cx, cx->runtime()->emptyString);
-        res.set(StringObject::create(cx, emptyString, /* proto = */ nullptr, TenuredObject));
+        res.set(StringObject::create(cx, emptyString, TenuredObject));
         return !!res;
     }
 
     if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
         RootedObject proto(cx, args[0].toObjectOrNull());
         res.set(ObjectCreateImpl(cx, proto, TenuredObject));
         return !!res;
     }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3055,19 +3055,19 @@ IsArrayConstructor(const Value& v)
     // constructor would be represented as a wrapper.
     return v.isObject() &&
            v.toObject().is<JSFunction>() &&
            v.toObject().as<JSFunction>().isNative() &&
            v.toObject().as<JSFunction>().native() == ArrayConstructor;
 }
 
 static bool
-ArrayFromCallArgs(JSContext* cx, CallArgs& args, HandleObject proto = nullptr)
+ArrayFromCallArgs(JSContext* cx, CallArgs& args)
 {
-    JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto);
+    JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length());
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
@@ -3178,22 +3178,18 @@ static const JSFunctionSpec array_static
 };
 
 /* ES5 15.4.2 */
 bool
 js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedObject proto(cx);
-    if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
-        return false;
-
     if (args.length() != 1 || !args[0].isNumber())
-        return ArrayFromCallArgs(cx, args, proto);
+        return ArrayFromCallArgs(cx, args);
 
     uint32_t length;
     if (args[0].isInt32()) {
         int32_t i = args[0].toInt32();
         if (i < 0) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
             return false;
         }
@@ -3202,17 +3198,17 @@ js::ArrayConstructor(JSContext* cx, unsi
         double d = args[0].toDouble();
         length = ToUint32(d);
         if (d != double(length)) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
             return false;
         }
     }
 
-    JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto);
+    JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length);
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 JSObject*
@@ -3309,37 +3305,38 @@ EnsureNewArrayElements(ExclusiveContext*
     if (!obj->ensureElements(cx, length))
         return false;
 
     MOZ_ASSERT_IF(cap, !obj->hasDynamicElements());
 
     return true;
 }
 
+static bool
+NewArrayIsCachable(ExclusiveContext* cxArg, NewObjectKind newKind)
+{
+    return cxArg->isJSContext() && newKind == GenericObject;
+}
+
 template <uint32_t maxLength>
 static MOZ_ALWAYS_INLINE ArrayObject*
 NewArray(ExclusiveContext* cxArg, uint32_t length,
          HandleObject protoArg, NewObjectKind newKind = GenericObject)
 {
     gc::AllocKind allocKind = GuessArrayGCKind(length);
     MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));
     allocKind = GetBackgroundAllocKind(allocKind);
 
-    RootedObject proto(cxArg, protoArg);
-    if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
-        return nullptr;
-
-    Rooted<TaggedProto> taggedProto(cxArg, TaggedProto(proto));
-    bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, taggedProto, newKind, &ArrayObject::class_);
+    bool isCachable = NewArrayIsCachable(cxArg, newKind);
     if (isCachable) {
         JSContext* cx = cxArg->asJSContext();
         JSRuntime* rt = cx->runtime();
         NewObjectCache& cache = rt->newObjectCache;
         NewObjectCache::EntryIndex entry = -1;
-        if (cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry)) {
+        if (cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry)) {
             gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
             AutoSetNewObjectMetadata metadata(cx);
             JSObject* obj = cache.newObjectFromHit(cx, entry, heap);
             if (obj) {
                 /* Fixup the elements pointer and length, which may be incorrect. */
                 ArrayObject* arr = &obj->as<ArrayObject>();
                 arr->setFixedElements();
                 arr->setLength(cx, length);
@@ -3348,16 +3345,20 @@ NewArray(ExclusiveContext* cxArg, uint32
                 {
                     return nullptr;
                 }
                 return arr;
             }
         }
     }
 
+    RootedObject proto(cxArg, protoArg);
+    if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
+        return nullptr;
+
     RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_,
                                                                 TaggedProto(proto)));
     if (!group)
         return nullptr;
 
     /*
      * Get a shape with zero fixed slots, regardless of the size class.
      * See JSObject::createArray.
@@ -3383,18 +3384,18 @@ NewArray(ExclusiveContext* cxArg, uint32
     }
 
     if (newKind == SingletonObject && !JSObject::setSingleton(cxArg, arr))
         return nullptr;
 
     if (isCachable) {
         NewObjectCache& cache = cxArg->asJSContext()->runtime()->newObjectCache;
         NewObjectCache::EntryIndex entry = -1;
-        cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry);
-        cache.fillProto(entry, &ArrayObject::class_, taggedProto, allocKind, arr);
+        cache.lookupGlobal(&ArrayObject::class_, cxArg->global(), allocKind, &entry);
+        cache.fillGlobal(entry, &ArrayObject::class_, cxArg->global(), allocKind, arr);
     }
 
     if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
         return nullptr;
 
     probes::CreateObject(cxArg, arr);
     return arr;
 }
@@ -3484,41 +3485,38 @@ js::NewDenseCopyOnWriteArray(JSContext* 
     if (!arr)
         return nullptr;
 
     probes::CreateObject(cx, arr);
     return arr;
 }
 
 // Return a new boxed or unboxed array with the specified length and allocated
-// capacity (up to maxLength), using the specified group if possible. If the
-// specified group cannot be used, ensure that the created array at least has
-// the given [[Prototype]].
+// capacity (up to maxLength), using the specified group if possible.
 template <uint32_t maxLength>
 static inline JSObject*
 NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
                     NewObjectKind newKind = GenericObject, bool forceAnalyze = false)
 {
     MOZ_ASSERT(newKind != SingletonObject);
 
     if (group->maybePreliminaryObjects())
         group->maybePreliminaryObjects()->maybeAnalyze(cx, group, forceAnalyze);
 
     if (group->shouldPreTenure() || group->maybePreliminaryObjects())
         newKind = TenuredObject;
 
-    RootedObject proto(cx, group->proto().toObject());
     if (group->maybeUnboxedLayout()) {
-        if (length > UnboxedArrayObject::MaximumCapacity) {
-            return NewArray<maxLength>(cx, length, proto, newKind);
-        }
+        if (length > UnboxedArrayObject::MaximumCapacity)
+            return NewArray<maxLength>(cx, length, nullptr, newKind);
+
         return UnboxedArrayObject::create(cx, group, length, newKind, maxLength);
     }
 
-    ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind);
+    ArrayObject* res = NewArray<maxLength>(cx, length, nullptr, newKind);
     if (!res)
         return nullptr;
 
     res->setGroup(group);
 
     // If the length calculation overflowed, make sure that is marked for the
     // new group.
     if (res->length() > INT32_MAX)
@@ -3587,19 +3585,19 @@ js::NewFullyAllocatedArrayForCallingAllo
 {
     RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
     if (!group)
         return nullptr;
     return NewArrayTryUseGroup<UINT32_MAX>(cx, group, length, newKind, forceAnalyze);
 }
 
 JSObject*
-js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto)
+js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length)
 {
-    RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto));
+    RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
     if (!group)
         return nullptr;
     return NewArrayTryUseGroup<ArrayObject::EagerAllocationMaxLength>(cx, group, length);
 }
 
 JSObject*
 js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
                               const Value* vp, size_t length, NewObjectKind newKind,
@@ -3649,20 +3647,19 @@ js::NewCopiedArrayTryUseGroup(ExclusiveC
     MOZ_ASSERT(result != DenseElementResult::Incomplete);
     if (result == DenseElementResult::Failure)
         return nullptr;
 
     return obj;
 }
 
 JSObject*
-js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
-                                           HandleObject proto /* = nullptr */)
+js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length)
 {
-    RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto));
+    RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
     if (!group)
         return nullptr;
     return NewCopiedArrayTryUseGroup(cx, group, vp, length);
 }
 
 #ifdef DEBUG
 bool
 js::ArrayInfo(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -96,33 +96,32 @@ extern JSObject*
 NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length);
 
 extern JSObject*
 NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length,
                                                NewObjectKind newKind = GenericObject,
                                                bool forceAnalyze = false);
 
 extern JSObject*
-NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto);
+NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length);
 
 enum class ShouldUpdateTypes
 {
     Update,
     DontUpdate
 };
 
 extern JSObject*
 NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
                           const Value* vp, size_t length,
                           NewObjectKind newKind = GenericObject,
                           ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
 
 extern JSObject*
-NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length,
-                                       HandleObject proto = nullptr);
+NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length);
 
 /*
  * Determines whether a write to the given element on |obj| should fail because
  * |obj| is an Array with a non-writable length, and writing that element would
  * increase the length of the array.
  */
 extern bool
 WouldDefinePastNonwritableLength(HandleNativeObject obj, uint32_t index);
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -111,23 +111,17 @@ static const JSFunctionSpec boolean_meth
 static bool
 Boolean(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false;
 
     if (args.isConstructing()) {
-        RootedObject newTarget (cx, &args.newTarget().toObject());
-        RootedObject proto(cx);
-
-        if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-            return false;
-
-        JSObject* obj = BooleanObject::create(cx, b, proto);
+        JSObject* obj = BooleanObject::create(cx, b);
         if (!obj)
             return false;
         args.rval().setObject(*obj);
     } else {
         args.rval().setBoolean(b);
     }
     return true;
 }
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3011,24 +3011,17 @@ static const JSFunctionSpec date_methods
     JS_FN(js_valueOf_str,        date_valueOf,            0,0),
     JS_SYM_FN(toPrimitive,       date_toPrimitive,        1,JSPROP_READONLY),
     JS_FS_END
 };
 
 static bool
 NewDateObject(JSContext* cx, const CallArgs& args, ClippedTime t)
 {
-    MOZ_ASSERT(args.isConstructing());
-
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    JSObject* obj = NewDateObjectMsec(cx, t, proto);
+    JSObject* obj = NewDateObjectMsec(cx, t);
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
@@ -3262,19 +3255,19 @@ const Class DateObject::protoClass_ = {
         nullptr,
         nullptr,
         nullptr,
         ClassSpec::IsDelegated
     }
 };
 
 JSObject*
-js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
+js::NewDateObjectMsec(JSContext* cx, ClippedTime t)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
+    JSObject* obj = NewBuiltinClassInstance(cx, &DateObject::class_);
     if (!obj)
         return nullptr;
     obj->as<DateObject>().setUTCTime(t);
     return obj;
 }
 
 JS_FRIEND_API(JSObject*)
 js::NewDateObject(JSContext* cx, int year, int mon, int mday,
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -25,17 +25,17 @@ namespace js {
  * These functions provide a C interface to the date/time object
  */
 
 /*
  * Construct a new Date Object from a time value given in milliseconds UTC
  * since the epoch.
  */
 extern JSObject*
-NewDateObjectMsec(JSContext* cx, JS::ClippedTime t, JS::HandleObject proto = nullptr);
+NewDateObjectMsec(JSContext* cx, JS::ClippedTime t);
 
 /*
  * Construct a new Date Object from an exploded local time value.
  *
  * Assert that mon < 12 to help catch off-by-one user errors, which are common
  * due to the 0-based month numbering copied into JS from Java (java.util.Date
  * in 1995).
  */
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -333,21 +333,16 @@ ExceptionStackOrNull(JSContext* cx, Hand
     return obj->as<ErrorObject>().stack();
 }
 
 bool
 Error(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString
-    RootedObject proto(cx);
-    if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
-        return false;
-
     /* Compute the error message, if any. */
     RootedString message(cx, nullptr);
     if (args.hasDefined(0)) {
         message = ToString<CanGC>(cx, args[0]);
         if (!message)
             return false;
     }
 
@@ -389,17 +384,17 @@ Error(JSContext* cx, unsigned argc, Valu
      * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
      * called as functions, without operator new.  But as we do not give
      * each constructor a distinct JSClass, we must get the exception type
      * ourselves.
      */
     JSExnType exnType = JSExnType(args.callee().as<JSFunction>().getExtendedSlot(0).toInt32());
 
     RootedObject obj(cx, ErrorObject::create(cx, exnType, stack, fileName,
-                                             lineNumber, columnNumber, nullptr, message, proto));
+                                             lineNumber, columnNumber, nullptr, message));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1587,32 +1587,16 @@ fun_isGenerator(JSContext* cx, unsigned 
         args.rval().setBoolean(false);
         return true;
     }
 
     args.rval().setBoolean(fun->isGenerator());
     return true;
 }
 
-static JSFunction*
-NewNativeFunctionWithGivenProto(JSContext* cx, Native native, unsigned nargs,
-                                HandleAtom atom, HandleObject proto)
-{
-    return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN, nullptr, atom, proto,
-                                AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto);
-}
-
-static JSFunction*
-NewNativeConstructorWithGivenProto(JSContext* cx, Native native, unsigned nargs,
-                                   HandleAtom atom, HandleObject proto)
-{
-    return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_CTOR, nullptr, atom, proto,
-                                AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto);
-}
-
 // ES6 draft rev32 19.2.3.2
 bool
 js::fun_bind(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     RootedValue thisv(cx, args.thisv());
@@ -1629,21 +1613,16 @@ js::fun_bind(JSContext* cx, unsigned arg
     if (args.length() > 1) {
         boundArgs = args.array() + 1;
         argslen = args.length() - 1;
     }
 
     RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue());
     RootedObject target(cx, &thisv.toObject());
 
-    // This is part of step 4, but we're delaying allocating the function object.
-    RootedObject proto(cx);
-    if (!GetPrototype(cx, target, &proto))
-        return false;
-
     double length = 0.0;
     // Try to avoid invoking the resolve hook.
     if (target->is<JSFunction>() && !target->as<JSFunction>().hasResolvedLength()) {
         uint16_t len;
         if (!target->as<JSFunction>().getLength(cx, &len))
             return false;
         length = Max(0.0, double(len) - argslen);
     } else {
@@ -1689,18 +1668,18 @@ js::fun_bind(JSContext* cx, unsigned arg
         return false;
 
     RootedAtom nameAtom(cx, sb.finishAtom());
     if (!nameAtom)
         return false;
 
     // Step 4.
     RootedFunction fun(cx, target->isConstructor() ?
-      NewNativeConstructorWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto) :
-      NewNativeFunctionWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto));
+      NewNativeConstructor(cx, CallOrConstructBoundFunction, length, nameAtom) :
+      NewNativeFunction(cx, CallOrConstructBoundFunction, length, nameAtom));
     if (!fun)
         return false;
 
     if (!fun->initBoundFunction(cx, target, thisArg, boundArgs, argslen))
         return false;
 
     // Steps 9-10. Set length again, because NewNativeFunction/NewNativeConstructor
     // sometimes truncates.
@@ -1857,21 +1836,17 @@ FunctionConstructor(JSContext* cx, unsig
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
     RootedObject proto(cx);
     if (isStarGenerator) {
         proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
         if (!proto)
             return false;
-    } else {
-        if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
-            return false;
     }
-
     RootedObject globalLexical(cx, &global->lexicalScope());
     RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
                                                 JSFunction::INTERPRETED_LAMBDA, globalLexical,
                                                 anonymousAtom, proto,
                                                 AllocKind::FUNCTION, TenuredObject));
     if (!fun)
         return false;
 
@@ -2033,37 +2008,30 @@ NewFunctionScopeIsWellFormed(ExclusiveCo
 }
 #endif
 
 JSFunction*
 js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
                          unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope,
                          HandleAtom atom, HandleObject proto,
                          gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
-                         NewObjectKind newKind /* = GenericObject */,
-                         NewFunctionProtoHandling protoHandling /* = NewFunctionClassProto */)
+                         NewObjectKind newKind /* = GenericObject */)
 {
     MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED);
     MOZ_ASSERT_IF(native, !enclosingDynamicScope);
     MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, enclosingDynamicScope));
 
     RootedObject funobj(cx);
     // Don't mark asm.js module functions as singleton since they are
     // cloned (via CloneFunctionObjectIfNotSingleton) which assumes that
     // isSingleton implies isInterpreted.
     if (native && !IsAsmJSModuleNative(native))
         newKind = SingletonObject;
-
-    if (protoHandling == NewFunctionClassProto) {
-        funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
-                                         newKind);
-    } else {
-        funobj = NewObjectWithGivenTaggedProto(cx, &JSFunction::class_, AsTaggedProto(proto),
-                                               allocKind, newKind);
-    }
+    funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
+                                     newKind);
     if (!funobj)
         return nullptr;
 
     RootedFunction fun(cx, &funobj->as<JSFunction>());
 
     if (allocKind == AllocKind::FUNCTION_EXTENDED)
         flags = JSFunction::Flags(flags | JSFunction::EXTENDED);
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -627,33 +627,25 @@ NewNativeConstructor(ExclusiveContext* c
 // global will be used.  In all cases the parent of the resulting object will be
 // the global.
 extern JSFunction*
 NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
                     HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
                     NewObjectKind newKind = GenericObject,
                     HandleObject enclosingDynamicScope = nullptr);
 
-// By default, if proto is nullptr, Function.prototype is used instead.i
-// If protoHandling is NewFunctionExactProto, and proto is nullptr, the created
-// function will use nullptr as its [[Prototype]] instead. If
+// If proto is nullptr, Function.prototype is used instead.  If
 // enclosingDynamicScope is null, the function will have a null environment()
 // (yes, null, not the global).  In all cases, the global will be used as the
 // parent.
-
-enum NewFunctionProtoHandling {
-    NewFunctionClassProto,
-    NewFunctionGivenProto
-};
 extern JSFunction*
 NewFunctionWithProto(ExclusiveContext* cx, JSNative native, unsigned nargs,
                      JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom,
                      HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
-                     NewObjectKind newKind = GenericObject,
-                     NewFunctionProtoHandling protoHandling = NewFunctionClassProto);
+                     NewObjectKind newKind = GenericObject);
 
 extern JSAtom*
 IdToFunctionName(JSContext* cx, HandleId id);
 
 extern JSFunction*
 DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
                unsigned nargs, unsigned flags,
                gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -483,21 +483,17 @@ Number(JSContext* cx, unsigned argc, Val
         args.rval().set(args[0]);
     } else {
         args.rval().setInt32(0);
     }
 
     if (!isConstructing)
         return true;
 
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    RootedObject proto(cx);
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-    JSObject* obj = NumberObject::create(cx, args.rval().toNumber(), proto);
+    JSObject* obj = NumberObject::create(cx, args.rval().toNumber());
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 IsNumber(HandleValue v)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -684,19 +684,19 @@ void
 NewObjectCache::fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
                           gc::AllocKind kind, NativeObject* obj)
 {
     MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->is<GlobalObject>());
     MOZ_ASSERT(obj->getTaggedProto() == proto);
     return fill(entry, clasp, proto.raw(), kind, obj);
 }
 
-bool
-js::NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
-                                       NewObjectKind newKind, const Class* clasp)
+static bool
+NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
+                                   NewObjectKind newKind, const Class* clasp)
 {
     return cxArg->isJSContext() &&
            proto.isObject() &&
            newKind == GenericObject &&
            clasp->isNative() &&
            !proto.toObject()->is<GlobalObject>();
 }
 
@@ -878,19 +878,21 @@ js::NewObjectScriptedCall(JSContext* cx,
 
     pobj.set(obj);
     return true;
 }
 
 JSObject*
 js::CreateThis(JSContext* cx, const Class* newclasp, HandleObject callee)
 {
-    RootedObject proto(cx);
-    if (!GetPrototypeFromConstructor(cx, callee, &proto))
+    RootedValue protov(cx);
+    if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov))
         return nullptr;
+
+    RootedObject proto(cx, protov.isObjectOrNull() ? protov.toObjectOrNull() : nullptr);
     gc::AllocKind kind = NewObjectGCKind(newclasp);
     return NewObjectWithClassProto(cx, newclasp, proto, kind);
 }
 
 static inline JSObject*
 CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
                                NewObjectKind newKind)
 {
@@ -982,45 +984,26 @@ js::CreateThisForFunctionWithProto(JSCon
         if (!script)
             return nullptr;
         TypeScript::SetThis(cx, script, TypeSet::ObjectType(res));
     }
 
     return res;
 }
 
-bool
-js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget, MutableHandleObject proto)
-{
-    RootedValue protov(cx);
-    if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
-        return false;
-    proto.set(protov.isObject() ? &protov.toObject() : nullptr);
-    return true;
-}
-
-bool
-js::GetPrototypeFromCallableConstructor(JSContext* cx, const CallArgs& args, MutableHandleObject proto)
-{
-    RootedObject newTarget(cx);
-    if (args.isConstructing())
-        newTarget = &args.newTarget().toObject();
-    else
-        newTarget = &args.callee();
-    return GetPrototypeFromConstructor(cx, newTarget, proto);
-}
-
 JSObject*
 js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget,
                           NewObjectKind newKind)
 {
+    RootedValue protov(cx);
+    if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
+        return nullptr;
     RootedObject proto(cx);
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return nullptr;
-
+    if (protov.isObject())
+        proto = &protov.toObject();
     JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
 
     if (obj && newKind == SingletonObject) {
         RootedPlainObject nobj(cx, &obj->as<PlainObject>());
 
         /* Reshape the singleton before passing it as the 'this' value. */
         NativeObject::clear(cx, nobj);
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1084,27 +1084,16 @@ GetInitialHeap(NewObjectKind newKind, co
 {
     if (newKind != GenericObject)
         return gc::TenuredHeap;
     if (clasp->finalize && !(clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE))
         return gc::TenuredHeap;
     return gc::DefaultHeap;
 }
 
-bool
-NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
-                                   NewObjectKind newKind, const Class* clasp);
-
-// ES6 9.1.15 GetPrototypeFromConstructor.
-extern bool
-GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto);
-
-extern bool
-GetPrototypeFromCallableConstructor(JSContext* cx, const CallArgs& args, js::MutableHandleObject proto);
-
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
 extern JSObject*
 CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
                                HandleObject proto, NewObjectKind newKind = GenericObject);
 
 // Specialized call for constructing |this| with a known function callee.
 extern JSObject*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -682,34 +682,16 @@ NewObjectWithClassProto(ExclusiveContext
 inline JSObject*
 NewObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
                         NewObjectKind newKind = GenericObject)
 {
     gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
     return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind);
 }
 
-template<class T>
-inline T*
-NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto,
-                        NewObjectKind newKind = GenericObject)
-{
-    JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind);
-    return obj ? &obj->as<T>() : nullptr;
-}
-
-template <class T>
-inline T*
-NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto, gc::AllocKind allocKind,
-                        NewObjectKind newKind = GenericObject)
-{
-    JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind);
-    return obj ? &obj->as<T>() : nullptr;
-}
-
 /*
  * Create a native instance of the given class with parent and proto set
  * according to the context's active global.
  */
 inline JSObject*
 NewBuiltinClassInstance(ExclusiveContext* cx, const Class* clasp, gc::AllocKind allocKind,
                         NewObjectKind newKind = GenericObject)
 {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4076,22 +4076,17 @@ js::StringConstructor(JSContext* cx, uns
         str = ToString<CanGC>(cx, args[0]);
         if (!str)
             return false;
     } else {
         str = cx->runtime()->emptyString;
     }
 
     if (args.isConstructing()) {
-        RootedObject proto(cx);
-        RootedObject newTarget(cx, &args.newTarget().toObject());
-        if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-            return false;
-
-        StringObject* strobj = StringObject::create(cx, str, proto);
+        StringObject* strobj = StringObject::create(cx, str);
         if (!strobj)
             return false;
         args.rval().setObject(*strobj);
         return true;
     }
 
     args.rval().setString(str);
     return true;
deleted file mode 100644
--- a/js/src/tests/ecma_6/Class/boundFunctionSubclassing.js
+++ /dev/null
@@ -1,24 +0,0 @@
-var test = `
-
-class func extends Function { }
-let inst = new func("x", "return this.bar + x");
-
-// First, ensure that we get sane prototype chains for the bound instance
-let bound = inst.bind({bar: 3}, 4);
-assertEq(bound instanceof func, true);
-assertEq(bound(), 7);
-
-// Check the corner case for Function.prototype.bind where the function has
-// a null [[Prototype]]
-Object.setPrototypeOf(inst, null);
-bound = Function.prototype.bind.call(inst, {bar:1}, 3);
-assertEq(Object.getPrototypeOf(bound), null);
-assertEq(bound(), 4);
-
-`;
-
-if (classesEnabled())
-    eval(test);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
+++ /dev/null
@@ -1,112 +0,0 @@
-var test = `
-
-function testBuiltinInstanceIsInstanceOf(instance, builtin, class_) {
-    assertEq(instance instanceof class_, true);
-    assertEq(instance instanceof builtin, true);
-
-    if (builtin === Array)
-        assertEq(Array.isArray(instance), true);
-}
-
-function testBuiltinInstance(builtin, ...args) {
-    class sub extends builtin {
-        constructor(...args) {
-            super(...args);
-            this.called = true;
-        }
-    }
-
-    let instance = new sub(...args);
-    assertEq(instance.called, true);
-    testBuiltinInstanceIsInstanceOf(instance, builtin, sub);
-}
-
-function testBuiltinMultipleSubclasses(builtin, ...args) {
-    function f(obj, prop) {
-        assertEq(obj.prop, prop);
-    }
-
-    class sub1 extends builtin { };
-    class sub2 extends builtin { };
-
-    const prop1 = "A";
-    const prop2 = "B";
-
-    sub1.prototype.prop = prop1;
-    sub2.prototype.prop = prop2;
-
-    let instance1 = new sub1(...args);
-    let instance2 = new sub2(...args);
-
-    // Also make sure we get the properties we want with a default constructor
-    testBuiltinInstanceIsInstanceOf(instance1, builtin, sub1);
-
-    for (let i = 0; i < 10; i++) {
-        f(instance1, prop1);
-        f(instance2, prop2);
-    }
-}
-
-function testBuiltin(builtin, ...args) {
-    testBuiltinInstance(builtin, ...args);
-    testBuiltinMultipleSubclasses(builtin, ...args);
-}
-
-function testBuiltinTypedArrays() {
-    let typedArrays = [Int8Array,
-                       Uint8Array,
-                       Uint8ClampedArray,
-                       Int16Array,
-                       Uint16Array,
-                       Int32Array,
-                       Uint32Array,
-                       Float32Array,
-                       Float64Array];
-
-    for (let array of typedArrays) {
-        testBuiltin(array);
-        testBuiltin(array, 5);
-        testBuiltin(array, new array());
-        testBuiltin(array, new ArrayBuffer());
-    }
-}
-
-testBuiltin(Function);
-testBuiltin(Object);
-testBuiltin(Boolean);
-testBuiltin(Error);
-testBuiltin(EvalError);
-testBuiltin(RangeError);
-testBuiltin(ReferenceError);
-testBuiltin(SyntaxError);
-testBuiltin(TypeError);
-testBuiltin(URIError);
-testBuiltin(Number);
-testBuiltin(Date);
-testBuiltin(Date, 5);
-testBuiltin(Date, 5, 10);
-testBuiltin(RegExp);
-testBuiltin(RegExp, /Regexp Argument/);
-testBuiltin(RegExp, "String Argument");
-testBuiltin(Map);
-testBuiltin(Set);
-testBuiltin(WeakMap);
-testBuiltin(WeakSet);
-testBuiltin(ArrayBuffer);
-testBuiltinTypedArrays();
-testBuiltin(DataView, new ArrayBuffer());
-testBuiltin(DataView, new (newGlobal().ArrayBuffer)());
-testBuiltin(String);
-testBuiltin(Array);
-testBuiltin(Array, 15);
-testBuiltin(Array, 3.0);
-testBuiltin(Array, "non-length one-arg");
-testBuiltin(Array, 5, 10, 15, "these are elements");
-
-`;
-
-if (classesEnabled())
-    eval(test);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js
+++ /dev/null
@@ -1,29 +0,0 @@
-var test = `
-
-class foo extends Array { }
-
-function testArrs(arrs) {
-    for (let arr of arrs) {
-        assertEq(Object.getPrototypeOf(arr), foo.prototype);
-    }
-}
-
-var arrs = [];
-for (var i = 0; i < 25; i++)
-    arrs.push(new foo(1));
-
-testArrs(arrs);
-
-arrs[0].nonIndexedProp = "uhoh";
-
-arrs.push(new foo(1));
-
-testArrs(arrs);
-
-`;
-
-if (classesEnabled())
-    eval(test);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
--- a/js/src/tests/ecma_6/Class/superCallBaseInvoked.js
+++ b/js/src/tests/ecma_6/Class/superCallBaseInvoked.js
@@ -48,15 +48,17 @@ testBase(baseFunc);
 
 let handler = {};
 let p = new Proxy(baseFunc, handler);
 testBase(p);
 
 handler.construct = (target, args, nt) => Reflect.construct(target, args, nt);
 testBase(p);
 
+// Object will have to wait for fixed builtins.
+
 `;
 
 if (classesEnabled())
     eval(test);
 
 if (typeof reportCompare === 'function')
     reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/DataView/detach-after-construction.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-
-for (var neuterArg of ['change-data', 'same-data']) {
-    var buf = new ArrayBuffer([1,2]);
-    var bufView = new DataView(buf);
-
-    neuter(buf, neuterArg);
-
-    assertThrowsInstanceOf(()=>bufView.getInt8(0), TypeError);
-}
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
--- a/js/src/tests/ecma_6/Reflect/construct.js
+++ b/js/src/tests/ecma_6/Reflect/construct.js
@@ -96,16 +96,18 @@ for (var ctor of constructors) {
 for (var v of SOME_PRIMITIVE_VALUES.concat(nonConstructors)) {
     assertThrowsInstanceOf(() => Reflect.construct(checkNewTarget, [], v), TypeError);
 }
 
 // The builtin Array constructor uses new.target.prototype and always
 // creates a real array object.
 function someConstructor() {}
 var result = Reflect.construct(Array, [], someConstructor);
-assertEq(Reflect.getPrototypeOf(result), someConstructor.prototype);
+assertEq(Reflect.getPrototypeOf(result),
+         Array.prototype, // should be someConstructor.prototype, per ES6 22.1.1.1 Array()
+        "Congratulations on implementing Array subclassing! Fix this test for +1 karma point.");
 assertEq(result.length, 0);
 assertEq(Array.isArray(result), true);
 
 
 // For more Reflect.construct tests, see target.js and argumentsList.js.
 
 reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/constructor-ordering-2.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Make sure that we don't ToString the second argument until /after/ doing
-// the appropriate subclassing lookups
-
-var didLookup = false;
-
-var re = /a/;
-var flags = { toString() { assertEq(didLookup, true); return "g"; } };
-var newRe = Reflect.construct(RegExp, [re, flags],
-                              Object.defineProperty(function(){}.bind(null), "prototype", {
-  get() {
-    didLookup = true;
-    return RegExp.prototype;
-  }
-}));
-
-assertEq(Object.getPrototypeOf(newRe), RegExp.prototype);
-assertEq(didLookup, true);
-
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/constructor-ordering.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Make sure that we don't misorder subclassing accesses with respect to
-// accessing regex arg internal slots
-//
-// Test credit André Bargull.
-
-var re = /a/;
-var newRe = Reflect.construct(RegExp, [re], Object.defineProperty(function(){}.bind(null), "prototype", {
-  get() {
-    re.compile("b");
-    return RegExp.prototype;
-  }
-}));
-assertEq(newRe.source, "a");
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedArray/constructor-non-detached.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-
-const constructors = [
-    Int8Array,
-    Uint8Array,
-    Uint8ClampedArray,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array
-];
-
-for (var constructor of constructors) {
-    for (var neuterType of ["change-data", "same-data"]) {
-        var buf = new constructor();
-        neuter(buf.buffer, neuterType);
-        assertThrowsInstanceOf(()=> new constructor(buf), TypeError);
-
-        var buffer = new ArrayBuffer();
-        neuter(buffer, neuterType);
-        assertThrowsInstanceOf(()=> new constructor(buffer), TypeError);
-    }
-}
-
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/js1_5/Error/constructor-ordering.js
+++ /dev/null
@@ -1,17 +0,0 @@
-var order = 0;
-function assertOrdering(ordering) {
-    assertEq(order, ordering);
-    order++;
-}
-
-// Spec mandates that the prototype is looked up /before/ we toString the
-// argument.
-var handler = { get() { assertOrdering(0); return Error.prototype } };
-var errorProxy = new Proxy(Error, handler);
-
-var toStringable = { toString() { assertOrdering(1); return "Argument"; } };
-
-new errorProxy(toStringable);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -471,22 +471,17 @@ ArrayBufferObject::class_constructor(JSC
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer value; if someone actually ever complains (validly), then we
          * can fix.
          */
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
         return false;
     }
 
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    JSObject* bufobj = create(cx, uint32_t(nbytes), proto);
+    JSObject* bufobj = create(cx, uint32_t(nbytes));
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 static ArrayBufferObject::BufferContents
 AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
@@ -785,17 +780,16 @@ void
 ArrayBufferObject::setFlags(uint32_t flags)
 {
     setSlot(FLAGS_SLOT, Int32Value(flags));
 }
 
 ArrayBufferObject*
 ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
                           OwnsState ownsState /* = OwnsData */,
-                          HandleObject proto /* = nullptr */,
                           NewObjectKind newKind /* = GenericObject */)
 {
     MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
 
     // If we need to allocate data, try to use a larger object size class so
     // that the array buffer's data can be allocated inline with the object.
     // The extra space will be left unused by the object's fixed slots and
     // available for the buffer's data, see NewObject().
@@ -826,18 +820,17 @@ ArrayBufferObject::create(JSContext* cx,
             allocated = true;
         }
     }
 
     MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
     gc::AllocKind allocKind = GetGCObjectKind(nslots);
 
     AutoSetNewObjectMetadata metadata(cx);
-    Rooted<ArrayBufferObject*> obj(cx,
-        NewObjectWithClassProto<ArrayBufferObject>(cx, proto, allocKind, newKind));
+    Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx, allocKind, newKind));
     if (!obj) {
         if (allocated)
             js_free(contents.data());
         return nullptr;
     }
 
     MOZ_ASSERT(obj->getClass() == &class_);
     MOZ_ASSERT(!gc::IsInsideNursery(obj));
@@ -850,21 +843,19 @@ ArrayBufferObject::create(JSContext* cx,
         obj->initialize(nbytes, contents, ownsState);
     }
 
     return obj;
 }
 
 ArrayBufferObject*
 ArrayBufferObject::create(JSContext* cx, uint32_t nbytes,
-                          HandleObject proto /* = nullptr */,
                           NewObjectKind newKind /* = GenericObject */)
 {
-    return create(cx, nbytes, BufferContents::createPlain(nullptr),
-                  OwnsState::OwnsData, proto);
+    return create(cx, nbytes, BufferContents::createPlain(nullptr));
 }
 
 JSObject*
 ArrayBufferObject::createSlice(JSContext* cx, Handle<ArrayBufferObject*> arrayBuffer,
                                uint32_t begin, uint32_t end)
 {
     uint32_t bufLength = arrayBuffer->byteLength();
     if (begin > bufLength || end > bufLength || begin > end) {
@@ -886,35 +877,31 @@ ArrayBufferObject::createSlice(JSContext
 
 bool
 ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(IsArrayBuffer(args.thisv()));
 
     /*
      * This method is only called for |DataView(alienBuf, ...)| which calls
-     * this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength,
-     *                                     DataView.prototype)|,
-     * ergo there must be exactly 3 arguments.
+     * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
+     * ergo there must be at least two arguments.
      */
-    MOZ_ASSERT(args.length() == 3);
+    MOZ_ASSERT(args.length() >= 2);
 
-    uint32_t byteOffset = args[0].toPrivateUint32();
-    uint32_t byteLength = args[1].toPrivateUint32();
-    Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
+    Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
+
+    Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
 
     /*
      * Pop off the passed-along prototype and delegate to normal DataViewObject
      * construction.
      */
-    JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject());
-    if (!obj)
-        return false;
-    args.rval().setObject(*obj);
-    return true;
+    CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
+    return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
 }
 
 bool
 ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
 }
@@ -1396,18 +1383,17 @@ JS_NewSharedArrayBuffer(JSContext* cx, u
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
 {
     MOZ_ASSERT_IF(!data, nbytes == 0);
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
-                                     /* proto = */ nullptr, TenuredObject);
+    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject);
 }
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferObject(JSObject* obj)
 {
     obj = CheckedUnwrap(obj);
     return obj && obj->is<ArrayBufferObject>();
 }
@@ -1462,18 +1448,17 @@ JS_StealArrayBufferContents(JSContext* c
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data)
 {
     MOZ_ASSERT(data);
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED>(data);
-    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData,
-                                     /* proto = */ nullptr, TenuredObject);
+    return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject);
 }
 
 JS_PUBLIC_API(void*)
 JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
 {
     return ArrayBufferObject::createMappedContents(fd, offset, length).data();
 }
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -213,20 +213,18 @@ class ArrayBufferObject : public ArrayBu
     static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp);
 #endif
 
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
 
     static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
                                      BufferContents contents,
                                      OwnsState ownsState = OwnsData,
-                                     HandleObject proto = nullptr,
                                      NewObjectKind newKind = GenericObject);
     static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
-                                     HandleObject proto = nullptr,
                                      NewObjectKind newKind = GenericObject);
 
     static JSObject* createSlice(JSContext* cx, Handle<ArrayBufferObject*> arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static bool createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
     static bool createDataViewForThis(JSContext* cx, unsigned argc, Value* vp);
 
--- a/js/src/vm/BooleanObject-inl.h
+++ b/js/src/vm/BooleanObject-inl.h
@@ -9,20 +9,21 @@
 
 #include "vm/BooleanObject.h"
 
 #include "jsobjinlines.h"
 
 namespace js {
 
 inline BooleanObject*
-BooleanObject::create(JSContext* cx, bool b, HandleObject proto /* = nullptr */)
+BooleanObject::create(JSContext* cx, bool b)
 {
-    BooleanObject* obj = NewObjectWithClassProto<BooleanObject>(cx, proto);
+    JSObject* obj = NewBuiltinClassInstance(cx, &class_);
     if (!obj)
         return nullptr;
-    obj->setPrimitiveValue(b);
-    return obj;
+    BooleanObject& boolobj = obj->as<BooleanObject>();
+    boolobj.setPrimitiveValue(b);
+    return &boolobj;
 }
 
 } // namespace js
 
 #endif /* vm_BooleanObject_inl_h */
--- a/js/src/vm/BooleanObject.h
+++ b/js/src/vm/BooleanObject.h
@@ -19,21 +19,20 @@ class BooleanObject : public NativeObjec
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
     /*
-     * Creates a new Boolean object boxing the given primitive bool.
-     * If proto is nullptr, the [[Prototype]] will default to Boolean.prototype.
+     * Creates a new Boolean object boxing the given primitive bool.  The
+     * object's [[Prototype]] is determined from context.
      */
-    static inline BooleanObject* create(JSContext* cx, bool b,
-                                        HandleObject proto = nullptr);
+    static inline BooleanObject* create(JSContext* cx, bool b);
 
     bool unbox() const {
         return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBoolean();
     }
 
   private:
     inline void setPrimitiveValue(bool b) {
         setFixedSlot(PRIMITIVE_VALUE_SLOT, BooleanValue(b));
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -79,27 +79,23 @@ js::ErrorObject::init(JSContext* cx, Han
         obj->setSlotWithType(cx, messageShape, StringValue(message));
 
     return true;
 }
 
 /* static */ ErrorObject*
 js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack,
                         HandleString fileName, uint32_t lineNumber, uint32_t columnNumber,
-                        ScopedJSFreePtr<JSErrorReport>* report, HandleString message,
-                        HandleObject protoArg /* = nullptr */)
+                        ScopedJSFreePtr<JSErrorReport>* report, HandleString message)
 {
     AssertObjectIsSavedFrameOrWrapper(cx, stack);
 
-    RootedObject proto(cx, protoArg);
-    if (!proto) {
-        proto = GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType);
-        if (!proto)
-            return nullptr;
-    }
+    Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType));
+    if (!proto)
+        return nullptr;
 
     Rooted<ErrorObject*> errObject(cx);
     {
         const Class* clasp = ErrorObject::classForType(errorType);
         JSObject* obj = NewObjectWithGivenProto(cx, clasp, proto);
         if (!obj)
             return nullptr;
         errObject = &obj->as<ErrorObject>();
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -67,17 +67,17 @@ class ErrorObject : public NativeObject
 
     // Create an error of the given type corresponding to the provided location
     // info.  If |message| is non-null, then the error will have a .message
     // property with that value; otherwise the error will have no .message
     // property.
     static ErrorObject*
     create(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName,
            uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr<JSErrorReport>* report,
-           HandleString message, HandleObject proto = nullptr);
+           HandleString message);
 
     /*
      * Assign the initial error shape to the empty object.  (This shape does
      * *not* include .message, which must be added separately if needed; see
      * ErrorObject::init.)
      */
     static Shape*
     assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> obj);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4699,17 +4699,30 @@ js::DefaultClassConstructor(JSContext* c
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.isConstructing()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
         return false;
     }
 
     RootedObject newTarget(cx, &args.newTarget().toObject());
-    JSObject* obj = CreateThis(cx, &PlainObject::class_, newTarget);
+    RootedValue protoVal(cx);
+
+    if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protoVal))
+        return false;
+
+    RootedObject proto(cx);
+    if (!protoVal.isObject()) {
+        if (!GetBuiltinPrototype(cx, JSProto_Object, &proto))
+            return false;
+    } else {
+        proto = &protoVal.toObject();
+    }
+
+    JSObject* obj = NewObjectWithGivenProto(cx, &PlainObject::class_, proto);
     if (!obj)
         return false;
 
     args.rval().set(ObjectValue(*obj));
     return true;
 }
 
 bool
--- a/js/src/vm/NumberObject-inl.h
+++ b/js/src/vm/NumberObject-inl.h
@@ -9,20 +9,21 @@
 
 #include "vm/NumberObject.h"
 
 #include "jsobjinlines.h"
 
 namespace js {
 
 inline NumberObject*
-NumberObject::create(JSContext* cx, double d, HandleObject proto /* = nullptr */)
+NumberObject::create(JSContext* cx, double d)
 {
-    NumberObject* obj = NewObjectWithClassProto<NumberObject>(cx, proto);
+    JSObject* obj = NewBuiltinClassInstance(cx, &class_);
     if (!obj)
         return nullptr;
-    obj->setPrimitiveValue(d);
-    return obj;
+    NumberObject& numobj = obj->as<NumberObject>();
+    numobj.setPrimitiveValue(d);
+    return &numobj;
 }
 
 } // namespace js
 
 #endif /* vm_NumberObject_inl_h */
--- a/js/src/vm/NumberObject.h
+++ b/js/src/vm/NumberObject.h
@@ -17,21 +17,20 @@ class NumberObject : public NativeObject
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
     /*
-     * Creates a new Number object boxing the given number.
-     * If proto is nullptr, then Number.prototype will be used instead.
+     * Creates a new Number object boxing the given number.  The object's
+     * [[Prototype]] is determined from context.
      */
-    static inline NumberObject* create(JSContext* cx, double d,
-                                       HandleObject proto = nullptr);
+    static inline NumberObject* create(JSContext* cx, double d);
 
     double unbox() const {
         return getFixedSlot(PRIMITIVE_VALUE_SLOT).toNumber();
     }
 
   private:
     inline void setPrimitiveValue(double d) {
         setFixedSlot(PRIMITIVE_VALUE_SLOT, NumberValue(d));
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1352,107 +1352,74 @@ ObjectGroup::newPlainObject(ExclusiveCon
 
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroupCompartment AllocationSiteTable
 /////////////////////////////////////////////////////////////////////
 
-struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey>,
-                                                   public JS::Traceable {
-    ReadBarrieredScript script;
+struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
+    JSScript* script;
 
     uint32_t offset : 24;
     JSProtoKey kind : 8;
 
-    ReadBarrieredObject proto;
-
     static const uint32_t OFFSET_LIMIT = (1 << 23);
 
-    AllocationSiteKey(JSScript* script_, uint32_t offset_, JSProtoKey kind_, JSObject* proto_)
-      : script(script_), offset(offset_), kind(kind_), proto(proto_)
-    {
-        MOZ_ASSERT(offset_ < OFFSET_LIMIT);
-    }
-
-    AllocationSiteKey(AllocationSiteKey&& key)
-      : script(mozilla::Move(key.script)),
-        offset(key.offset),
-        kind(key.kind),
-        proto(mozilla::Move(key.proto))
-    { }
-
-    AllocationSiteKey(const AllocationSiteKey& key)
-      : script(key.script),
-        offset(key.offset),
-        kind(key.kind),
-        proto(key.proto)
-    { }
+    AllocationSiteKey() { mozilla::PodZero(this); }
 
     static inline uint32_t hash(AllocationSiteKey key) {
-        return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind ^
-               MovableCellHasher<JSObject*>::hash(key.proto));
+        return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind);
     }
 
     static inline bool match(const AllocationSiteKey& a, const AllocationSiteKey& b) {
-        return DefaultHasher<JSScript*>::match(a.script, b.script) &&
-               a.offset == b.offset &&
-               a.kind == b.kind &&
-               MovableCellHasher<JSObject*>::match(a.proto, b.proto);
-    }
-
-    static void trace(AllocationSiteKey* key, JSTracer* trc) {
-        TraceRoot(trc, &key->script, "AllocationSiteKey script");
-        TraceNullableRoot(trc, &key->proto, "AllocationSiteKey proto");
+        return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
     }
 };
 
 /* static */ ObjectGroup*
-ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* pc,
-                                 JSProtoKey kind, HandleObject protoArg /* = nullptr */)
+ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
+                                 JSProtoKey kind)
 {
-    MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
-    MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
+    MOZ_ASSERT(!useSingletonForAllocationSite(script, pc, kind));
+
+    uint32_t offset = script->pcToOffset(pc);
 
-    uint32_t offset = scriptArg->pcToOffset(pc);
+    if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT)
+        return defaultNewGroup(cx, kind);
 
-    if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) {
-        if (protoArg)
-            return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg));
-        return defaultNewGroup(cx, kind);
-    }
+    ObjectGroupCompartment::AllocationSiteKey key;
+    key.script = script;
+    key.offset = offset;
+    key.kind = kind;
 
     ObjectGroupCompartment::AllocationSiteTable*& table =
         cx->compartment()->objectGroups.allocationSiteTable;
 
     if (!table) {
         table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>();
         if (!table || !table->init()) {
             ReportOutOfMemory(cx);
             js_delete(table);
             table = nullptr;
             return nullptr;
         }
     }
 
-    RootedScript script(cx, scriptArg);
-    RootedObject proto(cx, protoArg);
-    if (!proto && kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto))
-        return nullptr;
-
-    Rooted<ObjectGroupCompartment::AllocationSiteKey> key(cx,
-        ObjectGroupCompartment::AllocationSiteKey(script, offset, kind, proto));
-
     ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
     if (p)
         return p->value();
 
     AutoEnterAnalysis enter(cx);
 
+    RootedObject proto(cx);
+    if (kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto))
+        return nullptr;
+
     Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
     ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged,
                                                          OBJECT_FLAG_FROM_ALLOCATION_SITE);
     if (!res)
         return nullptr;
 
     if (JSOp(*pc) == JSOP_NEWOBJECT) {
         // Keep track of the preliminary objects with this group, so we can try
@@ -1487,39 +1454,38 @@ ObjectGroup::allocationSiteGroup(JSConte
 
     return res;
 }
 
 void
 ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
                                                    JSProtoKey kind, ObjectGroup* group)
 {
-    AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
+    AllocationSiteKey key;
+    key.script = script;
+    key.offset = script->pcToOffset(pc);
+    key.kind = kind;
 
     AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
     MOZ_RELEASE_ASSERT(p);
     allocationSiteTable->remove(p);
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!allocationSiteTable->putNew(key, group))
             oomUnsafe.crash("Inconsistent object table");
     }
 }
 
 /* static */ ObjectGroup*
-ObjectGroup::callingAllocationSiteGroup(JSContext* cx, JSProtoKey key, HandleObject proto)
+ObjectGroup::callingAllocationSiteGroup(JSContext* cx, JSProtoKey key)
 {
-    MOZ_ASSERT_IF(proto, key == JSProto_Array);
-
     jsbytecode* pc;
     RootedScript script(cx, cx->currentScript(&pc));
     if (script)
-        return allocationSiteGroup(cx, script, pc, key, proto);
-    if (proto)
-        return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto));
+        return allocationSiteGroup(cx, script, pc, key);
     return defaultNewGroup(cx, key);
 }
 
 /* static */ bool
 ObjectGroup::setAllocationSiteObjectGroup(JSContext* cx,
                                           HandleScript script, jsbytecode* pc,
                                           HandleObject obj, bool singleton)
 {
@@ -1794,21 +1760,23 @@ ObjectGroupCompartment::sweep(FreeOp* fo
                 js_free(entry.types);
                 e.removeFront();
             }
         }
     }
 
     if (allocationSiteTable) {
         for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) {
-            bool keyDying = IsAboutToBeFinalized(&e.front().mutableKey().script) ||
-                            (e.front().key().proto && IsAboutToBeFinalized(&e.front().mutableKey().proto));
+            AllocationSiteKey key = e.front().key();
+            bool keyDying = IsAboutToBeFinalizedUnbarriered(&key.script);
             bool valDying = IsAboutToBeFinalized(&e.front().value());
             if (keyDying || valDying)
                 e.removeFront();
+            else if (key.script != e.front().key().script)
+                e.rekeyFront(key);
         }
     }
 
     sweepNewTable(defaultNewTable);
     sweepNewTable(lazyTable);
 }
 
 void
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -505,21 +505,20 @@ class ObjectGroup : public gc::TenuredCe
                                     IdValuePair* properties, size_t nproperties,
                                     NewObjectKind newKind);
 
     // Static accessors for ObjectGroupCompartment AllocationSiteTable.
 
     // Get a non-singleton group to use for objects created at the specified
     // allocation site.
     static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
-                                            JSProtoKey key, HandleObject proto = nullptr);
+                                            JSProtoKey key);
 
     // Get a non-singleton group to use for objects created in a JSNative call.
-    static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key,
-                                                   HandleObject proto = nullptr);
+    static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key);
 
     // Set the group or singleton-ness of an object created for an allocation site.
     static bool
     setAllocationSiteObjectGroup(JSContext* cx, HandleScript script, jsbytecode* pc,
                                  HandleObject obj, bool singleton);
 
     static ArrayObject* getOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script,
                                                     jsbytecode* pc);
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -36,27 +36,35 @@ using js::frontend::TokenStream;
 using JS::AutoCheckCannotGC;
 
 JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
 JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
 JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
 JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
 
 RegExpObject*
-js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
+js::RegExpAlloc(ExclusiveContext* cx)
 {
     // Note: RegExp objects are always allocated in the tenured heap. This is
     // not strictly required, but simplifies embedding them in jitcode.
-    RegExpObject* regexp = NewObjectWithClassProto<RegExpObject>(cx, proto, TenuredObject);
+    RegExpObject* regexp = NewBuiltinClassInstance<RegExpObject>(cx, TenuredObject);
     if (!regexp)
         return nullptr;
+
     regexp->initPrivate(nullptr);
     return regexp;
 }
 
+RegExpObject*
+js::InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
+                     RegExpFlag flags)
+{
+    return regexp->init(cx, source, flags) ? regexp : nullptr;
+}
+
 /* MatchPairs */
 
 bool
 MatchPairs::initArrayFrom(MatchPairs& copyFrom)
 {
     MOZ_ASSERT(copyFrom.pairCount() > 0);
 
     if (!allocOrExpandArray(copyFrom.pairCount()))
@@ -142,23 +150,16 @@ RegExpObject::trace(JSTracer* trc, JSObj
         !obj->asTenured().zone()->isPreservingCode())
     {
         obj->as<RegExpObject>().NativeObject::setPrivate(nullptr);
     } else {
         shared->trace(trc);
     }
 }
 
-/* static */ bool
-RegExpObject::initFromAtom(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
-                           RegExpFlag flags)
-{
-    return regexp->init(cx, source, flags);
-}
-
 const Class RegExpObject::class_ = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
@@ -218,20 +219,17 @@ RegExpObject::createNoStatics(ExclusiveC
 
     if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source))
         return nullptr;
 
     Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
     if (!regexp)
         return nullptr;
 
-    if (!RegExpObject::initFromAtom(cx, regexp, source, flags))
-        return nullptr;
-
-    return regexp;
+    return InitializeRegExp(cx, regexp, source, flags);
 }
 
 bool
 RegExpObject::createShared(JSContext* cx, RegExpGuard* g)
 {
     Rooted<RegExpObject*> self(cx, this);
 
     MOZ_ASSERT(!maybeShared());
@@ -891,37 +889,34 @@ js::CloneRegExpObject(JSContext* cx, JSO
 
     RegExpFlag origFlags = regex->getFlags();
     RegExpFlag staticsFlags = currentStatics->getFlags();
     if ((origFlags & staticsFlags) != staticsFlags) {
         Rooted<RegExpObject*> clone(cx, RegExpAlloc(cx));
         if (!clone)
             return nullptr;
 
-        if (!RegExpObject::initFromAtom(cx, clone, source, RegExpFlag(origFlags | staticsFlags)))
-            return nullptr;
-
-        return clone;
+        return InitializeRegExp(cx, clone, source, RegExpFlag(origFlags | staticsFlags));
     }
 
     // Otherwise, the clone can use |regexp|'s RegExpShared.
     RootedObjectGroup group(cx, regex->group());
 
     // Note: RegExp objects are always allocated in the tenured heap. This is
     // not strictly required, but it simplifies embedding them in jitcode.
     Rooted<RegExpObject*> clone(cx, NewObjectWithGroup<RegExpObject>(cx, group, TenuredObject));
     if (!clone)
         return nullptr;
     clone->initPrivate(nullptr);
 
     RegExpGuard g(cx);
     if (!regex->getShared(cx, &g))
         return nullptr;
 
-    if (!RegExpObject::initFromAtom(cx, clone, source, g->getFlags()))
+    if (!InitializeRegExp(cx, clone, source, g->getFlags()))
         return nullptr;
 
     clone->setShared(*g.re());
     return clone;
 }
 
 static bool
 HandleRegExpFlag(RegExpFlag flag, RegExpFlag* flags)
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -59,17 +59,21 @@ enum RegExpFlag
 enum RegExpRunStatus
 {
     RegExpRunStatus_Error,
     RegExpRunStatus_Success,
     RegExpRunStatus_Success_NotFound
 };
 
 extern RegExpObject*
-RegExpAlloc(ExclusiveContext* cx, HandleObject proto = nullptr);
+RegExpAlloc(ExclusiveContext* cx);
+
+extern RegExpObject*
+InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
+                 RegExpFlag flags);
 
 // |regexp| is under-typed because this function's used in the JIT.
 extern JSObject*
 CloneRegExpObject(JSContext* cx, JSObject* regexp);
 
 extern JSObject*
 CreateRegExpPrototype(JSContext* cx, JSProtoKey key);
 
@@ -438,20 +442,21 @@ class RegExpObject : public NativeObject
 
     void setShared(RegExpShared& shared) {
         MOZ_ASSERT(!maybeShared());
         NativeObject::setPrivate(&shared);
     }
 
     static void trace(JSTracer* trc, JSObject* obj);
 
-    static bool initFromAtom(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
-                             RegExpFlag flags);
+  private:
+    friend RegExpObject*
+    InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
+                     RegExpFlag flags);
 
-  private:
     bool init(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags);
 
     /*
      * Precondition: the syntax for |source| has already been validated.
      * Side effect: sets the private field.
      */
     bool createShared(JSContext* cx, RegExpGuard* g);
     RegExpShared* maybeShared() const {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1285,31 +1285,20 @@ intrinsic_ConstructorForTypedArray(JSCon
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
     MOZ_ASSERT(IsAnyTypedArray(&args[0].toObject()));
 
     RootedObject object(cx, &args[0].toObject());
     JSProtoKey protoKey = StandardProtoKeyOrNull(object);
     MOZ_ASSERT(protoKey);
+    RootedValue ctor(cx, cx->global()->getConstructor(protoKey));
+    MOZ_ASSERT(ctor.isObject());
 
-    // 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
-    // the case. When we construct a typed array given a cross-compartment
-    // ArrayBuffer, we put the constructed TypedArray in the same compartment
-    // as the ArrayBuffer. Since we use the prototype from the initial
-    // compartment, and never call the constructor in the ArrayBuffer's
-    // compartment from script, we are not guaranteed to have initialized
-    // the constructor.
-    RootedObject ctor(cx);
-    if (!GetBuiltinConstructor(cx, protoKey, &ctor))
-        return false;
-
-    args.rval().setObject(*ctor);
+    args.rval().set(ctor);
     return true;
 }
 
 static bool
 intrinsic_IsModule(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
--- a/js/src/vm/StringObject-inl.h
+++ b/js/src/vm/StringObject-inl.h
@@ -28,19 +28,19 @@ StringObject::init(JSContext* cx, Handle
     MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT);
 
     self->setStringThis(str);
 
     return true;
 }
 
 inline StringObject*
-StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind)
+StringObject::create(JSContext* cx, HandleString str, NewObjectKind newKind)
 {
-    JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+    JSObject* obj = NewBuiltinClassInstance(cx, &class_, newKind);
     if (!obj)
         return nullptr;
     Rooted<StringObject*> strobj(cx, &obj->as<StringObject>());
     if (!strobj->init(cx, str))
         return nullptr;
     return strobj;
 }
 
--- a/js/src/vm/StringObject.h
+++ b/js/src/vm/StringObject.h
@@ -24,17 +24,16 @@ class StringObject : public NativeObject
 
     static const Class class_;
 
     /*
      * Creates a new String object boxing the given string.  The object's
      * [[Prototype]] is determined from context.
      */
     static inline StringObject* create(JSContext* cx, HandleString str,
-                                       HandleObject proto = nullptr,
                                        NewObjectKind newKind = GenericObject);
 
     /*
      * Compute the initial shape to associate with fresh String objects, which
      * encodes the initial length property. Return the shape after changing
      * |obj|'s last property to it.
      */
     static Shape*
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -136,27 +136,16 @@ AnyTypedArrayByteLength(const JSObject* 
 }
 
 inline bool
 IsAnyTypedArrayClass(const Class* clasp)
 {
     return IsTypedArrayClass(clasp) || IsSharedTypedArrayClass(clasp);
 }
 
-inline bool
-AnyTypedArrayIsDetached(const JSObject* obj)
-{
-    if (obj->is<TypedArrayObject>()) {
-        ArrayBufferObject* buffer = obj->as<TypedArrayObject>().buffer();
-        return buffer && buffer->isNeutered();
-    }
-    // You cannot detatch a shared array buffer
-    return false;
-}
-
 class SharedOps
 {
   public:
     template<typename T>
     static T load(SharedMem<T*> addr) {
         return js::jit::AtomicOperations::loadSafeWhenRacy(addr);
     }
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -177,30 +177,16 @@ js::ClampDoubleToUint8(const double x)
 }
 
 template<typename ElementType>
 static inline JSObject*
 NewArray(JSContext* cx, uint32_t nelements);
 
 namespace {
 
-// We allow nullptr for newTarget for all the creation methods, to allow for
-// JSFriendAPI functions that don't care about subclassing
-static bool
-GetPrototypeForInstance(JSContext* cx, HandleObject newTarget, MutableHandleObject proto)
-{
-    if (newTarget) {
-        if (!GetPrototypeFromConstructor(cx, newTarget, proto))
-            return false;
-    } else {
-        proto.set(nullptr);
-    }
-    return true;
-}
-
 // Note, this template can probably be merged in part with the one in
 // SharedTypedArrayObject.cpp once our implementation of
 // TypedArrayObject is closer to ES6: at the moment, our
 // implementation does not process construction arguments in
 // standards-compliant ways, at least, and a larger rewrite around the
 // prototype hierarchy is also coming.
 
 template<typename NativeType>
@@ -300,18 +286,27 @@ class TypedArrayObjectTemplate : public 
         }
     }
 
     static TypedArrayObject*
     makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
     {
         MOZ_ASSERT(proto);
 
-        JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
-        return obj ? &obj->as<TypedArrayObject>() : nullptr;
+        RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind));
+        if (!obj)
+            return nullptr;
+
+        ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, obj->getClass(),
+                                                          TaggedProto(proto.get()));
+        if (!group)
+            return nullptr;
+        obj->setGroup(group);
+
+        return &obj->as<TypedArrayObject>();
     }
 
     static TypedArrayObject*
     makeTypedInstance(JSContext* cx, uint32_t len, gc::AllocKind allocKind)
     {
         const Class* clasp = instanceClass();
         if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
             JSObject* obj = NewBuiltinClassInstance(cx, clasp, allocKind, SingletonObject);
@@ -425,23 +420,20 @@ class TypedArrayObjectTemplate : public 
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
     static JSObject*
     create(JSContext* cx, const CallArgs& args)
     {
-        MOZ_ASSERT(args.isConstructing());
-        RootedObject newTarget(cx, &args.newTarget().toObject());
-
         /* () or (number) */
         uint32_t len = 0;
         if (args.length() == 0 || ValueIsLength(args[0], &len))
-            return fromLength(cx, len, newTarget);
+            return fromLength(cx, len);
 
         /* (not an object) */
         if (!args[0].isObject()) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr;
         }
 
         RootedObject dataObj(cx, &args.get(0).toObject());
@@ -452,23 +444,19 @@ class TypedArrayObjectTemplate : public 
          * (type[] array)
          *
          * Otherwise create a new typed array and copy elements 0..len-1
          * properties from the object, treating it as some sort of array.
          * Note that offset and length will be ignored.  Note that a
          * shared array's values are copied here.
          */
         if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
-            return fromArray(cx, dataObj, newTarget);
+            return fromArray(cx, dataObj);
 
         /* (ArrayBuffer, [byteOffset, [length]]) */
-        RootedObject proto(cx);
-        if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-            return nullptr;
-
         int32_t byteOffset = 0;
         int32_t length = -1;
 
         if (args.length() > 1) {
             if (!ToInt32(cx, args[1], &byteOffset))
                 return nullptr;
             if (byteOffset < 0) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
@@ -482,17 +470,17 @@ class TypedArrayObjectTemplate : public 
                 if (length < 0) {
                     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
                     return nullptr;
                 }
             }
         }
 
-        return fromBufferWithProto(cx, dataObj, byteOffset, length, proto);
+        return fromBuffer(cx, dataObj, byteOffset, length);
     }
 
   public:
     static JSObject*
     fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt) {
         return fromBufferWithProto(cx, bufobj, byteOffset, lengthInt, nullptr);
     }
 
@@ -536,50 +524,43 @@ class TypedArrayObjectTemplate : public 
                  *
                  * Rather than hack some crazy solution together, implement
                  * this all using a private helper function, created when
                  * ArrayBufferObject was initialized and cached in the global.
                  * This reuses all the existing cross-compartment crazy so we
                  * don't have to do anything *uniquely* crazy here.
                  */
 
-                RootedObject protoRoot(cx, proto);
-                if (!protoRoot) {
-                    if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &protoRoot))
-                        return nullptr;
-                }
+                Rooted<JSObject*> proto(cx);
+                if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto))
+                    return nullptr;
 
                 InvokeArgs args(cx);
                 if (!args.init(3))
                     return nullptr;
 
                 args.setCallee(cx->compartment()->maybeGlobal()->createArrayFromBuffer<NativeType>());
                 args.setThis(ObjectValue(*bufobj));
                 args[0].setNumber(byteOffset);
                 args[1].setInt32(lengthInt);
-                args[2].setObject(*protoRoot);
+                args[2].setObject(*proto);
 
                 if (!Invoke(cx, args))
                     return nullptr;
                 return &args.rval().toObject();
             }
         }
 
         if (!IsArrayBuffer(bufobj)) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // must be arrayBuffer
         }
 
         Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
 
-        if (buffer->isNeutered()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-            return nullptr;
-        }
-
         if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // invalid byteOffset
         }
 
         uint32_t len;
         if (lengthInt == -1) {
             len = (buffer->byteLength() - byteOffset) / sizeof(NativeType);
@@ -628,31 +609,26 @@ class TypedArrayObjectTemplate : public 
         if (!buf)
             return false;
 
         buffer.set(buf);
         return true;
     }
 
     static JSObject*
-    fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr)
+    fromLength(JSContext* cx, uint32_t nelements)
     {
-        RootedObject proto(cx);
-        if (!GetPrototypeForInstance(cx, newTarget, &proto))
-            return nullptr;
-
         Rooted<ArrayBufferObject*> buffer(cx);
         if (!maybeCreateArrayBuffer(cx, nelements, &buffer))
             return nullptr;
-
-        return makeInstance(cx, buffer, 0, nelements, proto);
+        return makeInstance(cx, buffer, 0, nelements);
     }
 
     static JSObject*
-    fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr);
+    fromArray(JSContext* cx, HandleObject other);
 
     static const NativeType
     getIndex(JSObject* obj, uint32_t index)
     {
         TypedArrayObject& tarray = obj->as<TypedArrayObject>();
         MOZ_ASSERT(index < tarray.length());
         return static_cast<const NativeType*>(tarray.viewData())[index];
     }
@@ -682,45 +658,30 @@ typedef TypedArrayObjectTemplate<uint8_c
 template<typename T>
 struct TypedArrayObject::OfType
 {
     typedef TypedArrayObjectTemplate<T> Type;
 };
 
 template<typename T>
 /* static */ JSObject*
-TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
-                                       HandleObject newTarget /* = nullptr */)
+TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other)
 {
-    // Allow nullptr newTarget for FriendAPI methods, which don't care about
-    // subclassing.
-    RootedObject proto(cx);
-
     uint32_t len;
     if (IsAnyTypedArray(other)) {
-        if (!GetPrototypeForInstance(cx, newTarget, &proto))
-            return nullptr;
-
-        if (AnyTypedArrayIsDetached(other)) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-            return nullptr;
-        }
         len = AnyTypedArrayLength(other);
-    } else {
-        if (!GetLengthProperty(cx, other, &len))
-            return nullptr;
-        if (!GetPrototypeForInstance(cx, newTarget, &proto))
-            return nullptr;
+    } else if (!GetLengthProperty(cx, other, &len)) {
+        return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx);
     if (!maybeCreateArrayBuffer(cx, len, &buffer))
         return nullptr;
 
-    Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
+    Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len));
     if (!obj || !TypedArrayMethods<TypedArrayObject>::setFromArrayLike(cx, obj, other, len))
         return nullptr;
     return obj;
 }
 
 bool
 TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -996,43 +957,46 @@ DataViewNewObjectKind(JSContext* cx, uin
         return SingletonObject;
     jsbytecode* pc;
     JSScript* script = cx->currentScript(&pc);
     if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &DataViewObject::class_))
         return SingletonObject;
     return GenericObject;
 }
 
-DataViewObject*
+inline DataViewObject*
 DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
                        Handle<ArrayBufferObject*> arrayBuffer, JSObject* protoArg)
 {
     MOZ_ASSERT(byteOffset <= INT32_MAX);
     MOZ_ASSERT(byteLength <= INT32_MAX);
     MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
 
     RootedObject proto(cx, protoArg);
     RootedObject obj(cx);
 
     NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
-    obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
+    obj = NewBuiltinClassInstance(cx, &class_, newKind);
     if (!obj)
         return nullptr;
 
-    if (!proto) {
-        if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
-            MOZ_ASSERT(obj->isSingleton());
-        } else {
-            jsbytecode* pc;
-            RootedScript script(cx, cx->currentScript(&pc));
-            if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
-                                                                    newKind == SingletonObject))
-            {
-                return nullptr;
-            }
+    if (proto) {
+        ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(proto));
+        if (!group)
+            return nullptr;
+        obj->setGroup(group);
+    } else if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
+        MOZ_ASSERT(obj->isSingleton());
+    } else {
+        jsbytecode* pc;
+        RootedScript script(cx, cx->currentScript(&pc));
+        if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
+                                                                 newKind == SingletonObject))
+        {
+            return nullptr;
         }
     }
 
     // Caller should have established these preconditions, and no
     // (non-self-hosted) JS code has had an opportunity to run so nothing can
     // have invalidated them.
     MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
     MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
@@ -1053,183 +1017,106 @@ DataViewObject::create(JSContext* cx, ui
 
     if (!arrayBuffer->addView(cx, &dvobj))
         return nullptr;
 
     return &dvobj;
 }
 
 bool
-DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
-                                           uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
+DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, HandleObject proto)
 {
     if (!IsArrayBuffer(bufobj)) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                              "DataView", "ArrayBuffer", bufobj->getClass()->name);
         return false;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
     uint32_t byteOffset = 0;
     uint32_t byteLength = buffer->byteLength();
 
     if (args.length() > 1) {
         if (!ToUint32(cx, args[1], &byteOffset))
             return false;
         if (byteOffset > INT32_MAX) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
-            return false;
-        }
-    }
-
-    if (buffer->isNeutered()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return false;
-    }
-
-    if (args.length() > 1) {
-        if (byteOffset > byteLength) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
+                                 JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
             return false;
         }
 
-        if (args.get(2).isUndefined()) {
-            byteLength -= byteOffset;
-        } else {
+        if (!args.get(2).isUndefined()) {
             if (!ToUint32(cx, args[2], &byteLength))
                 return false;
             if (byteLength > INT32_MAX) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                                        JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
+                                     JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
                 return false;
             }
+        } else {
+            uint32_t bufferLength = buffer->byteLength();
 
-            MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
-                       "can't overflow: both numbers are less than INT32_MAX");
-            if (byteOffset + byteLength > buffer->byteLength()) {
+            if (byteOffset > bufferLength) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                                      JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
                 return false;
             }
+
+            byteLength = bufferLength - byteOffset;
         }
     }
 
     /* The sum of these cannot overflow a uint32_t */
     MOZ_ASSERT(byteOffset <= INT32_MAX);
     MOZ_ASSERT(byteLength <= INT32_MAX);
 
-
-    *byteOffsetPtr = byteOffset;
-    *byteLengthPtr = byteLength;
-
-    return true;
-}
+    if (byteOffset + byteLength > buffer->byteLength()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+        return false;
+    }
 
-bool
-DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args)
-{
-    MOZ_ASSERT(args.isConstructing());
-    assertSameCompartment(cx, bufobj);
-
-    uint32_t byteOffset, byteLength;
-    if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
-        return false;
-
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
     JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
-// Create a DataView object in another compartment.
-//
-// ES6 supports creating a DataView in global A (using global A's DataView
-// constructor) backed by an ArrayBuffer created in global B.
-//
-// Our DataViewObject implementation doesn't support a DataView in
-// compartment A backed by an ArrayBuffer in compartment B. So in this case,
-// we create the DataView in B (!) and return a cross-compartment wrapper.
-//
-// Extra twist: the spec says the new DataView's [[Prototype]] must be
-// A's DataView.prototype. So even though we're creating the DataView in B,
-// its [[Prototype]] must be (a cross-compartment wrapper for) the
-// DataView.prototype in A.
-//
-// As if this were not confusing enough, the way we actually do this is also
-// tricky. We call compartment A's createDataViewForThis method, passing it
-// bufobj as `this`. That calls ArrayBufferObject::createDataViewForThis(),
-// which uses CallNonGenericMethod to switch to compartment B so that
-// the new DataView is created there.
-bool
-DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args)
-{
-    MOZ_ASSERT(args.isConstructing());
-    MOZ_ASSERT(bufobj->is<WrapperObject>());
-
-    JSObject* unwrapped = CheckedUnwrap(bufobj);
-    if (!unwrapped) {
-        JS_ReportError(cx, "Permission denied to access object");
-        return false;
-    }
-
-    // NB: This entails the IsArrayBuffer check
-    uint32_t byteOffset, byteLength;
-    if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength))
-        return false;
-
-    // Make sure to get the [[Prototype]] for the created view from this
-    // compartment.
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
-    Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
-    if (!proto) {
-        proto = global->getOrCreateDataViewPrototype(cx);
-        if (!proto)
-            return false;
-    }
-
-    InvokeArgs args2(cx);
-    if (!args2.init(3))
-        return false;
-    args2.setCallee(global->createDataViewForThis());
-    args2.setThis(ObjectValue(*bufobj));
-    args2[0].set(PrivateUint32Value(byteOffset));
-    args2[1].set(PrivateUint32Value(byteLength));
-    args2[2].setObject(*proto);
-    if (!Invoke(cx, args2))
-        return false;
-    args.rval().set(args2.rval());
-    return true;
-}
-
 bool
 DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!ThrowIfNotConstructing(cx, args, "DataView"))
         return false;
 
     RootedObject bufobj(cx);
     if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
         return false;
 
-    if (bufobj->is<WrapperObject>())
-        return constructWrapped(cx, bufobj, args);
-    return constructSameCompartment(cx, bufobj, args);
+    if (bufobj->is<WrapperObject>() && IsArrayBuffer(UncheckedUnwrap(bufobj))) {
+        Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
+        Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
+        if (!proto)
+            return false;
+
+        InvokeArgs args2(cx);
+        if (!args2.init(args.length() + 1))
+            return false;
+        args2.setCallee(global->createDataViewForThis());
+        args2.setThis(ObjectValue(*bufobj));
+        PodCopy(args2.array(), args.array(), args.length());
+        args2[args.length()].setObject(*proto);
+        if (!Invoke(cx, args2))
+            return false;
+        args.rval().set(args2.rval());
+        return true;
+    }
+
+    return construct(cx, bufobj, args, nullptr);
 }
 
 template <typename NativeType>
 /* static */ uint8_t*
 DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint32_t offset)
 {
     const size_t TypeSize = sizeof(NativeType);
     if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
@@ -1326,21 +1213,16 @@ DataViewObject::read(JSContext* cx, Hand
     }
 
     uint32_t offset;
     if (!ToUint32(cx, args[0], &offset))
         return false;
 
     bool fromLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
 
-    if (obj->arrayBuffer().isNeutered()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return false;
-    }
-
     uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
     if (!data)
         return false;
 
     DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(fromLittleEndian));
     return true;
 }
 
@@ -1392,21 +1274,16 @@ DataViewObject::write(JSContext* cx, Han
         return false;
 
     NativeType value;
     if (!WebIDLCast(cx, args[1], &value))
         return false;
 
     bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
 
-    if (obj->arrayBuffer().isNeutered()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return false;
-    }
-
     uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
     if (!data)
         return false;
 
     DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(toLittleEndian));
     return true;
 }
 
@@ -1817,47 +1694,47 @@ TypedArrayObject::setElement(TypedArrayO
  *** JS impl
  ***/
 
 /*
  * TypedArrayObject boilerplate
  */
 
 #define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType)                                    \
-  JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements)           \
+  JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements)          \
   {                                                                                             \
       return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements);                   \
   }                                                                                             \
-  JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other)  \
+  JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \
   {                                                                                             \
       return TypedArrayObjectTemplate<NativeType>::fromArray(cx, other);                        \
   }                                                                                             \
-  JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx,                     \
+  JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx,                    \
                                HandleObject arrayBuffer, uint32_t byteOffset, int32_t length)   \
   {                                                                                             \
       return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset,      \
                                                               length);                          \
   }                                                                                             \
   JS_FRIEND_API(bool) JS_Is ## Name ## Array(JSObject* obj)                                     \
   {                                                                                             \
       if (!(obj = CheckedUnwrap(obj)))                                                          \
           return false;                                                                         \
       const Class* clasp = obj->getClass();                                                     \
       return clasp == TypedArrayObjectTemplate<NativeType>::instanceClass();                    \
-  }                                                                                             \
-  JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj)                           \
+  } \
+  JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj)                          \
   {                                                                                             \
       obj = CheckedUnwrap(obj);                                                                 \
       if (!obj)                                                                                 \
           return nullptr;                                                                       \
       const Class* clasp = obj->getClass();                                                     \
       if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass())                       \
           return obj;                                                                           \
       return nullptr;                                                                           \
-  }                                                                                             \
+  } \
   const js::Class* const js::detail::Name ## ArrayClassPtr =                                    \
       &js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];
 
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -372,26 +372,16 @@ class DataViewObject : public NativeObje
     template<Value ValueGetter(DataViewObject* view)>
     static bool
     getter(JSContext* cx, unsigned argc, Value* vp);
 
     template<Value ValueGetter(DataViewObject* view)>
     static bool
     defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto);
 
-    static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args,
-                                           uint32_t *byteOffset, uint32_t* byteLength);
-    static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
-    static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
-
-    friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
-    static DataViewObject*
-    create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
-           Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto);
-
   public:
     static const Class class_;
 
     static Value byteOffsetValue(DataViewObject* view) {
         Value v = view->getReservedSlot(TypedArrayLayout::BYTEOFFSET_SLOT);
         MOZ_ASSERT(v.toInt32() >= 0);
         return v;
     }
@@ -418,16 +408,23 @@ class DataViewObject : public NativeObje
         return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
     }
 
     void* dataPointer() const {
         return getPrivate();
     }
 
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
+    static bool constructWithProto(JSContext* cx, unsigned argc, Value* vp);
+    static bool construct(JSContext* cx, JSObject* bufobj, const CallArgs& args,
+                          HandleObject proto);
+
+    static inline DataViewObject*
+    create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
+           Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto);
 
     static bool getInt8Impl(JSContext* cx, const CallArgs& args);
     static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);
 
     static bool getUint8Impl(JSContext* cx, const CallArgs& args);
     static bool fun_getUint8(JSContext* cx, unsigned argc, Value* vp);
 
     static bool getInt16Impl(JSContext* cx, const CallArgs& args);