Bug 1505574 - Remove initial chunk of Unboxed Objects machinery r=iain
authorMatthew Gaudet <mgaudet@mozilla.com>
Fri, 22 Mar 2019 16:00:12 +0000
changeset 465708 4e8e9a0b6c694ae85b6aad32725f4392b4eee80e
parent 465707 0330a759e3997109d66bc8bc315d244a1c06e8e3
child 465709 ef947b198f2c861b13b13b66f5b4095c43b4acb8
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 initial chunk of Unboxed Objects machinery r=iain Differential Revision: https://phabricator.services.mozilla.com/D24037
js/src/jit/BaselineInspector.cpp
js/src/jit/BaselineInspector.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/vm/JSObject.h
js/src/vm/ObjectGroup.h
js/src/vm/TypeInference.cpp
js/src/vm/UnboxedObject.cpp
js/src/vm/UnboxedObject.h
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -55,26 +55,17 @@ static bool VectorAppendNoDuplicate(S& l
     if (list[i] == value) {
       return true;
     }
   }
   return list.append(value);
 }
 
 static bool AddReceiver(
-    const ReceiverGuard& receiver, BaselineInspector::ReceiverVector& receivers,
-    BaselineInspector::ObjectGroupVector& convertUnboxedGroups) {
-  if (receiver.group) {
-    AutoSweepObjectGroup sweep(receiver.group);
-    if (auto* layout = receiver.group->maybeUnboxedLayout(sweep)) {
-      if (layout->nativeGroup()) {
-        return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
-      }
-    }
-  }
+    const ReceiverGuard& receiver, BaselineInspector::ReceiverVector& receivers) {
   return VectorAppendNoDuplicate(receivers, receiver);
 }
 
 static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub,
                                                 ReceiverGuard* receiver) {
   // We match either:
   //
   //   GuardIsObject 0
@@ -250,25 +241,21 @@ ICEntry* BaselineInspector::maybeICEntry
   }
 
   MOZ_ASSERT(ent->isForOp());
   prevLookedUpEntry = ent;
   return ent;
 }
 
 bool BaselineInspector::maybeInfoForPropertyOp(
-    jsbytecode* pc, ReceiverVector& receivers,
-    ObjectGroupVector& convertUnboxedGroups) {
+    jsbytecode* pc, ReceiverVector& receivers) {
   // Return a list of the receivers seen by the baseline IC for the current
   // op. Empty lists indicate no receivers are known, or there was an
-  // uncacheable access. convertUnboxedGroups is used for unboxed object
-  // groups which have been seen, but have had instances converted to native
-  // objects and should be eagerly converted by Ion.
+  // uncacheable access. 
   MOZ_ASSERT(receivers.empty());
-  MOZ_ASSERT(convertUnboxedGroups.empty());
 
   if (!hasICScript()) {
     return true;
   }
 
   MOZ_ASSERT(isValidPC(pc));
   const ICEntry& entry = icEntryFromPC(pc);
 
@@ -291,17 +278,17 @@ bool BaselineInspector::maybeInfoForProp
         receivers.clear();
         return true;
       }
     } else {
       receivers.clear();
       return true;
     }
 
-    if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
+    if (!AddReceiver(receiver, receivers)) {
       return false;
     }
 
     stub = stub->next();
   }
 
   if (stub->toFallbackStub()->state().hasFailures()) {
     receivers.clear();
@@ -1084,17 +1071,16 @@ static bool MatchCacheIRReceiverGuard(Ca
   receiver->shape = stubInfo->getStubField<Shape*>(stub, reader.stubOffset());
   return true;
 }
 
 static bool AddCacheIRGlobalGetter(
     ICCacheIR_Monitored* stub, bool innerized, JSObject** holder_,
     Shape** holderShape_, JSFunction** commonGetter, Shape** globalShape_,
     bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers,
-    BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
     JSScript* script) {
   // We are matching on the IR generated by tryAttachGlobalNameGetter:
   //
   //   GuardShape objId
   //   globalId = LoadEnclosingEnvironment objId
   //   GuardShape globalId
   //   <holderId = LoadObject <holder>>
   //   <GuardShape holderId>
@@ -1150,17 +1136,17 @@ static bool AddCacheIRGlobalGetter(
   }
   size_t offset = reader.stubOffset();
   JSFunction* getter = &stub->stubInfo()
                             ->getStubField<JSObject*>(stub, offset)
                             ->as<JSFunction>();
 
   ReceiverGuard receiver;
   receiver.shape = globalLexicalShape;
-  if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
+  if (!AddReceiver(receiver, receivers)) {
     return false;
   }
 
   if (!*commonGetter) {
     *holder_ = holder;
     *holderShape_ = holderShape;
     *commonGetter = getter;
     *globalShape_ = globalShape;
@@ -1211,17 +1197,16 @@ static bool GuardSpecificAtomOrSymbol(Ca
 
   return true;
 }
 
 static bool AddCacheIRGetPropFunction(
     ICCacheIR_Monitored* stub, jsid id, bool innerized, JSObject** holder,
     Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
     bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers,
-    BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
     JSScript* script) {
   // We match either an own getter:
   //
   //   GuardIsObject objId
   //   [..Id Guard..]
   //   [..WindowProxy innerization..]
   //   <GuardReceiver objId>
   //   Call(Scripted|Native)GetterResult objId
@@ -1250,17 +1235,17 @@ static bool AddCacheIRGetPropFunction(
   //   GuardSpecific(Atom|Symbol) keyId, <atom|symbol>
 
   CacheIRReader reader(stub->stubInfo());
 
   ObjOperandId objId = ObjOperandId(0);
   if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
     return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape,
                                   commonGetter, globalShape, isOwnProperty,
-                                  receivers, convertUnboxedGroups, script);
+                                  receivers, script);
   }
 
   if (!JSID_IS_EMPTY(id)) {
     ValOperandId keyId = ValOperandId(1);
     if (!GuardSpecificAtomOrSymbol(reader, stub, stub->stubInfo(), keyId, id)) {
       return false;
     }
   }
@@ -1353,55 +1338,52 @@ static bool AddCacheIRGetPropFunction(
 
   MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter);
 
   if (obj->as<NativeObject>().lastProperty() != objShape) {
     // Skip this stub as the shape is no longer correct.
     return true;
   }
 
-  if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
+  if (!AddReceiver(receiver, receivers)) {
     return false;
   }
 
   *holder = obj;
   *holderShape = objShape;
   *commonGetter = getter;
   *isOwnProperty = false;
   return true;
 }
 
 bool BaselineInspector::commonGetPropFunction(
     jsbytecode* pc, jsid id, bool innerized, JSObject** holder,
     Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
-    bool* isOwnProperty, ReceiverVector& receivers,
-    ObjectGroupVector& convertUnboxedGroups) {
+    bool* isOwnProperty, ReceiverVector& receivers) {
   if (!hasICScript()) {
     return false;
   }
 
   MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || JSOp(*pc) == JSOP_GETGNAME);
   MOZ_ASSERT(receivers.empty());
-  MOZ_ASSERT(convertUnboxedGroups.empty());
 
   // Only GetElem operations need to guard against a specific property id.
   if (!IsGetElemPC(pc)) {
     id = JSID_EMPTY;
   }
 
   *globalShape = nullptr;
   *commonGetter = nullptr;
   const ICEntry& entry = icEntryFromPC(pc);
 
   for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     if (stub->isCacheIR_Monitored()) {
       if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), id, innerized,
                                      holder, holderShape, commonGetter,
-                                     globalShape, isOwnProperty, receivers,
-                                     convertUnboxedGroups, script)) {
+                                     globalShape, isOwnProperty, receivers, script)) {
         return false;
       }
     } else if (stub->isFallback()) {
       // If we have an unoptimizable access, don't try to optimize.
       if (stub->toFallbackStub()->state().hasFailures()) {
         return false;
       }
     } else {
@@ -1409,18 +1391,17 @@ bool BaselineInspector::commonGetPropFun
     }
   }
 
   if (!*commonGetter) {
     return false;
   }
 
   MOZ_ASSERT(*isOwnProperty == !*holder);
