Constant fold CheckTypeInfoFlags on ImplementsDefaultHasInstance
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 May 2018 01:49:24 +0000 (01:49 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 May 2018 01:49:24 +0000 (01:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185670

Reviewed by Yusuke Suzuki.

JSTests:

* microbenchmarks/constant-fold-check-type-info-flags.js: Added.
* stress/dont-constant-fold-check-type-info-on-bound-function.js: Added.

Source/JavaScriptCore:

This patch makes it so that we constant fold CheckTypeInfoFlags for
ImplementsDefaultHasInstance inside of AI/constant folding. We constant
fold in three ways:
- When the incoming value is a constant, we just look at its inline type
flags. Since those flags never change after an object is created, this
is sound.
- Based on the incoming value having a finite structure set. We just iterate
all structures and ensure they have the bit set.
- Based on speculated type. To do this, I split up SpecFunction into two
subheaps where one is for functions that have the bit set, and one for
functions that don't have the bit set. The latter is currently only comprised
of JSBoundFunctions. To constant fold, we check that the incoming
value only has the SpecFunction type with ImplementsDefaultHasInstance set.

* bytecode/SpeculatedType.cpp:
(JSC::speculationFromClassInfo):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCheckTypeInfoFlags):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* runtime/JSFunction.cpp:
(JSC::JSFunction::JSFunction):
(JSC::JSFunction::assertTypeInfoFlagInvariants):
* runtime/JSFunction.h:
(JSC::JSFunction::assertTypeInfoFlagInvariants):
* runtime/JSFunctionInlines.h:
(JSC::JSFunction::JSFunction):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231882 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
JSTests/ChangeLog
JSTests/microbenchmarks/constant-fold-check-type-info-flags.js [new file with mode: 0644]
JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSFunctionInlines.h

index da54253..0f487e8 100644 (file)
@@ -1,3 +1,13 @@
+2018-05-16  Saam Barati  <sbarati@apple.com>
+
+        Constant fold CheckTypeInfoFlags on ImplementsDefaultHasInstance
+        https://bugs.webkit.org/show_bug.cgi?id=185670
+
+        Reviewed by Yusuke Suzuki.
+
+        * microbenchmarks/constant-fold-check-type-info-flags.js: Added.
+        * stress/dont-constant-fold-check-type-info-on-bound-function.js: Added.
+
 2018-05-16  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231845.
 2018-05-16  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231845.
diff --git a/JSTests/microbenchmarks/constant-fold-check-type-info-flags.js b/JSTests/microbenchmarks/constant-fold-check-type-info-flags.js
new file mode 100644 (file)
index 0000000..57350ac
--- /dev/null
@@ -0,0 +1,41 @@
+"use strict";
+
+function clobber() { }
+noInline(clobber);
+
+class C { }
+class D { }
+
+function foo(x, C) {
+    clobber();
+    return x instanceof C;
+}
+noInline(foo);
+
+function access(o) {
+    return o.foo0;
+}
+noInline(access);
+
+function theClass(i) {
+    if (i & 1)
+        return C;
+    return D;
+}
+noInline(theClass);
+
+let x = new C;
+for (let i = 0; i < 1000; ++i) {
+    let k = theClass(i);
+    if (i < 20)
+        k["foo" + i] = i;
+    if (i >= 20)
+        access(k);
+    if (i === 100)
+        k["foo" + i] = i;
+    let result = foo(x, k);
+    if (k === C && result !== true)
+        throw new Error("Bad")
+    if (k !== C && result !== false)
+        throw new Error("Bad")
+}
diff --git a/JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js b/JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js
new file mode 100644 (file)
index 0000000..5c119b9
--- /dev/null
@@ -0,0 +1,17 @@
+"use strict";
+
+class C { }
+let x = new C;
+C = C.bind(this);
+
+function foo(x) {
+    x.foo;
+    return x instanceof C;
+}
+noInline(foo);
+
+for (let i = 0; i < 1000; ++i) {
+    let r = foo(x);
+    if (r !== true)
+        throw new Error("Bad")
+}
index 5cf240d..b2718d0 100644 (file)
@@ -1,3 +1,43 @@
+2018-05-16  Saam Barati  <sbarati@apple.com>
+
+        Constant fold CheckTypeInfoFlags on ImplementsDefaultHasInstance
+        https://bugs.webkit.org/show_bug.cgi?id=185670
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch makes it so that we constant fold CheckTypeInfoFlags for
+        ImplementsDefaultHasInstance inside of AI/constant folding. We constant
+        fold in three ways:
+        - When the incoming value is a constant, we just look at its inline type
+        flags. Since those flags never change after an object is created, this
+        is sound.
+        - Based on the incoming value having a finite structure set. We just iterate
+        all structures and ensure they have the bit set.
+        - Based on speculated type. To do this, I split up SpecFunction into two
+        subheaps where one is for functions that have the bit set, and one for
+        functions that don't have the bit set. The latter is currently only comprised
+        of JSBoundFunctions. To constant fold, we check that the incoming
+        value only has the SpecFunction type with ImplementsDefaultHasInstance set.
+
+        * bytecode/SpeculatedType.cpp:
+        (JSC::speculationFromClassInfo):
+        * bytecode/SpeculatedType.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCheckTypeInfoFlags):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::JSFunction):
+        (JSC::JSFunction::assertTypeInfoFlagInvariants):
+        * runtime/JSFunction.h:
+        (JSC::JSFunction::assertTypeInfoFlagInvariants):
+        * runtime/JSFunctionInlines.h:
+        (JSC::JSFunction::JSFunction):
+
 2018-05-16  Devin Rousso  <webkit@devinrousso.com>
 
         Web Inspector: create a navigation item for toggling the overlay rulers/guides
 2018-05-16  Devin Rousso  <webkit@devinrousso.com>
 
         Web Inspector: create a navigation item for toggling the overlay rulers/guides
