Backed out changeset aa85f08f9f76 (bug 1116855) for Hazard analysis failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 26 Jan 2015 15:58:58 -0500
changeset 253003 32048e974c4b8e087c917623186c94a1f5b4ebb7
parent 253002 f7f224c79675560bf09fedf77c2aad82b30849aa
child 253004 1afe3f5bc9c78b0ba452246cc310734f8b988d4c
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1116855
milestone38.0a1
backs outaa85f08f9f76b2637282d32c52ece39b88e4515d
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset aa85f08f9f76 (bug 1116855) for Hazard analysis failures.
js/src/builtin/TypedObject.h
js/src/gc/Marking.cpp
js/src/gc/Nursery.cpp
js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js
js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
js/src/jsapi.h
js/src/jsgc.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/moz.build
js/src/shell/js.cpp
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -722,23 +722,30 @@ class OutlineOpaqueTypedObject : public 
 
 // Class for a typed object whose data is allocated inline.
 class InlineTypedObject : public TypedObject
 {
     // Start of the inline data, which immediately follows the shape and type.
     uint8_t data_[1];
 
   public:
-    static const size_t MaximumSize = JSObject::MAX_BYTE_SIZE - sizeof(TypedObject);
+    static const size_t MaximumSize =
+        sizeof(NativeObject) - sizeof(TypedObject) + NativeObject::MAX_FIXED_SLOTS * sizeof(Value);
 
     static gc::AllocKind allocKindForTypeDescriptor(TypeDescr *descr) {
         size_t nbytes = descr->size();
         MOZ_ASSERT(nbytes <= MaximumSize);
 
-        return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject));
+        if (nbytes <= sizeof(NativeObject) - sizeof(TypedObject))
+            return gc::FINALIZE_OBJECT0;
+        nbytes -= sizeof(NativeObject) - sizeof(TypedObject);
+
+        size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
+        MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
+        return gc::GetGCObjectKind(dataSlots);
     }
 
     uint8_t *inlineTypedMem() const {
         static_assert(offsetof(InlineTypedObject, data_) == sizeof(JSObject),
                       "The data for an inline typed object must follow the shape and type.");
         return (uint8_t *) &data_;
     }
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -14,17 +14,16 @@
 #include "jit/IonCode.h"
 #include "js/SliceBudget.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/ArrayObject.h"
 #include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/Symbol.h"
 #include "vm/TypedArrayObject.h"
-#include "vm/UnboxedObject.h"
 
 #include "jscompartmentinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/String-inl.h"
 #include "vm/Symbol-inl.h"
@@ -1434,19 +1433,16 @@ ScanTypeObject(GCMarker *gcmarker, types
         PushMarkStack(gcmarker, type->proto().toObject());
 
     if (type->singleton() && !type->lazy())
         PushMarkStack(gcmarker, type->singleton());
 
     if (type->newScript())
         type->newScript()->trace(gcmarker);
 
-    if (type->maybeUnboxedLayout())
-        type->unboxedLayout().trace(gcmarker);
-
     if (TypeDescr *descr = type->maybeTypeDescr())
         PushMarkStack(gcmarker, descr);
 
     if (JSFunction *fun = type->maybeInterpretedFunction())
         PushMarkStack(gcmarker, fun);
 }
 
 static void
