Title: [184260] trunk
Revision
184260
Author
[email protected]
Date
2015-05-12 22:21:16 -0700 (Tue, 12 May 2015)

Log Message

js/dom/stack-trace.html fails with eager compilation
https://bugs.webkit.org/show_bug.cgi?id=144853

Reviewed by Benjamin Poulain.
        
Source/_javascript_Core:

All of our escape analyses were mishandling Check(). They were assuming that this is a
non-escaping operation. But, if we do for example a Check(Int32:@x) and @x is an escape
candidate, then we need to do something: if we eliminate or sink @x, then the check no
longer makes any sense since a phantom allocation has no type. This will make us forget
that this operation would have exited. This was causing us to not call a valueOf method in
js/dom/stack-trace.html with eager compilation enabled, because it was doing something like
+o where o had a valueOf method, and o was otherwise sinkable.
        
This changes our escape analyses to basically pretend that any Check() that isn't obviously
unnecessary is an escape. We don't have to be super careful here. Most checks will be
completely eliminated by constant-folding. If that doesn't run in time, then the most
common check we will see is CellUse. So, we just recognize some very obvious check kinds
that we know would have passed, and for all of the rest we just assume that it's an escape.
        
This was super tricky to test. The obvious way to test it is to use +o like
stack-trace.html, except that doing so relies on the fact that we still haven't implemented
the optimal behavior for op_to_number. So, I take four approaches in testing this patch:
        
1) Use +o. These will test what we want it to test for now, but at some point in the future
   these tests will just be a good sanity-check that our op_to_number implementation is
   right.
        
2) Do fancy control flow tricks to fool the profiling into thinking that some arithmetic
   operation always sees integers even though we eventually feed it an object and that
   object is a sink candidate.
        
3) Introduce a new jsc.cpp intrinsic called isInt32() which returns true if the incoming
   value is an int32. This intrinsic is required to be implemented by DFG by
   unconditionally speculating that the input is int32. This allows us to write much more
   targetted tests of the underlying issue.
        
4) I made a version of stack-trace.html that runs in run-jsc-stress-tests, so that we can
   get regression test coverage of this test in eager mode.

* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
* dfg/DFGVarargsForwardingPhase.cpp:
* ftl/FTLExitValue.cpp:
(JSC::FTL::ExitValue::dumpInContext):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::buildExitArguments):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileFTLOSRExit):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionIsInt32):
* runtime/Intrinsic.h:
* tests/stress/sink-arguments-past-invalid-check-dfg.js: Added.
* tests/stress/sink-arguments-past-invalid-check-int32-dfg.js: Added.
* tests/stress/sink-arguments-past-invalid-check-int32.js: Added.
* tests/stress/sink-arguments-past-invalid-check-sneakier.js: Added.
* tests/stress/sink-arguments-past-invalid-check.js: Added.
* tests/stress/sink-function-past-invalid-check-sneakier.js: Added.
* tests/stress/sink-function-past-invalid-check-sneaky.js: Added.
* tests/stress/sink-object-past-invalid-check-int32.js: Added.
* tests/stress/sink-object-past-invalid-check-sneakier.js: Added.
* tests/stress/sink-object-past-invalid-check-sneaky.js: Added.
* tests/stress/sink-object-past-invalid-check.js: Added.

LayoutTests:

Make a copy of the stack-trace test that only runs in run-jsc-stress-tests. Sadly, we don't
have a good way of having different expectation files for when a test runs in RJST versus
RWT. So, the approach I take is that I make a copy of the test just for RJST and I exclude
the .html file, which makes RWT overlook it. The test has different expectations in the
two harnesses because it does some small DOM things.

* js/script-tests/stack-trace.js: Added.
* js/stack-trace-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (184259 => 184260)


--- trunk/LayoutTests/ChangeLog	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/LayoutTests/ChangeLog	2015-05-13 05:21:16 UTC (rev 184260)
@@ -1,3 +1,19 @@
+2015-05-12  Filip Pizlo  <[email protected]>
+
+        js/dom/stack-trace.html fails with eager compilation
+        https://bugs.webkit.org/show_bug.cgi?id=144853
+
+        Reviewed by Benjamin Poulain.
+        
+        Make a copy of the stack-trace test that only runs in run-jsc-stress-tests. Sadly, we don't
+        have a good way of having different expectation files for when a test runs in RJST versus
+        RWT. So, the approach I take is that I make a copy of the test just for RJST and I exclude
+        the .html file, which makes RWT overlook it. The test has different expectations in the
+        two harnesses because it does some small DOM things.
+
+        * js/script-tests/stack-trace.js: Added.
+        * js/stack-trace-expected.txt: Added.
+
 2015-05-12  Joanmarie Diggs  <[email protected]>
 
         AX: [Win] REGRESSION(r184213) breaks aria-menubar-menuitems.html

Added: trunk/LayoutTests/js/script-tests/stack-trace.js (0 => 184260)