-  MOZ_ASSERT(*isOwnProperty ==
-             (receivers.empty() && convertUnboxedGroups.empty()));
+  MOZ_ASSERT(*isOwnProperty == receivers.empty());
   return true;
 }
 
 static JSFunction* GetMegamorphicGetterSetterFunction(
     ICStub* stub, const CacheIRStubInfo* stubInfo, jsid id, bool isGetter) {
   // We match:
   //
   //   GuardIsObject objId
@@ -1516,18 +1497,17 @@ bool BaselineInspector::megamorphicGette
   }
 
   return true;
 }
 
 static bool AddCacheIRSetPropFunction(
     ICCacheIR_Updated* stub, JSObject** holder, Shape** holderShape,
     JSFunction** commonSetter, bool* isOwnProperty,
-    BaselineInspector::ReceiverVector& receivers,
-    BaselineInspector::ObjectGroupVector& convertUnboxedGroups) {
+    BaselineInspector::ReceiverVector& receivers) {
   // We match either an own setter:
   //
   //   GuardIsObject objId
   //   <GuardReceiver objId>
   //   Call(Scripted|Native)Setter objId
   //
   // Or a setter on the prototype:
   //
@@ -1603,49 +1583,47 @@ static bool AddCacheIRSetPropFunction(
 
   MOZ_ASSERT_IF(*commonSetter, *commonSetter == setter);
 
   if (obj->as<NativeObject>().lastProperty() != objShape) {
     // Skip this stub as the shape is no longer correct.
     return true;
   }
 
-  if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
+  if (!AddReceiver(receiver, receivers)) {
     return false;
   }
 
   *holder = obj;
   *holderShape = objShape;
   *commonSetter = setter;
   *isOwnProperty = false;
   return true;
 }
 
 bool BaselineInspector::commonSetPropFunction(
     jsbytecode* pc, JSObject** holder, Shape** holderShape,
-    JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers,
-    ObjectGroupVector& convertUnboxedGroups) {
+    JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers) {
   if (!hasICScript()) {
     return false;
   }
 
   MOZ_ASSERT(IsSetPropPC(pc) || JSOp(*pc) == JSOP_INITGLEXICAL ||
              JSOp(*pc) == JSOP_INITPROP || JSOp(*pc) == JSOP_INITLOCKEDPROP ||
              JSOp(*pc) == JSOP_INITHIDDENPROP);
   MOZ_ASSERT(receivers.empty());
-  MOZ_ASSERT(convertUnboxedGroups.empty());
 
   *commonSetter = nullptr;
   const ICEntry& entry = icEntryFromPC(pc);
 
   for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     if (stub->isCacheIR_Updated()) {
       if (!AddCacheIRSetPropFunction(stub->toCacheIR_Updated(), holder,
                                      holderShape, commonSetter, isOwnProperty,
-                                     receivers, convertUnboxedGroups)) {
+                                     receivers)) {
         return false;
       }
     } else if (!stub->isFallback() ||
                stub->toFallbackStub()->state().hasFailures()) {
       // We have an unoptimizable access, so don't try to optimize.
       return false;
     }
   }
