[Builtins] Array.prototype.filter species creation error

If a species constructor is installed, filter() needs to loop over
the elements of the array in the "slow" way, because it doesn't
know the ElementsKind of the output array. The code failed to
bail out to the slow case for the loop right away on discovering this.

Bug: chromium:920184, chromium:920491
Change-Id: I74496db20a90807b631c1bebe7604d85b199df67
Reviewed-on: https://chromium-review.googlesource.com/c/1405035
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58713}
diff --git a/src/builtins/array-filter.tq b/src/builtins/array-filter.tq
index 1bfc2e4..d7ddf8c 100644
--- a/src/builtins/array-filter.tq
+++ b/src/builtins/array-filter.tq
@@ -173,20 +173,16 @@
   }
 
   // This method creates a 0-length array with the ElementsKind of the
-  // receiver if possible, otherwise, calls the species constructor.
-  macro FilterSpeciesCreate(implicit context: Context)(receiver: JSReceiver):
-      JSReceiver {
+  // receiver if possible, otherwise, bails out. It makes sense for the
+  // caller to know that the slow case needs to be invoked.
+  macro FastFilterSpeciesCreate(implicit context: Context)(
+      receiver: JSReceiver): JSReceiver labels Slow {
     const len: Smi = 0;
-    try {
-      if (IsArraySpeciesProtectorCellInvalid()) goto Slow;
-      const o: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
-      const newMap: Map = LoadJSArrayElementsMap(
-          o.map.elements_kind, LoadNativeContext(context));
-      return AllocateJSArray(PACKED_SMI_ELEMENTS, newMap, len, len);
-    }
-    label Slow {
-      return ArraySpeciesCreate(context, receiver, len);
-    }
+    if (IsArraySpeciesProtectorCellInvalid()) goto Slow;
+    const o: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
+    const newMap: Map =
+        LoadJSArrayElementsMap(o.map.elements_kind, LoadNativeContext(context));
+    return AllocateJSArray(PACKED_SMI_ELEMENTS, newMap, len, len);
   }
 
   // https://tc39.github.io/ecma262/#sec-array.prototype.filter
@@ -213,18 +209,25 @@
 
       // 4. If thisArg is present, let T be thisArg; else let T be undefined.
       const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
-      const array: JSReceiver = FilterSpeciesCreate(o);
+      let array: JSReceiver;
 
       // Special cases.
       let k: Number = 0;
       let to: Number = 0;
       try {
-        return FastArrayFilter(o, len, callbackfn, thisArg, array)
-            otherwise Bailout;
+        array = FastFilterSpeciesCreate(o) otherwise SlowSpeciesCreate;
+
+        try {
+          return FastArrayFilter(o, len, callbackfn, thisArg, array)
+              otherwise Bailout;
+        }
+        label Bailout(kValue: Smi, toValue: Smi) deferred {
+          k = kValue;
+          to = toValue;
+        }
       }
-      label Bailout(kValue: Smi, toValue: Smi) deferred {
-        k = kValue;
-        to = toValue;
+      label SlowSpeciesCreate {
+        array = ArraySpeciesCreate(context, receiver, 0);
       }
 
       return ArrayFilterLoopContinuation(
diff --git a/test/mjsunit/regress/regress-crbug-920184.js b/test/mjsunit/regress/regress-crbug-920184.js
new file mode 100644
index 0000000..c38f181
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-920184.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --verify-heap --enable-slow-asserts
+
+var Ctor = function() {
+  return [];
+};
+var a = ["one", "two", "three"];
+a.constructor = {};
+a.constructor[Symbol.species] = Ctor;
+
+a.filter(function() { return true; });