Title: [263944] trunk
Revision
263944
Author
[email protected]
Date
2020-07-04 13:06:54 -0700 (Sat, 04 Jul 2020)

Log Message

%TypedArray%.prototype.{indexOf,lastIndexOf} are not spec-perfect
https://bugs.webkit.org/show_bug.cgi?id=213715

Reviewed by Yusuke Suzuki.

JSTests:

* microbenchmarks/array-prototype-indexOf-empty.js: Added.
* microbenchmarks/typed-array-indexOf-empty.js: Added.
* stress/array-indexof-tointeger-order.js: Added.
* test262/expectations.yaml: Mark 10 test cases as passing.

Source/_javascript_Core:

This patch:

1. Implements step 3 of {Array,%TypedArray%}.prototype.indexOf [1] and
   %TypedArray%.prototype.lastIndexOf [2] since it is observable when
   second argument is an object with userland toString() or valueOf() method.
   Advances provided microbenchmark by 100% for Array and by 25% for %TypedArray%.

2. Removes argument count check from %TypedArray%.prototype.{indexOf,lastIndexOf},
   allowing these methods to be invoked w/o arguments. The spec treats missing
   arguments as `undefined`, always returning -1 for typed arrays.

Both changes align JSC with V8 and SpiderMonkey.

[1]: https://tc39.es/ecma262/#sec-array.prototype.indexof
[2]: https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof

* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncIndexOf):
(JSC::arrayProtoFuncLastIndexOf):
* runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::genericTypedArrayViewProtoFuncIndexOf):
(JSC::genericTypedArrayViewProtoFuncLastIndexOf):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (263943 => 263944)


--- trunk/JSTests/ChangeLog	2020-07-04 20:06:27 UTC (rev 263943)
+++ trunk/JSTests/ChangeLog	2020-07-04 20:06:54 UTC (rev 263944)
@@ -1,3 +1,15 @@
+2020-07-04  Alexey Shvayka  <[email protected]>
+
+        %TypedArray%.prototype.{indexOf,lastIndexOf} are not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=213715
+
+        Reviewed by Yusuke Suzuki.
+
+        * microbenchmarks/array-prototype-indexOf-empty.js: Added.
+        * microbenchmarks/typed-array-indexOf-empty.js: Added.
+        * stress/array-indexof-tointeger-order.js: Added.
+        * test262/expectations.yaml: Mark 10 test cases as passing.
+
 2020-07-03  Yusuke Suzuki  <[email protected]>
 
         [JSC] Promise should check whether a user-provided function is set by using `@isUndefinedOrNull`

Added: trunk/JSTests/microbenchmarks/array-prototype-indexOf-empty.js (0 => 263944)


--- trunk/JSTests/microbenchmarks/array-prototype-indexOf-empty.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/array-prototype-indexOf-empty.js	2020-07-04 20:06:54 UTC (rev 263944)
@@ -0,0 +1,5 @@
+var empty = [];
+noInline(Array.prototype.indexOf);
+
+for (var i = 0; i < 1e7; ++i)
+    empty.indexOf(1);

Added: trunk/JSTests/microbenchmarks/typed-array-indexOf-empty.js (0 => 263944)


--- trunk/JSTests/microbenchmarks/typed-array-indexOf-empty.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/typed-array-indexOf-empty.js	2020-07-04 20:06:54 UTC (rev 263944)
@@ -0,0 +1,5 @@
+var empty = new Int8Array();
+noInline(Int8Array.prototype.indexOf);
+
+for (var i = 0; i < 1e7; ++i)
+    empty.indexOf(1);

Added: trunk/JSTests/stress/array-indexof-tointeger-order.js (0 => 263944)