--- trunk/LayoutTests/js/script-tests/stack-trace.js	                        (rev 0)
+++ trunk/LayoutTests/js/script-tests/stack-trace.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,371 @@
+if (!this.alert) {
+    debug = print;
+    description = print;
+}
+
+description(
+'This test checks stack trace corectness in special cases.'
+);
+
+function stackTraceLineFor(stackTrace, frameIndex) {
+    var i = frameIndex;
+    var indexOfAt = stackTrace[i].indexOf('@')
+    var indexOfLastSlash = stackTrace[i].lastIndexOf('/');
+    if (indexOfLastSlash == -1)
+        indexOfLastSlash = indexOfAt
+    var functionName = stackTrace[i].substring(0, indexOfAt);
+    var fileName = stackTrace[i].substring(indexOfLastSlash + 1);
+    return functionName + " at " + fileName;
+}
+
+function printStack(stackTrace) {
+    debug("--> Stack Trace:")
+    stackTrace = stackTrace.split("\n");
+    var length = Math.min(stackTrace.length, 100);
+    for (var i = 0; i < length; i++)
+        debug("    " + i + "   " + stackTraceLineFor(stackTrace, i));
+    debug('');
+}
+
+function dumpPattern(pattern) {
+    for (var i = 0; i < pattern.length; i++)
+        debug("    " + i + "   " + pattern[i]);
+}
+
+function matchesPatternAtLine(pattern, patternIndex, traceLine) {
+    var patternLine = pattern[patternIndex];
+    return traceLine.slice(0, patternLine.length) == patternLine;
+}
+
+function matchPattern(pattern, traceLine) {
+    for (var i = 0; i < pattern.length; i++) {
+        if (matchesPatternAtLine(pattern, i, traceLine))
+            return i;
+    }
+    return -1;
+}
+
+function checkStackForPattern(stackTrace, pattern) {
+    stackTrace = stackTrace.split("\n");
+    var length = Math.min(stackTrace.length, 100);
+
+    // Get the match in the pattern for the first line:
+    var firstStackTraceLine = stackTraceLineFor(stackTrace, 0);
+    var patternIndex = matchPattern(pattern, firstStackTraceLine);
+    if (patternIndex < 0) {
+        debug("--> Stack Trace FAILED to match pattern:")
+        dumpPattern(pattern);
+        debug('');
+        return;
+    }
+
+    for (var i = 1; i < length; i++) {
+        patternIndex = ++patternIndex % pattern.length;
+        var traceLine = stackTraceLineFor(stackTrace, i);
+        if (!matchesPatternAtLine(pattern, patternIndex, traceLine)) {
+            debug("--> Stack Trace FAILED to match pattern:")
+            dumpPattern(pattern);
+            debug('');
+            return;
+        }
+    }
+
+    debug("--> Stack Trace matches pattern:")
+    dumpPattern(pattern);
+    debug('');
+}
+
+function hostThrower() { Element.prototype.appendChild.call({ }, [{ }]);  }
+function callbacker(f) { [0].map(f); }
+function outer(errorName) { inner(errorName); }
+function inner(errorName) { throw new Error("Error in " + errorName); }
+function evaler(code) { eval(code); }
+function normalOuter() { normalInner(); }
+function normalInner() { if(thisVarDoesntExist) failIfTrue("shouldFailBeforeThis") };
+function scripterInner() { htmlInner(); }
+function scripterOuter() { htmlOuter(); }
+                                                                       // Expected functions in stack trace
+// Normal Case
+try { normalOuter() } catch (e) { printStack(e.stack) }                     // normalOuter -> normalInner
+
+// Eval Case
+try { evaler("inner('inner eval');"); } catch (e) { printStack(e.stack) }   // evaler -> eval -> inner
+try { evaler("outer('outer eval');"); } catch (e) { printStack(e.stack) }   // evaler -> eval -> outer -> inner
+
+// Function Callback Case
+try { callbacker(inner('inner map')); } catch (e) { printStack(e.stack); }   // callbacker -> map -> inner
+try { callbacker(outer('outer map')); } catch (e) { printStack(e.stack); }   // callbacker -> map -> outer -> inner
+
+// Host Code Case
+try { hostThrower(); } catch (e) { printStack(e.stack); }                    // hostThrower
+
+try { scripterInner(); } catch (e) { printStack(e.stack) }                   // program -> scripter -> inner
+try { scripterOuter(); } catch (e) { printStack(e.stack) }                   // program -> scripter -> outer -> inner
+
+function selfRecursive1() { selfRecursive1();
+}
+
+
+try { selfRecursive1(); } catch (e) { printStack(e.stack) }                   // selfRecursive1 -> selfRecursive1 -> selfRecursive1 -> selfRecursive1 ...
+
+function selfRecursive2() {
+    // A little work to make the DFG kick in
+    for (var i = 0; i < 10; i++) {
+        if (i == 9)
+            selfRecursive2(); 
+    }
+}
+
+try { selfRecursive2(); } catch (e) { printStack(e.stack) }                   // selfRecursive2 -> selfRecursive2 -> selfRecursive2 -> selfRecursive2 ...
+
+function selfRecursive3() {
+    eval("selfRecursive3()");
+}
+
+try {
+    selfRecursive3();
+} catch (e) {
+    var pattern = [
+        " at eval code",
+        "eval at [native code]",
+        "selfRecursive3 at stack-trace.js"
+    ];
+    checkStackForPattern(e.stack, pattern);
+}
+
+var callCount = 0;
+
+function throwError() {
+    throw new Error();
+}
+
+var object = {
+    get getter1() {
+        var o = {
+            valueOf: function() {
+                throwError()
+            }
+        };
+        +o;
+    },
+    get getter2() {
+        var o = {
+            valueOf: throwError
+        };
+        +o;
+    },
+    get getter3() {
+        var o1 = {
+            valueOf: throwError
+        };
+        var o2 = {
+            valueOf: function () {
+                throwError();
+            }
+        };
+        if (callCount == 9998)
+            +o1;
+        if (callCount == 9999)
+            +o2;
+    },
+    nonInlineable : function () {
+        if (0) return [arguments, function(){}];
+        ++callCount;
+        if (callCount == 1) {
+            this.getter1;
+        } else if (callCount == 2) {
+            this.getter2;
+        } else {
+            this.getter3;
+        }
+    },
+    inlineable : function () {
+        this.nonInlineable();
+    }
+}
+
+function yetAnotherInlinedCall(o) {
+    o.inlineable();
+}
+
+function makeInlinableCall(o) {
+    for (var i = 0; i < 10000; i++) {
+        new yetAnotherInlinedCall(o);
+    }
+}
+for (var k = 0; k < 4; k++) {
+    try {
+        function g() {
+            var j = 0;
+            for (var i = 0; i < 1000; i++) {
+                j++;
+                makeInlinableCall(object);
+            }
+        }
+        [1].map(g);
+    } catch (e) {
+        printStack(e.stack);
+    }
+}
+
+function h() {
+    if (callCount++ == 1000)
+        throw new Error();
+    if (callCount > 1000) {
+        [].map.apply(undefined, throwError);
+    }
+}
+
+function mapTest(a) {
+    a.map(h);
+}
+
+function mapTestDriver() {
+    var a = [1,2,3];
+    for (var i = 0; i < 2000; i++)
+        mapTest(a);
+}
+
+try {
+    callCount = 0;
+    mapTestDriver()
+} catch(e) {
+    printStack(e.stack);
+}
+
+try {
+    mapTestDriver()
+} catch(e) {
+    printStack(e.stack);
+}
+
+var dfgFunctionShouldThrow = false;
+function dfgFunction() { 
+    if (dfgFunctionShouldThrow) { 
+        dfgFunctionShouldThrow = false; 
+        throwError();
+    }
+}
+
+for (var k = 0; k < 1000; k++)
+    dfgFunction();
+
+try {
+    dfgFunctionShouldThrow = true;
+    [1,2,3,4].map(dfgFunction);
+} catch (e) {
+    printStack(e.stack);
+}
+
+try { 
+    var o = { };
+    o.__defineGetter__("g", dfgFunction);
+    function f(o) {
+        o.g;
+    }
+    for (var k = 0; k < 1000; k++)
+        f(o);
+    
+    dfgFunctionShouldThrow = true;
+    f(o);
+
+} catch (e) {
+    printStack(e.stack);
+}
+
+var someValue = null;
+
+function callNonCallable() {
+    someValue();
+}
+
+for (var i = 0; i < 100; i++) {
+    try {
+        callNonCallable();
+    } catch (e) {
+    }
+}
+
+function dfgTest(f) {
+    dfgCount = 0;
+    while (dfgCount++ < 1000) {
+        try {
+            f();
+        } catch (e) {
+            printStack(e.stack)
+            return;
+        }
+    }
+}
+
+function inlineableThrow() {
+    if (dfgCount > 500) throw new Error();
+}
+
+var dfgThing = {
+    get willThrow() {
+        if (dfgCount > 500)
+            throw new Error();
+    },
+    get willThrowEventually() {
+        inlineableThrow();
+    },
+    willThrowFunc: function () { if (dfgCount > 500) throw new Error(); },
+    willThrowEventuallyFunc: function () { inlineableThrow(); }
+}
+dfgThing.__defineGetter__("hostWillThrow", hostThrower);
+
+function dfg1() {
+    dfgThing.willThrow
+}
+
+function dfg2() {
+    dfg1();
+}
+
+function dfg3() {
+    dfg2();
+}
+
+function dfg4() {
+    dfgThing.willThrowFunc();
+}
+
+function dfg5() {
+    dfg4();
+}
+
+function dfg6() {
+    dfg5();
+}
+
+function dfg7() {
+    dfgThing.willThrowEventually
+}
+
+function dfg8() {
+    dfg7();
+}
+
+function dfg9() {
+    dfg8();
+}
+
+function dfga() {
+    dfgThing.willThrowEventuallyFunc();
+}
+
+function dfgb() {
+    dfga();
+}
+
+function dfgc() {
+    dfgb();
+}
+
+dfgTest(dfg3)
+dfgTest(dfg6)
+dfgTest(dfg9)
+dfgTest(dfgc)
+
+successfullyParsed = true;

Added: trunk/LayoutTests/js/stack-trace-expected.txt (0 => 184260)


--- trunk/LayoutTests/js/stack-trace-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/stack-trace-expected.txt	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,362 @@
+This test checks stack trace corectness in special cases.
+--> Stack Trace:
+    0   normalInner at stack-trace.js:84:47
+    1   normalOuter at stack-trace.js:83:37
+    2   global code at stack-trace.js:89:18
+
+--> Stack Trace:
+    0   inner at stack-trace.js:81:44
+    1    at eval code
+    2   eval at [native code]
+    3   evaler at stack-trace.js:82:29
+    4   global code at stack-trace.js:92:13
+
+--> Stack Trace:
+    0   inner at stack-trace.js:81:44
+    1   outer at stack-trace.js:80:34
+    2    at eval code
+    3   eval at [native code]
+    4   evaler at stack-trace.js:82:29
+    5   global code at stack-trace.js:93:13
+
+--> Stack Trace:
+    0   inner at stack-trace.js:81:44
+    1   global code at stack-trace.js:96:23
+
+--> Stack Trace:
+    0   inner at stack-trace.js:81:44
+    1   outer at stack-trace.js:80:34
+    2   global code at stack-trace.js:97:23
+
+--> Stack Trace:
+    0   hostThrower at stack-trace.js:78:43
+    1   global code at stack-trace.js:100:18
+
+--> Stack Trace:
+    0   scripterInner at stack-trace.js:85:37
+    1   global code at stack-trace.js:102:20
+
+--> Stack Trace:
+    0   scripterOuter at stack-trace.js:86:37
+    1   global code at stack-trace.js:103:20
+
+--> Stack Trace:
+    0   selfRecursive1 at stack-trace.js:105:43
+    1   selfRecursive1 at stack-trace.js:105:43
+    2   selfRecursive1 at stack-trace.js:105:43
+    3   selfRecursive1 at stack-trace.js:105:43
+    4   selfRecursive1 at stack-trace.js:105:43
+    5   selfRecursive1 at stack-trace.js:105:43
+    6   selfRecursive1 at stack-trace.js:105:43
+    7   selfRecursive1 at stack-trace.js:105:43
+    8   selfRecursive1 at stack-trace.js:105:43
+    9   selfRecursive1 at stack-trace.js:105:43
+    10   selfRecursive1 at stack-trace.js:105:43
+    11   selfRecursive1 at stack-trace.js:105:43
+    12   selfRecursive1 at stack-trace.js:105:43
+    13   selfRecursive1 at stack-trace.js:105:43
+    14   selfRecursive1 at stack-trace.js:105:43
+    15   selfRecursive1 at stack-trace.js:105:43
+    16   selfRecursive1 at stack-trace.js:105:43
+    17   selfRecursive1 at stack-trace.js:105:43
+    18   selfRecursive1 at stack-trace.js:105:43
+    19   selfRecursive1 at stack-trace.js:105:43
+    20   selfRecursive1 at stack-trace.js:105:43
+    21   selfRecursive1 at stack-trace.js:105:43
+    22   selfRecursive1 at stack-trace.js:105:43
+    23   selfRecursive1 at stack-trace.js:105:43
+    24   selfRecursive1 at stack-trace.js:105:43
+    25   selfRecursive1 at stack-trace.js:105:43
+    26   selfRecursive1 at stack-trace.js:105:43
+    27   selfRecursive1 at stack-trace.js:105:43
+    28   selfRecursive1 at stack-trace.js:105:43
+    29   selfRecursive1 at stack-trace.js:105:43
+    30   selfRecursive1 at stack-trace.js:105:43
+    31   selfRecursive1 at stack-trace.js:105:43
+    32   selfRecursive1 at stack-trace.js:105:43
+    33   selfRecursive1 at stack-trace.js:105:43
+    34   selfRecursive1 at stack-trace.js:105:43
+    35   selfRecursive1 at stack-trace.js:105:43
+    36   selfRecursive1 at stack-trace.js:105:43
+    37   selfRecursive1 at stack-trace.js:105:43
+    38   selfRecursive1 at stack-trace.js:105:43
+    39   selfRecursive1 at stack-trace.js:105:43
+    40   selfRecursive1 at stack-trace.js:105:43
+    41   selfRecursive1 at stack-trace.js:105:43
+    42   selfRecursive1 at stack-trace.js:105:43
+    43   selfRecursive1 at stack-trace.js:105:43
+    44   selfRecursive1 at stack-trace.js:105:43
+    45   selfRecursive1 at stack-trace.js:105:43
+    46   selfRecursive1 at stack-trace.js:105:43
+    47   selfRecursive1 at stack-trace.js:105:43
+    48   selfRecursive1 at stack-trace.js:105:43
+    49   selfRecursive1 at stack-trace.js:105:43
+    50   selfRecursive1 at stack-trace.js:105:43
+    51   selfRecursive1 at stack-trace.js:105:43
+    52   selfRecursive1 at stack-trace.js:105:43
+    53   selfRecursive1 at stack-trace.js:105:43
+    54   selfRecursive1 at stack-trace.js:105:43
+    55   selfRecursive1 at stack-trace.js:105:43
+    56   selfRecursive1 at stack-trace.js:105:43
+    57   selfRecursive1 at stack-trace.js:105:43
+    58   selfRecursive1 at stack-trace.js:105:43
+    59   selfRecursive1 at stack-trace.js:105:43
+    60   selfRecursive1 at stack-trace.js:105:43
+    61   selfRecursive1 at stack-trace.js:105:43
+    62   selfRecursive1 at stack-trace.js:105:43
+    63   selfRecursive1 at stack-trace.js:105:43
+    64   selfRecursive1 at stack-trace.js:105:43
+    65   selfRecursive1 at stack-trace.js:105:43
+    66   selfRecursive1 at stack-trace.js:105:43
+    67   selfRecursive1 at stack-trace.js:105:43
+    68   selfRecursive1 at stack-trace.js:105:43
+    69   selfRecursive1 at stack-trace.js:105:43
+    70   selfRecursive1 at stack-trace.js:105:43
+    71   selfRecursive1 at stack-trace.js:105:43
+    72   selfRecursive1 at stack-trace.js:105:43
+    73   selfRecursive1 at stack-trace.js:105:43
+    74   selfRecursive1 at stack-trace.js:105:43
+    75   selfRecursive1 at stack-trace.js:105:43
+    76   selfRecursive1 at stack-trace.js:105:43
+    77   selfRecursive1 at stack-trace.js:105:43
+    78   selfRecursive1 at stack-trace.js:105:43
+    79   selfRecursive1 at stack-trace.js:105:43
+    80   selfRecursive1 at stack-trace.js:105:43
+    81   selfRecursive1 at stack-trace.js:105:43
+    82   selfRecursive1 at stack-trace.js:105:43
+    83   selfRecursive1 at stack-trace.js:105:43
+    84   selfRecursive1 at stack-trace.js:105:43
+    85   selfRecursive1 at stack-trace.js:105:43
+    86   selfRecursive1 at stack-trace.js:105:43
+    87   selfRecursive1 at stack-trace.js:105:43
+    88   selfRecursive1 at stack-trace.js:105:43
+    89   selfRecursive1 at stack-trace.js:105:43
+    90   selfRecursive1 at stack-trace.js:105:43
+    91   selfRecursive1 at stack-trace.js:105:43
+    92   selfRecursive1 at stack-trace.js:105:43
+    93   selfRecursive1 at stack-trace.js:105:43
+    94   selfRecursive1 at stack-trace.js:105:43
+    95   selfRecursive1 at stack-trace.js:105:43
+    96   selfRecursive1 at stack-trace.js:105:43
+    97   selfRecursive1 at stack-trace.js:105:43
+    98   selfRecursive1 at stack-trace.js:105:43
+    99   selfRecursive1 at stack-trace.js:105:43
+
+--> Stack Trace:
+    0   selfRecursive2 at stack-trace.js:115:27
+    1   selfRecursive2 at stack-trace.js:115:27
+    2   selfRecursive2 at stack-trace.js:115:27
+    3   selfRecursive2 at stack-trace.js:115:27
+    4   selfRecursive2 at stack-trace.js:115:27
+    5   selfRecursive2 at stack-trace.js:115:27
+    6   selfRecursive2 at stack-trace.js:115:27
+    7   selfRecursive2 at stack-trace.js:115:27
+    8   selfRecursive2 at stack-trace.js:115:27
+    9   selfRecursive2 at stack-trace.js:115:27
+    10   selfRecursive2 at stack-trace.js:115:27
+    11   selfRecursive2 at stack-trace.js:115:27
+    12   selfRecursive2 at stack-trace.js:115:27
+    13   selfRecursive2 at stack-trace.js:115:27
+    14   selfRecursive2 at stack-trace.js:115:27
+    15   selfRecursive2 at stack-trace.js:115:27
+    16   selfRecursive2 at stack-trace.js:115:27
+    17   selfRecursive2 at stack-trace.js:115:27
+    18   selfRecursive2 at stack-trace.js:115:27
+    19   selfRecursive2 at stack-trace.js:115:27
+    20   selfRecursive2 at stack-trace.js:115:27
+    21   selfRecursive2 at stack-trace.js:115:27
+    22   selfRecursive2 at stack-trace.js:115:27
+    23   selfRecursive2 at stack-trace.js:115:27
+    24   selfRecursive2 at stack-trace.js:115:27
+    25   selfRecursive2 at stack-trace.js:115:27
+    26   selfRecursive2 at stack-trace.js:115:27
+    27   selfRecursive2 at stack-trace.js:115:27
+    28   selfRecursive2 at stack-trace.js:115:27
+    29   selfRecursive2 at stack-trace.js:115:27
+    30   selfRecursive2 at stack-trace.js:115:27
+    31   selfRecursive2 at stack-trace.js:115:27
+    32   selfRecursive2 at stack-trace.js:115:27
+    33   selfRecursive2 at stack-trace.js:115:27
+    34   selfRecursive2 at stack-trace.js:115:27
+    35   selfRecursive2 at stack-trace.js:115:27
+    36   selfRecursive2 at stack-trace.js:115:27
+    37   selfRecursive2 at stack-trace.js:115:27
+    38   selfRecursive2 at stack-trace.js:115:27
+    39   selfRecursive2 at stack-trace.js:115:27
+    40   selfRecursive2 at stack-trace.js:115:27
+    41   selfRecursive2 at stack-trace.js:115:27
+    42   selfRecursive2 at stack-trace.js:115:27
+    43   selfRecursive2 at stack-trace.js:115:27
+    44   selfRecursive2 at stack-trace.js:115:27
+    45   selfRecursive2 at stack-trace.js:115:27
+    46   selfRecursive2 at stack-trace.js:115:27
+    47   selfRecursive2 at stack-trace.js:115:27
+    48   selfRecursive2 at stack-trace.js:115:27
+    49   selfRecursive2 at stack-trace.js:115:27
+    50   selfRecursive2 at stack-trace.js:115:27
+    51   selfRecursive2 at stack-trace.js:115:27
+    52   selfRecursive2 at stack-trace.js:115:27
+    53   selfRecursive2 at stack-trace.js:115:27
+    54   selfRecursive2 at stack-trace.js:115:27
+    55   selfRecursive2 at stack-trace.js:115:27
+    56   selfRecursive2 at stack-trace.js:115:27
+    57   selfRecursive2 at stack-trace.js:115:27
+    58   selfRecursive2 at stack-trace.js:115:27
+    59   selfRecursive2 at stack-trace.js:115:27
+    60   selfRecursive2 at stack-trace.js:115:27
+    61   selfRecursive2 at stack-trace.js:115:27
+    62   selfRecursive2 at stack-trace.js:115:27
+    63   selfRecursive2 at stack-trace.js:115:27
+    64   selfRecursive2 at stack-trace.js:115:27
+    65   selfRecursive2 at stack-trace.js:115:27
+    66   selfRecursive2 at stack-trace.js:115:27
+    67   selfRecursive2 at stack-trace.js:115:27
+    68   selfRecursive2 at stack-trace.js:115:27
+    69   selfRecursive2 at stack-trace.js:115:27
+    70   selfRecursive2 at stack-trace.js:115:27
+    71   selfRecursive2 at stack-trace.js:115:27
+    72   selfRecursive2 at stack-trace.js:115:27
+    73   selfRecursive2 at stack-trace.js:115:27
+    74   selfRecursive2 at stack-trace.js:115:27
+    75   selfRecursive2 at stack-trace.js:115:27
+    76   selfRecursive2 at stack-trace.js:115:27
+    77   selfRecursive2 at stack-trace.js:115:27
+    78   selfRecursive2 at stack-trace.js:115:27
+    79   selfRecursive2 at stack-trace.js:115:27
+    80   selfRecursive2 at stack-trace.js:115:27
+    81   selfRecursive2 at stack-trace.js:115:27
+    82   selfRecursive2 at stack-trace.js:115:27
+    83   selfRecursive2 at stack-trace.js:115:27
+    84   selfRecursive2 at stack-trace.js:115:27
+    85   selfRecursive2 at stack-trace.js:115:27
+    86   selfRecursive2 at stack-trace.js:115:27
+    87   selfRecursive2 at stack-trace.js:115:27
+    88   selfRecursive2 at stack-trace.js:115:27
+    89   selfRecursive2 at stack-trace.js:115:27
+    90   selfRecursive2 at stack-trace.js:115:27
+    91   selfRecursive2 at stack-trace.js:115:27
+    92   selfRecursive2 at stack-trace.js:115:27
+    93   selfRecursive2 at stack-trace.js:115:27
+    94   selfRecursive2 at stack-trace.js:115:27
+    95   selfRecursive2 at stack-trace.js:115:27
+    96   selfRecursive2 at stack-trace.js:115:27
+    97   selfRecursive2 at stack-trace.js:115:27
+    98   selfRecursive2 at stack-trace.js:115:27
+    99   selfRecursive2 at stack-trace.js:115:27
+
+--> Stack Trace matches pattern:
+    0    at eval code
+    1   eval at [native code]
+    2   selfRecursive3 at stack-trace.js
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   valueOf at stack-trace.js:146:27
+    2   getter1 at stack-trace.js:149:11
+    3   nonInlineable at stack-trace.js:175:17
+    4   inlineable at stack-trace.js:183:27
+    5   yetAnotherInlinedCall at stack-trace.js:188:17
+    6   makeInlinableCall at stack-trace.js:193:34
+    7   g at stack-trace.js:202:34
+    8   map at [native code]
+    9   global code at stack-trace.js:205:16
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   getter2 at stack-trace.js:155:11
+    2   nonInlineable at stack-trace.js:177:17
+    3   inlineable at stack-trace.js:183:27
+    4   yetAnotherInlinedCall at stack-trace.js:188:17
+    5   makeInlinableCall at stack-trace.js:193:34
+    6   g at stack-trace.js:202:34
+    7   map at [native code]
+    8   global code at stack-trace.js:205:16
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   getter3 at stack-trace.js:167:16
+    2   nonInlineable at stack-trace.js:179:17
+    3   inlineable at stack-trace.js:183:27
+    4   yetAnotherInlinedCall at stack-trace.js:188:17
+    5   makeInlinableCall at stack-trace.js:193:34
+    6   g at stack-trace.js:202:34
+    7   map at [native code]
+    8   global code at stack-trace.js:205:16
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   valueOf at stack-trace.js:163:27
+    2   getter3 at stack-trace.js:169:16
+    3   nonInlineable at stack-trace.js:179:17
+    4   inlineable at stack-trace.js:183:27
+    5   yetAnotherInlinedCall at stack-trace.js:188:17
+    6   makeInlinableCall at stack-trace.js:193:34
+    7   g at stack-trace.js:202:34
+    8   map at [native code]
+    9   global code at stack-trace.js:205:16
+
+--> Stack Trace:
+    0   h at stack-trace.js:213:24
+    1   map at [native code]
+    2   mapTest at stack-trace.js:220:10
+    3   mapTestDriver at stack-trace.js:226:16
+    4   global code at stack-trace.js:231:18
+
+--> Stack Trace:
+    0   map at [native code]
+    1   h at stack-trace.js:215:21
+    2   map at [native code]
+    3   mapTest at stack-trace.js:220:10
+    4   mapTestDriver at stack-trace.js:226:16
+    5   global code at stack-trace.js:237:18
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   dfgFunction at stack-trace.js:246:19
+    2   map at [native code]
+    3   global code at stack-trace.js:255:18
+
+--> Stack Trace:
+    0   throwError at stack-trace.js:139:20
+    1   dfgFunction at stack-trace.js:246:19
+    2   f at stack-trace.js:264:10
+    3   global code at stack-trace.js:270:6
+
+--> Stack Trace:
+    0   willThrow at stack-trace.js:308:28
+    1   dfg1 at stack-trace.js:319:13
+    2   dfg2 at stack-trace.js:323:9
+    3   dfg3 at stack-trace.js:327:9
+    4   dfgTest at stack-trace.js:293:14
+    5   global code at stack-trace.js:366:8
+
+--> Stack Trace:
+    0   willThrowFunc at stack-trace.js:313:69
+    1   dfg4 at stack-trace.js:331:27
+    2   dfg5 at stack-trace.js:335:9
+    3   dfg6 at stack-trace.js:339:9
+    4   dfgTest at stack-trace.js:293:14
+    5   global code at stack-trace.js:367:8
+
+--> Stack Trace:
+    0   inlineableThrow at stack-trace.js:302:40
+    1   willThrowEventually at stack-trace.js:311:24
+    2   dfg7 at stack-trace.js:343:13
+    3   dfg8 at stack-trace.js:347:9
+    4   dfg9 at stack-trace.js:351:9
+    5   dfgTest at stack-trace.js:293:14
+    6   global code at stack-trace.js:368:8
+
+--> Stack Trace:
+    0   inlineableThrow at stack-trace.js:302:40
+    1   willThrowEventuallyFunc at stack-trace.js:314:59
+    2   dfga at stack-trace.js:355:37
+    3   dfgb at stack-trace.js:359:9
+    4   dfgc at stack-trace.js:363:9
+    5   dfgTest at stack-trace.js:293:14
+    6   global code at stack-trace.js:369:8
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/Source/_javascript_Core/ChangeLog (184259 => 184260)


--- trunk/Source/_javascript_Core/ChangeLog	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-05-13 05:21:16 UTC (rev 184260)
@@ -1,3 +1,72 @@
+2015-05-12  Filip Pizlo  <[email protected]>
+
+        js/dom/stack-trace.html fails with eager compilation
+        https://bugs.webkit.org/show_bug.cgi?id=144853
+
+        Reviewed by Benjamin Poulain.
+        
+        All of our escape analyses were mishandling Check(). They were assuming that this is a
+        non-escaping operation. But, if we do for example a Check(Int32:@x) and @x is an escape
+        candidate, then we need to do something: if we eliminate or sink @x, then the check no
+        longer makes any sense since a phantom allocation has no type. This will make us forget
+        that this operation would have exited. This was causing us to not call a valueOf method in
+        js/dom/stack-trace.html with eager compilation enabled, because it was doing something like
+        +o where o had a valueOf method, and o was otherwise sinkable.
+        
+        This changes our escape analyses to basically pretend that any Check() that isn't obviously
+        unnecessary is an escape. We don't have to be super careful here. Most checks will be
+        completely eliminated by constant-folding. If that doesn't run in time, then the most
+        common check we will see is CellUse. So, we just recognize some very obvious check kinds
+        that we know would have passed, and for all of the rest we just assume that it's an escape.
+        
+        This was super tricky to test. The obvious way to test it is to use +o like
+        stack-trace.html, except that doing so relies on the fact that we still haven't implemented
+        the optimal behavior for op_to_number. So, I take four approaches in testing this patch:
+        
+        1) Use +o. These will test what we want it to test for now, but at some point in the future
+           these tests will just be a good sanity-check that our op_to_number implementation is
+           right.
+        
+        2) Do fancy control flow tricks to fool the profiling into thinking that some arithmetic
+           operation always sees integers even though we eventually feed it an object and that
+           object is a sink candidate.
+        
+        3) Introduce a new jsc.cpp intrinsic called isInt32() which returns true if the incoming
+           value is an int32. This intrinsic is required to be implemented by DFG by
+           unconditionally speculating that the input is int32. This allows us to write much more
+           targetted tests of the underlying issue.
+        
+        4) I made a version of stack-trace.html that runs in run-jsc-stress-tests, so that we can
+           get regression test coverage of this test in eager mode.
+
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
+        * dfg/DFGVarargsForwardingPhase.cpp:
+        * ftl/FTLExitValue.cpp:
+        (JSC::FTL::ExitValue::dumpInContext):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileFTLOSRExit):
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        (functionIsInt32):
+        * runtime/Intrinsic.h:
+        * tests/stress/sink-arguments-past-invalid-check-dfg.js: Added.
+        * tests/stress/sink-arguments-past-invalid-check-int32-dfg.js: Added.
+        * tests/stress/sink-arguments-past-invalid-check-int32.js: Added.
+        * tests/stress/sink-arguments-past-invalid-check-sneakier.js: Added.
+        * tests/stress/sink-arguments-past-invalid-check.js: Added.
+        * tests/stress/sink-function-past-invalid-check-sneakier.js: Added.
+        * tests/stress/sink-function-past-invalid-check-sneaky.js: Added.
+        * tests/stress/sink-object-past-invalid-check-int32.js: Added.
+        * tests/stress/sink-object-past-invalid-check-sneakier.js: Added.
+        * tests/stress/sink-object-past-invalid-check-sneaky.js: Added.
+        * tests/stress/sink-object-past-invalid-check.js: Added.
+
 2015-05-12  Benjamin Poulain  <[email protected]>
 
         Fix the iteration count of arith-modulo-node-behaviors.js

