зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1232266: Support iterables in TypedArray constructors. r=jandem
This commit is contained in:
Родитель
a9fedb7608
Коммит
3386f0c48a
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "builtin/SelfHostingDefines.h"
|
#include "builtin/SelfHostingDefines.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
|
#include "vm/NativeObject.h"
|
||||||
#include "vm/PIC.h"
|
#include "vm/PIC.h"
|
||||||
#include "vm/Runtime.h"
|
#include "vm/Runtime.h"
|
||||||
|
|
||||||
|
@ -270,8 +271,6 @@ class SetIteratorObject : public NativeObject
|
||||||
extern bool
|
extern bool
|
||||||
InitSelfHostingCollectionIteratorFunctions(JSContext* cx, js::HandleObject obj);
|
InitSelfHostingCollectionIteratorFunctions(JSContext* cx, js::HandleObject obj);
|
||||||
|
|
||||||
bool IsPackedArray(JSObject* obj);
|
|
||||||
|
|
||||||
using SetInitGetPrototypeOp = NativeObject* (*)(JSContext*, Handle<GlobalObject*>);
|
using SetInitGetPrototypeOp = NativeObject* (*)(JSContext*, Handle<GlobalObject*>);
|
||||||
using SetInitIsBuiltinOp = bool (*)(HandleValue, JSContext*);
|
using SetInitIsBuiltinOp = bool (*)(HandleValue, JSContext*);
|
||||||
|
|
||||||
|
|
|
@ -1521,6 +1521,33 @@ function TypedArrayToStringTag() {
|
||||||
}
|
}
|
||||||
_SetCanonicalName(TypedArrayToStringTag, "get [Symbol.toStringTag]");
|
_SetCanonicalName(TypedArrayToStringTag, "get [Symbol.toStringTag]");
|
||||||
|
|
||||||
|
// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
|
||||||
|
// 22.2.2.1.1 Runtime Semantics: IterableToList( items, method )
|
||||||
|
function IterableToList(items, method) {
|
||||||
|
// Step 1.
|
||||||
|
var iterator = GetIterator(items, method);
|
||||||
|
|
||||||
|
// Step 2.
|
||||||
|
var values = [];
|
||||||
|
|
||||||
|
// Steps 3-4.
|
||||||
|
var i = 0;
|
||||||
|
while (true) {
|
||||||
|
// Step 4.a.
|
||||||
|
var next = callContentFunction(iterator.next, iterator);
|
||||||
|
if (!IsObject(next))
|
||||||
|
ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
|
||||||
|
|
||||||
|
// Step 4.b.
|
||||||
|
if (next.done)
|
||||||
|
break;
|
||||||
|
_DefineDataProperty(values, i++, next.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
// ES 2016 draft Mar 25, 2016 24.1.4.3.
|
// ES 2016 draft Mar 25, 2016 24.1.4.3.
|
||||||
function ArrayBufferSlice(start, end) {
|
function ArrayBufferSlice(start, end) {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from generator.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 128)]) {
|
||||||
|
let typedArray = new constructor(function*(){ yield* array; }());
|
||||||
|
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
assertEqArray(typedArray, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from array with modified array iterator next method.
|
||||||
|
const ArrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]());
|
||||||
|
const origNext = ArrayIteratorPrototype.next;
|
||||||
|
const modifiedNext = function() {
|
||||||
|
let {value, done} = origNext.call(this);
|
||||||
|
return {value: value * 5, done};
|
||||||
|
};
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 24)]) {
|
||||||
|
ArrayIteratorPrototype.next = modifiedNext;
|
||||||
|
let typedArray;
|
||||||
|
try {
|
||||||
|
typedArray = new constructor(array);
|
||||||
|
} finally {
|
||||||
|
ArrayIteratorPrototype.next = origNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
assertEqArray(typedArray, array.map(v => v * 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from array with modified array iterator.
|
||||||
|
const origIterator = Array.prototype[Symbol.iterator];
|
||||||
|
const modifiedIterator = function*() {
|
||||||
|
for (let v of origIterator.call(this)) {
|
||||||
|
yield v * 5;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 24)]) {
|
||||||
|
Array.prototype[Symbol.iterator] = modifiedIterator;
|
||||||
|
let typedArray;
|
||||||
|
try {
|
||||||
|
typedArray = new constructor(array)
|
||||||
|
} finally {
|
||||||
|
Array.prototype[Symbol.iterator] = origIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
assertEqArray(typedArray, array.map(v => v * 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from iterable non-packed array.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let array of [[,], [,,], Array(1024)]) {
|
||||||
|
let typedArray = new constructor(array);
|
||||||
|
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
let expectedArray = Array(array.length).fill(isFloatConstructor(constructor) ? NaN : 0);
|
||||||
|
assertEqArray(typedArray, expectedArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from object with non-callable [Symbol.iterator] property.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let iterator of [true, 0, Math.PI, "", "10", Symbol.iterator, {}, []]) {
|
||||||
|
assertThrowsInstanceOf(() => new constructor({
|
||||||
|
[Symbol.iterator]: iterator
|
||||||
|
}), TypeError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from iterable packed array, array contains object with modifying
|
||||||
|
// valueOf() method.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
let array = [
|
||||||
|
0, 1, {valueOf() { array[3] = 30; return 2; }}, 3, 4
|
||||||
|
];
|
||||||
|
let typedArray = new constructor(array);
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
assertEqArray(typedArray, [0, 1, 2, 3, 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from iterable packed array.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let array of [[], [1], [2, 3], [4, 5, 6], Array(1024).fill(0).map((v, i) => i % 128)]) {
|
||||||
|
let typedArray = new constructor(array);
|
||||||
|
|
||||||
|
assertEq(typedArray.length, array.length);
|
||||||
|
assertEqArray(typedArray, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Construct typed array from object with undefined or null [Symbol.iterator] property.
|
||||||
|
for (let constructor of anyTypedArrayConstructors) {
|
||||||
|
for (let iterator of [undefined, null]) {
|
||||||
|
let arrayLike = {
|
||||||
|
[Symbol.iterator]: iterator,
|
||||||
|
length: 2,
|
||||||
|
0: 10,
|
||||||
|
1: 20,
|
||||||
|
};
|
||||||
|
let typedArray = new constructor(arrayLike);
|
||||||
|
|
||||||
|
assertEq(typedArray.length, arrayLike.length);
|
||||||
|
assertEqArray(typedArray, arrayLike);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -165,6 +165,7 @@
|
||||||
macro(isFinite, isFinite, "isFinite") \
|
macro(isFinite, isFinite, "isFinite") \
|
||||||
macro(isNaN, isNaN, "isNaN") \
|
macro(isNaN, isNaN, "isNaN") \
|
||||||
macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
|
macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
|
||||||
|
macro(IterableToList, IterableToList, "IterableToList") \
|
||||||
macro(iterate, iterate, "iterate") \
|
macro(iterate, iterate, "iterate") \
|
||||||
macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
|
macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
|
||||||
macro(join, join, "join") \
|
macro(join, join, "join") \
|
||||||
|
|
|
@ -1490,6 +1490,9 @@ MaybeNativeObject(JSObject* obj)
|
||||||
return obj ? &obj->as<NativeObject>() : nullptr;
|
return obj ? &obj->as<NativeObject>() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defined in NativeObject-inl.h.
|
||||||
|
bool IsPackedArray(JSObject* obj);
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "js/Conversions.h"
|
#include "js/Conversions.h"
|
||||||
#include "js/Value.h"
|
#include "js/Value.h"
|
||||||
|
|
||||||
|
#include "vm/NativeObject.h"
|
||||||
#include "vm/TypedArrayObject.h"
|
#include "vm/TypedArrayObject.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
@ -423,6 +424,64 @@ class ElementSpecific
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy |source| into the typed array |target|.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
|
||||||
|
HandleArrayObject source)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
|
||||||
|
"target type and NativeType must match");
|
||||||
|
MOZ_ASSERT(IsPackedArray(source), "source array must be packed");
|
||||||
|
MOZ_ASSERT(source->getDenseInitializedLength() <= target->length());
|
||||||
|
|
||||||
|
uint32_t len = source->getDenseInitializedLength();
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
// Attempt fast-path infallible conversion of dense elements up to the
|
||||||
|
// first potentially side-effectful conversion.
|
||||||
|
|
||||||
|
SharedMem<T*> dest =
|
||||||
|
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
|
||||||
|
|
||||||
|
const Value* srcValues = source->getDenseElements();
|
||||||
|
for (; i < len; i++) {
|
||||||
|
if (!canConvertInfallibly(srcValues[i]))
|
||||||
|
break;
|
||||||
|
Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
|
||||||
|
}
|
||||||
|
if (i == len)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Convert any remaining elements by first collecting them into a
|
||||||
|
// temporary list, and then copying them into the typed array.
|
||||||
|
AutoValueVector values(cx);
|
||||||
|
if (!values.append(srcValues + i, len - i))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedValue v(cx);
|
||||||
|
for (uint32_t j = 0; j < values.length(); i++, j++) {
|
||||||
|
v = values[j];
|
||||||
|
|
||||||
|
T n;
|
||||||
|
if (!valueToNative(cx, v, &n))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// |target| is a newly allocated typed array and not yet visible to
|
||||||
|
// content script, so valueToNative can't detach the underlying
|
||||||
|
// buffer.
|
||||||
|
MOZ_ASSERT(i < target->length());
|
||||||
|
|
||||||
|
// Compute every iteration in case GC moves the data.
|
||||||
|
SharedMem<T*> newDest =
|
||||||
|
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>();
|
||||||
|
Ops::store(newDest + i, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool
|
static bool
|
||||||
setFromOverlappingTypedArray(JSContext* cx,
|
setFromOverlappingTypedArray(JSContext* cx,
|
||||||
|
@ -767,6 +826,60 @@ class TypedArrayMethods
|
||||||
}
|
}
|
||||||
MOZ_CRASH("bad target array type");
|
MOZ_CRASH("bad target array type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
initFromIterablePackedArray(JSContext* cx, Handle<SomeTypedArray*> target,
|
||||||
|
HandleArrayObject source)
|
||||||
|
{
|
||||||
|
bool isShared = target->isSharedMemory();
|
||||||
|
|
||||||
|
switch (target->type()) {
|
||||||
|
case Scalar::Int8:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Int8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Int8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Uint8:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Uint8ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Uint8ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Int16:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Int16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Int16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Uint16:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Uint16ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Uint16ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Int32:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Int32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Int32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Uint32:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Uint32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Uint32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Float32:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Float32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Float32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Float64:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Float64ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Float64ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Uint8Clamped:
|
||||||
|
if (isShared)
|
||||||
|
return ElementSpecific<Uint8ClampedArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
return ElementSpecific<Uint8ClampedArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
|
||||||
|
case Scalar::Int64:
|
||||||
|
case Scalar::Float32x4:
|
||||||
|
case Scalar::Int8x16:
|
||||||
|
case Scalar::Int16x8:
|
||||||
|
case Scalar::Int32x4:
|
||||||
|
case Scalar::MaxTypedArrayViewType:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MOZ_CRASH("bad target array type");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "vm/ArrayBufferObject.h"
|
#include "vm/ArrayBufferObject.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
#include "vm/Interpreter.h"
|
#include "vm/Interpreter.h"
|
||||||
|
#include "vm/PIC.h"
|
||||||
#include "vm/SelfHosting.h"
|
#include "vm/SelfHosting.h"
|
||||||
#include "vm/TypedArrayCommon.h"
|
#include "vm/TypedArrayCommon.h"
|
||||||
#include "vm/WrapperObject.h"
|
#include "vm/WrapperObject.h"
|
||||||
|
@ -1241,20 +1242,114 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This is not compatible with TypedArrayFrom in the spec
|
static MOZ_ALWAYS_INLINE bool
|
||||||
// (ES 2016 draft Mar 25, 2016 22.2.4.4 and 22.2.2.1.1)
|
IsOptimizableInit(JSContext* cx, HandleObject iterable, bool* optimized)
|
||||||
// We should handle iterator protocol (bug 1232266).
|
{
|
||||||
|
MOZ_ASSERT(!*optimized);
|
||||||
|
|
||||||
|
if (!IsPackedArray(iterable))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
|
||||||
|
if (!stubChain)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return stubChain->tryOptimizeArray(cx, iterable.as<ArrayObject>(), optimized);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
|
||||||
|
// 22.2.4.4 TypedArray ( object )
|
||||||
template<typename T>
|
template<typename T>
|
||||||
/* static */ JSObject*
|
/* static */ JSObject*
|
||||||
TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, HandleObject newTarget)
|
TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, HandleObject newTarget)
|
||||||
{
|
{
|
||||||
|
// Steps 1-2 (Already performed in caller).
|
||||||
|
|
||||||
|
// Steps 3-4 (Allocation deferred until later).
|
||||||
RootedObject proto(cx);
|
RootedObject proto(cx);
|
||||||
Rooted<ArrayBufferObject*> buffer(cx);
|
|
||||||
uint32_t len;
|
|
||||||
if (!GetLengthProperty(cx, other, &len))
|
|
||||||
return nullptr;
|
|
||||||
if (!GetPrototypeForInstance(cx, newTarget, &proto))
|
if (!GetPrototypeForInstance(cx, newTarget, &proto))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
bool optimized = false;
|
||||||
|
if (!IsOptimizableInit(cx, other, &optimized))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Fast path when iterable is a packed array using the default iterator.
|
||||||
|
if (optimized) {
|
||||||
|
// Step 6.a (We don't need to call IterableToList for the fast path).
|
||||||
|
RootedArrayObject array(cx, &other->as<ArrayObject>());
|
||||||
|
|
||||||
|
// Step 6.b.
|
||||||
|
uint32_t len = array->getDenseInitializedLength();
|
||||||
|
|
||||||
|
// Step 6.c.
|
||||||
|
Rooted<ArrayBufferObject*> buffer(cx);
|
||||||
|
if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
|
||||||
|
if (!obj)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Steps 6.d-e.
|
||||||
|
if (!TypedArrayMethods<TypedArrayObject>::initFromIterablePackedArray(cx, obj, array))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Step 6.f (The assertion isn't applicable for the fast path).
|
||||||
|
|
||||||
|
// Step 6.g.
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5.
|
||||||
|
RootedValue callee(cx);
|
||||||
|
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
|
||||||
|
if (!GetProperty(cx, other, other, iteratorId, &callee))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Steps 6-8.
|
||||||
|
RootedObject arrayLike(cx);
|
||||||
|
if (!callee.isNullOrUndefined()) {
|
||||||
|
// Throw if other[Symbol.iterator] isn't callable.
|
||||||
|
if (!callee.isObject() || !callee.toObject().isCallable()) {
|
||||||
|
RootedValue otherVal(cx, ObjectValue(*other));
|
||||||
|
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, otherVal, nullptr);
|
||||||
|
if (!bytes)
|
||||||
|
return nullptr;
|
||||||
|
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
|
||||||
|
bytes.get());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedInvokeArgs<2> args2(cx);
|
||||||
|
args2[0].setObject(*other);
|
||||||
|
args2[1].set(callee);
|
||||||
|
|
||||||
|
// Step 6.a.
|
||||||
|
RootedValue rval(cx);
|
||||||
|
if (!CallSelfHostedFunction(cx, cx->names().IterableToList, UndefinedHandleValue, args2,
|
||||||
|
&rval))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 6.b-g (Implemented in steps 9-13 below).
|
||||||
|
arrayLike = &rval.toObject();
|
||||||
|
} else {
|
||||||
|
// Step 7 is an assertion: object is not an Iterator. Testing this is
|
||||||
|
// literally the very last thing we did, so we don't assert here.
|
||||||
|
|
||||||
|
// Step 8.
|
||||||
|
arrayLike = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
uint32_t len;
|
||||||
|
if (!GetLengthProperty(cx, arrayLike, &len))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Step 10.
|
||||||
|
Rooted<ArrayBufferObject*> buffer(cx);
|
||||||
if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
|
if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -1262,8 +1357,11 @@ TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, Handl
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, other, len))
|
// Steps 11-12.
|
||||||
|
if (!TypedArrayMethods<TypedArrayObject>::setFromNonTypedArray(cx, obj, arrayLike, len))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Step 13.
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче