Title: [203297] trunk/Source/_javascript_Core
Revision
203297
Author
[email protected]
Date
2016-07-15 13:58:52 -0700 (Fri, 15 Jul 2016)

Log Message

%TypedArray%.prototype.indexOf is coercing non-integers or non-floats to numbers wrongly
https://bugs.webkit.org/show_bug.cgi?id=159400

Reviewed by Geoffrey Garen.

This patch fixes coercion of non-numbers in indexOf/lastIndexOf.
Additionally, this patch fixes an issue with includes where it
would not check that the buffer remained non-neutered after
calling the toInteger() function. Lastly, some extra release
asserts have been added in some places to inform us of any issues
in the future.

Additionally, this patch changes bool toNativeFromDouble to
Optional<Type> toNativeFromDoubleWithoutCoercion. This makes it a
little clearer what the function does and also removes the return
argument. The only behavior change is that the function no longer
coerces non-numbers into numbers. That behavior was unused (maybe
unintended), however.

* runtime/JSGenericTypedArrayView.h:
(JSC::JSGenericTypedArrayView::toAdaptorNativeFromValueWithoutCoercion):
(JSC::JSGenericTypedArrayView::sort):
(JSC::JSGenericTypedArrayView::toAdaptorNativeFromValue): Deleted.
* runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::genericTypedArrayViewProtoFuncCopyWithin):
(JSC::genericTypedArrayViewProtoFuncIncludes):
(JSC::genericTypedArrayViewProtoFuncIndexOf):
(JSC::genericTypedArrayViewProtoFuncLastIndexOf):
* runtime/ToNativeFromValue.h:
(JSC::toNativeFromValueWithoutCoercion):
(JSC::toNativeFromValue): Deleted.
* runtime/TypedArrayAdaptors.h:
(JSC::IntegralTypedArrayAdaptor::toNativeFromInt32WithoutCoercion):
(JSC::IntegralTypedArrayAdaptor::toNativeFromUint32WithoutCoercion):
(JSC::IntegralTypedArrayAdaptor::toNativeFromDoubleWithoutCoercion):
(JSC::FloatTypedArrayAdaptor::toNativeFromInt32WithoutCoercion):
(JSC::FloatTypedArrayAdaptor::toNativeFromDoubleWithoutCoercion):
(JSC::Uint8ClampedAdaptor::toNativeFromInt32WithoutCoercion):
(JSC::Uint8ClampedAdaptor::toNativeFromDoubleWithoutCoercion):
(JSC::IntegralTypedArrayAdaptor::toNativeFromInt32): Deleted.
(JSC::IntegralTypedArrayAdaptor::toNativeFromUint32): Deleted.
(JSC::IntegralTypedArrayAdaptor::toNativeFromDouble): Deleted.
(JSC::FloatTypedArrayAdaptor::toNativeFromInt32): Deleted.
(JSC::FloatTypedArrayAdaptor::toNativeFromDouble): Deleted.
(JSC::Uint8ClampedAdaptor::toNativeFromInt32): Deleted.
(JSC::Uint8ClampedAdaptor::toNativeFromDouble): Deleted.
* tests/stress/resources/typedarray-test-helper-functions.js:
* tests/stress/typedarray-functions-with-neutered.js:
(callWithArgs):
* tests/stress/typedarray-includes.js: Added.
* tests/stress/typedarray-indexOf.js:
* tests/stress/typedarray-lastIndexOf.js:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (203296 => 203297)


