DFG performs incorrect DCE on (some?) intrinsics
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Apr 2012 20:43:01 +0000 (20:43 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Apr 2012 20:43:01 +0000 (20:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=84746
<rdar://problem/11310772>

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::setIntrinsicResult):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):

LayoutTests:

Rubber stamped by Oliver Hunt.

* fast/js/dfg-dead-min-one-arg-expected.txt: Added.
* fast/js/dfg-dead-min-one-arg.html: Added.
* fast/js/dfg-dead-min-two-args-expected.txt: Added.
* fast/js/dfg-dead-min-two-args.html: Added.
* fast/js/script-tests/dfg-dead-min-one-arg.js: Added.
(foo):
(.x.f.valueOf):
* fast/js/script-tests/dfg-dead-min-two-args.js: Added.
(foo):
(bar):
(.x.f.valueOf):
(.y.f.valueOf):

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/dfg-dead-min-one-arg-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-dead-min-one-arg.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-dead-min-two-args-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-dead-min-two-args.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-dead-min-one-arg.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-dead-min-two-args.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

index 3ad14b8..2138378 100644 (file)
@@ -1,3 +1,24 @@
+2012-04-24  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG performs incorrect DCE on (some?) intrinsics
+        https://bugs.webkit.org/show_bug.cgi?id=84746
+        <rdar://problem/11310772>
+
+        Rubber stamped by Oliver Hunt.
+
+        * fast/js/dfg-dead-min-one-arg-expected.txt: Added.
+        * fast/js/dfg-dead-min-one-arg.html: Added.
+        * fast/js/dfg-dead-min-two-args-expected.txt: Added.
+        * fast/js/dfg-dead-min-two-args.html: Added.
+        * fast/js/script-tests/dfg-dead-min-one-arg.js: Added.
+        (foo):
+        (.x.f.valueOf):
+        * fast/js/script-tests/dfg-dead-min-two-args.js: Added.
+        (foo):
+        (bar):
+        (.x.f.valueOf):
+        (.y.f.valueOf):
+
 2012-04-24  Andreas Kling  <kling@webkit.org>
 
         Rebaseline mac rendertree output for svg/custom/use-css-events.svg.