@@ -1711,23 +1689,21 @@ static bool GetCacheIRReceiverForProtoRe
     return false;
   }
 
   *holderResult = holder;
   return true;
 }
 
 bool BaselineInspector::maybeInfoForProtoReadSlot(
-    jsbytecode* pc, ReceiverVector& receivers,
-    ObjectGroupVector& convertUnboxedGroups, JSObject** holder) {
+    jsbytecode* pc, ReceiverVector& receivers, JSObject** holder) {
   // This is like maybeInfoForPropertyOp, but for when the property exists on
   // the prototype.
 
   MOZ_ASSERT(receivers.empty());
-  MOZ_ASSERT(convertUnboxedGroups.empty());
   MOZ_ASSERT(!*holder);
 
   if (!hasICScript()) {
     return true;
   }
 
   MOZ_ASSERT(isValidPC(pc));
   const ICEntry& entry = icEntryFromPC(pc);
@@ -1741,17 +1717,17 @@ bool BaselineInspector::maybeInfoForProt
         receivers.clear();
         return true;
       }
     } else {
       receivers.clear();
       return true;
     }
 
-    if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
+    if (!AddReceiver(receiver, receivers)) {
       return false;
     }
 
     stub = stub->next();
   }
 
   if (stub->toFallbackStub()->state().hasFailures()) {
     receivers.clear();
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -73,22 +73,20 @@ class BaselineInspector {
   ICStub* monomorphicStub(jsbytecode* pc);
   MOZ_MUST_USE bool dimorphicStub(jsbytecode* pc, ICStub** pfirst,
                                   ICStub** psecond);
 
  public:
   typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
   typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
   MOZ_MUST_USE bool maybeInfoForPropertyOp(
-      jsbytecode* pc, ReceiverVector& receivers,
-      ObjectGroupVector& convertUnboxedGroups);
+      jsbytecode* pc, ReceiverVector& receivers);
 
   MOZ_MUST_USE bool maybeInfoForProtoReadSlot(
-      jsbytecode* pc, ReceiverVector& receivers,
-      ObjectGroupVector& convertUnboxedGroups, JSObject** holder);
+      jsbytecode* pc, ReceiverVector& receivers, JSObject** holder);
 
   SetElemICInspector setElemICInspector(jsbytecode* pc) {
     return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
   }
 
   MIRType expectedResultType(jsbytecode* pc);
   MCompare::CompareType expectedCompareType(jsbytecode* pc);
   MIRType expectedBinaryArithSpecialization(jsbytecode* pc);
@@ -118,26 +116,24 @@ class BaselineInspector {
 
   // If |innerized| is true, we're doing a GETPROP on a WindowProxy and
   // IonBuilder unwrapped/innerized it to do the lookup on the Window (the
   // global object) instead. In this case we should only look for Baseline
   // stubs that performed the same optimization.
   MOZ_MUST_USE bool commonGetPropFunction(
       jsbytecode* pc, jsid id, bool innerized, JSObject** holder,
       Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
-      bool* isOwnProperty, ReceiverVector& receivers,
-      ObjectGroupVector& convertUnboxedGroups);
+      bool* isOwnProperty, ReceiverVector& receivers);
 
   MOZ_MUST_USE bool megamorphicGetterSetterFunction(
       jsbytecode* pc, jsid id, bool isGetter, JSFunction** getterOrSetter);
 
   MOZ_MUST_USE bool commonSetPropFunction(
       jsbytecode* pc, JSObject** holder, Shape** holderShape,
-      JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers,
-      ObjectGroupVector& convertUnboxedGroups);
+      JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers);
 
   MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape,
                                    uint32_t* slot, JSObject** prototypeObject);
 };
 
 }  // namespace jit
 }  // namespace js
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8454,19 +8454,16 @@ AbortReasonOr<Ok> IonBuilder::jsop_getel
     if (script()->argumentsHasVarBinding()) {
       trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
       return abort(AbortReason::Disable,
                    "Type is not definitely lazy arguments.");
     }
   }
 
   obj = maybeUnboxForPropertyAccess(obj);