--- trunk/Source/_javascript_Core/ChangeLog	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-07-15 20:58:52 UTC (rev 203297)
@@ -1,3 +1,58 @@
+2016-07-15  Keith Miller  <[email protected]>
+
+        %TypedArray%.prototype.indexOf is coercing non-integers or non-floats to numbers wrongly
+        https://bugs.webkit.org/show_bug.cgi?id=159400
+
+        Reviewed by Geoffrey Garen.
+
+        This patch fixes coercion of non-numbers in indexOf/lastIndexOf.
+        Additionally, this patch fixes an issue with includes where it
+        would not check that the buffer remained non-neutered after
+        calling the toInteger() function. Lastly, some extra release
+        asserts have been added in some places to inform us of any issues
+        in the future.
+
+        Additionally, this patch changes bool toNativeFromDouble to
+        Optional<Type> toNativeFromDoubleWithoutCoercion. This makes it a
+        little clearer what the function does and also removes the return
+        argument. The only behavior change is that the function no longer
+        coerces non-numbers into numbers. That behavior was unused (maybe
+        unintended), however.
+
+        * runtime/JSGenericTypedArrayView.h:
+        (JSC::JSGenericTypedArrayView::toAdaptorNativeFromValueWithoutCoercion):
+        (JSC::JSGenericTypedArrayView::sort):
+        (JSC::JSGenericTypedArrayView::toAdaptorNativeFromValue): Deleted.
+        * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+        (JSC::genericTypedArrayViewProtoFuncCopyWithin):
+        (JSC::genericTypedArrayViewProtoFuncIncludes):
+        (JSC::genericTypedArrayViewProtoFuncIndexOf):
+        (JSC::genericTypedArrayViewProtoFuncLastIndexOf):
+        * runtime/ToNativeFromValue.h:
+        (JSC::toNativeFromValueWithoutCoercion):
+        (JSC::toNativeFromValue): Deleted.
+        * runtime/TypedArrayAdaptors.h:
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromInt32WithoutCoercion):
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromUint32WithoutCoercion):
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromDoubleWithoutCoercion):
+        (JSC::FloatTypedArrayAdaptor::toNativeFromInt32WithoutCoercion):
+        (JSC::FloatTypedArrayAdaptor::toNativeFromDoubleWithoutCoercion):
+        (JSC::Uint8ClampedAdaptor::toNativeFromInt32WithoutCoercion):
+        (JSC::Uint8ClampedAdaptor::toNativeFromDoubleWithoutCoercion):
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromInt32): Deleted.
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromUint32): Deleted.
+        (JSC::IntegralTypedArrayAdaptor::toNativeFromDouble): Deleted.
+        (JSC::FloatTypedArrayAdaptor::toNativeFromInt32): Deleted.
+        (JSC::FloatTypedArrayAdaptor::toNativeFromDouble): Deleted.
+        (JSC::Uint8ClampedAdaptor::toNativeFromInt32): Deleted.
+        (JSC::Uint8ClampedAdaptor::toNativeFromDouble): Deleted.
+        * tests/stress/resources/typedarray-test-helper-functions.js:
+        * tests/stress/typedarray-functions-with-neutered.js:
+        (callWithArgs):
+        * tests/stress/typedarray-includes.js: Added.
+        * tests/stress/typedarray-indexOf.js:
+        * tests/stress/typedarray-lastIndexOf.js:
+
 2016-07-15  Csaba Osztrogonác  <[email protected]>
 
         Add new functions to ARMAssembler after r202214

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h (203296 => 203297)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayView.h	2016-07-15 20:58:52 UTC (rev 203297)
@@ -186,10 +186,11 @@
 
     static ElementType toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue) { return toNativeFromValue<Adaptor>(exec, jsValue); }
 
