зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1520286 - Part 2: Add VM-call for TypedArray constructor with Array/TypedArray arguments. r=jandem
--HG-- extra : rebase_source : 899acfc898773aec0a1b3b69aeb1aae07958cdc6
This commit is contained in:
Родитель
24cd46ac83
Коммит
2ee80e7ac9
|
@ -0,0 +1,165 @@
|
|||
// Test TypedArray constructor when called with iterables or typed arrays.
|
||||
|
||||
function testPackedArray() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
];
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testPackedArray();
|
||||
|
||||
function testHoleArray() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, /* hole */, 3,
|
||||
4, /* hole */, 6,
|
||||
7, /* hole */, 9,
|
||||
];
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j] || 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testHoleArray();
|
||||
|
||||
function testTypedArraySameType() {
|
||||
function test() {
|
||||
var array = new Int32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testTypedArraySameType();
|
||||
|
||||
function testTypedArrayDifferentType() {
|
||||
function test() {
|
||||
var array = new Float32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testTypedArrayDifferentType();
|
||||
|
||||
function testIterable() {
|
||||
function test() {
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
];
|
||||
array = Object.defineProperties({
|
||||
[Symbol.iterator]() {
|
||||
var index = 0;
|
||||
return {
|
||||
next() {
|
||||
var done = index >= array.length;
|
||||
var value = !done ? array[index++] : undefined;
|
||||
return {done, value};
|
||||
}
|
||||
};
|
||||
}
|
||||
}, Object.getOwnPropertyDescriptors(array));
|
||||
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testIterable();
|
||||
|
||||
function testWrappedArray() {
|
||||
var g = newGlobal();
|
||||
|
||||
function test() {
|
||||
var array = new g.Array(
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testWrappedArray();
|
||||
|
||||
function testWrappedTypedArray() {
|
||||
var g = newGlobal();
|
||||
|
||||
function test() {
|
||||
var array = new g.Int32Array([
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
]);
|
||||
for (var i = 0; i < 1000; ++i) {
|
||||
var ta = new Int32Array(array);
|
||||
assertEq(ta.length, array.length);
|
||||
for (var j = 0; j < array.length; ++j) {
|
||||
assertEq(ta[j], array[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
testWrappedTypedArray();
|
|
@ -3382,12 +3382,8 @@ static bool GetTemplateObjectForNative(JSContext* cx, HandleFunction target,
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
if (args[0].isInt32() && args[0].toInt32() >= 0) {
|
||||
len = args[0].toInt32();
|
||||
}
|
||||
return TypedArrayObject::GetTemplateObjectForNative(cx, target->native(),
|
||||
len, res);
|
||||
args[0], res);
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
@ -6318,6 +6318,19 @@ void CodeGenerator::visitNewTypedArrayDynamicLength(
|
|||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef TypedArrayObject* (*TypedArrayCreateWithTemplateFn)(JSContext*,
|
||||
HandleObject,
|
||||
HandleObject);
|
||||
static const VMFunction TypedArrayCreateWithTemplateInfo =
|
||||
FunctionInfo<TypedArrayCreateWithTemplateFn>(
|
||||
js::TypedArrayCreateWithTemplate, "TypedArrayCreateWithTemplate");
|
||||
|
||||
void CodeGenerator::visitNewTypedArrayFromArray(LNewTypedArrayFromArray* lir) {
|
||||
pushArg(ToRegister(lir->array()));
|
||||
pushArg(ImmGCPtr(lir->mir()->templateObject()));
|
||||
callVM(TypedArrayCreateWithTemplateInfo, lir);
|
||||
}
|
||||
|
||||
// Out-of-line object allocation for JSOP_NEWOBJECT.
|
||||
class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator> {
|
||||
LNewObject* lir_;
|
||||
|
|
|
@ -202,6 +202,15 @@ void LIRGenerator::visitNewTypedArrayDynamicLength(
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) {
|
||||
MDefinition* array = ins->array();
|
||||
MOZ_ASSERT(array->type() == MIRType::Object);
|
||||
|
||||
auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitNewObject(MNewObject* ins) {
|
||||
LNewObject* lir = new (alloc()) LNewObject(temp());
|
||||
define(lir, ins);
|
||||
|
|
|
@ -2931,19 +2931,11 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArray(CallInfo& callInfo,
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
|
||||
if (arg->type() != MIRType::Int32) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native);
|
||||
|
||||
if (!templateObject) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(templateObject->is<TypedArrayObject>());
|
||||
TypedArrayObject* obj = &templateObject->as<TypedArrayObject>();
|
||||
|
||||
|
@ -2953,35 +2945,59 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArray(CallInfo& callInfo,
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MInstruction* ins = nullptr;
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
MInstruction* ins;
|
||||
if (arg->type() == MIRType::Int32) {
|
||||
if (!arg->isConstant()) {
|
||||
ins = MNewTypedArrayDynamicLength::New(
|
||||
alloc(), constraints(), templateObject,
|
||||
templateObject->group()->initialHeap(constraints()), arg);
|
||||
} else {
|
||||
// Negative lengths must throw a RangeError. (We don't track that this
|
||||
// might have previously thrown, when determining whether to inline, so we
|
||||
// have to deal with this error case when inlining.)
|
||||
int32_t providedLen = arg->maybeConstantValue()->toInt32();
|
||||
if (providedLen <= 0) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
if (!arg->isConstant()) {
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
ins = MNewTypedArrayDynamicLength::New(
|
||||
uint32_t len = AssertedCast<uint32_t>(providedLen);
|
||||
if (obj->length() != len) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MConstant* templateConst =
|
||||
MConstant::NewConstraintlessObject(alloc(), obj);
|
||||
current->add(templateConst);
|
||||
ins = MNewTypedArray::New(alloc(), constraints(), templateConst,
|
||||
obj->group()->initialHeap(constraints()));
|
||||
}
|
||||
} else if (arg->type() == MIRType::Object) {
|
||||
TemporaryTypeSet* types = arg->resultTypeSet();
|
||||
if (!types) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Don't inline if the argument is a, possibly wrapped, ArrayBuffer or
|
||||
// SharedArrayBuffer object.
|
||||
auto IsPossiblyWrappedArrayBufferMaybeSharedClass = [](const Class* clasp) {
|
||||
return clasp->isProxy() || clasp == &ArrayBufferObject::class_ ||
|
||||
clasp == &SharedArrayBufferObject::class_;
|
||||
};
|
||||
auto result = types->forAllClasses(
|
||||
constraints(), IsPossiblyWrappedArrayBufferMaybeSharedClass);
|
||||
if (result != TemporaryTypeSet::ForAllResult::ALL_FALSE) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
ins = MNewTypedArrayFromArray::New(
|
||||
alloc(), constraints(), templateObject,
|
||||
templateObject->group()->initialHeap(constraints()), arg);
|
||||
} else {
|
||||
// Negative lengths must throw a RangeError. (We don't track that this
|
||||
// might have previously thrown, when determining whether to inline, so we
|
||||
// have to deal with this error case when inlining.)
|
||||
int32_t providedLen = arg->maybeConstantValue()->toInt32();
|
||||
if (providedLen <= 0) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
uint32_t len = AssertedCast<uint32_t>(providedLen);
|
||||
|
||||
if (obj->length() != len) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), obj);
|
||||
current->add(templateConst);
|
||||
ins = MNewTypedArray::New(alloc(), constraints(), templateConst,
|
||||
obj->group()->initialHeap(constraints()));
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
MOZ_TRY(resumeAfter(ins));
|
||||
|
|
|
@ -2138,12 +2138,10 @@ class MNewTypedArrayDynamicLength : public MUnaryInstruction,
|
|||
: MUnaryInstruction(classOpcode, length),
|
||||
templateObject_(templateObject),
|
||||
initialHeap_(initialHeap) {
|
||||
MOZ_ASSERT(!templateObject->isSingleton());
|
||||
setGuard(); // Need to throw if length is negative.
|
||||
setResultType(MIRType::Object);
|
||||
if (!templateObject->isSingleton()) {
|
||||
setResultTypeSet(
|
||||
MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -2161,6 +2159,40 @@ class MNewTypedArrayDynamicLength : public MUnaryInstruction,
|
|||
}
|
||||
};
|
||||
|
||||
// Create a new TypedArray from an Array (or Array-like object) or a TypedArray.
|
||||
class MNewTypedArrayFromArray : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
CompilerObject templateObject_;
|
||||
gc::InitialHeap initialHeap_;
|
||||
|
||||
MNewTypedArrayFromArray(TempAllocator& alloc,
|
||||
CompilerConstraintList* constraints,
|
||||
JSObject* templateObject, gc::InitialHeap initialHeap,
|
||||
MDefinition* array)
|
||||
: MUnaryInstruction(classOpcode, array),
|
||||
templateObject_(templateObject),
|
||||
initialHeap_(initialHeap) {
|
||||
MOZ_ASSERT(!templateObject->isSingleton());
|
||||
setGuard(); // Can throw during construction.
|
||||
setResultType(MIRType::Object);
|
||||
setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NewTypedArrayFromArray)
|
||||
TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
|
||||
|
||||
MDefinition* array() const { return getOperand(0); }
|
||||
JSObject* templateObject() const { return templateObject_; }
|
||||
gc::InitialHeap initialHeap() const { return initialHeap_; }
|
||||
|
||||
bool appendRoots(MRootList& roots) const override {
|
||||
return roots.append(templateObject_);
|
||||
}
|
||||
|
||||
bool possiblyCalls() const override { return true; }
|
||||
};
|
||||
|
||||
class MNewObject : public MUnaryInstruction, public NoTypePolicy::Data {
|
||||
public:
|
||||
enum Mode { ObjectLiteral, ObjectCreate };
|
||||
|
|
|
@ -386,6 +386,22 @@ class LNewTypedArrayDynamicLength : public LInstructionHelper<1, 1, 1> {
|
|||
}
|
||||
};
|
||||
|
||||
class LNewTypedArrayFromArray : public LCallInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
LIR_HEADER(NewTypedArrayFromArray)
|
||||
|
||||
explicit LNewTypedArrayFromArray(const LAllocation& array)
|
||||
: LCallInstructionHelper(classOpcode) {
|
||||
setOperand(0, array);
|
||||
}
|
||||
|
||||
const LAllocation* array() { return getOperand(0); }
|
||||
|
||||
MNewTypedArrayFromArray* mir() const {
|
||||
return mir_->toNewTypedArrayFromArray();
|
||||
}
|
||||
};
|
||||
|
||||
class LNewObject : public LInstructionHelper<1, 0, 1> {
|
||||
public:
|
||||
LIR_HEADER(NewObject)
|
||||
|
|
|
@ -382,11 +382,26 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
|
||||
static TypedArrayObject* makeTypedInstance(JSContext* cx,
|
||||
CreateSingleton createSingleton,
|
||||
HandleObjectGroup group,
|
||||
gc::AllocKind allocKind) {
|
||||
if (createSingleton == CreateSingleton::Yes) {
|
||||
MOZ_ASSERT(!group);
|
||||
return newBuiltinClassInstance(cx, allocKind, SingletonObject);
|
||||
}
|
||||
|
||||
if (group) {
|
||||
MOZ_ASSERT(group->clasp() == instanceClass());
|
||||
NewObjectKind newKind = GenericObject;
|
||||
{
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
if (group->shouldPreTenure(sweep)) {
|
||||
newKind = TenuredObject;
|
||||
}
|
||||
}
|
||||
return NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind,
|
||||
newKind);
|
||||
}
|
||||
|
||||
jsbytecode* pc;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
|
@ -406,7 +421,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
static TypedArrayObject* makeInstance(
|
||||
JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer,
|
||||
CreateSingleton createSingleton, uint32_t byteOffset, uint32_t len,
|
||||
HandleObject proto) {
|
||||
HandleObject proto, HandleObjectGroup group = nullptr) {
|
||||
MOZ_ASSERT(len < INT32_MAX / BYTES_PER_ELEMENT);
|
||||
|
||||
gc::AllocKind allocKind =
|
||||
|
@ -427,9 +442,10 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
AutoSetNewObjectMetadata metadata(cx);
|
||||
Rooted<TypedArrayObject*> obj(cx);
|
||||
if (proto && proto != checkProto) {
|
||||
MOZ_ASSERT(!group);
|
||||
obj = makeProtoInstance(cx, proto, allocKind);
|
||||
} else {
|
||||
obj = makeTypedInstance(cx, createSingleton, allocKind);
|
||||
obj = makeTypedInstance(cx, createSingleton, group, allocKind);
|
||||
}
|
||||
if (!obj || !obj->init(cx, buffer, byteOffset, len, BYTES_PER_ELEMENT)) {
|
||||
return nullptr;
|
||||
|
@ -446,6 +462,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
|
||||
gc::AllocKind allocKind = !fitsInline ? gc::GetGCObjectKind(instanceClass())
|
||||
: AllocKindForLazyBuffer(nbytes);
|
||||
MOZ_ASSERT(allocKind >= gc::GetGCObjectKind(instanceClass()));
|
||||
|
||||
AutoSetNewObjectMetadata metadata(cx);
|
||||
jsbytecode* pc;
|
||||
|
@ -552,6 +569,15 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
return obj;
|
||||
}
|
||||
|
||||
static TypedArrayObject* makeTypedArrayWithTemplate(
|
||||
JSContext* cx, TypedArrayObject* templateObj, HandleObject array) {
|
||||
MOZ_ASSERT(!IsWrapper(array));
|
||||
MOZ_ASSERT(!array->is<ArrayBufferObjectMaybeShared>());
|
||||
|
||||
RootedObjectGroup group(cx, templateObj->group());
|
||||
return fromArray(cx, array, nullptr, group);
|
||||
}
|
||||
|
||||
// ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
|
||||
// 22.2.4.1 TypedArray ( )
|
||||
// 22.2.4.2 TypedArray ( length )
|
||||
|
@ -881,14 +907,17 @@ class TypedArrayObjectTemplate : public TypedArrayObject {
|
|||
uint32_t count,
|
||||
MutableHandle<ArrayBufferObject*> buffer);
|
||||
|
||||
static JSObject* fromArray(JSContext* cx, HandleObject other,
|
||||
HandleObject proto = nullptr);
|
||||
static TypedArrayObject* fromArray(JSContext* cx, HandleObject other,
|
||||
HandleObject proto = nullptr,
|
||||
HandleObjectGroup group = nullptr);
|
||||
|
||||
static JSObject* fromTypedArray(JSContext* cx, HandleObject other,
|
||||
bool isWrapped, HandleObject proto);
|
||||
static TypedArrayObject* fromTypedArray(JSContext* cx, HandleObject other,
|
||||
bool isWrapped, HandleObject proto,
|
||||
HandleObjectGroup group);
|
||||
|
||||
static JSObject* fromObject(JSContext* cx, HandleObject other,
|
||||
HandleObject proto);
|
||||
static TypedArrayObject* fromObject(JSContext* cx, HandleObject other,
|
||||
HandleObject proto,
|
||||
HandleObjectGroup group);
|
||||
|
||||
static const NativeType getIndex(TypedArrayObject* tarray, uint32_t index) {
|
||||
MOZ_ASSERT(index < tarray->length());
|
||||
|
@ -931,6 +960,24 @@ TypedArrayObject* js::TypedArrayCreateWithTemplate(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
TypedArrayObject* js::TypedArrayCreateWithTemplate(JSContext* cx,
|
||||
HandleObject templateObj,
|
||||
HandleObject array) {
|
||||
MOZ_ASSERT(templateObj->is<TypedArrayObject>());
|
||||
TypedArrayObject* tobj = &templateObj->as<TypedArrayObject>();
|
||||
|
||||
switch (tobj->type()) {
|
||||
#define CREATE_TYPED_ARRAY(T, N) \
|
||||
case Scalar::N: \
|
||||
return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, \
|
||||
array);
|
||||
JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
|
||||
#undef CREATE_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
}
|
||||
|
||||
// ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3
|
||||
// 24.1.1.1 AllocateArrayBuffer ( constructor, byteLength )
|
||||
// byteLength = count * BYTES_PER_ELEMENT
|
||||
|
@ -1025,27 +1072,29 @@ static JSObject* GetBufferSpeciesConstructor(
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromArray(
|
||||
JSContext* cx, HandleObject other, HandleObject proto /* = nullptr */) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromArray(
|
||||
JSContext* cx, HandleObject other, HandleObject proto /* = nullptr */,
|
||||
HandleObjectGroup group /* = nullptr */) {
|
||||
// Allow nullptr proto for FriendAPI methods, which don't care about
|
||||
// subclassing.
|
||||
if (other->is<TypedArrayObject>()) {
|
||||
return fromTypedArray(cx, other, /* wrapped= */ false, proto);
|
||||
return fromTypedArray(cx, other, /* wrapped= */ false, proto, group);
|
||||
}
|
||||
|
||||
if (other->is<WrapperObject>() &&
|
||||
UncheckedUnwrap(other)->is<TypedArrayObject>()) {
|
||||
return fromTypedArray(cx, other, /* wrapped= */ true, proto);
|
||||
return fromTypedArray(cx, other, /* wrapped= */ true, proto, group);
|
||||
}
|
||||
|
||||
return fromObject(cx, other, proto);
|
||||
return fromObject(cx, other, proto, group);
|
||||
}
|
||||
|
||||
// ES2018 draft rev 272beb67bc5cd9fd18a220665198384108208ee1
|
||||
// 22.2.4.3 TypedArray ( typedArray )
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromTypedArray(
|
||||
JSContext* cx, HandleObject other, bool isWrapped, HandleObject proto) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromTypedArray(
|
||||
JSContext* cx, HandleObject other, bool isWrapped, HandleObject proto,
|
||||
HandleObjectGroup group) {
|
||||
// Step 1.
|
||||
MOZ_ASSERT_IF(!isWrapped, other->is<TypedArrayObject>());
|
||||
MOZ_ASSERT_IF(isWrapped, other->is<WrapperObject>() &&
|
||||
|
@ -1123,8 +1172,8 @@ template <typename T>
|
|||
|
||||
// Steps 3-4 (remaining part), 20-23.
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx,
|
||||
makeInstance(cx, buffer, CreateSingleton::No, 0, elementLength, proto));
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, elementLength, proto,
|
||||
group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1165,8 +1214,9 @@ static MOZ_ALWAYS_INLINE bool IsOptimizableInit(JSContext* cx,
|
|||
// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
template <typename T>
|
||||
/* static */ JSObject* TypedArrayObjectTemplate<T>::fromObject(
|
||||
JSContext* cx, HandleObject other, HandleObject proto) {
|
||||
/* static */ TypedArrayObject* TypedArrayObjectTemplate<T>::fromObject(
|
||||
JSContext* cx, HandleObject other, HandleObject proto,
|
||||
HandleObjectGroup group) {
|
||||
// Steps 1-2 (Already performed in caller).
|
||||
|
||||
// Steps 3-4 (Allocation deferred until later).
|
||||
|
@ -1191,7 +1241,8 @@ template <typename T>
|
|||
}
|
||||
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto));
|
||||
cx,
|
||||
makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto, group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1266,7 +1317,7 @@ template <typename T>
|
|||
}
|
||||
|
||||
Rooted<TypedArrayObject*> obj(
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto));
|
||||
cx, makeInstance(cx, buffer, CreateSingleton::No, 0, len, proto, group));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1290,18 +1341,46 @@ bool TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool GetTemplateObjectForNative(JSContext* cx, HandleValue arg,
|
||||
MutableHandleObject res) {
|
||||
if (arg.isInt32()) {
|
||||
uint32_t len = 0;
|
||||
if (arg.toInt32() >= 0) {
|
||||
len = arg.toInt32();
|
||||
}
|
||||
|
||||
size_t nbytes;
|
||||
if (!js::CalculateAllocSize<T>(len, &nbytes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nbytes >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (arg.isObject() && !IsWrapper(&arg.toObject()) &&
|
||||
!arg.toObject().is<ArrayBufferObjectMaybeShared>()) {
|
||||
// We don't use the template's length in the object case, so we can create
|
||||
// the template typed array with an initial length of zero.
|
||||
uint32_t len = 0;
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool TypedArrayObject::GetTemplateObjectForNative(
|
||||
JSContext* cx, Native native, uint32_t len, MutableHandleObject res) {
|
||||
JSContext* cx, Native native, HandleValue arg, MutableHandleObject res) {
|
||||
MOZ_ASSERT(!res);
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
|
||||
size_t nbytes; \
|
||||
if (!js::CalculateAllocSize<T>(len, &nbytes)) return true; \
|
||||
\
|
||||
if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \
|
||||
res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \
|
||||
return !!res; \
|
||||
} \
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
|
||||
return ::GetTemplateObjectForNative<T>(cx, arg, res); \
|
||||
}
|
||||
JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
|
||||
#undef CHECK_TYPED_ARRAY_CONSTRUCTOR
|
||||
|
|
|
@ -136,7 +136,8 @@ class TypedArrayObject : public ArrayBufferViewObject {
|
|||
void getElements(Value* vp);
|
||||
|
||||
static bool GetTemplateObjectForNative(JSContext* cx, Native native,
|
||||
uint32_t len, MutableHandleObject res);
|
||||
HandleValue arg,
|
||||
MutableHandleObject res);
|
||||
|
||||
/*
|
||||
* Byte length above which created typed arrays will have singleton types
|
||||
|
@ -191,6 +192,10 @@ extern TypedArrayObject* TypedArrayCreateWithTemplate(JSContext* cx,
|
|||
HandleObject templateObj,
|
||||
int32_t len);
|
||||
|
||||
extern TypedArrayObject* TypedArrayCreateWithTemplate(JSContext* cx,
|
||||
HandleObject templateObj,
|
||||
HandleObject array);
|
||||
|
||||
inline bool IsTypedArrayClass(const Class* clasp) {
|
||||
return &TypedArrayObject::classes[0] <= clasp &&
|
||||
clasp < &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType];
|
||||
|
|
Загрузка…
Ссылка в новой задаче