DFG does not correctly handle exceptions caught in the LLInt
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2012 19:45:20 +0000 (19:45 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2012 19:45:20 +0000 (19:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=87885

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Make the DFG use genericThrow, rather than reimplementing a small portion of it.
Also make the LLInt slow paths validate that their PC is correct.

* dfg/DFGOperations.cpp:
* llint/LLIntSlowPaths.cpp:
(LLInt):

LayoutTests:

Pile of code to convince the DFG to throw an exception that ends up being caught
in the LLInt

* fast/js/exception-propagate-from-dfg-to-llint-expected.txt: Added.
* fast/js/exception-propagate-from-dfg-to-llint.html: Added.
* fast/js/script-tests/exception-propagate-from-dfg-to-llint.js: Added.
(o.toString):
(h):
(g):
(f1):
(f2):

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

LayoutTests/ChangeLog
LayoutTests/fast/js/exception-propagate-from-dfg-to-llint-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/exception-propagate-from-dfg-to-llint.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/exception-propagate-from-dfg-to-llint.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

index a03bd9e..9872363 100644 (file)
@@ -1,3 +1,22 @@
+2012-05-30  Oliver Hunt  <oliver@apple.com>
+
+        DFG does not correctly handle exceptions caught in the LLInt
+        https://bugs.webkit.org/show_bug.cgi?id=87885
+
+        Reviewed by Filip Pizlo.
+
+        Pile of code to convince the DFG to throw an exception that ends up being caught
+        in the LLInt
+
+        * fast/js/exception-propagate-from-dfg-to-llint-expected.txt: Added.
+        * fast/js/exception-propagate-from-dfg-to-llint.html: Added.
+        * fast/js/script-tests/exception-propagate-from-dfg-to-llint.js: Added.
+        (o.toString):
+        (h):
+        (g):
+        (f1):
+        (f2):
+
 2012-05-30  Ulan Degenbaev  <ulan@chromium.org>
 
         [v8] Crash after redefining setter on typed array to a number
diff --git a/LayoutTests/fast/js/exception-propagate-from-dfg-to-llint-expected.txt b/LayoutTests/fast/js/exception-propagate-from-dfg-to-llint-expected.txt
new file mode 100644 (file)
index 0000000..11ff210
--- /dev/null
@@ -0,0 +1,10 @@
+Ensures that we pass exceptions to the correct codeblock when throwing from the DFG to the LLInt.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Caught exception in correct codeblock
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/exception-propagate-from-dfg-to-llint.html b/LayoutTests/fast/js/exception-propagate-from-dfg-to-llint.html
new file mode 100644 (file)
index 0000000..7132f81
--- /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/exception-propagate-from-dfg-to-llint.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/exception-propagate-from-dfg-to-llint.js b/LayoutTests/fast/js/script-tests/exception-propagate-from-dfg-to-llint.js
new file mode 100644 (file)
index 0000000..75e6049
--- /dev/null
@@ -0,0 +1,187 @@
+description("Ensures that we pass exceptions to the correct codeblock when throwing from the DFG to the LLInt.");
+var o = {
+    toString: function() { if (shouldThrow) throw {}; return ""; }
+};
+
+var shouldThrow = false;
+function h(o) {
+    return String(o);
+}
+
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+try { shouldThrow = !shouldThrow; h(o); } catch (e) {}
+
+
+function g() {
+    with({})
+        h(o);
+}
+
+function f1() {
+    try {
+        g();
+    } catch (e) {
+        testFailed("Caught exception in wrong codeblock");
+    }
+}
+
+function f2() {
+    try {
+        g();
+    } catch (e) {
+        testPassed("Caught exception in correct codeblock");
+    }
+}
+
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+f1();
+shouldThrow = true;
+f2();
+var successfullyParsed = true;
index 5c9d766..0ceb64a 100644 (file)
@@ -1,3 +1,17 @@
+2012-05-30  Oliver Hunt  <oliver@apple.com>
+
+        DFG does not correctly handle exceptions caught in the LLInt
+        https://bugs.webkit.org/show_bug.cgi?id=87885
+
+        Reviewed by Filip Pizlo.
+
+        Make the DFG use genericThrow, rather than reimplementing a small portion of it.
+        Also make the LLInt slow paths validate that their PC is correct.
+
+        * dfg/DFGOperations.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        (LLInt):
+
 2012-05-29  Filip Pizlo  <fpizlo@apple.com>
 
         DFG CFA should infer types and values of captured variables
index f95b993..b5ac460 100644 (file)
@@ -34,6 +34,7 @@
 #include "GetterSetter.h"
 #include <wtf/InlineASM.h>
 #include "Interpreter.h"
+#include "JITExceptions.h"
 #include "JSActivation.h"
 #include "JSGlobalData.h"
 #include "JSStaticScopeObject.h"
@@ -1149,35 +1150,31 @@ DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
-    
+
     JSValue exceptionValue = exec->exception();
     ASSERT(exceptionValue);
-
+    
     unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex);
-    HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
-
-    void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
-    ASSERT(catchRoutine);
-    return dfgHandlerEncoded(exec, catchRoutine);
+    ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, vPCIndex);
+    ASSERT(handler.catchRoutine);
+    return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
 }
 
 DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
-    
+
     JSValue exceptionValue = exec->exception();
     ASSERT(exceptionValue);
     
     CodeOrigin codeOrigin = stubInfo->codeOrigin;
     while (codeOrigin.inlineCallFrame)
         codeOrigin = codeOrigin.inlineCallFrame->caller;
-
-    HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, codeOrigin.bytecodeIndex);
-
-    void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
-    ASSERT(catchRoutine);
-    return dfgHandlerEncoded(exec, catchRoutine);
+    
+    ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, codeOrigin.bytecodeIndex);
+    ASSERT(handler.catchRoutine);
+    return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
 }
 
 double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
index 5cba5ea..b13e84b 100644 (file)
@@ -53,8 +53,16 @@ namespace JSC { namespace LLInt {
     JSGlobalData& globalData = exec->globalData();      \
     NativeCallFrameTracer tracer(&globalData, exec)
 
-#define LLINT_SET_PC_FOR_STUBS() \
-    exec->setCurrentVPC(pc + 1)
+#ifndef NDEBUG
+#define LLINT_SET_PC_FOR_STUBS() do { \
+        exec->codeBlock()->bytecodeOffset(pc); \
+        exec->setCurrentVPC(pc + 1); \
+    } while (false)
+#else
+#define LLINT_SET_PC_FOR_STUBS() do { \
+        exec->setCurrentVPC(pc + 1); \
+    } while (false)
+#endif
 
 #define LLINT_BEGIN()                           \
     LLINT_BEGIN_NO_SET_PC();                    \