[JSC] AI should convert IsCellWithType to constant when Structure set is finite
https://bugs.webkit.org/show_bug.cgi?id=204141

Reviewed by Mark Lam.

JSTests:

* stress/generator-cell-with-type.js: Added.
(shouldBe):
(shouldThrow):
(test):
(i.shouldThrow):
* stress/is-cell-with-type-should-check-non-cell-cases.js: Added.
(getter):
(foo):

Source/JavaScriptCore:

We should fold IsCellWithType if Structure set is finite since we have a chance to know what JSType is.
The difference from the last patch is that we have `if (!(child.m_type & ~SpecCell))` check. Even if
structures meet the requirement, this structures do not guarantee that non cell types never come. We
should ensure it by using proven type.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@253144 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 7d9c572..d2b8174 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,19 @@
+2019-12-04  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] AI should convert IsCellWithType to constant when Structure set is finite
+        https://bugs.webkit.org/show_bug.cgi?id=204141
+
+        Reviewed by Mark Lam.
+
+        * stress/generator-cell-with-type.js: Added.
+        (shouldBe):
+        (shouldThrow):
+        (test):
+        (i.shouldThrow):
+        * stress/is-cell-with-type-should-check-non-cell-cases.js: Added.
+        (getter):
+        (foo):
+
 2019-12-04  Mark Lam  <mark.lam@apple.com>
 
         Fix missing exception check in ArrayPrototype's fastJoin().
diff --git a/JSTests/stress/generator-cell-with-type.js b/JSTests/stress/generator-cell-with-type.js
new file mode 100644
index 0000000..fdc6e88
--- /dev/null
+++ b/JSTests/stress/generator-cell-with-type.js
@@ -0,0 +1,45 @@
+// This test takes too long on arm and mips devices.
+//@ skip if ["arm", "mips"].include?($architecture)
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+function *generator()
+{
+}
+
+function test(gen)
+{
+    var func = gen.next;
+    shouldBe(gen.next().done, true);
+    return func;
+}
+noInline(test);
+var gen = generator();
+for (var i = 0; i < 1e6; ++i)
+    test(gen);
+
+for (var i = 0; i < 1e6; ++i) {
+    test(gen);
+    shouldThrow(() => {
+        test({
+            __proto__: gen.__proto__
+        });
+    }, `TypeError: |this| should be a generator`);
+}
diff --git a/JSTests/stress/is-cell-with-type-should-check-non-cell-cases.js b/JSTests/stress/is-cell-with-type-should-check-non-cell-cases.js
new file mode 100644
index 0000000..e056ee5
--- /dev/null
+++ b/JSTests/stress/is-cell-with-type-should-check-non-cell-cases.js
@@ -0,0 +1,13 @@
+function getter() {
+  if (+undefined) {
+    return '';
+  }
+}
+
+function foo() {}
+
+Object.defineProperty(foo, 'name', {get: getter});
+
+for (let i=0; i<10000; i++) {
+  foo.bind(null, foo, null);
+}
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 7529a31..a79dab0 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,20 @@
 2019-12-04  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] AI should convert IsCellWithType to constant when Structure set is finite
+        https://bugs.webkit.org/show_bug.cgi?id=204141
+
+        Reviewed by Mark Lam.
+
+        We should fold IsCellWithType if Structure set is finite since we have a chance to know what JSType is.
+        The difference from the last patch is that we have `if (!(child.m_type & ~SpecCell))` check. Even if
+        structures meet the requirement, this structures do not guarantee that non cell types never come. We
+        should ensure it by using proven type.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+
+2019-12-04  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] Put TypedArrays in IsoSubspace
         https://bugs.webkit.org/show_bug.cgi?id=204867
 
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index f91d4f4..220b0fd 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -1444,6 +1444,37 @@
             if (constantWasSet)
                 break;
         }
+
+        if (!(child.m_type & ~SpecCell)) {
+            if (child.m_structure.isFinite()) {
+                bool constantWasSet = false;
+                switch (node->op()) {
+                case IsCellWithType: {
+                    bool ok = true;
+                    Optional<bool> result;
+                    child.m_structure.forEach(
+                        [&](RegisteredStructure structure) {
+                            bool matched = structure->typeInfo().type() == node->queriedType();
+                            if (!result)
+                                result = matched;
+                            else {
+                                if (result.value() != matched)
+                                    ok = false;
+                            }
+                        });
+                    if (ok && result) {
+                        setConstant(node, jsBoolean(result.value()));
+                        constantWasSet = true;
+                    }
+                    break;
+                }
+                default:
+                    break;
+                }
+                if (constantWasSet)
+                    break;
+            }
+        }
         
         // FIXME: This code should really use AbstractValue::isType() and
         // AbstractValue::couldBeType().