-  if (obj->type() == MIRType::Object) {
-    obj = convertUnboxedObjects(obj);
-  }
 
   if (!forceInlineCaches()) {
     // Note: no trackOptimizationAttempt call is needed, getElemTryGetProp
     // will call it.
     MOZ_TRY(getElemTryGetProp(&emitted, obj, index));
     if (emitted) {
       return Ok();
     }
@@ -9530,17 +9527,17 @@ AbortReasonOr<Ok> IonBuilder::jsop_getel
 }
 
 AbortReasonOr<Ok> IonBuilder::jsop_setelem() {
   bool emitted = false;
   startTrackingOptimizations();
 
   MDefinition* value = current->pop();
   MDefinition* index = current->pop();
-  MDefinition* object = convertUnboxedObjects(current->pop());
+  MDefinition* object = current->pop();
 
   trackTypeInfo(TrackedTypeSite::Receiver, object->type(),
                 object->resultTypeSet());
   trackTypeInfo(TrackedTypeSite::Index, index->type(), index->resultTypeSet());
   trackTypeInfo(TrackedTypeSite::Value, value->type(), value->resultTypeSet());
 
   if (shouldAbortOnPreliminaryGroups(object)) {
     MInstruction* ins =
@@ -10949,19 +10946,16 @@ AbortReasonOr<Ok> IonBuilder::jsop_getpr
     trackOptimizationAttempt(TrackedStrategy::GetProp_ArgumentsCallee);
     MOZ_TRY(getPropTryArgumentsCallee(&emitted, obj, name));
     if (emitted) {
       return Ok();
     }
   }
 
   obj = maybeUnboxForPropertyAccess(obj);
-  if (obj->type() == MIRType::Object) {
-    obj = convertUnboxedObjects(obj);
-  }
 
   BarrierKind barrier = PropertyReadNeedsTypeBarrier(
       analysisContext, alloc(), constraints(), obj, name, types);
 
   // Try to optimize to a specific constant.
   trackOptimizationAttempt(TrackedStrategy::GetProp_InferredConstant);
   if (barrier == BarrierKind::NoBarrier) {
     MOZ_TRY(getPropTryInferredConstant(&emitted, obj, name, types));
@@ -11396,60 +11390,16 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
   if (!byteOffset.add(fieldOffset)) {
     return abort(AbortReason::Disable, "Overflow of field offsets.");
   }
 
   return pushDerivedTypedObject(emitted, typedObj, byteOffset, fieldPrediction,
                                 fieldTypeObj);
 }
 
-MDefinition* IonBuilder::convertUnboxedObjects(MDefinition* obj) {
-  // If obj might be in any particular unboxed group which should be
-  // converted to a native representation, perform that conversion. This does
-  // not guarantee the object will not have such a group afterwards, if the
-  // object's possible groups are not precisely known.
-  TemporaryTypeSet* types = obj->resultTypeSet();
-  if (!types || types->unknownObject() || !types->objectOrSentinel()) {
-    return obj;
-  }
-
-  BaselineInspector::ObjectGroupVector list(alloc());
-  for (size_t i = 0; i < types->getObjectCount(); i++) {
-    TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i);
-    if (!key || !key->isGroup()) {
-      continue;
-    }
-
-    AutoSweepObjectGroup sweep(key->group());
-    if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout(sweep)) {
-      AutoEnterOOMUnsafeRegion oomUnsafe;
-      if (layout->nativeGroup() && !list.append(key->group())) {
-        oomUnsafe.crash("IonBuilder::convertUnboxedObjects");
-      }
-    }
-  }
-
-  return convertUnboxedObjects(obj, list);
-}
-
-MDefinition* IonBuilder::convertUnboxedObjects(
-    MDefinition* obj, const BaselineInspector::ObjectGroupVector& list) {
-  for (size_t i = 0; i < list.length(); i++) {
-    ObjectGroup* group = list[i];
-    if (TemporaryTypeSet* types = obj->resultTypeSet()) {
-      if (!types->hasType(TypeSet::ObjectType(group))) {
-        continue;
-      }
-    }
-    obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group);
-    current->add(obj->toInstruction());
-  }
-  return obj;
-}
-
 AbortReasonOr<Ok> IonBuilder::getPropTryDefiniteSlot(bool* emitted,
                                                      MDefinition* obj,
                                                      PropertyName* name,
                                                      BarrierKind barrier,
                                                      TemporaryTypeSet* types) {
   MOZ_ASSERT(*emitted == false);
 
   uint32_t nfixed;
@@ -11632,23 +11582,20 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
   trackOptimizationSuccess();
   *emitted = true;
   return Ok();
 }
 
 MDefinition* IonBuilder::addShapeGuardsForGetterSetter(
     MDefinition* obj, JSObject* holder, Shape* holderShape,
     const BaselineInspector::ReceiverVector& receivers,
-    const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
     bool isOwnProperty) {
   MOZ_ASSERT(isOwnProperty == !holder);
   MOZ_ASSERT(holderShape);
 
-  obj = convertUnboxedObjects(obj, convertUnboxedGroups);
-
   if (isOwnProperty) {
     MOZ_ASSERT(receivers.empty());
     return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
   }
 
   MDefinition* holderDef = constant(ObjectValue(*holder));
   addShapeGuard(holderDef, holderShape, Bailout_ShapeGuard);
 
@@ -11668,34 +11615,33 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
   MDefinition* globalGuard = nullptr;
 
   {
     Shape* lastProperty = nullptr;
     Shape* globalShape = nullptr;
     JSObject* foundProto = nullptr;
     bool isOwnProperty = false;
     BaselineInspector::ReceiverVector receivers(alloc());
-    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
     if (inspector->commonGetPropFunction(
             pc, id, innerized, &foundProto, &lastProperty, &commonGetter,
-            &globalShape, &isOwnProperty, receivers, convertUnboxedGroups)) {
+            &globalShape, &isOwnProperty, receivers)) {
       bool canUseTIForGetter = false;
       if (!isOwnProperty) {
         // If it's not an own property, try to use TI to avoid shape guards.
         // For own properties we use the path below.
         MOZ_TRY_VAR(canUseTIForGetter,
                     testCommonGetterSetter(objTypes, id,
                                            /* isGetter = */ true, commonGetter,
                                            &guard, globalShape, &globalGuard));
       }
       if (!canUseTIForGetter) {
         // If it's an own property or type information is bad, we can still
         // optimize the getter if we shape guard.
         obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
-                                            receivers, convertUnboxedGroups,
+                                            receivers,
                                             isOwnProperty);
         if (!obj) {
           return abort(AbortReason::Alloc);
         }
       }
     } else if (inspector->megamorphicGetterSetterFunction(
                    pc, id, /* isGetter = */ true, &commonGetter)) {
       // Try to use TI to guard on this getter.
@@ -11885,27 +11831,24 @@ static Shape* PropertyShapesHaveSameSlot
 AbortReasonOr<Ok> IonBuilder::getPropTryInlineAccess(bool* emitted,
                                                      MDefinition* obj,
                                                      PropertyName* name,
                                                      BarrierKind barrier,
                                                      TemporaryTypeSet* types) {
   MOZ_ASSERT(*emitted == false);
 
   BaselineInspector::ReceiverVector receivers(alloc());
-  BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
-  if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) {
+  if (!inspector->maybeInfoForPropertyOp(pc, receivers)) {
     return abort(AbortReason::Alloc);
   }
 
   if (!canInlinePropertyOpShapes(receivers)) {
     return Ok();
   }
 
-  obj = convertUnboxedObjects(obj, convertUnboxedGroups);
-
   MIRType rvalType = types->getKnownMIRType();
   if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) {
     rvalType = MIRType::Value;
   }
 
   if (receivers.length() == 1) {
     if (!receivers[0].group) {
       // Monomorphic load from a native object.
@@ -12015,19 +11958,18 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
 }
 
 AbortReasonOr<Ok> IonBuilder::getPropTryInlineProtoAccess(
     bool* emitted, MDefinition* obj, PropertyName* name,
     TemporaryTypeSet* types) {
   MOZ_ASSERT(*emitted == false);
 
   BaselineInspector::ReceiverVector receivers(alloc());
-  BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
   JSObject* holder = nullptr;
-  if (!inspector->maybeInfoForProtoReadSlot(pc, receivers, convertUnboxedGroups,
+  if (!inspector->maybeInfoForProtoReadSlot(pc, receivers,
                                             &holder)) {
     return abort(AbortReason::Alloc);
   }
 
   if (!canInlinePropertyOpShapes(receivers)) {
     return Ok();
   }
 
@@ -12039,17 +11981,16 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
               PropertyReadOnPrototypeNeedsTypeBarrier(this, obj, name, types));
 
   MIRType rvalType = types->getKnownMIRType();
   if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) {
     rvalType = MIRType::Value;
   }
 
   // Guard on the receiver shapes/groups.
-  obj = convertUnboxedObjects(obj, convertUnboxedGroups);
   obj = addGuardReceiverPolymorphic(obj, receivers);
   if (!obj) {
     return abort(AbortReason::Alloc);
   }
 
   // Guard on the holder's shape.
   MInstruction* holderDef = constant(ObjectValue(*holder));
   Shape* holderShape = holder->as<NativeObject>().shape();
@@ -12252,17 +12193,17 @@ AbortReasonOr<Ok> IonBuilder::getPropTry
   MOZ_TRY(getPropAddCache(inner, name, barrier, types));
 
   *emitted = true;
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::jsop_setprop(PropertyName* name) {
   MDefinition* value = current->pop();
-  MDefinition* obj = convertUnboxedObjects(current->pop());
+  MDefinition* obj = current->pop();
 
   bool emitted = false;
   startTrackingOptimizations();
   trackTypeInfo(TrackedTypeSite::Receiver, obj->type(), obj->resultTypeSet());
   trackTypeInfo(TrackedTypeSite::Value, value->type(), value->resultTypeSet());
 
   // Always use a call if we are doing the definite properties analysis and
   // not actually emitting code, to simplify later analysis.
@@ -12339,35 +12280,33 @@ AbortReasonOr<Ok> IonBuilder::setPropTry
   JSFunction* commonSetter = nullptr;
   MDefinition* guard = nullptr;
 
   {
     Shape* lastProperty = nullptr;
     JSObject* foundProto = nullptr;
     bool isOwnProperty;
     BaselineInspector::ReceiverVector receivers(alloc());
-    BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
     if (inspector->commonSetPropFunction(pc, &foundProto, &lastProperty,
                                          &commonSetter, &isOwnProperty,
-                                         receivers, convertUnboxedGroups)) {
+                                         receivers)) {
       bool canUseTIForSetter = false;
       if (!isOwnProperty) {
         // If it's not an own property, try to use TI to avoid shape guards.
         // For own properties we use the path below.
         MOZ_TRY_VAR(canUseTIForSetter,
                     testCommonGetterSetter(objTypes, NameToId(name),
                                            /* isGetter = */ false, commonSetter,
                                            &guard));
       }
       if (!canUseTIForSetter) {
         // If it's an own property or type information is bad, we can still
         // optimize the setter if we shape guard.
         obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
-                                            receivers, convertUnboxedGroups,
-                                            isOwnProperty);
+                                            receivers, isOwnProperty);
         if (!obj) {
           return abort(AbortReason::Alloc);
         }
       }
     } else if (inspector->megamorphicGetterSetterFunction(
                    pc, NameToId(name), /* isGetter = */ false, &commonSetter)) {
       // Try to use TI to guard on this setter.
       bool canUseTIForSetter = false;
@@ -12745,27 +12684,24 @@ AbortReasonOr<Ok> IonBuilder::setPropTry
   MOZ_ASSERT(*emitted == false);
 
   if (barrier) {
     trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
     return Ok();
   }
 
   BaselineInspector::ReceiverVector receivers(alloc());
-  BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
-  if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) {
+  if (!inspector->maybeInfoForPropertyOp(pc, receivers)) {
     return abort(AbortReason::Alloc);
   }
 
   if (!canInlinePropertyOpShapes(receivers)) {
     return Ok();
   }
 
-  obj = convertUnboxedObjects(obj, convertUnboxedGroups);
-
   if (receivers.length() == 1) {
     if (!receivers[0].group) {
       // Monomorphic store to a native object.
       spew("Inlining monomorphic native SETPROP");
 
       obj = addShapeGuard(obj, receivers[0].shape, Bailout_ShapeGuard);
 
       Shape* shape = receivers[0].shape->searchLinear(NameToId(name));
@@ -13401,17 +13337,17 @@ AbortReasonOr<Ok> IonBuilder::jsop_setal
     store = MStoreSlot::NewBarriered(alloc(), slots, slot, rval);
   }
 
   current->add(store);
   return resumeAfter(store);
 }
 
 AbortReasonOr<Ok> IonBuilder::jsop_in() {
-  MDefinition* obj = convertUnboxedObjects(current->pop());
+  MDefinition* obj = current->pop();
   MDefinition* id = current->pop();
 
   if (!forceInlineCaches()) {
     bool emitted = false;
 
     MOZ_TRY(inTryDense(&emitted, obj, id));
     if (emitted) {
       return Ok();
@@ -13557,17 +13493,17 @@ AbortReasonOr<Ok> IonBuilder::hasTryDefi
 
   pushConstant(BooleanValue(true));
   obj->setImplicitlyUsedUnchecked();
   id->setImplicitlyUsedUnchecked();
   return Ok();
 }
 
 AbortReasonOr<Ok> IonBuilder::jsop_hasown() {
-  MDefinition* obj = convertUnboxedObjects(current->pop());
+  MDefinition* obj = current->pop();
   MDefinition* id = current->pop();
 
   if (!forceInlineCaches()) {
     bool emitted = false;
 
     MOZ_TRY(hasTryNotDefined(&emitted, obj, id, /* ownProperty = */ true));
     if (emitted) {
       return Ok();
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -913,17 +913,16 @@ class IonBuilder : public MIRGenerator,
       JSFunction* getterOrSetter, MDefinition** guard,
       Shape* globalShape = nullptr, MDefinition** globalGuard = nullptr);
   AbortReasonOr<bool> testShouldDOMCall(TypeSet* inTypes, JSFunction* func,
                                         JSJitInfo::OpType opType);
 
   MDefinition* addShapeGuardsForGetterSetter(
       MDefinition* obj, JSObject* holder, Shape* holderShape,
       const BaselineInspector::ReceiverVector& receivers,
-      const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
       bool isOwnProperty);
 
   AbortReasonOr<Ok> annotateGetPropertyCache(MDefinition* obj,
                                              PropertyName* name,
                                              MGetPropertyCache* getPropCache,
                                              TemporaryTypeSet* objTypes,
                                              TemporaryTypeSet* pushedTypes);
 
@@ -933,19 +932,17 @@ class IonBuilder : public MIRGenerator,
 
   JSObject* testSingletonProperty(JSObject* obj, jsid id);
   JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
 
   AbortReasonOr<bool> testNotDefinedProperty(MDefinition* obj, jsid id,
                                              bool ownProperty = false);
 
   uint32_t getDefiniteSlot(TemporaryTypeSet* types, jsid id, uint32_t* pnfixed);
-  MDefinition* convertUnboxedObjects(MDefinition* obj);
-  MDefinition* convertUnboxedObjects(
-      MDefinition* obj, const BaselineInspector::ObjectGroupVector& list);
+
   uint32_t getUnboxedOffset(TemporaryTypeSet* types, jsid id,
                             JSValueType* punboxedType);
   MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset,
                                     JSValueType unboxedType,
                                     BarrierKind barrier,
                                     TemporaryTypeSet* types);
   MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
                                  MDefinition* scaledOffset,
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -906,17 +906,17 @@ IonBuilder::InliningResult IonBuilder::i
   // non-extensible arrays (non-extensible objects always have a capacity
   // equal to their initialized length). We check this here because there's
   // no non-extensible ObjectElements flag so we would need an extra guard
   // on the BaseShape flags.
   ObjectGroupFlags unhandledFlags =
       OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW |
       OBJECT_FLAG_ITERATED | OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS;
 
-  MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
+  MDefinition* obj = callInfo.thisArg();
   TemporaryTypeSet* thisTypes = obj->resultTypeSet();
   if (!thisTypes) {
     return InliningStatus_NotInlined;
   }
   const Class* clasp = thisTypes->getKnownClass(constraints());
   if (clasp != &ArrayObject::class_) {
     return InliningStatus_NotInlined;
   }
@@ -1013,17 +1013,17 @@ IonBuilder::InliningResult IonBuilder::i
   }
 
   // XXX bug 1493903.
   if (callInfo.argc() != 1) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     return InliningStatus_NotInlined;
   }
 
-  MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
+  MDefinition* obj = callInfo.thisArg();
   for (uint32_t i = 0; i < callInfo.argc(); i++) {
     MDefinition* value = callInfo.getArg(i);
     if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj,
                                       nullptr, &value,
                                       /* canModify = */ false)) {
       trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
       return InliningStatus_NotInlined;
     }
@@ -1144,17 +1144,17 @@ IonBuilder::InliningResult IonBuilder::i
 }
 
 IonBuilder::InliningResult IonBuilder::inlineArraySlice(CallInfo& callInfo) {
   if (callInfo.constructing()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     return InliningStatus_NotInlined;
   }
 
-  MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
+  MDefinition* obj = callInfo.thisArg();
 
   // Ensure |this| and result are objects.
   if (getInlineReturnType() != MIRType::Object) {
     return InliningStatus_NotInlined;
   }
   if (obj->type() != MIRType::Object) {
     return InliningStatus_NotInlined;
   }
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -79,19 +79,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()
- *
- * NOTE: UnboxedObjects may change class without changing |group_|.
- *       - js::TryConvertToUnboxedLayout
  */
 class JSObject : public js::gc::Cell {
  protected:
   js::GCPtrObjectGroup group_;
   void* shapeOrExpando_;
 
  private:
   friend class js::Shape;
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -190,16 +190,18 @@ class ObjectGroup : public gc::TenuredCe
     clasp_ = clasp;
   }
 
   // Certain optimizations may mutate the class of an ObjectGroup - and thus
   // all objects in it - after it is created. If true, the JIT must not
   // assume objects of a previously seen group have the same class as before.
   //
   // See: TryConvertToUnboxedLayout
+  //
+  // MG:Unboxed: Verify above comment still holds
   bool hasUncacheableClass() const { return clasp_->isNative(); }
 
   bool hasDynamicPrototype() const { return proto_.isDynamic(); }
 
   const GCPtr<TaggedProto>& proto() const { return proto_; }
 
   GCPtr<TaggedProto>& proto() { return proto_; }
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3850,18 +3850,16 @@ void PreliminaryObjectArrayWithTemplate:
       return;
     }
 
     if (CommonPrefix(obj->lastProperty(), shape()) != shape()) {
       return;
     }
   }
 
-  TryConvertToUnboxedLayout(cx, enter, shape(), group,
-                            preliminaryObjects.get());
   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
@@ -4151,22 +4149,16 @@ bool TypeNewScript::maybeAnalyze(JSConte
     if (!initializerList) {
       ReportOutOfMemory(cx);
       return false;
     }
     PodCopy(initializerList, initializerVector.begin(),
             initializerVector.length());
   }
 
-  // Try to use an unboxed representation for the group.
-  if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(),
-                                 group, preliminaryObjects)) {
-    return false;
-  }
-
   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();
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -1211,363 +1211,23 @@ const Class UnboxedPlainObject::class_ =
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     &UnboxedPlainObjectObjectOps};
 
 /////////////////////////////////////////////////////////////////////
 // API
 /////////////////////////////////////////////////////////////////////
 