@@ -1463,19 +1459,16 @@ gc::MarkChildren(JSTracer *trc, types::T
         MarkObject(trc, &type->protoRaw(), "type_proto");
 
     if (type->singleton() && !type->lazy())
         MarkObject(trc, &type->singletonRaw(), "type_singleton");
 
     if (type->newScript())
         type->newScript()->trace(trc);
 
-    if (type->maybeUnboxedLayout())
-        type->unboxedLayout().trace(trc);
-
     if (JSObject *descr = type->maybeTypeDescr()) {
         MarkObjectUnbarriered(trc, &descr, "type_descr");
         type->setTypeDescr(&descr->as<TypeDescr>());
     }
 
     if (JSObject *fun = type->maybeInterpretedFunction()) {
         MarkObjectUnbarriered(trc, &fun, "type_function");
         type->setInterpretedFunction(&fun->as<JSFunction>());
@@ -1702,19 +1695,16 @@ GCMarker::processMarkStackTop(SliceBudge
     /*
      * The function uses explicit goto and implements the scanning of the
      * object directly. It allows to eliminate the tail recursion and
      * significantly improve the marking performance, see bug 641025.
      */
     HeapSlot *vp, *end;
     JSObject *obj;
 
-    const int32_t *unboxedTraceList;
-    uint8_t *unboxedMemory;
-
     uintptr_t addr = stack.pop();
     uintptr_t tag = addr & StackTagMask;
     addr &= ~StackTagMask;
 
     if (tag == ValueArrayTag) {
         JS_STATIC_ASSERT(ValueArrayTag == 0);
         MOZ_ASSERT(!(addr & CellMask));
         obj = reinterpret_cast<JSObject *>(addr);
@@ -1750,43 +1740,48 @@ GCMarker::processMarkStackTop(SliceBudge
                 goto scan_obj;
             }
         } else if (v.isSymbol()) {
             markAndScanSymbol(obj, v.toSymbol());
         }
     }
     return;
 
-  scan_unboxed:
+  scan_typed_obj:
     {
-        while (*unboxedTraceList != -1) {
-            JSString *str = *reinterpret_cast<JSString **>(unboxedMemory + *unboxedTraceList);
+        TypeDescr *descr = &obj->as<InlineOpaqueTypedObject>().typeDescr();
+        if (!descr->hasTraceList())
+            return;
+        const int32_t *list = descr->traceList();
+        uint8_t *memory = obj->as<InlineOpaqueTypedObject>().inlineTypedMem();
+        while (*list != -1) {
+            JSString *str = *reinterpret_cast<JSString **>(memory + *list);
             markAndScanString(obj, str);
-            unboxedTraceList++;
+            list++;
         }
-        unboxedTraceList++;
-        while (*unboxedTraceList != -1) {
-            JSObject *obj2 = *reinterpret_cast<JSObject **>(unboxedMemory + *unboxedTraceList);
+        list++;
+        while (*list != -1) {
+            JSObject *obj2 = *reinterpret_cast<JSObject **>(memory + *list);
             if (obj2 && markObject(obj, obj2))
                 pushObject(obj2);
-            unboxedTraceList++;
+            list++;
         }
-        unboxedTraceList++;
-        while (*unboxedTraceList != -1) {
-            const Value &v = *reinterpret_cast<Value *>(unboxedMemory + *unboxedTraceList);
+        list++;
+        while (*list != -1) {
+            const Value &v = *reinterpret_cast<Value *>(memory + *list);
             if (v.isString()) {
                 markAndScanString(obj, v.toString());
             } else if (v.isObject()) {
                 JSObject *obj2 = &v.toObject();
                 if (markObject(obj, obj2))
                     pushObject(obj2);
             } else if (v.isSymbol()) {
                 markAndScanSymbol(obj, v.toSymbol());
             }
-            unboxedTraceList++;
+            list++;
         }
         return;
     }
 
   scan_obj:
     {
         JS_COMPARTMENT_ASSERT(runtime(), obj);
 
@@ -1806,32 +1801,18 @@ GCMarker::processMarkStackTop(SliceBudge
         const Class *clasp = type->clasp();
         if (clasp->trace) {
             // Global objects all have the same trace hook. That hook is safe without barriers
             // if the global has no custom trace hook of its own, or has been moved to a different
             // compartment, and so can't have one.
             MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
                             (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
                           clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
-            if (clasp->trace == InlineTypedObject::obj_trace) {
-                TypeDescr *descr = &obj->as<InlineOpaqueTypedObject>().typeDescr();
-                if (!descr->hasTraceList())
-                    return;
-                unboxedTraceList = descr->traceList();
-                unboxedMemory = obj->as<InlineOpaqueTypedObject>().inlineTypedMem();
-                goto scan_unboxed;
-            }
-            if (clasp == &UnboxedPlainObject::class_) {
-                const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
-                unboxedTraceList = layout.traceList();
-                if (!unboxedTraceList)
-                    return;
-                unboxedMemory = obj->as<UnboxedPlainObject>().data();
-                goto scan_unboxed;
-            }
+            if (clasp->trace == InlineTypedObject::obj_trace)
+                goto scan_typed_obj;
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
             return;
 
         NativeObject *nobj = &obj->as<NativeObject>();
         unsigned nslots = nobj->slotSpan();
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -415,38 +415,32 @@ GetObjectAllocKindForCopy(const Nursery 
     if (obj->is<TypedArrayObject>() && !obj->as<TypedArrayObject>().buffer()) {
         size_t nbytes = obj->as<TypedArrayObject>().byteLength();
         return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
     }
 
     // Proxies have finalizers and are not nursery allocated.
     MOZ_ASSERT(!IsProxy(obj));
 
-    // Unboxed plain objects are sized according to the data they store.
-    if (obj->is<UnboxedPlainObject>()) {
-        size_t nbytes = obj->as<UnboxedPlainObject>().layout().size();
-        return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
-    }
-
     // Inlined typed objects are followed by their data, so make sure we copy
     // it all over to the new object.
     if (obj->is<InlineTypedObject>()) {
         // Figure out the size of this object, from the prototype's TypeDescr.
         // The objects we are traversing here are all tenured, so we don't need
         // to check forwarding pointers.
         TypeDescr *descr = &obj->as<InlineTypedObject>().typeDescr();
         MOZ_ASSERT(!IsInsideNursery(descr));
         return InlineTypedObject::allocKindForTypeDescriptor(descr);
     }
 
     // Outline typed objects use the minimum allocation kind.
     if (obj->is<OutlineTypedObject>())
         return FINALIZE_OBJECT0;
 
-    // All nursery allocatable non-native objects are handled above.
+    // The only non-native objects in existence are proxies and typed objects.
     MOZ_ASSERT(obj->isNative());
 
     AllocKind kind = GetGCObjectFixedSlotsKind(obj->as<NativeObject>().numFixedSlots());
     MOZ_ASSERT(!IsBackgroundFinalized(kind));
     if (!CanBeFinalizedInBackground(kind, obj->getClass()))
         return kind;
     return GetBackgroundAllocKind(kind);
 }
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/unboxed-object-clear-new-script.js
+++ /dev/null
@@ -1,49 +0,0 @@
-
-function Foo(a, b) {
-    this.a = a;
-    this.b = b;
-}
-
-function invalidate_foo() {
-    var a = [];
-    var counter = 0;
-    for (var i = 0; i < 50; i++)
-        a.push(new Foo(i, i + 1));
-    Object.defineProperty(Foo.prototype, "a", {configurable: true, set: function() { counter++; }});
-    for (var i = 0; i < 50; i++)
-        a.push(new Foo(i, i + 1));
-    delete Foo.prototype.a;
-    var total = 0;
-    for (var i = 0; i < a.length; i++) {
-        assertEq('a' in a[i], i < 50);
-        total += a[i].b;
-    }
-    assertEq(total, 2550);
-    assertEq(counter, 50);
-}
-invalidate_foo();
-
-function Bar(a, b, fn) {
-    this.a = a;
-    if (b == 30)
-        Object.defineProperty(Bar.prototype, "b", {configurable: true, set: fn});
-    this.b = b;
-}
-
-function invalidate_bar() {
-    var a = [];
-    var counter = 0;
-    function fn() { counter++; }
-    for (var i = 0; i < 50; i++)
-        a.push(new Bar(i, i + 1, fn));
-    delete Bar.prototype.b;
-    var total = 0;
-    for (var i = 0; i < a.length; i++) {
-        assertEq('a' in a[i], true);
-        assertEq('b' in a[i], i < 29);
-        total += a[i].a;
-    }
-    assertEq(total, 1225);
-    assertEq(counter, 21);
-}
-invalidate_bar();
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/unboxed-object-convert-to-native.js
+++ /dev/null
@@ -1,47 +0,0 @@
-
-// Test various ways of converting an unboxed object to native.
-
-function Foo(a, b) {
-    this.a = a;
-    this.b = b;
-}
-
-var proxyObj = {
-  get: function(recipient, name) {
-    return recipient[name] + 2;
-  }
-};
-
-function f() {
-    var a = [];
-    for (var i = 0; i < 50; i++)
-        a.push(new Foo(i, i + 1));
-
-    var prop = "a";
-
-    i = 0;
-    for (; i < 5; i++)
-        a[i].c = i;
-    for (; i < 10; i++)
-        Object.defineProperty(a[i], 'c', {value: i});
-    for (; i < 15; i++)
-        a[i] = new Proxy(a[i], proxyObj);
-    for (; i < 20; i++)
-        a[i].a = 3.5;
-    for (; i < 25; i++)
-        delete a[i].b;
-    for (; i < 30; i++)
-        a[prop] = 4;
-
-    var total = 0;
-    for (i = 0; i < a.length; i++) {
-        if ('a' in a[i])
-            total += a[i].a;
-        if ('b' in a[i])
-            total += a[i].b;
-        if ('c' in a[i])
-            total += a[i].c;
-    }
-    assertEq(total, 2382.5);
-}
-f();
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9078,37 +9078,33 @@ TryAttachCallStub(JSContext *cx, ICCall_
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
         // Remember the template object associated with any script being called
         // as a constructor, for later use during Ion compilation.
         RootedPlainObject templateObject(cx);
         if (constructing) {
-            JSObject *thisObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
-            if (!thisObject)
+            templateObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
+            if (!templateObject)
                 return false;
 
-            if (thisObject->is<PlainObject>()) {
-                templateObject = &thisObject->as<PlainObject>();
-
-                // If we are calling a constructor for which the new script
-                // properties analysis has not been performed yet, don't attach a
-                // stub. After the analysis is performed, CreateThisForFunction may
-                // start returning objects with a different type, and the Ion
-                // compiler might get confused.
-                if (templateObject->type()->newScript() &&
-                    !templateObject->type()->newScript()->analyzed())
-                {
-                    // Clear the object just created from the preliminary objects
-                    // on the TypeNewScript, as it will not be used or filled in by
-                    // running code.
-                    templateObject->type()->newScript()->unregisterNewObject(templateObject);
-                    return true;
-                }
+            // If we are calling a constructor for which the new script
+            // properties analysis has not been performed yet, don't attach a
+            // stub. After the analysis is performed, CreateThisForFunction may
+            // start returning objects with a different type, and the Ion
+            // compiler might get confused.
+            if (templateObject->type()->newScript() &&
+                !templateObject->type()->newScript()->analyzed())
+            {
+                // Clear the object just created from the preliminary objects
+                // on the TypeNewScript, as it will not be used or filled in by
+                // running code.
+                templateObject->type()->newScript()->unregisterNewObject(templateObject);
+                return true;
             }
         }
 
         JitSpew(JitSpew_BaselineIC,
                 "  Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s, spread=%s)",
                 fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno(),
                 constructing ? "yes" : "no", isSpread ? "yes" : "no");
         ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5376,20 +5376,16 @@ IonBuilder::createThisScriptedSingleton(
         return nullptr;
 
     JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject || !templateObject->is<PlainObject>())
         return nullptr;
     if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
         return nullptr;
 
-    types::TypeObjectKey *templateObjectType = types::TypeObjectKey::get(templateObject->type());
-    if (templateObjectType->hasFlags(constraints(), types::OBJECT_FLAG_NEW_SCRIPT_CLEARED))
-        return nullptr;
-
     types::StackTypeSet *thisTypes = types::TypeScript::ThisTypes(target->nonLazyScript());
     if (!thisTypes || !thisTypes->hasType(types::Type::ObjectType(templateObject)))
         return nullptr;
 
     // Generate an inline path to create a new |this| object with
     // the given singleton prototype.
     MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     MCreateThisWithTemplate *createThis =
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1492,17 +1492,16 @@ namespace JS {
 
 class JS_PUBLIC_API(RuntimeOptions) {
   public:
     RuntimeOptions()
       : baseline_(false),
         ion_(false),
         asmJS_(false),
         nativeRegExp_(false),
-        unboxedObjects_(false),
         werror_(false),
         strictMode_(false),
         extraWarnings_(false),
         varObjFix_(false)
     {
     }
 
     bool baseline() const { return baseline_; }
@@ -1536,22 +1535,16 @@ class JS_PUBLIC_API(RuntimeOptions) {
     }
 
     bool nativeRegExp() const { return nativeRegExp_; }
     RuntimeOptions &setNativeRegExp(bool flag) {
         nativeRegExp_ = flag;
         return *this;
     }
 
-    bool unboxedObjects() const { return unboxedObjects_; }
-    RuntimeOptions &setUnboxedObjects(bool flag) {
-        unboxedObjects_ = flag;
-        return *this;
-    }
-
     bool werror() const { return werror_; }
     RuntimeOptions &setWerror(bool flag) {
         werror_ = flag;
         return *this;
     }
     RuntimeOptions &toggleWerror() {
         werror_ = !werror_;
         return *this;
@@ -1587,17 +1580,16 @@ class JS_PUBLIC_API(RuntimeOptions) {
         return *this;
     }
 
   private:
     bool baseline_ : 1;
     bool ion_ : 1;
     bool asmJS_ : 1;
     bool nativeRegExp_ : 1;
-    bool unboxedObjects_ : 1;
     bool werror_ : 1;
     bool strictMode_ : 1;
     bool extraWarnings_ : 1;
     bool varObjFix_ : 1;
 };
 
 JS_PUBLIC_API(RuntimeOptions &)
 RuntimeOptionsRef(JSRuntime *rt);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -187,32 +187,16 @@ GetGCArrayKind(size_t numSlots)
 
 static inline AllocKind
 GetGCObjectFixedSlotsKind(size_t numFixedSlots)
 {
     MOZ_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
     return slotsToThingKind[numFixedSlots];
 }
 
-// Get the best kind to use when allocating an object that needs a specific
-// number of bytes.
-static inline AllocKind
-GetGCObjectKindForBytes(size_t nbytes)
-{
-    MOZ_ASSERT(nbytes <= JSObject::MAX_BYTE_SIZE);
-
-    if (nbytes <= sizeof(NativeObject))
-        return FINALIZE_OBJECT0;
-    nbytes -= sizeof(NativeObject);
-
-    size_t dataSlots = AlignBytes(nbytes, sizeof(Value)) / sizeof(Value);
-    MOZ_ASSERT(nbytes <= dataSlots * sizeof(Value));
-    return GetGCObjectKind(dataSlots);
-}
-
 static inline AllocKind
 GetBackgroundAllocKind(AllocKind kind)
 {
     MOZ_ASSERT(!IsBackgroundFinalized(kind));
     MOZ_ASSERT(kind <= FINALIZE_OBJECT_LAST);
     return (AllocKind) (kind + 1);
 }
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -25,17 +25,16 @@
 #include "jit/CompileInfo.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/JitCompartment.h"
 #include "js/MemoryMetrics.h"
 #include "vm/HelperThreads.h"
 #include "vm/Opcodes.h"
 #include "vm/Shape.h"
-#include "vm/UnboxedObject.h"
 
 #include "jsatominlines.h"
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
@@ -3270,108 +3269,71 @@ TypeObject::markUnknown(ExclusiveContext
         Property *prop = getProperty(i);
         if (prop) {
             prop->types.addType(cx, Type::UnknownType());
             prop->types.setNonDataProperty(cx);
         }
     }
 }
 
-TypeNewScript *
-TypeObject::anyNewScript()
-{
-    if (newScript())
-        return newScript();
-    if (maybeUnboxedLayout())
-        return unboxedLayout().newScript();
-    return nullptr;
-}
-
-void
-TypeObject::detachNewScript(bool writeBarrier)
-{
-    // Clear the TypeNewScript from this TypeObject and, if it has been
-    // analyzed, remove it from the newTypeObjects table so that it will not be
-    // produced by calling 'new' on the associated function anymore.
-    // The TypeNewScript is not actually destroyed.
-    TypeNewScript *newScript = anyNewScript();
-    MOZ_ASSERT(newScript);
-
-    if (newScript->analyzed()) {
-        NewTypeObjectTable &newTypeObjects = newScript->function()->compartment()->newTypeObjects;
-        NewTypeObjectTable::Ptr p =
-            newTypeObjects.lookup(NewTypeObjectTable::Lookup(nullptr, proto(), newScript->function()));
-        MOZ_ASSERT(p->object == this);
-
-        newTypeObjects.remove(p);
-    }
-
-    if (this->newScript())
-        setAddendum(Addendum_None, nullptr, writeBarrier);
-    else
-        unboxedLayout().setNewScript(nullptr, writeBarrier);
-}
-
 void
 TypeObject::maybeClearNewScriptOnOOM()
 {
     MOZ_ASSERT(zone()->isGCSweepingOrCompacting());
 
     if (!isMarked())
         return;
 
-    TypeNewScript *newScript = anyNewScript();
-    if (!newScript)
+    if (!newScript())
         return;
 
-    addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
-
-    // This method is called during GC sweeping, so don't trigger pre barriers.
-    detachNewScript(/* writeBarrier = */ false);
-
-    js_delete(newScript);
+    for (unsigned i = 0; i < getPropertyCount(); i++) {
+        Property *prop = getProperty(i);
+        if (!prop)
+            continue;
+        if (prop->types.definiteProperty())
+            prop->types.setNonDataPropertyIgnoringConstraints();
+    }
+
+    // This method is called during GC sweeping, so there is no write barrier
+    // that needs to be triggered.
+    js_delete(newScript());
+    addendum_ = nullptr;
 }
 
 void
 TypeObject::clearNewScript(ExclusiveContext *cx)
 {
-    TypeNewScript *newScript = anyNewScript();
-    if (!newScript)
+    if (!newScript())
         return;
 
-    // Invalidate any Ion code constructing objects of this type.
-    setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
-
-    // Mark the constructing function as having its 'new' script cleared, so we
-    // will not try to construct another one later.
-    if (!newScript->function()->setNewScriptCleared(cx))
-        cx->recoverFromOutOfMemory();
-
-    detachNewScript(/* writeBarrier = */ true);
+    TypeNewScript *newScript = this->newScript();
+    setNewScript(nullptr);
 
     AutoEnterAnalysis enter(cx);
 
+    /*
+     * Any definite properties we added due to analysis of the new script when
+     * the type object was created are now invalid: objects with the same type
+     * can be created by using 'new' on a different script or through some
+     * other mechanism (e.g. Object.create). Rather than clear out the definite
+     * bits on the object's properties, just mark such properties as having
+     * been deleted/reconfigured, which will have the same effect on JITs
+     * wanting to use the definite bits to optimize property accesses.
+     */
+    for (unsigned i = 0; i < getPropertyCount(); i++) {
+        Property *prop = getProperty(i);
+        if (!prop)
+            continue;
+        if (prop->types.definiteProperty())
+            prop->types.setNonDataProperty(cx);
+    }
+
     if (cx->isJSContext()) {
-        bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
-
-        // If we managed to rollback any partially initialized objects, then
-        // any definite properties we added due to analysis of the new script
-        // are now invalid, so remove them. If there weren't any partially
-        // initialized objects then we don't need to change type information,
-        // as no more objects of this type will be created and the 'new' script
-        // analysis was still valid when older objects were created.
-        if (found) {
-            for (unsigned i = 0; i < getPropertyCount(); i++) {
-                Property *prop = getProperty(i);
-                if (!prop)
-                    continue;
-                if (prop->types.definiteProperty())
-                    prop->types.setNonDataProperty(cx);
-            }
-        }
+        newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
     } else {
         // Threads with an ExclusiveContext are not allowed to run scripts.
         MOZ_ASSERT(!cx->perThreadData->runtimeIfOnOwnerThread() ||
                    !cx->perThreadData->runtimeIfOnOwnerThread()->activation());
     }
 
     js_delete(newScript);
     markStateChange(cx);
@@ -3804,98 +3766,42 @@ JSFunction::setTypeForScriptedFunction(E
         fun->setType(type);
         type->setInterpretedFunction(fun);
     }
 
     return true;
 }
 
 /////////////////////////////////////////////////////////////////////
-// PreliminaryObjectArray
-/////////////////////////////////////////////////////////////////////
-
-void
-PreliminaryObjectArray::registerNewObject(JSObject *res)
-{
-    // The preliminary object pointers are weak, and won't be swept properly
-    // during nursery collections, so the preliminary objects need to be
-    // initially tenured.
-    MOZ_ASSERT(!IsInsideNursery(res));
-
-    for (size_t i = 0; i < COUNT; i++) {
-        if (!objects[i]) {
-            objects[i] = res;
-            return;
-        }
-    }
-
-    MOZ_CRASH("There should be room for registering the new object");
-}
-
-void
-PreliminaryObjectArray::unregisterNewObject(JSObject *res)
-{
-    for (size_t i = 0; i < COUNT; i++) {
-        if (objects[i] == res) {
-            objects[i] = nullptr;
-            return;
-        }
-    }
-
-    MOZ_CRASH("The object should be one of the preliminary objects");
-}
-
-bool
-PreliminaryObjectArray::full() const
-{
-    for (size_t i = 0; i < COUNT; i++) {
-        if (!objects[i])
-            return false;
-    }
-    return true;
-}
-
-void
-PreliminaryObjectArray::sweep()
-{
-    // All objects in the array are weak, so clear any that are about to be
-    // destroyed.
-    for (size_t i = 0; i < COUNT; i++) {
-        JSObject **ptr = &objects[i];
-        if (*ptr && IsObjectAboutToBeFinalized(ptr))
-            *ptr = nullptr;
-    }
-}
-
-/////////////////////////////////////////////////////////////////////
 // TypeNewScript
 /////////////////////////////////////////////////////////////////////
 
 // Make a TypeNewScript for |type|, and set it up to hold the initial
 // PRELIMINARY_OBJECT_COUNT objects created with the type.
 /* static */ void
 TypeNewScript::make(JSContext *cx, TypeObject *type, JSFunction *fun)
 {
     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
     MOZ_ASSERT(!type->newScript());
-    MOZ_ASSERT(!type->maybeUnboxedLayout());
 
     if (type->unknownProperties())
         return;
 
     ScopedJSDeletePtr<TypeNewScript> newScript(cx->new_<TypeNewScript>());
     if (!newScript)
         return;
 
-    newScript->function_ = fun;
-
-    newScript->preliminaryObjects = type->zone()->new_<PreliminaryObjectArray>();
-    if (!newScript->preliminaryObjects)
+    newScript->fun = fun;
+
+    PlainObject **preliminaryObjects =
+        type->zone()->pod_calloc<PlainObject *>(PRELIMINARY_OBJECT_COUNT);
+    if (!preliminaryObjects)
         return;
 
+    newScript->preliminaryObjects = preliminaryObjects;
     type->setNewScript(newScript.forget());
 
     gc::TraceTypeNewScript(type);
 }
 
 size_t
 TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
@@ -3905,29 +3811,50 @@ TypeNewScript::sizeOfIncludingThis(mozil
     return n;
 }
 
 void
 TypeNewScript::registerNewObject(PlainObject *res)
 {
     MOZ_ASSERT(!analyzed());
 
+    // The preliminary object pointers are weak, and won't be swept properly
+    // during nursery collections, so the preliminary objects need to be
+    // initially tenured.
+    MOZ_ASSERT(!IsInsideNursery(res));
+
     // New script objects must have the maximum number of fixed slots, so that
     // we can adjust their shape later to match the number of fixed slots used
     // by the template object we eventually create.
     MOZ_ASSERT(res->numFixedSlots() == NativeObject::MAX_FIXED_SLOTS);
 
-    preliminaryObjects->registerNewObject(res);
+    for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+        if (!preliminaryObjects[i]) {
+            preliminaryObjects[i] = res;
+            return;
+        }
+    }
+
+    MOZ_CRASH("There should be room for registering the new object");
 }
 
 void
 TypeNewScript::unregisterNewObject(PlainObject *res)
 {
     MOZ_ASSERT(!analyzed());
-    preliminaryObjects->unregisterNewObject(res);
+
+    for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+        if (preliminaryObjects[i] == res) {
+            preliminaryObjects[i] = nullptr;
+            return;
+        }
+    }
+
+    // The object should be one of the preliminary objects.
+    MOZ_CRASH();
 }
 
 // Return whether shape consists entirely of plain data properties.
 static bool
 OnlyHasDataProperties(Shape *shape)
 {
     MOZ_ASSERT(!shape->inDictionary());
 
@@ -4018,35 +3945,38 @@ TypeNewScript::maybeAnalyze(JSContext *c
     if (regenerate)
         *regenerate = false;
 
     if (analyzed()) {
         // The analyses have already been performed.
         return true;
     }
 
-    // Don't perform the analyses until sufficient preliminary objects have
-    // been allocated.
-    if (!force && !preliminaryObjects->full())
-        return true;
+    if (!force) {
+        // Don't perform the analyses until sufficient preliminary objects have
+        // been allocated.
+        for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+            if (!preliminaryObjects[i])
+                return true;
+        }
+    }
 
     AutoEnterAnalysis enter(cx);
 
     // Any failures after this point will clear out this TypeNewScript.
     DestroyTypeNewScript destroyNewScript(cx, type);
 
     // Compute the greatest common shape prefix and the largest slot span of
     // the preliminary objects.
     Shape *prefixShape = nullptr;
     size_t maxSlotSpan = 0;
-    for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-        JSObject *objBase = preliminaryObjects->get(i);
-        if (!objBase)
+    for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+        PlainObject *obj = preliminaryObjects[i];
+        if (!obj)
             continue;
-        PlainObject *obj = &objBase->as<PlainObject>();
 
         // For now, we require all preliminary objects to have only simple
         // lineages of plain data properties.
         Shape *shape = obj->lastProperty();
         if (shape->inDictionary() || !OnlyHasDataProperties(shape))
             return true;
 
         maxSlotSpan = Max<size_t>(maxSlotSpan, obj->slotSpan());
@@ -4072,21 +4002,20 @@ TypeNewScript::maybeAnalyze(JSContext *c
         // preliminary objects that have already been constructed. Optimizing
         // definite property accesses requires both that the property is
         // definitely in a particular slot and that the object has a specific
         // number of fixed slots. So, adjust the shape and slot layout of all
         // the preliminary objects so that their structure matches that of the
         // template object. Also recompute the prefix shape, as it reflects the
         // old number of fixed slots.
         Shape *newPrefixShape = nullptr;
-        for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-            JSObject *objBase = preliminaryObjects->get(i);
-            if (!objBase)
+        for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+            PlainObject *obj = preliminaryObjects[i];
+            if (!obj)
                 continue;
-            PlainObject *obj = &objBase->as<PlainObject>();
             if (!ChangeObjectFixedSlotCount(cx, obj, kind))
                 return false;
             if (newPrefixShape) {
                 MOZ_ASSERT(CommonPrefix(obj->lastProperty(), newPrefixShape) == newPrefixShape);
             } else {
                 newPrefixShape = obj->lastProperty();
                 while (newPrefixShape->slotSpan() > prefixShape->slotSpan())
                     newPrefixShape = newPrefixShape->previous();
@@ -4098,17 +4027,17 @@ TypeNewScript::maybeAnalyze(JSContext *c
     RootedTypeObject typeRoot(cx, type);
     templateObject_ = NewObjectWithType<PlainObject>(cx, typeRoot, cx->global(), kind, MaybeSingletonObject);
     if (!templateObject_)
         return false;
 
     Vector<Initializer> initializerVector(cx);
 
     RootedPlainObject templateRoot(cx, templateObject());
-    if (!jit::AnalyzeNewScriptDefiniteProperties(cx, function(), type, templateRoot, &initializerVector))
+    if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, type, templateRoot, &initializerVector))
         return false;
 
     if (!type->newScript())
         return true;
 
     MOZ_ASSERT(OnlyHasDataProperties(templateObject()->lastProperty()));
 
     if (templateObject()->slotSpan() != 0) {
@@ -4143,38 +4072,19 @@ TypeNewScript::maybeAnalyze(JSContext *c
             return false;
 
         initializerList = type->zone()->pod_calloc<Initializer>(initializerVector.length());
         if (!initializerList)
             return false;
         PodCopy(initializerList, initializerVector.begin(), initializerVector.length());
     }
 
-    // Try to use an unboxed representation for the type.
-    if (!TryConvertToUnboxedLayout(cx, templateObject()->lastProperty(), type, preliminaryObjects))
-        return false;
-
-    js_delete(preliminaryObjects);
+    js_free(preliminaryObjects);
     preliminaryObjects = nullptr;
 
-    if (type->maybeUnboxedLayout()) {
-        // An unboxed layout was constructed for the type, and this has already
-        // been hooked into it.
-        MOZ_ASSERT(type->unboxedLayout().newScript() == this);
-        destroyNewScript.type = nullptr;
-
-        // Clear out the template object. This is not used for TypeNewScripts
-        // with an unboxed layout, and additionally this template is now a
-        // mutant object with a non-native class and native shape, and must be
-        // collected by the next GC.
-        templateObject_ = nullptr;
-
-        return true;
-    }
-
     if (prefixShape->slotSpan() == templateObject()->slotSpan()) {
         // The definite properties analysis found exactly the properties that
         // are held in common by the preliminary objects. No further analysis
         // is needed.
         if (!type->addDefiniteProperties(cx, templateObject()->lastProperty()))
             return false;
 
         destroyNewScript.type = nullptr;
@@ -4197,21 +4107,21 @@ TypeNewScript::maybeAnalyze(JSContext *c
         return false;
 
     if (!initialType->addDefiniteProperties(cx, templateObject()->lastProperty()))
         return false;
     if (!type->addDefiniteProperties(cx, prefixShape))
         return false;
 
     NewTypeObjectTable &table = cx->compartment()->newTypeObjects;
-    NewTypeObjectTable::Lookup lookup(nullptr, type->proto(), function());
+    NewTypeObjectTable::Lookup lookup(type->clasp(), type->proto(), fun);
 
     MOZ_ASSERT(table.lookup(lookup)->object == type);
     table.remove(lookup);
-    table.putNew(lookup, NewTypeObjectEntry(initialType, function()));
+    table.putNew(lookup, NewTypeObjectEntry(initialType, fun));
 
     templateObject()->setType(initialType);
 
     // Transfer this TypeNewScript from the fully initialized type to the
     // partially initialized type.
     type->setNewScript(nullptr);
     initialType->setNewScript(this);
 
@@ -4220,54 +4130,46 @@ TypeNewScript::maybeAnalyze(JSContext *c
 
     destroyNewScript.type = nullptr;
 
     if (regenerate)
         *regenerate = true;
     return true;
 }
 
-bool
+void
 TypeNewScript::rollbackPartiallyInitializedObjects(JSContext *cx, TypeObject *type)
 {
     // If we cleared this new script while in the middle of initializing an
     // object, it will still have the new script's shape and reflect the no
     // longer correct state of the object once its initialization is completed.
     // We can't detect the possibility of this statically while remaining
     // robust, but the new script keeps track of where each property is
     // initialized so we can walk the stack and fix up any such objects.
-    // Return whether any objects were modified.
 
     if (!initializerList)
-        return false;
-
-    bool found = false;
-
-    RootedFunction function(cx, this->function());
+        return;
+
+    RootedFunction function(cx, fun);
     Vector<uint32_t, 32> pcOffsets(cx);
     for (ScriptFrameIter iter(cx); !iter.done(); ++iter) {
         pcOffsets.append(iter.script()->pcToOffset(iter.pc()));
 
-        if (!iter.isConstructing() || !iter.matchCallee(cx, function))
+        // This frame has no this.
+        if (!iter.isConstructing() || iter.matchCallee(cx, function))
             continue;
 
         Value thisv = iter.thisv(cx);
         if (!thisv.isObject() ||
             thisv.toObject().hasLazyType() ||
             thisv.toObject().type() != type)
         {
             continue;
         }
 
-        if (thisv.toObject().is<UnboxedPlainObject>() &&
-            !thisv.toObject().as<UnboxedPlainObject>().convertToNative(cx))
-        {
-            CrashAtUnhandlableOOM("rollbackPartiallyInitializedObjects");
-        }
-
         // Found a matching frame.
         RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>());
 
         // Whether all identified 'new' properties have been initialized.
         bool finished = false;
 
         // If not finished, number of properties that have been added.
         uint32_t numProperties = 0;
@@ -4310,45 +4212,48 @@ TypeNewScript::rollbackPartiallyInitiali
                 }
             } else {
                 MOZ_ASSERT(init->kind == Initializer::DONE);
                 finished = true;
                 break;
             }
         }
 
-        if (!finished) {
+        if (!finished)
             (void) NativeObject::rollbackProperties(cx, obj, numProperties);
-            found = true;
-        }
-    }
-
-    return found;
+    }
 }
 
 void
 TypeNewScript::trace(JSTracer *trc)
 {
-    MarkObject(trc, &function_, "TypeNewScript_function");
+    MarkObject(trc, &fun, "TypeNewScript_function");
 
     if (templateObject_)
         MarkObject(trc, &templateObject_, "TypeNewScript_templateObject");
 
     if (initializedShape_)
         MarkShape(trc, &initializedShape_, "TypeNewScript_initializedShape");
 
     if (initializedType_)
         MarkTypeObject(trc, &initializedType_, "TypeNewScript_initializedType");
 }
 
 void
 TypeNewScript::sweep()
 {
-    if (preliminaryObjects)
-        preliminaryObjects->sweep();
+    // preliminaryObjects only holds weak pointers, so clear any objects that
+    // are about to be destroyed.
+    if (preliminaryObjects) {
+        for (size_t i = 0; i < PRELIMINARY_OBJECT_COUNT; i++) {
+            PlainObject **ptr = &preliminaryObjects[i];
+            if (*ptr && IsObjectAboutToBeFinalized(ptr))
+                *ptr = nullptr;
+        }
+    }
 }
 
 /////////////////////////////////////////////////////////////////////
 // JSObject
 /////////////////////////////////////////////////////////////////////
 
 bool
 JSObject::shouldSplicePrototype(JSContext *cx)
@@ -4452,17 +4357,17 @@ NewTypeObjectEntry::hash(const Lookup &l
            PointerHasher<const Class *, 3>::hash(lookup.clasp) ^
            PointerHasher<JSObject *, 3>::hash(lookup.associated);
 }
 
 /* static */ inline bool
 NewTypeObjectEntry::match(const NewTypeObjectEntry &key, const Lookup &lookup)
 {
     return key.object->proto() == lookup.matchProto &&
-           (!lookup.clasp || key.object->clasp() == lookup.clasp) &&
+           key.object->clasp() == lookup.clasp &&
            key.associated == lookup.associated;
 }
 
 #ifdef DEBUG
 bool
 JSObject::hasNewType(const Class *clasp, TypeObject *type)
 {
     NewTypeObjectTable &table = compartment()->newTypeObjects;
@@ -4521,18 +4426,17 @@ class NewTypeObjectsSetRef : public Buff
         trc->setTracingLocation(&*prior);
         Mark(trc, &proto, "newTypeObjects set prototype");
         if (prior == proto)
             return;
 
         NewTypeObjectTable::Ptr p =
             set->lookup(NewTypeObjectTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto),
                                                    associated));
-        if (!p)
-            return;
+        MOZ_ASSERT(p);  // newTypeObjects set must still contain original entry.
 
         set->rekeyAs(NewTypeObjectTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), associated),
                      NewTypeObjectTable::Lookup(clasp, TaggedProto(proto), associated), *p);
     }
 };
 
 static void
 TypeObjectTablePostBarrier(ExclusiveContext *cx, NewTypeObjectTable *table,
@@ -4556,71 +4460,52 @@ TypeObjectTablePostBarrier(ExclusiveCont
 
 TypeObject *
 ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSObject *associated)
 {
     MOZ_ASSERT_IF(associated, proto.isObject());
     MOZ_ASSERT_IF(associated, associated->is<JSFunction>() || associated->is<TypeDescr>());
     MOZ_ASSERT_IF(proto.isObject(), isInsideCurrentCompartment(proto.toObject()));
 
-    // A null lookup clasp is used for 'new' type objects with an associated
-    // function. The type starts out as a plain object but might mutate into an
-    // unboxed plain object.
-    MOZ_ASSERT(!clasp == (associated && associated->is<JSFunction>()));
-
     NewTypeObjectTable &newTypeObjects = compartment()->newTypeObjects;
 
     if (!newTypeObjects.initialized() && !newTypeObjects.init())
         return nullptr;
 
+    // Canonicalize new functions to use the original one associated with its script.
     if (associated && associated->is<JSFunction>()) {
-        MOZ_ASSERT(!clasp);
-
-        // Canonicalize new functions to use the original one associated with its script.
         JSFunction *fun = &associated->as<JSFunction>();
         if (fun->hasScript())
             associated = fun->nonLazyScript()->functionNonDelazifying();
         else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin())
             associated = fun->lazyScript()->functionNonDelazifying();
         else
             associated = nullptr;
-
-        // If we have previously cleared the 'new' script information for this
-        // function, don't try to construct another one.
-        if (associated && associated->wasNewScriptCleared())
-            associated = nullptr;
-
-        if (!associated)
-            clasp = &PlainObject::class_;
     }
 
     NewTypeObjectTable::AddPtr p =
         newTypeObjects.lookupForAdd(NewTypeObjectTable::Lookup(clasp, proto, associated));
     if (p) {
         TypeObject *type = p->object;
-        MOZ_ASSERT_IF(clasp, type->clasp() == clasp);
-        MOZ_ASSERT_IF(!clasp, type->clasp() == &PlainObject::class_ ||
-                              type->clasp() == &UnboxedPlainObject::class_);
+        MOZ_ASSERT(type->clasp() == clasp);
         MOZ_ASSERT(type->proto() == proto);
         return type;
     }
 
     AutoEnterAnalysis enter(this);
 
     if (proto.isObject() && !proto.toObject()->setDelegate(this))
         return nullptr;
 
     TypeObjectFlags initialFlags = 0;
-    if (!proto.isObject() || proto.toObject()->isNewTypeUnknown())
+    if (!proto.isObject() || proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN))
         initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
 
     Rooted<TaggedProto> protoRoot(this, proto);
-    TypeObject *type = compartment()->types.newTypeObject(this,
-                                                          clasp ? clasp : &PlainObject::class_,
-                                                          protoRoot, initialFlags);
+    TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, initialFlags);
     if (!type)
         return nullptr;
 
     if (!newTypeObjects.add(p, NewTypeObjectEntry(type, associated)))
         return nullptr;
 
     TypeObjectTablePostBarrier(this, &newTypeObjects, clasp, proto, associated);
 
@@ -4837,19 +4722,16 @@ TypeObject::maybeSweep(AutoClearTypeInfe
     setGeneration(zone()->types.generation);
 
     MOZ_ASSERT(zone()->isGCSweepingOrCompacting());
     MOZ_ASSERT(!zone()->runtimeFromMainThread()->isHeapMinorCollecting());
 
     Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
     EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM);
 
-    if (maybeUnboxedLayout() && unboxedLayout().newScript())
-        unboxedLayout().newScript()->sweep();
-
     if (newScript())
         newScript()->sweep();
 
     LifoAlloc &typeLifoAlloc = zone()->types.typeLifoAlloc;
 
     /*
      * Properties were allocated from the old arena, and need to be copied over
      * to the new one.
@@ -5055,26 +4937,63 @@ JSCompartment::fixupNewTypeObjectTable(N
                 proto = TaggedProto(Forwarded(proto.toObject()));
                 needRekey = true;
             }
             if (entry.associated && IsForwarded(entry.associated)) {
                 entry.associated = Forwarded(entry.associated);
                 needRekey = true;
             }
             if (needRekey) {
-                const Class *clasp = entry.object->clasp();
-                if (entry.associated && entry.associated->is<JSFunction>())
-                    clasp = nullptr;
-                NewTypeObjectTable::Lookup lookup(clasp, proto, entry.associated);
+                NewTypeObjectTable::Lookup lookup(entry.object->clasp(),
+                                                  proto,
+                                                  entry.associated);
                 e.rekeyFront(lookup, entry);
             }
         }
     }
 }
 
+void
+TypeNewScript::fixupAfterMovingGC()
+{
+    if (fun && IsForwarded(fun.get()))
+        fun = Forwarded(fun.get());
+    /* preliminaryObjects are handled by sweep(). */
+    if (templateObject_ && IsForwarded(templateObject_.get()))
+        templateObject_ = Forwarded(templateObject_.get());
+    if (initializedShape_ && IsForwarded(initializedShape_.get()))
+        initializedShape_ = Forwarded(initializedShape_.get());
+}
+
+void
+TypeObject::fixupAfterMovingGC()
+{
+    if (proto().isObject() && IsForwarded(proto_.get()))
+        proto_ = Forwarded(proto_.get());
+    if (singleton_ && !lazy() && IsForwarded(singleton_.get()))
+        singleton_ = Forwarded(singleton_.get());
+    if (addendum_) {
+        switch (addendumKind()) {
+          case Addendum_NewScript:
+            newScript()->fixupAfterMovingGC();
+            break;
+          case Addendum_TypeDescr:
+            if (IsForwarded(&typeDescr()))
+                addendum_ = Forwarded(&typeDescr());
+            break;
+          case Addendum_InterpretedFunction:
+            if (IsForwarded(maybeInterpretedFunction()))
+                addendum_ = Forwarded(maybeInterpretedFunction());
+            break;
+          default:
+            MOZ_CRASH();
+        }
+    }
+}
+
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 JSCompartment::checkTypeObjectTablesAfterMovingGC()
 {
     checkTypeObjectTableAfterMovingGC(newTypeObjects);
     checkTypeObjectTableAfterMovingGC(lazyTypeObjects);
 }
@@ -5092,21 +5011,18 @@ JSCompartment::checkTypeObjectTableAfter
     for (NewTypeObjectTable::Enum e(table); !e.empty(); e.popFront()) {
         NewTypeObjectEntry entry = e.front();
         CheckGCThingAfterMovingGC(entry.object.get());
         TaggedProto proto = entry.object->proto();
         if (proto.isObject())
             CheckGCThingAfterMovingGC(proto.toObject());
         CheckGCThingAfterMovingGC(entry.associated);
 
-        const Class *clasp = entry.object->clasp();
-        if (entry.associated && entry.associated->is<JSFunction>())
-            clasp = nullptr;
-
-        NewTypeObjectTable::Lookup lookup(clasp, proto, entry.associated);
+        NewTypeObjectTable::Lookup
+            lookup(entry.object->clasp(), proto, entry.associated);
         NewTypeObjectTable::Ptr ptr = table.lookup(lookup);
         MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
     }
 }
 
 #endif // JSGC_HASH_TABLE_CHECKS
 
 TypeCompartment::~TypeCompartment()
@@ -5205,22 +5121,18 @@ TypeCompartment::addSizeOfExcludingThis(
             *objectTypeTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types);
         }
     }
 }
 
 size_t
 TypeObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
