Title: [197192] trunk/Source/_javascript_Core
Revision
197192
Author
[email protected]
Date
2016-02-26 12:25:42 -0800 (Fri, 26 Feb 2016)

Log Message

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):

Modified Paths

Added Paths

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();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to