-static bool UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) {
-  if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32) {
-    return true;
-  }
-  if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL) {
-    return true;
-  }
-  return false;
-}
-
-static bool CombineUnboxedTypes(const Value& value, JSValueType* existing) {
-  JSValueType type =
-      value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType();
-
-  if (*existing == JSVAL_TYPE_MAGIC || *existing == type ||
-      UnboxedTypeIncludes(type, *existing)) {
-    *existing = type;
-    return true;
-  }
-  if (UnboxedTypeIncludes(*existing, type)) {
-    return true;
-  }
-  return false;
-}
-
-// Return whether the property names and types in layout are a subset of the
-// specified vector.
-static bool PropertiesAreSuperset(
-    const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout) {
-  for (size_t i = 0; i < layout->properties().length(); i++) {
-    const UnboxedLayout::Property& layoutProperty = layout->properties()[i];
-    bool found = false;
-    for (size_t j = 0; j < properties.length(); j++) {
-      if (layoutProperty.name == properties[j].name) {
-        found = (layoutProperty.type == properties[j].type);
-        break;
-      }
-    }
-    if (!found) {
-      return false;
-    }
-  }
-  return true;
-}
-
-static bool CombinePlainObjectProperties(
-    PlainObject* obj, Shape* templateShape,
-    UnboxedLayout::PropertyVector& properties) {
-  // All preliminary objects must have been created with enough space to
-  // fill in their unboxed data inline. This is ensured either by using
-  // the largest allocation kind (which limits the maximum size of an
-  // unboxed object), or by using an allocation kind that covers all
-  // properties in the template, as the space used by unboxed properties
-  // is less than or equal to that used by boxed properties.
-  MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >=
-             Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan()));
-
-  if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) {
-    // Only use an unboxed representation if all created objects match
-    // the template shape exactly.
-    return false;
-  }
-
-  for (size_t i = 0; i < templateShape->slotSpan(); i++) {
-    Value val = obj->getSlot(i);
-
-    JSValueType& existing = properties[i].type;
-    if (!CombineUnboxedTypes(val, &existing)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-static size_t ComputePlainObjectLayout(
-    JSContext* cx, ObjectGroupRealm& realm, Shape* templateShape,
-    UnboxedLayout::PropertyVector& properties) {
-  // Fill in the names for all the object's properties.
-  for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
-    size_t slot = r.front().slot();
-    MOZ_ASSERT(!properties[slot].name);
-    properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
-  }
-
-  // Fill in all the unboxed object's property offsets.
-  uint32_t offset = 0;
-
-  // Search for an existing unboxed layout which is a subset of this one.
-  // If there are multiple such layouts, use the largest one. If we're able
-  // to find such a layout, use the same property offsets for the shared
-  // properties, which will allow us to generate better code if the objects
-  // have a subtype/supertype relation and are accessed at common sites.
-  UnboxedLayout* bestExisting = nullptr;
-  for (UnboxedLayout* existing : realm.unboxedLayouts) {
-    if (PropertiesAreSuperset(properties, existing)) {
-      if (!bestExisting || existing->properties().length() >
-                               bestExisting->properties().length()) {
-        bestExisting = existing;
-      }
-    }
-  }
-  if (bestExisting) {
-    for (size_t i = 0; i < bestExisting->properties().length(); i++) {
-      const UnboxedLayout::Property& existingProperty =
-          bestExisting->properties()[i];
-      for (size_t j = 0; j < templateShape->slotSpan(); j++) {
-        if (existingProperty.name == properties[j].name) {
-          MOZ_ASSERT(existingProperty.type == properties[j].type);
-          properties[j].offset = existingProperty.offset;
-        }
-      }
-    }
-    offset = bestExisting->size();
-  }
-
-  // Order remaining properties from the largest down for the best space
-  // utilization.
-  static const size_t typeSizes[] = {8, 4, 1};
-
-  for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
-    size_t size = typeSizes[i];
-    for (size_t j = 0; j < templateShape->slotSpan(); j++) {
-      if (properties[j].offset != UINT32_MAX) {
-        continue;
-      }
-      JSValueType type = properties[j].type;
-      if (UnboxedTypeSize(type) == size) {
-        offset = JS_ROUNDUP(offset, size);
-        properties[j].offset = offset;
-        offset += size;
-      }
-    }
-  }
-
-  // The final offset is the amount of data needed by the object.
-  return offset;
-}
-
-static bool SetLayoutTraceList(JSContext* cx, UnboxedLayout* layout) {
-  // Figure out the offsets of any objects or string properties.
-  Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
-  for (size_t i = 0; i < layout->properties().length(); i++) {
-    const UnboxedLayout::Property& property = layout->properties()[i];
-    MOZ_ASSERT(property.offset != UINT32_MAX);
-    if (property.type == JSVAL_TYPE_OBJECT) {
-      if (!objectOffsets.append(property.offset)) {
-        return false;
-      }
-    } else if (property.type == JSVAL_TYPE_STRING) {
-      if (!stringOffsets.append(property.offset)) {
-        return false;
-      }
-    }
-  }
-
-  // Construct the layout's trace list.
-  if (!objectOffsets.empty() || !stringOffsets.empty()) {
-    Vector<int32_t, 8, SystemAllocPolicy> entries;
-    if (!entries.appendAll(stringOffsets) || !entries.append(-1) ||
-        !entries.appendAll(objectOffsets) || !entries.append(-1) ||
-        !entries.append(-1)) {
-      return false;
-    }
-    int32_t* traceList = cx->zone()->pod_malloc<int32_t>(entries.length());
-    if (!traceList) {
-      return false;
-    }
-    PodCopy(traceList, entries.begin(), entries.length());
-    layout->setTraceList(traceList);
-  }
-
-  return true;
-}
-
 static inline Value NextValue(Handle<GCVector<Value>> values,
                               size_t* valueCursor) {
   return values[(*valueCursor)++];
 }
 