-    size_t n = 0;
-    if (TypeNewScript *newScript = newScriptDontCheckGeneration())
-        n += newScript->sizeOfIncludingThis(mallocSizeOf);
-    if (UnboxedLayout *layout = maybeUnboxedLayoutDontCheckGeneration())
-        n += layout->sizeOfIncludingThis(mallocSizeOf);
-    return n;
+    TypeNewScript *newScript = newScriptDontCheckGeneration();
+    return newScript ? newScript->sizeOfIncludingThis(mallocSizeOf) : 0;
 }
 
 TypeZone::TypeZone(Zone *zone)
   : zone_(zone),
     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     generation(0),
     compilerOutputs(nullptr),
     sweepTypeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
@@ -5374,26 +5286,24 @@ TypeScript::printTypes(JSContext *cx, Ha
         }
     }
 
     fprintf(stderr, "\n");
 }
 #endif /* DEBUG */
 
 void
-TypeObject::setAddendum(AddendumKind kind, void *addendum, bool writeBarrier /* = true */)
+TypeObject::setAddendum(AddendumKind kind, void *addendum)
 {
     MOZ_ASSERT(!needsSweep());
     MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT));
-
-    if (writeBarrier) {
-        // Manually trigger barriers if we are clearing a TypeNewScript. Other
-        // kinds of addendums are immutable.
-        if (newScript())
-            TypeNewScript::writeBarrierPre(newScript());
-        else
-            MOZ_ASSERT(addendumKind() == Addendum_None || addendumKind() == kind);
-    }
-
-    flags_ &= ~OBJECT_FLAG_ADDENDUM_MASK;
+    MOZ_ASSERT(addendumKind() == 0 || addendumKind() == kind);
+
+    // Manually trigger barriers if we are clearing a TypeNewScript. Other
+    // kinds of addendums are immutable.
+    if (newScript()) {
+        MOZ_ASSERT(kind == Addendum_NewScript);
+        TypeNewScript::writeBarrierPre(newScript());
+    }
+
     flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT;
     addendum_ = addendum;
 }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -22,17 +22,16 @@
 #include "jit/IonTypes.h"
 #include "js/UbiNode.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace js {
 
 class TypeDescr;