Modified: trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/dfg/DFGArgumentsEliminationPhase.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -42,11 +42,14 @@
 #include "JSCInlines.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
+#include <wtf/ListDump.h>
 
 namespace JSC { namespace DFG {
 
 namespace {
 
+bool verbose = false;
+
 class ArgumentsEliminationPhase : public Phase {
 public:
     ArgumentsEliminationPhase(Graph& graph)
@@ -101,6 +104,9 @@
                 }
             }
         }
+        
+        if (verbose)
+            dataLog("Candidates: ", listDump(m_candidates), "\n");
     }
     
     // Look for escaping sites, and remove from the candidates set if we see an escape.
@@ -160,6 +166,21 @@
                     break;
 
                 case Check:
+                    m_graph.doToChildren(
+                        node,
+                        [&] (Edge edge) {
+                            switch (edge.useKind()) {
+                            case CellUse:
+                            case ObjectUse:
+                                break;
+                                
+                            default:
+                                escape(edge);
+                                break;
+                            }
+                        });
+                    break;
+                    
                 case MovHint:
                 case PutHint:
                     break;
@@ -189,6 +210,9 @@
                 }
             }
         }
+
+        if (verbose)
+            dataLog("After escape analysis: ", listDump(m_candidates), "\n");
     }
 
     // Anywhere that a candidate is live (in bytecode or in DFG), check if there is a chance of
