зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1176451 - Optimize Array.concat when used on different types of boxed vs. unboxed arrays, r=jandem.
This commit is contained in:
Родитель
fe87d76bdf
Коммит
0f1cdda9e1
|
@ -9541,7 +9541,7 @@ TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
|
GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
|
||||||
MutableHandleObject res)
|
MutableHandleObject res, bool* skipAttach)
|
||||||
{
|
{
|
||||||
// Check for natives to which template objects can be attached. This is
|
// Check for natives to which template objects can be attached. This is
|
||||||
// done to provide templates to Ion for inlining these natives later on.
|
// done to provide templates to Ion for inlining these natives later on.
|
||||||
|
@ -9557,10 +9557,17 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
|
||||||
count = args[0].toInt32();
|
count = args[0].toInt32();
|
||||||
|
|
||||||
if (count <= ArrayObject::EagerAllocationMaxLength) {
|
if (count <= ArrayObject::EagerAllocationMaxLength) {
|
||||||
|
ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array);
|
||||||
|
if (!group)
|
||||||
|
return false;
|
||||||
|
if (group->maybePreliminaryObjects()) {
|
||||||
|
*skipAttach = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// With this and other array templates, set forceAnalyze so that we
|
// With this and other array templates, set forceAnalyze so that we
|
||||||
// don't end up with a template whose structure might change later.
|
// don't end up with a template whose structure might change later.
|
||||||
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject,
|
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject));
|
||||||
/* forceAnalyze = */ true));
|
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -9568,17 +9575,30 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (native == js::array_concat || native == js::array_slice) {
|
if (native == js::array_concat || native == js::array_slice) {
|
||||||
if (args.thisv().isObject() && !args.thisv().toObject().isSingleton()) {
|
if (args.thisv().isObject()) {
|
||||||
res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0,
|
JSObject* obj = &args.thisv().toObject();
|
||||||
TenuredObject, /* forceAnalyze = */ true));
|
if (!obj->isSingleton()) {
|
||||||
if (!res)
|
if (obj->group()->maybePreliminaryObjects()) {
|
||||||
return false;
|
*skipAttach = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0,
|
||||||
|
TenuredObject));
|
||||||
|
return !!res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (native == js::str_split && args.length() == 1 && args[0].isString()) {
|
if (native == js::str_split && args.length() == 1 && args[0].isString()) {
|
||||||
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject,
|
ObjectGroup* group = ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array);
|
||||||
/* forceAnalyze = */ true));
|
if (!group)
|
||||||
|
return false;
|
||||||
|
if (group->maybePreliminaryObjects()) {
|
||||||
|
*skipAttach = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, 0, TenuredObject));
|
||||||
if (!res)
|
if (!res)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -9877,9 +9897,15 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||||
|
|
||||||
RootedObject templateObject(cx);
|
RootedObject templateObject(cx);
|
||||||
if (MOZ_LIKELY(!isSpread)) {
|
if (MOZ_LIKELY(!isSpread)) {
|
||||||
|
bool skipAttach = false;
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject))
|
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
|
||||||
return false;
|
return false;
|
||||||
|
if (skipAttach) {
|
||||||
|
*handled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects());
|
||||||
}
|
}
|
||||||
|
|
||||||
JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
|
JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
|
||||||
|
|
|
@ -7222,22 +7222,23 @@ CodeGenerator::visitArrayConcat(LArrayConcat* lir)
|
||||||
// inline and pass it to the stub. Else, we just pass nullptr and the stub falls
|
// inline and pass it to the stub. Else, we just pass nullptr and the stub falls
|
||||||
// back to a slow path.
|
// back to a slow path.
|
||||||
Label fail, call;
|
Label fail, call;
|
||||||
if (lir->mir()->unboxedType() == JSVAL_TYPE_MAGIC) {
|
if (lir->mir()->unboxedThis()) {
|
||||||
masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1);
|
|
||||||
masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
|
|
||||||
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
|
|
||||||
|
|
||||||
masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1);
|
|
||||||
masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
|
|
||||||
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
|
|
||||||
} else {
|
|
||||||
masm.load32(Address(lhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1);
|
masm.load32(Address(lhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1);
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1);
|
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1);
|
||||||
masm.branch32(Assembler::NotEqual, Address(lhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail);
|
masm.branch32(Assembler::NotEqual, Address(lhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail);
|
||||||
|
} else {
|
||||||
|
masm.loadPtr(Address(lhs, NativeObject::offsetOfElements()), temp1);
|
||||||
|
masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
|
||||||
|
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
|
||||||
|
}
|
||||||
|
if (lir->mir()->unboxedArg()) {
|
||||||
masm.load32(Address(rhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1);
|
masm.load32(Address(rhs, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), temp1);
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1);
|
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp1);
|
||||||
masm.branch32(Assembler::NotEqual, Address(rhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail);
|
masm.branch32(Assembler::NotEqual, Address(rhs, UnboxedArrayObject::offsetOfLength()), temp1, &fail);
|
||||||
|
} else {
|
||||||
|
masm.loadPtr(Address(rhs, NativeObject::offsetOfElements()), temp1);
|
||||||
|
masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
|
||||||
|
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to allocate an object.
|
// Try to allocate an object.
|
||||||
|
|
|
@ -864,9 +864,10 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
|
||||||
if (!thisTypes || !argTypes)
|
if (!thisTypes || !argTypes)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
|
||||||
const Class* clasp = thisTypes->getKnownClass(constraints());
|
const Class* thisClasp = thisTypes->getKnownClass(constraints());
|
||||||
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
|
if (thisClasp != &ArrayObject::class_ && thisClasp != &UnboxedArrayObject::class_)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
bool unboxedThis = (thisClasp == &UnboxedArrayObject::class_);
|
||||||
if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
|
if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
|
||||||
OBJECT_FLAG_LENGTH_OVERFLOW))
|
OBJECT_FLAG_LENGTH_OVERFLOW))
|
||||||
{
|
{
|
||||||
|
@ -874,8 +875,10 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argTypes->getKnownClass(constraints()) != clasp)
|
const Class* argClasp = argTypes->getKnownClass(constraints());
|
||||||
|
if (argClasp != &ArrayObject::class_ && argClasp != &UnboxedArrayObject::class_)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
|
bool unboxedArg = (argClasp == &UnboxedArrayObject::class_);
|
||||||
if (argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
|
if (argTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
|
||||||
OBJECT_FLAG_LENGTH_OVERFLOW))
|
OBJECT_FLAG_LENGTH_OVERFLOW))
|
||||||
{
|
{
|
||||||
|
@ -883,15 +886,6 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
|
||||||
return InliningStatus_NotInlined;
|
return InliningStatus_NotInlined;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
|
|
||||||
if (clasp == &UnboxedArrayObject::class_) {
|
|
||||||
unboxedType = UnboxedArrayElementType(constraints(), thisArg, nullptr);
|
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC)
|
|
||||||
return InliningStatus_NotInlined;
|
|
||||||
if (unboxedType != UnboxedArrayElementType(constraints(), objArg, nullptr))
|
|
||||||
return InliningStatus_NotInlined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch out for indexed properties on the prototype.
|
// Watch out for indexed properties on the prototype.
|
||||||
if (ArrayPrototypeHasIndexedProperty(this, script())) {
|
if (ArrayPrototypeHasIndexedProperty(this, script())) {
|
||||||
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
|
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
|
||||||
|
@ -951,7 +945,7 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
|
||||||
MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(), thisArg, objArg,
|
MArrayConcat* ins = MArrayConcat::New(alloc(), constraints(), thisArg, objArg,
|
||||||
templateObj,
|
templateObj,
|
||||||
templateObj->group()->initialHeap(constraints()),
|
templateObj->group()->initialHeap(constraints()),
|
||||||
unboxedType);
|
unboxedThis, unboxedArg);
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
|
|
||||||
|
|
|
@ -9186,14 +9186,16 @@ class MArrayConcat
|
||||||
{
|
{
|
||||||
CompilerObject templateObj_;
|
CompilerObject templateObj_;
|
||||||
gc::InitialHeap initialHeap_;
|
gc::InitialHeap initialHeap_;
|
||||||
JSValueType unboxedType_;
|
bool unboxedThis_, unboxedArg_;
|
||||||
|
|
||||||
MArrayConcat(CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs,
|
MArrayConcat(CompilerConstraintList* constraints, MDefinition* lhs, MDefinition* rhs,
|
||||||
JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
|
JSObject* templateObj, gc::InitialHeap initialHeap,
|
||||||
|
bool unboxedThis, bool unboxedArg)
|
||||||
: MBinaryInstruction(lhs, rhs),
|
: MBinaryInstruction(lhs, rhs),
|
||||||
templateObj_(templateObj),
|
templateObj_(templateObj),
|
||||||
initialHeap_(initialHeap),
|
initialHeap_(initialHeap),
|
||||||
unboxedType_(unboxedType)
|
unboxedThis_(unboxedThis),
|
||||||
|
unboxedArg_(unboxedArg)
|
||||||
{
|
{
|
||||||
setResultType(MIRType_Object);
|
setResultType(MIRType_Object);
|
||||||
setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj));
|
setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj));
|
||||||
|
@ -9205,10 +9207,10 @@ class MArrayConcat
|
||||||
static MArrayConcat* New(TempAllocator& alloc, CompilerConstraintList* constraints,
|
static MArrayConcat* New(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||||
MDefinition* lhs, MDefinition* rhs,
|
MDefinition* lhs, MDefinition* rhs,
|
||||||
JSObject* templateObj, gc::InitialHeap initialHeap,
|
JSObject* templateObj, gc::InitialHeap initialHeap,
|
||||||
JSValueType unboxedType)
|
bool unboxedThis, bool unboxedArg)
|
||||||
{
|
{
|
||||||
return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj,
|
return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj,
|
||||||
initialHeap, unboxedType);
|
initialHeap, unboxedThis, unboxedArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* templateObj() const {
|
JSObject* templateObj() const {
|
||||||
|
@ -9219,12 +9221,17 @@ class MArrayConcat
|
||||||
return initialHeap_;
|
return initialHeap_;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValueType unboxedType() const {
|
bool unboxedThis() const {
|
||||||
return unboxedType_;
|
return unboxedThis_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unboxedArg() const {
|
||||||
|
return unboxedArg_;
|
||||||
}
|
}
|
||||||
|
|
||||||
AliasSet getAliasSet() const override {
|
AliasSet getAliasSet() const override {
|
||||||
return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) |
|
return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedThis() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) |
|
||||||
|
AliasSet::BoxedOrUnboxedElements(unboxedArg() ? JSVAL_TYPE_INT32 : JSVAL_TYPE_MAGIC) |
|
||||||
AliasSet::ObjectFields);
|
AliasSet::ObjectFields);
|
||||||
}
|
}
|
||||||
bool possiblyCalls() const override {
|
bool possiblyCalls() const override {
|
||||||
|
|
|
@ -2563,40 +2563,41 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <JSValueType Type>
|
template <JSValueType TypeOne, JSValueType TypeTwo>
|
||||||
DenseElementResult
|
DenseElementResult
|
||||||
ArrayConcatDenseKernel(JSContext* cx, JSObject* obj1, JSObject* obj2, JSObject* result)
|
ArrayConcatDenseKernel(JSContext* cx, JSObject* obj1, JSObject* obj2, JSObject* result)
|
||||||
{
|
{
|
||||||
uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength<Type>(obj1);
|
uint32_t initlen1 = GetBoxedOrUnboxedInitializedLength<TypeOne>(obj1);
|
||||||
MOZ_ASSERT(initlen1 == GetAnyBoxedOrUnboxedArrayLength(obj1));
|
MOZ_ASSERT(initlen1 == GetAnyBoxedOrUnboxedArrayLength(obj1));
|
||||||
|
|
||||||
uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength<Type>(obj2);
|
uint32_t initlen2 = GetBoxedOrUnboxedInitializedLength<TypeTwo>(obj2);
|
||||||
MOZ_ASSERT(initlen2 == GetAnyBoxedOrUnboxedArrayLength(obj2));
|
MOZ_ASSERT(initlen2 == GetAnyBoxedOrUnboxedArrayLength(obj2));
|
||||||
|
|
||||||
/* No overflow here due to nelements limit. */
|
/* No overflow here due to nelements limit. */
|
||||||
uint32_t len = initlen1 + initlen2;
|
uint32_t len = initlen1 + initlen2;
|
||||||
|
|
||||||
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<Type>(result) == 0);
|
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<TypeOne>(result) == 0);
|
||||||
|
|
||||||
if (!EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, len))
|
DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<TypeOne>(cx, result, len);
|
||||||
return DenseElementResult::Failure;
|
if (rv != DenseElementResult::Success)
|
||||||
|
return rv;
|
||||||
|
|
||||||
CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj1, 0, 0, initlen1);
|
CopyBoxedOrUnboxedDenseElements<TypeOne, TypeOne>(cx, result, obj1, 0, 0, initlen1);
|
||||||
CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj2, initlen1, 0, initlen2);
|
CopyBoxedOrUnboxedDenseElements<TypeOne, TypeTwo>(cx, result, obj2, initlen1, 0, initlen2);
|
||||||
|
|
||||||
SetAnyBoxedOrUnboxedArrayLength(cx, result, len);
|
SetAnyBoxedOrUnboxedArrayLength(cx, result, len);
|
||||||
return DenseElementResult::Success;
|
return DenseElementResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineBoxedOrUnboxedFunctor4(ArrayConcatDenseKernel,
|
DefineBoxedOrUnboxedFunctorPair4(ArrayConcatDenseKernel,
|
||||||
JSContext*, JSObject*, JSObject*, JSObject*);
|
JSContext*, JSObject*, JSObject*, JSObject*);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::array_concat_dense(JSContext* cx, HandleObject obj1, HandleObject obj2,
|
js::array_concat_dense(JSContext* cx, HandleObject obj1, HandleObject obj2,
|
||||||
HandleObject result)
|
HandleObject result)
|
||||||
{
|
{
|
||||||
ArrayConcatDenseKernelFunctor functor(cx, obj1, obj2, result);
|
ArrayConcatDenseKernelFunctor functor(cx, obj1, obj2, result);
|
||||||
DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, result);
|
DenseElementResult rv = CallBoxedOrUnboxedSpecialization(functor, obj1, obj2);
|
||||||
MOZ_ASSERT(rv != DenseElementResult::Incomplete);
|
MOZ_ASSERT(rv != DenseElementResult::Incomplete);
|
||||||
return rv == DenseElementResult::Success;
|
return rv == DenseElementResult::Success;
|
||||||
}
|
}
|
||||||
|
@ -2627,17 +2628,63 @@ js::array_concat(JSContext* cx, unsigned argc, Value* vp)
|
||||||
narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, initlen);
|
narr = NewFullyAllocatedArrayTryReuseGroup(cx, aobj, initlen);
|
||||||
if (!narr)
|
if (!narr)
|
||||||
return false;
|
return false;
|
||||||
|
CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen);
|
||||||
SetAnyBoxedOrUnboxedArrayLength(cx, narr, length);
|
SetAnyBoxedOrUnboxedArrayLength(cx, narr, length);
|
||||||
|
|
||||||
DebugOnly<DenseElementResult> result =
|
|
||||||
CopyAnyBoxedOrUnboxedDenseElements(cx, narr, aobj, 0, 0, initlen);
|
|
||||||
MOZ_ASSERT(result.value == DenseElementResult::Success);
|
|
||||||
|
|
||||||
args.rval().setObject(*narr);
|
args.rval().setObject(*narr);
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
return true;
|
return true;
|
||||||
argc--;
|
argc--;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
if (length == initlen) {
|
||||||
|
while (argc) {
|
||||||
|
HandleValue v = HandleValue::fromMarkedLocation(p);
|
||||||
|
if (!v.isObject())
|
||||||
|
break;
|
||||||
|
RootedObject obj(cx, &v.toObject());
|
||||||
|
|
||||||
|
// This should be IsConcatSpreadable
|
||||||
|
if (!IsArray(obj, cx) || ObjectMayHaveExtraIndexedProperties(obj))
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint32_t argLength;
|
||||||
|
if (!GetLengthProperty(cx, obj, &argLength))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
|
||||||
|
if (argLength != initlen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DenseElementResult result =
|
||||||
|
EnsureAnyBoxedOrUnboxedDenseElements(cx, narr, length + argLength);
|
||||||
|
if (result == DenseElementResult::Failure)
|
||||||
|
return false;
|
||||||
|
if (result == DenseElementResult::Incomplete)
|
||||||
|
break;
|
||||||
|
|
||||||
|
SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length + argLength);
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
for (size_t i = 0; i < initlen; i++) {
|
||||||
|
Value v = GetAnyBoxedOrUnboxedDenseElement(obj, i);
|
||||||
|
if (!InitAnyBoxedOrUnboxedDenseElement(cx, narr, length + i, v)) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
SetAnyBoxedOrUnboxedInitializedLength(cx, narr, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
length += argLength;
|
||||||
|
SetAnyBoxedOrUnboxedArrayLength(cx, narr, length);
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
narr = NewDenseEmptyArray(cx);
|
narr = NewDenseEmptyArray(cx);
|
||||||
if (!narr)
|
if (!narr)
|
||||||
|
@ -2934,9 +2981,10 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en
|
||||||
if (initlen > begin) {
|
if (initlen > begin) {
|
||||||
size_t count = Min<size_t>(initlen - begin, end - begin);
|
size_t count = Min<size_t>(initlen - begin, end - begin);
|
||||||
if (count) {
|
if (count) {
|
||||||
if (!EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count))
|
DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count);
|
||||||
return DenseElementResult::Failure;
|
if (rv != DenseElementResult::Success)
|
||||||
CopyBoxedOrUnboxedDenseElements<Type>(cx, result, obj, 0, begin, count);
|
return rv;
|
||||||
|
CopyBoxedOrUnboxedDenseElements<Type, Type>(cx, result, obj, 0, begin, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,12 @@ UnboxedArrayObject::triggerPreBarrier(size_t index)
|
||||||
// Combined methods for NativeObject and UnboxedArrayObject accesses.
|
// Combined methods for NativeObject and UnboxedArrayObject accesses.
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
|
||||||
|
{
|
||||||
|
return obj->isNative() || obj->is<UnboxedArrayObject>();
|
||||||
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
|
GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
|
||||||
{
|
{
|
||||||
|
@ -330,6 +336,16 @@ SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, con
|
||||||
return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
|
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.
|
// Template methods for NativeObject and UnboxedArrayObject accesses.
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
@ -417,19 +433,19 @@ SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const
|
||||||
}
|
}
|
||||||
|
|
||||||
template <JSValueType Type>
|
template <JSValueType Type>
|
||||||
static inline bool
|
static inline DenseElementResult
|
||||||
EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
|
EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
|
||||||
{
|
{
|
||||||
if (Type == JSVAL_TYPE_MAGIC) {
|
if (Type == JSVAL_TYPE_MAGIC) {
|
||||||
if (!obj->as<ArrayObject>().ensureElements(cx, count))
|
if (!obj->as<ArrayObject>().ensureElements(cx, count))
|
||||||
return false;
|
return DenseElementResult::Failure;
|
||||||
} else {
|
} else {
|
||||||
if (obj->as<UnboxedArrayObject>().capacity() < count) {
|
if (obj->as<UnboxedArrayObject>().capacity() < count) {
|
||||||
if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
|
if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
|
||||||
return false;
|
return DenseElementResult::Failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return DenseElementResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <JSValueType Type>
|
template <JSValueType Type>
|
||||||
|
@ -547,33 +563,54 @@ MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart,
|
||||||
return DenseElementResult::Success;
|
return DenseElementResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <JSValueType Type>
|
template <JSValueType DstType, JSValueType SrcType>
|
||||||
static inline DenseElementResult
|
static inline DenseElementResult
|
||||||
CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
|
CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
|
||||||
uint32_t dstStart, uint32_t srcStart, uint32_t length)
|
uint32_t dstStart, uint32_t srcStart, uint32_t length)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(src));
|
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
|
||||||
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(dst));
|
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
|
||||||
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<Type>(dst) == dstStart);
|
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
|
||||||
MOZ_ASSERT(GetBoxedOrUnboxedCapacity<Type>(dst) >= length);
|
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(src) >= srcStart + length);
|
||||||
|
MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
|
||||||
|
|
||||||
SetBoxedOrUnboxedInitializedLength<Type>(cx, dst, dstStart + length);
|
SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
|
||||||
|
|
||||||
if (Type == JSVAL_TYPE_MAGIC) {
|
if (DstType == JSVAL_TYPE_MAGIC) {
|
||||||
const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
|
if (SrcType == JSVAL_TYPE_MAGIC) {
|
||||||
dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
|
const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
|
||||||
} else {
|
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* dstData = dst->as<UnboxedArrayObject>().elements();
|
||||||
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
|
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
|
||||||
size_t elementSize = UnboxedTypeSize(Type);
|
size_t elementSize = UnboxedTypeSize(DstType);
|
||||||
|
|
||||||
memcpy(dstData + dstStart * elementSize,
|
memcpy(dstData + dstStart * elementSize,
|
||||||
srcData + srcStart * elementSize,
|
srcData + srcStart * elementSize,
|
||||||
length * elementSize);
|
length * elementSize);
|
||||||
|
|
||||||
// Add a store buffer entry if we might have copied a nursery pointer to dst.
|
// Add a store buffer entry if we might have copied a nursery pointer to dst.
|
||||||
if (UnboxedTypeNeedsPostBarrier(Type) && !IsInsideNursery(dst))
|
if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
|
||||||
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(dst);
|
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCellFromMainThread(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;
|
return DenseElementResult::Success;
|
||||||
|
@ -596,19 +633,70 @@ template <typename F>
|
||||||
DenseElementResult
|
DenseElementResult
|
||||||
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
|
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
|
||||||
{
|
{
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(obj))
|
if (!HasAnyBoxedOrUnboxedDenseElements(obj))
|
||||||
|
return DenseElementResult::Incomplete;
|
||||||
|
switch (GetBoxedOrUnboxedType(obj)) {
|
||||||
|
case JSVAL_TYPE_MAGIC:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_BOOLEAN>(obj))
|
case JSVAL_TYPE_BOOLEAN:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_INT32>(obj))
|
case JSVAL_TYPE_INT32:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_DOUBLE>(obj))
|
case JSVAL_TYPE_DOUBLE:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_STRING>(obj))
|
case JSVAL_TYPE_STRING:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
|
||||||
if (HasBoxedOrUnboxedDenseElements<JSVAL_TYPE_OBJECT>(obj))
|
case JSVAL_TYPE_OBJECT:
|
||||||
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
|
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
|
||||||
return DenseElementResult::Incomplete;
|
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
|
#undef DEPENDENT_TEMPLATE_HINT
|
||||||
|
@ -649,6 +737,18 @@ struct Signature ## Functor { \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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) \
|
#define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E) \
|
||||||
struct Signature ## Functor { \
|
struct Signature ## Functor { \
|
||||||
A a; B b; C c; D d; E e; \
|
A a; B b; C c; D d; E e; \
|
||||||
|
@ -673,6 +773,18 @@ struct Signature ## Functor { \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
DenseElementResult
|
||||||
SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
|
SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
|
||||||
uint32_t start, const Value* vp, uint32_t count,
|
uint32_t start, const Value* vp, uint32_t count,
|
||||||
|
@ -689,7 +801,7 @@ CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
|
||||||
void
|
void
|
||||||
SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
|
SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
|
||||||
|
|
||||||
bool
|
DenseElementResult
|
||||||
EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
|
EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
@ -1671,11 +1671,9 @@ CombineArrayObjectElements(ExclusiveContext* cx, ArrayObject* obj, JSValueType*
|
||||||
{
|
{
|
||||||
if (obj->inDictionaryMode() ||
|
if (obj->inDictionaryMode() ||
|
||||||
obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
|
obj->lastProperty()->propid() != AtomToId(cx->names().length) ||
|
||||||
!obj->lastProperty()->previous()->isEmptyShape() ||
|
!obj->lastProperty()->previous()->isEmptyShape())
|
||||||
!obj->getDenseInitializedLength())
|
|
||||||
{
|
{
|
||||||
// Only use an unboxed representation if the object has at
|
// Only use an unboxed representation if the object has no properties.
|
||||||
// least one element, and no properties.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1830,6 +1828,8 @@ UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
|
||||||
setLength(cx, NextValue(values, valueCursor).toInt32());
|
setLength(cx, NextValue(values, valueCursor).toInt32());
|
||||||
|
|
||||||
int32_t initlen = NextValue(values, valueCursor).toInt32();
|
int32_t initlen = NextValue(values, valueCursor).toInt32();
|
||||||
|
if (!initlen)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!growElements(cx, initlen))
|
if (!growElements(cx, initlen))
|
||||||
CrashAtUnhandlableOOM("UnboxedArrayObject::fillAfterConvert");
|
CrashAtUnhandlableOOM("UnboxedArrayObject::fillAfterConvert");
|
||||||
|
@ -2055,15 +2055,15 @@ js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
|
||||||
return CallBoxedOrUnboxedSpecialization(functor, obj);
|
return CallBoxedOrUnboxedSpecialization(functor, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineBoxedOrUnboxedFunctor6(CopyBoxedOrUnboxedDenseElements,
|
DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements,
|
||||||
JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t);
|
JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t);
|
||||||
|
|
||||||
DenseElementResult
|
DenseElementResult
|
||||||
js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
|
js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
|
||||||
uint32_t dstStart, uint32_t srcStart, uint32_t length)
|
uint32_t dstStart, uint32_t srcStart, uint32_t length)
|
||||||
{
|
{
|
||||||
CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length);
|
CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length);
|
||||||
return CallBoxedOrUnboxedSpecialization(functor, dst);
|
return CallBoxedOrUnboxedSpecialization(functor, dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength,
|
DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength,
|
||||||
|
@ -2075,3 +2075,13 @@ js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t i
|
||||||
SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen);
|
SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen);
|
||||||
JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
|
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);
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче