summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2019-06-19 10:56:35 +0000
committerGitHub <noreply@github.com>2019-06-19 10:56:35 +0000
commit276f6583e00edf2a217a3092471ca2aa3aab5a09 (patch)
tree202c502b7e964384fb7f0639b756353374b0c045 /js/src/vm
parent77a9720accf21b790ab88ca4b3658c8412889d30 (diff)
parentfcc11b2fec61c37c90ffe40e8f406eba64654a9c (diff)
downloadUXP-276f6583e00edf2a217a3092471ca2aa3aab5a09.tar
UXP-276f6583e00edf2a217a3092471ca2aa3aab5a09.tar.gz
UXP-276f6583e00edf2a217a3092471ca2aa3aab5a09.tar.lz
UXP-276f6583e00edf2a217a3092471ca2aa3aab5a09.tar.xz
UXP-276f6583e00edf2a217a3092471ca2aa3aab5a09.zip
Merge pull request #1137 from MoonchildProductions/remove-unboxed-checked
Remove unboxed (checked branch)
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/Interpreter-inl.h2
-rw-r--r--js/src/vm/Interpreter.cpp16
-rw-r--r--js/src/vm/JSONParser.cpp4
-rw-r--r--js/src/vm/NativeObject-inl.h32
-rw-r--r--js/src/vm/NativeObject.h15
-rw-r--r--js/src/vm/ObjectGroup.cpp103
-rw-r--r--js/src/vm/ObjectGroup.h10
-rw-r--r--js/src/vm/Opcodes.h12
-rw-r--r--js/src/vm/ReceiverGuard.cpp8
-rw-r--r--js/src/vm/Stack.cpp2
-rw-r--r--js/src/vm/Stack.h2
-rw-r--r--js/src/vm/TypeInference.cpp6
-rw-r--r--js/src/vm/TypeInference.h4
-rw-r--r--js/src/vm/UnboxedObject-inl.h663
-rw-r--r--js/src/vm/UnboxedObject.cpp826
-rw-r--r--js/src/vm/UnboxedObject.h207
16 files changed, 88 insertions, 1824 deletions
diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h
index 710f1d89b..a2c8e220a 100644
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -593,7 +593,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t
JSOp op = JSOp(*pc);
MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
- MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
+ MOZ_ASSERT(obj->is<ArrayObject>());
if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 3cf2deb83..74a1ef3e9 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1916,6 +1916,7 @@ CASE(EnableInterruptsPseudoOpcode)
/* Various 1-byte no-ops. */
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
+CASE(JSOP_UNUSED126)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED209)
CASE(JSOP_UNUSED210)
@@ -3636,7 +3637,6 @@ CASE(JSOP_NEWINIT)
END_CASE(JSOP_NEWINIT)
CASE(JSOP_NEWARRAY)
-CASE(JSOP_SPREADCALLARRAY)
{
uint32_t length = GET_UINT32(REGS.pc);
JSObject* obj = NewArrayOperation(cx, script, REGS.pc, length);
@@ -4933,7 +4933,7 @@ js::NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
newKind = TenuredObject;
}
- RootedObject obj(cx);
+ RootedPlainObject obj(cx);
if (*pc == JSOP_NEWOBJECT) {
RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
@@ -5001,9 +5001,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject;
-
- if (group->maybeUnboxedLayout())
- return UnboxedArrayObject::create(cx, group, length, newKind);
}
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
@@ -5014,9 +5011,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32
MOZ_ASSERT(obj->isSingleton());
} else {
obj->setGroup(group);
-
- if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
- preliminaryObjects->registerNewObject(obj);
}
return obj;
@@ -5029,12 +5023,6 @@ js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject)
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
- if (templateObject->is<UnboxedArrayObject>()) {
- uint32_t length = templateObject->as<UnboxedArrayObject>().length();
- RootedObjectGroup group(cx, templateObject->group());
- return UnboxedArrayObject::create(cx, group, length, newKind);
- }
-
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(),
nullptr, newKind);
if (!obj)
diff --git a/js/src/vm/JSONParser.cpp b/js/src/vm/JSONParser.cpp
index 01883bb15..e50da3bc4 100644
--- a/js/src/vm/JSONParser.cpp
+++ b/js/src/vm/JSONParser.cpp
@@ -606,8 +606,8 @@ JSONParserBase::finishArray(MutableHandleValue vp, ElementVector& elements)
{
MOZ_ASSERT(&elements == &stack.back().elements());
- JSObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(),
- GenericObject);
+ ArrayObject* obj = ObjectGroup::newArrayObject(cx, elements.begin(), elements.length(),
+ GenericObject);
if (!obj)
return false;
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index 48a42a8db..052a3385c 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -235,6 +235,38 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t
return DenseElementResult::Success;
}
+inline DenseElementResult
+NativeObject::setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp,
+ uint32_t count,
+ ShouldUpdateTypes updateTypes)
+{
+ if (denseElementsAreFrozen())
+ return DenseElementResult::Incomplete;
+
+ if (is<ArrayObject>() &&
+ !as<ArrayObject>().lengthIsWritable() &&
+ start + count >= as<ArrayObject>().length())
+ {
+ return DenseElementResult::Incomplete;
+ }
+
+ DenseElementResult result = ensureDenseElements(cx, start, count);
+ if (result != DenseElementResult::Success)
+ return result;
+
+ if (is<ArrayObject>() && start + count >= as<ArrayObject>().length())
+ as<ArrayObject>().setLengthInt32(start + count);
+
+ if (updateTypes == ShouldUpdateTypes::DontUpdate && !shouldConvertDoubleElements()) {
+ copyDenseElements(start, vp, count);
+ } else {
+ for (size_t i = 0; i < count; i++)
+ setDenseElementWithType(cx, start + i, vp[i]);
+ }
+
+ return DenseElementResult::Success;
+}
+
inline Value
NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
{
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index 4dbc167ab..da4f873a6 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -339,16 +339,19 @@ IsObjectValueInCompartment(const Value& v, JSCompartment* comp);
#endif
// Operations which change an object's dense elements can either succeed, fail,
-// or be unable to complete. For native objects, the latter is used when the
-// object's elements must become sparse instead. The enum below is used for
-// such operations, and for similar operations on unboxed arrays and methods
-// that work on both kinds of objects.
+// or be unable to complete. The latter is used when the object's elements must
+// become sparse instead. The enum below is used for such operations.
enum class DenseElementResult {
Failure,
Success,
Incomplete
};
+enum class ShouldUpdateTypes {
+ Update,
+ DontUpdate
+};
+
/*
* NativeObject specifies the internal implementation of a native object.
*
@@ -1147,6 +1150,10 @@ class NativeObject : public ShapedObject
elementsRangeWriteBarrierPost(dstStart, count);
}
+ inline DenseElementResult
+ setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, uint32_t count,
+ ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
+
bool shouldConvertDoubleElements() {
return getElementsHeader()->shouldConvertDoubleElements();
}
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index 46159a972..63ac33eea 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -774,7 +774,7 @@ GetValueTypeForTable(const Value& v)
return type;
}
-/* static */ JSObject*
+/* static */ ArrayObject*
ObjectGroup::newArrayObject(ExclusiveContext* cx,
const Value* vp, size_t length,
NewObjectKind newKind, NewArrayKind arrayKind)
@@ -838,56 +838,13 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx,
AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
- if (elementType != TypeSet::UnknownType()) {
- // Keep track of the initial objects we create with this type.
- // If the initial ones have a consistent shape and property types, we
- // will try to use an unboxed layout for the group.
- PreliminaryObjectArrayWithTemplate* preliminaryObjects =
- cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
- if (!preliminaryObjects)
- return nullptr;
- group->setPreliminaryObjects(preliminaryObjects);
- }
-
if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
return nullptr;
}
// The type of the elements being added will already be reflected in type
- // information, but make sure when creating an unboxed array that the
- // common element type is suitable for the unboxed representation.
+ // information.
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate;
- if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length))
- return nullptr;
- if (group->maybePreliminaryObjects())
- group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
- if (group->maybeUnboxedLayout()) {
- switch (group->unboxedLayout().elementType()) {
- case JSVAL_TYPE_BOOLEAN:
- if (elementType != TypeSet::BooleanType())
- updateTypes = ShouldUpdateTypes::Update;
- break;
- case JSVAL_TYPE_INT32:
- if (elementType != TypeSet::Int32Type())
- updateTypes = ShouldUpdateTypes::Update;
- break;
- case JSVAL_TYPE_DOUBLE:
- if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType())
- updateTypes = ShouldUpdateTypes::Update;
- break;
- case JSVAL_TYPE_STRING:
- if (elementType != TypeSet::StringType())
- updateTypes = ShouldUpdateTypes::Update;
- break;
- case JSVAL_TYPE_OBJECT:
- if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked())
- updateTypes = ShouldUpdateTypes::Update;
- break;
- default:
- MOZ_CRASH();
- }
- }
-
return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes);
}
@@ -897,49 +854,15 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
{
MOZ_ASSERT(source->group() != target->group());
- if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>())
+ if (!target->is<ArrayObject>() || !source->is<ArrayObject>()) {
return true;
-
- if (target->group()->maybePreliminaryObjects()) {
- bool force = IsInsideNursery(source);
- target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force);
}
- if (target->is<ArrayObject>()) {
- ObjectGroup* sourceGroup = source->group();
+ source->setGroup(target->group());
- if (source->is<UnboxedArrayObject>()) {
- Shape* shape = target->as<ArrayObject>().lastProperty();
- if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape))
- return false;
- } else if (source->is<ArrayObject>()) {
- source->setGroup(target->group());
- } else {
- return true;
- }
-
- if (sourceGroup->maybePreliminaryObjects())
- sourceGroup->maybePreliminaryObjects()->unregisterObject(source);
- if (target->group()->maybePreliminaryObjects())
- target->group()->maybePreliminaryObjects()->registerNewObject(source);
-
- for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) {
- Value v = source->as<ArrayObject>().getDenseElement(i);
- AddTypePropertyId(cx, source->group(), source, JSID_VOID, v);
- }
-
- return true;
- }
-
- if (target->is<UnboxedArrayObject>()) {
- if (!source->is<UnboxedArrayObject>())
- return true;
- if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32)
- return true;
- if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE)
- return true;
-
- return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group());
+ for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) {
+ Value v = source->as<ArrayObject>().getDenseElement(i);
+ AddTypePropertyId(cx, source->group(), source, JSID_VOID, v);
}
return true;
@@ -1503,18 +1426,6 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
}
}
- if (kind == JSProto_Array &&
- (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) &&
- cx->options().unboxedArrays())
- {
- PreliminaryObjectArrayWithTemplate* preliminaryObjects =
- cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
- if (preliminaryObjects)
- res->setPreliminaryObjects(preliminaryObjects);
- else
- cx->recoverFromOutOfMemory();
- }
-
if (!table->add(p, key, res)) {
ReportOutOfMemory(cx);
return nullptr;
diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h
index 4e24de9f1..553cb8366 100644
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -505,11 +505,11 @@ class ObjectGroup : public gc::TenuredCell
UnknownIndex // Make an array with an unknown element type.
};
- // Create an ArrayObject or UnboxedArrayObject with the specified elements
- // and a group specialized for the elements.
- static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
- NewObjectKind newKind,
- NewArrayKind arrayKind = NewArrayKind::Normal);
+ // Create an ArrayObject with the specified elements and a group specialized
+ // for the elements.
+ static ArrayObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
+ NewObjectKind newKind,
+ NewArrayKind arrayKind = NewArrayKind::Normal);
// Create a PlainObject or UnboxedPlainObject with the specified properties
// and a group specialized for those properties.
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index 4b044c8d8..095ef57ae 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1281,17 +1281,7 @@
* Stack: receiver, obj, propval => obj[propval]
*/ \
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \
- /*
- * Pushes newly created array for a spread call onto the stack. This has
- * the same semantics as JSOP_NEWARRAY, but is distinguished to avoid
- * using unboxed arrays in spread calls, which would make compiling spread
- * calls in baseline more complex.
- * Category: Literals
- * Type: Array
- * Operands: uint32_t length
- * Stack: => obj
- */ \
- macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 5, 0, 1, JOF_UINT32) \
+ macro(JSOP_UNUSED126, 126, "unused126", NULL, 5, 0, 1, JOF_UINT32) \
\
/*
* Defines the given function on the current scope.
diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp
index 11c2d0727..e37bf8ee5 100644
--- a/js/src/vm/ReceiverGuard.cpp
+++ b/js/src/vm/ReceiverGuard.cpp
@@ -19,7 +19,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj)
group = obj->group();
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
shape = expando->lastProperty();
- } else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
+ } else if (obj->is<TypedObject>()) {
group = obj->group();
} else {
shape = obj->maybeShape();
@@ -34,7 +34,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
const Class* clasp = group->clasp();
if (clasp == &UnboxedPlainObject::class_) {
// Keep both group and shape.
- } else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) {
+ } else if (IsTypedObjectClass(clasp)) {
this->shape = nullptr;
} else {
this->group = nullptr;
@@ -49,8 +49,8 @@ HeapReceiverGuard::keyBits(JSObject* obj)
// Both the group and shape need to be guarded for unboxed plain objects.
return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
}
- if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
- // Only the group needs to be guarded for unboxed arrays and typed objects.
+ if (obj->is<TypedObject>()) {
+ // Only the group needs to be guarded for typed objects.
return 2;
}
// Other objects only need the shape to be guarded.
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 87e95c893..c5f2cf5f3 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -82,7 +82,7 @@ InterpreterFrame::isNonGlobalEvalFrame() const
return isEvalFrame() && script()->bodyScope()->as<EvalScope>().isNonGlobal();
}
-JSObject*
+ArrayObject*
InterpreterFrame::createRestParameter(JSContext* cx)
{
MOZ_ASSERT(script()->hasRest());
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index 552738d89..dc9306c99 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -523,7 +523,7 @@ class InterpreterFrame
ArgumentsObject& argsObj() const;
void initArgsObj(ArgumentsObject& argsobj);
- JSObject* createRestParameter(JSContext* cx);
+ ArrayObject* createRestParameter(JSContext* cx);
/*
* Environment chain
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 9e0342382..0551e2c58 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2505,7 +2505,7 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid
bool
js::ClassCanHaveExtraProperties(const Class* clasp)
{
- if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
+ if (clasp == &UnboxedPlainObject::class_)
return false;
return clasp->getResolve()
|| clasp->getOpsLookupProperty()
@@ -3393,7 +3393,7 @@ JSFunction::setTypeForScriptedFunction(ExclusiveContext* cx, HandleFunction fun,
/////////////////////////////////////////////////////////////////////
void
-PreliminaryObjectArray::registerNewObject(JSObject* res)
+PreliminaryObjectArray::registerNewObject(PlainObject* res)
{
// The preliminary object pointers are weak, and won't be swept properly
// during nursery collections, so the preliminary objects need to be
@@ -3411,7 +3411,7 @@ PreliminaryObjectArray::registerNewObject(JSObject* res)
}
void
-PreliminaryObjectArray::unregisterObject(JSObject* obj)
+PreliminaryObjectArray::unregisterObject(PlainObject* obj)
{
for (size_t i = 0; i < COUNT; i++) {
if (objects[i] == obj) {
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 04fed448c..94ce7e871 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -814,8 +814,8 @@ class PreliminaryObjectArray
public:
PreliminaryObjectArray() = default;
- void registerNewObject(JSObject* res);
- void unregisterObject(JSObject* obj);
+ void registerNewObject(PlainObject* res);
+ void unregisterObject(PlainObject* obj);
JSObject* get(size_t i) const {
MOZ_ASSERT(i < COUNT);
diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h
index 93ad7bf28..c1468a5b1 100644
--- a/js/src/vm/UnboxedObject-inl.h
+++ b/js/src/vm/UnboxedObject-inl.h
@@ -172,669 +172,6 @@ UnboxedPlainObject::layout() const
return group()->unboxedLayout();
}
-/////////////////////////////////////////////////////////////////////
-// UnboxedArrayObject
-/////////////////////////////////////////////////////////////////////
-
-inline const UnboxedLayout&
-UnboxedArrayObject::layout() const
-{
- return group()->unboxedLayout();
-}
-
-inline void
-UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
-{
- if (length > INT32_MAX) {
- // Track objects with overflowing lengths in type information.
- MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
- }
-
- length_ = length;
-}
-
-inline void
-UnboxedArrayObject::setInitializedLength(uint32_t initlen)
-{
- if (initlen < initializedLength()) {
- switch (elementType()) {
- case JSVAL_TYPE_STRING:
- for (size_t i = initlen; i < initializedLength(); i++)
- triggerPreBarrier<JSVAL_TYPE_STRING>(i);
- break;
- case JSVAL_TYPE_OBJECT:
- for (size_t i = initlen; i < initializedLength(); i++)
- triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
- break;
- default:
- MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
- }
- }
- setInitializedLengthNoBarrier(initlen);
-}
-
-template <JSValueType Type>
-inline bool
-UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- MOZ_ASSERT(Type == elementType());
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
- return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
-}
-
-template <JSValueType Type>
-inline void
-UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- MOZ_ASSERT(Type == elementType());
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
- return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true);
-}
-
-template <JSValueType Type>
-inline bool
-UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- MOZ_ASSERT(Type == elementType());
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
- return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
-}
-
-template <JSValueType Type>
-inline void
-UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v)
-{
- MOZ_ASSERT(index < initializedLength());
- MOZ_ASSERT(Type == elementType());
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
- return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
-}
-
-template <JSValueType Type>
-inline Value
-UnboxedArrayObject::getElementSpecific(size_t index)
-{
- MOZ_ASSERT(index < initializedLength());
- MOZ_ASSERT(Type == elementType());
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
- return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false);
-}
-
-template <JSValueType Type>
-inline void
-UnboxedArrayObject::triggerPreBarrier(size_t index)
-{
- MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type));
-
- uint8_t* p = elements() + index * UnboxedTypeSize(Type);
-
- switch (Type) {
- case JSVAL_TYPE_STRING: {
- JSString** np = reinterpret_cast<JSString**>(p);
- JSString::writeBarrierPre(*np);
- break;
- }
-
- case JSVAL_TYPE_OBJECT: {
- JSObject** np = reinterpret_cast<JSObject**>(p);
- JSObject::writeBarrierPre(*np);
- break;
- }
-
- default:
- MOZ_CRASH("Bad type");
- }
-}
-
-/////////////////////////////////////////////////////////////////////
-// Combined methods for NativeObject and UnboxedArrayObject accesses.
-/////////////////////////////////////////////////////////////////////
-
-static inline bool
-HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
-{
- return obj->isNative() || obj->is<UnboxedArrayObject>();
-}
-
-static inline size_t
-GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
-{
- if (obj->isNative())
- return obj->as<NativeObject>().getDenseInitializedLength();
- if (obj->is<UnboxedArrayObject>())
- return obj->as<UnboxedArrayObject>().initializedLength();
- return 0;
-}
-
-static inline size_t
-GetAnyBoxedOrUnboxedCapacity(JSObject* obj)
-{
- if (obj->isNative())
- return obj->as<NativeObject>().getDenseCapacity();
- if (obj->is<UnboxedArrayObject>())
- return obj->as<UnboxedArrayObject>().capacity();
- return 0;
-}
-
-static inline Value
-GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
-{
- if (obj->isNative())
- return obj->as<NativeObject>().getDenseElement(index);
- return obj->as<UnboxedArrayObject>().getElement(index);
-}
-
-static inline size_t
-GetAnyBoxedOrUnboxedArrayLength(JSObject* obj)
-{
- if (obj->is<ArrayObject>())
- return obj->as<ArrayObject>().length();
- return obj->as<UnboxedArrayObject>().length();
-}
-
-static inline void
-SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length)
-{
- if (obj->is<ArrayObject>()) {
- MOZ_ASSERT(length >= obj->as<ArrayObject>().length());
- obj->as<ArrayObject>().setLength(cx, length);
- } else {
- MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length());
- obj->as<UnboxedArrayObject>().setLength(cx, length);
- }
-}
-
-static inline bool
-SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
-{
- if (obj->isNative()) {
- obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
- return true;
- }
- return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
-}
-
-static inline bool
-InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
-{
- if (obj->isNative()) {
- obj->as<NativeObject>().initDenseElementWithType(cx, index, value);
- return true;
- }
- return obj->as<UnboxedArrayObject>().initElement(cx, index, value);
-}
-
-/////////////////////////////////////////////////////////////////////
-// Template methods for NativeObject and UnboxedArrayObject accesses.
-/////////////////////////////////////////////////////////////////////
-
-static inline JSValueType
-GetBoxedOrUnboxedType(JSObject* obj)
-{
- if (obj->isNative())
- return JSVAL_TYPE_MAGIC;
- return obj->as<UnboxedArrayObject>().elementType();
-}
-
-template <JSValueType Type>
-static inline bool
-HasBoxedOrUnboxedDenseElements(JSObject* obj)
-{
- if (Type == JSVAL_TYPE_MAGIC)
- return obj->isNative();
- return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type;
-}
-
-template <JSValueType Type>
-static inline size_t
-GetBoxedOrUnboxedInitializedLength(JSObject* obj)
-{
- if (Type == JSVAL_TYPE_MAGIC)
- return obj->as<NativeObject>().getDenseInitializedLength();
- return obj->as<UnboxedArrayObject>().initializedLength();
-}
-
-template <JSValueType Type>
-static inline DenseElementResult
-SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
-{
- size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
- if (Type == JSVAL_TYPE_MAGIC) {
- obj->as<NativeObject>().setDenseInitializedLength(initlen);
- if (initlen < oldInitlen)
- obj->as<NativeObject>().shrinkElements(cx, initlen);
- } else {
- obj->as<UnboxedArrayObject>().setInitializedLength(initlen);
- if (initlen < oldInitlen)
- obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen);
- }
- return DenseElementResult::Success;
-}
-
-template <JSValueType Type>
-static inline size_t
-GetBoxedOrUnboxedCapacity(JSObject* obj)
-{
- if (Type == JSVAL_TYPE_MAGIC)
- return obj->as<NativeObject>().getDenseCapacity();
- return obj->as<UnboxedArrayObject>().capacity();
-}
-
-template <JSValueType Type>
-static inline Value
-GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
-{
- if (Type == JSVAL_TYPE_MAGIC)
- return obj->as<NativeObject>().getDenseElement(index);
- return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index);
-}
-
-template <JSValueType Type>
-static inline void
-SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value)
-{
- if (Type == JSVAL_TYPE_MAGIC)
- obj->as<NativeObject>().setDenseElement(index, value);
- else
- obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value);
-}
-
-template <JSValueType Type>
-static inline bool
-SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
-{
- if (Type == JSVAL_TYPE_MAGIC) {
- obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
- return true;
- }
- return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value);
-}
-
-template <JSValueType Type>
-static inline DenseElementResult
-EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
-{
- if (Type == JSVAL_TYPE_MAGIC) {
- if (!obj->as<ArrayObject>().ensureElements(cx, count))
- return DenseElementResult::Failure;
- } else {
- if (obj->as<UnboxedArrayObject>().capacity() < count) {
- if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
- return DenseElementResult::Failure;
- }
- }
- return DenseElementResult::Success;
-}
-
-template <JSValueType Type>
-static inline DenseElementResult
-SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
- uint32_t start, const Value* vp, uint32_t count,
- ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update)
-{
- if (Type == JSVAL_TYPE_MAGIC) {
- NativeObject* nobj = &obj->as<NativeObject>();
-
- if (nobj->denseElementsAreFrozen())
- return DenseElementResult::Incomplete;
-
- if (obj->is<ArrayObject>() &&
- !obj->as<ArrayObject>().lengthIsWritable() &&
- start + count >= obj->as<ArrayObject>().length())
- {
- return DenseElementResult::Incomplete;
- }
-
- DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
- if (result != DenseElementResult::Success)
- return result;
-
- if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
- obj->as<ArrayObject>().setLengthInt32(start + count);
-
- if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
- nobj->copyDenseElements(start, vp, count);
- } else {
- for (size_t i = 0; i < count; i++)
- nobj->setDenseElementWithType(cx, start + i, vp[i]);
- }
-
- return DenseElementResult::Success;
- }
-
- UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
-
- if (start > nobj->initializedLength())
- return DenseElementResult::Incomplete;
-
- if (start + count >= UnboxedArrayObject::MaximumCapacity)
- return DenseElementResult::Incomplete;
-
- if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count))
- return DenseElementResult::Failure;
-
- size_t oldInitlen = nobj->initializedLength();
-
- // Overwrite any existing elements covered by the new range. If we fail
- // after this point due to some incompatible type being written to the
- // object's elements, afterwards the contents will be different from when
- // we started. The caller must retry the operation using a generic path,
- // which will overwrite the already-modified elements as well as the ones
- // that were left alone.
- size_t i = 0;
- if (updateTypes == ShouldUpdateTypes::DontUpdate) {
- for (size_t j = start; i < count && j < oldInitlen; i++, j++)
- nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]);
- } else {
- for (size_t j = start; i < count && j < oldInitlen; i++, j++) {
- if (!nobj->setElementSpecific<Type>(cx, j, vp[i]))
- return DenseElementResult::Incomplete;
- }
- }
-
- if (i != count) {
- obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
- if (updateTypes == ShouldUpdateTypes::DontUpdate) {
- for (; i < count; i++)
- nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]);
- } else {
- for (; i < count; i++) {
- if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) {
- nobj->setInitializedLengthNoBarrier(oldInitlen);
- return DenseElementResult::Incomplete;
- }
- }
- }
- }
-
- if (start + count >= nobj->length())
- nobj->setLength(cx, start + count);
-
- return DenseElementResult::Success;
-}
-
-template <JSValueType Type>
-static inline DenseElementResult
-MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart,
- uint32_t length)
-{
- MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
-
- if (Type == JSVAL_TYPE_MAGIC) {
- if (obj->as<NativeObject>().denseElementsAreFrozen())
- return DenseElementResult::Incomplete;
-
- if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
- return DenseElementResult::Failure;
- obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
- } else {
- uint8_t* data = obj->as<UnboxedArrayObject>().elements();
- size_t elementSize = UnboxedTypeSize(Type);
-
- if (UnboxedTypeNeedsPreBarrier(Type) &&
- JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier())
- {
- // Trigger pre barriers on any elements we are overwriting. See
- // NativeObject::moveDenseElements. No post barrier is needed as
- // only whole cell post barriers are used with unboxed objects.
- for (size_t i = 0; i < length; i++)
- obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i);
- }
-
- memmove(data + dstStart * elementSize,
- data + srcStart * elementSize,
- length * elementSize);
- }
-
- return DenseElementResult::Success;
-}
-
-template <JSValueType DstType, JSValueType SrcType>
-static inline DenseElementResult
-CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
- uint32_t dstStart, uint32_t srcStart, uint32_t length)
-{
- MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
- MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
- MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
- MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
- MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
-
- SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
-
- if (DstType == JSVAL_TYPE_MAGIC) {
- if (SrcType == JSVAL_TYPE_MAGIC) {
- const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
- dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
- } else {
- for (size_t i = 0; i < length; i++) {
- Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
- dst->as<NativeObject>().initDenseElement(dstStart + i, v);
- }
- }
- } else if (DstType == SrcType) {
- uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
- uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
- size_t elementSize = UnboxedTypeSize(DstType);
-
- memcpy(dstData + dstStart * elementSize,
- srcData + srcStart * elementSize,
- length * elementSize);
-
- // Add a store buffer entry if we might have copied a nursery pointer to dst.
- if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
- dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst);
- } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
- uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
- uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
-
- for (size_t i = 0; i < length; i++) {
- int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t));
- *reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v;
- }
- } else {
- for (size_t i = 0; i < length; i++) {
- Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
- dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v);
- }
- }
-
- return DenseElementResult::Success;
-}
-
-/////////////////////////////////////////////////////////////////////
-// Dispatch to specialized methods based on the type of an object.
-/////////////////////////////////////////////////////////////////////
-
-// Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h.
-// The clang-cl front end defines _MSC_VER, but still requires the explicit
-// template declaration, so we must test for __clang__ here as well.
-#if defined(_MSC_VER) && !defined(__clang__)
-# define DEPENDENT_TEMPLATE_HINT
-#else
-# define DEPENDENT_TEMPLATE_HINT template
-#endif
-
-// Function to dispatch a method specialized to whatever boxed or unboxed dense
-// elements which an input object has.
-template <typename F>
-DenseElementResult
-CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
-{
- if (!HasAnyBoxedOrUnboxedDenseElements(obj))
- return DenseElementResult::Incomplete;
- switch (GetBoxedOrUnboxedType(obj)) {
- case JSVAL_TYPE_MAGIC:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
- case JSVAL_TYPE_BOOLEAN:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
- case JSVAL_TYPE_INT32:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
- case JSVAL_TYPE_DOUBLE:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
- case JSVAL_TYPE_STRING:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
- case JSVAL_TYPE_OBJECT:
- return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
- default:
- MOZ_CRASH();
- }
-}
-
-// As above, except the specialization can reflect the unboxed type of two objects.
-template <typename F>
-DenseElementResult
-CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2)
-{
- if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2))
- return DenseElementResult::Incomplete;
-
-#define SPECIALIZE_OBJ2(TYPE) \
- switch (GetBoxedOrUnboxedType(obj2)) { \
- case JSVAL_TYPE_MAGIC: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \
- case JSVAL_TYPE_BOOLEAN: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \
- case JSVAL_TYPE_INT32: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \
- case JSVAL_TYPE_DOUBLE: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \
- case JSVAL_TYPE_STRING: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \
- case JSVAL_TYPE_OBJECT: \
- return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \
- default: \
- MOZ_CRASH(); \
- }
-
- switch (GetBoxedOrUnboxedType(obj1)) {
- case JSVAL_TYPE_MAGIC:
- SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC)
- case JSVAL_TYPE_BOOLEAN:
- SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN)
- case JSVAL_TYPE_INT32:
- SPECIALIZE_OBJ2(JSVAL_TYPE_INT32)
- case JSVAL_TYPE_DOUBLE:
- SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE)
- case JSVAL_TYPE_STRING:
- SPECIALIZE_OBJ2(JSVAL_TYPE_STRING)
- case JSVAL_TYPE_OBJECT:
- SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT)
- default:
- MOZ_CRASH();
- }
-
-#undef SPECIALIZE_OBJ2
-}
-
-#undef DEPENDENT_TEMPLATE_HINT
-
-#define DefineBoxedOrUnboxedFunctor1(Signature, A) \
-struct Signature ## Functor { \
- A a; \
- explicit Signature ## Functor(A a) \
- : a(a) \
- {} \
- template <JSValueType Type> \
- DenseElementResult operator()() { \
- return Signature<Type>(a); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C) \
-struct Signature ## Functor { \
- A a; B b; C c; \
- Signature ## Functor(A a, B b, C c) \
- : a(a), b(b), c(c) \
- {} \
- template <JSValueType Type> \
- DenseElementResult operator()() { \
- return Signature<Type>(a, b, c); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D) \
-struct Signature ## Functor { \
- A a; B b; C c; D d; \
- Signature ## Functor(A a, B b, C c, D d) \
- : a(a), b(b), c(c), d(d) \
- {} \
- template <JSValueType Type> \
- DenseElementResult operator()() { \
- return Signature<Type>(a, b, c, d); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D) \
-struct Signature ## Functor { \
- A a; B b; C c; D d; \
- Signature ## Functor(A a, B b, C c, D d) \
- : a(a), b(b), c(c), d(d) \
- {} \
- template <JSValueType TypeOne, JSValueType TypeTwo> \
- DenseElementResult operator()() { \
- return Signature<TypeOne, TypeTwo>(a, b, c, d); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \
-struct Signature ## Functor { \
- A a; B b; C c; D d; E e; \
- Signature ## Functor(A a, B b, C c, D d, E e) \
- : a(a), b(b), c(c), d(d), e(e) \
- {} \
- template <JSValueType Type> \
- DenseElementResult operator()() { \
- return Signature<Type>(a, b, c, d, e); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \
-struct Signature ## Functor { \
- A a; B b; C c; D d; E e; F f; \
- Signature ## Functor(A a, B b, C c, D d, E e, F f) \
- : a(a), b(b), c(c), d(d), e(e), f(f) \
- {} \
- template <JSValueType Type> \
- DenseElementResult operator()() { \
- return Signature<Type>(a, b, c, d, e, f); \
- } \
-}
-
-#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \
-struct Signature ## Functor { \
- A a; B b; C c; D d; E e; F f; \
- Signature ## Functor(A a, B b, C c, D d, E e, F f) \
- : a(a), b(b), c(c), d(d), e(e), f(f) \
- {} \
- template <JSValueType TypeOne, JSValueType TypeTwo> \
- DenseElementResult operator()() { \
- return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f); \
- } \
-}
-
-DenseElementResult
-SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
- uint32_t start, const Value* vp, uint32_t count,
- ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
-
-DenseElementResult
-MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
- uint32_t dstStart, uint32_t srcStart, uint32_t length);
-
-DenseElementResult
-CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
- uint32_t dstStart, uint32_t srcStart, uint32_t length);
-
-void
-SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
-
-DenseElementResult
-EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
-
} // namespace js
#endif // vm_UnboxedObject_inl_h
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);
-}
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h
index 779dd14c7..ba66434bc 100644
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -96,17 +96,11 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
// from an array of values.
GCPtrJitCode constructorCode_;
- // The following members are only used for unboxed arrays.
-
- // The type of array elements.
- JSValueType elementType_;
-
public:
UnboxedLayout()
: nativeGroup_(nullptr), nativeShape_(nullptr),
allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
- size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr),
- elementType_(JSVAL_TYPE_MAGIC)
+ size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr)
{}
bool initProperties(const PropertyVector& properties, size_t size) {
@@ -114,10 +108,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
return properties_.appendAll(properties);
}
- void initArray(JSValueType elementType) {
- elementType_ = elementType;
- }
-
~UnboxedLayout() {
if (newScript_)
newScript_->clear();
@@ -130,10 +120,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
constructorCode_.init(nullptr);
}
- bool isArray() const {
- return elementType_ != JSVAL_TYPE_MAGIC;
- }
-
void detachFromCompartment();
const PropertyVector& properties() const {
@@ -201,10 +187,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
constructorCode_ = code;
}
- JSValueType elementType() const {
- return elementType_;
- }
-
inline gc::AllocKind getAllocKind() const;
void trace(JSTracer* trc);
@@ -324,193 +306,6 @@ UnboxedLayout::getAllocKind() const
return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
}
-// Class for an array object using an unboxed representation.
-class UnboxedArrayObject : public JSObject
-{
- // Elements pointer for the object.
- uint8_t* elements_;
-
- // The nominal array length. This always fits in an int32_t.
- uint32_t length_;
-
- // Value indicating the allocated capacity and initialized length of the
- // array. The top CapacityBits bits are an index into CapacityArray, which
- // indicates the elements capacity. The low InitializedLengthBits store the
- // initialized length of the array.
- uint32_t capacityIndexAndInitializedLength_;
-
- // If the elements are inline, they will point here.
- uint8_t inlineElements_[1];
-
- public:
- static const uint32_t CapacityBits = 6;
- static const uint32_t CapacityShift = 26;
-
- static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
- static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
-
- static const uint32_t MaximumCapacity = InitializedLengthMask;
- static const uint32_t MinimumDynamicCapacity = 8;
-
- static const uint32_t CapacityArray[];
-
- // Capacity index which indicates the array's length is also its capacity.
- static const uint32_t CapacityMatchesLengthIndex = 0;
-
- private:
- static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
- if (index == CapacityMatchesLengthIndex)
- return length;
- return CapacityArray[index];
- }
-
- static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
- static uint32_t exactCapacityIndex(uint32_t capacity);
-
- 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();
- }
-
- JSValueType elementType() const {
- return layoutDontCheckGeneration().elementType();
- }
-
- uint32_t elementSize() const {
- return UnboxedTypeSize(elementType());
- }
-
- static bool convertToNative(JSContext* cx, JSObject* obj);
- static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group,
- uint32_t length, NewObjectKind newKind,
- uint32_t maxLength = MaximumCapacity);
-
- static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
- ObjectGroup* group, Shape* shape);
- bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group);
-
- void fillAfterConvert(ExclusiveContext* cx,
- Handle<GCVector<Value>> values, size_t* valueCursor);
-
- static void trace(JSTracer* trc, JSObject* object);
- static void objectMoved(JSObject* obj, const JSObject* old);
- static void finalize(FreeOp* fop, JSObject* obj);
-
- static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
- gc::AllocKind allocKind);
-
- uint8_t* elements() {
- return elements_;
- }
-
- bool hasInlineElements() const {
- return elements_ == &inlineElements_[0];
- }
-
- uint32_t length() const {
- return length_;
- }
-
- uint32_t initializedLength() const {
- return capacityIndexAndInitializedLength_ & InitializedLengthMask;
- }
-
- uint32_t capacityIndex() const {
- return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
- }
-
- uint32_t capacity() const {
- return computeCapacity(capacityIndex(), length());
- }
-
- bool containsProperty(ExclusiveContext* cx, jsid id);
-
- bool setElement(ExclusiveContext* cx, size_t index, const Value& v);
- bool initElement(ExclusiveContext* cx, size_t index, const Value& v);
- void initElementNoTypeChange(size_t index, const Value& v);
- Value getElement(size_t index);
-
- template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index,
- const Value& v);
- template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v);
- template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index,
- const Value& v);
- template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v);
- template <JSValueType Type> inline Value getElementSpecific(size_t index);
- template <JSValueType Type> inline void triggerPreBarrier(size_t index);
-
- bool growElements(ExclusiveContext* cx, size_t cap);
- void shrinkElements(ExclusiveContext* cx, size_t cap);
-
- static uint32_t offsetOfElements() {
- return offsetof(UnboxedArrayObject, elements_);
- }
- static uint32_t offsetOfLength() {
- return offsetof(UnboxedArrayObject, length_);
- }
- static uint32_t offsetOfCapacityIndexAndInitializedLength() {
- return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
- }
- static uint32_t offsetOfInlineElements() {
- return offsetof(UnboxedArrayObject, inlineElements_);
- }
-
- void setLengthInt32(uint32_t length) {
- MOZ_ASSERT(length <= INT32_MAX);
- length_ = length;
- }
-
- inline void setLength(ExclusiveContext* cx, uint32_t len);
- inline void setInitializedLength(uint32_t initlen);
-
- inline void setInitializedLengthNoBarrier(uint32_t initlen) {
- MOZ_ASSERT(initlen <= InitializedLengthMask);
- capacityIndexAndInitializedLength_ =
- (capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
- }
-
- private:
- void setInlineElements() {
- elements_ = &inlineElements_[0];
- }
-
- void setCapacityIndex(uint32_t index) {
- MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
- capacityIndexAndInitializedLength_ =
- (index << CapacityShift) | initializedLength();
- }
-};
-
} // namespace js
namespace JS {