@@ -331,6 +355,9 @@
         // availabilities may become whatever. OSR exit should be able to handle this quite naturally,
         // since those availabilities speak of the stack before the optimizing compiler stack frame is
         // torn down.
+
+        if (verbose)
+            dataLog("After interference analysis: ", listDump(m_candidates), "\n");
     }
     
     void transform()

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -2111,6 +2111,16 @@
         return true;
     }
         
+    case CheckInt32Intrinsic: {
+        insertChecks();
+        for (int i = 1; i < argumentCountIncludingThis; ++i) {
+            Node* node = get(virtualRegisterForArgument(i, registerOffset));
+            addToGraph(Phantom, Edge(node, Int32Use));
+        }
+        set(VirtualRegister(resultOperand), jsConstant(jsBoolean(true)));
+        return true;
+    }
+        
     case FiatInt52Intrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;

Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -828,25 +828,45 @@
         case NewFunction:
             if (!node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
                 sinkCandidate();
-            m_graph.doToChildren(
-                node,
-                [&] (Edge edge) {
-                    escape(edge.node());
-                });
+            escape(node->child1().node());
             break;
 
         case CreateActivation:
             if (!m_graph.symbolTableFor(node->origin.semantic)->singletonScope()->isStillValid())
                 sinkCandidate();
+            escape(node->child1().node());
+            break;
+
+        case Check:
             m_graph.doToChildren(
                 node,
                 [&] (Edge edge) {
-                    escape(edge.node());
+                    bool ok = true;
+
+                    switch (edge.useKind()) {
+                    case KnownCellUse:
+                    case CellUse:
+                    case ObjectUse:
+                        // All of our allocations will pass this.
+                        break;
+                        
+                    case FunctionUse:
+                        // Function allocations will pass this.
+                        if (edge->op() != NewFunction)
+                            ok = false;
+                        break;
+                        
+                    default:
+                        ok = false;
+                        break;
+                    }
+                    
+                    if (!ok)
+                        escape(edge.node());
                 });
             break;
 
         case MovHint:
-        case Check:
         case PutHint:
         case StoreBarrier:
         case StoreBarrierWithNullCheck:

Modified: trunk/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/dfg/DFGVarargsForwardingPhase.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -104,7 +104,30 @@
                     relevantLocals.append(node->unlinkedLocal());
                 break;
                 
-            case Check:
+            case Check: {
+                bool sawEscape = false;
+                m_graph.doToChildren(
+                    node,
+                    [&] (Edge edge) {
+                        switch (edge.useKind()) {
+                        case CellUse:
+                        case ObjectUse:
+                            if (edge == candidate)
+                                lastUserIndex = nodeIndex;
+                            break;
+                        default:
+                            sawEscape = true;
+                            break;
+                        }  
+                    });
+                if (sawEscape) {
+                    if (verbose)
+                        dataLog("    Escape at ", node, "\n");
+                    return;
+                }
+                break;
+            }
+                
             case LoadVarargs:
                 if (m_graph.uses(node, candidate))
                     lastUserIndex = nodeIndex;

Modified: trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/ftl/FTLExitValue.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -114,7 +114,7 @@
         out.print("Recovery(", recoveryOpcode(), ", arg", leftRecoveryArgument(), ", arg", rightRecoveryArgument(), ", ", recoveryFormat(), ")");
         return;
     case ExitValueMaterializeNewObject:
-        out.print("Materialize(", WTF::RawPointer(objectMaterialization()), ":..)");
+        out.print("Materialize(", WTF::RawPointer(objectMaterialization()), ")");
         return;
     }
     

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -8052,7 +8052,7 @@
             if (!exit.m_materializations.isEmpty()) {
                 dataLog("        Materializations: \n");
                 for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
-                    dataLog("            Materialize(", pointerDump(materialization), ")\n");
+                    dataLog("            ", pointerDump(materialization), "\n");
             }
         }
     }

Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -477,6 +477,19 @@
     JITCode* jitCode = codeBlock->jitCode()->ftl();
     OSRExit& exit = jitCode->osrExit[exitID];
     
