Title: [231882] trunk
Revision
231882
Author
sbar...@apple.com
Date
2018-05-16 18:49:24 -0700 (Wed, 16 May 2018)

Log Message

Constant fold CheckTypeInfoFlags on ImplementsDefaultHasInstance
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/_javascript_Core:

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):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (231881 => 231882)


--- trunk/JSTests/ChangeLog	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/JSTests/ChangeLog	2018-05-17 01:49:24 UTC (rev 231882)
@@ -1,3 +1,13 @@
+2018-05-16  Saam Barati  <sbar...@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-qu...@webkit.org>
 
         Unreviewed, rolling out r231845.

Added: trunk/JSTests/microbenchmarks/constant-fold-check-type-info-flags.js (0 => 231882)


--- trunk/JSTests/microbenchmarks/constant-fold-check-type-info-flags.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/constant-fold-check-type-info-flags.js	2018-05-17 01:49:24 UTC (rev 231882)
@@ -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")
+}

Added: trunk/JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js (0 => 231882)


--- trunk/JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js	                        (rev 0)
+++ trunk/JSTests/stress/dont-constant-fold-check-type-info-on-bound-function.js	2018-05-17 01:49:24 UTC (rev 231882)
@@ -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")
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (231881 => 231882)


--- trunk/Source/_javascript_Core/ChangeLog	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-05-17 01:49:24 UTC (rev 231882)
@@ -1,3 +1,43 @@
+2018-05-16  Saam Barati  <sbar...@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  <web...@devinrousso.com>
 
         Web Inspector: create a navigation item for toggling the overlay rulers/guides

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp (231881 => 231882)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2018-05-17 01:49:24 UTC (rev 231882)
@@ -32,6 +32,7 @@
 #include "DirectArguments.h"
 #include "JSArray.h"
 #include "JSBigInt.h"
+#include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSMap.h"
@@ -432,8 +433,11 @@
     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);

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.h (231881 => 231882)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2018-05-17 01:49:24 UTC (rev 231882)
@@ -38,64 +38,66 @@
 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

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (231881 => 231882)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-17 01:49:24 UTC (rev 231882)
@@ -3437,7 +3437,6 @@
     case CountExecution:
     case CheckTierUpInLoop:
     case CheckTierUpAtReturn:
-    case CheckTypeInfoFlags:
     case SuperSamplerBegin:
     case SuperSamplerEnd:
     case CheckTierUpAndOSREnter:
@@ -3446,6 +3445,43 @@
     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)) {

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (231881 => 231882)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2018-05-17 01:49:24 UTC (rev 231882)
@@ -806,6 +806,46 @@
                 }
                 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:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (231881 => 231882)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-17 01:49:24 UTC (rev 231882)
@@ -3389,6 +3389,9 @@
 
     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);

Modified: trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp (231881 => 231882)


--- trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/dfg/DFGStrengthReductionPhase.cpp	2018-05-17 01:49:24 UTC (rev 231882)
@@ -303,7 +303,7 @@
             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())

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (231881 => 231882)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2018-05-17 01:49:24 UTC (rev 231882)
@@ -100,6 +100,7 @@
     : Base(vm, globalObject, structure)
     , m_executable()
 {
+    assertTypeInfoFlagInvariants();
 }
 
 
@@ -789,4 +790,16 @@
     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

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (231881 => 231882)


--- trunk/Source/_javascript_Core/runtime/JSFunction.h	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h	2018-05-17 01:49:24 UTC (rev 231882)
@@ -208,6 +208,12 @@
     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);

Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (231881 => 231882)


--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2018-05-17 01:37:33 UTC (rev 231881)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2018-05-17 01:49:24 UTC (rev 231882)
@@ -43,6 +43,7 @@
     , m_executable(vm, this, executable)
     , m_rareData()
 {
+    assertTypeInfoFlagInvariants();
 }
 
 inline FunctionExecutable* JSFunction::jsExecutable() const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to