-class UnboxedLayout;
 
 class TaggedProto
 {
   public:
     static JSObject * const LazyProto;
 
     TaggedProto() : proto(nullptr) {}
     explicit TaggedProto(JSObject *proto) : proto(proto) {}
@@ -402,36 +401,33 @@ enum : uint32_t {
      * Whether objects with this type should be allocated directly in the
      * tenured heap.
      */
     OBJECT_FLAG_PRE_TENURE            = 0x00800000,
 
     /* Whether objects with this type might have copy on write elements. */
     OBJECT_FLAG_COPY_ON_WRITE         = 0x01000000,
 
-    /* Whether this type has had its 'new' script cleared in the past. */
-    OBJECT_FLAG_NEW_SCRIPT_CLEARED    = 0x02000000,
-
     /*
      * Whether all properties of this object are considered unknown.
      * If set, all other flags in DYNAMIC_MASK will also be set.
      */
-    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x04000000,
+    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x02000000,
 
     /* Flags which indicate dynamic properties of represented objects. */
-    OBJECT_FLAG_DYNAMIC_MASK          = 0x07ff0000,
+    OBJECT_FLAG_DYNAMIC_MASK          = 0x03ff0000,
 
     // Mask/shift for the kind of addendum attached to this type object.
-    OBJECT_FLAG_ADDENDUM_MASK         = 0x38000000,
-    OBJECT_FLAG_ADDENDUM_SHIFT        = 27,
+    OBJECT_FLAG_ADDENDUM_MASK         = 0x0c000000,
+    OBJECT_FLAG_ADDENDUM_SHIFT        = 26,
 
     // Mask/shift for this type object's generation. If out of sync with the
     // TypeZone's generation, this TypeObject hasn't been swept yet.
-    OBJECT_FLAG_GENERATION_MASK       = 0x40000000,
-    OBJECT_FLAG_GENERATION_SHIFT      = 30,
+    OBJECT_FLAG_GENERATION_MASK       = 0x10000000,
+    OBJECT_FLAG_GENERATION_SHIFT      = 28,
 };
 typedef uint32_t TypeObjectFlags;
 
 class StackTypeSet;
 class HeapTypeSet;
 class TemporaryTypeSet;
 
 /*
@@ -634,16 +630,17 @@ class StackTypeSet : public ConstraintTy
 
 class HeapTypeSet : public ConstraintTypeSet
 {
     inline void newPropertyState(ExclusiveContext *cx);
 
   public:
     /* Mark this type set as representing a non-data property. */
     inline void setNonDataProperty(ExclusiveContext *cx);
+    inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
 
     /* Mark this type set as representing a non-writable property. */
     inline void setNonWritableProperty(ExclusiveContext *cx);
 
     // Mark this type set as being non-constant.
     inline void setNonConstantProperty(ExclusiveContext *cx);
 };
 
@@ -792,48 +789,16 @@ struct Property
     Property(const Property &o)
       : id(o.id.get()), types(o.types)
     {}
 
     static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
     static jsid getKey(Property *p) { return p->id; }
 };
 
-// For types where only a small number of objects have been allocated, this
-// structure keeps track of all objects with the type in existence. Once
-// COUNT objects have been allocated, this structure is cleared and the objects
-// are analyzed, to perform the new script properties analyses or determine if
-// an unboxed representation can be used.
-class PreliminaryObjectArray
-{
-  public:
-    static const uint32_t COUNT = 20;
-
-  private:
-    // All objects with the type which have been allocated. The pointers in
-    // this array are weak.
-    JSObject *objects[COUNT];
-
-  public:
-    PreliminaryObjectArray() {
-        mozilla::PodZero(this);
-    }
-
-    void registerNewObject(JSObject *res);
-    void unregisterNewObject(JSObject *res);
-
-    JSObject *get(size_t i) const {
-        MOZ_ASSERT(i < COUNT);
-        return objects[i];
-    }
-
-    bool full() const;
-    void sweep();
-};
-
 // New script properties analyses overview.
 //
 // When constructing objects using 'new' on a script, we attempt to determine
 // the properties which that object will eventually have. This is done via two
 // analyses. One of these, the definite properties analysis, is static, and the
 // other, the acquired properties analysis, is dynamic. As objects are
 // constructed using 'new' on some script to create objects of type T, our
 // analysis strategy is as follows:
