[dart2js][js_runtime] Use Array.isArray more consistently

The main reason is to do this change is to avoid inconsistencies in what is considered to be a `JSArray`. Using `Array.isArray` allows js-interop where the JavaScript code subclasses `Array`.

dart2js-production results:

ArrayLoop.pseudopoly.hoisted1-indexing  -50.20%
ArrayLoop.pseudopoly.indexing           -35.18%
Iteration.concat.manual                  11.69%
ListCopy.List.int.unmodifiable.2         12.03%
ListCopy.for.int.2                       12.58%
ListCopy.spread.int.2                    13.57%
ListCopy.toList.fixed.100                16.06%
ListCopy.List.of.fixed.100               16.96%
ListCopy.toList.100                      17.28%
ListCopy.spread.int.cast.2               18.45%
ObjectHash.hash.5                        19.62%
TypedDataPoly.A_UVx5.view.2              21.12%
ObjectHash.manual.5                      21.70%
ListCopy.spread.int.map.2                21.96%
ListCopy.spread.int.cast.100             22.12%
TypedDataPoly.A_UVx5.view.100            23.04%
ListCopy.spread.int.map.100              25.26%
ListCopy.List.of.100                     27.88%
ImagingGaussianBlurOnce                  29.67%
MegaEquality                             37.90%

An investigation of the two regressions shows that they benefit from a micro-benchmarking effect. The previous code was monomorphic at the property access in `receiver.constructor == Array`. If this is forced to be polymorphic, the baseline is quite a bit worse, leading to an improvement in line with some of the other benchmarks.


Change-Id: I5c265b1d7408fbd41da9c6fa17472bf648000c8d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287140
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
Stephen Adams
2023-04-18 20:39:39 +00:00
committed by Commit Queue
parent 000655e4d3
commit 62a67ba5bc
2 changed files with 5 additions and 6 deletions
@@ -69,7 +69,7 @@ class InterceptorStubGenerator {
cls == _commonElements.jsMutableArrayClass ||
cls == _commonElements.jsFixedArrayClass ||
cls == _commonElements.jsExtendableArrayClass) {
condition = js('receiver.constructor == Array');
condition = js('Array.isArray(receiver)');
} else if (cls == _commonElements.jsStringClass) {
condition = js('(typeof receiver) == "string"');
} else if (cls == _commonElements.jsNullClass) {
@@ -303,8 +303,7 @@ class InterceptorStubGenerator {
// For an index operation, this code generates:
//
// if (typeof a0 === "number") {
// if (receiver.constructor == Array ||
// typeof receiver == "string") {
// if (Array.isArray(receiver) || typeof receiver == "string") {
// if (a0 >>> 0 === a0 && a0 < receiver.length) {
// return receiver[a0];
// }
@@ -314,7 +313,7 @@ class InterceptorStubGenerator {
// For an index set operation, this code generates:
//
// if (typeof a0 === "number") {
// if (receiver.constructor == Array && !receiver.immutable$list) {
// if (Array.isArray(receiver) && !receiver.immutable$list) {
// if (a0 >>> 0 === a0 && a0 < receiver.length) {
// return receiver[a0] = a1;
// }
@@ -343,7 +342,7 @@ class InterceptorStubGenerator {
if (!containsArray && !containsString) {
return null;
}
jsAst.Expression arrayCheck = js('receiver.constructor == Array');
jsAst.Expression arrayCheck = js('Array.isArray(receiver)');
// Lazy generation of the indexable check. If indexable behavior isn't
// used, the isJsIndexable function isn't part of the closed world.
@@ -385,7 +385,7 @@ void initHooks() {
if (JS('bool', 'typeof # == "function"', transformers)) {
transformers = [transformers];
}
if (JS('bool', '#.constructor == Array', transformers)) {
if (JS('bool', 'Array.isArray(#)', transformers)) {
for (int i = 0; i < JS('int', '#.length', transformers); i++) {
var transformer = JS('', '#[#]', transformers, i);
if (JS('bool', 'typeof # == "function"', transformer)) {