summaryrefslogtreecommitdiffstats
path: root/js/src/vm/UnboxedObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/UnboxedObject.cpp')
-rw-r--r--js/src/vm/UnboxedObject.cpp826
1 files changed, 15 insertions, 811 deletions
diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
index d7ad91de4..806a9db81 100644
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -417,8 +417,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
RootedObjectGroup replacementGroup(cx);
- const Class* clasp = layout.isArray() ? &ArrayObject::class_ : &PlainObject::class_;
-
// 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
@@ -426,8 +424,6 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
// 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()) {
- MOZ_ASSERT(!layout.isArray());
-
replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
if (!replacementGroup)
return false;
@@ -453,15 +449,14 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
RootedScript script(cx, layout.allocationScript());
jsbytecode* pc = layout.allocationPc();
- replacementGroup = ObjectGroupCompartment::makeGroup(cx, clasp, proto);
+ replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
if (!replacementGroup)
return false;
PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>();
replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty());
- JSProtoKey key = layout.isArray() ? JSProto_Array : JSProto_Object;
- cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, key,
+ cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object,
replacementGroup);
// Clear any baseline information at this opcode which might use the old group.
@@ -477,22 +472,12 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
}
}
- size_t nfixed = layout.isArray() ? 0 : gc::GetGCKindSlots(layout.getAllocKind());
-
- if (layout.isArray()) {
- // The length shape to use for arrays is cached via a modified initial
- // shape for array objects. Create an array now to make sure this entry
- // is instantiated.
- if (!NewDenseEmptyArray(cx))
- return false;
- }
+ size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
- RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, proto, nfixed, 0));
+ RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, nfixed, 0));
if (!shape)
return false;
- MOZ_ASSERT_IF(layout.isArray(), !shape->isEmptyShape() && shape->slotSpan() == 0);
-
// 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];
@@ -505,7 +490,7 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
}
ObjectGroup* nativeGroup =
- ObjectGroupCompartment::makeGroup(cx, clasp, proto,
+ ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto,
group->flags() & OBJECT_FLAG_DYNAMIC_MASK);
if (!nativeGroup)
return false;
@@ -513,24 +498,19 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
// 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.
- if (layout.isArray()) {
- if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup))
+ 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;
- } else {
- 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;
+ // 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);
- }
+ HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id);
+ if (nativeProperty && nativeProperty->canSetDefinite(i))
+ nativeProperty->setDefinite(i);
}
} else {
// If we skip, though, the new group had better agree.
@@ -956,702 +936,6 @@ const Class UnboxedPlainObject::class_ = {
};
/////////////////////////////////////////////////////////////////////
-// UnboxedArrayObject
-/////////////////////////////////////////////////////////////////////
-
-template <JSValueType Type>
-DenseElementResult
-AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen,
- MutableHandle<GCVector<Value>> values)
-{
- for (size_t i = 0; i < initlen; i++)
- values.infallibleAppend(obj->getElementSpecific<Type>(i));
- return DenseElementResult::Success;
-}
-
-DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements,
- UnboxedArrayObject*, uint32_t, MutableHandle<GCVector<Value>>);
-
-/* static */ bool
-UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
- ObjectGroup* group, Shape* shape)
-{
- size_t length = obj->as<UnboxedArrayObject>().length();
- size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
-
- Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
- if (!values.reserve(initlen))
- return false;
-
- AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values);
- DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj);
- MOZ_ASSERT(result.value == DenseElementResult::Success);
-
- obj->setGroup(group);
-
- ArrayObject* aobj = &obj->as<ArrayObject>();
- aobj->setLastPropertyMakeNative(cx, shape);
-
- // Make sure there is at least one element, so that this array does not
- // use emptyObjectElements / emptyObjectElementsShared.
- if (!aobj->ensureElements(cx, Max<size_t>(initlen, 1)))
- return false;
-
- MOZ_ASSERT(!aobj->getDenseInitializedLength());
- aobj->setDenseInitializedLength(initlen);
- aobj->initDenseElements(0, values.begin(), initlen);
- aobj->setLengthInt32(length);
-
- return true;
-}
-
-/* static */ bool
-UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj)
-{
- const UnboxedLayout& layout = obj->as<UnboxedArrayObject>().layout();
-
- if (!layout.nativeGroup()) {
- if (!UnboxedLayout::makeNativeGroup(cx, obj->group()))
- return false;
- }
-
- return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape());
-}
-
-bool
-UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group)
-{
- MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32);
- MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE);
-
- Vector<int32_t> values(cx);
- if (!values.reserve(initializedLength()))
- return false;
- for (size_t i = 0; i < initializedLength(); i++)
- values.infallibleAppend(getElementSpecific<JSVAL_TYPE_INT32>(i).toInt32());
-
- uint8_t* newElements;
- if (hasInlineElements()) {
- newElements = AllocateObjectBuffer<uint8_t>(cx, this, capacity() * sizeof(double));
- } else {
- newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
- capacity() * sizeof(int32_t),
- capacity() * sizeof(double));
- }
- if (!newElements)
- return false;
-
- setGroup(group);
- elements_ = newElements;
-
- for (size_t i = 0; i < initializedLength(); i++)
- setElementNoTypeChangeSpecific<JSVAL_TYPE_DOUBLE>(i, DoubleValue(values[i]));
-
- return true;
-}
-
-/* static */ UnboxedArrayObject*
-UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length,
- NewObjectKind newKind, uint32_t maxLength)
-{
- MOZ_ASSERT(length <= MaximumCapacity);
-
- MOZ_ASSERT(group->clasp() == &class_);
- uint32_t elementSize = UnboxedTypeSize(group->unboxedLayout().elementType());
- uint32_t capacity = Min(length, maxLength);
- uint32_t nbytes = offsetOfInlineElements() + elementSize * capacity;
-
- UnboxedArrayObject* res;
- if (nbytes <= JSObject::MAX_BYTE_SIZE) {
- gc::AllocKind allocKind = gc::GetGCObjectKindForBytes(nbytes);
-
- // If there was no provided length information, pick an allocation kind
- // to accommodate small arrays (as is done for normal native arrays).
- if (capacity == 0)
- allocKind = gc::AllocKind::OBJECT8;
-
- res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, allocKind, newKind);
- if (!res)
- return nullptr;
- res->setInitializedLengthNoBarrier(0);
- res->setInlineElements();
-
- size_t actualCapacity = (GetGCKindBytes(allocKind) - offsetOfInlineElements()) / elementSize;
- MOZ_ASSERT(actualCapacity >= capacity);
- res->setCapacityIndex(exactCapacityIndex(actualCapacity));
- } else {
- res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, gc::AllocKind::OBJECT0, newKind);
- if (!res)
- return nullptr;
- res->setInitializedLengthNoBarrier(0);
-
- uint32_t capacityIndex = (capacity == length)
- ? CapacityMatchesLengthIndex
- : chooseCapacityIndex(capacity, length);
- uint32_t actualCapacity = computeCapacity(capacityIndex, length);
-
- res->elements_ = AllocateObjectBuffer<uint8_t>(cx, res, actualCapacity * elementSize);
- if (!res->elements_) {
- // Make the object safe for GC.
- res->setInlineElements();
- return nullptr;
- }
-
- res->setCapacityIndex(capacityIndex);
- }
-
- res->setLength(cx, length);
- return res;
-}
-
-bool
-UnboxedArrayObject::setElement(ExclusiveContext* cx, size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- uint8_t* p = elements() + index * elementSize();
- return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
-}
-
-bool
-UnboxedArrayObject::initElement(ExclusiveContext* cx, size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- uint8_t* p = elements() + index * elementSize();
- return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
-}
-
-void
-UnboxedArrayObject::initElementNoTypeChange(size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- uint8_t* p = elements() + index * elementSize();
- if (UnboxedTypeNeedsPreBarrier(elementType()))
- *reinterpret_cast<void**>(p) = nullptr;
- SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
-}
-
-Value
-UnboxedArrayObject::getElement(size_t index)
-{
- MOZ_ASSERT(index < initializedLength());
- uint8_t* p = elements() + index * elementSize();
- return GetUnboxedValue(p, elementType(), /* maybeUninitialized = */ false);
-}
-
-/* static */ void
-UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj)
-{
- JSValueType type = obj->as<UnboxedArrayObject>().elementType();
- if (!UnboxedTypeNeedsPreBarrier(type))
- return;
-
- MOZ_ASSERT(obj->as<UnboxedArrayObject>().elementSize() == sizeof(uintptr_t));
- size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
- void** elements = reinterpret_cast<void**>(obj->as<UnboxedArrayObject>().elements());
-
- switch (type) {
- case JSVAL_TYPE_OBJECT:
- for (size_t i = 0; i < initlen; i++) {
- GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(elements + i);
- TraceNullableEdge(trc, heap, "unboxed_object");
- }
- break;
-
- case JSVAL_TYPE_STRING:
- for (size_t i = 0; i < initlen; i++) {
- GCPtrString* heap = reinterpret_cast<GCPtrString*>(elements + i);
- TraceEdge(trc, heap, "unboxed_string");
- }
- break;
-
- default:
- MOZ_CRASH();
- }
-}
-
-/* static */ void
-UnboxedArrayObject::objectMoved(JSObject* obj, const JSObject* old)
-{
- UnboxedArrayObject& dst = obj->as<UnboxedArrayObject>();
- const UnboxedArrayObject& src = old->as<UnboxedArrayObject>();
-
- // Fix up possible inline data pointer.
- if (src.hasInlineElements())
- dst.setInlineElements();
-}
-
-/* static */ void
-UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj)
-{
- MOZ_ASSERT(!IsInsideNursery(obj));
- if (!obj->as<UnboxedArrayObject>().hasInlineElements())
- js_free(obj->as<UnboxedArrayObject>().elements());
-}
-
-/* static */ size_t
-UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
- gc::AllocKind allocKind)
-{
- UnboxedArrayObject* ndst = &dst->as<UnboxedArrayObject>();
- UnboxedArrayObject* nsrc = &src->as<UnboxedArrayObject>();
- MOZ_ASSERT(ndst->elements() == nsrc->elements());
-
- Nursery& nursery = trc->runtime()->gc.nursery;
-
- if (!nursery.isInside(nsrc->elements())) {
- nursery.removeMallocedBuffer(nsrc->elements());
- return 0;
- }
-
- // Determine if we can use inline data for the target array. If this is
- // possible, the nursery will have picked an allocation size that is large
- // enough.
- size_t nbytes = nsrc->capacity() * nsrc->elementSize();
- if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) {
- ndst->setInlineElements();
- } else {
- MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0);
-
- AutoEnterOOMUnsafeRegion oomUnsafe;
- uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes);
- if (!data)
- oomUnsafe.crash("Failed to allocate unboxed array elements while tenuring.");
- ndst->elements_ = data;
- }
-
- PodCopy(ndst->elements(), nsrc->elements(), nsrc->initializedLength() * nsrc->elementSize());
-
- // Set a forwarding pointer for the element buffers in case they were
- // preserved on the stack by Ion.
- bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t);
- nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct);
-
- return ndst->hasInlineElements() ? 0 : nbytes;
-}
-
-// Possible capacities for unboxed arrays. Some of these capacities might seem
-// a little weird, but were chosen to allow the inline data of objects of each
-// size to be fully utilized for arrays of the various types on both 32 bit and
-// 64 bit platforms.
-//
-// To find the possible inline capacities, the following script was used:
-//
-// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16];
-// var dataSizes = [1, 4, 8];
-// var header32 = 4 * 2 + 4 * 2;
-// var header64 = 8 * 2 + 4 * 2;
-//
-// for (var i = 0; i < fixedSlotCapacities.length; i++) {
-// var nfixed = fixedSlotCapacities[i];
-// var size32 = 4 * 4 + 8 * nfixed - header32;
-// var size64 = 8 * 4 + 8 * nfixed - header64;
-// for (var j = 0; j < dataSizes.length; j++) {
-// print(size32 / dataSizes[j]);
-// print(size64 / dataSizes[j]);
-// }
-// }
-//
-/* static */ const uint32_t
-UnboxedArrayObject::CapacityArray[] = {
- UINT32_MAX, // For CapacityMatchesLengthIndex.
- 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136,
- 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
- 1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336,
- 13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464,
- 46137344, 52428800, 59768832, MaximumCapacity
-};
-
-static const uint32_t
-Pow2CapacityIndexes[] = {
- 2, // 1
- 3, // 2
- 5, // 4
- 8, // 8
- 13, // 16
- 18, // 32
- 21, // 64
- 25, // 128
- 27, // 256
- 28, // 512
- 29, // 1024
- 30, // 2048
- 31, // 4096
- 32, // 8192
- 33, // 16384
- 34, // 32768
- 35, // 65536
- 36, // 131072
- 37, // 262144
- 38, // 524288
- 39 // 1048576
-};
-
-static const uint32_t MebiCapacityIndex = 39;
-
-/* static */ uint32_t
-UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length)
-{
- // Note: the structure and behavior of this method follow along with
- // NativeObject::goodAllocated. Changes to the allocation strategy in one
- // should generally be matched by the other.
-
- // Make sure we have enough space to store all possible values for the capacity index.
- // This ought to be a static_assert, but MSVC doesn't like that.
- MOZ_ASSERT(mozilla::ArrayLength(CapacityArray) - 1 <= (CapacityMask >> CapacityShift));
-
- // The caller should have ensured the capacity is possible for an unboxed array.
- MOZ_ASSERT(capacity <= MaximumCapacity);
-
- static const uint32_t Mebi = 1024 * 1024;
-
- if (capacity <= Mebi) {
- capacity = mozilla::RoundUpPow2(capacity);
-
- // When the required capacity is close to the array length, then round
- // up to the array length itself, as for NativeObject.
- if (length >= capacity && capacity > (length / 3) * 2)
- return CapacityMatchesLengthIndex;
-
- if (capacity < MinimumDynamicCapacity)
- capacity = MinimumDynamicCapacity;
-
- uint32_t bit = mozilla::FloorLog2Size(capacity);
- MOZ_ASSERT(capacity == uint32_t(1 << bit));
- MOZ_ASSERT(bit <= 20);
- MOZ_ASSERT(mozilla::ArrayLength(Pow2CapacityIndexes) == 21);
-
- uint32_t index = Pow2CapacityIndexes[bit];
- MOZ_ASSERT(CapacityArray[index] == capacity);
-
- return index;
- }
-
- MOZ_ASSERT(CapacityArray[MebiCapacityIndex] == Mebi);
-
- for (uint32_t i = MebiCapacityIndex + 1;; i++) {
- if (CapacityArray[i] >= capacity)
- return i;
- }
-
- MOZ_CRASH("Invalid capacity");
-}
-
-/* static */ uint32_t
-UnboxedArrayObject::exactCapacityIndex(uint32_t capacity)
-{
- for (size_t i = CapacityMatchesLengthIndex + 1; i < ArrayLength(CapacityArray); i++) {
- if (CapacityArray[i] == capacity)
- return i;
- }
- MOZ_CRASH();
-}
-
-bool
-UnboxedArrayObject::growElements(ExclusiveContext* cx, size_t cap)
-{
- // The caller should have checked if this capacity is possible for an
- // unboxed array, so the only way this call can fail is from OOM.
- MOZ_ASSERT(cap <= MaximumCapacity);
-
- uint32_t oldCapacity = capacity();
- uint32_t newCapacityIndex = chooseCapacityIndex(cap, length());
- uint32_t newCapacity = computeCapacity(newCapacityIndex, length());
-
- MOZ_ASSERT(oldCapacity < cap);
- MOZ_ASSERT(cap <= newCapacity);
-
- // The allocation size computation below cannot have integer overflows.
- JS_STATIC_ASSERT(MaximumCapacity < UINT32_MAX / sizeof(double));
-
- uint8_t* newElements;
- if (hasInlineElements()) {
- newElements = AllocateObjectBuffer<uint8_t>(cx, this, newCapacity * elementSize());
- if (!newElements)
- return false;
- js_memcpy(newElements, elements(), initializedLength() * elementSize());
- } else {
- newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
- oldCapacity * elementSize(),
- newCapacity * elementSize());
- if (!newElements)
- return false;
- }
-
- elements_ = newElements;
- setCapacityIndex(newCapacityIndex);
-
- return true;
-}
-
-void
-UnboxedArrayObject::shrinkElements(ExclusiveContext* cx, size_t cap)
-{
- if (hasInlineElements())
- return;
-
- uint32_t oldCapacity = capacity();
- uint32_t newCapacityIndex = chooseCapacityIndex(cap, 0);
- uint32_t newCapacity = computeCapacity(newCapacityIndex, 0);
-
- MOZ_ASSERT(cap < oldCapacity);
- MOZ_ASSERT(cap <= newCapacity);
-
- if (newCapacity >= oldCapacity)
- return;
-
- uint8_t* newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
- oldCapacity * elementSize(),
- newCapacity * elementSize());
- if (!newElements)
- return;
-
- elements_ = newElements;
- setCapacityIndex(newCapacityIndex);
-}
-
-bool
-UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id)
-{
- if (JSID_IS_INT(id) && uint32_t(JSID_TO_INT(id)) < initializedLength())
- return true;
- if (JSID_IS_ATOM(id) && JSID_TO_ATOM(id) == cx->names().length)
- return true;
- return false;
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
- HandleId id, MutableHandleObject objp,
- MutableHandleShape propp)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(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
-UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
- Handle<PropertyDescriptor> desc,
- ObjectOpResult& result)
-{
- if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) {
- UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
-
- uint32_t index = JSID_TO_INT(id);
- if (index < nobj->initializedLength()) {
- if (nobj->setElement(cx, index, desc.value()))
- return result.succeed();
- } else if (index == nobj->initializedLength() && index < MaximumCapacity) {
- if (nobj->initializedLength() == nobj->capacity()) {
- if (!nobj->growElements(cx, index + 1))
- return false;
- }
- nobj->setInitializedLength(index + 1);
- if (nobj->initElement(cx, index, desc.value())) {
- if (nobj->length() <= index)
- nobj->setLengthInt32(index + 1);
- return result.succeed();
- }
- nobj->setInitializedLengthNoBarrier(index);
- }
- }
-
- if (!convertToNative(cx, obj))
- return false;
-
- return DefineProperty(cx, obj, id, desc, result);
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(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
-UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
- HandleId id, MutableHandleValue vp)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- if (JSID_IS_INT(id))
- vp.set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
- else
- vp.set(Int32Value(obj->as<UnboxedArrayObject>().length()));
- return true;
- }
-
- RootedObject proto(cx, obj->staticPrototype());
- if (!proto) {
- vp.setUndefined();
- return true;
- }
-
- return GetProperty(cx, proto, receiver, id, vp);
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
- HandleValue receiver, ObjectOpResult& result)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- if (receiver.isObject() && obj == &receiver.toObject()) {
- if (JSID_IS_INT(id)) {
- if (obj->as<UnboxedArrayObject>().setElement(cx, JSID_TO_INT(id), v))
- return result.succeed();
- } else {
- uint32_t len;
- if (!CanonicalizeArrayLengthValue(cx, v, &len))
- return false;
- UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
- if (len < nobj->initializedLength()) {
- nobj->setInitializedLength(len);
- nobj->shrinkElements(cx, len);
- }
- nobj->setLength(cx, len);
- return result.succeed();
- }
-
- if (!convertToNative(cx, obj))
- return false;
- return SetProperty(cx, obj, id, v, receiver, result);
- }
-
- return SetPropertyByDefining(cx, id, v, receiver, result);
- }
-
- return SetPropertyOnProto(cx, obj, id, v, receiver, result);
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandle<PropertyDescriptor> desc)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- if (JSID_IS_INT(id)) {
- desc.value().set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
- desc.setAttributes(JSPROP_ENUMERATE);
- } else {
- desc.value().set(Int32Value(obj->as<UnboxedArrayObject>().length()));
- desc.setAttributes(JSPROP_PERMANENT);
- }
- desc.object().set(obj);
- return true;
- }
-
- desc.object().set(nullptr);
- return true;
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
- ObjectOpResult& result)
-{
- if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
- if (JSID_IS_INT(id) && JSID_TO_INT(id) == int32_t(initlen - 1)) {
- obj->as<UnboxedArrayObject>().setInitializedLength(initlen - 1);
- obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen - 1);
- return result.succeed();
- }
- }
-
- if (!convertToNative(cx, obj))
- return false;
- return DeleteProperty(cx, obj, id, result);
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable)
-{
- if (!convertToNative(cx, obj))
- return false;
- return WatchProperty(cx, obj, id, callable);
-}
-
-/* static */ bool
-UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
- bool enumerableOnly)
-{
- for (size_t i = 0; i < obj->as<UnboxedArrayObject>().initializedLength(); i++) {
- if (!properties.append(INT_TO_JSID(i)))
- return false;
- }
-
- if (!enumerableOnly && !properties.append(NameToId(cx->names().length)))
- return false;
-
- return true;
-}
-
-static const ClassOps UnboxedArrayObjectClassOps = {
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- UnboxedArrayObject::finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- UnboxedArrayObject::trace,
-};
-
-static const ClassExtension UnboxedArrayObjectClassExtension = {
- nullptr, /* weakmapKeyDelegateOp */
- UnboxedArrayObject::objectMoved
-};
-
-static const ObjectOps UnboxedArrayObjectObjectOps = {
- UnboxedArrayObject::obj_lookupProperty,
- UnboxedArrayObject::obj_defineProperty,
- UnboxedArrayObject::obj_hasProperty,
- UnboxedArrayObject::obj_getProperty,
- UnboxedArrayObject::obj_setProperty,
- UnboxedArrayObject::obj_getOwnPropertyDescriptor,
- UnboxedArrayObject::obj_deleteProperty,
- UnboxedArrayObject::obj_watch,
- nullptr, /* No unwatch needed, as watch() converts the object to native */
- nullptr, /* getElements */
- UnboxedArrayObject::obj_enumerate,
- nullptr /* funToString */
-};
-
-const Class UnboxedArrayObject::class_ = {
- "Array",
- Class::NON_NATIVE |
- JSCLASS_SKIP_NURSERY_FINALIZE |
- JSCLASS_BACKGROUND_FINALIZE,
- &UnboxedArrayObjectClassOps,
- JS_NULL_CLASS_SPEC,
- &UnboxedArrayObjectClassExtension,
- &UnboxedArrayObjectObjectOps
-};
-
-/////////////////////////////////////////////////////////////////////
// API
/////////////////////////////////////////////////////////////////////
@@ -1662,31 +946,6 @@ NextValue(Handle<GCVector<Value>> values, size_t* valueCursor)
}
void
-UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
- Handle<GCVector<Value>> values, size_t* valueCursor)
-{
- MOZ_ASSERT(CapacityArray[1] == 0);
- setCapacityIndex(1);
- setInitializedLengthNoBarrier(0);
- setInlineElements();
-
- setLength(cx, NextValue(values, valueCursor).toInt32());
-
- int32_t initlen = NextValue(values, valueCursor).toInt32();
- if (!initlen)
- return;
-
- AutoEnterOOMUnsafeRegion oomUnsafe;
- if (!growElements(cx, initlen))
- oomUnsafe.crash("UnboxedArrayObject::fillAfterConvert");
-
- setInitializedLength(initlen);
-
- for (size_t i = 0; i < size_t(initlen); i++)
- JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
-}
-
-void
UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor)
{
@@ -1695,58 +954,3 @@ UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx,
for (size_t i = 0; i < layout().properties().length(); i++)
JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
}
-
-DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
- ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
- ShouldUpdateTypes);
-
-DenseElementResult
-js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
- uint32_t start, const Value* vp, uint32_t count,
- ShouldUpdateTypes updateTypes)
-{
- SetOrExtendBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, start, vp, count, updateTypes);
- return CallBoxedOrUnboxedSpecialization(functor, obj);
-};
-
-DefineBoxedOrUnboxedFunctor5(MoveBoxedOrUnboxedDenseElements,
- JSContext*, JSObject*, uint32_t, uint32_t, uint32_t);
-
-DenseElementResult
-js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
- uint32_t dstStart, uint32_t srcStart, uint32_t length)
-{
- MoveBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, dstStart, srcStart, length);
- return CallBoxedOrUnboxedSpecialization(functor, obj);
-}
-
-DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements,
- JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t);
-
-DenseElementResult
-js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
- uint32_t dstStart, uint32_t srcStart, uint32_t length)
-{
- CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length);
- return CallBoxedOrUnboxedSpecialization(functor, dst, src);
-}
-
-DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength,
- JSContext*, JSObject*, size_t);
-
-void
-js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
-{
- SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen);
- JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
-}
-
-DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements,
- JSContext*, JSObject*, size_t);
-
-DenseElementResult
-js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen)
-{
- EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen);
- return CallBoxedOrUnboxedSpecialization(functor, obj);
-}