Bug 1505574 - Remove Unboxed Objects from vm/ - Part 3 r=iain
authorMatthew Gaudet <mgaudet@mozilla.com>
Fri, 22 Mar 2019 15:32:59 +0000
changeset 465718 d4383df46286ab737ce478764cfc07acbe6f5c7f
parent 465717 6b55560f4da9abf1987b7417831c86f7819d5f7c
child 465719 fa973fb70a3227a95f6be02f97ecb3b141e98ccc
push id35746
push usershindli@mozilla.com
push dateSat, 23 Mar 2019 09:46:24 +0000
treeherdermozilla-central@02b7484f316b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersiain
bugs1505574
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1505574 - Remove Unboxed Objects from vm/ - Part 3 r=iain Differential Revision: https://phabricator.services.mozilla.com/D24047
js/src/jsfriendapi.cpp
js/src/moz.build
js/src/shell/js.cpp
js/src/vm/JSObject-inl.h
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/ObjectGroup-inl.h
js/src/vm/ObjectGroup.cpp
js/src/vm/ObjectGroup.h
js/src/vm/TypeInference-inl.h
js/src/vm/TypeInference.cpp
js/src/vm/UnboxedObject-inl.h
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -267,17 +267,17 @@ JS_FRIEND_API bool JS_DefineFunctionsWit
 }
 
 JS_FRIEND_API bool js::GetBuiltinClass(JSContext* cx, HandleObject obj,
                                        ESClass* cls) {
   if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
     return Proxy::getBuiltinClass(cx, obj, cls);
   }
 
-  if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>()) {
+  if (obj->is<PlainObject>()) {
     *cls = ESClass::Object;
   } else if (obj->is<ArrayObject>()) {
     *cls = ESClass::Array;
   } else if (obj->is<NumberObject>()) {
     *cls = ESClass::Number;
   } else if (obj->is<StringObject>()) {
     *cls = ESClass::String;
   } else if (obj->is<BooleanObject>()) {
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -319,17 +319,16 @@ UNIFIED_SOURCES += [
     'vm/SymbolType.cpp',
     'vm/TaggedProto.cpp',
     'vm/Time.cpp',
     'vm/TypedArrayObject.cpp',
     'vm/TypeInference.cpp',
     'vm/UbiNode.cpp',
     'vm/UbiNodeCensus.cpp',
     'vm/UbiNodeShortestPaths.cpp',
-    'vm/UnboxedObject.cpp',
     'vm/Value.cpp',
     'vm/Xdr.cpp',
 ]
 
 # builtin/RegExp.cpp cannot be built in unified mode because it causes huge
 #   win32 test slowdowns
 # jsmath.cpp cannot be built in unified mode because it needs to re-#define the
 #   RtlGenRandom declaration's calling convention in <ntsecapi.h> on Windows.
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6557,26 +6557,23 @@ static bool IsLatin1(JSContext* cx, unsi
   return true;
 }
 
 static bool UnboxedObjectsEnabled(JSContext* cx, unsigned argc, Value* vp) {
   // Note: this also returns |false| if we're using --ion-eager or if the
   // JITs are disabled, since that affects how unboxed objects are used.
 
   CallArgs args = CallArgsFromVp(argc, vp);
-  args.rval().setBoolean(!jit::JitOptions.disableUnboxedObjects &&
-                         !jit::JitOptions.eagerCompilation &&
-                         jit::IsIonEnabled(cx));
+  args.rval().setBoolean(false);
   return true;
 }
 
 static bool IsUnboxedObject(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
-  args.rval().setBoolean(args.get(0).isObject() &&
-                         args[0].toObject().is<UnboxedPlainObject>());
+  args.rval().setBoolean(false);
   return true;
 }
 
 static bool HasCopyOnWriteElements(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   args.rval().setBoolean(
       args.get(0).isObject() && args[0].toObject().isNative() &&
       args[0].toObject().as<NativeObject>().denseElementsAreCopyOnWrite());
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -29,40 +29,25 @@
 #include "gc/Marking-inl.h"
 #include "gc/ObjectKind-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/ObjectOperations-inl.h"  // js::MaybeHasInterestingSymbolProperty
 #include "vm/Realm-inl.h"
 #include "vm/ShapedObject-inl.h"
 #include "vm/TypeInference-inl.h"
 
-namespace js {
-
-// This is needed here for ensureShape() below.
-inline bool MaybeConvertUnboxedObjectToNative(JSContext* cx, JSObject* obj) {
-  if (obj->is<UnboxedPlainObject>()) {
-    return UnboxedPlainObject::convertToNative(cx, obj);
-  }
-  return true;
-}
-
-}  // namespace js
-
 inline js::Shape* JSObject::maybeShape() const {
   if (!is<js::ShapedObject>()) {
     return nullptr;
   }
 
   return as<js::ShapedObject>().shape();
 }
 
 inline js::Shape* JSObject::ensureShape(JSContext* cx) {
-  if (!js::MaybeConvertUnboxedObjectToNative(cx, this)) {
-    return nullptr;
-  }
   js::Shape* shape = maybeShape();
   MOZ_ASSERT(shape);
   return shape;
 }
 
 inline void JSObject::finalize(js::FreeOp* fop) {
   js::probes::FinalizeObject(this);
 
@@ -266,29 +251,20 @@ inline bool JSObject::isDelegate() const
   return hasAllFlags(js::BaseShape::DELEGATE);
 }
 
 inline bool JSObject::hasUncacheableProto() const {
   return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
 }
 
 MOZ_ALWAYS_INLINE bool JSObject::maybeHasInterestingSymbolProperty() const {
-  const js::NativeObject* nobj;
   if (isNative()) {
-    nobj = &as<js::NativeObject>();
-  } else if (is<js::UnboxedPlainObject>()) {
-    nobj = as<js::UnboxedPlainObject>().maybeExpando();
-    if (!nobj) {
-      return false;
-    }
-  } else {
-    return true;
+    return as<js::NativeObject>().hasInterestingSymbol();
   }
-
-  return nobj->hasInterestingSymbol();
+  return true;
 }
 
 inline bool JSObject::staticPrototypeIsImmutable() const {
   MOZ_ASSERT(hasStaticPrototype());
   return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE);
 }
 
 inline bool JSObject::isIteratedSingleton() const {
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -334,43 +334,16 @@ void NativeObject::setLastPropertyMakeNo
   if (hasDynamicSlots()) {
     js_free(slots_);
     slots_ = nullptr;
   }
 
   setShape(shape);
 }
 
-//MG:Unbox:Remove
-void NativeObject::setLastPropertyMakeNative(JSContext* cx, Shape* shape) {
-  MOZ_ASSERT(getClass()->isNative());
-  MOZ_ASSERT(shape->getObjectClass()->isNative());
-  MOZ_ASSERT(!shape->inDictionary());
-
-  // This method is used to convert unboxed objects into native objects. In
-  // this case, the shape_ field was previously used to store other data and
-  // this should be treated as an initialization.
-  initShape(shape);
-
-  slots_ = nullptr;
-  elements_ = emptyObjectElements;
-
-  size_t oldSpan = shape->numFixedSlots();
-  size_t newSpan = shape->slotSpan();
-
-  initializeSlotRange(0, oldSpan);
-
-  // A failure at this point will leave the object as a mutant, and we
-  // can't recover.
-  AutoEnterOOMUnsafeRegion oomUnsafe;
-  if (oldSpan != newSpan && !updateSlotsForSpan(cx, oldSpan, newSpan)) {
-    oomUnsafe.crash("NativeObject::setLastPropertyMakeNative");
-  }
-}
-
 bool NativeObject::setSlotSpan(JSContext* cx, uint32_t span) {
   MOZ_ASSERT(inDictionaryMode());
 
   size_t oldSpan = lastProperty()->base()->slotSpan();
   if (oldSpan == span) {
     return true;
   }
 
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -539,21 +539,16 @@ class NativeObject : public ShapedObject
   // 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);
 
-  // As for setLastProperty(), but changes the class associated with the
-  // object to a native one. The object's type has already been changed, and
-  // this brings the shape into sync with it.
-  void setLastPropertyMakeNative(JSContext* cx, Shape* shape);
-
   // Newly-created TypedArrays that map a SharedArrayBuffer are
   // marked as shared by giving them an ObjectElements that has the
   // ObjectElements::SHARED_MEMORY flag set.
   void setIsSharedMemory() {
     MOZ_ASSERT(elements_ == emptyObjectElements);
     elements_ = emptyObjectElementsShared;
   }
 
--- a/js/src/vm/ObjectGroup-inl.h
+++ b/js/src/vm/ObjectGroup-inl.h
@@ -79,23 +79,11 @@ inline TypeNewScript* ObjectGroup::newSc
 }
 
 inline PreliminaryObjectArrayWithTemplate* ObjectGroup::maybePreliminaryObjects(
     const AutoSweepObjectGroup& sweep) {
   MOZ_ASSERT(sweep.group() == this);
   return maybePreliminaryObjectsDontCheckGeneration();
 }
 
-inline UnboxedLayout* ObjectGroup::maybeUnboxedLayout(
-    const AutoSweepObjectGroup& sweep) {
-  MOZ_ASSERT(sweep.group() == this);
-  return maybeUnboxedLayoutDontCheckGeneration();
-}
-
-inline UnboxedLayout& ObjectGroup::unboxedLayout(
-    const AutoSweepObjectGroup& sweep) {
-  MOZ_ASSERT(sweep.group() == this);
-  return unboxedLayoutDontCheckGeneration();
-}
-
 }  // namespace js
 
 #endif /* vm_ObjectGroup_inl_h */
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -21,18 +21,20 @@
 #include "vm/ArrayObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSObject.h"
 #include "vm/RegExpObject.h"
 #include "vm/Shape.h"
 #include "vm/TaggedProto.h"
 
 #include "gc/Marking-inl.h"
+#include "gc/ObjectKind-inl.h"
+#include "vm/JSObject-inl.h"
+#include "vm/NativeObject-inl.h"
 #include "vm/TypeInference-inl.h"
-#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroup
 /////////////////////////////////////////////////////////////////////
 
 ObjectGroup::ObjectGroup(const Class* clasp, TaggedProto proto,
@@ -45,17 +47,16 @@ ObjectGroup::ObjectGroup(const Class* cl
   setGeneration(zone()->types.generation);
 }
 
 void ObjectGroup::finalize(FreeOp* fop) {
   if (newScriptDontCheckGeneration()) {
     newScriptDontCheckGeneration()->clear();
   }
   fop->delete_(newScriptDontCheckGeneration());
-  fop->delete_(maybeUnboxedLayoutDontCheckGeneration());
   if (maybePreliminaryObjectsDontCheckGeneration()) {
     maybePreliminaryObjectsDontCheckGeneration()->clear();
   }
   fop->delete_(maybePreliminaryObjectsDontCheckGeneration());
 }
 
 void ObjectGroup::setProtoUnchecked(TaggedProto proto) {
   proto_ = proto;
@@ -69,19 +70,16 @@ void ObjectGroup::setProto(TaggedProto p
 }
 
 size_t ObjectGroup::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;
 }
 
 void ObjectGroup::setAddendum(AddendumKind kind, void* addendum,
                               bool writeBarrier /* = true */) {
   MOZ_ASSERT(!needsSweep());
   MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT));
 
@@ -562,18 +560,17 @@ ObjectGroup* ObjectGroup::defaultNewGrou
     }
   }
 
   ObjectGroupRealm::NewTable::AddPtr p = table->lookupForAdd(
       ObjectGroupRealm::NewEntry::Lookup(clasp, proto, associated));
   if (p) {
     ObjectGroup* group = p->group;
     MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
-    MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ ||
-                              group->clasp() == &UnboxedPlainObject::class_);
+    MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_);
     MOZ_ASSERT(group->proto() == proto);
     groups.defaultNewGroupCache.put(group, associated);
     return group;
   }
 
   ObjectGroupFlags initialFlags = 0;
   if (proto.isDynamic() ||
       (proto.isObject() && proto.toObject()->isNewGroupUnknown())) {
@@ -1010,70 +1007,17 @@ bool js::CombinePlainObjectPropertyTypes
               if (!GiveObjectGroup(cx, &otherValue.toObject(), newInnerObj)) {
                 return false;
               }
             }
           }
         }
       }
     }
-  } else if (newObj->is<UnboxedPlainObject>()) {
-    const UnboxedLayout& layout = newObj->as<UnboxedPlainObject>().layout();
-    const int32_t* traceList = layout.traceList();
-    if (!traceList) {
-      return true;
-    }
-
-    uint8_t* newData = newObj->as<UnboxedPlainObject>().data();
-    uint8_t* oldData = oldObj->as<UnboxedPlainObject>().data();
-
-    for (; *traceList != -1; traceList++) {
-    }
-    traceList++;
-    for (; *traceList != -1; traceList++) {
-      JSObject* newInnerObj =
-          *reinterpret_cast<JSObject**>(newData + *traceList);
-      JSObject* oldInnerObj =
-          *reinterpret_cast<JSObject**>(oldData + *traceList);
-
-      if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj)) {
-        continue;
-      }
-
-      if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj)) {
-        return false;
-      }
-
-      if (SameGroup(oldInnerObj, newInnerObj)) {
-        continue;
-      }
-
-      if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj)) {
-        return false;
-      }
-
-      if (SameGroup(oldInnerObj, newInnerObj)) {
-        for (size_t i = 1; i < ncompare; i++) {
-          if (compare[i].isObject() &&
-              SameGroup(&compare[i].toObject(), newObj)) {
-            uint8_t* otherData =
-                compare[i].toObject().as<UnboxedPlainObject>().data();
-            JSObject* otherInnerObj =
-                *reinterpret_cast<JSObject**>(otherData + *traceList);
-            if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) {
-              if (!GiveObjectGroup(cx, otherInnerObj, newInnerObj)) {
-                return false;
-              }
-            }
-          }
-        }
-      }
-    }
   }
-
   return true;
 }
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroupRealm PlainObjectTable
 /////////////////////////////////////////////////////////////////////
 
 struct ObjectGroupRealm::PlainObjectKey {
@@ -1299,25 +1243,16 @@ JSObject* ObjectGroup::newPlainObject(JS
 
   RootedObjectGroup group(cx, p->value().group);
 
   // AutoSweepObjectGroup checks no GC happens in its scope, so we use Maybe
   // and reset() it before GC calls.
   mozilla::Maybe<AutoSweepObjectGroup> sweep;
   sweep.emplace(group);
 
-  // Watch for existing groups which now use an unboxed layout.
-  if (group->maybeUnboxedLayout(*sweep)) {
-    MOZ_ASSERT(group->maybeUnboxedLayout(*sweep)->properties().length() ==
-               nproperties);
-    sweep.reset();
-    return UnboxedPlainObject::createWithProperties(cx, group, newKind,
-                                                    properties);
-  }
-
   // Update property types according to the properties we are about to add.
   // Do this before we do anything which can GC, which might move or remove
   // this table entry.
   if (!group->unknownProperties(*sweep)) {
     for (size_t i = 0; i < nproperties; i++) {
       TypeSet::Type type = p->value().types[i];
       TypeSet::Type ntype = GetValueTypeForTable(properties[i].value);
       if (ntype == type) {
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -16,17 +16,16 @@
 #include "js/GCHashTable.h"
 #include "js/TypeDecls.h"
 #include "vm/TaggedProto.h"
 #include "vm/TypeSet.h"
 
 namespace js {
 
 class TypeDescr;
-class UnboxedLayout;
 
 class PreliminaryObjectArrayWithTemplate;
 class TypeNewScript;
 class AutoClearTypeInferenceStateOnOOM;
 class AutoSweepObjectGroup;
 class CompilerConstraintList;
 class ObjectGroupRealm;
 
@@ -244,21 +243,16 @@ class ObjectGroup : public gc::TenuredCe
     // When used by the 'new' group when constructing an interpreted
     // function, the addendum stores a TypeNewScript.
     Addendum_NewScript,
 
     // For some plain objects, the addendum stores a
     // PreliminaryObjectArrayWithTemplate.
     Addendum_PreliminaryObjects,
 
-    // When objects in this group have an unboxed representation, the
-    // addendum stores an UnboxedLayout (which might have a TypeNewScript
-    // as well, if the group is also constructed using 'new').
-    Addendum_UnboxedLayout,
-
     // If this group is used by objects that have been converted from an
     // unboxed representation and/or have the same allocation kind as such
     // objects, the addendum points to that unboxed group.
     Addendum_OriginalUnboxedGroup,
 
     // When used by typed objects, the addendum stores a TypeDescr.
     Addendum_TypeDescr
   };
@@ -313,35 +307,16 @@ class ObjectGroup : public gc::TenuredCe
 
   void detachPreliminaryObjects() {
     MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration());
     setAddendum(Addendum_None, nullptr);
   }
 
   inline bool hasUnanalyzedPreliminaryObjects();
 
-  inline UnboxedLayout* maybeUnboxedLayout(const AutoSweepObjectGroup& sweep);
-  inline UnboxedLayout& unboxedLayout(const AutoSweepObjectGroup& sweep);
-
-  UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
-    if (addendumKind() == Addendum_UnboxedLayout) {
-      return &unboxedLayoutDontCheckGeneration();
-    }
-    return nullptr;
-  }
-
-  UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
-    MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
-    return *reinterpret_cast<UnboxedLayout*>(addendum_);
-  }
-
-  void setUnboxedLayout(UnboxedLayout* layout) {
-    setAddendum(Addendum_UnboxedLayout, layout);
-  }
-
   ObjectGroup* maybeOriginalUnboxedGroup() const {
     if (addendumKind() == Addendum_OriginalUnboxedGroup) {
       return reinterpret_cast<ObjectGroup*>(addendum_);
     }
     return nullptr;
   }
 
   void setOriginalUnboxedGroup(ObjectGroup* group) {
@@ -551,18 +526,18 @@ class ObjectGroup : public gc::TenuredCe
   };
 
   // Create an ArrayObject with the specified elements and a group specialized
   // for the elements.
   static ArrayObject* newArrayObject(
       JSContext* cx, const Value* vp, size_t length, NewObjectKind newKind,
       NewArrayKind arrayKind = NewArrayKind::Normal);
 
-  // Create a PlainObject or UnboxedPlainObject with the specified properties
-  // and a group specialized for those properties.
+  // Create a PlainObject with the specified properties and a group specialized
+  // for those properties.
   static JSObject* newPlainObject(JSContext* cx, IdValuePair* properties,
                                   size_t nproperties, NewObjectKind newKind);
 
   // Static accessors for ObjectGroupRealm AllocationSiteTable.
 
   // Get a non-singleton group to use for objects created at the specified
   // allocation site.
   static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script,
@@ -654,20 +629,16 @@ class ObjectGroupRealm {
   // A single per-realm ObjectGroup for all calls to StringSplitString.
   // StringSplitString is always called from self-hosted code, and conceptually
   // the return object for a string.split(string) operation should have a
   // unified type.  Having a global group for this also allows us to remove
   // the hash-table lookup that would be required if we allocated this group
   // on the basis of call-site pc.
   ReadBarrieredObjectGroup stringSplitStringGroup = {};
 
- public:
-  // All unboxed layouts in the realm.
-  mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
-
   // END OF PROPERTIES
 
  private:
   friend class ObjectGroup;
 
   struct AllocationSiteKey;
 
  public:
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -26,17 +26,16 @@
 #include "vm/JSFunction.h"
 #include "vm/NativeObject.h"
 #include "vm/NumberObject.h"
 #include "vm/ObjectGroup.h"
 #include "vm/Shape.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
-#include "vm/UnboxedObject.h"
 
 #include "vm/JSContext-inl.h"
 #include "vm/ObjectGroup-inl.h"
 
 namespace js {
 
 /////////////////////////////////////////////////////////////////////
 // RecompileInfo
@@ -286,19 +285,17 @@ class TypeNewScript {
 
   // Any preliminary objects with the type. The analyses are not performed
   // until this array is cleared.
   PreliminaryObjectArray* preliminaryObjects = nullptr;
 
   // 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.
   HeapPtr<PlainObject*> 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
@@ -360,28 +357,16 @@ class TypeNewScript {
 
   size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
   static size_t offsetOfPreliminaryObjects() {
     return offsetof(TypeNewScript, preliminaryObjects);
   }
 };
 
-inline UnboxedLayout::~UnboxedLayout() {
-  if (newScript_) {
-    newScript_->clear();
-  }
-  js_delete(newScript_);
-  js_free(traceList_);
-
-  nativeGroup_.init(nullptr);
-  nativeShape_.init(nullptr);
-  replacementGroup_.init(nullptr);
-  constructorCode_.init(nullptr);
-}
 
 inline bool ObjectGroup::hasUnanalyzedPreliminaryObjects() {
   return (newScriptDontCheckGeneration() &&
           !newScriptDontCheckGeneration()->analyzed()) ||
          maybePreliminaryObjectsDontCheckGeneration();
 }
 
 /*
@@ -389,20 +374,16 @@ inline bool ObjectGroup::hasUnanalyzedPr
  * change type information must use this, and functions which depend on
  * intermediate types (i.e. JITs) can use this to ensure that intermediate
  * information is not collected and does not change.
  *
  * Ensures that GC cannot occur. Does additional sanity checking that inference
  * is not reentrant and that recompilations occur properly.
  */
 struct MOZ_RAII AutoEnterAnalysis {
-  // For use when initializing an UnboxedLayout.  The UniquePtr's destructor
-  // must run when GC is not suppressed.
-  UniquePtr<UnboxedLayout> unboxedLayoutToCleanUp;
-
   // Prevent GC activity in the middle of analysis.
   gc::AutoSuppressGC suppressGC;
 
   // Allow clearing inference info on OOM during incremental sweeping. This is
   // constructed for the outermost AutoEnterAnalysis on the stack.
   mozilla::Maybe<AutoClearTypeInferenceStateOnOOM> oom;
 
   // Pending recompilations to perform before execution of JIT code can resume.
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -32,17 +32,16 @@
 #include "vm/HelperThreads.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Opcodes.h"
 #include "vm/Printer.h"
 #include "vm/Shape.h"
 #include "vm/Time.h"
-#include "vm/UnboxedObject.h"
 
 #include "gc/Marking-inl.h"
 #include "gc/PrivateIterators-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
@@ -305,20 +304,16 @@ bool js::ObjectGroupHasProperty(JSContex
       }
       for (size_t i = 0; i < types->getObjectCount(); i++) {
         if (TypeSet::ObjectKey* key = types->getObject(i)) {
           if (key->unknownProperties()) {
             return true;
           }
         }
       }
-      JSObject* obj = &value.toObject();
-      if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup()) {
-        return true;
-      }
     }
 
     if (!types->hasType(type)) {
       TypeFailure(cx, "Missing type in object %s %s: %s",
                   TypeSet::ObjectGroupString(group).get(), TypeIdString(id),
                   TypeSet::TypeString(type).get());
     }
   }
@@ -2011,42 +2006,16 @@ class ConstraintDataFreezeObjectForTyped
   bool shouldSweep() {
     // Note: |viewData| is only used for equality testing.
     return IsAboutToBeFinalizedUnbarriered(&obj);
   }
 
   Compartment* maybeCompartment() { return obj->compartment(); }
 };
 
-// Constraint which triggers recompilation if an unboxed object in some group
-// is converted to a native object.
-class ConstraintDataFreezeObjectForUnboxedConvertedToNative {
- public:
-  ConstraintDataFreezeObjectForUnboxedConvertedToNative() {}
-
-  const char* kind() { return "freezeObjectForUnboxedConvertedToNative"; }
-
-  bool invalidateOnNewType(TypeSet::Type type) { return false; }
-  bool invalidateOnNewPropertyState(TypeSet* property) { return false; }
-  bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep,
-                                  ObjectGroup* group) {
-    return group->unboxedLayout(sweep).nativeGroup() != nullptr;
-  }
-
-  bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx,
-                       const HeapTypeSetKey& property,
-                       TemporaryTypeSet* expected) {
-    return !invalidateOnNewObjectState(sweep, property.object()->maybeGroup());
-  }
-
-  bool shouldSweep() { return false; }
-
-  Compartment* maybeCompartment() { return nullptr; }
-};
-
 } /* anonymous namespace */
 
 void TypeSet::ObjectKey::watchStateChangeForTypedArrayData(
     CompilerConstraintList* constraints) {
   TypedArrayObject& tarray = singleton()->as<TypedArrayObject>();
   HeapTypeSetKey objectProperty = property(JSID_EMPTY);
   LifoAlloc* alloc = constraints->alloc();
 
@@ -2664,19 +2633,16 @@ bool TemporaryTypeSet::propertyNeedsBarr
       return true;
     }
   }
 
   return false;
 }
 
 bool js::ClassCanHaveExtraProperties(const Class* clasp) {
-  if (clasp == &UnboxedPlainObject::class_) {
-    return false;
-  }
   return clasp->getResolve() || clasp->getOpsLookupProperty() ||
          clasp->getOpsGetProperty() || IsTypedArrayClass(clasp);
 }
 
 void TypeZone::processPendingRecompiles(FreeOp* fop,
                                         RecompileInfoVector& recompiles) {
   MOZ_ASSERT(!recompiles.empty());
 
@@ -2974,29 +2940,16 @@ void js::AddTypePropertyId(JSContext* cx
   // initialized groups for the acquired properties analysis. Note that we
   // don't need to do this for other property changes, as these will also be
   // reflected via shape changes on the object that will prevent the object
   // from acquiring the fully initialized group.
   if (group->newScript(sweep) && group->newScript(sweep)->initializedGroup()) {
     AddTypePropertyId(cx, group->newScript(sweep)->initializedGroup(), nullptr,
                       id, type);
   }
-
-  // Maintain equivalent type information for unboxed object groups and their
-  // corresponding native group. Since type sets might contain the unboxed
-  // group but not the native group, this ensures optimizations based on the
-  // unboxed group are valid for the native group.
-  if (group->maybeUnboxedLayout(sweep) &&
-      group->maybeUnboxedLayout(sweep)->nativeGroup()) {
-    AddTypePropertyId(cx, group->maybeUnboxedLayout(sweep)->nativeGroup(),
-                      nullptr, id, type);
-  }
-  if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) {
-    AddTypePropertyId(cx, unboxedGroup, nullptr, id, type);
-  }
 }
 
 void js::AddTypePropertyId(JSContext* cx, ObjectGroup* group, JSObject* obj,
                            jsid id, const Value& value) {
   AddTypePropertyId(cx, group, obj, id, TypeSet::GetValueType(value));
 }
 
 void ObjectGroup::markPropertyNonData(JSContext* cx, JSObject* obj, jsid id) {
@@ -3066,26 +3019,16 @@ void ObjectGroup::setFlags(const AutoSwe
   ObjectStateChange(sweep, cx, this, false);
 
   // Propagate flag changes from partially to fully initialized groups for the
   // acquired properties analysis.
   if (newScript(sweep) && newScript(sweep)->initializedGroup()) {
     AutoSweepObjectGroup sweepInit(newScript(sweep)->initializedGroup());
     newScript(sweep)->initializedGroup()->setFlags(sweepInit, cx, flags);
   }
-
-  // Propagate flag changes between unboxed and corresponding native groups.
-  if (maybeUnboxedLayout(sweep) && maybeUnboxedLayout(sweep)->nativeGroup()) {
-    AutoSweepObjectGroup sweepNative(maybeUnboxedLayout(sweep)->nativeGroup());
-    maybeUnboxedLayout(sweep)->nativeGroup()->setFlags(sweepNative, cx, flags);
-  }
-  if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
-    AutoSweepObjectGroup sweepUnboxed(unboxedGroup);
-    unboxedGroup->setFlags(sweepUnboxed, cx, flags);
-  }
 }
 
 void ObjectGroup::markUnknown(const AutoSweepObjectGroup& sweep,
                               JSContext* cx) {
   AutoEnterAnalysis enter(cx);
 
   MOZ_ASSERT(cx->zone()->types.activeAnalysis);
   MOZ_ASSERT(!unknownProperties(sweep));
@@ -3111,36 +3054,22 @@ void ObjectGroup::markUnknown(const Auto
     Property* prop = getProperty(sweep, i);
     if (prop) {
       prop->types.addType(sweep, cx, TypeSet::UnknownType());
       prop->types.setNonDataProperty(sweep, cx);
     }
   }
 
   clearProperties(sweep);
-
-  if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
-    MarkObjectGroupUnknownProperties(cx, unboxedGroup);
-  }
-  if (maybeUnboxedLayout(sweep) && maybeUnboxedLayout(sweep)->nativeGroup()) {
-    MarkObjectGroupUnknownProperties(cx,
-                                     maybeUnboxedLayout(sweep)->nativeGroup());
-  }
-  if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
-    MarkObjectGroupUnknownProperties(cx, unboxedGroup);
-  }
 }
 
 TypeNewScript* ObjectGroup::anyNewScript(const AutoSweepObjectGroup& sweep) {
   if (newScript(sweep)) {
     return newScript(sweep);
   }
-  if (maybeUnboxedLayout(sweep)) {
-    return unboxedLayout(sweep).newScript();
-  }
   return nullptr;
 }
 
 void ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement) {
   // Clear the TypeNewScript from this ObjectGroup and, if it has been
   // analyzed, remove it from the newObjectGroups table so that it will not be
   // produced by calling 'new' on the associated function anymore.
   // The TypeNewScript is not actually destroyed.
@@ -3163,21 +3092,17 @@ void ObjectGroup::detachNewScript(bool w
                                           replacement);
     } else {
       objectGroups.removeDefaultNewGroup(nullptr, proto, associated);
     }
   } else {
     MOZ_ASSERT(!replacement);
   }
 
-  if (this->newScript(sweep)) {
-    setAddendum(Addendum_None, nullptr, writeBarrier);
-  } else {
-    unboxedLayout(sweep).setNewScript(nullptr, writeBarrier);
-  }
+  setAddendum(Addendum_None, nullptr, writeBarrier);
 }
 
 void ObjectGroup::maybeClearNewScriptOnOOM() {
   MOZ_ASSERT(zone()->isGCSweepingOrCompacting());
 
   if (!isMarkedAny()) {
     return;
   }
@@ -3723,33 +3648,16 @@ bool PreliminaryObjectArray::empty() con
 }
 
 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 && IsAboutToBeFinalizedUnbarriered(ptr)) {
-      // Before we clear this reference, change the object's group to the
-      // Object.prototype group. This is done to ensure JSObject::finalize
-      // sees a NativeObject Class even if we change the current group's
-      // Class to one of the unboxed object classes in the meantime. If
-      // the realm's global is dead, we don't do anything as the group's
-      // Class is not going to change in that case.
-      JSObject* obj = *ptr;
-      GlobalObject* global =
-          obj->as<NativeObject>().realm()->unsafeUnbarrieredMaybeGlobal();
-      if (global && !obj->isSingleton()) {
-        JSObject* objectProto = global->maybeGetPrototype(JSProto_Object);
-        obj->setGroup(objectProto->groupRaw());
-        MOZ_ASSERT(obj->is<NativeObject>());
-        MOZ_ASSERT(obj->getClass() == objectProto->getClass());
-        MOZ_ASSERT(!obj->getClass()->hasFinalize());
-      }
-
       *ptr = nullptr;
     }
   }
 }
 
 void PreliminaryObjectArrayWithTemplate::trace(JSTracer* trc) {
   TraceNullableEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
 }
@@ -3837,40 +3745,34 @@ void PreliminaryObjectArrayWithTemplate:
       return;
     }
 
     if (CommonPrefix(obj->lastProperty(), shape()) != shape()) {
       return;
     }
   }
 
-  AutoSweepObjectGroup sweep(group);
-  if (group->maybeUnboxedLayout(sweep)) {
-    return;
-  }
-
-  // We weren't able to use an unboxed layout, but since the preliminary
-  // objects still reflect the template object's properties, and all
-  // objects in the future will be created with those properties, the
-  // properties can be marked as definite for objects in the group.
+  // Since the preliminary objects still reflect the template object's
+  // properties, and all objects in the future will be created with those
+  // properties, the properties can be marked as definite for objects in the
+  // group.
   group->addDefiniteProperties(cx, shape());
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeNewScript
 /////////////////////////////////////////////////////////////////////
 
 // Make a TypeNewScript for |group|, and set it up to hold the preliminary
 // objects created with the group.
 /* static */
 bool TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun) {
   AutoSweepObjectGroup sweep(group);
   MOZ_ASSERT(cx->zone()->types.activeAnalysis);
   MOZ_ASSERT(!group->newScript(sweep));
-  MOZ_ASSERT(!group->maybeUnboxedLayout(sweep));
   MOZ_ASSERT(cx->realm() == group->realm());
   MOZ_ASSERT(cx->realm() == fun->realm());
 
   // rollbackPartiallyInitializedObjects expects function_ to be
   // canonicalized.
   MOZ_ASSERT(fun->maybeCanonicalFunction() == fun);
 
   if (group->unknownProperties(sweep)) {
@@ -4139,38 +4041,16 @@ bool TypeNewScript::maybeAnalyze(JSConte
     }
     PodCopy(initializerList, initializerVector.begin(),
             initializerVector.length());
   }
 
   js_delete(preliminaryObjects);
   preliminaryObjects = nullptr;
 
-  if (group->maybeUnboxedLayout(sweep)) {
-    // An unboxed layout was constructed for the group, and this has already
-    // been hooked into it.
-    MOZ_ASSERT(group->unboxedLayout(sweep).newScript() == this);
-    destroyNewScript.release();
-
-    // Clear out the template object, which is not used for TypeNewScripts
-    // with an unboxed layout. Currently it is a mutant object with a
-    // non-native group and native shape, so make it safe for GC by changing
-    // its group to the default for its prototype.
-    AutoEnterOOMUnsafeRegion oomUnsafe;
-    ObjectGroup* plainGroup =
-        ObjectGroup::defaultNewGroup(cx, &PlainObject::class_, group->proto());
-    if (!plainGroup) {
-      oomUnsafe.crash("TypeNewScript::maybeAnalyze");
-    }
-    templateObject_->setGroup(plainGroup);
-    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.
     group->addDefiniteProperties(cx, templateObject()->lastProperty());
 
     destroyNewScript.release();
     return true;
@@ -4263,23 +4143,16 @@ bool TypeNewScript::rollbackPartiallyIni
     MOZ_ASSERT(!iter.script()->isDerivedClassConstructor());
 
     Value thisv = iter.thisArgument(cx);
     if (!thisv.isObject() || thisv.toObject().hasLazyGroup() ||
         thisv.toObject().group() != group) {
       continue;
     }
 
-    if (thisv.toObject().is<UnboxedPlainObject>()) {
-      AutoEnterOOMUnsafeRegion oomUnsafe;
-      if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject())) {
-        oomUnsafe.crash("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;
@@ -4469,22 +4342,16 @@ void ConstraintTypeSet::sweep(const Auto
           break;
         }
       } else if (key->isGroup() &&
                  key->groupNoBarrier()
                      ->unknownPropertiesDontCheckGeneration()) {
         // Object sets containing objects with unknown properties might
         // not be complete. Mark the type set as unknown, which it will
         // be treated as during Ion compilation.
-        //
-        // Note that we don't have to do this when the type set might
-        // be missing the native group corresponding to an unboxed
-        // object group. In this case, the native group points to the
-        // unboxed object group via its addendum, so as long as objects
-        // with either group exist, neither group will be finalized.
         flags |= TYPE_FLAG_ANYOBJECT;
         clearObjects();
         objectCount = 0;
         break;
       }
     }
     setBaseObjectCount(objectCount);
     // Note: -1/+1 to also poison the capacity field.
@@ -4558,34 +4425,16 @@ void ObjectGroup::sweep(const AutoSweepO
 
   Maybe<AutoClearTypeInferenceStateOnOOM> clearStateOnOOM;
   if (!zone()->types.isSweepingTypes()) {
     clearStateOnOOM.emplace(zone());
   }
 
   AutoTouchingGrayThings tgt;
 
-  if (auto* layout = maybeUnboxedLayout(sweep)) {
-    // Remove unboxed layouts that are about to be finalized from the
-    // realm wide list while we are still on the main thread.
-    ObjectGroup* group = this;
-    if (IsAboutToBeFinalizedUnbarriered(&group)) {
-      layout->detachFromRealm();
-    }
-
-    if (layout->newScript()) {
-      layout->newScript()->sweep();
-    }
-
-    // Discard constructor code to avoid holding onto ExecutablePools.
-    if (zone()->isGCCompacting()) {
-      layout->setConstructorCode(nullptr);
-    }
-  }
-
   if (maybePreliminaryObjects(sweep)) {
     maybePreliminaryObjects(sweep)->sweep();
   }
 
   if (newScript(sweep)) {
     newScript(sweep)->sweep();
   }
 
deleted file mode 100644
--- a/js/src/vm/UnboxedObject-inl.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * 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_inl_h
-#define vm_UnboxedObject_inl_h
-
-#include "vm/UnboxedObject.h"
-
-#include "vm/TypeInference.h"
-
-#include "gc/StoreBuffer-inl.h"
-#include "vm/NativeObject-inl.h"
-
-namespace js {
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedPlainObject
-/////////////////////////////////////////////////////////////////////
-
-inline const UnboxedLayout& UnboxedPlainObject::layout() const {
-  AutoSweepObjectGroup sweep(group());
-  return group()->unboxedLayout(sweep);
-}
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedLayout
-/////////////////////////////////////////////////////////////////////
-
-gc::AllocKind js::UnboxedLayout::getAllocKind() const {
-  MOZ_ASSERT(size());
-  return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() +
-                                     size());
-}
-
-}  // namespace js
-
-#endif  // vm_UnboxedObject_inl_h
deleted file mode 100644
--- a/js/src/vm/UnboxedObject.cpp
+++ /dev/null
@@ -1,969 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * 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-inl.h"
-
-#include "mozilla/Maybe.h"
-#include "mozilla/MemoryChecking.h"
-
-#include "jit/BaselineIC.h"
-#include "jit/ExecutableAllocator.h"
-#include "jit/JitCommon.h"
-#include "jit/Linker.h"
-
-#include "gc/Nursery-inl.h"
-#include "jit/MacroAssembler-inl.h"
-#include "vm/JSObject-inl.h"
-#include "vm/JSScript-inl.h"
-#include "vm/Shape-inl.h"
-#include "vm/TypeInference-inl.h"
-
-using mozilla::ArrayLength;
-using mozilla::PodCopy;
-
-using namespace js;
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedLayout
-/////////////////////////////////////////////////////////////////////
-
-void UnboxedLayout::trace(JSTracer* trc) {
-  for (size_t i = 0; i < properties_.length(); i++) {
-    TraceManuallyBarrieredEdge(trc, &properties_[i].name,
-                               "unboxed_layout_name");
-  }
-
-  if (newScript()) {
-    newScript()->trace(trc);
-  }
-
-  TraceNullableEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup");
-  TraceNullableEdge(trc, &nativeShape_, "unboxed_layout_nativeShape");
-  TraceNullableEdge(trc, &allocationScript_, "unboxed_layout_allocationScript");
-  TraceNullableEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup");
-  TraceNullableEdge(trc, &constructorCode_, "unboxed_layout_constructorCode");
-}
-
-size_t UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
-  return mallocSizeOf(this) + properties_.sizeOfExcludingThis(mallocSizeOf) +
-         (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0) +
-         mallocSizeOf(traceList());
-}
-
-void UnboxedLayout::setNewScript(TypeNewScript* newScript,
-                                 bool writeBarrier /* = true */) {
-  if (newScript_ && writeBarrier) {
-    TypeNewScript::writeBarrierPre(newScript_);
-  }
-  newScript_ = newScript;
-}
-
-// Constructor code returns a 0x1 value to indicate the constructor code should
-// be cleared.
-static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1;
-
-/* static */
-bool UnboxedLayout::makeConstructorCode(JSContext* cx,
-                                        HandleObjectGroup group) {
-    return false;
-}
-
-void UnboxedLayout::detachFromRealm() {
-  if (isInList()) {
-    remove();
-  }
-}
-
-static Value GetUnboxedValue(uint8_t* p, JSValueType type,
-                             bool maybeUninitialized) {
-  switch (type) {
-    case JSVAL_TYPE_BOOLEAN:
-      if (maybeUninitialized) {
-        // Squelch Valgrind/MSan errors.
-        MOZ_MAKE_MEM_DEFINED(p, 1);
-      }
-      return BooleanValue(*p != 0);
-
-    case JSVAL_TYPE_INT32:
-      if (maybeUninitialized) {
-        MOZ_MAKE_MEM_DEFINED(p, sizeof(int32_t));
-      }
-      return Int32Value(*reinterpret_cast<int32_t*>(p));
-
-    case JSVAL_TYPE_DOUBLE: {
-      // During unboxed plain object creation, non-GC thing properties are
-      // left uninitialized. This is normally fine, since the properties will
-      // be filled in shortly, but if they are read before that happens we
-      // need to make sure that doubles are canonical.
-      if (maybeUninitialized) {
-        MOZ_MAKE_MEM_DEFINED(p, sizeof(double));
-      }
-      double d = *reinterpret_cast<double*>(p);
-      if (maybeUninitialized) {
-        return DoubleValue(JS::CanonicalizeNaN(d));
-      }
-      return DoubleValue(d);
-    }
-
-    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");
-  }
-}
-
-static bool SetUnboxedValue(JSContext* cx, JSObject* unboxedObject, jsid id,
-                            uint8_t* p, JSValueType type, const Value& v,
-                            bool preBarrier) {
-  switch (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()) {
-        JSString** np = reinterpret_cast<JSString**>(p);
-        if (IsInsideNursery(v.toString()) && !IsInsideNursery(unboxedObject)) {
-          v.toString()->storeBuffer()->putWholeCell(unboxedObject);
-        }
-
-        if (preBarrier) {
-          JSString::writeBarrierPre(*np);
-        }
-        *np = v.toString();
-        return true;
-      }
-      return false;
-
-    case JSVAL_TYPE_OBJECT:
-      if (v.isObjectOrNull()) {
-        JSObject** np = reinterpret_cast<JSObject**>(p);
-
-        // Update property types when writing object properties. Types for
-        // other properties were captured when the unboxed layout was
-        // created.
-        AddTypePropertyId(cx, unboxedObject, id, v);
-
-        // As above, trigger post barriers on the whole object.
-        JSObject* obj = v.toObjectOrNull();
-        if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) {
-          obj->storeBuffer()->putWholeCell(unboxedObject);
-        }
-
-        if (preBarrier) {
-          JSObject::writeBarrierPre(*np);
-        }
-        *np = obj;
-        return true;
-      }
-      return false;
-
-    default:
-      MOZ_CRASH("Invalid type for unboxed value");
-  }
-}
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedPlainObject
-/////////////////////////////////////////////////////////////////////
-
-bool UnboxedPlainObject::setValue(JSContext* cx,
-                                  const UnboxedLayout::Property& property,
-                                  const Value& v) {
-  uint8_t* p = &data_[property.offset];
-  return SetUnboxedValue(cx, this, NameToId(property.name), p, property.type, v,
-                         /* preBarrier = */ true);
-}
-
-Value UnboxedPlainObject::getValue(const UnboxedLayout::Property& property,
-                                   bool maybeUninitialized /* = false */) {
-  uint8_t* p = &data_[property.offset];
-  return GetUnboxedValue(p, property.type, maybeUninitialized);
-}
-
-void UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj) {
-  UnboxedPlainObject* uobj = &obj->as<UnboxedPlainObject>();
-
-  if (uobj->maybeExpando()) {
-    TraceManuallyBarrieredEdge(trc, uobj->addressOfExpando(),
-                               "unboxed_expando");
-  }
-
-  const UnboxedLayout& layout = uobj->layoutDontCheckGeneration();
-  const int32_t* list = layout.traceList();
-  if (!list) {
-    return;
-  }
-
-  uint8_t* data = uobj->data();
-  while (*list != -1) {
-    GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
-    TraceEdge(trc, heap, "unboxed_string");
-    list++;
-  }
-  list++;
-  while (*list != -1) {
-    GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list);
-    TraceNullableEdge(trc, heap, "unboxed_object");
-    list++;
-  }
-
-  // Unboxed objects don't have Values to trace.
-  MOZ_ASSERT(*(list + 1) == -1);
-}
-
-/* static */
-UnboxedExpandoObject* UnboxedPlainObject::ensureExpando(
-    JSContext* cx, Handle<UnboxedPlainObject*> obj) {
-  if (obj->maybeExpando()) {
-    return obj->maybeExpando();
-  }
-
-  UnboxedExpandoObject* expando = NewObjectWithGivenProto<UnboxedExpandoObject>(
-      cx, nullptr, gc::AllocKind::OBJECT4);
-  if (!expando) {
-    return nullptr;
-  }
-
-  // Don't track property types for expando objects. This allows Baseline
-  // and Ion AddSlot ICs to guard on the unboxed group without guarding on
-  // the expando group.
-  MarkObjectGroupUnknownProperties(cx, expando->group());
-
-  // If the expando is tenured then the original object must also be tenured.
-  // Otherwise barriers triggered on the original object for writes to the
-  // expando (as can happen in the JIT) won't see the tenured->nursery edge.
-  // See WholeCellEdges::mark.
-  MOZ_ASSERT_IF(!IsInsideNursery(expando), !IsInsideNursery(obj));
-
-  // As with setValue(), we need to manually trigger post barriers on the
-  // whole object. If we treat the field as a GCPtrObject and later
-  // convert the object to its native representation, we will end up with a
-  // corrupted store buffer entry.
-  if (IsInsideNursery(expando) && !IsInsideNursery(obj)) {
-    expando->storeBuffer()->putWholeCell(obj);
-  }
-
-  obj->setExpandoUnsafe(expando);
-  return expando;
-}
-
-bool UnboxedPlainObject::containsUnboxedOrExpandoProperty(JSContext* cx,
-                                                          jsid id) const {
-  if (layoutDontCheckGeneration().lookup(id)) {
-    return true;
-  }
-
-  if (maybeExpando() && maybeExpando()->containsShapeOrElement(cx, id)) {
-    return true;
-  }
-
-  return false;
-}
-
-static bool PropagatePropertyTypes(JSContext* cx, jsid id,
-                                   ObjectGroup* oldGroup,
-                                   ObjectGroup* newGroup) {
-  AutoSweepObjectGroup sweepOld(oldGroup);
-  HeapTypeSet* typeProperty = oldGroup->maybeGetProperty(sweepOld, id);
-  TypeSet::TypeList types;
-  if (!typeProperty->enumerateTypes(&types)) {
-    ReportOutOfMemory(cx);
-    return false;
-  }
-  for (size_t j = 0; j < types.length(); j++) {
-    AddTypePropertyId(cx, newGroup, nullptr, id, types[j]);
-  }
-  return true;
-}
-
-static PlainObject* MakeReplacementTemplateObject(JSContext* cx,
-                                                  HandleObjectGroup group,
-                                                  const UnboxedLayout& layout) {
-  Rooted<PlainObject*> obj(
-      cx, NewObjectWithGroup<PlainObject>(cx, group, layout.getAllocKind(),
-                                          TenuredObject));
-  if (!obj) {
-    return nullptr;
-  }
-
-  RootedId id(cx);
-  for (size_t i = 0; i < layout.properties().length(); i++) {
-    const UnboxedLayout::Property& property = layout.properties()[i];
-    id = NameToId(property.name);
-    Shape* shape = NativeObject::addDataProperty(
-        cx, obj, id, SHAPE_INVALID_SLOT, JSPROP_ENUMERATE);
-    if (!shape) {
-      return nullptr;
-    }
-    MOZ_ASSERT(shape->slot() == i);
-    MOZ_ASSERT(obj->slotSpan() == i + 1);
-    MOZ_ASSERT(!obj->inDictionaryMode());
-  }
-
-  return obj;
-}
-
-/* static */
-bool UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) {
-  MOZ_ASSERT(cx->realm() == group->realm());
-
-  AutoEnterAnalysis enter(cx);
-
-  AutoSweepObjectGroup sweep(group);
-  UnboxedLayout& layout = group->unboxedLayout(sweep);
-  Rooted<TaggedProto> proto(cx, group->proto());
-
-  MOZ_ASSERT(!layout.nativeGroup());
-
-  RootedObjectGroup replacementGroup(cx);
-
-  // Immediately clear any new script on the group. This is done by replacing
-  // the existing new script with one for a replacement default new group.
-  // This is done so that the size of the replacment group's objects is the
-  // same as that for the unboxed group, so that we do not see polymorphic
-  // slot accesses later on for sites that see converted objects from this
-  // group and objects that were allocated using the replacement new group.
-  if (layout.newScript()) {
-    replacementGroup = ObjectGroupRealm::makeGroup(cx, group->realm(),
-                                                   &PlainObject::class_, proto);
-    if (!replacementGroup) {
-      return false;
-    }
-
-    PlainObject* templateObject =
-        MakeReplacementTemplateObject(cx, replacementGroup, layout);
-    if (!templateObject) {
-      return false;
-    }
-
-    TypeNewScript* replacementNewScript = TypeNewScript::makeNativeVersion(
-        cx, layout.newScript(), templateObject);
-    if (!replacementNewScript) {
-      return false;
-    }
-
-    replacementGroup->setNewScript(replacementNewScript);
-    gc::gcTracer.traceTypeNewScript(replacementGroup);
-
-    group->clearNewScript(cx, replacementGroup);
-  }
-
-  // Similarly, if this group is keyed to an allocation site, replace its
-  // entry with a new group that has no unboxed layout.
-  if (layout.allocationScript()) {
-    RootedScript script(cx, layout.allocationScript());
-    jsbytecode* pc = layout.allocationPc();
-
-    replacementGroup = ObjectGroupRealm::makeGroup(cx, group->realm(),
-                                                   &PlainObject::class_, proto);
-    if (!replacementGroup) {
-      return false;
-    }
-
-    PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>();
-    replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty());
-
-    ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
-    realm.replaceAllocationSiteGroup(script, pc, JSProto_Object,
-                                     replacementGroup);
-
-    // Clear any baseline information at this opcode which might use the old
-    // group.
-    if (script->hasICScript()) {
-      jit::ICEntry& entry =
-          script->icScript()->icEntryFromPCOffset(script->pcToOffset(pc));
-      jit::ICFallbackStub* fallback = entry.fallbackStub();
-      for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd();
-           iter++) {
-        iter.unlink(cx);
-      }
-      if (fallback->isNewObject_Fallback()) {
-        fallback->toNewObject_Fallback()->setTemplateObject(nullptr);
-      } else if (fallback->isNewArray_Fallback()) {
-        fallback->toNewArray_Fallback()->setTemplateGroup(replacementGroup);
-      }
-    }
-  }
-
-  size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
-
-  RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_,
-                                                    proto, nfixed, 0));
-  if (!shape) {
-    return false;
-  }
-
-  // Add shapes for each property, if this is for a plain object.
-  for (size_t i = 0; i < layout.properties().length(); i++) {
-    const UnboxedLayout::Property& property = layout.properties()[i];
-
-    Rooted<StackShape> child(
-        cx, StackShape(shape->base()->unowned(), NameToId(property.name), i,
-                       JSPROP_ENUMERATE));
-    shape = cx->zone()->propertyTree().getChild(cx, shape, child);
-    if (!shape) {
-      return false;
-    }
-  }
-
-  ObjectGroup* nativeGroup = ObjectGroupRealm::makeGroup(
-      cx, group->realm(), &PlainObject::class_, proto,
-      group->flags(sweep) & OBJECT_FLAG_DYNAMIC_MASK);
-  if (!nativeGroup) {
-    return false;
-  }
-
-  // No sense propagating if we don't know what we started with.
-  AutoSweepObjectGroup sweepNative(nativeGroup);
-  if (!group->unknownProperties(sweep)) {
-    for (size_t i = 0; i < layout.properties().length(); i++) {
-      const UnboxedLayout::Property& property = layout.properties()[i];
-      jsid id = NameToId(property.name);
-      if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) {
-        return false;
-      }
-
-      // If we are OOM we may not be able to propagate properties.
-      if (nativeGroup->unknownProperties(sweepNative)) {
-        break;
-      }
-    }
-  } else {
-    // If we skip, though, the new group had better agree.
-    MOZ_ASSERT(nativeGroup->unknownProperties(sweepNative));
-  }
-
-  layout.nativeGroup_ = nativeGroup;
-  layout.nativeShape_ = shape;
-  layout.replacementGroup_ = replacementGroup;
-
-  nativeGroup->setOriginalUnboxedGroup(group);
-
-  group->markStateChange(sweep, cx);
-
-  return true;
-}
-
-/* static */
-NativeObject* UnboxedPlainObject::convertToNative(JSContext* cx,
-                                                  JSObject* obj) {
-  // This function returns the original object (instead of bool) to make sure
-  // Ion's LConvertUnboxedObjectToNative works correctly. If we return bool
-  // and use defineReuseInput, the object register is not preserved across the
-  // call.
-
-  const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
-  UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
-
-  // Ensure we're working in the object's realm, so we don't have to worry about
-  // creating groups or templates in the wrong realm.
-  AutoRealm ar(cx, obj);
-
-  if (!layout.nativeGroup()) {
-    if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) {
-      return nullptr;
-    }
-
-    // makeNativeGroup can reentrantly invoke this method.
-    if (obj->is<PlainObject>()) {
-      return &obj->as<PlainObject>();
-    }
-  }
-
-  AutoValueVector values(cx);
-  for (size_t i = 0; i < layout.properties().length(); i++) {
-    // We might be reading properties off the object which have not been
-    // initialized yet. Make sure any double values we read here are
-    // canonicalized.
-    if (!values.append(obj->as<UnboxedPlainObject>().getValue(
-            layout.properties()[i], true))) {
-      return nullptr;
-    }
-  }
-
-  // We are eliminating the expando edge with the conversion, so trigger a
-  // pre barrier.
-  JSObject::writeBarrierPre(expando);
-
-  // Additionally trigger a post barrier on the expando itself. Whole cell
-  // store buffer entries can be added on the original unboxed object for
-  // writes to the expando (see WholeCellEdges::trace), so after conversion
-  // we need to make sure the expando itself will still be traced.
-  if (expando && !IsInsideNursery(expando)) {
-    cx->runtime()->gc.storeBuffer().putWholeCell(expando);
-  }
-
-  obj->setGroup(layout.nativeGroup());
-  obj->as<PlainObject>().setLastPropertyMakeNative(cx, layout.nativeShape());
-
-  for (size_t i = 0; i < values.length(); i++) {
-    obj->as<PlainObject>().initSlotUnchecked(i, values[i]);
-  }
-
-  if (!expando) {
-    return &obj->as<PlainObject>();
-  }
-
-  // Add properties from the expando object to the object, in order.
-  // Suppress GC here, so that callers don't need to worry about this
-  // method collecting. The stuff below can only fail due to OOM, in
-  // which case the object will not have been completely filled back in.
-  gc::AutoSuppressGC suppress(cx);
-
-  Vector<jsid> ids(cx);
-  for (Shape::Range<NoGC> r(expando->lastProperty()); !r.empty();
-       r.popFront()) {
-    if (!ids.append(r.front().propid())) {
-      return nullptr;
-    }
-  }
-  for (size_t i = 0; i < expando->getDenseInitializedLength(); i++) {
-    if (!expando->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
-      if (!ids.append(INT_TO_JSID(i))) {
-        return nullptr;
-      }
-    }
-  }
-  ::Reverse(ids.begin(), ids.end());
-
-  RootedPlainObject nobj(cx, &obj->as<PlainObject>());
-  Rooted<UnboxedExpandoObject*> nexpando(cx, expando);
-  RootedId id(cx);
-  Rooted<PropertyDescriptor> desc(cx);
-  for (size_t i = 0; i < ids.length(); i++) {
-    id = ids[i];
-    if (!GetOwnPropertyDescriptor(cx, nexpando, id, &desc)) {
-      return nullptr;
-    }
-    ObjectOpResult result;
-    if (!DefineProperty(cx, nobj, id, desc, result)) {
-      return nullptr;
-    }
-    MOZ_ASSERT(result.ok());
-  }
-
-  return nobj;
-}
-
-/* static */ JS::Result<UnboxedObject*, JS::OOM&> UnboxedObject::createInternal(
-    JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
-    js::HandleObjectGroup group) {
-  const js::Class* clasp = group->clasp();
-  MOZ_ASSERT(clasp == &UnboxedPlainObject::class_);
-
-  MOZ_ASSERT(CanBeFinalizedInBackground(kind, clasp));
-  kind = GetBackgroundAllocKind(kind);
-
-  debugCheckNewObject(group, /* shape = */ nullptr, kind, heap);
-
-  JSObject* obj =
-      js::AllocateObject(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
-  if (!obj) {
-    return cx->alreadyReportedOOM();
-  }
-
-  UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
-  uobj->initGroup(group);
-
-  MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
-  cx->realm()->setObjectPendingMetadata(cx, uobj);
-
-  js::gc::gcTracer.traceCreateObject(uobj);
-
-  return uobj;
-}
-
-/* static */
-UnboxedPlainObject* UnboxedPlainObject::create(JSContext* cx,
-                                               HandleObjectGroup group,
-                                               NewObjectKind newKind) {
-  AutoSetNewObjectMetadata metadata(cx);
-
-  MOZ_ASSERT(group->clasp() == &class_);
-
-  gc::AllocKind allocKind;
-  {
-    AutoSweepObjectGroup sweep(group);
-    allocKind = group->unboxedLayout(sweep).getAllocKind();
-  }
-  gc::InitialHeap heap = GetInitialHeap(newKind, &class_);
-
-  MOZ_ASSERT(newKind != SingletonObject);
-
-  JSObject* obj;
-  JS_TRY_VAR_OR_RETURN_NULL(cx, obj,
-                            createInternal(cx, allocKind, heap, group));
-
-  UnboxedPlainObject* uobj = static_cast<UnboxedPlainObject*>(obj);
-  uobj->initExpando();
-
-  // 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 = uobj->layout().traceList();
-  if (list) {
-    uint8_t* data = uobj->data();
-    while (*list != -1) {
-      GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
-      heap->init(cx->names().empty);
-      list++;
-    }
-    list++;
-    while (*list != -1) {
-      GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list);
-      heap->init(nullptr);
-      list++;
-    }
-    // Unboxed objects don't have Values to initialize.
-    MOZ_ASSERT(*(list + 1) == -1);
-  }
-
-  return uobj;
-}
-
-/* static */
-JSObject* UnboxedPlainObject::createWithProperties(JSContext* cx,
-                                                   HandleObjectGroup group,
-                                                   NewObjectKind newKind,
-                                                   IdValuePair* properties) {
-  MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject);
-
-  {
-    AutoSweepObjectGroup sweep(group);
-    UnboxedLayout& layout = group->unboxedLayout(sweep);
-
-    if (layout.constructorCode()) {
-      MOZ_ASSERT(!cx->helperThread());
-
-      typedef JSObject* (*ConstructorCodeSignature)(IdValuePair*,
-                                                    NewObjectKind);
-      ConstructorCodeSignature function =
-          reinterpret_cast<ConstructorCodeSignature>(
-              layout.constructorCode()->raw());
-
-      JSObject* obj;
-      {
-        JS::AutoSuppressGCAnalysis nogc;
-        obj = reinterpret_cast<JSObject*>(
-            CALL_GENERATED_2(function, properties, newKind));
-      }
-      if (obj > reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN)) {
-        return obj;
-      }
-
-      if (obj == reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN)) {
-        layout.setConstructorCode(nullptr);
-      }
-    }
-  }
-
-  UnboxedPlainObject* obj = UnboxedPlainObject::create(cx, group, newKind);
-  if (!obj) {
-    return nullptr;
-  }
-
-  // AutoSweepObjectGroup can't be live across a GC call, so we reset() it
-  // before calling NewPlainObjectWithProperties.
-  mozilla::Maybe<AutoSweepObjectGroup> sweep;
-  sweep.emplace(group);
-  UnboxedLayout& layout = group->unboxedLayout(*sweep);
-
-  for (size_t i = 0; i < layout.properties().length(); i++) {
-    if (!obj->setValue(cx, layout.properties()[i], properties[i].value)) {
-      sweep.reset();
-      return NewPlainObjectWithProperties(
-          cx, properties, layout.properties().length(), newKind);
-    }
-  }
-
-#ifndef JS_CODEGEN_NONE
-  if (!cx->helperThread() && !group->unknownProperties(*sweep) &&
-      !layout.constructorCode() && cx->runtime()->jitSupportsFloatingPoint &&
-      jit::CanLikelyAllocateMoreExecutableMemory()) {
-    if (!UnboxedLayout::makeConstructorCode(cx, group)) {
-      return nullptr;
-    }
-  }
-#endif
-
-  return obj;
-}
-
-/* static */
-bool UnboxedPlainObject::obj_lookupProperty(
-    JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-    MutableHandle<PropertyResult> propp) {
-  if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
-    propp.setNonNativeProperty();
-    objp.set(obj);
-    return true;
-  }
-
-  RootedObject proto(cx, obj->staticPrototype());
-  if (!proto) {
-    objp.set(nullptr);
-    propp.setNotFound();
-    return true;
-  }
-
-  return LookupProperty(cx, proto, id, objp, propp);
-}
-
-/* static */
-bool UnboxedPlainObject::obj_defineProperty(JSContext* cx, HandleObject obj,
-                                            HandleId id,
-                                            Handle<PropertyDescriptor> desc,
-                                            ObjectOpResult& result) {
-  const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
-
-  if (const UnboxedLayout::Property* property = layout.lookup(id)) {
-    if (!desc.getter() && !desc.setter() &&
-        desc.attributes() == JSPROP_ENUMERATE) {
-      // This define is equivalent to setting an existing property.
-      if (obj->as<UnboxedPlainObject>().setValue(cx, *property, desc.value())) {
-        return result.succeed();
-      }
-    }
-
-    // Trying to incompatibly redefine an existing property requires the
-    // object to be converted to a native object.
-    if (!convertToNative(cx, obj)) {
-      return false;
-    }
-
-    return DefineProperty(cx, obj, id, desc, result);
-  }
-
-  // Define the property on the expando object.
-  Rooted<UnboxedExpandoObject*> expando(
-      cx, ensureExpando(cx, obj.as<UnboxedPlainObject>()));
-  if (!expando) {
-    return false;
-  }
-
-  // Update property types on the unboxed object as well.
-  AddTypePropertyId(cx, obj, id, desc.value());
-
-  return DefineProperty(cx, expando, id, desc, result);
-}
-
-/* static */
-bool UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj,
-                                         HandleId id, bool* foundp) {
-  if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
-    *foundp = true;
-    return true;
-  }
-
-  RootedObject proto(cx, obj->staticPrototype());
-  if (!proto) {
-    *foundp = false;
-    return true;
-  }
-
-  return HasProperty(cx, proto, id, foundp);
-}
-
-/* static */
-bool UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj,
-                                         HandleValue 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;
-  }
-
-  if (UnboxedExpandoObject* expando =
-          obj->as<UnboxedPlainObject>().maybeExpando()) {
-    if (expando->containsShapeOrElement(cx, id)) {
-      RootedObject nexpando(cx, expando);
-      return GetProperty(cx, nexpando, receiver, id, vp);
-    }
-  }
-
-  RootedObject proto(cx, obj->staticPrototype());
-  if (!proto) {
-    vp.setUndefined();
-    return true;
-  }
-
-  return GetProperty(cx, proto, receiver, id, vp);
-}
-
-/* static */
-bool UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj,
-                                         HandleId id, HandleValue v,
-                                         HandleValue receiver,
-                                         ObjectOpResult& result) {
-  const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
-
-  if (const UnboxedLayout::Property* property = layout.lookup(id)) {
-    if (receiver.isObject() && obj == &receiver.toObject()) {
-      if (obj->as<UnboxedPlainObject>().setValue(cx, *property, v)) {
-        return result.succeed();
-      }
-
-      if (!convertToNative(cx, obj)) {
-        return false;
-      }
-      return SetProperty(cx, obj, id, v, receiver, result);
-    }
-
-    return SetPropertyByDefining(cx, id, v, receiver, result);
-  }
-
-  if (UnboxedExpandoObject* expando =
-          obj->as<UnboxedPlainObject>().maybeExpando()) {
-    if (expando->containsShapeOrElement(cx, id)) {
-      // Update property types on the unboxed object as well.
-      AddTypePropertyId(cx, obj, id, v);
-
-      RootedObject nexpando(cx, expando);
-      return SetProperty(cx, nexpando, id, v, receiver, result);
-    }
-  }
-
-  return SetPropertyOnProto(cx, obj, id, v, receiver, result);
-}
-
-/* static */
-bool UnboxedPlainObject::obj_getOwnPropertyDescriptor(
-    JSContext* cx, HandleObject obj, HandleId id,
-    MutableHandle<PropertyDescriptor> 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;
-  }
-
-  if (UnboxedExpandoObject* expando =
-          obj->as<UnboxedPlainObject>().maybeExpando()) {
-    if (expando->containsShapeOrElement(cx, id)) {
-      RootedObject nexpando(cx, expando);
-      if (!GetOwnPropertyDescriptor(cx, nexpando, id, desc)) {
-        return false;
-      }
-      if (desc.object() == nexpando) {
-        desc.object().set(obj);
-      }
-      return true;
-    }
-  }
-
-  desc.object().set(nullptr);
-  return true;
-}
-
-/* static */
-bool UnboxedPlainObject::obj_deleteProperty(JSContext* cx, HandleObject obj,
-                                            HandleId id,
-                                            ObjectOpResult& result) {
-  if (!convertToNative(cx, obj)) {
-    return false;
-  }
-  return DeleteProperty(cx, obj, id, result);
-}
-
-/* static */
-bool UnboxedPlainObject::newEnumerate(JSContext* cx, HandleObject obj,
-                                      AutoIdVector& properties,
-                                      bool enumerableOnly) {
-  // Ignore expando properties here, they are special-cased by the property
-  // enumeration code.
-
-  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 UnboxedExpandoObject::class_ = {"UnboxedExpandoObject", 0};
-
-static const ClassOps UnboxedPlainObjectClassOps = {
-    nullptr, /* addProperty */
-    nullptr, /* delProperty */
-    nullptr, /* enumerate   */
-    UnboxedPlainObject::newEnumerate,
-    nullptr, /* resolve     */
-    nullptr, /* mayResolve  */
-    nullptr, /* finalize    */
-    nullptr, /* call        */
-    nullptr, /* hasInstance */
-    nullptr, /* construct   */
-    UnboxedPlainObject::trace,
-};
-
-static const ObjectOps UnboxedPlainObjectObjectOps = {
-    UnboxedPlainObject::obj_lookupProperty,
-    UnboxedPlainObject::obj_defineProperty,
-    UnboxedPlainObject::obj_hasProperty,
-    UnboxedPlainObject::obj_getProperty,
-    UnboxedPlainObject::obj_setProperty,
-    UnboxedPlainObject::obj_getOwnPropertyDescriptor,
-    UnboxedPlainObject::obj_deleteProperty,
-    nullptr, /* getElements */
-    nullptr  /* funToString */
-};
-
-const Class UnboxedPlainObject::class_ = {
-    js_Object_str,
-    Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
-        JSCLASS_DELAY_METADATA_BUILDER,
-    &UnboxedPlainObjectClassOps,
-    JS_NULL_CLASS_SPEC,
-    JS_NULL_CLASS_EXT,
-    &UnboxedPlainObjectObjectOps};
-
-/////////////////////////////////////////////////////////////////////
-// API
-/////////////////////////////////////////////////////////////////////
-
-static inline Value NextValue(Handle<GCVector<Value>> values,
-                              size_t* valueCursor) {
-  return values[(*valueCursor)++];
-}
-
-void UnboxedPlainObject::fillAfterConvert(JSContext* cx,
-                                          Handle<GCVector<Value>> values,
-                                          size_t* valueCursor) {
-  initExpando();
-  memset(data(), 0, layout().size());
-  for (size_t i = 0; i < layout().properties().length(); i++) {
-    MOZ_ALWAYS_TRUE(
-        setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
-  }
-}
\ No newline at end of file
deleted file mode 100644
--- a/js/src/vm/UnboxedObject.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * 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 "gc/DeletePolicy.h"
-#include "vm/JSObject.h"
-#include "vm/Runtime.h"
-
-namespace js {
-
-struct AutoEnterAnalysis;
-class PreliminaryObjectArray;
-
-// 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;
-  }
-}
-
-static inline bool UnboxedTypeNeedsPreBarrier(JSValueType type) {
-  return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
-}
-
-static inline bool UnboxedTypeNeedsPostBarrier(JSValueType type) {
-  return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
-}
-
-// Class tracking information specific to unboxed objects.
-class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> {
- public:
-  struct Property {
-    PropertyName* name = nullptr;
-    uint32_t offset = UINT32_MAX;
-    JSValueType type = JSVAL_TYPE_MAGIC;
-
-    Property() = default;
-  };
-
-  using PropertyVector = Vector<Property, 0, SystemAllocPolicy>;
-
- private:
-  JS::Zone* zone_;
-
-  // If objects in this group have ever been converted to native objects,
-  // these store the corresponding native group and initial shape for such
-  // objects. Type information for this object is reflected in nativeGroup.
-  GCPtrObjectGroup nativeGroup_ = {};
-  GCPtrShape nativeShape_ = {};
-
-  // Any script/pc which the associated group is created for.
-  GCPtrScript allocationScript_ = {};
-  jsbytecode* allocationPc_ = {};
-
-  // If nativeGroup is set and this object originally had a TypeNewScript or
-  // was keyed to an allocation site, this points to the group which replaced
-  // this one. This link is only needed to keep the replacement group from
-  // being GC'ed. If it were GC'ed and a new one regenerated later, that new
-  // group might have a different allocation kind from this group.
-  GCPtrObjectGroup replacementGroup_ = {};
-
-  // The following members are only used for unboxed plain objects.
-
-  // 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_ = 0;
-
-  // Any 'new' script information associated with this layout.
-  TypeNewScript* newScript_ = nullptr;
-
-  // List for use in tracing objects with this layout. This has the same
-  // structure as the trace list on a TypeDescr.
-  int32_t* traceList_ = nullptr;
-
-  // If this layout has been used to construct script or JSON constant
-  // objects, this code might be filled in to more quickly fill in objects
-  // from an array of values.
-  GCPtrJitCode constructorCode_ = {};
-
- public:
-  explicit UnboxedLayout(JS::Zone* zone) : zone_(zone) {}
-
-  inline ~UnboxedLayout();
-
-  JS::Zone* zone() const { return zone_; }
-
-  bool initProperties(const PropertyVector& properties, size_t size) {
-    size_ = size;
-    return properties_.appendAll(properties);
-  }
-
-  void detachFromRealm();
-
-  const PropertyVector& properties() const { return properties_; }
-
-  TypeNewScript* newScript() const { return newScript_; }
-
-  void setNewScript(TypeNewScript* newScript, bool writeBarrier = true);
-
-  JSScript* allocationScript() const { return allocationScript_; }
-
-  jsbytecode* allocationPc() const { return allocationPc_; }
-
-  void setAllocationSite(JSScript* script, jsbytecode* pc) {
-    allocationScript_ = script;
-    allocationPc_ = pc;
-  }
-
-  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_; }
-
-  ObjectGroup* nativeGroup() const { return nativeGroup_; }
-
-  Shape* nativeShape() const { return nativeShape_; }
-
-  jit::JitCode* constructorCode() const { return constructorCode_; }
-
-  void setConstructorCode(jit::JitCode* code) { constructorCode_ = code; }
-
-  inline gc::AllocKind getAllocKind() const;
-
-  void trace(JSTracer* trc);
-
-  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
-
-  static bool makeNativeGroup(JSContext* cx, ObjectGroup* group);
-  static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group);
-};
-
-class UnboxedObject : public JSObject {
- protected:
-  static JS::Result<UnboxedObject*, JS::OOM&> createInternal(
-      JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
-      js::HandleObjectGroup group);
-};
-
-// Class for expando objects holding extra properties given to an unboxed plain
-// object. These objects behave identically to normal native plain objects, and
-// have a separate Class to distinguish them for memory usage reporting.
-class UnboxedExpandoObject : public NativeObject {
- public:
-  static const Class class_;
-};
-
-// 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 UnboxedObject {
-  // The |JSObject::shapeOrExpando_| field can optionally refer to an object
-  // which stores extra properties on this object. This is not automatically
-  // barriered to avoid problems if the object is converted to a native. See
-  // ensureExpando(). This object must be an UnboxedExpandoObject.
-  //
-  // NOTE: The JIT should not assume that seeing the same expando pointer
-  //       means the object is even an UnboxedObject. Always check |group_|.
-
-  // Start of the inline data, which immediately follows the group and extra
-  // properties.
-  uint8_t data_[1];
-
- public:
-  static const Class class_;
-
-  static bool obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
-                                 MutableHandleObject objp,
-                                 MutableHandle<PropertyResult> propp);
-
-  static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
-                                 Handle<PropertyDescriptor> desc,
-                                 ObjectOpResult& result);
-
-  static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id,
-                              bool* foundp);
-
-  static bool obj_getProperty(JSContext* cx, HandleObject obj,
-                              HandleValue receiver, HandleId id,
-                              MutableHandleValue vp);
-
-  static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id,
-                              HandleValue v, HandleValue receiver,
-                              ObjectOpResult& result);
-
-  static bool obj_getOwnPropertyDescriptor(
-      JSContext* cx, HandleObject obj, HandleId id,
-      MutableHandle<PropertyDescriptor> desc);
-
-  static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
-                                 ObjectOpResult& result);
-
-  static bool newEnumerate(JSContext* cx, HandleObject obj,
-                           AutoIdVector& properties, bool enumerableOnly);
-
-  inline const UnboxedLayout& layout() const;
-
-  const UnboxedLayout& layoutDontCheckGeneration() const {
-    return group()->unboxedLayoutDontCheckGeneration();
-  }
-
-  uint8_t* data() { return &data_[0]; }
-
-  UnboxedExpandoObject* maybeExpando() const {
-    return static_cast<UnboxedExpandoObject*>(shapeOrExpando_);
-  }
-
-  void setExpandoUnsafe(UnboxedExpandoObject* expando) {
-    shapeOrExpando_ = expando;
-  }
-
-  void initExpando() { shapeOrExpando_ = nullptr; }
-
-  // For use during GC.
-  JSObject** addressOfExpando() {
-    return reinterpret_cast<JSObject**>(&shapeOrExpando_);
-  }
-
-  bool containsUnboxedOrExpandoProperty(JSContext* cx, jsid id) const;
-
-  static UnboxedExpandoObject* ensureExpando(JSContext* cx,
-                                             Handle<UnboxedPlainObject*> obj);
-
-  bool setValue(JSContext* cx, const UnboxedLayout::Property& property,
-                const Value& v);
-  Value getValue(const UnboxedLayout::Property& property,
-                 bool maybeUninitialized = false);
-
-  static NativeObject* convertToNative(JSContext* cx, JSObject* obj);
-  static UnboxedPlainObject* create(JSContext* cx, HandleObjectGroup group,
-                                    NewObjectKind newKind);
-  static JSObject* createWithProperties(JSContext* cx, HandleObjectGroup group,
-                                        NewObjectKind newKind,
-                                        IdValuePair* properties);
-
-  void fillAfterConvert(JSContext* cx, Handle<GCVector<Value>> values,
-                        size_t* valueCursor);
-
-  static void trace(JSTracer* trc, JSObject* object);
-
-  static size_t offsetOfExpando() { return offsetOfShapeOrExpando(); }
-
-  static size_t offsetOfData() {
-    return offsetof(UnboxedPlainObject, data_[0]);
-  }
-};
-
-inline bool IsUnboxedObjectClass(const Class* class_) {
-  return class_ == &UnboxedPlainObject::class_;
-}
-
-}  // namespace js
-
-namespace JS {
-
-template <>
-struct DeletePolicy<js::UnboxedLayout>
-    : public js::GCManagedDeletePolicy<js::UnboxedLayout> {};
-
-} /* namespace JS */
-
-#endif /* vm_UnboxedObject_h */