--- trunk/JSTests/stress/array-indexof-tointeger-order.js	                        (rev 0)
+++ trunk/JSTests/stress/array-indexof-tointeger-order.js	2020-07-04 20:06:54 UTC (rev 263944)
@@ -0,0 +1,54 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion");
+}
+
+(function () {
+    function indexOfInt32(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32);
+
+    function indexOfDouble(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDouble);
+
+    function indexOfString(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfString);
+
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+    var doubleArray = [0, 1, 2, 3, 4.2, 5, 6, 7.33, 8, 9, 10.5];
+    var stringArray = ["cocoa", "cappuccino", "matcha", "rize"];
+
+    for (var i = 0; i < 1e5; ++i) {
+        assert(indexOfInt32(int32Array, 3, 2) === 3);
+        assert(indexOfDouble(doubleArray, 3, 1) === 3);
+        assert(indexOfString(stringArray, "cocoa", 0) === 0);
+    }
+
+    int32Array.length = 0;
+    doubleArray.splice(0);
+    while (stringArray.length) stringArray.pop();
+
+    assert($vm.indexingMode(int32Array) !== "ArrayWithUndecided");
+    assert($vm.indexingMode(doubleArray) !== "ArrayWithUndecided");
+    assert($vm.indexingMode(stringArray) !== "ArrayWithUndecided");
+
+    var fromIndex = {
+        get valueOf() {
+            throw new Error("fromIndex.valueOf");
+        },
+    };
+
+    for (var i = 0; i < 1e5; ++i) {
+        assert(indexOfInt32(int32Array, 3, fromIndex) === -1);
+        assert(indexOfDouble(doubleArray, 3, fromIndex) === -1);
+        assert(indexOfString(stringArray, "cocoa", fromIndex) === -1);
+    }
+}());

Modified: trunk/JSTests/test262/expectations.yaml (263943 => 263944)


--- trunk/JSTests/test262/expectations.yaml	2020-07-04 20:06:27 UTC (rev 263943)
+++ trunk/JSTests/test262/expectations.yaml	2020-07-04 20:06:54 UTC (rev 263944)
@@ -618,9 +618,6 @@
 test/annexB/language/statements/function/default-parameters-emulates-undefined.js:
   default: 'Test262Error: Expected SameValue(«undefined», «[object Function]») to be true'
   strict mode: 'Test262Error: Expected SameValue(«undefined», «[object Function]») to be true'
-test/built-ins/Array/prototype/indexOf/length-zero-returns-minus-one.js:
-  default: 'Test262Error: Length should be checked before ToInteger(fromIndex).'
-  strict mode: 'Test262Error: Length should be checked before ToInteger(fromIndex).'
 test/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js:
   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
@@ -1440,18 +1437,6 @@
 test/built-ins/TypedArray/prototype/filter/speciesctor-get-species-custom-ctor-length-throws.js:
   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all (Testing with Float64Array.)'
   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all (Testing with Float64Array.)'
-test/built-ins/TypedArray/prototype/indexOf/length-zero-returns-minus-one.js:
-  default: 'Test262Error:  (Testing with Float64Array.)'
-  strict mode: 'Test262Error:  (Testing with Float64Array.)'
-test/built-ins/TypedArray/prototype/indexOf/no-arg.js:
-  default: 'TypeError: Expected at least one argument (Testing with Float64Array.)'
-  strict mode: 'TypeError: Expected at least one argument (Testing with Float64Array.)'
-test/built-ins/TypedArray/prototype/lastIndexOf/length-zero-returns-minus-one.js:
-  default: 'Test262Error:  (Testing with Float64Array.)'
-  strict mode: 'Test262Error:  (Testing with Float64Array.)'
-test/built-ins/TypedArray/prototype/lastIndexOf/no-arg.js:
-  default: 'TypeError: Expected at least one argument (Testing with Float64Array.)'
-  strict mode: 'TypeError: Expected at least one argument (Testing with Float64Array.)'
 test/built-ins/TypedArray/prototype/map/speciesctor-get-ctor-returns-throws.js:
   default: 'Test262Error: 42 Expected a TypeError to be thrown but no exception was thrown at all (Testing with Float64Array.)'
   strict mode: 'Test262Error: 42 Expected a TypeError to be thrown but no exception was thrown at all (Testing with Float64Array.)'