-static bool GetValuesFromPreliminaryPlainObject(
-    PlainObject* obj, MutableHandle<GCVector<Value>> values) {
-  for (size_t i = 0; i < obj->slotSpan(); i++) {
-    if (!values.append(obj->getSlot(i))) {
-      return false;
-    }
-  }
-  return true;
-}
-
 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)));
   }
-}
-
-bool js::TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter,
-                                   Shape* templateShape, ObjectGroup* group,
-                                   PreliminaryObjectArray* objects) {
-  MOZ_ASSERT(templateShape);
-
-  if (jit::JitOptions.disableUnboxedObjects) {
-    return true;
-  }
-
-  AutoSweepObjectGroup sweep(group);
-
-  MOZ_ASSERT(!templateShape->getObjectFlags());
-
-  if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global())) {
-    return true;
-  }
-
-  if (templateShape->slotSpan() == 0) {
-    return true;
-  }
-
-  UnboxedLayout::PropertyVector properties;
-  if (!properties.appendN(UnboxedLayout::Property(),
-                          templateShape->slotSpan())) {
-    return false;
-  }
-
-  size_t objectCount = 0;
-  for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-    JSObject* obj = objects->get(i);
-    if (!obj) {
-      continue;
-    }
-
-    if (obj->isSingleton() || obj->group() != group) {
-      return true;
-    }
-
-    objectCount++;
-
-    if (!CombinePlainObjectProperties(&obj->as<PlainObject>(), templateShape,
-                                      properties)) {
-      return true;
-    }
-  }
-
-  size_t layoutSize = 0;
-  if (objectCount <= 1) {
-    // If only one of the objects has been created, it is more likely
-    // to have new properties added later.
-    return true;
-  }
-
-  for (size_t i = 0; i < templateShape->slotSpan(); i++) {
-    // We can't use an unboxed representation if e.g. all the objects have
-    // a null value for one of the properties, as we can't decide what type
-    // it is supposed to have.
-    if (UnboxedTypeSize(properties[i].type) == 0) {
-      return true;
-    }
-  }
-
-  // Make sure that all properties on the template shape are property
-  // names, and not indexes.
-  for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
-    jsid id = r.front().propid();
-    uint32_t dummy;
-    if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy)) {
-      return true;
-    }
-  }
-
-  ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
-  layoutSize = ComputePlainObjectLayout(cx, realm, templateShape, properties);
-
-  // The entire object must be allocatable inline.
-  if (UnboxedPlainObject::offsetOfData() + layoutSize >
-      JSObject::MAX_BYTE_SIZE) {
-    return true;
-  }
-
-  UniquePtr<UnboxedLayout>& layout = enter.unboxedLayoutToCleanUp;
-  MOZ_ASSERT(!layout);
-  layout = group->zone()->make_unique<UnboxedLayout>(group->zone());
-  if (!layout) {
-    return false;
-  }
-
-  if (!layout->initProperties(properties, layoutSize)) {
-    return false;
-  }
-
-  // The unboxedLayouts list only tracks layouts for plain objects.
-  realm.unboxedLayouts.insertFront(layout.get());
-
-  if (!SetLayoutTraceList(cx, layout.get())) {
-    return false;
-  }
-
-  // We've determined that all the preliminary objects can use the new layout
-  // just constructed, so convert the existing group to use the unboxed class,
-  // and update the preliminary objects to use the new layout. Do the
-  // fallible stuff first before modifying any objects.
-
-  // Get an empty shape which we can use for the preliminary objects.
-  Shape* newShape = EmptyShape::getInitialShape(cx, &UnboxedPlainObject::class_,
-                                                group->proto(), 0);
-  if (!newShape) {
-    cx->recoverFromOutOfMemory();
-    return false;
-  }
-
-  // Accumulate a list of all the values in each preliminary object, and
-  // update their shapes.
-  Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
-  for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-    JSObject* obj = objects->get(i);
-    if (!obj) {
-      continue;
-    }
-
-    if (!GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(),
-                                             &values)) {
-      cx->recoverFromOutOfMemory();
-      return false;
-    }
-  }
-
-  if (TypeNewScript* newScript = group->newScript(sweep)) {
-    layout->setNewScript(newScript);
-  }
-
-  for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-    if (JSObject* obj = objects->get(i)) {
-      obj->as<NativeObject>().setLastPropertyMakeNonNative(newShape);
-    }
-  }
-
-  group->setClasp(&UnboxedPlainObject::class_);
-  group->setUnboxedLayout(layout.release());
-
-  size_t valueCursor = 0;
-  for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
-    JSObject* obj = objects->get(i);
-    if (!obj) {
-      continue;
-    }
-
-    obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
-  }
-
-  MOZ_ASSERT(valueCursor == values.length());
-  return true;
-}
+}
\ No newline at end of file
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -280,23 +280,16 @@ class UnboxedPlainObject : public Unboxe
     return offsetof(UnboxedPlainObject, data_[0]);
   }
 };
 
 inline bool IsUnboxedObjectClass(const Class* class_) {
   return class_ == &UnboxedPlainObject::class_;
 }
 
-// Try to construct an UnboxedLayout for each of the preliminary objects,
-// provided they all match the template shape. If successful, converts the
-// preliminary objects and their group to the new unboxed representation.
-bool TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter,
-                               Shape* templateShape, ObjectGroup* group,
-                               PreliminaryObjectArray* objects);
-
 }  // namespace js
 
 namespace JS {
 
 template <>
 struct DeletePolicy<js::UnboxedLayout>
     : public js::GCManagedDeletePolicy<js::UnboxedLayout> {};