Remove functors for array natives.

This commit is contained in:
wolfbeast 2019-06-12 11:03:35 +00:00 committed by Roy Tam
commit 18166cf949
3 changed files with 59 additions and 230 deletions

View file

@ -333,37 +333,31 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver,
return true;
}
template <JSValueType Type>
DenseElementResult
GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp)
static bool
GetDenseElements(NativeObject* aobj, uint32_t length, Value* vp)
{
MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj));
if (length > aobj->as<NativeObject>().getDenseInitializedLength())
return DenseElementResult::Incomplete;
if (length > aobj->getDenseInitializedLength())
return false;
for (size_t i = 0; i < length; i++) {
vp[i] = aobj->as<NativeObject>().getDenseElement(i);
vp[i] = aobj->getDenseElement(i);
// No other indexed properties so hole => undefined.
if (vp[i].isMagic(JS_ELEMENTS_HOLE))
vp[i] = UndefinedValue();
}
return DenseElementResult::Success;
return true;
}
DefineBoxedOrUnboxedFunctor3(GetBoxedOrUnboxedDenseElements,
JSObject*, uint32_t, Value*);
bool
js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length, Value* vp)
{
if (!ObjectMayHaveExtraIndexedProperties(aobj)) {
GetBoxedOrUnboxedDenseElementsFunctor functor(aobj, length, vp);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, aobj);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
if (GetDenseElements(&aobj->as<NativeObject>(), length, vp))
return true;
}
if (aobj->is<ArgumentsObject>()) {
@ -1061,32 +1055,32 @@ struct StringSeparatorOp
}
};
template <typename SeparatorOp, JSValueType Type>
static DenseElementResult
ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length,
template <typename SeparatorOp>
static bool
ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, uint64_t length,
StringBuffer& sb, uint32_t* numProcessed)
{
// This loop handles all elements up to initializedLength. If
// length > initLength we rely on the second loop to add the
// other elements.
MOZ_ASSERT(*numProcessed == 0);
uint32_t initLength = Min<uint32_t>(obj->as<NativeObject>().getDenseInitializedLength(),
uint32_t initLength = Min<uint32_t>(obj->getDenseInitializedLength(),
length);
while (*numProcessed < initLength) {
if (!CheckForInterrupt(cx))
return DenseElementResult::Failure;
return false;
Value elem = obj->as<NativeObject>().getDenseElement(*numProcessed);
if (elem.isString()) {
if (!sb.append(elem.toString()))
return DenseElementResult::Failure;
return false;
} else if (elem.isNumber()) {
if (!NumberValueToStringBuffer(cx, elem, sb))
return DenseElementResult::Failure;
return false;
} else if (elem.isBoolean()) {
if (!BooleanToStringBuffer(elem.toBoolean(), sb))
return DenseElementResult::Failure;
return false;
} else if (elem.isObject() || elem.isSymbol()) {
/*
* Object stringifying could modify the initialized length or make
@ -1102,32 +1096,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_
}
if (++(*numProcessed) != length && !sepOp(cx, sb))
return DenseElementResult::Failure;
return false;
}
return DenseElementResult::Incomplete;
return true;
}
template <typename SeparatorOp>
struct ArrayJoinDenseKernelFunctor {
JSContext* cx;
SeparatorOp sepOp;
HandleObject obj;
uint32_t length;
StringBuffer& sb;
uint32_t* numProcessed;
ArrayJoinDenseKernelFunctor(JSContext* cx, SeparatorOp sepOp, HandleObject obj,
uint32_t length, StringBuffer& sb, uint32_t* numProcessed)
: cx(cx), sepOp(sepOp), obj(obj), length(length), sb(sb), numProcessed(numProcessed)
{}
template <JSValueType Type>
DenseElementResult operator()() {
return ArrayJoinDenseKernel<SeparatorOp, Type>(cx, sepOp, obj, length, sb, numProcessed);
}
};
template <typename SeparatorOp>
static bool
ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t length,
@ -1136,10 +1110,10 @@ ArrayJoinKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_t len
uint32_t i = 0;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
ArrayJoinDenseKernelFunctor<SeparatorOp> functor(cx, sepOp, obj, length, sb, &i);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
if (result == DenseElementResult::Failure)
if (!ArrayJoinDenseKernel<SeparatorOp>(cx, sepOp, obj.as<NativeObject>(), length, sb, &i))
{
return false;
}
}
if (i != length) {
@ -1260,7 +1234,7 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
}
// Step 11
JSString *str = sb.finishString();
JSString* str = sb.finishString();
if (!str)
return false;
@ -1360,15 +1334,14 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start,
return true;
}
template <JSValueType Type>
DenseElementResult
ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
static DenseElementResult
ArrayReverseDenseKernel(JSContext* cx, HandleNativeObject obj, uint32_t length)
{
/* An empty array or an array with no elements is already reversed. */
if (length == 0 || obj->as<NativeObject>().getDenseInitializedLength() == 0)
if (length == 0 || obj->getDenseInitializedLength() == 0)
return DenseElementResult::Success;
if (obj->as<NativeObject>().denseElementsAreFrozen())
if (obj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
/*
@ -1380,26 +1353,26 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
* holes in the array at its start) and ensure that the capacity is
* sufficient to hold all the elements in the array if it were full.
*/
DenseElementResult result = obj->as<NativeObject>().ensureDenseElements(cx, length, 0);
DenseElementResult result = obj->ensureDenseElements(cx, length, 0);
if (result != DenseElementResult::Success)
return result;
/* Fill out the array's initialized length to its proper length. */
obj->as<NativeObject>().ensureDenseInitializedLength(cx, length, 0);
obj->ensureDenseInitializedLength(cx, length, 0);
RootedValue origlo(cx), orighi(cx);
uint32_t lo = 0, hi = length - 1;
for (; lo < hi; lo++, hi--) {
origlo = obj->as<NativeObject>().getDenseElement(lo);
orighi = obj->as<NativeObject>().getDenseElement(hi);
obj->as<NativeObject>().setDenseElement(lo, orighi);
origlo = obj->getDenseElement(lo);
orighi = obj->getDenseElement(hi);
obj->setDenseElement(lo, orighi);
if (orighi.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo)))
{
return DenseElementResult::Failure;
}
obj->as<NativeObject>().setDenseElement(hi, origlo);
obj->setDenseElement(hi, origlo);
if (origlo.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi)))
{
@ -1410,9 +1383,6 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel,
JSContext*, HandleObject, uint32_t);
bool
js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
{
@ -1427,8 +1397,8 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
return false;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
ArrayReverseDenseKernelFunctor functor(cx, obj, len);
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
DenseElementResult result =
ArrayReverseDenseKernel(cx, obj.as<NativeObject>(), uint32_t(len));
if (result != DenseElementResult::Incomplete) {
/*
* Per ECMA-262, don't update the length of the array, even if the new
@ -2137,33 +2107,20 @@ js::array_pop(JSContext* cx, unsigned argc, Value* vp)
return SetLengthProperty(cx, obj, index);
}
template <JSValueType Type>
static inline DenseElementResult
ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj)
void
js::ArrayShiftMoveElements(NativeObject* obj)
{
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
size_t initlen = obj->as<NativeObject>().getDenseInitializedLength();
size_t initlen = obj->getDenseInitializedLength();
MOZ_ASSERT(initlen > 0);
/*
* At this point the length and initialized length have already been
* decremented and the result fetched, so just shift the array elements
* themselves.
*/
obj->as<NativeObject>().moveDenseElementsNoPreBarrier(0, 1, initlen);
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor1(ShiftMoveBoxedOrUnboxedDenseElements, JSObject*);
void
js::ArrayShiftMoveElements(JSObject* obj)
{
MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
ShiftMoveBoxedOrUnboxedDenseElementsFunctor functor(obj);
JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
obj->moveDenseElementsNoPreBarrier(0, 1, initlen - 1);
}
static inline void
@ -2175,8 +2132,7 @@ SetInitializedLength(JSContext* cx, NativeObject* obj, size_t initlen)
obj->shrinkElements(cx, initlen);
}
template <JSValueType Type>
DenseElementResult
static DenseElementResult
ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
if (ObjectMayHaveExtraIndexedProperties(obj))
@ -2205,9 +2161,6 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval)
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(ArrayShiftDenseKernel,
JSContext*, HandleObject, MutableHandleValue);
/* ES5 15.4.4.9 */
bool
js::array_shift(JSContext* cx, unsigned argc, Value* vp)
@ -2239,8 +2192,7 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp)
uint32_t newlen = len - 1;
/* Fast paths. */
ArrayShiftDenseKernelFunctor functor(cx, obj, args.rval());
DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
DenseElementResult result = ArrayShiftDenseKernel(cx, obj, args.rval());
if (result != DenseElementResult::Incomplete) {
if (result == DenseElementResult::Failure)
return false;
@ -2999,11 +2951,10 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp)
return true;
}
template <JSValueType Type>
DenseElementResult
ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t endArg, JSObject* result)
static bool
ArraySliceDenseKernel(JSContext* cx, ArrayObject* arr, int32_t beginArg, int32_t endArg, ArrayObject* result)
{
int32_t length = obj->as<ArrayObject>().length();
int32_t length = arr->length();
uint32_t begin = NormalizeSliceTerm(beginArg, length);
uint32_t end = NormalizeSliceTerm(endArg, length);
@ -3011,34 +2962,33 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en
if (begin > end)
begin = end;
size_t initlen = obj->as<NativeObject>().getDenseInitializedLength();
size_t initlen = arr->getDenseInitializedLength();
size_t count = Min<size_t>(initlen - begin, end - begin);
if (initlen > begin) {
if (count) {
if (!result->as<ArrayObject>().ensureElements(cx, count))
return DenseElementResult::Failure;
CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count);
if (!result->ensureElements(cx, count))
return false;
CopyBoxedOrUnboxedDenseElements(cx, result, arr, 0, begin, count);
}
}
MOZ_ASSERT(count >= result->as<ArrayObject>().length());
result->as<ArrayObject>().setLength(cx, count);
MOZ_ASSERT(count >= result->length());
result->setLength(cx, count);
return DenseElementResult::Success;
return true;
}
DefineBoxedOrUnboxedFunctor5(ArraySliceDenseKernel,
JSContext*, JSObject*, int32_t, int32_t, JSObject*);
JSObject*
js::array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end,
HandleObject result)
{
if (result && IsArraySpecies(cx, obj)) {
ArraySliceDenseKernelFunctor functor(cx, obj, begin, end, result);
DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result);
MOZ_ASSERT(rv != DenseElementResult::Incomplete);
return rv == DenseElementResult::Success ? result : nullptr;
if (!ArraySliceDenseKernel(cx, &obj->as<ArrayObject>(), begin, end,
&result->as<ArrayObject>()))
{
return nullptr;
}
return result;
}
// Slower path if the JIT wasn't able to allocate an object inline.