Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197191 => 197192)
--- trunk/Source/_javascript_Core/ChangeLog 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-02-26 20:25:42 UTC (rev 197192)
@@ -1,3 +1,45 @@
+2016-02-26 Keith Miller <[email protected]>
+
+ Native Typed Array functions should use Symbol.species
+ https://bugs.webkit.org/show_bug.cgi?id=154569
+
+ Reviewed by Michael Saboff.
+
+ This patch adds support for Symbol.species in the native Typed Array prototype
+ functions. Additionally, now that other types of typedarrays are creatable inside
+ the slice we use the JSGenericTypedArrayView::set function, which has been beefed
+ up, to put everything into the correct place.
+
+ * runtime/JSDataView.cpp:
+ (JSC::JSDataView::set):
+ * runtime/JSDataView.h:
+ * runtime/JSGenericTypedArrayView.h:
+ * runtime/JSGenericTypedArrayViewConstructorInlines.h:
+ (JSC::constructGenericTypedArrayViewFromIterator):
+ (JSC::constructGenericTypedArrayViewWithArguments):
+ (JSC::constructGenericTypedArrayView):
+ * runtime/JSGenericTypedArrayViewInlines.h:
+ (JSC::JSGenericTypedArrayView<Adaptor>::setWithSpecificType):
+ (JSC::JSGenericTypedArrayView<Adaptor>::set):
+ * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+ (JSC::speciesConstruct):
+ (JSC::genericTypedArrayViewProtoFuncSet):
+ (JSC::genericTypedArrayViewProtoFuncSlice):
+ (JSC::genericTypedArrayViewProtoFuncSubarray):
+ * tests/stress/typedarray-slice.js:
+ (subclasses.typedArrays.map):
+ (testSpecies):
+ (forEach):
+ (subclasses.forEach):
+ (testSpeciesRemoveConstructor):
+ (testSpeciesWithSameBuffer):
+ * tests/stress/typedarray-subarray.js: Added.
+ (subclasses.typedArrays.map):
+ (testSpecies):
+ (forEach):
+ (subclasses.forEach):
+ (testSpeciesRemoveConstructor):
+
2016-02-26 Benjamin Poulain <[email protected]>
[JSC] Add32(Imm, Tmp, Tmp) does not ZDef the destination if Imm is zero
Modified: trunk/Source/_javascript_Core/runtime/JSDataView.cpp (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSDataView.cpp 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSDataView.cpp 2016-02-26 20:25:42 UTC (rev 197192)
@@ -78,7 +78,7 @@
return 0;
}
-bool JSDataView::set(ExecState*, JSObject*, unsigned, unsigned)
+bool JSDataView::set(ExecState*, unsigned, JSObject*, unsigned, unsigned)
{
UNREACHABLE_FOR_PLATFORM();
return false;
Modified: trunk/Source/_javascript_Core/runtime/JSDataView.h (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSDataView.h 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSDataView.h 2016-02-26 20:25:42 UTC (rev 197192)
@@ -48,7 +48,7 @@
// placate some template specialization we do elsewhere.
static JSDataView* createUninitialized(ExecState*, Structure*, unsigned length);
static JSDataView* create(ExecState*, Structure*, unsigned length);
- bool set(ExecState*, JSObject*, unsigned offset, unsigned length);
+ bool set(ExecState*, unsigned, JSObject*, unsigned, unsigned length);
bool setIndex(ExecState*, unsigned, JSValue);
ArrayBuffer* buffer() const { return m_buffer; }
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h 2016-02-26 20:25:42 UTC (rev 197192)
@@ -83,6 +83,11 @@
// template<T> static T::Type convertTo(uint8_t);
// };
+enum class CopyType {
+ LeftToRight,
+ Unobservable,
+};
+
template<typename Adaptor>
class JSGenericTypedArrayView : public JSArrayBufferView {
public:
@@ -217,10 +222,10 @@
// Like canSetQuickly, except: if it returns false, it will throw the
// appropriate exception.
bool validateRange(ExecState*, unsigned offset, unsigned length);
-
+
// Returns true if successful, and false on error; if it returns false
// then it will have thrown an exception.
- bool set(ExecState*, JSObject*, unsigned offset, unsigned length);
+ bool set(ExecState*, unsigned offset, JSObject*, unsigned objectOffset, unsigned length, CopyType type = CopyType::Unobservable);
PassRefPtr<typename Adaptor::ViewType> typedImpl()
{
@@ -291,8 +296,8 @@
// Returns true if successful, and false on error; it will throw on error.
template<typename OtherAdaptor>
bool setWithSpecificType(
- ExecState*, JSGenericTypedArrayView<OtherAdaptor>*,
- unsigned offset, unsigned length);
+ ExecState*, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>*,
+ unsigned objectOffset, unsigned length, CopyType);
// The ECMA 6 spec states that floating point Typed Arrays should have the following ordering:
//
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewConstructorInlines.h 2016-02-26 20:25:42 UTC (rev 197192)
@@ -77,7 +77,7 @@
}
template<typename ViewClass>
-static JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
+inline JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
{
if (!iterator.isObject())
return throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object.");
@@ -115,7 +115,7 @@
}
template<typename ViewClass>
-static JSObject* constructGenericTypedArrayViewWithArguments(ExecState* exec, Structure* structure, EncodedJSValue firstArgument, unsigned offset, Optional<unsigned> lengthOpt)
+inline JSObject* constructGenericTypedArrayViewWithArguments(ExecState* exec, Structure* structure, EncodedJSValue firstArgument, unsigned offset, Optional<unsigned> lengthOpt)
{
JSValue firstValue = JSValue::decode(firstArgument);
VM& vm = exec->vm();
@@ -193,7 +193,7 @@
return nullptr;
}
- if (!result->set(exec, object, 0, length))
+ if (!result->set(exec, 0, object, 0, length))
return nullptr;
return result;
@@ -216,7 +216,10 @@
}
template<typename ViewClass>
-static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState*);
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
{
Structure* structure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType));
if (exec->hadException())
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h 2016-02-26 20:25:42 UTC (rev 197192)
@@ -138,8 +138,8 @@
template<typename Adaptor>
template<typename OtherAdaptor>
bool JSGenericTypedArrayView<Adaptor>::setWithSpecificType(
- ExecState* exec, JSGenericTypedArrayView<OtherAdaptor>* other,
- unsigned offset, unsigned length)
+ ExecState* exec, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>* other,
+ unsigned otherOffset, unsigned length, CopyType type)
{
// Handle the hilarious case: the act of getting the length could have resulted
// in neutering. Well, no. That'll never happen because there cannot be
@@ -148,15 +148,11 @@
// check. Worst case, if we're wrong, people start seeing less things get copied
// but we won't have a security vulnerability.
length = std::min(length, other->length());
-
+
+ RELEASE_ASSERT(other->canAccessRangeQuickly(otherOffset, length));
if (!validateRange(exec, offset, length))
return false;
- if (other->length() != length) {
- exec->vm().throwException(exec, createRangeError(exec, "Length of incoming array changed unexpectedly."));
- return false;
- }
-
// This method doesn't support copying between the same array. Note that
// set() will only call this if the types differ, which implicitly guarantees
// that we can't be the same array. This is relevant because the way we detect
@@ -185,25 +181,26 @@
// specialization.
unsigned otherElementSize = sizeof(typename OtherAdaptor::Type);
-
- // Handle cases (1) and (2B).
+
+ // Handle cases (1) and (2A).
if (!hasArrayBuffer() || !other->hasArrayBuffer()
|| existingBuffer() != other->existingBuffer()
- || (elementSize == otherElementSize && vector() > other->vector())) {
- for (unsigned i = length; i--;) {
+ || (elementSize == otherElementSize && vector() <= other->vector())
+ || type == CopyType::LeftToRight) {
+ for (unsigned i = 0; i < length; ++i) {
setIndexQuicklyToNativeValue(
offset + i, OtherAdaptor::template convertTo<Adaptor>(
- other->getIndexQuicklyAsNativeValue(i)));
+ other->getIndexQuicklyAsNativeValue(i + otherOffset)));
}
return true;
}
-
- // Now we either have (2A) or (3) - so first we try to cover (2A).
+
+ // Now we either have (2B) or (3) - so first we try to cover (2B).
if (elementSize == otherElementSize) {
- for (unsigned i = 0; i < length; ++i) {
+ for (unsigned i = length; i--;) {
setIndexQuicklyToNativeValue(
offset + i, OtherAdaptor::template convertTo<Adaptor>(
- other->getIndexQuicklyAsNativeValue(i)));
+ other->getIndexQuicklyAsNativeValue(i + otherOffset)));
}
return true;
}
@@ -212,7 +209,7 @@
Vector<typename Adaptor::Type, 32> transferBuffer(length);
for (unsigned i = length; i--;) {
transferBuffer[i] = OtherAdaptor::template convertTo<Adaptor>(
- other->getIndexQuicklyAsNativeValue(i));
+ other->getIndexQuicklyAsNativeValue(i + otherOffset));
}
for (unsigned i = length; i--;)
setIndexQuicklyToNativeValue(offset + i, transferBuffer[i]);
@@ -222,7 +219,7 @@
template<typename Adaptor>
bool JSGenericTypedArrayView<Adaptor>::set(
- ExecState* exec, JSObject* object, unsigned offset, unsigned length)
+ ExecState* exec, unsigned offset, JSObject* object, unsigned objectOffset, unsigned length, CopyType type)
{
const ClassInfo* ci = object->classInfo();
if (ci->typedArrayStorageType == Adaptor::typeValue) {
@@ -230,48 +227,50 @@
JSGenericTypedArrayView* other = jsCast<JSGenericTypedArrayView*>(object);
length = std::min(length, other->length());
+ RELEASE_ASSERT(other->canAccessRangeQuickly(objectOffset, length));
if (!validateRange(exec, offset, length))
return false;
-
- memmove(typedVector() + offset, other->typedVector(), other->byteLength());
+
+ memmove(typedVector() + offset, other->typedVector() + objectOffset, other->byteLength());
return true;
}
switch (ci->typedArrayStorageType) {
case TypeInt8:
return setWithSpecificType<Int8Adaptor>(
- exec, jsCast<JSInt8Array*>(object), offset, length);
+ exec, offset, jsCast<JSInt8Array*>(object), objectOffset, length, type);
case TypeInt16:
return setWithSpecificType<Int16Adaptor>(
- exec, jsCast<JSInt16Array*>(object), offset, length);
+ exec, offset, jsCast<JSInt16Array*>(object), objectOffset, length, type);
case TypeInt32:
return setWithSpecificType<Int32Adaptor>(
- exec, jsCast<JSInt32Array*>(object), offset, length);
+ exec, offset, jsCast<JSInt32Array*>(object), objectOffset, length, type);
case TypeUint8:
return setWithSpecificType<Uint8Adaptor>(
- exec, jsCast<JSUint8Array*>(object), offset, length);
+ exec, offset, jsCast<JSUint8Array*>(object), objectOffset, length, type);
case TypeUint8Clamped:
return setWithSpecificType<Uint8ClampedAdaptor>(
- exec, jsCast<JSUint8ClampedArray*>(object), offset, length);
+ exec, offset, jsCast<JSUint8ClampedArray*>(object), objectOffset, length, type);
case TypeUint16:
return setWithSpecificType<Uint16Adaptor>(
- exec, jsCast<JSUint16Array*>(object), offset, length);
+ exec, offset, jsCast<JSUint16Array*>(object), objectOffset, length, type);
case TypeUint32:
return setWithSpecificType<Uint32Adaptor>(
- exec, jsCast<JSUint32Array*>(object), offset, length);
+ exec, offset, jsCast<JSUint32Array*>(object), objectOffset, length, type);
case TypeFloat32:
return setWithSpecificType<Float32Adaptor>(
- exec, jsCast<JSFloat32Array*>(object), offset, length);
+ exec, offset, jsCast<JSFloat32Array*>(object), objectOffset, length, type);
case TypeFloat64:
return setWithSpecificType<Float64Adaptor>(
- exec, jsCast<JSFloat64Array*>(object), offset, length);
+ exec, offset, jsCast<JSFloat64Array*>(object), objectOffset, length, type);
case NotTypedArray:
case TypeDataView: {
if (!validateRange(exec, offset, length))
return false;
+
// We could optimize this case. But right now, we don't.
for (unsigned i = 0; i < length; ++i) {
- JSValue value = object->get(exec, i);
+ JSValue value = object->get(exec, i + objectOffset);
if (!setIndex(exec, offset + i, value))
return false;
}
Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (197191 => 197192)
--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h 2016-02-26 20:25:42 UTC (rev 197192)
@@ -45,6 +45,40 @@
static const char* typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
+// This implements 22.2.4.7 TypedArraySpeciesCreate
+// Note, that this function throws.
+template<typename Functor>
+inline JSArrayBufferView* speciesConstruct(ExecState* exec, JSObject* exemplar, MarkedArgumentBuffer& args, const Functor& defaultConstructor)
+{
+ JSValue constructor = exemplar->get(exec, exec->propertyNames().constructor);
+ if (exec->hadException())
+ return nullptr;
+
+ if (constructor.isUndefined())
+ return defaultConstructor();
+ if (!constructor.isObject()) {
+ throwTypeError(exec, "constructor Property should not be null");
+ return nullptr;
+ }
+
+ JSValue species = constructor.get(exec, exec->propertyNames().speciesSymbol);
+ if (exec->hadException())
+ return nullptr;
+
+ if (species.isUndefinedOrNull())
+ return defaultConstructor();
+
+ JSValue result = construct(exec, species, args, "species is not a constructor");
+ if (exec->hadException())
+ return nullptr;
+
+ if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(result))
+ return view;
+
+ throwTypeError(exec, "species constructor did not return a TypedArray View");
+ return nullptr;
+}
+
inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
{
JSValue value = exec->argument(argument);
@@ -99,7 +133,7 @@
if (exec->hadException())
return JSValue::encode(jsUndefined());
- thisObject->set(exec, sourceArray, offset, length);
+ thisObject->set(exec, offset, sourceArray, 0, length, CopyType::Unobservable);
return JSValue::encode(jsUndefined());
}
@@ -363,15 +397,53 @@
ASSERT(end >= begin);
unsigned length = end - begin;
- typename ViewClass::ElementType* array = thisObject->typedVector();
+ MarkedArgumentBuffer args;
+ args.append(jsNumber(length));
- Structure* structure =
- callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+ JSArrayBufferView* result = speciesConstruct(exec, thisObject, args, [&]() {
+ Structure* structure = callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+ return ViewClass::createUninitialized(exec, structure, length);
+ });
+ if (exec->hadException())
+ return JSValue::encode(JSValue());
- ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
+ // We return early here since we don't allocate a backing store if length is 0 and memmove does not like nullptrs
+ if (!length)
+ return JSValue::encode(result);
- // We can use memcpy since we know this a new buffer
- memcpy(static_cast<void*>(result->typedVector()), static_cast<void*>(array + begin), length * thisObject->elementSize);
+ // The species constructor may return an array with any arbitrary length.
+ length = std::min(length, result->length());
+ switch (result->classInfo()->typedArrayStorageType) {
+ case TypeInt8:
+ jsCast<JSInt8Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeInt16:
+ jsCast<JSInt16Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeInt32:
+ jsCast<JSInt32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeUint8:
+ jsCast<JSUint8Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeUint8Clamped:
+ jsCast<JSUint8ClampedArray*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeUint16:
+ jsCast<JSUint16Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeUint32:
+ jsCast<JSUint32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeFloat32:
+ jsCast<JSFloat32Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ case TypeFloat64:
+ jsCast<JSFloat64Array*>(result)->set(exec, 0, thisObject, begin, length, CopyType::LeftToRight);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
return JSValue::encode(result);
}
@@ -405,14 +477,24 @@
RefPtr<ArrayBuffer> arrayBuffer = thisObject->buffer();
RELEASE_ASSERT(thisLength == thisObject->length());
- Structure* structure =
- callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+ unsigned newByteOffset = thisObject->byteOffset() + offset * ViewClass::elementSize;
- ViewClass* result = ViewClass::create(
- exec, structure, arrayBuffer,
- thisObject->byteOffset() + offset * ViewClass::elementSize,
- length);
+ MarkedArgumentBuffer args;
+ args.append(exec->vm().m_typedArrayController->toJS(exec, thisObject->globalObject(), thisObject->buffer()));
+ args.append(jsNumber(newByteOffset));
+ args.append(jsNumber(length));
+ JSArrayBufferView* result = speciesConstruct(exec, thisObject, args, [&]() {
+ Structure* structure = callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+
+ return ViewClass::create(
+ exec, structure, arrayBuffer,
+ thisObject->byteOffset() + offset * ViewClass::elementSize,
+ length);
+ });
+ if (exec->hadException())
+ return JSValue::encode(JSValue());
+
return JSValue::encode(result);
}
Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-slice.js (197191 => 197192)
--- trunk/Source/_javascript_Core/tests/stress/typedarray-slice.js 2016-02-26 19:49:36 UTC (rev 197191)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-slice.js 2016-02-26 20:25:42 UTC (rev 197192)
@@ -38,7 +38,103 @@
var intView = new Int32Array(1)
var newView = intView.slice(0,1);
newView[0] = 1;
+debug("");
shouldBe("intView[0]", "0");
debug("");
+
+debug("4.0 Symbol.species Test");
+subclasses = typedArrays.map(function(constructor) { return class extends constructor { } } );
+
+function testSpecies(array, constructor) {
+ let newArray = array.slice(0, 0);
+ return newArray instanceof constructor;
+}
+shouldBeTrue("forEachTypedArray(subclasses, testSpecies)");
+
+Foo = class extends Int32Array { }
+subclasses.forEach(function(constructor) { Object.defineProperty(constructor, Symbol.species, { value:Foo, writable:true }); });
+function testSpeciesWithFoo(array, constructor) {
+ let newArray = array.slice(0, 0);
+ return newArray instanceof Foo;
+}
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesWithFoo)");
+debug("");
+
+debug("4.1 Symbol.species Test throws");
+subclasses.forEach(function(constructor) { Object.defineProperty(constructor, Symbol.species, { value:1, writable:true }); });
+shouldThrow("forEachTypedArray(subclasses, testSpecies)");
+
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = Array; });
+shouldThrow("forEachTypedArray(subclasses, testSpecies)");
+debug("");
+
+debug("4.2 Symbol.species Test with Defaults");
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = null; });
+function testSpeciesIsDefault(array, constructor) {
+ let newArray = array.slice(0, 0);
+ let defaultConstructor = typedArrays[subclasses.indexOf(constructor)];
+ return newArray instanceof defaultConstructor;
+}
+
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesIsDefault)");
+
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = undefined; });
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesIsDefault)");
+
+subclasses = typedArrays.map(function(constructor) { return class extends constructor { } } );
+function testSpeciesRemoveConstructor(array, constructor) {
+ array.constructor = undefined;
+ let newArray = array.slice(0, 0);
+ let defaultConstructor = typedArrays[subclasses.indexOf(constructor)];
+ return newArray instanceof defaultConstructor;
+}
+
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesRemoveConstructor)");
+debug("");
+
+debug("5.0 Symbol.species returns a different type");
+buffer = new ArrayBuffer(64);
+subclasses.forEach(function(constructor) { Object.defineProperty(constructor, Symbol.species, { value:1, writable:true }); });
+
+function setArray(array) {
+ array[0] = 43;
+ array[1] = 1.345;
+ array[3] = NaN;
+ array[4] = -Infinity;
+ array[5] = Infinity;
+ array[6] = -1;
+ array[7] = -0;
+ for (let i = 0; i < array.length; i++)
+ array[i] = 0;
+
+}
+
+function testSpeciesWithSameBuffer(unused, constructor) {
+ return typedArrays.every(function(speciesConstructor) {
+ constructor[Symbol.species] = function() { return new speciesConstructor(buffer); };
+ let array = new constructor(buffer);
+ let otherArray = new speciesConstructor(buffer);
+ setArray(array);
+ for (let i = 0; i < array.length; i++)
+ otherArray[i] = array[i];
+
+ let resultString = otherArray.toString();
+
+ setArray(array);
+ otherArray = array.slice(0,array.length)
+ let sliceString = otherArray.toString();
+
+ if (sliceString === resultString)
+ return true;
+
+ debug("Symbol.species didn't get the correct result got: " + sliceString + " but wanted: " + resultString);
+ debug("with initial type: " + constructor.__proto__.name + " and species type " + otherArray.constructor.name);
+ return false;
+ });
+}
+
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesWithSameBuffer)");
+
+
finishJSTest();
Added: trunk/Source/_javascript_Core/tests/stress/typedarray-subarray.js (0 => 197192)
--- trunk/Source/_javascript_Core/tests/stress/typedarray-subarray.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-subarray.js 2016-02-26 20:25:42 UTC (rev 197192)
@@ -0,0 +1,61 @@
+load("./resources/typedarray-test-helper-functions.js");
+description(
+"This test checks the behavior of the TypedArray.prototype.subarray function"
+);
+
+shouldBe("Int32Array.prototype.subarray.length", "2");
+shouldBe("Int32Array.prototype.subarray.name", "'subarray'");
+shouldBeTrue("isSameFunctionForEachTypedArrayPrototype('subarray')");
+shouldBeTrue("testPrototypeReceivesArray('subarray', [undefined, this, { }, [ ], true, ''])");
+debug("");
+
+debug("1.0 Symbol.species Test");
+subclasses = typedArrays.map(function(constructor) { return class extends constructor { } } );
+
+function testSpecies(array, constructor) {
+ let newArray = array.subarray(0, 0);
+ return newArray instanceof constructor;
+}
+shouldBeTrue("forEachTypedArray(subclasses, testSpecies)");
+
+Foo = class extends Int32Array { }
+subclasses.forEach(function(constructor) { Object.defineProperty(constructor, Symbol.species, { value:Foo, writable:true }); });
+function testSpeciesWithFoo(array, constructor) {
+ let newArray = array.subarray(0, 0);
+ return newArray instanceof Foo;
+}
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesWithFoo)");
+debug("");
+
+debug("4.1 Symbol.species Test throws");
+subclasses.forEach(function(constructor) { Object.defineProperty(constructor, Symbol.species, { value:1, writable:true }); });
+shouldThrow("forEachTypedArray(subclasses, testSpecies)");
+
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = Array; });
+shouldThrow("forEachTypedArray(subclasses, testSpecies)");
+debug("");
+
+debug("4.2 Symbol.species Test with Defaults");
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = null; });
+function testSpeciesIsDefault(array, constructor) {
+ let newArray = array.subarray(0, 0);
+ let defaultConstructor = typedArrays[subclasses.indexOf(constructor)];
+ return newArray instanceof defaultConstructor;
+}
+
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesIsDefault)");
+
+subclasses.forEach(function(constructor) { constructor[Symbol.species] = undefined; });
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesIsDefault)");
+
+subclasses = typedArrays.map(function(constructor) { return class extends constructor { } } );
+function testSpeciesRemoveConstructor(array, constructor) {
+ array.constructor = undefined;
+ let newArray = array.subarray(0, 0);
+ let defaultConstructor = typedArrays[subclasses.indexOf(constructor)];
+ return newArray instanceof defaultConstructor;
+}
+
+shouldBeTrue("forEachTypedArray(subclasses, testSpeciesRemoveConstructor)");
+
+finishJSTest();