Value profiling should use tier-up threshold randomization to get more coverage
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jun 2012 02:14:07 +0000 (02:14 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jun 2012 02:14:07 +0000 (02:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=89802

Source/JavaScriptCore:

Reviewed by Gavin Barraclough.

This patch causes both LLInt and Baseline JIT code to take the OSR slow path several
times before actually doing OSR. If we take the OSR slow path before the execution
count threshold is reached, then we just call CodeBlock::updateAllPredictions() to
compute the current latest least-upper-bound SpecType of all values seen in each
ValueProfile.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC):
(JSC::CodeBlock::updateAllPredictions):
(JSC::CodeBlock::shouldOptimizeNow):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::llintExecuteCounter):
(JSC::CodeBlock::jitExecuteCounter):
(CodeBlock):
(JSC::CodeBlock::updateAllPredictions):
* bytecode/ExecutionCounter.cpp:
(JSC::ExecutionCounter::setThreshold):
(JSC::ExecutionCounter::status):
(JSC):
* bytecode/ExecutionCounter.h:
(JSC::ExecutionCounter::count):
(ExecutionCounter):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGOperations.cpp:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::jitCompileAndSetHeuristics):
(JSC::LLInt::entryOSR):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
(JSC):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::weakRandomInteger):
* runtime/Options.cpp:
(Options):
(JSC::Options::initializeOptions):
* runtime/Options.h:
(Options):
* runtime/WeakRandom.h:
(WeakRandom):
(JSC::WeakRandom::seedUnsafe):

LayoutTests:

Reviewed by Gavin Barraclough.

* fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt: Added.
* fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html: Added.
* fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js: Added.
(foo):

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/ExecutionCounter.cpp
Source/JavaScriptCore/bytecode/ExecutionCounter.h
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/Options.cpp
Source/JavaScriptCore/runtime/Options.h
Source/JavaScriptCore/runtime/WeakRandom.h

index c65e661..461f7af 100644 (file)
@@ -1,3 +1,15 @@
+2012-06-25  Filip Pizlo  <fpizlo@apple.com>
+
+        Value profiling should use tier-up threshold randomization to get more coverage
+        https://bugs.webkit.org/show_bug.cgi?id=89802
+
+        Reviewed by Gavin Barraclough.
+        
+        * fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt: Added.
+        * fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html: Added.
+        * fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js: Added.
+        (foo):
+
 2012-06-25  Shinya Kawanaka  <shinyak@chromium.org>
 
         [Shadow] Deleting list distributed to Shadow DOM does not work correctly.
diff --git a/LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt b/LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt
new file mode 100644 (file)
index 0000000..93d1233
--- /dev/null
@@ -0,0 +1,209 @@
+Tests what happens when you store an unexpected value into an argument (where the original argument value was the expected one) and then OSR exit.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 1
+PASS foo(3, {f:f, g:g}, p) is 85
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS foo(3, {f:f, g:g}, p) is 0.5
+PASS foo(3, {f:f, g:g}, p) is 85.5
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html b/LayoutTests/fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html
new file mode 100644 (file)
index 0000000..f4b94f2
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js b/LayoutTests/fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js
new file mode 100644 (file)
index 0000000..7247815
--- /dev/null
@@ -0,0 +1,41 @@
+description(
+"Tests what happens when you store an unexpected value into an argument (where the original argument value was the expected one) and then OSR exit."
+);
+
+function foo(x, o, p) {
+    x = o.f;
+    if (p) {
+        var result = o.g + x;
+        x = true; // Force x to not have a hoisted integer speculation.
+        return result;
+    } else
+        return o.g - x;
+}
+
+for (var i = 0; i < 200; ++i) {
+    var expected;
+    var p, f, g;
+    if (i < 150) {
+        f = 42;
+        g = 43;
+        if (i%2) {
+            p = true;
+            expected = 85;
+        } else {
+            p = false;
+            expected = 1;
+        }
+    } else {
+        f = 42.5;
+        g = 43;
+        if (i%2) {
+            p = true;
+            expected = 85.5;
+        } else {
+            p = false;
+            expected = 0.5;
+        }
+    }
+    shouldBe("foo(3, {f:f, g:g}, p)", "" + expected);
+}
+
index cdefab9..2bf3c99 100644 (file)
@@ -1,3 +1,60 @@
+2012-06-22  Filip Pizlo  <fpizlo@apple.com>
+
+        Value profiling should use tier-up threshold randomization to get more coverage
+        https://bugs.webkit.org/show_bug.cgi?id=89802
+
+        Reviewed by Gavin Barraclough.
+        
+        This patch causes both LLInt and Baseline JIT code to take the OSR slow path several
+        times before actually doing OSR. If we take the OSR slow path before the execution
+        count threshold is reached, then we just call CodeBlock::updateAllPredictions() to
+        compute the current latest least-upper-bound SpecType of all values seen in each
+        ValueProfile.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::stronglyVisitStrongReferences):
+        (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
+        (JSC):
+        (JSC::CodeBlock::updateAllPredictions):
+        (JSC::CodeBlock::shouldOptimizeNow):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::llintExecuteCounter):
+        (JSC::CodeBlock::jitExecuteCounter):
+        (CodeBlock):
+        (JSC::CodeBlock::updateAllPredictions):
+        * bytecode/ExecutionCounter.cpp:
+        (JSC::ExecutionCounter::setThreshold):
+        (JSC::ExecutionCounter::status):
+        (JSC):
+        * bytecode/ExecutionCounter.h:
+        (JSC::ExecutionCounter::count):
+        (ExecutionCounter):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::jitCompileAndSetHeuristics):
+        (JSC::LLInt::entryOSR):
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::JSGlobalObject):
+        (JSC):
+        * runtime/JSGlobalObject.h:
+        (JSGlobalObject):
+        (JSC::JSGlobalObject::weakRandomInteger):
+        * runtime/Options.cpp:
+        (Options):
+        (JSC::Options::initializeOptions):
+        * runtime/Options.h:
+        (Options):
+        * runtime/WeakRandom.h:
+        (WeakRandom):
+        (JSC::WeakRandom::seedUnsafe):
+
 2012-06-25  Yong Li  <yoli@rim.com>
 
         [BlackBerry] Add JSC statistics into about:memory
index c48ef49..6a8a893 100755 (executable)
@@ -9,6 +9,7 @@ EXPORTS
     ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z
     ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z 
     ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z
+    ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z
     ??0JSLock@JSC@@QAE@PAVExecState@1@@Z
     ??0MD5@WTF@@QAE@XZ
     ??0Mutex@WTF@@QAE@XZ
index bcbb51f..e0a4da7 100644 (file)
@@ -2104,26 +2104,7 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
     }
 #endif
 
-#if ENABLE(DFG_JIT)
-    if (hasCodeOrigins()) {
-        // Make sure that executables that we have inlined don't die.
-        // FIXME: If they would have otherwise died, we should probably trigger recompilation.
-        for (size_t i = 0; i < inlineCallFrames().size(); ++i) {
-            InlineCallFrame& inlineCallFrame = inlineCallFrames()[i];
-            visitor.append(&inlineCallFrame.executable);
-            visitor.append(&inlineCallFrame.callee);
-        }
-    }
-    
-    m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection);
-#endif
-
-#if ENABLE(VALUE_PROFILER)
-    for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
-        valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection);
-    for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
-        valueProfile(profileIndex)->computeUpdatedPrediction(Collection);
-#endif
+    updateAllPredictions(Collection);
 }
 
 void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor)
@@ -2574,21 +2555,11 @@ bool FunctionCodeBlock::jitCompileImpl(ExecState* exec)
 #endif
 
 #if ENABLE(VALUE_PROFILER)
