Backed out 2 changesets (bug 1055472) to hopefully fix the build bustage causing the CLOSED TREE
☠☠ backed out by 259854424b8e ☠ ☠
authorWes Kocher <wkocher@mozilla.com>
Wed, 18 Nov 2015 14:38:40 -0800
changeset 307309 70f41cd98857fabc1476024e27ba6ae35e39291b
parent 307308 044b9ffab63cd806448941e71437735a4daca630
child 307310 c629037407173cf6b067fd2ce29009edba8aae19
push idunknown
push userunknown
push dateunknown
bugs1055472
milestone45.0a1
backs out0389acea3fc76584ffb374a2dc26d2c086b229ac
6f4006cfea7a22d27608e4872d2901167f9e8fd9
Backed out 2 changesets (bug 1055472) to hopefully fix the build bustage causing the CLOSED TREE Backed out changeset 0389acea3fc7 (bug 1055472) Backed out changeset 6f4006cfea7a (bug 1055472)
js/src/gc/Marking.cpp
js/src/gc/Tracer.h
js/src/jit-test/tests/baseline/arraySubclassPropertyLookup.js
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js
js/src/tests/ecma_6/Reflect/construct.js
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
--- 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
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/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/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>();
 }
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1084,20 +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,
--- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
+++ b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js
@@ -1,60 +1,22 @@
 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 {
+function testBuiltin(builtin, ...args) {
+    class inst extends builtin {
         constructor(...args) {
             super(...args);
             this.called = true;
         }
     }
 
-    let instance = new sub(...args);
+    let instance = new inst(...args);
+    assertEq(instance instanceof inst, true);
+    assertEq(instance instanceof builtin, true);
     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,
@@ -92,21 +54,16 @@ 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/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);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -1352,93 +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() { 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
@@ -1473,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)
 {
@@ -1780,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);