+    if (shouldShowDisassembly() || Options::verboseOSR() || Options::verboseFTLOSRExit()) {
+        dataLog("    Owning block: ", pointerDump(codeBlock), "\n");
+        dataLog("    Origin: ", exit.m_codeOrigin, "\n");
+        if (exit.m_codeOriginForExitProfile != exit.m_codeOrigin)
+            dataLog("    Origin for exit profile: ", exit.m_codeOriginForExitProfile, "\n");
+        dataLog("    Exit values: ", exit.m_values, "\n");
+        if (!exit.m_materializations.isEmpty()) {
+            dataLog("    Materializations:\n");
+            for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
+                dataLog("        ", pointerDump(materialization), "\n");
+        }
+    }
+
     prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin);
     
     compileStub(exitID, jitCode, exit, vm, codeBlock);

Modified: trunk/Source/_javascript_Core/jsc.cpp (184259 => 184260)


--- trunk/Source/_javascript_Core/jsc.cpp	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/jsc.cpp	2015-05-13 05:21:16 UTC (rev 184260)
@@ -470,6 +470,7 @@
 static EncodedJSValue JSC_HOST_CALL functionFalse2(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEffectful42(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionMakeMasquerader(ExecState*);
@@ -620,6 +621,7 @@
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum | JSC::Function);
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isFinalTier"), 0, functionFalse2, IsFinalTierIntrinsic, DontEnum | JSC::Function);
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "predictInt32"), 0, functionUndefined2, SetInt32HeapPredictionIntrinsic, DontEnum | JSC::Function);
+        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "isInt32"), 0, functionIsInt32, CheckInt32Intrinsic, DontEnum | JSC::Function);
         putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "fiatInt52"), 0, functionIdentity, FiatInt52Intrinsic, DontEnum | JSC::Function);
         
         addFunction(vm, "effectful42", functionEffectful42, 0);