-bool CodeBlock::shouldOptimizeNow()
+void CodeBlock::updateAllPredictionsAndCountLiveness(
+    OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
 {
-#if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("Considering optimizing %p...\n", this);
-#endif
-
-#if ENABLE(VERBOSE_VALUE_PROFILE)
-    dumpValueProfiles();
-#endif
-
-    if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
-        return true;
-    
-    unsigned numberOfLiveNonArgumentValueProfiles = 0;
-    unsigned numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
+    numberOfLiveNonArgumentValueProfiles = 0;
+    numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
     for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
         ValueProfile* profile = getFromAllValueProfiles(i);
         unsigned numSamples = profile->totalNumberOfSamples();
@@ -2596,13 +2567,41 @@ bool CodeBlock::shouldOptimizeNow()
             numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
         numberOfSamplesInProfiles += numSamples;
         if (profile->m_bytecodeOffset < 0) {
-            profile->computeUpdatedPrediction();
+            profile->computeUpdatedPrediction(operation);
             continue;
         }
         if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
             numberOfLiveNonArgumentValueProfiles++;
-        profile->computeUpdatedPrediction();
+        profile->computeUpdatedPrediction(operation);
     }
+    
+#if ENABLE(DFG_JIT)
+    m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
+#endif
+}
+
+void CodeBlock::updateAllPredictions(OperationInProgress operation)
+{
+    unsigned ignoredValue1, ignoredValue2;
+    updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+}
+
+bool CodeBlock::shouldOptimizeNow()
+{
+#if ENABLE(JIT_VERBOSE_OSR)
+    dataLog("Considering optimizing %p...\n", this);
+#endif
+
+#if ENABLE(VERBOSE_VALUE_PROFILE)
+    dumpValueProfiles();
+#endif
+
+    if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
+        return true;
+    
+    unsigned numberOfLiveNonArgumentValueProfiles;
+    unsigned numberOfSamplesInProfiles;
+    updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
 
 #if ENABLE(JIT_VERBOSE_OSR)
     dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
index b73dcb2..4e4fee2 100644 (file)
@@ -913,9 +913,9 @@ namespace JSC {
             m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon, this);
         }
         
-        int32_t llintExecuteCounter() const
+        const ExecutionCounter& llintExecuteCounter() const
         {
-            return m_llintExecuteCounter.m_counter;
+            return m_llintExecuteCounter;
         }
         
         // Functions for controlling when tiered compilation kicks in. This
@@ -971,7 +971,7 @@ namespace JSC {
         static ptrdiff_t offsetOfJITExecutionActiveThreshold() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_activeThreshold); }
         static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_totalCount); }
 
-        int32_t jitExecuteCounter() const { return m_jitExecuteCounter.m_counter; }
+        const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; }
         
         unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; }
         
@@ -1100,8 +1100,10 @@ namespace JSC {
 
 #if ENABLE(VALUE_PROFILER)
         bool shouldOptimizeNow();
+        void updateAllPredictions(OperationInProgress = NoOperation);
 #else
         bool shouldOptimizeNow() { return false; }
+        void updateAllPredictions(OperationInProgress = NoOperation) { }
 #endif
         
 #if ENABLE(JIT)
@@ -1134,6 +1136,9 @@ namespace JSC {
 #else
         void tallyFrequentExitSites() { }
 #endif
+#if ENABLE(VALUE_PROFILER)
+        void updateAllPredictionsAndCountLiveness(OperationInProgress, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
+#endif
         
         void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&);
 
index ea33500..abbcf6b 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "CodeBlock.h"
 #include "ExecutableAllocator.h"
+#include <wtf/StringExtras.h>
 
 namespace JSC {
 
@@ -125,7 +126,7 @@ bool ExecutionCounter::setThreshold(CodeBlock* codeBlock)
     ASSERT(!hasCrossedThreshold(codeBlock));
         
     // Compute the true total count.
-    double trueTotalCount = static_cast<double>(m_totalCount) + m_counter;
+    double trueTotalCount = count();
         
     // Correct the threshold for current memory usage.
     double threshold = applyMemoryUsageHeuristics(m_activeThreshold, codeBlock);
@@ -143,9 +144,11 @@ bool ExecutionCounter::setThreshold(CodeBlock* codeBlock)
         return true;
     }
 
-    if (threshold > std::numeric_limits<int32_t>::max())
-        threshold = std::numeric_limits<int32_t>::max();
-        
+    int32_t maxThreshold =
+        codeBlock->globalObject()->weakRandomInteger() % Options::maximumExecutionCountsBetweenCheckpoints;
+    if (threshold > maxThreshold)
+        threshold = maxThreshold;
+    
     m_counter = static_cast<int32_t>(-threshold);
         
     m_totalCount = trueTotalCount + threshold;
@@ -160,5 +163,12 @@ void ExecutionCounter::reset()
     m_activeThreshold = 0;
 }
 
+const char* ExecutionCounter::status() const
+{
+    static char result[80];
+    snprintf(result, sizeof(result), "%lf/%lf, %d", count(), static_cast<double>(m_activeThreshold), m_counter);
+    return result;
+}
+
 } // namespace JSC
 
index d2ffbb6..1c0d23f 100644 (file)
@@ -38,6 +38,8 @@ public:
     bool checkIfThresholdCrossedAndSet(CodeBlock*);
     void setNewThreshold(int32_t threshold, CodeBlock*);
     void deferIndefinitely();
+    double count() const { return static_cast<double>(m_totalCount) + m_counter; }
+    const char* status() const;
     static double applyMemoryUsageHeuristics(int32_t value, CodeBlock*);
     static int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*);
 
index 94e9685..b4205ef 100644 (file)
@@ -1392,7 +1392,7 @@ bool AbstractState::execute(unsigned indexInBlock)
     case StructureTransitionWatchpoint: {
         // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible!
         AbstractValue& value = forNode(node.child1());
-        ASSERT(isCellSpeculation(value.m_type));
+        ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
         value.filter(node.structure());
         node.setCanExit(true);
         break;
index b056a3c..3ece917 100644 (file)
@@ -1238,12 +1238,12 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
     SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
     CodeBlock* codeBlock = debugInfo->codeBlock;
     CodeBlock* alternative = codeBlock->alternative();
-    dataLog("Speculation failure in %p at @%u with executeCounter = %d, "
+    dataLog("Speculation failure in %p at @%u with executeCounter = %s, "
             "reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, "
             "success/fail %u/(%u+%u)\n",
             codeBlock,
             debugInfo->nodeIndex,
-            alternative ? alternative->jitExecuteCounter() : 0,
+            alternative ? alternative->jitExecuteCounter().status() : 0,
             alternative ? alternative->reoptimizationRetryCounter() : 0,
             alternative ? alternative->optimizationDelayCounter() : 0,
             codeBlock->speculativeSuccessCounter(),
index d9a79f1..b0fed46 100644 (file)
@@ -986,13 +986,8 @@ void SpeculativeJIT::compile(BasicBlock& block)
     m_jit.jitAssertHasValidCallFrame();
 
     ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
-    for (size_t i = 0; i < m_arguments.size(); ++i) {
-        NodeIndex nodeIndex = block.variablesAtHead.argument(i);
-        if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i))
-            m_arguments[i] = ValueSource(ValueInRegisterFile);
-        else
-            m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction());
-    }
+    for (size_t i = 0; i < m_arguments.size(); ++i)
+        m_arguments[i] = ValueSource(ValueInRegisterFile);
     
     m_state.reset();
     m_state.beginBasicBlock(&block);
index b0ff4a0..6b80828 100644 (file)
@@ -1928,11 +1928,13 @@ DEFINE_STUB_FUNCTION(void, optimize)
     unsigned bytecodeIndex = stackFrame.args[0].int32();
 
 #if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
+    dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
 #endif
 
-    if (!codeBlock->checkIfOptimizationThresholdReached())
+    if (!codeBlock->checkIfOptimizationThresholdReached()) {
+        codeBlock->updateAllPredictions();
         return;
+    }
 
     if (codeBlock->hasOptimizedReplacement()) {
 #if ENABLE(JIT_VERBOSE_OSR)
index ca3eb1e..a7698be 100644 (file)
@@ -264,6 +264,8 @@ inline bool shouldJIT(ExecState* exec)
 // Returns true if we should try to OSR.
 inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
 {
+    codeBlock->updateAllPredictions();
+    
     if (!codeBlock->checkIfJITThresholdReached()) {
 #if ENABLE(JIT_VERBOSE_OSR)
         dataLog("    JIT threshold should be lifted.\n");
@@ -300,7 +302,8 @@ enum EntryKind { Prologue, ArityCheck };
 static SlowPathReturnType entryOSR(ExecState* exec, Instruction* pc, CodeBlock* codeBlock, const char *name, EntryKind kind)
 {
 #if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("%p: Entered %s with executeCounter = %d\n", codeBlock, name, codeBlock->llintExecuteCounter());
+    dataLog("%p: Entered %s with executeCounter = %s\n", codeBlock, name,
+            codeBlock->llintExecuteCounter().status());
 #endif
     
     if (!shouldJIT(exec)) {
@@ -346,7 +349,8 @@ LLINT_SLOW_PATH_DECL(loop_osr)
     CodeBlock* codeBlock = exec->codeBlock();
     
 #if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("%p: Entered loop_osr with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter());
+    dataLog("%p: Entered loop_osr with executeCounter = %s\n", codeBlock,
+            codeBlock->llintExecuteCounter().status());
 #endif
     
     if (!shouldJIT(exec)) {
@@ -376,7 +380,8 @@ LLINT_SLOW_PATH_DECL(replace)
     CodeBlock* codeBlock = exec->codeBlock();
     
 #if ENABLE(JIT_VERBOSE_OSR)
-    dataLog("%p: Entered replace with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter());
+    dataLog("%p: Entered replace with executeCounter = %s\n", codeBlock,
+            codeBlock->llintExecuteCounter().status());
 #endif
     
     if (shouldJIT(exec))
index d38570d..d19db4f 100644 (file)
@@ -112,6 +112,15 @@ template <typename T> static inline void visitIfNeeded(SlotVisitor& visitor, Wri
         visitor.append(v);
 }
 
+JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
+    : JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
+    , m_globalScopeChain()
+    , m_weakRandom(Options::forceWeakRandomSeed ? Options::forcedWeakRandomSeed : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+    , m_evalEnabled(true)
+    , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
+{
+}
+
 JSGlobalObject::~JSGlobalObject()
 {
     ASSERT(JSLock::currentThreadIsHoldingLock());
index 2396142..8fec633 100644 (file)
@@ -175,14 +175,7 @@ namespace JSC {
         static JS_EXPORTDATA const ClassInfo s_info;
 
     protected:
-        explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)
-            : JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
-            , m_globalScopeChain()
-            , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
-            , m_evalEnabled(true)
-            , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
-        {
-        }
+        JS_EXPORT_PRIVATE explicit JSGlobalObject(JSGlobalData&, Structure*, const GlobalObjectMethodTable* = 0);
 
         void finishCreation(JSGlobalData& globalData)
         {
@@ -328,6 +321,7 @@ namespace JSC {
         }
 
         double weakRandomNumber() { return m_weakRandom.get(); }
+        unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }
     protected:
 
         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSSegmentedVariableObject::StructureFlags;
index 7b6da65..f7da9e2 100644 (file)
@@ -67,6 +67,8 @@ int32_t thresholdForOptimizeSoon;
 int32_t executionCounterIncrementForLoop;
 int32_t executionCounterIncrementForReturn;
 
+int32_t maximumExecutionCountsBetweenCheckpoints;
+
 unsigned desiredSpeculativeSuccessFailRatio;
 
 double likelyToTakeSlowCaseThreshold;
@@ -95,6 +97,9 @@ unsigned gcMarkStackSegmentSize;
 unsigned numberOfGCMarkers;
 unsigned opaqueRootMergeThreshold;
 
+bool forceWeakRandomSeed;
+unsigned forcedWeakRandomSeed;
+
 #if ENABLE(RUN_TIME_HEURISTICS)
 static bool parse(const char* string, bool& value)
 {
@@ -184,6 +189,8 @@ void initializeOptions()
 
     SET(executionCounterIncrementForLoop,   1);
     SET(executionCounterIncrementForReturn, 15);
+    
+    SET(maximumExecutionCountsBetweenCheckpoints, 1000);
 
     SET(desiredSpeculativeSuccessFailRatio, 6);
     
@@ -227,6 +234,9 @@ void initializeOptions()
     
     ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) > 0);
     ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
+    
+    SET(forceWeakRandomSeed, false);
+    SET(forcedWeakRandomSeed, 0);
 }
 
 } } // namespace JSC::Options
index 0adb59e..47e5113 100644 (file)
@@ -53,6 +53,8 @@ extern int32_t thresholdForOptimizeNextInvocation;
 extern int32_t executionCounterIncrementForLoop;
 extern int32_t executionCounterIncrementForReturn;
 
+extern int32_t maximumExecutionCountsBetweenCheckpoints;
+
 extern unsigned desiredSpeculativeSuccessFailRatio;
 
 extern double likelyToTakeSlowCaseThreshold;
@@ -81,6 +83,9 @@ extern unsigned gcMarkStackSegmentSize;
 JS_EXPORTDATA extern unsigned numberOfGCMarkers;
 JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold;
 
+extern bool forceWeakRandomSeed;
+extern unsigned forcedWeakRandomSeed;
+
 void initializeOptions();
 
 } } // namespace JSC::Options
index 6083980..3cd1016 100644 (file)
@@ -62,6 +62,9 @@ public:
         , m_high(seed)
     {
     }
+    
+    // Returns the seed provided that you've never called get() or getUint32().
+    unsigned seedUnsafe() const { return m_high; }
 
     double get()
     {