Modified: trunk/Source/_javascript_Core/ChangeLog (263943 => 263944)


--- trunk/Source/_javascript_Core/ChangeLog	2020-07-04 20:06:27 UTC (rev 263943)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-07-04 20:06:54 UTC (rev 263944)
@@ -1,3 +1,33 @@
+2020-07-04  Alexey Shvayka  <[email protected]>
+
+        %TypedArray%.prototype.{indexOf,lastIndexOf} are not spec-perfect
+        https://bugs.webkit.org/show_bug.cgi?id=213715
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch:
+
+        1. Implements step 3 of {Array,%TypedArray%}.prototype.indexOf [1] and
+           %TypedArray%.prototype.lastIndexOf [2] since it is observable when
+           second argument is an object with userland toString() or valueOf() method.
+           Advances provided microbenchmark by 100% for Array and by 25% for %TypedArray%.
+
+        2. Removes argument count check from %TypedArray%.prototype.{indexOf,lastIndexOf},
+           allowing these methods to be invoked w/o arguments. The spec treats missing
+           arguments as `undefined`, always returning -1 for typed arrays.
+
+        Both changes align JSC with V8 and SpiderMonkey.
+
+        [1]: https://tc39.es/ecma262/#sec-array.prototype.indexof
+        [2]: https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::arrayProtoFuncIndexOf):
+        (JSC::arrayProtoFuncLastIndexOf):
+        * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+        (JSC::genericTypedArrayViewProtoFuncIndexOf):
+        (JSC::genericTypedArrayViewProtoFuncLastIndexOf):
+
 2020-07-04  Darin Adler  <[email protected]>
 
         [Cocoa] Remove unconditional features from FeatureDefines.xcconfig, making sure they are covered in PlatformEnableCocoa.h

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (263943 => 263944)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2020-07-04 20:06:27 UTC (rev 263943)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2020-07-04 20:06:54 UTC (rev 263944)
@@ -1386,6 +1386,8 @@
         return { };
     uint64_t length = static_cast<uint64_t>(toLength(globalObject, thisObject));
     RETURN_IF_EXCEPTION(scope, { });
+    if (!length)
+        return JSValue::encode(jsNumber(-1));
 
     uint64_t index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
     RETURN_IF_EXCEPTION(scope, { });
@@ -1423,7 +1425,8 @@
     if (UNLIKELY(!thisObject))
         return { };
     uint64_t length = static_cast<uint64_t>(toLength(globalObject, thisObject));
-    if (UNLIKELY(scope.exception()) || !length)
+    RETURN_IF_EXCEPTION(scope, { });
+    if (!length)
         return JSValue::encode(jsNumber(-1));
 
     uint64_t index = length - 1;

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (263943 => 263944)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2020-07-04 20:06:27 UTC (rev 263943)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2020-07-04 20:06:54 UTC (rev 263944)
@@ -233,11 +233,11 @@
     if (thisObject->isNeutered())
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
-    if (!callFrame->argumentCount())
-        return throwVMTypeError(globalObject, scope, "Expected at least one argument"_s);
-
     unsigned length = thisObject->length();
 
+    if (!length)
+        return JSValue::encode(jsNumber(-1));
+
     JSValue valueToFind = callFrame->argument(0);
     unsigned index = argumentClampedIndexFromStartOrEnd(globalObject, callFrame->argument(1), length);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -309,11 +309,11 @@
     if (thisObject->isNeutered())
         return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage);
 
-    if (!callFrame->argumentCount())
-        return throwVMTypeError(globalObject, scope, "Expected at least one argument"_s);
-
     unsigned length = thisObject->length();
 
+    if (!length)
+        return JSValue::encode(jsNumber(-1));
+
     JSValue valueToFind = callFrame->argument(0);
 
     int index = length - 1;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to