-    static bool toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue, ElementType& result) { return toNativeFromValue<Adaptor>(exec, jsValue, result); }
+    static Optional<ElementType> toAdaptorNativeFromValueWithoutCoercion(JSValue jsValue) { return toNativeFromValueWithoutCoercion<Adaptor>(jsValue); }
 
     void sort()
     {
+        RELEASE_ASSERT(!isNeutered());
         switch (Adaptor::typeValue) {
         case TypeFloat32:
             sortFloat<int32_t>();

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (203296 => 203297)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2016-07-15 20:58:52 UTC (rev 203297)
@@ -154,14 +154,14 @@
     if (vm.exception())
         return encodedJSValue();
 
-    if (thisObject->isNeutered())
-        return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
-
     if (final < from)
         return JSValue::encode(exec->thisValue());
 
     long count = std::min(length - std::max(to, from), final - from);
 
+    if (thisObject->isNeutered())
+        return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
     typename ViewClass::ElementType* array = thisObject->typedVector();
     memmove(array + to, array + from, count * thisObject->elementSize);
 
@@ -171,6 +171,7 @@
 template<typename ViewClass>
 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncIncludes(ExecState* exec)
 {
+    VM& vm = exec->vm();
     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
     if (thisObject->isNeutered())
         return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
@@ -183,19 +184,21 @@
     JSValue valueToFind = exec->argument(0);
 
     unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+    if (vm.exception())
+        return JSValue::encode(jsUndefined());
 
-    if (!valueToFind.isNumber())
-        return JSValue::encode(jsBoolean(false));
+    if (thisObject->isNeutered())
+        return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
-    typename ViewClass::ElementType target;
-    if (!ViewClass::toAdaptorNativeFromValue(exec, valueToFind, target))
+    auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
+    if (!targetOption)
         return JSValue::encode(jsBoolean(false));
 
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
+    ASSERT(!vm.exception());
+    RELEASE_ASSERT(!thisObject->isNeutered());
 
-    if (std::isnan(static_cast<double>(target))) {
+    if (std::isnan(static_cast<double>(*targetOption))) {
         for (; index < length; ++index) {
             if (std::isnan(static_cast<double>(array[index])))
                 return JSValue::encode(jsBoolean(true));
@@ -202,7 +205,7 @@
         }
     } else {
         for (; index < length; ++index) {
-            if (array[index] == target)
+            if (array[index] == targetOption)
                 return JSValue::encode(jsBoolean(true));
         }
     }
@@ -233,12 +236,14 @@
         return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
 
     typename ViewClass::ElementType* array = thisObject->typedVector();
-    typename ViewClass::ElementType target = ViewClass::toAdaptorNativeFromValue(exec, valueToFind);
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
+    auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
+    if (!targetOption)
+        return JSValue::encode(jsNumber(-1));
+    ASSERT(!vm.exception());
+    RELEASE_ASSERT(!thisObject->isNeutered());
 
     for (; index < length; ++index) {
-        if (array[index] == target)
+        if (array[index] == targetOption)
             return JSValue::encode(jsNumber(index));
     }
 
@@ -287,6 +292,7 @@
 EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncLastIndexOf(ExecState* exec)
 {
     // 22.2.3.16
+    VM& vm = exec->vm();
     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
     if (thisObject->isNeutered())
         return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
@@ -311,16 +317,22 @@
             index = static_cast<unsigned>(fromDouble);
     }
 
+    if (vm.exception())
+        return JSValue::encode(JSValue());
+
     if (thisObject->isNeutered())
         return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
 
+    auto targetOption = ViewClass::toAdaptorNativeFromValueWithoutCoercion(valueToFind);
+    if (!targetOption)
+        return JSValue::encode(jsNumber(-1));
+
     typename ViewClass::ElementType* array = thisObject->typedVector();
-    typename ViewClass::ElementType target = ViewClass::toAdaptorNativeFromValue(exec, valueToFind);
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
+    ASSERT(!vm.exception());
+    RELEASE_ASSERT(!thisObject->isNeutered());
 
     for (; index >= 0; --index) {
-        if (array[index] == target)
+        if (array[index] == targetOption)
             return JSValue::encode(jsNumber(index));
     }
 

Modified: trunk/Source/_javascript_Core/runtime/ToNativeFromValue.h (203296 => 203297)


--- trunk/Source/_javascript_Core/runtime/ToNativeFromValue.h	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/runtime/ToNativeFromValue.h	2016-07-15 20:58:52 UTC (rev 203297)
@@ -49,13 +49,13 @@
 }
 
 template<typename Adaptor>
-bool toNativeFromValue(ExecState* exec, JSValue value, typename Adaptor::Type& result)
+Optional<typename Adaptor::Type> toNativeFromValueWithoutCoercion(JSValue value)
 {
+    if (!value.isNumber())
+        return Nullopt;
     if (value.isInt32())
-        return Adaptor::toNativeFromInt32(value.asInt32(), result);
-    if (value.isNumber())
-        return Adaptor::toNativeFromDouble(value.asDouble(), result);
-    return Adaptor::toNativeFromDouble(value.toNumber(exec), result);
+        return Adaptor::toNativeFromInt32WithoutCoercion(value.asInt32());
+    return Adaptor::toNativeFromDoubleWithoutCoercion(value.asDouble());
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/TypedArrayAdaptors.h (203296 => 203297)


--- trunk/Source/_javascript_Core/runtime/TypedArrayAdaptors.h	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/runtime/TypedArrayAdaptors.h	2016-07-15 20:58:52 UTC (rev 203297)
@@ -79,36 +79,31 @@
         return OtherAdaptor::toNativeFromInt32(value);
     }
 
-    static bool toNativeFromInt32(int32_t value, Type& result)
+    static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
     {
         if ((value >= 0 && static_cast<uint32_t>(value) > static_cast<uint32_t>(maxValue)) || value < static_cast<int32_t>(minValue))
-            return false;
-
-        result = static_cast<Type>(value);
-
-        return true;
+            return Nullopt;
+        return static_cast<Type>(value);
     }
 
-    static bool toNativeFromUint32(uint32_t value, Type& result)
+    static Optional<Type> toNativeFromUint32WithoutCoercion(uint32_t value)
     {
         if (value > static_cast<uint32_t>(maxValue))
-            return false;
+            return Nullopt;
 
-        result = static_cast<Type>(value);
-
-        return true;
+        return static_cast<Type>(value);
     }
 
-    static bool toNativeFromDouble(double value, Type& result)
+    static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
     {
         Type integer = static_cast<Type>(value);
         if (static_cast<double>(integer) != value)
-            return false;
+            return Nullopt;
 
         if (value < 0)
-            return toNativeFromInt32(static_cast<int32_t>(value), result);
+            return toNativeFromInt32WithoutCoercion(static_cast<int32_t>(value));
         
-        return toNativeFromUint32(static_cast<uint32_t>(value), result);
+        return toNativeFromUint32WithoutCoercion(static_cast<uint32_t>(value));
     }
 };
 
@@ -154,29 +149,25 @@
         return OtherAdaptor::toNativeFromDouble(value);
     }
 
-    static bool toNativeFromInt32(int32_t value, Type& result)
+    static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
     {
-        result = static_cast<Type>(value);
-        return true;
+        return static_cast<Type>(value);
     }
 
-    static Type toNativeFromDouble(double value, Type& result)
+    static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
     {
-        if (std::isnan(value) || std::isinf(value)) {
-            result = static_cast<Type>(value);
-            return true;
-        }
+        if (std::isnan(value) || std::isinf(value))
+            return static_cast<Type>(value);
 
         Type valueResult = static_cast<Type>(value);
 
         if (static_cast<double>(valueResult) != value)
-            return false;
+            return Nullopt;
 
         if (value < minValue || value > maxValue)
-            return false;
+            return Nullopt;
 
-        result = valueResult;
-        return true;
+        return valueResult;
     }
 };
 