@@ -1056,6 +1058,14 @@
 
 EncodedJSValue JSC_HOST_CALL functionUndefined1(ExecState*) { return JSValue::encode(jsUndefined()); }
 EncodedJSValue JSC_HOST_CALL functionUndefined2(ExecState*) { return JSValue::encode(jsUndefined()); }
+EncodedJSValue JSC_HOST_CALL functionIsInt32(ExecState* exec)
+{
+    for (size_t i = 0; i < exec->argumentCount(); ++i) {
+        if (!exec->argument(i).isInt32())
+            return JSValue::encode(jsBoolean(false));
+    }
+    return JSValue::encode(jsBoolean(true));
+}
 
 EncodedJSValue JSC_HOST_CALL functionIdentity(ExecState* exec) { return JSValue::encode(exec->argument(0)); }
 

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (184259 => 184260)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2015-05-13 05:18:01 UTC (rev 184259)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2015-05-13 05:21:16 UTC (rev 184260)
@@ -60,6 +60,7 @@
     OSRExitIntrinsic,
     IsFinalTierIntrinsic,
     SetInt32HeapPredictionIntrinsic,
+    CheckInt32Intrinsic,
     FiatInt52Intrinsic,
 };
 

Added: trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-dfg.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-dfg.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-dfg.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,17 @@
+var globalResult;
+Object.prototype.valueOf = function() { globalResult = 1; }
+
+function foo() {
+    globalResult = 0;
+    +arguments;
+    return globalResult;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo();
+    if (result !== 1)
+        throw "Error: bad result: " + result;
+}
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32-dfg.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32-dfg.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32-dfg.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,12 @@
+function foo() {
+    return isInt32(arguments);
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo();
+    if (result !== false)
+        throw "Error: bad result: " + result;
+}
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-int32.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,24 @@
+function foo(p) {
+    var result = 42;
+    var o = arguments;
+    if (p)
+        result = isInt32(o);
+    return result;
+}
+
+noInline(foo);
+
+var result = foo(true);
+if (result !== false)
+    throw "Error: bad result at beginning: " + result;
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false);
+    if (result !== 42)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== false)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-sneakier.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-sneakier.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check-sneakier.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,37 @@
+function bar(o, p) {
+    var o2 = {f: 0};
+    if (p)
+        o2.f = o;
+    return +o2.f;
+}
+
+var globalResult;
+Object.prototype.valueOf = function() { globalResult = 1; };
+
+function foo(p, q) {
+    globalResult = 0;
+    var o = arguments;
+    if (p)
+        bar(o, q);
+    return globalResult;
+}
+
+noInline(foo);
+
+foo(true, false);
+
+for (var i = 0; i < 10000; ++i) {
+    bar(1, true);
+    bar({}, false);
+}
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false, true);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true, true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-arguments-past-invalid-check.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,23 @@
+var globalResult;
+Object.prototype.valueOf = function() { globalResult = 1; }
+
+function foo(p) {
+    globalResult = 0;
+    var o = arguments;
+    if (p)
+        +o;
+    return globalResult;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneakier.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneakier.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneakier.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,35 @@
+function bar(o, p) {
+    if (p)
+        return +o.f;
+    return 42;
+}
+
+var globalResult;
+Function.prototype.valueOf = function() { globalResult = 1; };
+
+function foo(p, q) {
+    globalResult = 0;
+    var o = function() { };
+    var o2 = {f: o};
+    if (p)
+        bar(o2, q);
+    return globalResult;
+}
+
+noInline(foo);
+
+foo(true, false);
+
+for (var i = 0; i < 10000; ++i)
+    bar({f:42}, true);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false, true);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true, true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneaky.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneaky.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-function-past-invalid-check-sneaky.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,13 @@
+function foo(p) {
+    var o = function() { };
+    var q = {f: p ? o : 42};
+    var tmp = q.f + 1;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i)
+    foo(false);
+
+foo(true);
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-int32.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-int32.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-int32.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,24 @@
+function foo(p) {
+    var result = 42;
+    var o = {};
+    if (p)
+        result = isInt32(o);
+    return result;
+}
+
+noInline(foo);
+
+var result = foo(true);
+if (result !== false)
+    throw "Error: bad result at end: " + result;
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false);
+    if (result !== 42)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== false)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneakier.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneakier.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneakier.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,32 @@
+function bar(o, p) {
+    if (p)
+        return +o.f;
+    return 42;
+}
+
+function foo(p, q) {
+    var result = 0;
+    var o = {valueOf: function() { result = 1; }};
+    var o2 = {f: o};
+    if (p)
+        bar(o2, q);
+    return result;
+}
+
+noInline(foo);
+
+foo(true, false);
+
+for (var i = 0; i < 10000; ++i)
+    bar({f:42}, true);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false, true);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true, true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneaky.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneaky.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check-sneaky.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,23 @@
+// https://bugs.webkit.org/show_bug.cgi?id=144945
+//@ skip
+
+function foo(p) {
+    var result = 0;
+    var o = {valueOf: function() { result = 1; }};
+    var q = {f: p ? o : 42};
+    var tmp = q.f + 1;
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+

Added: trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check.js (0 => 184260)


--- trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/sink-object-past-invalid-check.js	2015-05-13 05:21:16 UTC (rev 184260)
@@ -0,0 +1,20 @@
+function foo(p) {
+    var result = 0;
+    var o = {valueOf:function() { result = 1; }};
+    if (p)
+        +o;
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(false);
+    if (result !== 0)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== 1)
+    throw "Error: bad result at end: " + result;
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to