index b488180..2f14a58 100644 (file)
@@ -32,6 +32,7 @@
 #include "DirectArguments.h"
 #include "JSArray.h"
 #include "JSBigInt.h"
 #include "DirectArguments.h"
 #include "JSArray.h"
 #include "JSBigInt.h"
+#include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSMap.h"
 #include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSMap.h"
@@ -432,8 +433,11 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
     if (classInfo == ProxyObject::info())
         return SpecProxyObject;
     
     if (classInfo == ProxyObject::info())
         return SpecProxyObject;
     
-    if (classInfo->isSubClassOf(JSFunction::info()))
-        return SpecFunction;
+    if (classInfo->isSubClassOf(JSFunction::info())) {
+        if (classInfo == JSBoundFunction::info())
+            return SpecFunctionWithNonDefaultHasInstance;
+        return SpecFunctionWithDefaultHasInstance;
+    }
     
     if (isTypedView(classInfo->typedArrayStorageType))
         return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
     
     if (isTypedView(classInfo->typedArrayStorageType))
         return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
index 74dc462..1fe5b35 100644 (file)
@@ -38,64 +38,66 @@ namespace JSC {
 class Structure;
 
 typedef uint64_t SpeculatedType;
 class Structure;
 
 typedef uint64_t SpeculatedType;
-static const SpeculatedType SpecNone               = 0; // We don't know anything yet.
-static const SpeculatedType SpecFinalObject        = 1ull << 0; // It's definitely a JSFinalObject.
-static const SpeculatedType SpecArray              = 1ull << 1; // It's definitely a JSArray.
-static const SpeculatedType SpecFunction           = 1ull << 2; // It's definitely a JSFunction.
-static const SpeculatedType SpecInt8Array          = 1ull << 3; // It's definitely an Int8Array or one of its subclasses.
-static const SpeculatedType SpecInt16Array         = 1ull << 4; // It's definitely an Int16Array or one of its subclasses.
-static const SpeculatedType SpecInt32Array         = 1ull << 5; // It's definitely an Int32Array or one of its subclasses.
-static const SpeculatedType SpecUint8Array         = 1ull << 6; // It's definitely an Uint8Array or one of its subclasses.
-static const SpeculatedType SpecUint8ClampedArray  = 1ull << 7; // It's definitely an Uint8ClampedArray or one of its subclasses.
-static const SpeculatedType SpecUint16Array        = 1ull << 8; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecUint32Array        = 1ull << 9; // It's definitely an Uint32Array or one of its subclasses.
-static const SpeculatedType SpecFloat32Array       = 1ull << 10; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecFloat64Array       = 1ull << 11; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecTypedArrayView     = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
-static const SpeculatedType SpecDirectArguments    = 1ull << 12; // It's definitely a DirectArguments object.
-static const SpeculatedType SpecScopedArguments    = 1ull << 13; // It's definitely a ScopedArguments object.
-static const SpeculatedType SpecStringObject       = 1ull << 14; // It's definitely a StringObject.
-static const SpeculatedType SpecRegExpObject       = 1ull << 15; // It's definitely a RegExpObject (and not any subclass of RegExpObject).
-static const SpeculatedType SpecMapObject          = 1ull << 16; // It's definitely a Map object or one of its subclasses.
-static const SpeculatedType SpecSetObject          = 1ull << 17; // It's definitely a Set object or one of its subclasses.
-static const SpeculatedType SpecWeakMapObject      = 1ull << 18; // It's definitely a WeakMap object or one of its subclasses.
-static const SpeculatedType SpecWeakSetObject      = 1ull << 19; // It's definitely a WeakSet object or one of its subclasses.
-static const SpeculatedType SpecProxyObject        = 1ull << 20; // It's definitely a Proxy object or one of its subclasses.
-static const SpeculatedType SpecDerivedArray       = 1ull << 21; // It's definitely a DerivedArray object.
-static const SpeculatedType SpecObjectOther        = 1ull << 22; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static const SpeculatedType SpecObject             = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
-static const SpeculatedType SpecStringIdent        = 1ull << 23; // It's definitely a JSString, and it's an identifier.
-static const SpeculatedType SpecStringVar          = 1ull << 24; // It's definitely a JSString, and it's not an identifier.
-static const SpeculatedType SpecString             = SpecStringIdent | SpecStringVar; // It's definitely a JSString.
-static const SpeculatedType SpecSymbol             = 1ull << 25; // It's definitely a Symbol.
-static const SpeculatedType SpecCellOther          = 1ull << 26; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString, BigInt, or Symbol.
-static const SpeculatedType SpecBoolInt32          = 1ull << 27; // It's definitely an Int32 with value 0 or 1.
-static const SpeculatedType SpecNonBoolInt32       = 1ull << 28; // It's definitely an Int32 with value other than 0 or 1.
-static const SpeculatedType SpecInt32Only          = SpecBoolInt32 | SpecNonBoolInt32; // It's definitely an Int32.
-static const SpeculatedType SpecInt52Only          = 1ull << 29; // It's definitely an Int52 and we intend it to unbox it. It's also definitely not an Int32.
-static const SpeculatedType SpecAnyInt             = SpecInt32Only | SpecInt52Only; // It's something that we can do machine int arithmetic on.
-static const SpeculatedType SpecAnyIntAsDouble     = 1ull << 30; // It's definitely an Int52 and it's inside a double.
-static const SpeculatedType SpecNonIntAsDouble     = 1ull << 31; // It's definitely not an Int52 but it's a real number and it's a double.
-static const SpeculatedType SpecDoubleReal         = SpecNonIntAsDouble | SpecAnyIntAsDouble; // It's definitely a non-NaN double.
-static const SpeculatedType SpecDoublePureNaN      = 1ull << 32; // It's definitely a NaN that is safe to tag (i.e. pure).
-static const SpeculatedType SpecDoubleImpureNaN    = 1ull << 33; // It's definitely a NaN that is unsafe to tag (i.e. impure).
-static const SpeculatedType SpecDoubleNaN          = SpecDoublePureNaN | SpecDoubleImpureNaN; // It's definitely some kind of NaN.
-static const SpeculatedType SpecBytecodeDouble     = SpecDoubleReal | SpecDoublePureNaN; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN.
-static const SpeculatedType SpecFullDouble         = SpecDoubleReal | SpecDoubleNaN; // It's either a non-NaN or a NaN double.
-static const SpeculatedType SpecBytecodeRealNumber = SpecInt32Only | SpecDoubleReal; // It's either an Int32 or a DoubleReal.
-static const SpeculatedType SpecFullRealNumber     = SpecAnyInt | SpecDoubleReal; // It's either an Int32 or a DoubleReal, or a Int52.
-static const SpeculatedType SpecBytecodeNumber     = SpecInt32Only | SpecBytecodeDouble; // It's either an Int32 or a Double, and the Double cannot be an impure NaN.
-static const SpeculatedType SpecFullNumber         = SpecAnyInt | SpecFullDouble; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN.
-static const SpeculatedType SpecBoolean            = 1ull << 34; // It's definitely a Boolean.
-static const SpeculatedType SpecOther              = 1ull << 35; // It's definitely either Null or Undefined.
-static const SpeculatedType SpecMisc               = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
-static const SpeculatedType SpecEmpty              = 1ull << 36; // It's definitely an empty value marker.
-static const SpeculatedType SpecBigInt             = 1ull << 37; // It's definitely a BigInt.
-static const SpeculatedType SpecPrimitive          = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc | SpecBigInt; // It's any non-Object JSValue.
-static const SpeculatedType SpecCell               = SpecObject | SpecString | SpecSymbol | SpecCellOther | SpecBigInt; // It's definitely a JSCell.
-static const SpeculatedType SpecHeapTop            = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
-static const SpeculatedType SpecBytecodeTop        = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
-static const SpeculatedType SpecFullTop            = SpecBytecodeTop | SpecFullNumber; // It can be anything that bytecode could see plus exotic encodings of numbers.
+static const SpeculatedType SpecNone                              = 0; // We don't know anything yet.
+static const SpeculatedType SpecFinalObject                       = 1ull << 0; // It's definitely a JSFinalObject.
+static const SpeculatedType SpecArray                             = 1ull << 1; // It's definitely a JSArray.
+static const SpeculatedType SpecFunctionWithDefaultHasInstance    = 1ull << 2; // It's definitely a JSFunction that has its ImplementsDefaultHasInstance type info flags bit set.
+static const SpeculatedType SpecFunctionWithNonDefaultHasInstance = 1ull << 3; // It's definitely a JSFunction that does not have its ImplementsDefaultHasInstance type info flags bit set.
+static const SpeculatedType SpecFunction                          = SpecFunctionWithDefaultHasInstance | SpecFunctionWithNonDefaultHasInstance; // It's definitely a JSFunction.
+static const SpeculatedType SpecInt8Array                         = 1ull << 4; // It's definitely an Int8Array or one of its subclasses.
+static const SpeculatedType SpecInt16Array                        = 1ull << 5; // It's definitely an Int16Array or one of its subclasses.
+static const SpeculatedType SpecInt32Array                        = 1ull << 6; // It's definitely an Int32Array or one of its subclasses.
+static const SpeculatedType SpecUint8Array                        = 1ull << 7; // It's definitely an Uint8Array or one of its subclasses.
+static const SpeculatedType SpecUint8ClampedArray                 = 1ull << 8; // It's definitely an Uint8ClampedArray or one of its subclasses.
+static const SpeculatedType SpecUint16Array                       = 1ull << 9; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecUint32Array                       = 1ull << 10; // It's definitely an Uint32Array or one of its subclasses.
+static const SpeculatedType SpecFloat32Array                      = 1ull << 11; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecFloat64Array                      = 1ull << 12; // It's definitely an Uint16Array or one of its subclasses.
+static const SpeculatedType SpecTypedArrayView                    = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array;
+static const SpeculatedType SpecDirectArguments                   = 1ull << 13; // It's definitely a DirectArguments object.
+static const SpeculatedType SpecScopedArguments                   = 1ull << 14; // It's definitely a ScopedArguments object.
+static const SpeculatedType SpecStringObject                      = 1ull << 15; // It's definitely a StringObject.
+static const SpeculatedType SpecRegExpObject                      = 1ull << 16; // It's definitely a RegExpObject (and not any subclass of RegExpObject).
+static const SpeculatedType SpecMapObject                         = 1ull << 17; // It's definitely a Map object or one of its subclasses.
+static const SpeculatedType SpecSetObject                         = 1ull << 18; // It's definitely a Set object or one of its subclasses.
+static const SpeculatedType SpecWeakMapObject                     = 1ull << 19; // It's definitely a WeakMap object or one of its subclasses.
+static const SpeculatedType SpecWeakSetObject                     = 1ull << 20; // It's definitely a WeakSet object or one of its subclasses.
+static const SpeculatedType SpecProxyObject                       = 1ull << 21; // It's definitely a Proxy object or one of its subclasses.
+static const SpeculatedType SpecDerivedArray                      = 1ull << 22; // It's definitely a DerivedArray object.
+static const SpeculatedType SpecObjectOther                       = 1ull << 23; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static const SpeculatedType SpecObject                            = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
+static const SpeculatedType SpecStringIdent                       = 1ull << 24; // It's definitely a JSString, and it's an identifier.
+static const SpeculatedType SpecStringVar                         = 1ull << 25; // It's definitely a JSString, and it's not an identifier.
+static const SpeculatedType SpecString                            = SpecStringIdent | SpecStringVar; // It's definitely a JSString.
+static const SpeculatedType SpecSymbol                            = 1ull << 26; // It's definitely a Symbol.
+static const SpeculatedType SpecCellOther                         = 1ull << 27; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString, BigInt, or Symbol.
+static const SpeculatedType SpecBoolInt32                         = 1ull << 28; // It's definitely an Int32 with value 0 or 1.
+static const SpeculatedType SpecNonBoolInt32                      = 1ull << 29; // It's definitely an Int32 with value other than 0 or 1.
+static const SpeculatedType SpecInt32Only                         = SpecBoolInt32 | SpecNonBoolInt32; // It's definitely an Int32.
+static const SpeculatedType SpecInt52Only                         = 1ull << 30; // It's definitely an Int52 and we intend it to unbox it. It's also definitely not an Int32.
+static const SpeculatedType SpecAnyInt                            = SpecInt32Only | SpecInt52Only; // It's something that we can do machine int arithmetic on.
+static const SpeculatedType SpecAnyIntAsDouble                    = 1ull << 31; // It's definitely an Int52 and it's inside a double.
+static const SpeculatedType SpecNonIntAsDouble                    = 1ull << 32; // It's definitely not an Int52 but it's a real number and it's a double.
+static const SpeculatedType SpecDoubleReal                        = SpecNonIntAsDouble | SpecAnyIntAsDouble; // It's definitely a non-NaN double.
+static const SpeculatedType SpecDoublePureNaN                     = 1ull << 33; // It's definitely a NaN that is safe to tag (i.e. pure).
+static const SpeculatedType SpecDoubleImpureNaN                   = 1ull << 34; // It's definitely a NaN that is unsafe to tag (i.e. impure).
+static const SpeculatedType SpecDoubleNaN                         = SpecDoublePureNaN | SpecDoubleImpureNaN; // It's definitely some kind of NaN.
+static const SpeculatedType SpecBytecodeDouble                    = SpecDoubleReal | SpecDoublePureNaN; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN.
+static const SpeculatedType SpecFullDouble                        = SpecDoubleReal | SpecDoubleNaN; // It's either a non-NaN or a NaN double.
+static const SpeculatedType SpecBytecodeRealNumber                = SpecInt32Only | SpecDoubleReal; // It's either an Int32 or a DoubleReal.
+static const SpeculatedType SpecFullRealNumber                    = SpecAnyInt | SpecDoubleReal; // It's either an Int32 or a DoubleReal, or a Int52.
+static const SpeculatedType SpecBytecodeNumber                    = SpecInt32Only | SpecBytecodeDouble; // It's either an Int32 or a Double, and the Double cannot be an impure NaN.
+static const SpeculatedType SpecFullNumber                        = SpecAnyInt | SpecFullDouble; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN.
+static const SpeculatedType SpecBoolean                           = 1ull << 35; // It's definitely a Boolean.
+static const SpeculatedType SpecOther                             = 1ull << 36; // It's definitely either Null or Undefined.
+static const SpeculatedType SpecMisc                              = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
+static const SpeculatedType SpecEmpty                             = 1ull << 37; // It's definitely an empty value marker.
+static const SpeculatedType SpecBigInt                            = 1ull << 38; // It's definitely a BigInt.
+static const SpeculatedType SpecPrimitive                         = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc | SpecBigInt; // It's any non-Object JSValue.
+static const SpeculatedType SpecCell                              = SpecObject | SpecString | SpecSymbol | SpecCellOther | SpecBigInt; // It's definitely a JSCell.
+static const SpeculatedType SpecHeapTop                           = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
+static const SpeculatedType SpecBytecodeTop                       = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
+static const SpeculatedType SpecFullTop                           = SpecBytecodeTop | SpecFullNumber; // It can be anything that bytecode could see plus exotic encodings of numbers.
 
 // SpecCellCheck is the type set representing the values that can flow through a cell check.
 // On 64-bit platforms, the empty value passes a cell check. Also, ~SpecCellCheck is the type
 
 // SpecCellCheck is the type set representing the values that can flow through a cell check.
 // On 64-bit platforms, the empty value passes a cell check. Also, ~SpecCellCheck is the type
index 87fd8ac..9bd8a53 100644 (file)
@@ -3437,7 +3437,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case CountExecution:
     case CheckTierUpInLoop:
     case CheckTierUpAtReturn:
     case CountExecution:
     case CheckTierUpInLoop:
     case CheckTierUpAtReturn:
-    case CheckTypeInfoFlags:
     case SuperSamplerBegin:
     case SuperSamplerEnd:
     case CheckTierUpAndOSREnter:
     case SuperSamplerBegin:
     case SuperSamplerEnd:
     case CheckTierUpAndOSREnter:
@@ -3446,6 +3445,43 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case ExitOK:
         break;
 
     case ExitOK:
         break;
 
+    case CheckTypeInfoFlags: {
+        const AbstractValue& abstractValue = forNode(node->child1());
+        unsigned bits = node->typeInfoOperand();
+        ASSERT(bits);
+        if (bits == ImplementsDefaultHasInstance) {
+            if (abstractValue.m_type == SpecFunctionWithDefaultHasInstance) {
+                m_state.setFoundConstants(true);
+                break;
+            }
+        }
+
+        if (JSValue value = abstractValue.value()) {
+            if (value.isCell()) {
+                // This works because if we see a cell here, we know it's fully constructed
+                // and we can read its inline type info flags. These flags don't change over the
+                // object's lifetime.
+                if ((value.asCell()->inlineTypeFlags() & bits) == bits) {
+                    m_state.setFoundConstants(true);
+                    break;
+                }
+            }
+        }
+
+        if (abstractValue.m_structure.isFinite()) {
+            bool ok = true;
+            abstractValue.m_structure.forEach([&] (RegisteredStructure structure) {
+                ok &= (structure->typeInfo().inlineTypeFlags() & bits) == bits;
+            });
+            if (ok) {
+                m_state.setFoundConstants(true);
+                break;
+            }
+        }
+
+        break;
+    }
+
     case ParseInt: {
         AbstractValue value = forNode(node->child1());
         if (value.m_type && !(value.m_type & ~SpecInt32Only)) {
     case ParseInt: {
         AbstractValue value = forNode(node->child1());
         if (value.m_type && !(value.m_type & ~SpecInt32Only)) {
index fbaeff1..7374185 100644 (file)
@@ -806,6 +806,46 @@ private:
                 }
                 break;
             }
                 }
                 break;
             }
+
+            case CheckTypeInfoFlags: {
+                const AbstractValue& abstractValue = m_state.forNode(node->child1());
+                unsigned bits = node->typeInfoOperand();
+                ASSERT(bits);
+                if (bits == ImplementsDefaultHasInstance) {
+                    if (abstractValue.m_type == SpecFunctionWithDefaultHasInstance) {
+                        changed = true;
+                        node->remove(m_graph);
+                        break;
+                    }
+                }
+
+                if (JSValue value = abstractValue.value()) {
+                    if (value.isCell()) {
+                        // This works because if we see a cell here, we know it's fully constructed
+                        // and we can read its inline type info flags. These flags don't change over the
+                        // object's lifetime.
+                        if ((value.asCell()->inlineTypeFlags() & bits) == bits) {
+                            changed = true;
+                            node->remove(m_graph);
+                            break;
+                        }
+                    }
+                }
+
+                if (abstractValue.m_structure.isFinite()) {
+                    bool ok = true;
+                    abstractValue.m_structure.forEach([&] (RegisteredStructure structure) {
+                        ok &= (structure->typeInfo().inlineTypeFlags() & bits) == bits;
+                    });
+                    if (ok) {
+                        changed = true;
+                        node->remove(m_graph);
+                        break;
+                    }
+                }
+
+                break;
+            }
                 
             case PhantomNewObject:
             case PhantomNewFunction:
                 
             case PhantomNewObject:
             case PhantomNewFunction:
index dbcfccf..b901318 100644 (file)
@@ -3389,6 +3389,9 @@ void SpeculativeJIT::compileCheckTypeInfoFlags(Node* node)
 
     GPRReg baseGPR = base.gpr();
 
 
     GPRReg baseGPR = base.gpr();
 
+    // FIXME: This only works for checking if a single bit is set. If we want to check more
+    // than one bit at once, we'll need to fix this:
+    // https://bugs.webkit.org/show_bug.cgi?id=185705
     speculationCheck(BadTypeInfoFlags, JSValueRegs(), 0, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(node->typeInfoOperand())));
 
     noResult(node);
     speculationCheck(BadTypeInfoFlags, JSValueRegs(), 0, m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(baseGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(node->typeInfoOperand())));
 
     noResult(node);