@@ -264,24 +255,21 @@
         return OtherAdaptor::toNativeFromInt32(value);
     }
     
-    static bool toNativeFromInt32(int32_t value, Type& result)
+    static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
     {
         if (value > maxValue || value < minValue)
-            return false;
+            return Nullopt;
 
-        result = static_cast<Type>(value);
-
-        return true;
+        return static_cast<Type>(value);
     }
 
-    static bool toNativeFromDouble(double value, uint8_t& result)
+    static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
     {
         uint8_t integer = static_cast<uint8_t>(value);
         if (static_cast<double>(integer) != value)
-            return false;
+            return Nullopt;
 
-        result = integer;
-        return true;
+        return integer;
     }
 
 private:

Modified: trunk/Source/_javascript_Core/tests/stress/resources/typedarray-test-helper-functions.js (203296 => 203297)


--- trunk/Source/_javascript_Core/tests/stress/resources/typedarray-test-helper-functions.js	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/tests/stress/resources/typedarray-test-helper-functions.js	2016-07-15 20:58:52 UTC (rev 203297)
@@ -4,6 +4,8 @@
 
 var signedArrays = [Int8Array, Int16Array, Int32Array, Float32Array, Float64Array];
 
+var intArrays = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array];
+
 var floatArrays = [Float32Array, Float64Array];
 
 function forEachTypedArray(constructors, testFunction /* , initialValues */ ) {

Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js (203296 => 203297)


--- trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-functions-with-neutered.js	2016-07-15 20:58:52 UTC (rev 203297)
@@ -83,6 +83,7 @@
     { func:proto.findIndex, args:["func"] },
     { func:proto.forEach, args:["func"] },
     { func:proto.indexOf, args:["na", "prim"] },
+    { func:proto.includes, args:["na", "prim"] },
     { func:proto.join, args:["prim"] },
     { func:proto.lastIndexOf, args:["na", "prim"] },
     { func:proto.map, args:["func"] },
@@ -105,7 +106,7 @@
     return argNum;
 }
 
-function callWithArgs(func, array, args) {
+function callWithArgs(func, array, args, argNum) {
     let failed = true;
     try {
         func.call(array, ...args);
@@ -115,7 +116,7 @@
         failed = false;
     }
     if (failed)
-        throw new Error([func, args]);
+        throw new Error([func, argNum]);
 }
 
 
@@ -135,13 +136,13 @@
                 transferArrayBuffer(array.buffer);
                 return func === array.every ? 1 : 0;
             };
-            callWithArgs(func, array, callArgs);
+            callWithArgs(func, array, callArgs, argNum);
         } else if (arg === "prim") {
             callArgs[argNum] = { [Symbol.toPrimitive]() {
                 transferArrayBuffer(array.buffer);
                 return argNum;
             } };
-            callWithArgs(func, array, callArgs);
+            callWithArgs(func, array, callArgs, argNum);
         } else if (arg === "array") {
             callArgs[argNum] = new Array(4);
             callArgs[argNum].fill(2);
@@ -150,7 +151,7 @@
                 return 1;
             } };
             Object.defineProperty(callArgs[argNum], 1, desc);
-            callWithArgs(func, array, callArgs);
+            callWithArgs(func, array, callArgs, argNum);
         } else
             throw new Error(arg);
     }

Added: trunk/Source/_javascript_Core/tests/stress/typedarray-includes.js (0 => 203297)


--- trunk/Source/_javascript_Core/tests/stress/typedarray-includes.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-includes.js	2016-07-15 20:58:52 UTC (rev 203297)
@@ -0,0 +1,10 @@
+load("resources/typedarray-test-helper-functions.js");
+
+for (constructor of typedArrays) {
+    let a = new constructor(10);
+    passed = true;
+    result = a.includes({ valueOf() { passed = false; return 1; } });
+    shouldBeTrue("passed");
+    shouldBeFalse("result");
+}
+finishJSTest();

Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-indexOf.js (203296 => 203297)


--- trunk/Source/_javascript_Core/tests/stress/typedarray-indexOf.js	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-indexOf.js	2016-07-15 20:58:52 UTC (rev 203297)
@@ -28,4 +28,40 @@
 shouldBeTrue("testPrototypeFunction('indexOf', '(2, -1)', array, 3)");
 shouldBeTrue("testPrototypeFunction('indexOf', '(2, -2)', array, 3)");
 debug("");