@@ -881,28 +846,31 @@ class TypeNewScript
           : kind(kind), offset(offset)
         {}
     };
 
   private:
     // Scripted function which this information was computed for.
     // If instances of the associated type object are created without calling
     // 'new' on this function, the new script information is cleared.
-    HeapPtrFunction function_;
+    HeapPtrFunction fun;
 
-    // Any preliminary objects with the type. The analyses are not performed
-    // until this array is cleared.
-    PreliminaryObjectArray *preliminaryObjects;
+    // If fewer than PRELIMINARY_OBJECT_COUNT instances of the type are
+    // created, this array holds pointers to each of those objects. When the
+    // threshold has been reached, the definite and acquired properties
+    // analyses are performed and this array is cleared. The pointers in this
+    // array are weak.
+    static const uint32_t PRELIMINARY_OBJECT_COUNT = 20;
+    PlainObject **preliminaryObjects;
 
     // After the new script properties analyses have been performed, a template
     // object to use for newly constructed objects. The shape of this object
     // reflects all definite properties the object will have, and the
-    // allocation kind to use. This is null if the new objects have an unboxed
-    // layout, in which case the UnboxedLayout provides the initial structure
-    // of the object.
+    // allocation kind to use. Note that this is actually a PlainObject, but is
+    // JSObject here to avoid cyclic include dependencies.
     HeapPtrPlainObject templateObject_;
 
     // Order in which definite properties become initialized. We need this in
     // case the definite properties are invalidated (such as by adding a setter
     // to an object on the prototype chain) while an object is in the middle of
     // being initialized, so we can walk the stack and fixup any objects which
     // look for in-progress objects which were prematurely set with an incorrect
     // shape. Property assignments in inner frames are preceded by a series of
@@ -919,50 +887,55 @@ class TypeNewScript
 
     // Type object with definite properties set for all properties found by
     // both the definite and acquired properties analyses.
     HeapPtrTypeObject initializedType_;
 
   public:
     TypeNewScript() { mozilla::PodZero(this); }
     ~TypeNewScript() {
-        js_delete(preliminaryObjects);
+        js_free(preliminaryObjects);
         js_free(initializerList);
     }
 
     static inline void writeBarrierPre(TypeNewScript *newScript);
 
     bool analyzed() const {
-        return preliminaryObjects == nullptr;
+        if (preliminaryObjects) {
+            MOZ_ASSERT(!templateObject());
+            MOZ_ASSERT(!initializerList);
+            MOZ_ASSERT(!initializedShape());
+            MOZ_ASSERT(!initializedType());
+            return false;
+        }
+        MOZ_ASSERT(templateObject());
+        return true;
     }
 
     PlainObject *templateObject() const {
         return templateObject_;
     }
 
     Shape *initializedShape() const {
         return initializedShape_;
     }
 
     TypeObject *initializedType() const {
         return initializedType_;
     }
 
-    JSFunction *function() const {
-        return function_;
-    }
-
     void trace(JSTracer *trc);
     void sweep();
+    void fixupAfterMovingGC();
 
     void registerNewObject(PlainObject *res);
     void unregisterNewObject(PlainObject *res);
     bool maybeAnalyze(JSContext *cx, TypeObject *type, bool *regenerate, bool force = false);
 
-    bool rollbackPartiallyInitializedObjects(JSContext *cx, TypeObject *type);
+    void rollbackPartiallyInitializedObjects(JSContext *cx, TypeObject *type);
 
     static void make(JSContext *cx, TypeObject *type, JSFunction *fun);
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 /*
  * Lazy type objects overview.
@@ -1003,16 +976,17 @@ struct TypeObject : public gc::TenuredCe
 
   public:
 
     const Class *clasp() const {
         return clasp_;
     }
 
     void setClasp(const Class *clasp) {
+        MOZ_ASSERT(singleton());
         clasp_ = clasp;
     }
 
     TaggedProto proto() const {
         return TaggedProto(proto_);
     }
 
     JSObject *singleton() const {
@@ -1050,51 +1024,37 @@ struct TypeObject : public gc::TenuredCe
         // When used by interpreted function, the addendum stores the
         // canonical JSFunction object.
         Addendum_InterpretedFunction,
 
         // When used by the 'new' type when constructing an interpreted
         // function, the addendum stores a TypeNewScript.
         Addendum_NewScript,
 
-        // When objects with this type have an unboxed representation, the
-        // addendum stores an UnboxedLayout (which might have a TypeNewScript
-        // as well, if the type is also constructed using 'new').
-        Addendum_UnboxedLayout,
-
         // When used by typed objects, the addendum stores a TypeDescr.
         Addendum_TypeDescr
     };
 
     // If non-null, holds additional information about this object, whose
     // format is indicated by the object's addendum kind.
     void *addendum_;
 
-    void setAddendum(AddendumKind kind, void *addendum, bool writeBarrier = true);
+    void setAddendum(AddendumKind kind, void *addendum);
 
     AddendumKind addendumKind() const {
         return (AddendumKind)
             ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
     }
 
     TypeNewScript *newScriptDontCheckGeneration() const {
-        if (addendumKind() == Addendum_NewScript)
-            return reinterpret_cast<TypeNewScript *>(addendum_);
-        return nullptr;
+        return addendumKind() == Addendum_NewScript
+               ? reinterpret_cast<TypeNewScript *>(addendum_)
+               : nullptr;
     }
 
-    UnboxedLayout *maybeUnboxedLayoutDontCheckGeneration() const {
-        if (addendumKind() == Addendum_UnboxedLayout)
-            return reinterpret_cast<UnboxedLayout *>(addendum_);
-        return nullptr;
-    }
-
-    TypeNewScript *anyNewScript();
-    void detachNewScript(bool writeBarrier);
-
   public:
 
     TypeObjectFlags flags() {
         maybeSweep(nullptr);
         return flags_;
     }
 
     void addFlags(TypeObjectFlags flags) {
@@ -1111,30 +1071,16 @@ struct TypeObject : public gc::TenuredCe
         maybeSweep(nullptr);
         return newScriptDontCheckGeneration();
     }
 
     void setNewScript(TypeNewScript *newScript) {
         setAddendum(Addendum_NewScript, newScript);
     }
 
-    UnboxedLayout *maybeUnboxedLayout() {
-        maybeSweep(nullptr);
-        return maybeUnboxedLayoutDontCheckGeneration();
-    }
-
-    UnboxedLayout &unboxedLayout() {
-        MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
-        return *maybeUnboxedLayout();
-    }
-
-    void setUnboxedLayout(UnboxedLayout *layout) {
-        setAddendum(Addendum_UnboxedLayout, layout);
-    }
-
     TypeDescr *maybeTypeDescr() {
         // Note: there is no need to sweep when accessing the type descriptor
         // of an object, as it is strongly held and immutable.
         if (addendumKind() == Addendum_TypeDescr)
             return reinterpret_cast<TypeDescr *>(addendum_);
         return nullptr;
     }
 
@@ -1164,18 +1110,18 @@ struct TypeObject : public gc::TenuredCe
      * Properties of this object. This may contain JSID_VOID, representing the
      * types of all integer indexes of the object, and/or JSID_EMPTY, holding
      * constraints listening to changes to the object's state.
      *
      * The type sets in the properties of a type object describe the possible
      * values that can be read out of that property in actual JS objects.
      * In native objects, property types account for plain data properties
      * (those with a slot and no getter or setter hook) and dense elements.
-     * In typed objects and unboxed objects, property types account for object
-     * and value properties and elements in the object.
+     * In typed objects, property types account for object and value properties
+     * and elements in the object.
      *
      * For accesses on these properties, the correspondence is as follows:
      *
      * 1. If the type has unknownProperties(), the possible properties and
      *    value types for associated JSObjects are unknown.
      *
      * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
      *    which is a property in obj, before obj->getProperty(id) the property
@@ -1188,20 +1134,19 @@ struct TypeObject : public gc::TenuredCe
      *    remain empty, and the 'undefined' type will only be added after a
      *    subsequent assignment or deletion. After these properties have been
      *    assigned a defined value, the only way they can become undefined
      *    again is after such an assign or deletion.
      *
      * 2. Array lengths are special cased by the compiler and VM and are not
      *    reflected in property types.
      *
-     * 3. In typed objects (but not unboxed objects), the initial values of
-     *    properties (null pointers and undefined values) are not reflected in
-     *    the property types. These values are always possible when reading the
-     *    property.
+     * 3. In typed objects, the initial values of properties (null pointers and
+     *    undefined values) are not reflected in the property types. These
+     *    values are always possible when reading the property.
      *
      * We establish these by using write barriers on calls to setProperty and
      * defineProperty which are on native properties, and on any jitcode which
      * might update the property with a new type.
      */
     Property **propertySet;
   public:
 
@@ -1289,20 +1234,21 @@ struct TypeObject : public gc::TenuredCe
 
   public:
     void setGeneration(uint32_t generation) {
         MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT));
         flags_ &= ~OBJECT_FLAG_GENERATION_MASK;
         flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT;
     }
 
+    void fixupAfterMovingGC();
+
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     inline void finalize(FreeOp *fop);
-    void fixupAfterMovingGC() {}
 
     static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
 
     static inline uint32_t offsetOfClasp() {
         return offsetof(TypeObject, clasp_);
     }
 
     static inline uint32_t offsetOfProto() {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -17,17 +17,16 @@
 #include "jit/BaselineJIT.h"
 #include "vm/ArrayObject.h"
 #include "vm/BooleanObject.h"
 #include "vm/NumberObject.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/SharedTypedArrayObject.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
-#include "vm/UnboxedObject.h"
 
 #include "jscntxtinlines.h"
 
 namespace js {
 namespace types {
 
 /////////////////////////////////////////////////////////////////////
 // CompilerOutput & RecompileInfo
@@ -1078,22 +1077,28 @@ HeapTypeSet::newPropertyState(ExclusiveC
             constraint = constraint->next;
         }
     } else {
         MOZ_ASSERT(!constraintList);
     }
 }
 
 inline void
+HeapTypeSet::setNonDataPropertyIgnoringConstraints()
+{
+    flags |= TYPE_FLAG_NON_DATA_PROPERTY;
+}
+
+inline void
 HeapTypeSet::setNonDataProperty(ExclusiveContext *cx)
 {
     if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
         return;
 
-    flags |= TYPE_FLAG_NON_DATA_PROPERTY;
+    setNonDataPropertyIgnoringConstraints();
     newPropertyState(cx);
 }
 
 inline void
 HeapTypeSet::setNonWritableProperty(ExclusiveContext *cx)
 {
     if (flags & TYPE_FLAG_NON_WRITABLE_PROPERTY)
         return;
@@ -1190,17 +1195,16 @@ inline TypeObject::TypeObject(const Clas
 
     InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
 }
 
 inline void
 TypeObject::finalize(FreeOp *fop)
 {
     fop->delete_(newScriptDontCheckGeneration());
-    fop->delete_(maybeUnboxedLayoutDontCheckGeneration());
 }
 
 inline uint32_t
 TypeObject::basePropertyCount()
 {
     return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
 }
 
@@ -1285,20 +1289,20 @@ TypeObject::getProperty(unsigned i)
         return (Property *) propertySet;
     }
     return propertySet[i];
 }
 
 inline void
 TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
 {
-    if (!newScript->function()->runtimeFromAnyThread()->needsIncrementalBarrier())
+    if (!newScript->fun->runtimeFromAnyThread()->needsIncrementalBarrier())
         return;
 
-    JS::Zone *zone = newScript->function()->zoneFromAnyThread();
+    JS::Zone *zone = newScript->fun->zoneFromAnyThread();
     if (zone->needsIncrementalBarrier())
         newScript->trace(zone->barrierTracer());
 }
 
 } } /* namespace js::types */
 
 inline js::types::TypeScript *
 JSScript::types()
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -896,19 +896,16 @@ bool
 js::StandardDefineProperty(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
                            bool throwError, bool *rval)
 {
     if (obj->is<ArrayObject>()) {
         Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
         return DefinePropertyOnArray(cx, arr, id, desc, throwError, rval);
     }
 
-    if (obj->is<UnboxedPlainObject>() && !obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-
     if (obj->getOps()->lookupGeneric) {
         if (obj->is<ProxyObject>()) {
             Rooted<PropertyDescriptor> pd(cx);
             desc.populatePropertyDescriptor(obj, &pd);
             pd.object().set(obj);
             return Proxy::defineProperty(cx, obj, id, &pd);
         }
         return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
@@ -961,19 +958,16 @@ js::DefineProperties(JSContext *cx, Hand
         Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
         for (size_t i = 0, len = ids.length(); i < len; i++) {
             if (!DefinePropertyOnArray(cx, arr, ids[i], descs[i], true, &dummy))
                 return false;
         }
         return true;
     }
 
-    if (obj->is<UnboxedPlainObject>() && !obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-
     if (obj->getOps()->lookupGeneric) {
         if (obj->is<ProxyObject>()) {
             Rooted<PropertyDescriptor> pd(cx);
             for (size_t i = 0, len = ids.length(); i < len; i++) {
                 descs[i].populatePropertyDescriptor(obj, &pd);
                 if (!Proxy::defineProperty(cx, obj, ids[i], &pd))
                     return false;
             }
@@ -1492,23 +1486,20 @@ js::CreateThis(JSContext *cx, const Clas
         return nullptr;
 
     JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : nullptr;
     JSObject *parent = callee->getParent();
     gc::AllocKind kind = NewObjectGCKind(newclasp);
     return NewObjectWithClassProto(cx, newclasp, proto, parent, kind);
 }
 
-static inline JSObject *
+static inline PlainObject *
 CreateThisForFunctionWithType(JSContext *cx, HandleTypeObject type, JSObject *parent,
                               NewObjectKind newKind)
 {
-    if (type->maybeUnboxedLayout() && newKind != SingletonObject)
-        return UnboxedPlainObject::create(cx, type, newKind);
-
     if (types::TypeNewScript *newScript = type->newScript()) {
         if (newScript->analyzed()) {
             // The definite properties analysis has been performed for this
             // type, so get the shape and finalize kind to use from the
             // TypeNewScript's template.
             RootedPlainObject templateObject(cx, newScript->templateObject());
             MOZ_ASSERT(templateObject->type() == type);
 
@@ -1544,36 +1535,36 @@ CreateThisForFunctionWithType(JSContext 
 
         return res;
     }
 
     gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
     return NewObjectWithType<PlainObject>(cx, type, parent, allocKind, newKind);
 }
 
-JSObject *
+PlainObject *
 js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject *proto,
                                    NewObjectKind newKind /* = GenericObject */)
 {
-    RootedObject res(cx);
+    RootedPlainObject res(cx);
 
     if (proto) {
-        RootedTypeObject type(cx, cx->getNewType(nullptr, TaggedProto(proto),
+        RootedTypeObject type(cx, cx->getNewType(&PlainObject::class_, TaggedProto(proto),
                                                  &callee->as<JSFunction>()));
         if (!type)
             return nullptr;
 
         if (type->newScript() && !type->newScript()->analyzed()) {
             bool regenerate;
             if (!type->newScript()->maybeAnalyze(cx, type, &regenerate))
                 return nullptr;
             if (regenerate) {
                 // The script was analyzed successfully and may have changed
                 // the new type table, so refetch the type.
-                type = cx->getNewType(nullptr, TaggedProto(proto),
+                type = cx->getNewType(&PlainObject::class_, TaggedProto(proto),
                                       &callee->as<JSFunction>());
                 MOZ_ASSERT(type && type->newScript());
             }
         }
 
         res = CreateThisForFunctionWithType(cx, type, callee->getParent(), newKind);
     } else {
         gc::AllocKind allocKind = NewObjectGCKind(&PlainObject::class_);
@@ -1585,31 +1576,31 @@ js::CreateThisForFunctionWithProto(JSCon
         if (!script)
             return nullptr;
         TypeScript::SetThis(cx, script, types::Type::ObjectType(res));
     }
 
     return res;
 }
 
-JSObject *
+PlainObject *
 js::CreateThisForFunction(JSContext *cx, HandleObject callee, NewObjectKind newKind)
 {
     RootedValue protov(cx);
     if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov))
         return nullptr;
     JSObject *proto;
     if (protov.isObject())
         proto = &protov.toObject();
     else
         proto = nullptr;
-    JSObject *obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind);
+    PlainObject *obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind);
 
     if (obj && newKind == SingletonObject) {
-        RootedPlainObject nobj(cx, &obj->as<PlainObject>());
+        RootedPlainObject nobj(cx, obj);
 
         /* Reshape the singleton before passing it as the 'this' value. */
         NativeObject::clear(cx, nobj);
 
         JSScript *calleeScript = callee->as<JSFunction>().nonLazyScript();
         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
 
         return nobj;
@@ -3800,17 +3791,16 @@ JSObject::dump()
     if (obj->isBoundFunction()) fprintf(stderr, " bound_function");
     if (obj->isQualifiedVarObj()) fprintf(stderr, " varobj");
     if (obj->isUnqualifiedVarObj()) fprintf(stderr, " unqualified_varobj");
     if (obj->watched()) fprintf(stderr, " watched");
     if (obj->isIteratedSingleton()) fprintf(stderr, " iterated_singleton");
     if (obj->isNewTypeUnknown()) fprintf(stderr, " new_type_unknown");
     if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto");
     if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access");
-    if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared");
 
     if (obj->isNative()) {
         NativeObject *nobj = &obj->as<NativeObject>();
         if (nobj->inDictionaryMode())
             fprintf(stderr, " inDictionaryMode");
         if (nobj->hasShapeTable())
             fprintf(stderr, " hasShapeTable");
     }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -421,24 +421,16 @@ class JSObject : public js::gc::Cell
      * Mark an object as requiring its default 'new' type to have unknown
      * properties.
      */
     bool isNewTypeUnknown() const {
         return lastProperty()->hasObjectFlag(js::BaseShape::NEW_TYPE_UNKNOWN);
     }
     static bool setNewTypeUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj);
 
-    // Mark an object as having its 'new' script information cleared.
-    bool wasNewScriptCleared() const {
-        return lastProperty()->hasObjectFlag(js::BaseShape::NEW_SCRIPT_CLEARED);
-    }
-    bool setNewScriptCleared(js::ExclusiveContext *cx) {
-        return setFlag(cx, js::BaseShape::NEW_SCRIPT_CLEARED);
-    }
-
     /* Set a new prototype for an object with a singleton type. */
     bool splicePrototype(JSContext *cx, const js::Class *clasp, js::Handle<js::TaggedProto> proto);
 
     /*
      * For bootstrapping, whether to splice a prototype for Function.prototype
      * or the global object.
      */
     bool shouldSplicePrototype(JSContext *cx);
@@ -602,19 +594,16 @@ class JSObject : public js::gc::Cell
     /* JIT Accessors */
 
     static size_t offsetOfShape() { return offsetof(JSObject, shape_); }
     js::HeapPtrShape *addressOfShape() { return &shape_; }
 
     static size_t offsetOfType() { return offsetof(JSObject, type_); }
     js::HeapPtrTypeObject *addressOfType() { return &type_; }
 
-    // Maximum size in bytes of a JSObject.
-    static const size_t MAX_BYTE_SIZE = 4 * sizeof(void *) + 16 * sizeof(JS::Value);
-
   private:
     JSObject() = delete;
     JSObject(const JSObject &other) = delete;
     void operator=(const JSObject &other) = delete;
 };
 
 template <class U>
 MOZ_ALWAYS_INLINE JS::Handle<U*>
@@ -1160,22 +1149,22 @@ GetInitialHeap(NewObjectKind newKind, co
         return gc::TenuredHeap;
     if (clasp->finalize && !(clasp->flags & JSCLASS_FINALIZE_FROM_NURSERY))
         return gc::TenuredHeap;
     return gc::DefaultHeap;
 }
 
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
-extern JSObject *
+extern PlainObject *
 CreateThisForFunctionWithProto(JSContext *cx, js::HandleObject callee, JSObject *proto,
                                NewObjectKind newKind = GenericObject);
 
 // Specialized call for constructing |this| with a known function callee.
-extern JSObject *
+extern PlainObject *
 CreateThisForFunction(JSContext *cx, js::HandleObject callee, NewObjectKind newKind);
 
 // Generic call for constructing |this|.
 extern JSObject *
 CreateThis(JSContext *cx, const js::Class *clasp, js::HandleObject callee);
 
 extern JSObject *
 CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent);
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -266,17 +266,16 @@ UNIFIED_SOURCES += [
     'vm/SPSProfiler.cpp',
     'vm/Stack.cpp',
     'vm/String.cpp',
     'vm/StringBuffer.cpp',
     'vm/StructuredClone.cpp',
     'vm/Symbol.cpp',
     'vm/TypedArrayObject.cpp',
     'vm/UbiNode.cpp',
-    'vm/UnboxedObject.cpp',
     'vm/Unicode.cpp',
     'vm/Value.cpp',
     'vm/WeakMapPtr.cpp',
     'vm/Xdr.cpp'
 ]
 
 # jsarray.cpp and jsatom.cpp cannot be built in unified mode because
 # xpcshell is broken during packaging when compiled with gcc-4.8.2
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5524,23 +5524,21 @@ ProcessArgs(JSContext *cx, JSObject *obj
 
 static bool
 SetRuntimeOptions(JSRuntime *rt, const OptionParser &op)
 {
     bool enableBaseline = !op.getBoolOption("no-baseline");
     bool enableIon = !op.getBoolOption("no-ion");
     bool enableAsmJS = !op.getBoolOption("no-asmjs");
     bool enableNativeRegExp = !op.getBoolOption("no-native-regexp");
-    bool enableUnboxedObjects = op.getBoolOption("unboxed-objects");
 
     JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
-                             .setNativeRegExp(enableNativeRegExp)
-                             .setUnboxedObjects(enableUnboxedObjects);
+                             .setNativeRegExp(enableNativeRegExp);
 
     if (const char *str = op.getStringOption("ion-scalar-replacement")) {
         if (strcmp(str, "on") == 0)
             jit::js_JitOptions.disableScalarReplacement = false;
         else if (strcmp(str, "off") == 0)
             jit::js_JitOptions.disableScalarReplacement = true;
         else
             return OptionFailure("ion-scalar-replacement", str);
@@ -5872,17 +5870,16 @@ main(int argc, char **argv, char **envp)
                                          "String arguments to bind as |scriptArgs| in the "
                                          "shell's global")
         || !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads "
                             "(default: # of cores - 1)", -1)
         || !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)")
         || !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
         || !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
         || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
-        || !op.addBoolOption('\0', "unboxed-objects", "Allow creating unboxed objects")
         || !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
                                "Scalar Replacement (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-gvn", "[mode]",
                                "Specify Ion global value numbering:\n"
                                "  off: disable GVN\n"
                                "  on:  enable GVN (default)\n")
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -362,30 +362,16 @@ NativeObject::setLastPropertyShrinkFixed
     MOZ_ASSERT(shape->slotSpan() <= oldFixed);
     MOZ_ASSERT(shape->slotSpan() <= newFixed);
     MOZ_ASSERT(dynamicSlotsCount(oldFixed, shape->slotSpan(), getClass()) == 0);
     MOZ_ASSERT(dynamicSlotsCount(newFixed, shape->slotSpan(), getClass()) == 0);
 
     shape_ = shape;
 }
 
-void
-NativeObject::setLastPropertyMakeNonNative(Shape *shape)
-{
-    MOZ_ASSERT(!inDictionaryMode());
-    MOZ_ASSERT(!shape->getObjectClass()->isNative());
-    MOZ_ASSERT(shape->compartment() == compartment());
-    MOZ_ASSERT(shape->slotSpan() == 0);
-    MOZ_ASSERT(shape->numFixedSlots() == 0);
-    MOZ_ASSERT(!hasDynamicElements());
-    MOZ_ASSERT(!hasDynamicSlots());
-
-    shape_ = shape;
-}
-
 /* static */ bool
 NativeObject::setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span)
 {
     MOZ_ASSERT(obj->inDictionaryMode());
 
     size_t oldSpan = obj->lastProperty()->base()->slotSpan();
     if (oldSpan == span)
         return true;
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -368,18 +368,16 @@ class NativeObject : public JSObject
                       "shadow type must match actual type");
         static_assert(offsetof(NativeObject, slots_) == offsetof(shadow::Object, slots),
                       "shadow slots must match actual slots");
         static_assert(offsetof(NativeObject, elements_) == offsetof(shadow::Object, _1),
                       "shadow placeholder must match actual elements");
 
         static_assert(MAX_FIXED_SLOTS <= Shape::FIXED_SLOTS_MAX,
                       "verify numFixedSlots() bitfield is big enough");
-        static_assert(sizeof(NativeObject) + MAX_FIXED_SLOTS * sizeof(Value) == JSObject::MAX_BYTE_SIZE,
-                      "inconsistent maximum object size");
     }
 
   public:
     HeapSlotArray getDenseElements() {
         return HeapSlotArray(elements_, !getElementsHeader()->isCopyOnWrite());
     }
     HeapSlotArray getDenseElementsAllowCopyOnWrite() {
         // Backdoor allowing direct access to copy on write elements.
@@ -407,21 +405,16 @@ class NativeObject : public JSObject
                                 HandleNativeObject obj, HandleShape shape);
 
     // As for setLastProperty(), but allows the number of fixed slots to
     // change. This can only be used when fixed slots are being erased from the
     // object, and only when the object will not require dynamic slots to cover
     // the new properties.
     void setLastPropertyShrinkFixedSlots(Shape *shape);
 
-    // As for setLastProperty(), but changes the class associated with the
-    // object to a non-native one. This leaves the object with a type and shape
-    // that are (temporarily) inconsistent.
-    void setLastPropertyMakeNonNative(Shape *shape);
-
   protected:
 #ifdef DEBUG
     void checkShapeConsistency();
 #else
     void checkShapeConsistency() { }
 #endif
 
     Shape *
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1073,16 +1073,17 @@ NativeObject::rollbackProperties(Exclusi
     while (true) {
         if (obj->lastProperty()->isEmptyShape()) {
             MOZ_ASSERT(slotSpan == 0);
             break;
         } else {
             uint32_t slot = obj->lastProperty()->slot();
             if (slot < slotSpan)
                 break;
+            MOZ_ASSERT(obj->getSlot(slot).isUndefined());
         }
         if (!obj->removeProperty(cx, obj->lastProperty()->propid()))
             return false;
     }
 
     return true;
 }
 
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -401,21 +401,17 @@ class BaseShape : public gc::TenuredCell
         // chain that has the QUALIFIED_VAROBJ flag set. If it's "unqualified"
         // (i.e., if it was introduced without any var, let, or const, which
         // incidentally is an error in strict mode) then it goes on the lowest
         // scope in the chain with the UNQUALIFIED_VAROBJ flag set (which is
         // typically the global).
         QUALIFIED_VAROBJ    = 0x2000,
         UNQUALIFIED_VAROBJ  = 0x4000,
 
-        // For a function used as an interpreted constructor, whether a 'new'
-        // type had constructor information cleared.
-        NEW_SCRIPT_CLEARED  = 0x8000,
-
-        OBJECT_FLAG_MASK    = 0xfff8
+        OBJECT_FLAG_MASK    = 0x7ff8
     };
 
   private:
     const Class         *clasp_;        /* Class of referring object. */
     HeapPtrObject       parent;         /* Parent of referring object. */
     HeapPtrObject       metadata;       /* Optional holder of metadata about
                                          * the referring object. */
     JSCompartment       *compartment_;  /* Compartment shape belongs to. */
deleted file mode 100644
--- a/js/src/vm/UnboxedObject.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "vm/UnboxedObject.h"
-
-#include "jsinferinlines.h"
-#include "jsobjinlines.h"
-
-#include "vm/Shape-inl.h"
-
-using mozilla::ArrayLength;
-using mozilla::DebugOnly;
-using mozilla::PodCopy;
-
-using namespace js;
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedLayout
-/////////////////////////////////////////////////////////////////////
-
-void
-UnboxedLayout::trace(JSTracer *trc)
-{
-    for (size_t i = 0; i < properties_.length(); i++)
-        MarkStringUnbarriered(trc, &properties_[i].name, "unboxed_layout_name");
-
-    if (newScript())
-        newScript()->trace(trc);
-}
-
-size_t
-UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
-{
-    return mallocSizeOf(this)
-         + properties_.sizeOfExcludingThis(mallocSizeOf)
-         + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0)
-         + mallocSizeOf(traceList());
-}
-
-void
-UnboxedLayout::setNewScript(types::TypeNewScript *newScript, bool writeBarrier /* = true */)
-{
-    if (newScript_ && writeBarrier)
-        types::TypeNewScript::writeBarrierPre(newScript_);
-    newScript_ = newScript;
-}
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedPlainObject
-/////////////////////////////////////////////////////////////////////
-
-bool
-UnboxedPlainObject::setValue(JSContext *cx, const UnboxedLayout::Property &property, const Value &v)
-{
-    uint8_t *p = &data_[property.offset];
-
-    switch (property.type) {
-      case JSVAL_TYPE_BOOLEAN:
-        if (v.isBoolean()) {
-            *p = v.toBoolean();
-            return true;
-        }
-        return false;
-
-      case JSVAL_TYPE_INT32:
-        if (v.isInt32()) {
-            *reinterpret_cast<int32_t*>(p) = v.toInt32();
-            return true;
-        }
-        return false;
-
-      case JSVAL_TYPE_DOUBLE:
-        if (v.isNumber()) {
-            *reinterpret_cast<double*>(p) = v.toNumber();
-            return true;
-        }
-        return false;
-
-      case JSVAL_TYPE_STRING:
-        if (v.isString()) {
-            *reinterpret_cast<HeapPtrString*>(p) = v.toString();
-            return true;
-        }
-        return false;
-
-      case JSVAL_TYPE_OBJECT:
-        if (v.isObjectOrNull()) {
-            // Update property types when writing object properties. Types for
-            // other properties were captured when the unboxed layout was
-            // created.
-            types::AddTypePropertyId(cx, this, NameToId(property.name), v);
-
-            *reinterpret_cast<HeapPtrObject*>(p) = v.toObjectOrNull();
-            return true;
-        }
-        return false;
-
-      default:
-        MOZ_CRASH("Invalid type for unboxed value");
-    }
-}
-
-Value
-UnboxedPlainObject::getValue(const UnboxedLayout::Property &property)
-{
-    uint8_t *p = &data_[property.offset];
-
-    switch (property.type) {
-      case JSVAL_TYPE_BOOLEAN:
-        return BooleanValue(*p != 0);
-
-      case JSVAL_TYPE_INT32:
-        return Int32Value(*reinterpret_cast<int32_t*>(p));
-
-      case JSVAL_TYPE_DOUBLE:
-        return DoubleValue(*reinterpret_cast<double*>(p));
-
-      case JSVAL_TYPE_STRING:
-        return StringValue(*reinterpret_cast<JSString**>(p));
-
-      case JSVAL_TYPE_OBJECT:
-        return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p));
-
-      default:
-        MOZ_CRASH("Invalid type for unboxed value");
-    }
-}
-
-void
-UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj)
-{
-    const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
-    const int32_t *list = layout.traceList();
-    if (!list)
-        return;
-
-    uint8_t *data = obj->as<UnboxedPlainObject>().data();
-    while (*list != -1) {
-        HeapPtrString *heap = reinterpret_cast<HeapPtrString *>(data + *list);
-        MarkString(trc, heap, "unboxed_string");
-        list++;
-    }
-    list++;
-    while (*list != -1) {
-        HeapPtrObject *heap = reinterpret_cast<HeapPtrObject *>(data + *list);
-        if (*heap)
-            MarkObject(trc, heap, "unboxed_object");
-        list++;
-    }
-
-    // Unboxed objects don't have Values to trace.
-    MOZ_ASSERT(*(list + 1) == -1);
-}
-
-bool
-UnboxedPlainObject::convertToNative(JSContext *cx)
-{
-    // Immediately clear any new script on this object's type,
-    // as rollbackPartiallyInitializedObjects() will be confused by the type
-    // changes we make in this function.
-    type()->clearNewScript(cx);
-
-    // clearNewScript() can reentrantly invoke this method.
-    if (!is<UnboxedPlainObject>())
-        return true;
-
-    Rooted<UnboxedPlainObject *> obj(cx, this);
-    Rooted<TaggedProto> proto(cx, getTaggedProto());
-
-    size_t nfixed = gc::GetGCKindSlots(obj->layout().getAllocKind());
-
-    AutoValueVector values(cx);
-    RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
-                                                      getMetadata(), getParent(), nfixed,
-                                                      lastProperty()->getObjectFlags()));
-    if (!shape)
-        return false;
-
-    for (size_t i = 0; i < obj->layout().properties().length(); i++) {
-        const UnboxedLayout::Property &property = obj->layout().properties()[i];
-
-        if (!values.append(obj->getValue(property)))
-            return false;
-
-        StackShape unrootedChild(shape->base()->unowned(), NameToId(property.name), i,
-                                 JSPROP_ENUMERATE, 0);
-        RootedGeneric<StackShape*> child(cx, &unrootedChild);
-        shape = cx->compartment()->propertyTree.getChild(cx, shape, *child);
-        if (!shape)
-            return false;
-    }
-
-    if (!SetClassAndProto(cx, obj, &PlainObject::class_, proto))
-        return false;
-
-    // Any failures after this point will leave the object as a mutant, and we
-    // can't recover.
-
-    RootedPlainObject nobj(cx, &obj->as<PlainObject>());
-    if (!nobj->setLastProperty(cx, nobj, shape))
-        CrashAtUnhandlableOOM("UnboxedPlainObject::convertToNative");
-
-    for (size_t i = 0; i < values.length(); i++)
-        nobj->initSlot(i, values[i]);
-
-    return true;
-}
-
-/* static */
-UnboxedPlainObject *
-UnboxedPlainObject::create(JSContext *cx, HandleTypeObject type, NewObjectKind newKind)
-{
-    MOZ_ASSERT(type->clasp() == &class_);
-    gc::AllocKind allocKind = type->unboxedLayout().getAllocKind();
-
-    UnboxedPlainObject *res = NewObjectWithType<UnboxedPlainObject>(cx, type, cx->global(),
-                                                                    allocKind, newKind);
-    if (!res)
-        return nullptr;
-
-    // Initialize reference fields of the object. All fields in the object will
-    // be overwritten shortly, but references need to be safe for the GC.
-    const int32_t *list = res->layout().traceList();
-    if (list) {
-        uint8_t *data = res->data();
-        while (*list != -1) {
-            HeapPtrString *heap = reinterpret_cast<HeapPtrString *>(data + *list);
-            heap->init(cx->names().empty);
-            list++;
-        }
-        list++;
-        while (*list != -1) {
-            HeapPtrObject *heap = reinterpret_cast<HeapPtrObject *>(data + *list);
-            heap->init(nullptr);
-            list++;
-        }
-        // Unboxed objects don't have Values to initialize.
-        MOZ_ASSERT(*(list + 1) == -1);
-    }
-
-    return res;
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_lookupGeneric(JSContext *cx, HandleObject obj,
-                                      HandleId id, MutableHandleObject objp,
-                                      MutableHandleShape propp)
-{
-    if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
-        MarkNonNativePropertyFound(propp);
-        objp.set(obj);
-        return true;
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (!proto) {
-        objp.set(nullptr);
-        propp.set(nullptr);
-        return true;
-    }
-
-    return LookupProperty(cx, proto, id, objp, propp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_lookupProperty(JSContext *cx, HandleObject obj,
-                                       HandlePropertyName name,
-                                       MutableHandleObject objp,
-                                       MutableHandleShape propp)
-{
-    RootedId id(cx, NameToId(name));
-    return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_lookupElement(JSContext *cx, HandleObject obj,
-                                      uint32_t index, MutableHandleObject objp,
-                                      MutableHandleShape propp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-
-    return DefineProperty(cx, obj, id, v, getter, setter, attrs);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_defineProperty(JSContext *cx, HandleObject obj,
-                                       HandlePropertyName name, HandleValue v,
-                                       PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    Rooted<jsid> id(cx, NameToId(name));
-    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
-    AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                   HandleId id, MutableHandleValue vp)
-{
-    const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
-
-    if (const UnboxedLayout::Property *property = layout.lookup(id)) {
-        vp.set(obj->as<UnboxedPlainObject>().getValue(*property));
-        return true;
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (!proto) {
-        vp.setUndefined();
-        return true;
-    }
-
-    return GetProperty(cx, proto, receiver, id, vp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                    HandlePropertyName name, MutableHandleValue vp)
-{
-    RootedId id(cx, NameToId(name));
-    return obj_getGeneric(cx, obj, receiver, id, vp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                   uint32_t index, MutableHandleValue vp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_getGeneric(cx, obj, receiver, id, vp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                   MutableHandleValue vp, bool strict)
-{
-    const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
-
-    if (const UnboxedLayout::Property *property = layout.lookup(id)) {
-        if (obj->as<UnboxedPlainObject>().setValue(cx, *property, vp))
-            return true;
-
-        if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-            return false;
-        return SetProperty(cx, obj, obj, id, vp, strict);
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (!proto) {
-        if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-            return false;
-        return SetProperty(cx, obj, obj, id, vp, strict);
-    }
-
-    return SetProperty(cx, proto, obj, id, vp, strict);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                    MutableHandleValue vp, bool strict)
-{
-    RootedId id(cx, NameToId(name));
-    return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                   MutableHandleValue vp, bool strict)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
-                                                 MutableHandle<JSPropertyDescriptor> desc)
-{
-    const UnboxedLayout &layout = obj->as<UnboxedPlainObject>().layout();
-
-    if (const UnboxedLayout::Property *property = layout.lookup(id)) {
-        desc.value().set(obj->as<UnboxedPlainObject>().getValue(*property));
-        desc.setAttributes(JSPROP_ENUMERATE);
-        desc.object().set(obj);
-        return true;
-    }
-
-    desc.object().set(nullptr);
-    return true;
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
-                                             HandleId id, unsigned *attrsp)
-{
-    if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-    return SetPropertyAttributes(cx, obj, id, attrsp);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_deleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
-{
-    if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-    return DeleteProperty(cx, obj, id, succeeded);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable)
-{
-    if (!obj->as<UnboxedPlainObject>().convertToNative(cx))
-        return false;
-    return WatchProperty(cx, obj, id, callable);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties)
-{
-    const UnboxedLayout::PropertyVector &unboxed = obj->as<UnboxedPlainObject>().layout().properties();
-    for (size_t i = 0; i < unboxed.length(); i++) {
-        if (!properties.append(NameToId(unboxed[i].name)))
-            return false;
-    }
-    return true;
-}
-
-const Class UnboxedPlainObject::class_ = {
-    "Object",
-    Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS,
-    nullptr,        /* addProperty */
-    nullptr,        /* delProperty */
-    nullptr,        /* getProperty */
-    nullptr,        /* setProperty */
-    nullptr,        /* enumerate   */
-    nullptr,        /* resolve     */
-    nullptr,        /* convert     */
-    nullptr,        /* finalize    */
-    nullptr,        /* call        */
-    nullptr,        /* hasInstance */
-    nullptr,        /* construct   */
-    UnboxedPlainObject::trace,
-    JS_NULL_CLASS_SPEC,
-    JS_NULL_CLASS_EXT,
-    {
-        UnboxedPlainObject::obj_lookupGeneric,
-        UnboxedPlainObject::obj_lookupProperty,
-        UnboxedPlainObject::obj_lookupElement,
-        UnboxedPlainObject::obj_defineGeneric,
-        UnboxedPlainObject::obj_defineProperty,
-        UnboxedPlainObject::obj_defineElement,
-        UnboxedPlainObject::obj_getGeneric,
-        UnboxedPlainObject::obj_getProperty,
-        UnboxedPlainObject::obj_getElement,
-        UnboxedPlainObject::obj_setGeneric,
-        UnboxedPlainObject::obj_setProperty,
-        UnboxedPlainObject::obj_setElement,
-        UnboxedPlainObject::obj_getOwnPropertyDescriptor,
-        UnboxedPlainObject::obj_setGenericAttributes,
-        UnboxedPlainObject::obj_deleteGeneric,
-        UnboxedPlainObject::obj_watch,
-        nullptr,   /* No unwatch needed, as watch() converts the object to native */
-        nullptr,   /* getElements */
-        UnboxedPlainObject::obj_enumerate,
-        nullptr, /* thisObject */
-    }
-};
-
-/////////////////////////////////////////////////////////////////////
-// API
-/////////////////////////////////////////////////////////////////////
-
-static bool
-UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype)
-{
-    if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32)
-        return true;
-    if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL)
-        return true;
-    return false;
-}
-
-bool
-js::TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape,
-                              types::TypeObject *type, types::PreliminaryObjectArray *objects)
-{
-    if (!cx->runtime()->options().unboxedObjects())
-        return true;
-
-    if (templateShape->slotSpan() == 0)
-        return true;
-
-    UnboxedLayout::PropertyVector properties;
-    if (!properties.appendN(UnboxedLayout::Property(), templateShape->slotSpan()))
-        return false;
-
-    size_t objectCount = 0;
-    for (size_t i = 0; i < types::PreliminaryObjectArray::COUNT; i++) {
-        JSObject *obj = objects->get(i);
-        if (!obj)
-            continue;
-
-        objectCount++;
-
-        // All preliminary objects must have been created with the largest
-        // allocation kind possible, which will allow their unboxed data to be
-        // filled in inline.
-        MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) ==
-                   NativeObject::MAX_FIXED_SLOTS);
-
-        if (obj->as<PlainObject>().lastProperty() != templateShape ||
-            obj->as<PlainObject>().hasDynamicElements())
-        {
-            // Only use an unboxed representation if all created objects match
-            // the template shape exactly.
-            return true;
-        }
-
-        for (size_t i = 0; i < templateShape->slotSpan(); i++) {
-            Value val = obj->as<PlainObject>().getSlot(i);
-
-            JSValueType &existing = properties[i].type;
-            JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
-
-            if (existing == JSVAL_TYPE_MAGIC || existing == type || UnboxedTypeIncludes(type, existing))
-                existing = type;
-            else if (!UnboxedTypeIncludes(existing, type))
-                return true;
-        }
-    }
-
-    if (objectCount <= 1) {
-        // If only one of the objects has been created, it is more likely to
-        // have new properties added later.
-        return true;
-    }
-
-    for (size_t i = 0; i < templateShape->slotSpan(); i++) {
-        // We can't use an unboxed representation if e.g. all the objects have
-        // a null value for one of the properties, as we can't decide what type
-        // it is supposed to have.
-        if (UnboxedTypeSize(properties[i].type) == 0)
-            return true;
-    }
-
-    // Fill in the names for all the object's properties.
-    for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
-        size_t slot = r.front().slot();
-        MOZ_ASSERT(!properties[slot].name);
-        properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
-    }
-
-    // Fill in all the unboxed object's property offsets, ordering fields from the
-    // largest down to avoid alignment issues.
-    uint32_t offset = 0;
-
-    static const size_t typeSizes[] = { 8, 4, 1 };
-
-    Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
-
-    DebugOnly<size_t> addedProperties = 0;
-    for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
-        size_t size = typeSizes[i];
-        for (size_t j = 0; j < templateShape->slotSpan(); j++) {
-            JSValueType type = properties[j].type;
-            if (UnboxedTypeSize(type) == size) {
-                if (type == JSVAL_TYPE_OBJECT) {
-                    if (!objectOffsets.append(offset))
-                        return false;
-                } else if (type == JSVAL_TYPE_STRING) {
-                    if (!stringOffsets.append(offset))
-                        return false;
-                }
-                addedProperties++;
-                properties[j].offset = offset;
-                offset += size;
-            }
-        }
-    }
-    MOZ_ASSERT(addedProperties == templateShape->slotSpan());
-
-    // The entire object must be allocatable inline.
-    if (sizeof(JSObject) + offset > JSObject::MAX_BYTE_SIZE)
-        return true;
-
-    UnboxedLayout *layout = type->zone()->new_<UnboxedLayout>(properties, offset);
-    if (!layout)
-        return false;
-
-    // Construct the layout's trace list.
-    if (!objectOffsets.empty() || !stringOffsets.empty()) {
-        Vector<int32_t, 8, SystemAllocPolicy> entries;
-        if (!entries.appendAll(stringOffsets) ||
-            !entries.append(-1) ||
-            !entries.appendAll(objectOffsets) ||
-            !entries.append(-1) ||
-            !entries.append(-1))
-        {
-            return false;
-        }
-        int32_t *traceList = type->zone()->pod_malloc<int32_t>(entries.length());
-        if (!traceList)
-            return false;
-        PodCopy(traceList, entries.begin(), entries.length());
-        layout->setTraceList(traceList);
-    }
-
-    // We've determined that all the preliminary objects can use the new layout
-    // just constructed, so convert the existing type to be an
-    // UnboxedPlainObject rather than a PlainObject, and update the preliminary
-    // objects to use the new layout. Do the fallible stuff first before
-    // modifying any objects.
-
-    // Get an empty shape which we can use for the preliminary objects.
-    Shape *newShape = EmptyShape::getInitialShape(cx, &UnboxedPlainObject::class_,
-                                                  type->proto(),
-                                                  templateShape->getObjectMetadata(),
-                                                  templateShape->getObjectParent(),
-                                                  templateShape->getObjectFlags());
-    if (!newShape) {
-        cx->clearPendingException();
-        return false;
-    }
-
-    // Accumulate a list of all the properties in each preliminary object, and
-    // update their shapes.
-    Vector<Value, 0, SystemAllocPolicy> values;
-    if (!values.reserve(objectCount * templateShape->slotSpan()))
-        return false;
-    for (size_t i = 0; i < types::PreliminaryObjectArray::COUNT; i++) {
-        if (!objects->get(i))
-            continue;
-
-        RootedNativeObject obj(cx, &objects->get(i)->as<NativeObject>());
-        for (size_t j = 0; j < templateShape->slotSpan(); j++)
-            values.infallibleAppend(obj->getSlot(j));
-
-        // Clear the object to remove any dynamically allocated information.
-        NativeObject::clear(cx, obj);
-
-        obj->setLastPropertyMakeNonNative(newShape);
-    }
-
-    if (types::TypeNewScript *newScript = type->newScript())
-        layout->setNewScript(newScript);
-
-    type->setClasp(&UnboxedPlainObject::class_);
-    type->setUnboxedLayout(layout);
-
-    size_t valueCursor = 0;
-    for (size_t i = 0; i < types::PreliminaryObjectArray::COUNT; i++) {
-        if (!objects->get(i))
-            continue;
-        UnboxedPlainObject *obj = &objects->get(i)->as<UnboxedPlainObject>();
-        memset(obj->data(), 0, layout->size());
-        for (size_t j = 0; j < templateShape->slotSpan(); j++) {
-            Value v = values[valueCursor++];
-            JS_ALWAYS_TRUE(obj->setValue(cx, properties[j], v));
-        }
-    }
-
-    MOZ_ASSERT(valueCursor == values.length());
-    return true;
-}
deleted file mode 100644
--- a/js/src/vm/UnboxedObject.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef vm_UnboxedObject_h
-#define vm_UnboxedObject_h
-
-#include "jsgc.h"
-#include "jsinfer.h"
-#include "jsobj.h"
-
-namespace js {
-
-// Memory required for an unboxed value of a given type. Returns zero for types
-// which can't be used for unboxed objects.
-static inline size_t
-UnboxedTypeSize(JSValueType type)
-{
-    switch (type) {
-      case JSVAL_TYPE_BOOLEAN: return 1;
-      case JSVAL_TYPE_INT32:   return 4;
-      case JSVAL_TYPE_DOUBLE:  return 8;
-      case JSVAL_TYPE_STRING:  return sizeof(void *);
-      case JSVAL_TYPE_OBJECT:  return sizeof(void *);
-      default:                 return 0;
-    }
-}
-
-// Class describing the layout of an UnboxedPlainObject.
-class UnboxedLayout
-{
-  public:
-    struct Property {
-        PropertyName *name;
-        uint32_t offset;
-        JSValueType type;
-
-        Property()
-          : name(nullptr), offset(0), type(JSVAL_TYPE_MAGIC)
-        {}
-    };
-
-    typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
-
-  private:
-    // All properties on objects with this layout, in enumeration order.
-    PropertyVector properties_;
-
-    // Byte size of the data for objects with this layout.
-    size_t size_;
-
-    // Any 'new' script information associated with this layout.
-    types::TypeNewScript *newScript_;
-
-    // List for use in tracing objects with this layout. This has the same
-    // structure as the trace list on a TypeDescr.
-    int32_t *traceList_;
-
-  public:
-    UnboxedLayout(const PropertyVector &properties, size_t size)
-      : size_(size), newScript_(nullptr), traceList_(nullptr)
-    {
-        properties_.appendAll(properties);
-    }
-
-    ~UnboxedLayout() {
-        js_delete(newScript_);
-        js_free(traceList_);
-    }
-
-    const PropertyVector &properties() const {
-        return properties_;
-    }
-
-    types::TypeNewScript *newScript() const {
-        return newScript_;
-    }
-
-    void setNewScript(types::TypeNewScript *newScript, bool writeBarrier = true);
-
-    const int32_t *traceList() const {
-        return traceList_;
-    }
-
-    void setTraceList(int32_t *traceList) {
-        traceList_ = traceList;
-    }
-
-    const Property *lookup(JSAtom *atom) const {
-        for (size_t i = 0; i < properties_.length(); i++) {
-            if (properties_[i].name == atom)
-                return &properties_[i];
-        }
-        return nullptr;
-    }
-
-    const Property *lookup(jsid id) const {
-        if (JSID_IS_STRING(id))
-            return lookup(JSID_TO_ATOM(id));
-        return nullptr;
-    }
-
-    size_t size() const {
-        return size_;
-    }
-
-    inline gc::AllocKind getAllocKind() const;
-
-    void trace(JSTracer *trc);
-
-    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
-};
-
-// Class for a plain object using an unboxed representation. The physical
-// layout of these objects is identical to that of an InlineTypedObject, though
-// these objects use an UnboxedLayout instead of a TypeDescr to keep track of
-// how their properties are stored.
-class UnboxedPlainObject : public JSObject
-{
-    // Start of the inline data, which immediately follows the shape and type.
-    uint8_t data_[1];
-
-  public:
-    static const Class class_;
-
-    static bool obj_lookupGeneric(JSContext *cx, HandleObject obj,
-                                  HandleId id, MutableHandleObject objp,
-                                  MutableHandleShape propp);
-
-    static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
-                                   HandlePropertyName name,
-                                   MutableHandleObject objp,
-                                   MutableHandleShape propp);
-
-    static bool obj_lookupElement(JSContext *cx, HandleObject obj,
-                                  uint32_t index, MutableHandleObject objp,
-                                  MutableHandleShape propp);
-
-    static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
-                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
-    static bool obj_defineProperty(JSContext *cx, HandleObject obj,
-                                   HandlePropertyName name, HandleValue v,
-                                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
-    static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
-                                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
-    static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               HandleId id, MutableHandleValue vp);
-
-    static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
-                                HandlePropertyName name, MutableHandleValue vp);
-
-    static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
-                               uint32_t index, MutableHandleValue vp);
-
-    static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                               MutableHandleValue vp, bool strict);
-    static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                MutableHandleValue vp, bool strict);
-    static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
-                               MutableHandleValue vp, bool strict);
-
-    static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
-                                             MutableHandle<JSPropertyDescriptor> desc);
-
-    static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
-                                         HandleId id, unsigned *attrsp);
-
-    static bool obj_deleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
-
-    static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
-    static bool obj_watch(JSContext *cx, HandleObject obj, HandleId id, HandleObject callable);
-
-    const UnboxedLayout &layout() const {
-        return type()->unboxedLayout();
-    }
-
-    uint8_t *data() {
-        return &data_[0];
-    }
-
-    bool setValue(JSContext *cx, const UnboxedLayout::Property &property, const Value &v);
-    Value getValue(const UnboxedLayout::Property &property);
-
-    bool convertToNative(JSContext *cx);
-
-    static UnboxedPlainObject *create(JSContext *cx, HandleTypeObject type, NewObjectKind newKind);
-
-    static void trace(JSTracer *trc, JSObject *object);
-
-    static size_t offsetOfData() {
-        return offsetof(UnboxedPlainObject, data_[0]);
-    }
-};
-
-// Try to construct an UnboxedLayout for each of the preliminary objects,
-// provided they all match the template shape. If successful, converts the
-// preliminary objects and their type to the new unboxed representation.
-bool
-TryConvertToUnboxedLayout(JSContext *cx, Shape *templateShape,
-                          types::TypeObject *type, types::PreliminaryObjectArray *objects);
-
-inline gc::AllocKind
-UnboxedLayout::getAllocKind() const
-{
-    return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
-}
-
-} // namespace js
-
-#endif /* vm_UnboxedObject_h */