diff --git a/LayoutTests/fast/js/dfg-dead-min-one-arg-expected.txt b/LayoutTests/fast/js/dfg-dead-min-one-arg-expected.txt
new file mode 100644 (file)
index 0000000..f523256
--- /dev/null
@@ -0,0 +1,259 @@
+Tests that a dummy use of Math.min(a) at least speculates that its argument is indeed a number.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS result is 42
+PASS ok is 150
+PASS result is 37
+PASS ok is 151
+PASS result is 37
+PASS ok is 152
+PASS result is 37
+PASS ok is 153
+PASS result is 37
+PASS ok is 154
+PASS result is 37
+PASS ok is 155
+PASS result is 37
+PASS ok is 156
+PASS result is 37
+PASS ok is 157
+PASS result is 37
+PASS ok is 158
+PASS result is 37
+PASS ok is 159
+PASS result is 37
+PASS ok is 160
+PASS result is 37
+PASS ok is 161
+PASS result is 37
+PASS ok is 162
+PASS result is 37
+PASS ok is 163
+PASS result is 37
+PASS ok is 164
+PASS result is 37
+PASS ok is 165
+PASS result is 37
+PASS ok is 166
+PASS result is 37
+PASS ok is 167
+PASS result is 37
+PASS ok is 168
+PASS result is 37
+PASS ok is 169
+PASS result is 37
+PASS ok is 170
+PASS result is 37
+PASS ok is 171
+PASS result is 37
+PASS ok is 172
+PASS result is 37
+PASS ok is 173
+PASS result is 37
+PASS ok is 174
+PASS result is 37
+PASS ok is 175
+PASS result is 37
+PASS ok is 176
+PASS result is 37
+PASS ok is 177
+PASS result is 37
+PASS ok is 178
+PASS result is 37
+PASS ok is 179
+PASS result is 37
+PASS ok is 180
+PASS result is 37
+PASS ok is 181
+PASS result is 37
+PASS ok is 182
+PASS result is 37
+PASS ok is 183
+PASS result is 37
+PASS ok is 184
+PASS result is 37
+PASS ok is 185
+PASS result is 37
+PASS ok is 186
+PASS result is 37
+PASS ok is 187
+PASS result is 37
+PASS ok is 188
+PASS result is 37
+PASS ok is 189
+PASS result is 37
+PASS ok is 190
+PASS result is 37
+PASS ok is 191
+PASS result is 37
+PASS ok is 192
+PASS result is 37
+PASS ok is 193
+PASS result is 37
+PASS ok is 194
+PASS result is 37
+PASS ok is 195
+PASS result is 37
+PASS ok is 196
+PASS result is 37
+PASS ok is 197
+PASS result is 37
+PASS ok is 198
+PASS result is 37
+PASS ok is 199
+PASS result is 37
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-dead-min-one-arg.html b/LayoutTests/fast/js/dfg-dead-min-one-arg.html
new file mode 100644 (file)
index 0000000..9c15e95
--- /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-dead-min-one-arg.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-dead-min-two-args-expected.txt b/LayoutTests/fast/js/dfg-dead-min-two-args-expected.txt
new file mode 100644 (file)
index 0000000..a8e8b51
--- /dev/null
@@ -0,0 +1,509 @@
+Tests that a dead use of Math.min(a,b) at least speculates that its arguments are indeed numbers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS ok is 150
+PASS result is 100
+PASS ok is 151
+PASS result is 100
+PASS ok is 152
+PASS result is 100
+PASS ok is 153
+PASS result is 100
+PASS ok is 154
+PASS result is 100
+PASS ok is 155
+PASS result is 100
+PASS ok is 156
+PASS result is 100
+PASS ok is 157
+PASS result is 100
+PASS ok is 158
+PASS result is 100
+PASS ok is 159
+PASS result is 100
+PASS ok is 160
+PASS result is 100
+PASS ok is 161
+PASS result is 100
+PASS ok is 162
+PASS result is 100
+PASS ok is 163
+PASS result is 100
+PASS ok is 164
+PASS result is 100
+PASS ok is 165
+PASS result is 100
+PASS ok is 166
+PASS result is 100
+PASS ok is 167
+PASS result is 100
+PASS ok is 168
+PASS result is 100
+PASS ok is 169
+PASS result is 100
+PASS ok is 170
+PASS result is 100
+PASS ok is 171
+PASS result is 100
+PASS ok is 172
+PASS result is 100
+PASS ok is 173
+PASS result is 100
+PASS ok is 174
+PASS result is 100
+PASS ok is 175
+PASS result is 100
+PASS ok is 176
+PASS result is 100
+PASS ok is 177
+PASS result is 100
+PASS ok is 178
+PASS result is 100
+PASS ok is 179
+PASS result is 100
+PASS ok is 180
+PASS result is 100
+PASS ok is 181
+PASS result is 100
+PASS ok is 182
+PASS result is 100
+PASS ok is 183
+PASS result is 100
+PASS ok is 184
+PASS result is 100
+PASS ok is 185
+PASS result is 100
+PASS ok is 186
+PASS result is 100
+PASS ok is 187
+PASS result is 100
+PASS ok is 188
+PASS result is 100
+PASS ok is 189
+PASS result is 100
+PASS ok is 190
+PASS result is 100
+PASS ok is 191
+PASS result is 100
+PASS ok is 192
+PASS result is 100
+PASS ok is 193
+PASS result is 100
+PASS ok is 194
+PASS result is 100
+PASS ok is 195
+PASS result is 100
+PASS ok is 196
+PASS result is 100
+PASS ok is 197
+PASS result is 100
+PASS ok is 198
+PASS result is 100
+PASS ok is 199
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS result is 100
+PASS ok is 150
+PASS result is 100
+PASS ok is 151
+PASS result is 100
+PASS ok is 152
+PASS result is 100
+PASS ok is 153
+PASS result is 100
+PASS ok is 154
+PASS result is 100
+PASS ok is 155
+PASS result is 100
+PASS ok is 156
+PASS result is 100
+PASS ok is 157
+PASS result is 100
+PASS ok is 158
+PASS result is 100
+PASS ok is 159
+PASS result is 100
+PASS ok is 160
+PASS result is 100
+PASS ok is 161
+PASS result is 100
+PASS ok is 162
+PASS result is 100
+PASS ok is 163
+PASS result is 100
+PASS ok is 164
+PASS result is 100
+PASS ok is 165
+PASS result is 100
+PASS ok is 166
+PASS result is 100
+PASS ok is 167
+PASS result is 100
+PASS ok is 168
+PASS result is 100
+PASS ok is 169
+PASS result is 100
+PASS ok is 170
+PASS result is 100
+PASS ok is 171
+PASS result is 100
+PASS ok is 172
+PASS result is 100
+PASS ok is 173
+PASS result is 100
+PASS ok is 174
+PASS result is 100
+PASS ok is 175
+PASS result is 100
+PASS ok is 176
+PASS result is 100
+PASS ok is 177
+PASS result is 100
+PASS ok is 178
+PASS result is 100
+PASS ok is 179
+PASS result is 100
+PASS ok is 180
+PASS result is 100
+PASS ok is 181
+PASS result is 100
+PASS ok is 182
+PASS result is 100
+PASS ok is 183
+PASS result is 100
+PASS ok is 184
+PASS result is 100
+PASS ok is 185
+PASS result is 100
+PASS ok is 186
+PASS result is 100
+PASS ok is 187
+PASS result is 100
+PASS ok is 188
+PASS result is 100
+PASS ok is 189
+PASS result is 100
+PASS ok is 190
+PASS result is 100
+PASS ok is 191
+PASS result is 100
+PASS ok is 192
+PASS result is 100
+PASS ok is 193
+PASS result is 100
+PASS ok is 194
+PASS result is 100
+PASS ok is 195
+PASS result is 100
+PASS ok is 196
+PASS result is 100
+PASS ok is 197
+PASS result is 100
+PASS ok is 198
+PASS result is 100
+PASS ok is 199
+PASS result is 100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-dead-min-two-args.html b/LayoutTests/fast/js/dfg-dead-min-two-args.html
new file mode 100644 (file)
index 0000000..f062d42
--- /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-dead-min-two-args.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/dfg-dead-min-one-arg.js b/LayoutTests/fast/js/script-tests/dfg-dead-min-one-arg.js
new file mode 100644 (file)
index 0000000..d6a59f4
--- /dev/null
@@ -0,0 +1,24 @@
+description(
+"Tests that a dummy use of Math.min(a) at least speculates that its argument is indeed a number."
+);
+
+function foo(a) {
+    return Math.min(a.f);
+}
+
+var x = {f:42};
+var ok = null;
+var expected = 42;
+var empty = "";
+
+for (var i = 0; i < 200; ++i) {
+    if (i == 150) {
+        x = {f:{valueOf:function(){ ok = i; return 37; }}};
+        expected = 37;
+    }
+    var result = eval(empty + "foo(x)");
+    if (i >= 150)
+        shouldBe("ok", "" + i);
+    shouldBe("result", "" + expected);
+}
+
diff --git a/LayoutTests/fast/js/script-tests/dfg-dead-min-two-args.js b/LayoutTests/fast/js/script-tests/dfg-dead-min-two-args.js
new file mode 100644 (file)
index 0000000..f46bf3c
--- /dev/null
@@ -0,0 +1,47 @@
+description(
+"Tests that a dead use of Math.min(a,b) at least speculates that its arguments are indeed numbers."
+);
+
+function foo(a, b) {
+    Math.min(a.f, b.f);
+    return 100;
+}
+
+function bar(a, b) {
+    Math.min(a.f, b.f);
+    return 100;
+}
+
+var x = {f:42};
+var y = {f:43};
+var ok = null;
+var expected = 42;
+var empty = "";
+
+for (var i = 0; i < 200; ++i) {
+    if (i == 150) {
+        x = {f:{valueOf:function(){ ok = i; return 37; }}};
+        expected = 37;
+    }
+    var result = eval(empty + "foo(x, y)");
+    if (i >= 150)
+        shouldBe("ok", "" + i);
+    shouldBe("result", "100");
+}
+
+x = {f:42};
+y = {f:43};
+ok = null;
+expected = 42;
+
+for (var i = 0; i < 200; ++i) {
+    if (i == 150) {
+        y = {f:{valueOf:function(){ ok = i; return 37; }}};
+        expected = 37;
+    }
+    var result = eval(empty + "bar(x, y)");
+    if (i >= 150)
+        shouldBe("ok", "" + i);
+    shouldBe("result", "100");
+}
+
index aebca8e..8933b7e 100644 (file)
@@ -1,3 +1,27 @@
+2012-04-24  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG performs incorrect DCE on (some?) intrinsics
+        https://bugs.webkit.org/show_bug.cgi?id=84746
+        <rdar://problem/11310772>
+
+        Reviewed by Oliver Hunt.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGByteCodeParser.cpp:
+        (ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::setIntrinsicResult):
+        (JSC::DFG::ByteCodeParser::handleMinMax):
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+
 2012-04-24  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Failure to allocate ArrayStorage in emit_op_new_array leads to poisonous JSArray