index 91ee1c3..5c1c97d 100644 (file)
@@ -303,7 +303,7 @@ private:
             break;
         }
 
             break;
         }
 
-        // FIXME: we should probably do this in constant folding but this currently relies on an OSR exit rule.
+        // FIXME: we should probably do this in constant folding but this currently relies on OSR exit history:
         // https://bugs.webkit.org/show_bug.cgi?id=154832
         case OverridesHasInstance: {
             if (!m_node->child2().node()->isCellConstant())
         // https://bugs.webkit.org/show_bug.cgi?id=154832
         case OverridesHasInstance: {
             if (!m_node->child2().node()->isCellConstant())
index deb1a67..01feddf 100644 (file)
@@ -100,6 +100,7 @@ JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structur
     : Base(vm, globalObject, structure)
     , m_executable()
 {
     : Base(vm, globalObject, structure)
     , m_executable()
 {
+    assertTypeInfoFlagInvariants();
 }
 
 
 }
 
 
@@ -789,4 +790,16 @@ JSFunction::PropertyStatus JSFunction::reifyLazyBoundNameIfNeeded(VM& vm, ExecSt
     return PropertyStatus::Reified;
 }
 
     return PropertyStatus::Reified;
 }
 
+#if !ASSERT_DISABLED
+void JSFunction::assertTypeInfoFlagInvariants()
+{
+    // If you change this, you'll need to update speculationFromClassInfo.
+    const ClassInfo* info = classInfo(*vm());
+    if (!(inlineTypeFlags() & ImplementsDefaultHasInstance))
+        RELEASE_ASSERT(info == JSBoundFunction::info());
+    else
+        RELEASE_ASSERT(info != JSBoundFunction::info());
+}
+#endif
+
 } // namespace JSC
 } // namespace JSC
index c3fb0c3..c5a34c6 100644 (file)
@@ -208,6 +208,12 @@ private:
     PropertyStatus reifyLazyNameIfNeeded(VM&, ExecState*, PropertyName);
     PropertyStatus reifyLazyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
 
     PropertyStatus reifyLazyNameIfNeeded(VM&, ExecState*, PropertyName);
     PropertyStatus reifyLazyBoundNameIfNeeded(VM&, ExecState*, PropertyName);
 
+#if ASSERT_DISABLED
+    void assertTypeInfoFlagInvariants() { }
+#else
+    void assertTypeInfoFlagInvariants();
+#endif
+
     friend class LLIntOffsetsExtractor;
 
     static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, PropertyName);
     friend class LLIntOffsetsExtractor;
 
     static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, PropertyName);
index d480a40..fedbc13 100644 (file)
@@ -43,6 +43,7 @@ inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* s
     , m_executable(vm, this, executable)
     , m_rareData()
 {
     , m_executable(vm, this, executable)
     , m_rareData()
 {
+    assertTypeInfoFlagInvariants();
 }
 
 inline FunctionExecutable* JSFunction::jsExecutable() const
 }
 
 inline FunctionExecutable* JSFunction::jsExecutable() const