summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2019-06-28 11:25:09 +0000
committerGitHub <noreply@github.com>2019-06-28 11:25:09 +0000
commit31a02a022e1e3f01463672af71a5c4296f672bfb (patch)
tree041ebdd049d68aaa30caaee6c53260fe9116755b /js/src/vm
parent610c5fc6cee6346b5333077c29029e3e90e0c4cb (diff)
parentb8ff1df2c96270c481a645947390c4cdae93e3cc (diff)
downloadUXP-31a02a022e1e3f01463672af71a5c4296f672bfb.tar
UXP-31a02a022e1e3f01463672af71a5c4296f672bfb.tar.gz
UXP-31a02a022e1e3f01463672af71a5c4296f672bfb.tar.lz
UXP-31a02a022e1e3f01463672af71a5c4296f672bfb.tar.xz
UXP-31a02a022e1e3f01463672af71a5c4296f672bfb.zip
Merge pull request #1142 from MoonchildProductions/remove-unboxed
Remove unboxed objects
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/Interpreter.cpp5
-rw-r--r--js/src/vm/NativeObject.cpp27
-rw-r--r--js/src/vm/NativeObject.h5
-rw-r--r--js/src/vm/ObjectGroup-inl.h14
-rw-r--r--js/src/vm/ObjectGroup.cpp55
-rw-r--r--js/src/vm/ObjectGroup.h62
-rw-r--r--js/src/vm/ReceiverGuard.cpp14
-rw-r--r--js/src/vm/TypeInference-inl.h5
-rw-r--r--js/src/vm/TypeInference.cpp156
-rw-r--r--js/src/vm/UnboxedObject-inl.h177
-rw-r--r--js/src/vm/UnboxedObject.cpp956
-rw-r--r--js/src/vm/UnboxedObject.h319
12 files changed, 20 insertions, 1775 deletions
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 74a1ef3e9..0f83c3435 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4970,11 +4970,6 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject)
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
- if (templateObject->group()->maybeUnboxedLayout()) {
- RootedObjectGroup group(cx, templateObject->group());
- return UnboxedPlainObject::create(cx, group, newKind);
- }
-
JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
if (!obj)
return nullptr;
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index 21f73f4a9..a3f28653a 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -390,33 +390,6 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape)
shape_ = shape;
}
-void
-NativeObject::setLastPropertyMakeNative(ExclusiveContext* 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.
- shape_.init(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(ExclusiveContext* cx, uint32_t span)
{
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index da4f873a6..d9d8b8aec 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -470,11 +470,6 @@ class NativeObject : public ShapedObject
// 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(ExclusiveContext* 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.
diff --git a/js/src/vm/ObjectGroup-inl.h b/js/src/vm/ObjectGroup-inl.h
index 9074f4d97..d41343be6 100644
--- a/js/src/vm/ObjectGroup-inl.h
+++ b/js/src/vm/ObjectGroup-inl.h
@@ -108,20 +108,6 @@ ObjectGroup::maybePreliminaryObjects()
return maybePreliminaryObjectsDontCheckGeneration();
}
-inline UnboxedLayout*
-ObjectGroup::maybeUnboxedLayout()
-{
- maybeSweep(nullptr);
- return maybeUnboxedLayoutDontCheckGeneration();
-}
-
-inline UnboxedLayout&
-ObjectGroup::unboxedLayout()
-{
- maybeSweep(nullptr);
- return unboxedLayoutDontCheckGeneration();
-}
-
} // namespace js
#endif /* vm_ObjectGroup_inl_h */
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index 63ac33eea..676792379 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -18,11 +18,10 @@
#include "vm/ArrayObject.h"
#include "vm/Shape.h"
#include "vm/TaggedProto.h"
-#include "vm/UnboxedObject.h"
#include "jsobjinlines.h"
-#include "vm/UnboxedObject-inl.h"
+#include "vm/NativeObject-inl.h"
using namespace js;
@@ -56,7 +55,6 @@ ObjectGroup::finalize(FreeOp* fop)
if (newScriptDontCheckGeneration())
newScriptDontCheckGeneration()->clear();
fop->delete_(newScriptDontCheckGeneration());
- fop->delete_(maybeUnboxedLayoutDontCheckGeneration());
if (maybePreliminaryObjectsDontCheckGeneration())
maybePreliminaryObjectsDontCheckGeneration()->clear();
fop->delete_(maybePreliminaryObjectsDontCheckGeneration());
@@ -83,8 +81,6 @@ 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;
}
@@ -530,8 +526,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
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);
return group;
}
@@ -971,46 +966,6 @@ js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj,
}
}
}
- } 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;
@@ -1234,12 +1189,6 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_
RootedObjectGroup group(cx, p->value().group);
- // Watch for existing groups which now use an unboxed layout.
- if (group->maybeUnboxedLayout()) {
- MOZ_ASSERT(group->unboxedLayout().properties().length() == nproperties);
- 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.
diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
index 553cb8366..0b6eaee51 100644
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -20,7 +20,6 @@
namespace js {
class TypeDescr;
-class UnboxedLayout;
class PreliminaryObjectArrayWithTemplate;
class TypeNewScript;
@@ -154,16 +153,6 @@ class ObjectGroup : public gc::TenuredCell
// 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
};
@@ -185,7 +174,6 @@ class ObjectGroup : public gc::TenuredCell
return nullptr;
}
- TypeNewScript* anyNewScript();
void detachNewScript(bool writeBarrier, ObjectGroup* replacement);
ObjectGroupFlags flagsDontCheckGeneration() const {
@@ -225,34 +213,6 @@ class ObjectGroup : public gc::TenuredCell
maybePreliminaryObjectsDontCheckGeneration();
}
- inline UnboxedLayout* maybeUnboxedLayout();
- inline UnboxedLayout& unboxedLayout();
-
- UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const {
- if (addendumKind() == Addendum_UnboxedLayout)
- return reinterpret_cast<UnboxedLayout*>(addendum_);
- return nullptr;
- }
-
- UnboxedLayout& unboxedLayoutDontCheckGeneration() const {
- MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout);
- return *maybeUnboxedLayoutDontCheckGeneration();
- }
-
- 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) {
- setAddendum(Addendum_OriginalUnboxedGroup, group);
- }
-
TypeDescr* maybeTypeDescr() {
// Note: there is no need to sweep when accessing the type descriptor
// of an object, as it is strongly held and immutable.
@@ -313,9 +273,8 @@ class ObjectGroup : public gc::TenuredCell
* that can be read out of that property in actual JS objects. In native
* objects, property types account for plain data properties (those with a
* slot and no getter or setter hook) and dense elements. In typed objects
- * and unboxed objects, property types account for object and value
- * properties and elements in the object, and expando properties in unboxed
- * objects.
+ * property types account for object and value properties and elements in
+ * the object.
*
* For accesses on these properties, the correspondence is as follows:
*
@@ -338,10 +297,9 @@ class ObjectGroup : public gc::TenuredCell
* 2. Array lengths are special cased by the compiler and VM and are not
* reflected in property types.
*
- * 3. In typed objects (but not unboxed objects), the initial values of
- * properties (null pointers and undefined values) are not reflected in
- * the property types. These values are always possible when reading the
- * property.
+ * 3. In typed objects, the initial values of properties (null pointers and
+ * undefined values) are not reflected in the property types. These
+ * values are always possible when reading the property.
*
* We establish these by using write barriers on calls to setProperty and
* defineProperty which are on native properties, and on any jitcode which
@@ -455,12 +413,6 @@ class ObjectGroup : public gc::TenuredCell
return &flags_;
}
- // Get the bit pattern stored in an object's addendum when it has an
- // original unboxed group.
- static inline int32_t addendumOriginalUnboxedGroupValue() {
- return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT;
- }
-
inline uint32_t basePropertyCount();
private:
@@ -511,8 +463,8 @@ class ObjectGroup : public gc::TenuredCell
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(ExclusiveContext* cx,
IdValuePair* properties, size_t nproperties,
NewObjectKind newKind);
diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp
index e37bf8ee5..e95e8a208 100644
--- a/js/src/vm/ReceiverGuard.cpp
+++ b/js/src/vm/ReceiverGuard.cpp
@@ -15,11 +15,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj)
: group(nullptr), shape(nullptr)
{
if (obj) {
- if (obj->is<UnboxedPlainObject>()) {
- group = obj->group();
- if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
- shape = expando->lastProperty();
- } else if (obj->is<TypedObject>()) {
+ if (obj->is<TypedObject>()) {
group = obj->group();
} else {
shape = obj->maybeShape();
@@ -32,9 +28,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* 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;
@@ -45,10 +39,6 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
/* static */ int32_t
HeapReceiverGuard::keyBits(JSObject* obj)
{
- if (obj->is<UnboxedPlainObject>()) {
- // Both the group and shape need to be guarded for unboxed plain objects.
- return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
- }
if (obj->is<TypedObject>()) {
// Only the group needs to be guarded for typed objects.
return 2;
diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h
index da47fa898..2af252cea 100644
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -23,7 +23,6 @@
#include "vm/SharedArrayObject.h"
#include "vm/StringObject.h"
#include "vm/TypedArrayObject.h"
-#include "vm/UnboxedObject.h"
#include "jscntxtinlines.h"
@@ -285,10 +284,6 @@ TypeIdString(jsid id)
*/
struct 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;
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 0551e2c58..ba809fc4e 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -35,7 +35,6 @@
#include "vm/Opcodes.h"
#include "vm/Shape.h"
#include "vm/Time.h"
-#include "vm/UnboxedObject.h"
#include "jsatominlines.h"
#include "jsscriptinlines.h"
@@ -297,9 +296,6 @@ js::ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Val
return true;
}
}
- JSObject* obj = &value.toObject();
- if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup())
- return true;
}
if (!types->hasType(type)) {
@@ -1944,33 +1940,6 @@ class ConstraintDataFreezeObjectForTypedArrayData
}
};
-// 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(ObjectGroup* group) {
- return group->unboxedLayout().nativeGroup() != nullptr;
- }
-
- bool constraintHolds(JSContext* cx,
- const HeapTypeSetKey& property, TemporaryTypeSet* expected)
- {
- return !invalidateOnNewObjectState(property.object()->maybeGroup());
- }
-
- bool shouldSweep() { return false; }
-
- JSCompartment* maybeCompartment() { return nullptr; }
-};
-
} /* anonymous namespace */
void
@@ -2505,8 +2474,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid
bool
js::ClassCanHaveExtraProperties(const Class* clasp)
{
- if (clasp == &UnboxedPlainObject::class_)
- return false;
return clasp->getResolve()
|| clasp->getOpsLookupProperty()
|| clasp->getOpsGetProperty()
@@ -2805,15 +2772,6 @@ js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, j
// from acquiring the fully initialized group.
if (group->newScript() && group->newScript()->initializedGroup())
AddTypePropertyId(cx, group->newScript()->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() && group->maybeUnboxedLayout()->nativeGroup())
- AddTypePropertyId(cx, group->maybeUnboxedLayout()->nativeGroup(), nullptr, id, type);
- if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup())
- AddTypePropertyId(cx, unboxedGroup, nullptr, id, type);
}
void
@@ -2885,12 +2843,6 @@ ObjectGroup::setFlags(ExclusiveContext* cx, ObjectGroupFlags flags)
// acquired properties analysis.
if (newScript() && newScript()->initializedGroup())
newScript()->initializedGroup()->setFlags(cx, flags);
-
- // Propagate flag changes between unboxed and corresponding native groups.
- if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
- maybeUnboxedLayout()->nativeGroup()->setFlags(cx, flags);
- if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
- unboxedGroup->setFlags(cx, flags);
}
void
@@ -2923,23 +2875,6 @@ ObjectGroup::markUnknown(ExclusiveContext* cx)
prop->types.setNonDataProperty(cx);
}
}
-
- if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
- MarkObjectGroupUnknownProperties(cx, unboxedGroup);
- if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup())
- MarkObjectGroupUnknownProperties(cx, maybeUnboxedLayout()->nativeGroup());
- if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup())
- MarkObjectGroupUnknownProperties(cx, unboxedGroup);
-}
-
-TypeNewScript*
-ObjectGroup::anyNewScript()
-{
- if (newScript())
- return newScript();
- if (maybeUnboxedLayout())
- return unboxedLayout().newScript();
- return nullptr;
}
void
@@ -2949,7 +2884,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement)
// 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.
- TypeNewScript* newScript = anyNewScript();
+ TypeNewScript* newScript = this->newScript();
MOZ_ASSERT(newScript);
if (newScript->analyzed()) {
@@ -2968,10 +2903,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement)
MOZ_ASSERT(!replacement);
}
- if (this->newScript())
- setAddendum(Addendum_None, nullptr, writeBarrier);
- else
- unboxedLayout().setNewScript(nullptr, writeBarrier);
+ setAddendum(Addendum_None, nullptr, writeBarrier);
}
void
@@ -2982,7 +2914,7 @@ ObjectGroup::maybeClearNewScriptOnOOM()
if (!isMarked())
return;
- TypeNewScript* newScript = anyNewScript();
+ TypeNewScript* newScript = this->newScript();
if (!newScript)
return;
@@ -2997,7 +2929,7 @@ ObjectGroup::maybeClearNewScriptOnOOM()
void
ObjectGroup::clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement /* = nullptr*/)
{
- TypeNewScript* newScript = anyNewScript();
+ TypeNewScript* newScript = this->newScript();
if (!newScript)
return;
@@ -3451,22 +3383,6 @@ PreliminaryObjectArray::sweep()
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 compartment'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->compartment()->unsafeUnbarrieredMaybeGlobal();
- if (global && !obj->isSingleton()) {
- JSObject* objectProto = GetBuiltinPrototypePure(global, JSProto_Object);
- obj->setGroup(objectProto->groupRaw());
- MOZ_ASSERT(obj->is<NativeObject>());
- MOZ_ASSERT(obj->getClass() == objectProto->getClass());
- MOZ_ASSERT(!obj->getClass()->hasFinalize());
- }
-
*ptr = nullptr;
}
}
@@ -3566,16 +3482,11 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro
}
}
- if (group->maybeUnboxedLayout())
- return;
-
- if (shape()) {
- // 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.
- group->addDefiniteProperties(cx, shape());
- }
+ // 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 definitive for objects in
+ // the group.
+ group->addDefiniteProperties(cx, shape());
}
/////////////////////////////////////////////////////////////////////
@@ -3589,7 +3500,6 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun)
{
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
MOZ_ASSERT(!group->newScript());
- MOZ_ASSERT(!group->maybeUnboxedLayout());
// rollbackPartiallyInitializedObjects expects function_ to be
// canonicalized.
@@ -3852,27 +3762,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
js_delete(preliminaryObjects);
preliminaryObjects = nullptr;
- if (group->maybeUnboxedLayout()) {
- // An unboxed layout was constructed for the group, and this has already
- // been hooked into it.
- MOZ_ASSERT(group->unboxedLayout().newScript() == this);
- destroyNewScript.group = nullptr;
-
- // 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
@@ -3968,12 +3857,6 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
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>());
@@ -4167,12 +4050,6 @@ ConstraintTypeSet::sweep(Zone* zone, AutoClearTypeInferenceStateOnOOM& oom)
// 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;
@@ -4256,21 +4133,6 @@ ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom)
Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM;
EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM);
- if (maybeUnboxedLayout()) {
- // Remove unboxed layouts that are about to be finalized from the
- // compartment wide list while we are still on the main thread.
- ObjectGroup* group = this;
- if (IsAboutToBeFinalizedUnbarriered(&group))
- unboxedLayout().detachFromCompartment();
-
- if (unboxedLayout().newScript())
- unboxedLayout().newScript()->sweep();
-
- // Discard constructor code to avoid holding onto ExecutablePools.
- if (zone()->isGCCompacting())
- unboxedLayout().setConstructorCode(nullptr);
- }
-
if (maybePreliminaryObjects())
maybePreliminaryObjects()->sweep();
diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h
deleted file mode 100644
index c1468a5b1..000000000
--- a/js/src/vm/UnboxedObject-inl.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef vm_UnboxedObject_inl_h
-#define vm_UnboxedObject_inl_h
-
-#include "vm/UnboxedObject.h"
-
-#include "gc/StoreBuffer-inl.h"
-#include "vm/ArrayObject-inl.h"
-#include "vm/NativeObject-inl.h"
-
-namespace js {
-
-static inline Value
-GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized)
-{
- switch (type) {
- case JSVAL_TYPE_BOOLEAN:
- return BooleanValue(*p != 0);
-
- case JSVAL_TYPE_INT32:
- 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.
- 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 inline void
-SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
- uint8_t* p, JSValueType type, const Value& v,
- bool preBarrier)
-{
- switch (type) {
- case JSVAL_TYPE_BOOLEAN:
- *p = v.toBoolean();
- return;
-
- case JSVAL_TYPE_INT32:
- *reinterpret_cast<int32_t*>(p) = v.toInt32();
- return;
-
- case JSVAL_TYPE_DOUBLE:
- *reinterpret_cast<double*>(p) = v.toNumber();
- return;
-
- case JSVAL_TYPE_STRING: {
- MOZ_ASSERT(!IsInsideNursery(v.toString()));
- JSString** np = reinterpret_cast<JSString**>(p);
- if (preBarrier)
- JSString::writeBarrierPre(*np);
- *np = v.toString();
- return;
- }
-
- case JSVAL_TYPE_OBJECT: {
- JSObject** np = reinterpret_cast<JSObject**>(p);
-
- // Manually trigger post barriers on the whole object. If we treat
- // the pointer as a HeapPtrObject we will get confused later if the
- // object is converted to its native representation.
- JSObject* obj = v.toObjectOrNull();
- if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) {
- JSRuntime* rt = unboxedObject->runtimeFromMainThread();
- rt->gc.storeBuffer.putWholeCell(unboxedObject);
- }
-
- if (preBarrier)
- JSObject::writeBarrierPre(*np);
- *np = obj;
- return;
- }
-
- default:
- MOZ_CRASH("Invalid type for unboxed value");
- }
-}
-
-static inline bool
-SetUnboxedValue(ExclusiveContext* 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()) {
- MOZ_ASSERT(!IsInsideNursery(v.toString()));
- JSString** np = reinterpret_cast<JSString**>(p);
- 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(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) {
- JSRuntime* rt = unboxedObject->runtimeFromMainThread();
- rt->gc.storeBuffer.putWholeCell(unboxedObject);
- }
-
- if (preBarrier)
- JSObject::writeBarrierPre(*np);
- *np = obj;
- return true;
- }
- return false;
-
- default:
- MOZ_CRASH("Invalid type for unboxed value");
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedPlainObject
-/////////////////////////////////////////////////////////////////////
-
-inline const UnboxedLayout&
-UnboxedPlainObject::layout() const
-{
- return group()->unboxedLayout();
-}
-
-} // namespace js
-
-#endif // vm_UnboxedObject_inl_h
diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
deleted file mode 100644
index 806a9db81..000000000
--- a/js/src/vm/UnboxedObject.cpp
+++ /dev/null
@@ -1,956 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "vm/UnboxedObject-inl.h"
-
-#include "jit/BaselineIC.h"
-#include "jit/ExecutableAllocator.h"
-#include "jit/JitCommon.h"
-#include "jit/Linker.h"
-
-#include "jsobjinlines.h"
-
-#include "gc/Nursery-inl.h"
-#include "jit/MacroAssembler-inl.h"
-#include "vm/Shape-inl.h"
-
-using mozilla::ArrayLength;
-using mozilla::DebugOnly;
-using mozilla::PodCopy;
-
-using namespace js;
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedLayout
-/////////////////////////////////////////////////////////////////////
-
-void
-UnboxedLayout::trace(JSTracer* trc)
-{
- for (size_t i = 0; i < properties_.length(); i++)
- 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)
-{
- gc::AutoSuppressGC suppress(cx);
-
- using namespace jit;
-
- if (!cx->compartment()->ensureJitCompartmentExists(cx))
- return false;
-
- UnboxedLayout& layout = group->unboxedLayout();
- MOZ_ASSERT(!layout.constructorCode());
-
- UnboxedPlainObject* templateObject = UnboxedPlainObject::create(cx, group, TenuredObject);
- if (!templateObject)
- return false;
-
- JitContext jitContext(cx, nullptr);
-
- MacroAssembler masm;
-
- Register propertiesReg, newKindReg;
-#ifdef JS_CODEGEN_X86
- propertiesReg = eax;
- newKindReg = ecx;
- masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg);
- masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg);
-#else
- propertiesReg = IntArgReg0;
- newKindReg = IntArgReg1;
-#endif
-
-#ifdef JS_CODEGEN_ARM64
- // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
- masm.initStackPtr();
-#endif
-
- MOZ_ASSERT(propertiesReg.volatile_());
- MOZ_ASSERT(newKindReg.volatile_());
-
- AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
- regs.take(propertiesReg);
- regs.take(newKindReg);
- Register object = regs.takeAny(), scratch1 = regs.takeAny(), scratch2 = regs.takeAny();
-
- LiveGeneralRegisterSet savedNonVolatileRegisters = SavedNonVolatileRegisters(regs);
- masm.PushRegsInMask(savedNonVolatileRegisters);
-
- // The scratch double register might be used by MacroAssembler methods.
- if (ScratchDoubleReg.volatile_())
- masm.push(ScratchDoubleReg);
-
- Label failure, tenuredObject, allocated;
- masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), &tenuredObject);
- masm.branchTest32(Assembler::NonZero, AbsoluteAddress(group->addressOfFlags()),
- Imm32(OBJECT_FLAG_PRE_TENURE), &tenuredObject);
-
- // Allocate an object in the nursery
- masm.createGCObject(object, scratch1, templateObject, gc::DefaultHeap, &failure,
- /* initFixedSlots = */ false);
-
- masm.jump(&allocated);
- masm.bind(&tenuredObject);
-
- // Allocate an object in the tenured heap.
- masm.createGCObject(object, scratch1, templateObject, gc::TenuredHeap, &failure,
- /* initFixedSlots = */ false);
-
- // If any of the properties being stored are in the nursery, add a store
- // buffer entry for the new object.
- Label postBarrier;
- for (size_t i = 0; i < layout.properties().length(); i++) {
- const UnboxedLayout::Property& property = layout.properties()[i];
- if (property.type == JSVAL_TYPE_OBJECT) {
- Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
- Label notObject;
- masm.branchTestObject(Assembler::NotEqual, valueAddress, &notObject);
- Register valueObject = masm.extractObject(valueAddress, scratch1);
- masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, &postBarrier);
- masm.bind(&notObject);
- }
- }
-
- masm.jump(&allocated);
- masm.bind(&postBarrier);
-
- LiveGeneralRegisterSet liveVolatileRegisters;
- liveVolatileRegisters.add(propertiesReg);
- if (object.volatile_())
- liveVolatileRegisters.add(object);
- masm.PushRegsInMask(liveVolatileRegisters);
-
- masm.mov(ImmPtr(cx->runtime()), scratch1);
- masm.setupUnalignedABICall(scratch2);
- masm.passABIArg(scratch1);
- masm.passABIArg(object);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
-
- masm.PopRegsInMask(liveVolatileRegisters);
-
- masm.bind(&allocated);
-
- ValueOperand valueOperand;
-#ifdef JS_NUNBOX32
- valueOperand = ValueOperand(scratch1, scratch2);
-#else
- valueOperand = ValueOperand(scratch1);
-#endif
-
- Label failureStoreOther, failureStoreObject;
-
- for (size_t i = 0; i < layout.properties().length(); i++) {
- const UnboxedLayout::Property& property = layout.properties()[i];
- Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
- Address targetAddress(object, UnboxedPlainObject::offsetOfData() + property.offset);
-
- masm.loadValue(valueAddress, valueOperand);
-
- if (property.type == JSVAL_TYPE_OBJECT) {
- HeapTypeSet* types = group->maybeGetProperty(IdToTypeId(NameToId(property.name)));
-
- Label notObject;
- masm.branchTestObject(Assembler::NotEqual, valueOperand,
- types->mightBeMIRType(MIRType::Null) ? &notObject : &failureStoreObject);
-
- Register payloadReg = masm.extractObject(valueOperand, scratch1);
-
- if (!types->hasType(TypeSet::AnyObjectType())) {
- Register scratch = (payloadReg == scratch1) ? scratch2 : scratch1;
- masm.guardObjectType(payloadReg, types, scratch, &failureStoreObject);
- }
-
- masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT,
- TypedOrValueRegister(MIRType::Object,
- AnyRegister(payloadReg)), nullptr);
-
- if (notObject.used()) {
- Label done;
- masm.jump(&done);
- masm.bind(&notObject);
- masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
- masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, NullValue(), nullptr);
- masm.bind(&done);
- }
- } else {
- masm.storeUnboxedProperty(targetAddress, property.type,
- ConstantOrRegister(valueOperand), &failureStoreOther);
- }
- }
-
- Label done;
- masm.bind(&done);
-
- if (object != ReturnReg)
- masm.movePtr(object, ReturnReg);
-
- // Restore non-volatile registers which were saved on entry.
- if (ScratchDoubleReg.volatile_())
- masm.pop(ScratchDoubleReg);
- masm.PopRegsInMask(savedNonVolatileRegisters);
-
- masm.abiret();
-
- masm.bind(&failureStoreOther);
-
- // There was a failure while storing a value which cannot be stored at all
- // in the unboxed object. Initialize the object so it is safe for GC and
- // return null.
- masm.initUnboxedObjectContents(object, templateObject);
-
- masm.bind(&failure);
-
- masm.movePtr(ImmWord(0), object);
- masm.jump(&done);
-
- masm.bind(&failureStoreObject);
-
- // There was a failure while storing a value to an object slot of the
- // unboxed object. If the value is storable, the failure occurred due to
- // incomplete type information in the object, so return a token to trigger
- // regeneration of the jitcode after a new object is created in the VM.
- {
- Label isObject;
- masm.branchTestObject(Assembler::Equal, valueOperand, &isObject);
- masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
- masm.bind(&isObject);
- }
-
- // Initialize the object so it is safe for GC.
- masm.initUnboxedObjectContents(object, templateObject);
-
- masm.movePtr(ImmWord(CLEAR_CONSTRUCTOR_CODE_TOKEN), object);
- masm.jump(&done);
-
- Linker linker(masm);
- AutoFlushICache afc("UnboxedObject");
- JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
- if (!code)
- return false;
-
- layout.setConstructorCode(code);
- return true;
-}
-
-void
-UnboxedLayout::detachFromCompartment()
-{
- if (isInList())
- remove();
-}
-
-/////////////////////////////////////////////////////////////////////
-// UnboxedPlainObject
-/////////////////////////////////////////////////////////////////////
-
-bool
-UnboxedPlainObject::setValue(ExclusiveContext* 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)
-{
- if (obj->as<UnboxedPlainObject>().expando_) {
- TraceManuallyBarrieredEdge(trc,
- reinterpret_cast<NativeObject**>(&obj->as<UnboxedPlainObject>().expando_),
- "unboxed_expando");
- }
-
- const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration();
- const int32_t* list = layout.traceList();
- if (!list)
- return;
-
- uint8_t* data = obj->as<UnboxedPlainObject>().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->expando_)
- return obj->expando_;
-
- 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))
- cx->runtime()->gc.storeBuffer.putWholeCell(obj);
-
- obj->expando_ = expando;
- return expando;
-}
-
-bool
-UnboxedPlainObject::containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const
-{
- if (layout().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)
-{
- HeapTypeSet* typeProperty = oldGroup->maybeGetProperty(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)
-{
- PlainObject* obj = NewObjectWithGroup<PlainObject>(cx, group, layout.getAllocKind(),
- TenuredObject);
- if (!obj)
- return nullptr;
-
- for (size_t i = 0; i < layout.properties().length(); i++) {
- const UnboxedLayout::Property& property = layout.properties()[i];
- if (!obj->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE))
- return nullptr;
- MOZ_ASSERT(obj->slotSpan() == i + 1);
- MOZ_ASSERT(!obj->inDictionaryMode());
- }
-
- return obj;
-}
-
-/* static */ bool
-UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
-{
- AutoEnterAnalysis enter(cx);
-
- UnboxedLayout& layout = group->unboxedLayout();
- 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 = ObjectGroupCompartment::makeGroup(cx, &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::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 = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
- if (!replacementGroup)
- return false;
-
- PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>();
- replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty());
-
- cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object,
- replacementGroup);
-
- // Clear any baseline information at this opcode which might use the old group.
- if (script->hasBaselineScript()) {
- jit::ICEntry& entry = script->baselineScript()->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, 0));
- shape = cx->zone()->propertyTree.getChild(cx, shape, child);
- if (!shape)
- return false;
- }
-
- ObjectGroup* nativeGroup =
- ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto,
- group->flags() & OBJECT_FLAG_DYNAMIC_MASK);
- if (!nativeGroup)
- return false;
-
- // No sense propagating if we don't know what we started with.
- if (!group->unknownProperties()) {
- // Propagate all property types from the old group to the new group.
- 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())
- break;
-
- HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id);
- if (nativeProperty && nativeProperty->canSetDefinite(i))
- nativeProperty->setDefinite(i);
- }
- } else {
- // If we skip, though, the new group had better agree.
- MOZ_ASSERT(nativeGroup->unknownProperties());
- }
-
- layout.nativeGroup_ = nativeGroup;
- layout.nativeShape_ = shape;
- layout.replacementGroup_ = replacementGroup;
-
- nativeGroup->setOriginalUnboxedGroup(group);
-
- group->markStateChange(cx);
-
- return true;
-}
-
-/* static */ bool
-UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj)
-{
- const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
- UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
-
- if (!layout.nativeGroup()) {
- if (!UnboxedLayout::makeNativeGroup(cx, obj->group()))
- return false;
-
- // makeNativeGroup can reentrantly invoke this method.
- if (obj->is<PlainObject>())
- return true;
- }
-
- 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 false;
- }
-
- // 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) {
- // 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 false;
- }
- 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 false;
- }
- }
- ::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 false;
- ObjectOpResult result;
- if (!DefineProperty(cx, nobj, id, desc, result))
- return false;
- MOZ_ASSERT(result.ok());
- }
- }
-
- return true;
-}
-
-/* static */
-UnboxedPlainObject*
-UnboxedPlainObject::create(ExclusiveContext* cx, HandleObjectGroup group, NewObjectKind newKind)
-{
- AutoSetNewObjectMetadata metadata(cx);
-
- MOZ_ASSERT(group->clasp() == &class_);
- gc::AllocKind allocKind = group->unboxedLayout().getAllocKind();
-
- UnboxedPlainObject* res =
- NewObjectWithGroup<UnboxedPlainObject>(cx, group, allocKind, newKind);
- if (!res)
- return nullptr;
-
- // Overwrite the dummy shape which was written to the object's expando field.
- res->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 = res->layout().traceList();
- if (list) {
- uint8_t* data = res->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 res;
-}
-
-/* static */ JSObject*
-UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
- NewObjectKind newKind, IdValuePair* properties)
-{
- MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject);
-
- UnboxedLayout& layout = group->unboxedLayout();
-
- if (layout.constructorCode()) {
- MOZ_ASSERT(cx->isJSContext());
-
- 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;
-
- for (size_t i = 0; i < layout.properties().length(); i++) {
- if (!obj->setValue(cx, layout.properties()[i], properties[i].value))
- return NewPlainObjectWithProperties(cx, properties, layout.properties().length(), newKind);
- }
-
-#ifndef JS_CODEGEN_NONE
- if (cx->isJSContext() &&
- !group->unknownProperties() &&
- !layout.constructorCode() &&
- cx->asJSContext()->runtime()->jitSupportsFloatingPoint &&
- jit::CanLikelyAllocateMoreExecutableMemory())
- {
- if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group))
- return nullptr;
- }
-#endif
-
- return obj;
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
- HandleId id, MutableHandleObject objp,
- MutableHandleShape propp)
-{
- if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
- MarkNonNativePropertyFound<CanGC>(propp);
- objp.set(obj);
- return true;
- }
-
- RootedObject proto(cx, obj->staticPrototype());
- if (!proto) {
- objp.set(nullptr);
- propp.set(nullptr);
- 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::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
-{
- if (!convertToNative(cx, obj))
- return false;
- return WatchProperty(cx, obj, id, callable);
-}
-
-/* static */ bool
-UnboxedPlainObject::obj_enumerate(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, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- 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,
- UnboxedPlainObject::obj_watch,
- nullptr, /* No unwatch needed, as watch() converts the object to native */
- nullptr, /* getElements */
- UnboxedPlainObject::obj_enumerate,
- 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(ExclusiveContext* cx,
- Handle<GCVector<Value>> values, size_t* valueCursor)
-{
- initExpando();
- memset(data(), 0, layout().size());
- for (size_t i = 0; i < layout().properties().length(); i++)
- JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
-}
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h
deleted file mode 100644
index ba66434bc..000000000
--- a/js/src/vm/UnboxedObject.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef vm_UnboxedObject_h
-#define vm_UnboxedObject_h
-
-#include "jsgc.h"
-#include "jsobj.h"
-
-#include "vm/Runtime.h"
-#include "vm/TypeInference.h"
-
-namespace js {
-
-// Memory required for an unboxed value of a given type. Returns zero for types
-// which can't be used for unboxed objects.
-static inline size_t
-UnboxedTypeSize(JSValueType type)
-{
- switch (type) {
- case JSVAL_TYPE_BOOLEAN: return 1;
- case JSVAL_TYPE_INT32: return 4;
- case JSVAL_TYPE_DOUBLE: return 8;
- case JSVAL_TYPE_STRING: return sizeof(void*);
- case JSVAL_TYPE_OBJECT: return sizeof(void*);
- default: return 0;
- }
-}
-
-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_OBJECT;
-}
-
-// Class tracking information specific to unboxed objects.
-class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
-{
- public:
- struct Property {
- PropertyName* name;
- uint32_t offset;
- JSValueType type;
-
- Property()
- : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
- {}
- };
-
- typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
-
- private:
- // 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_;
-
- // Any 'new' script information associated with this layout.
- TypeNewScript* newScript_;
-
- // List for use in tracing objects with this layout. This has the same
- // structure as the trace list on a TypeDescr.
- int32_t* traceList_;
-
- // 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:
- UnboxedLayout()
- : nativeGroup_(nullptr), nativeShape_(nullptr),
- allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
- size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr)
- {}
-
- bool initProperties(const PropertyVector& properties, size_t size) {
- size_ = size;
- return properties_.appendAll(properties);
- }
-
- ~UnboxedLayout() {
- if (newScript_)
- newScript_->clear();
- js_delete(newScript_);
- js_free(traceList_);
-
- nativeGroup_.init(nullptr);
- nativeShape_.init(nullptr);
- replacementGroup_.init(nullptr);
- constructorCode_.init(nullptr);
- }
-
- void detachFromCompartment();
-
- 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 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 JSObject
-{
- // Optional 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().
- UnboxedExpandoObject* expando_;
-
- // 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,
- MutableHandleShape 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 obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
- bool enumerableOnly);
- static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
-
- inline const UnboxedLayout& layout() const;
-
- const UnboxedLayout& layoutDontCheckGeneration() const {
- return group()->unboxedLayoutDontCheckGeneration();
- }
-
- uint8_t* data() {
- return &data_[0];
- }
-
- UnboxedExpandoObject* maybeExpando() const {
- return expando_;
- }
-
- void initExpando() {
- expando_ = nullptr;
- }
-
- // For use during GC.
- JSObject** addressOfExpando() {
- return reinterpret_cast<JSObject**>(&expando_);
- }
-
- bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const;
-
- static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj);
-
- bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v);
- Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false);
-
- static bool convertToNative(JSContext* cx, JSObject* obj);
- static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group,
- NewObjectKind newKind);
- static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
- NewObjectKind newKind, IdValuePair* properties);
-
- void fillAfterConvert(ExclusiveContext* cx,
- Handle<GCVector<Value>> values, size_t* valueCursor);
-
- static void trace(JSTracer* trc, JSObject* object);
-
- static size_t offsetOfExpando() {
- return offsetof(UnboxedPlainObject, expando_);
- }
-
- static size_t offsetOfData() {
- return offsetof(UnboxedPlainObject, data_[0]);
- }
-};
-
-inline gc::AllocKind
-UnboxedLayout::getAllocKind() const
-{
- MOZ_ASSERT(size());
- return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
-}
-
-} // namespace js
-
-namespace JS {
-
-template <>
-struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout>
-{};
-
-} /* namespace JS */
-
-#endif /* vm_UnboxedObject_h */