index ad01df3..0beec9d 100644 (file)
@@ -310,6 +310,10 @@ bool AbstractState::execute(unsigned indexInBlock)
         forNode(node.child1()).filter(PredictNumber);
         forNode(nodeIndex).set(PredictDouble);
         break;
+        
+    case CheckNumber:
+        forNode(node.child1()).filter(PredictNumber);
+        break;
             
     case ValueAdd:
     case ArithAdd: {
index 6d74550..654ac98 100644 (file)
@@ -89,6 +89,8 @@ private:
     void emitFunctionCheck(JSFunction* expectedFunction, NodeIndex callTarget, int registerOffset, CodeSpecializationKind);
     // Handle inlining. Return true if it succeeded, false if we need to plant a call.
     bool handleInlining(bool usesResult, int callTarget, NodeIndex callTargetNodeIndex, int resultOperand, bool certainAboutExpectedFunction, JSFunction*, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
+    // Handle setting the result of an intrinsic.
+    void setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex);
     // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call.
     bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, PredictedType prediction);
     // Prepare to parse a block.
@@ -1287,23 +1289,30 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
     return true;
 }
 
-bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis)
+void ByteCodeParser::setIntrinsicResult(bool usesResult, int resultOperand, NodeIndex nodeIndex)
 {
     if (!usesResult)
-        return true;
+        return;
+    set(resultOperand, nodeIndex);
+}
 
+bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis)
+{
     if (argumentCountIncludingThis == 1) { // Math.min()
-        set(resultOperand, constantNaN());
+        setIntrinsicResult(usesResult, resultOperand, constantNaN());
         return true;
     }
      
     if (argumentCountIncludingThis == 2) { // Math.min(x)
-        set(resultOperand, get(registerOffset + argumentToOperand(1)));
+        // FIXME: what we'd really like is a ValueToNumber, except we don't support that right now. Oh well.
+        NodeIndex result = get(registerOffset + argumentToOperand(1));
+        addToGraph(CheckNumber, result);
+        setIntrinsicResult(usesResult, resultOperand, result);
         return true;
     }
     
     if (argumentCountIncludingThis == 3) { // Math.min(x, y)
-        set(resultOperand, addToGraph(op, get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
+        setIntrinsicResult(usesResult, resultOperand, addToGraph(op, get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
         return true;
     }
     
@@ -1317,14 +1326,8 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
 {
     switch (intrinsic) {
     case AbsIntrinsic: {
-        if (!usesResult) {
-            // There is no such thing as executing abs for effect, so this
-            // is dead code.
-            return true;
-        }
-        
         if (argumentCountIncludingThis == 1) { // Math.abs()
-            set(resultOperand, constantNaN());
+            setIntrinsicResult(usesResult, resultOperand, constantNaN());
             return true;
         }
 
@@ -1334,7 +1337,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
         NodeIndex nodeIndex = addToGraph(ArithAbs, get(registerOffset + argumentToOperand(1)));
         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
             m_graph[nodeIndex].mergeFlags(NodeMayOverflow);
-        set(resultOperand, nodeIndex);
+        setIntrinsicResult(usesResult, resultOperand, nodeIndex);
         return true;
     }
 
@@ -1345,18 +1348,15 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
         return handleMinMax(usesResult, resultOperand, ArithMax, registerOffset, argumentCountIncludingThis);
         
     case SqrtIntrinsic: {
-        if (!usesResult)
-            return true;
-        
         if (argumentCountIncludingThis == 1) { // Math.sqrt()
-            set(resultOperand, constantNaN());
+            setIntrinsicResult(usesResult, resultOperand, constantNaN());
             return true;
         }
         
         if (!MacroAssembler::supportsFloatingPointSqrt())
             return false;
         
-        set(resultOperand, addToGraph(ArithSqrt, get(registerOffset + argumentToOperand(1))));
+        setIntrinsicResult(usesResult, resultOperand, addToGraph(ArithSqrt, get(registerOffset + argumentToOperand(1))));
         return true;
     }
         
index e51b2db..182bdc4 100644 (file)
@@ -75,11 +75,14 @@ namespace JSC { namespace DFG {
     macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
     /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
     macro(UInt32ToNumber, NodeResultNumber) \
+    \
     /* Used to cast known integers to doubles, so as to separate the double form */\
     /* of the value from the integer form. */\
     macro(Int32ToDouble, NodeResultNumber) \
     /* Used to speculate that a double value is actually an integer. */\
     macro(DoubleAsInt32, NodeResultInt32) \
+    /* Used to record places where we must check if a value is a number. */\
+    macro(CheckNumber, NodeMustGenerate) \
     \
     /* Nodes for arithmetic operations. */\
     macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \
index 84ae9b3..cdbd6d3 100644 (file)
@@ -620,6 +620,7 @@ private:
         case CheckFunction:
         case PutStructure:
         case TearOffActivation:
+        case CheckNumber:
             changed |= mergeDefaultFlags(node);
             break;
             
index bb81411..f197084 100644 (file)
@@ -2053,6 +2053,19 @@ void SpeculativeJIT::compile(Node& node)
         compileInt32ToDouble(node);
         break;
     }
+        
+    case CheckNumber: {
+        if (!isPredictedNumber(m_state.forNode(node.child1()).m_type)) {
+            JSValueOperand op1(this, node.child1());
+            JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op1.tagGPR(), TrustedImm32(JSValue::Int32Tag));
+            speculationCheck(
+                BadType, JSValueRegs(op1.tagGPR(), op1.payloadGPR()), node.child1().index(),
+                m_jit.branch32(MacroAssembler::AboveOrEqual, op1.tagGPR(), TrustedImm32(JSValue::LowestTag)));
+            isInteger.link(&m_jit);
+        }
+        noResult(m_compileIndex);
+        break;
+    }
 
     case ValueAdd:
     case ArithAdd:
index 9f42248..6feeaaa 100644 (file)
@@ -2128,6 +2128,19 @@ void SpeculativeJIT::compile(Node& node)
         compileInt32ToDouble(node);
         break;
     }
+        
+    case CheckNumber: {
+        if (!isNumberPrediction(m_state.forNode(node.child1()).m_type)) {
+            JSValueOperand op1(this, node.child1());
+            JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, op1.gpr(), GPRInfo::tagTypeNumberRegister);
+            speculationCheck(
+                BadType, JSValueRegs(op1.gpr()), node.child1().index(),
+                m_jit.branchTestPtr(MacroAssembler::Zero, op1.gpr(), GPRInfo::tagTypeNumberRegister));
+            isInteger.link(&m_jit);
+        }
+        noResult(m_compileIndex);
+        break;
+    }
 
     case ValueAdd:
     case ArithAdd: