Bug 1505574 - Remove Unboxed Objects from vm/ - Part 2 r=iain
authorMatthew Gaudet <mgaudet@mozilla.com>
Fri, 22 Mar 2019 15:32:21 +0000
changeset 465715 8d759131d76e3d3c7be7ad3438a707a2ab77f2b3
parent 465714 2939d41f1ade73020256e6f50bd8653cebee17c9
child 465716 c54c4aa147f910b4fdfa873d4e1e948f1c37cebf
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 2 r=iain Differential Revision: https://phabricator.services.mozilla.com/D24044
js/src/vm/Interpreter.cpp
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/Realm.cpp
js/src/vm/ReceiverGuard-inl.h
js/src/vm/ReceiverGuard.cpp
js/src/vm/SelfHosting.cpp
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -5183,26 +5183,20 @@ JSObject* js::NewObjectOperationWithTemp
                                              HandleObject templateObject) {
   // This is an optimized version of NewObjectOperation for use when the
   // object is not a singleton and has had its preliminary objects analyzed,
   // with the template object a copy of the object to create.
   MOZ_ASSERT(!templateObject->isSingleton());
   MOZ_ASSERT(cx->realm() == templateObject->nonCCWRealm());
 
   NewObjectKind newKind;
-  bool isUnboxed;
   {
     ObjectGroup* group = templateObject->group();
     AutoSweepObjectGroup sweep(group);
     newKind = group->shouldPreTenure(sweep) ? TenuredObject : GenericObject;
-    isUnboxed = group->maybeUnboxedLayout(sweep);
-  }
-  if (isUnboxed) {
-    RootedObjectGroup group(cx, templateObject->group());
-    return UnboxedPlainObject::create(cx, group, newKind);
   }
 
   JSObject* obj =
       CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
   if (!obj) {
     return nullptr;
   }
 
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -71,17 +71,16 @@
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/ObjectGroup-inl.h"
 #include "vm/Realm-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/TypedArrayObject-inl.h"
 #include "vm/TypeInference-inl.h"
-#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 void js::ReportNotObject(JSContext* cx, HandleValue v) {
   MOZ_ASSERT(!v.isObject());
 
   if (UniqueChars bytes =
           DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr)) {
@@ -1033,28 +1032,22 @@ JSObject* js::CreateThis(JSContext* cx, 
   }
   gc::AllocKind kind = NewObjectGCKind(newclasp);
   return NewObjectWithClassProto(cx, newclasp, proto, kind);
 }
 
 static inline JSObject* CreateThisForFunctionWithGroup(JSContext* cx,
                                                        HandleObjectGroup group,
                                                        NewObjectKind newKind) {
-  bool isUnboxed;
   TypeNewScript* maybeNewScript;
   {
     AutoSweepObjectGroup sweep(group);
-    isUnboxed = group->maybeUnboxedLayout(sweep);
     maybeNewScript = group->newScript(sweep);
   }
 
-  if (isUnboxed && newKind != SingletonObject) {
-    return UnboxedPlainObject::create(cx, group, newKind);
-  }
-
   if (maybeNewScript) {
     if (maybeNewScript->analyzed()) {
       // The definite properties analysis has been performed for this
       // group, so get the shape and alloc kind to use from the
       // TypeNewScript's template.
       RootedPlainObject templateObject(cx, maybeNewScript->templateObject());
       MOZ_ASSERT(templateObject->group() == group);
 
@@ -1418,60 +1411,40 @@ static bool GetScriptArrayObjectElements
     values[i].set(arr->getDenseElement(i));
   }
 
   return true;
 }
 
 static bool GetScriptPlainObjectProperties(
     HandleObject obj, MutableHandle<IdValueVector> properties) {
-  if (obj->is<PlainObject>()) {
-    PlainObject* nobj = &obj->as<PlainObject>();
-
-    if (!properties.appendN(IdValuePair(), nobj->slotSpan())) {
+  MOZ_ASSERT(obj->is<PlainObject>());
+  PlainObject* nobj = &obj->as<PlainObject>();
+
+  if (!properties.appendN(IdValuePair(), nobj->slotSpan())) {
+    return false;
+  }
+
+  for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
+    Shape& shape = r.front();
+    MOZ_ASSERT(shape.isDataDescriptor());
+    uint32_t slot = shape.slot();
+    properties[slot].get().id = shape.propid();
+    properties[slot].get().value = nobj->getSlot(slot);
+  }
+
+  for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
+    Value v = nobj->getDenseElement(i);
+    if (!v.isMagic(JS_ELEMENTS_HOLE) &&
+        !properties.append(IdValuePair(INT_TO_JSID(i), v))) {
       return false;
     }
-
-    for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
-      Shape& shape = r.front();
-      MOZ_ASSERT(shape.isDataDescriptor());
-      uint32_t slot = shape.slot();
-      properties[slot].get().id = shape.propid();
-      properties[slot].get().value = nobj->getSlot(slot);
-    }
-
-    for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
-      Value v = nobj->getDenseElement(i);
-      if (!v.isMagic(JS_ELEMENTS_HOLE) &&
-          !properties.append(IdValuePair(INT_TO_JSID(i), v))) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  if (obj->is<UnboxedPlainObject>()) {
-    UnboxedPlainObject* nobj = &obj->as<UnboxedPlainObject>();
-
-    const UnboxedLayout& layout = nobj->layout();
-    if (!properties.appendN(IdValuePair(), layout.properties().length())) {
-      return false;
-    }
-
-    for (size_t i = 0; i < layout.properties().length(); i++) {
-      const UnboxedLayout::Property& property = layout.properties()[i];
-      properties[i].get().id = NameToId(property.name);
-      properties[i].get().value = nobj->getValue(property);
-    }
-
-    return true;
-  }
-
-  MOZ_CRASH("Bad object kind");
+  }
+
+  return true;
 }
 
 static bool DeepCloneValue(JSContext* cx, Value* vp, NewObjectKind newKind) {
   if (vp->isObject()) {
     RootedObject obj(cx, &vp->toObject());
     obj = DeepCloneObjectLiteral(cx, obj, newKind);
     if (!obj) {
       return false;
@@ -1483,18 +1456,17 @@ static bool DeepCloneValue(JSContext* cx
   return true;
 }
 
 JSObject* js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj,
                                      NewObjectKind newKind) {
   /* NB: Keep this in sync with XDRObjectLiteral. */
   MOZ_ASSERT_IF(obj->isSingleton(),
                 cx->realm()->behaviors().getSingletonsAsTemplates());
-  MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
-             obj->is<ArrayObject>());
+  MOZ_ASSERT(obj->is<PlainObject>() || obj->is<ArrayObject>());
   MOZ_ASSERT(newKind != SingletonObject);
 
   if (obj->is<ArrayObject>()) {
     Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
     if (!GetScriptArrayObjectElements(obj.as<ArrayObject>(), &values)) {
       return nullptr;
     }
 
@@ -1607,18 +1579,17 @@ XDRResult js::XDRObjectLiteral(XDRState<
 
   JSContext* cx = xdr->cx();
   cx->check(obj);
 
   // Distinguish between objects and array classes.
   uint32_t isArray = 0;
   {
     if (mode == XDR_ENCODE) {
-      MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
-                 obj->is<ArrayObject>());
+      MOZ_ASSERT(obj->is<PlainObject>() || obj->is<ArrayObject>());
       isArray = obj->is<ArrayObject>() ? 1 : 0;
     }
 
     MOZ_TRY(xdr->codeUint32(&isArray));
   }
 
   RootedValue tmpValue(cx), tmpIdValue(cx);
   RootedId tmpId(cx);
@@ -2570,22 +2541,16 @@ bool js::LookupOwnPropertyPure(JSContext
       return true;
     }
 
     // Fail if there's a resolve hook, unless the mayResolve hook tells
     // us the resolve hook won't define a property with this id.
     if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) {
       return false;
     }
-  } else if (obj->is<UnboxedPlainObject>()) {
-    if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx,
-                                                                       id)) {
-      propp->setNonNativeProperty();
-      return true;
-    }
   } else if (obj->is<TypedObject>()) {
     if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
       propp->setNonNativeProperty();
       return true;
     }
   } else {
     return false;
   }
@@ -2612,71 +2577,46 @@ static inline bool NativeGetPureInline(N
     return false;
   }
 
   *vp = pobj->getSlot(shape->slot());
   MOZ_ASSERT(!vp->isMagic());
   return true;
 }
 
-static inline bool UnboxedGetPureInline(JSObject* pobj, jsid id,
-                                        PropertyResult prop, Value* vp) {
-  MOZ_ASSERT(prop.isNonNativeProperty());
-
-  // This might be a TypedObject.
-  if (!pobj->is<UnboxedPlainObject>()) {
-    return false;
-  }
-
-  const UnboxedLayout& layout = pobj->as<UnboxedPlainObject>().layout();
-  if (const UnboxedLayout::Property* property = layout.lookup(id)) {
-    *vp = pobj->as<UnboxedPlainObject>().getValue(*property);
-    return true;
-  }
-
-  // Don't bother supporting expandos for now.
-  return false;
-}
-
 bool js::GetPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp) {
   JSObject* pobj;
   PropertyResult prop;
   if (!LookupPropertyPure(cx, obj, id, &pobj, &prop)) {
     return false;
   }
 
   if (!prop) {
     vp->setUndefined();
     return true;
   }
 
-  if (MOZ_LIKELY(pobj->isNative())) {
-    return NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
-  }
-  return UnboxedGetPureInline(pobj, id, prop, vp);
+  return NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
 }
 
 bool js::GetOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp,
                             bool* found) {
   PropertyResult prop;
   if (!LookupOwnPropertyPure(cx, obj, id, &prop)) {
     return false;
   }
 
   if (!prop) {
     *found = false;
     vp->setUndefined();
     return true;
   }
 
   *found = true;
-  if (MOZ_LIKELY(obj->isNative())) {
-    return NativeGetPureInline(&obj->as<NativeObject>(), id, prop, vp);
-  }
-  return UnboxedGetPureInline(obj, id, prop, vp);
+  return NativeGetPureInline(&obj->as<NativeObject>(), id, prop, vp);
 }
 
 static inline bool NativeGetGetterPureInline(PropertyResult prop,
                                              JSFunction** fp) {
   if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) {
     Shape* shape = prop.shape();
     if (shape->getterObject()->is<JSFunction>()) {
       *fp = &shape->getterObject()->as<JSFunction>();
@@ -2843,22 +2783,16 @@ bool js::SetPrototype(JSContext* cx, Han
     if (!GetPrototypeIfOrdinary(cx, obj2, &isOrdinary, &obj2)) {
       return false;
     }
     if (!isOrdinary) {
       break;
     }
   }
 
-  // Convert unboxed objects to their native representations before changing
-  // their prototype/group, as they depend on the group for their layout.
-  if (!MaybeConvertUnboxedObjectToNative(cx, obj)) {
-    return false;
-  }
-
   Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
   if (!SetProto(cx, obj, taggedProto)) {
     return false;
   }
 
   return result.succeed();
 }
 
@@ -2879,20 +2813,16 @@ bool js::PreventExtensions(JSContext* cx
     // and fixed.
     MOZ_ASSERT_IF(obj->isNative(),
                   obj->as<NativeObject>().getDenseInitializedLength() ==
                       obj->as<NativeObject>().getDenseCapacity());
 
     return result.succeed();
   }
 
-  if (!MaybeConvertUnboxedObjectToNative(cx, obj)) {
-    return false;
-  }
-
   if (obj->isNative()) {
     // Force lazy properties to be resolved.
     if (!ResolveLazyProperties(cx, obj.as<NativeObject>())) {
       return false;
     }
 
     // Prepare the elements. We have to do this before we mark the object
     // non-extensible; that's fine because these changes are not observable.
@@ -3933,22 +3863,16 @@ js::gc::AllocKind JSObject::allocKindFor
     if (!nursery.isInside(aobj.getElementsHeader())) {
       return gc::AllocKind::OBJECT0_BACKGROUND;
     }
 
     size_t nelements = aobj.getDenseCapacity();
     return GetBackgroundAllocKind(GetGCArrayKind(nelements));
   }
 
-  // Unboxed plain objects are sized according to the data they store.
-  if (is<UnboxedPlainObject>()) {
-    size_t nbytes = as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
-    return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
-  }
-
   if (is<JSFunction>()) {
     return as<JSFunction>().getAllocKind();
   }
 
   /*
    * Typed arrays in the nursery may have a lazily allocated buffer, make
    * sure there is room for the array's fixed data when moving the array.
    */
@@ -4278,21 +4202,17 @@ bool js::Unbox(JSContext* cx, HandleObje
 #ifdef DEBUG
 /* static */
 void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape,
                                    js::gc::AllocKind allocKind,
                                    js::gc::InitialHeap heap) {
   const js::Class* clasp = group->clasp();
   MOZ_ASSERT(clasp != &ArrayObject::class_);
 
-  if (shape) {
-    MOZ_ASSERT(clasp == shape->getObjectClass());
-  } else {
-    MOZ_ASSERT(clasp == &UnboxedPlainObject::class_);
-  }
+  MOZ_ASSERT_IF(shape, clasp == shape->getObjectClass());
 
   if (!ClassCanHaveFixedData(clasp)) {
     MOZ_ASSERT(shape);
     MOZ_ASSERT(gc::GetGCKindSlots(allocKind, clasp) == shape->numFixedSlots());
   }
 
   // Classes with a finalizer must specify whether instances will be finalized
   // on the main thread or in the background, except proxies whose behaviour
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -78,17 +78,16 @@ bool SetImmutablePrototype(JSContext* cx
  *
  * NOTE: The JIT may check |shapeOrExpando_| pointer value without ever
  *       inspecting |group_| or the class.
  *
  * NOTE: Some operations can change the contents of an object (including class)
  *       in-place so avoid assuming an object with same pointer has same class
  *       as before.
  *       - JSObject::swap()
- *       - UnboxedPlainObject::convertToNative()
  */
 class JSObject : public js::gc::Cell {
  protected:
   js::GCPtrObjectGroup group_;
   void* shapeOrExpando_;
 
  private:
   friend class js::Shape;
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -13,26 +13,24 @@
 
 #include "gc/Marking.h"
 #include "jit/BaselineIC.h"
 #include "js/CharacterEncoding.h"
 #include "js/Value.h"
 #include "vm/Debugger.h"
 #include "vm/EqualityOperations.h"  // js::SameValue
 #include "vm/TypedArrayObject.h"
-#include "vm/UnboxedObject.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/ArrayObject-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/TypeInference-inl.h"
-#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 using JS::AutoCheckCannotGC;
 using mozilla::ArrayLength;
 using mozilla::CheckedInt;
 using mozilla::DebugOnly;
 using mozilla::PodCopy;
@@ -336,16 +334,17 @@ 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.
@@ -3167,71 +3166,9 @@ bool js::CopyDataPropertiesNative(JSCont
     } else {
       if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE)) {
         return false;
       }
     }
   }
 
   return true;
-}
-
-bool js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
-                                  Handle<UnboxedPlainObject*> from,
-                                  HandlePlainObject excludedItems,
-                                  bool* optimized) {
-  MOZ_ASSERT(
-      !target->isDelegate(),
-      "CopyDataPropertiesNative should only be called during object literal "
-      "construction"
-      "which precludes that |target| is the prototype of any other object");
-
-  *optimized = false;
-
-  // Don't use the fast path for unboxed objects with expandos.
-  if (from->maybeExpando()) {
-    return true;
-  }
-
-  *optimized = true;
-
-  // If |target| contains no own properties, we can directly call
-  // addProperty instead of the slower putProperty.
-  const bool targetHadNoOwnProperties = target->lastProperty()->isEmptyShape();
-
-#ifdef DEBUG
-  RootedObjectGroup fromGroup(cx, from->group());
-#endif
-
-  RootedId key(cx);
-  RootedValue value(cx);
-  const UnboxedLayout& layout = from->layout();
-  for (size_t i = 0; i < layout.properties().length(); i++) {
-    const UnboxedLayout::Property& property = layout.properties()[i];
-    key = NameToId(property.name);
-    MOZ_ASSERT(!JSID_IS_INT(key));
-
-    if (excludedItems && excludedItems->contains(cx, key)) {
-      continue;
-    }
-
-    // Ensure the object stays unboxed.
-    MOZ_ASSERT(from->group() == fromGroup);
-
-    // All unboxed properties are enumerable.
-    value = from->getValue(property);
-
-    if (targetHadNoOwnProperties) {
-      MOZ_ASSERT(!target->contains(cx, key),
-                 "didn't expect to find an existing property");
-
-      if (!AddDataPropertyNonDelegate(cx, target, key, value)) {
-        return false;
-      }
-    } else {
-      if (!NativeDefineDataProperty(cx, target, key, value, JSPROP_ENUMERATE)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
+}
\ No newline at end of file
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -23,17 +23,16 @@
 #include "vm/Shape.h"
 #include "vm/ShapedObject.h"
 #include "vm/StringType.h"
 
 namespace js {
 
 class Shape;
 class TenuringTracer;
-class UnboxedPlainObject;
 
 /*
  * To really poison a set of values, using 'magic' or 'undefined' isn't good
  * enough since often these will just be ignored by buggy code (see bug 629974)
  * in debug builds and crash in release builds. Instead, we use a safe-for-crash
  * pointer.
  */
 static MOZ_ALWAYS_INLINE void Debug_SetValueRangeToCrashOnTouch(Value* beg,
@@ -1670,16 +1669,11 @@ extern void AddPropertyTypesAfterProtoCh
                                              ObjectGroup* oldGroup);
 
 // Specializations of 7.3.23 CopyDataProperties(...) for NativeObjects.
 extern bool CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
                                      HandleNativeObject from,
                                      HandlePlainObject excludedItems,
                                      bool* optimized);
 
-extern bool CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
-                                     Handle<UnboxedPlainObject*> from,
-                                     HandlePlainObject excludedItems,
-                                     bool* optimized);
-
 }  // namespace js
 
 #endif /* vm_NativeObject_h */
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -29,17 +29,16 @@
 
 #include "gc/GC-inl.h"
 #include "gc/Marking-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSFunction-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
-#include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 
 ObjectRealm::ObjectRealm(JS::Zone* zone) : innerViews(zone) {}
 
 ObjectRealm::~ObjectRealm() {
   MOZ_ASSERT(enumerators == iteratorSentinel_.get());
 }
@@ -64,24 +63,16 @@ Realm::~Realm() {
   MOZ_ASSERT(!hasBeenEnteredIgnoringJit());
 
   // Write the code coverage information in a file.
   JSRuntime* rt = runtimeFromMainThread();
   if (rt->lcovOutput().isEnabled()) {
     rt->lcovOutput().writeLCovResult(lcovOutput);
   }
 
-#ifdef DEBUG
-  // Avoid assertion destroying the unboxed layouts list if the embedding
-  // leaked GC things.
-  if (!runtime_->gc.shutdownCollectedEverything()) {
-    objectGroups_.unboxedLayouts.clear();
-  }
-#endif
-
   MOZ_ASSERT(runtime_->numRealms > 0);
   runtime_->numRealms--;
 }
 
 bool ObjectRealm::init(JSContext* cx) {
   NativeIteratorSentinel sentinel(NativeIterator::allocateSentinel(cx));
   if (!sentinel) {
     return false;
--- a/js/src/vm/ReceiverGuard-inl.h
+++ b/js/src/vm/ReceiverGuard-inl.h
@@ -7,47 +7,36 @@
 #ifndef vm_ReceiverGuard_inl_h
 #define vm_ReceiverGuard_inl_h
 
 #include "vm/ReceiverGuard.h"
 
 #include "builtin/TypedObject.h"
 #include "vm/JSObject.h"
 #include "vm/ShapedObject.h"
-#include "vm/UnboxedObject.h"
 
 namespace js {
 
 MOZ_ALWAYS_INLINE
 ReceiverGuard::ReceiverGuard(JSObject* obj) : group(nullptr), shape(nullptr) {
   if (!obj->isNative()) {
-    if (obj->is<UnboxedPlainObject>()) {
-      group = obj->group();
-      if (UnboxedExpandoObject* expando =
-              obj->as<UnboxedPlainObject>().maybeExpando()) {
-        shape = expando->lastProperty();
-      }
-      return;
-    }
     if (obj->is<TypedObject>()) {
       group = obj->group();
       return;
     }
   }
   shape = obj->as<ShapedObject>().shape();
 }
 
 MOZ_ALWAYS_INLINE
 ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
     : group(group), shape(shape) {
   if (group) {
     const Class* clasp = group->clasp();
-    if (clasp == &UnboxedPlainObject::class_) {
-      // Keep both group and shape.
-    } else if (IsTypedObjectClass(clasp)) {
+    if (IsTypedObjectClass(clasp)) {
       this->shape = nullptr;
     } else {
       this->group = nullptr;
     }
   }
 }
 
 }  // namespace js
--- a/js/src/vm/ReceiverGuard.cpp
+++ b/js/src/vm/ReceiverGuard.cpp
@@ -2,17 +2,16 @@
  * 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/ReceiverGuard.h"
 
 #include "builtin/TypedObject.h"
-#include "vm/UnboxedObject.h"
 
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 
 void HeapReceiverGuard::trace(JSTracer* trc) {
   TraceNullableEdge(trc, &shape_, "receiver_guard_shape");
   TraceNullableEdge(trc, &group_, "receiver_guard_group");
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2336,32 +2336,16 @@ static bool intrinsic_CopyDataProperties
     }
 
     if (optimized) {
       args.rval().setNull();
       return true;
     }
   }
 
-  if (from->is<UnboxedPlainObject>() && target->is<PlainObject>() &&
-      (!excludedItems || excludedItems->is<PlainObject>())) {
-    bool optimized;
-    if (!CopyDataPropertiesNative(
-            cx, target.as<PlainObject>(), from.as<UnboxedPlainObject>(),
-            (excludedItems ? excludedItems.as<PlainObject>() : nullptr),
-            &optimized)) {
-      return false;
-    }
-
-    if (optimized) {
-      args.rval().setNull();
-      return true;
-    }
-  }
-
   return GetOwnPropertyKeys(
       cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, args.rval());
 }
 
 // The self-hosting global isn't initialized with the normal set of builtins.
 // Instead, individual C++-implemented functions that're required by
 // self-hosted code are defined as global functions. Accessing these
 // functions via a content compartment's builtins would be unsafe, because