+
+debug("Check object coersion");
+for (constructor of typedArrays) {
+    a = new constructor([0,2,3]);
+    passed = true;
+
+    shouldBe("a.indexOf({ valueOf() { passed = false; return 1; }})", "-1");
+    shouldBeTrue("passed");
+    shouldBe("a.indexOf(3, {valueOf: () => -1})", "2");
+
+    // test we don't coerce non-native values
+    shouldBe("a.indexOf(\"abc\")", "-1");
+    shouldBe("a.indexOf(null)", "-1");
+    shouldBe("a.indexOf(undefined)", "-1");
+    shouldBe("a.indexOf({1: ''})", "-1");
+    shouldBe("a.indexOf(\"\")", "-1");
+}
+
+
+for (constructor of intArrays) {
+    a = new constructor([0,2,3]);
+
+    shouldBe("a.indexOf(2.0)", "1");
+    shouldBe("a.indexOf(2.5)", "-1");
+}
+
+for (constructor of floatArrays) {
+    a = new constructor([0,2.0,3.6, NaN, Infinity]);
+
+    shouldBe("a.indexOf(2.0)", "1");
+    shouldBe("a.indexOf(2.5)", "-1");
+    shouldBe("a.indexOf(3.600001)", "-1");
+    shouldBe("a.indexOf(NaN)", "-1");
+    shouldBe("a.indexOf(Infinity)", "4");
+}
+
 finishJSTest();

Modified: trunk/Source/_javascript_Core/tests/stress/typedarray-lastIndexOf.js (203296 => 203297)


--- trunk/Source/_javascript_Core/tests/stress/typedarray-lastIndexOf.js	2016-07-15 20:56:29 UTC (rev 203296)
+++ trunk/Source/_javascript_Core/tests/stress/typedarray-lastIndexOf.js	2016-07-15 20:58:52 UTC (rev 203297)
@@ -25,4 +25,40 @@
 shouldBeTrue("testPrototypeFunction('lastIndexOf', '(2, -1)', array, 3)");
 shouldBeTrue("testPrototypeFunction('lastIndexOf', '(2, -2)', array, 0)");
 debug("");
+
+debug("Check object coersion");
+for (constructor of typedArrays) {
+    a = new constructor([0,2,3]);
+    passed = true;
+
+    shouldBe("a.lastIndexOf({ valueOf() { passed = false; return 1; }})", "-1");
+    shouldBeTrue("passed");
+    shouldBe("a.lastIndexOf(3, {valueOf: () => 3})", "2");
+
+    // test we don't coerce non-native values
+    shouldBe("a.lastIndexOf(\"abc\")", "-1");
+    shouldBe("a.lastIndexOf(null)", "-1");
+    shouldBe("a.lastIndexOf(undefined)", "-1");
+    shouldBe("a.lastIndexOf({1: ''})", "-1");
+    shouldBe("a.lastIndexOf(\"\")", "-1");
+}
+
+
+for (constructor of intArrays) {
+    a = new constructor([0,2,3]);
+
+    shouldBe("a.lastIndexOf(2.0)", "1");
+    shouldBe("a.lastIndexOf(2.5)", "-1");
+}
+
+for (constructor of floatArrays) {
+    a = new constructor([0,2.0,3.6, NaN, Infinity]);
+
+    shouldBe("a.lastIndexOf(2.0)", "1");
+    shouldBe("a.lastIndexOf(2.5)", "-1");
+    shouldBe("a.lastIndexOf(3.600001)", "-1");
+    shouldBe("a.lastIndexOf(NaN)", "-1");
+    shouldBe("a.lastIndexOf(Infinity)", "4");
+}
+
 finishJSTest();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to