Source/JavaScriptCore: Add LLINT and baseline JIT support for timing out scripts.
https://bugs.webkit.org/show_bug.cgi?id=114577.

Reviewed by Geoffrey Garen.

Introduces the new Watchdog class which is used to track script
execution time, and initiate script termination if needed.

* API/JSContextRef.cpp:
(internalScriptTimeoutCallback):
(JSContextGroupSetExecutionTimeLimit):
(JSContextGroupClearExecutionTimeLimit):
* API/JSContextRefPrivate.h:
- Added new script execution time limit APIs.
* API/tests/testapi.c:
(currentCPUTime):
(shouldTerminateCallback):
(cancelTerminateCallback):
(extendTerminateCallback):
(main):
- Added new API tests for script execution time limit.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitLoopHint):
- loop hints are needed for the llint as well. Hence, it will be
  emitted unconditionally.
* interpreter/Interpreter.cpp:
(JSC::Interpreter::addStackTraceIfNecessary):
(JSC::Interpreter::throwException):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
- Added checks for script termination before entering script code.
* jit/JIT.cpp:
(JSC::JIT::emitWatchdogTimerCheck):
* jit/JIT.h:
(JSC::JIT::emit_op_loop_hint):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION(void, handle_watchdog_timer)):
* jit/JITStubs.h:
* llint/LLIntExceptions.cpp:
(JSC::LLInt::doThrow):
- Factored out some common code from returnToThrow() and callToThrow().
(JSC::LLInt::returnToThrow):
(JSC::LLInt::callToThrow):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer)):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ExceptionHelpers.cpp:
(JSC::throwTerminatedExecutionException):
- Also removed the now unused InterruptedExecutionException.
* runtime/ExceptionHelpers.h:
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h:
- Added watchdog, and removed the now obsolete Terminator.
* runtime/Terminator.h: Removed.
* runtime/Watchdog.cpp: Added.
(JSC::Watchdog::Watchdog):
(JSC::Watchdog::~Watchdog):
(JSC::Watchdog::setTimeLimit):
(JSC::Watchdog::didFire):
(JSC::Watchdog::isEnabled):
(JSC::Watchdog::fire):
(JSC::Watchdog::arm):
(JSC::Watchdog::disarm):
(JSC::Watchdog::startCountdownIfNeeded):
(JSC::Watchdog::startCountdown):
(JSC::Watchdog::stopCountdown):
(JSC::Watchdog::Scope::Scope):
(JSC::Watchdog::Scope::~Scope):
* runtime/Watchdog.h: Added.
(Watchdog):
(JSC::Watchdog::didFire):
(JSC::Watchdog::timerDidFireAddress):
(JSC::Watchdog::isArmed):
(Watchdog::Scope):
* runtime/WatchdogMac.cpp: Added.
(JSC::Watchdog::initTimer):
(JSC::Watchdog::destroyTimer):
(JSC::Watchdog::startTimer):
(JSC::Watchdog::stopTimer):
* runtime/WatchdogNone.cpp: Added.
(JSC::Watchdog::initTimer):
(JSC::Watchdog::destroyTimer):
(JSC::Watchdog::startTimer):
(JSC::Watchdog::stopTimer):

Source/WebCore: Add LLINT and baseline JIT support for timing out scripts.
https://bugs.webkit.org/show_bug.cgi?id=114577.

Reviewed by Geoffrey Garen.

Replaced use of the obsolete JSGlobalData.terminator methods with the
JSGlobalData.watchdog equivalents.

* bindings/js/JSEventListener.cpp:
(WebCore::JSEventListener::handleEvent):
* bindings/js/SerializedScriptValue.cpp:
(WebCore::SerializedScriptValue::maybeThrowExceptionIfSerializationFailed):
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::evaluate):
(WebCore::WorkerScriptController::scheduleExecutionTermination):
(WebCore::WorkerScriptController::isExecutionTerminating):

Source/WTF: Added currentCPUTime() and currentCPUTimeMS().
https://bugs.webkit.org/show_bug.cgi?id=114577.

Reviewed by Geoffrey Garen.

The currentCPUTime() implementation came from the old TimeoutChecker.cpp.

* wtf/CurrentTime.cpp:
(WTF::currentCPUTime):
(WTF::currentCPUTimeMS):
* wtf/CurrentTime.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@148639 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/API/JSContextRef.cpp b/Source/JavaScriptCore/API/JSContextRef.cpp
index bc21876..c59a00a 100644
--- a/Source/JavaScriptCore/API/JSContextRef.cpp
+++ b/Source/JavaScriptCore/API/JSContextRef.cpp
@@ -79,6 +79,30 @@
     wtfThreadData().setCurrentIdentifierTable(savedIdentifierTable);
 }
 
+static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, void* callbackData)
+{
+    JSShouldTerminateCallback callback = reinterpret_cast<JSShouldTerminateCallback>(callbackPtr);
+    JSContextRef contextRef = toRef(exec);
+    return callback(contextRef, callbackData);
+}
+
+void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData)
+{
+    JSGlobalData& globalData = *toJS(group);
+    APIEntryShim entryShim(&globalData);
+    Watchdog& watchdog = globalData.watchdog;
+    void* callbackPtr = reinterpret_cast<void*>(callback);
+    watchdog.setTimeLimit(globalData, limit, internalScriptTimeoutCallback, callbackPtr, callbackData);
+}
+
+void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group)
+{
+    JSGlobalData& globalData = *toJS(group);
+    APIEntryShim entryShim(&globalData);
+    Watchdog& watchdog = globalData.watchdog;
+    watchdog.setTimeLimit(globalData, std::numeric_limits<double>::infinity());
+}
+
 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.
 
 JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass)
diff --git a/Source/JavaScriptCore/API/JSContextRefPrivate.h b/Source/JavaScriptCore/API/JSContextRefPrivate.h
index 4f77aea..8d7684a 100644
--- a/Source/JavaScriptCore/API/JSContextRefPrivate.h
+++ b/Source/JavaScriptCore/API/JSContextRefPrivate.h
@@ -55,6 +55,54 @@
 */
 JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) AVAILABLE_IN_WEBKIT_VERSION_4_0;
     
+
+/*! 
+@typedef JSShouldTerminateCallback
+@abstract The callback invoked when script execution has exceeded the allowed
+ time limit previously specified via JSContextGroupSetExecutionTimeLimit.
+@param ctx The execution context to use.
+@param context User specified context data previously passed to
+ JSContextGroupSetExecutionTimeLimit.
+@discussion If you named your function Callback, you would declare it like this:
+
+ bool Callback(JSContextRef ctx, void* context);
+
+ If you return true, the timed out script will terminate.
+ If you return false, the script will run for another period of the allowed
+ time limit specified via JSContextGroupSetExecutionTimeLimit.
+
+ Within this callback function, you may call JSContextGroupSetExecutionTimeLimit
+ to set a new time limit, or JSContextGroupClearExecutionTimeLimit to cancel the
+ timeout.
+*/
+typedef bool
+(*JSShouldTerminateCallback) (JSContextRef ctx, void* context);
+
+/*!
+@function
+@abstract Sets the script execution time limit.
+@param group The JavaScript context group that this time limit applies to.
+@param limit The time limit of allowed script execution time in seconds.
+@param callback The callback function that will be invoked when the time limit
+ has been reached. This will give you a chance to decide if you want to
+ terminate the script or not. If you pass a NULL callback, the script will be
+ terminated unconditionally when the time limit has been reached.
+@param context User data that you can provide to be passed back to you
+ in your callback.
+
+ In order to guarantee that the execution time limit will take effect, you will
+ need to call JSContextGroupSetExecutionTimeLimit before you start executing
+ any scripts.
+*/
+JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef, double limit, JSShouldTerminateCallback, void* context) AVAILABLE_IN_WEBKIT_VERSION_4_0;
+
+/*!
+@function
+@abstract Clears the script execution time limit.
+@param group The JavaScript context group that the time limit is cleared on.
+*/
+JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef) AVAILABLE_IN_WEBKIT_VERSION_4_0;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c
index ac61f3a..f286a81 100644
--- a/Source/JavaScriptCore/API/tests/testapi.c
+++ b/Source/JavaScriptCore/API/tests/testapi.c
@@ -33,6 +33,12 @@
 #include <wtf/Assertions.h>
 #include <wtf/UnusedParam.h>
 
+#if PLATFORM(MAC) || PLATFORM(IOS)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#endif
+
 #if OS(WINDOWS)
 #include <windows.h>
 #endif
@@ -1045,6 +1051,56 @@
     val.name = "something";
 }
 
+#if PLATFORM(MAC) || PLATFORM(IOS)
+static double currentCPUTime()
+{
+    mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
+    thread_basic_info_data_t info;
+
+    /* Get thread information */
+    mach_port_t threadPort = mach_thread_self();
+    thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount);
+    mach_port_deallocate(mach_task_self(), threadPort);
+    
+    double time = info.user_time.seconds + info.user_time.microseconds / 1000000.;
+    time += info.system_time.seconds + info.system_time.microseconds / 1000000.;
+    
+    return time;
+}
+
+bool shouldTerminateCallbackWasCalled = false;
+static bool shouldTerminateCallback(JSContextRef ctx, void* context)
+{
+    UNUSED_PARAM(ctx);
+    UNUSED_PARAM(context);
+    shouldTerminateCallbackWasCalled = true;
+    return true;
+}
+
+bool cancelTerminateCallbackWasCalled = false;
+static bool cancelTerminateCallback(JSContextRef ctx, void* context)
+{
+    UNUSED_PARAM(ctx);
+    UNUSED_PARAM(context);
+    cancelTerminateCallbackWasCalled = true;
+    return false;
+}
+
+int extendTerminateCallbackCalled = 0;
+static bool extendTerminateCallback(JSContextRef ctx, void* context)
+{
+    UNUSED_PARAM(context);
+    extendTerminateCallbackCalled++;
+    if (extendTerminateCallbackCalled == 1) {
+        JSContextGroupRef contextGroup = JSContextGetGroup(ctx);
+        JSContextGroupSetExecutionTimeLimit(contextGroup, 2, extendTerminateCallback, 0);
+        return false;
+    }
+    return true;
+}
+#endif /* PLATFORM(MAC) || PLATFORM(IOS) */
+
+
 int main(int argc, char* argv[])
 {
 #if OS(WINDOWS)
@@ -1692,6 +1748,95 @@
         free(scriptUTF8);
     }
 
+#if PLATFORM(MAC) || PLATFORM(IOS)
+    /* Test script timeout: */
+    JSContextGroupSetExecutionTimeLimit(contextGroup, 1, shouldTerminateCallback, 0);
+    {
+        const char* loopForeverScript = "startTime = Date.now(); try { while (true) { if (Date.now() - startTime > 5000) break; } } catch(e) { }";
+        JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
+        double startTime;
+        double endTime;
+        exception = NULL;
+        startTime = currentCPUTime();
+        v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
+        endTime = currentCPUTime();
+
+        if (((endTime - startTime) < 2) && shouldTerminateCallbackWasCalled)
+            printf("PASS: script timed out as expected.\n");
+        else {
+            if (!((endTime - startTime) < 2))
+                printf("FAIL: script did not timed out as expected.\n");
+            if (!shouldTerminateCallbackWasCalled)
+                printf("FAIL: script timeout callback was not called.\n");
+            failed = true;
+        }
+
+        if (exception)
+            printf("PASS: TerminationExecutionException was not catchable.\n");
+        else {
+            printf("FAIL: TerminationExecutionException was caught.\n");
+            failed = true;
+        }
+    }
+
+    /* Test script timeout cancellation: */
+    JSContextGroupSetExecutionTimeLimit(contextGroup, 1, cancelTerminateCallback, 0);
+    {
+        const char* loopForeverScript = "startTime = Date.now(); try { while (true) { if (Date.now() - startTime > 5000) break; } } catch(e) { }";
+        JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
+        double startTime;
+        double endTime;
+        exception = NULL;
+        startTime = currentCPUTime();
+        v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
+        endTime = currentCPUTime();
+
+        if (((endTime - startTime) >= 2) && cancelTerminateCallbackWasCalled && !exception)
+            printf("PASS: script timeout was cancelled as expected.\n");
+        else {
+            if (((endTime - startTime) < 2) || exception)
+                printf("FAIL: script timeout was not cancelled.\n");
+            if (!cancelTerminateCallbackWasCalled)
+                printf("FAIL: script timeout callback was not called.\n");
+            failed = true;
+        }
+    }
+
+    /* Test script timeout extension: */
+    JSContextGroupSetExecutionTimeLimit(contextGroup, 1, extendTerminateCallback, 0);
+    {
+        const char* loopForeverScript = "startTime = Date.now(); try { while (true) { if (Date.now() - startTime > 5000) break; } } catch(e) { }";
+        JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
+        double startTime;
+        double endTime;
+        double deltaTime;
+        exception = NULL;
+        startTime = currentCPUTime();
+        v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception);
+        endTime = currentCPUTime();
+        deltaTime = endTime - startTime;
+
+        if ((deltaTime >= 3) && (deltaTime < 5) && (extendTerminateCallbackCalled == 2) && exception)
+            printf("PASS: script timeout was extended as expected.\n");
+        else {
+            if (deltaTime < 2)
+                printf("FAIL: script timeout was not extended as expected.\n");
+            else if (deltaTime >= 5)
+                printf("FAIL: script did not timeout.\n");
+
+            if (extendTerminateCallbackCalled < 1)
+                printf("FAIL: script timeout callback was not called.\n");
+            if (extendTerminateCallbackCalled < 2)
+                printf("FAIL: script timeout callback was not called after timeout extension.\n");
+
+            if (!exception)
+                printf("FAIL: TerminationExecutionException was caught during timeout extension test.\n");
+
+            failed = true;
+        }
+    }
+#endif /* PLATFORM(MAC) || PLATFORM(IOS) */
+
     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected
     function = NULL;
     v = NULL;
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index faa02f5..d85c8d6 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -305,6 +305,8 @@
     runtime/StructureRareData.cpp
     runtime/StructureChain.cpp
     runtime/SymbolTable.cpp
+    runtime/Watchdog.cpp
+    runtime/WatchdogNone.cpp
 
     tools/CodeProfile.cpp
     tools/CodeProfiling.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 0d9de1c..43e817c 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,102 @@
+2013-04-17  Mark Lam  <mark.lam@apple.com>
+
+        Add LLINT and baseline JIT support for timing out scripts.
+        https://bugs.webkit.org/show_bug.cgi?id=114577.
+
+        Reviewed by Geoffrey Garen.
+
+        Introduces the new Watchdog class which is used to track script
+        execution time, and initiate script termination if needed.
+
+        * API/JSContextRef.cpp:
+        (internalScriptTimeoutCallback):
+        (JSContextGroupSetExecutionTimeLimit):
+        (JSContextGroupClearExecutionTimeLimit):
+        * API/JSContextRefPrivate.h:
+        - Added new script execution time limit APIs.
+        * API/tests/testapi.c:
+        (currentCPUTime):
+        (shouldTerminateCallback):
+        (cancelTerminateCallback):
+        (extendTerminateCallback):
+        (main):
+        - Added new API tests for script execution time limit.
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitLoopHint):
+        - loop hints are needed for the llint as well. Hence, it will be
+          emitted unconditionally.
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::addStackTraceIfNecessary):
+        (JSC::Interpreter::throwException):
+        (JSC::Interpreter::execute):
+        (JSC::Interpreter::executeCall):
+        (JSC::Interpreter::executeConstruct):
+        - Added checks for script termination before entering script code.
+        * jit/JIT.cpp:
+        (JSC::JIT::emitWatchdogTimerCheck):
+        * jit/JIT.h:
+        (JSC::JIT::emit_op_loop_hint):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION(void, handle_watchdog_timer)):
+        * jit/JITStubs.h:
+        * llint/LLIntExceptions.cpp:
+        (JSC::LLInt::doThrow):
+        - Factored out some common code from returnToThrow() and callToThrow().
+        (JSC::LLInt::returnToThrow):
+        (JSC::LLInt::callToThrow):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer)):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::throwTerminatedExecutionException):
+        - Also removed the now unused InterruptedExecutionException.
+        * runtime/ExceptionHelpers.h:
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        * runtime/JSGlobalData.h:
+        - Added watchdog, and removed the now obsolete Terminator.
+        * runtime/Terminator.h: Removed.
+        * runtime/Watchdog.cpp: Added.
+        (JSC::Watchdog::Watchdog):
+        (JSC::Watchdog::~Watchdog):
+        (JSC::Watchdog::setTimeLimit):
+        (JSC::Watchdog::didFire):
+        (JSC::Watchdog::isEnabled):
+        (JSC::Watchdog::fire):
+        (JSC::Watchdog::arm):
+        (JSC::Watchdog::disarm):
+        (JSC::Watchdog::startCountdownIfNeeded):
+        (JSC::Watchdog::startCountdown):
+        (JSC::Watchdog::stopCountdown):
+        (JSC::Watchdog::Scope::Scope):
+        (JSC::Watchdog::Scope::~Scope):
+        * runtime/Watchdog.h: Added.
+        (Watchdog):
+        (JSC::Watchdog::didFire):
+        (JSC::Watchdog::timerDidFireAddress):
+        (JSC::Watchdog::isArmed):
+        (Watchdog::Scope):
+        * runtime/WatchdogMac.cpp: Added.
+        (JSC::Watchdog::initTimer):
+        (JSC::Watchdog::destroyTimer):
+        (JSC::Watchdog::startTimer):
+        (JSC::Watchdog::stopTimer):
+        * runtime/WatchdogNone.cpp: Added.
+        (JSC::Watchdog::initTimer):
+        (JSC::Watchdog::destroyTimer):
+        (JSC::Watchdog::startTimer):
+        (JSC::Watchdog::stopTimer):
+
 2013-04-14  Roger Fong  <roger_fong@apple.com>
 
         Unreviewed. VS2010 Windows build fix.
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 8fc4c74..8cc9dc1 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -782,10 +782,12 @@
 	Source/JavaScriptCore/runtime/StructureTransitionTable.h \
 	Source/JavaScriptCore/runtime/SymbolTable.cpp \
 	Source/JavaScriptCore/runtime/SymbolTable.h \
-	Source/JavaScriptCore/runtime/Terminator.h \
 	Source/JavaScriptCore/runtime/Tracing.h \
 	Source/JavaScriptCore/runtime/TypedArrayDescriptor.h \
 	Source/JavaScriptCore/runtime/Uint16WithFraction.h \
+	Source/JavaScriptCore/runtime/Watchdog.cpp \
+	Source/JavaScriptCore/runtime/Watchdog.h \
+	Source/JavaScriptCore/runtime/WatchdogNone.cpp \
 	Source/JavaScriptCore/runtime/WeakGCMap.h \
 	Source/JavaScriptCore/runtime/WeakRandom.h \
 	Source/JavaScriptCore/runtime/WriteBarrier.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index 08cdd38..6bb0374 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1370,11 +1370,19 @@
 				>
 			</File>
 			<File
-				RelativePath="..\..\runtime\Terminator.h"
+				RelativePath="..\..\runtime\TypedArrayDescriptor.h"
 				>
 			</File>
 			<File
-				RelativePath="..\..\runtime\TypedArrayDescriptor.h"
+				RelativePath="..\..\runtime\Watchdog.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\runtime\Watchdog.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\runtime\WatchdogNone.cpp"
 				>
 			</File>
 			<File
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 1e74b87..f4c630f 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -370,6 +370,8 @@
     <ClCompile Include="..\runtime\StructureChain.cpp" />

     <ClCompile Include="..\runtime\StructureRareData.cpp" />

     <ClCompile Include="..\runtime\SymbolTable.cpp" />

+    <ClCompile Include="..\runtime\Watchdog.cpp" />

+    <ClCompile Include="..\runtime\WatchdogNone.cpp" />

     <ClCompile Include="..\tools\CodeProfile.cpp" />

     <ClCompile Include="..\tools\CodeProfiling.cpp" />

     <ClCompile Include="..\yarr\YarrCanonicalizeUCS2.cpp" />

@@ -752,10 +754,10 @@
     <ClInclude Include="..\runtime\StructureRareDataInlines.h" />

     <ClInclude Include="..\runtime\StructureTransitionTable.h" />

     <ClInclude Include="..\runtime\SymbolTable.h" />

-    <ClInclude Include="..\runtime\Terminator.h" />

     <ClInclude Include="..\runtime\Tracing.h" />

     <ClInclude Include="..\runtime\TypedArrayDescriptor.h" />

     <ClInclude Include="..\runtime\Uint16WithFraction.h" />

+    <ClInclude Include="..\runtime\Watchdog.h" />

     <ClInclude Include="..\runtime\WeakGCMap.h" />

     <ClInclude Include="..\runtime\WeakRandom.h" />

     <ClInclude Include="..\runtime\WriteBarrier.h" />

diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
index 153f046..bb5a67e 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
@@ -717,6 +717,12 @@
     <ClCompile Include="..\runtime\SymbolTable.cpp">

       <Filter>runtime</Filter>

     </ClCompile>

+    <ClCompile Include="..\runtime\Watchdog.cpp">

+      <Filter>runtime</Filter>

+    </ClCompile>

+    <ClCompile Include="..\runtime\WatchdogNone.cpp">

+      <Filter>runtime</Filter>

+    </ClCompile>

     <ClCompile Include="..\tools\CodeProfile.cpp">

       <Filter>tools</Filter>

     </ClCompile>

@@ -1790,9 +1796,6 @@
     <ClInclude Include="..\runtime\SymbolTable.h">

       <Filter>runtime</Filter>

     </ClInclude>

-    <ClInclude Include="..\runtime\Terminator.h">

-      <Filter>runtime</Filter>

-    </ClInclude>

     <ClInclude Include="..\runtime\Tracing.h">

       <Filter>runtime</Filter>

     </ClInclude>

@@ -1802,6 +1805,9 @@
     <ClInclude Include="..\runtime\Uint16WithFraction.h">

       <Filter>runtime</Filter>

     </ClInclude>

+    <ClInclude Include="..\runtime\Watchdog.h">

+      <Filter>runtime</Filter>

+    </ClInclude>

     <ClInclude Include="..\runtime\WeakGCMap.h">

       <Filter>runtime</Filter>

     </ClInclude>

diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 82da87c..5326a0e 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -660,7 +660,6 @@
 		969A07990ED1D3AE00F1F681 /* Instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07930ED1D3AE00F1F681 /* Instruction.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		969A079A0ED1D3AE00F1F681 /* Opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 969A07940ED1D3AE00F1F681 /* Opcode.cpp */; };
 		969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07950ED1D3AE00F1F681 /* Opcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		971EDEA61169E0D3005E4262 /* Terminator.h in Headers */ = {isa = PBXBuildFile; fileRef = 97F6903A1169DF7F00A6BB46 /* Terminator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		978801401471AD920041B016 /* JSDateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9788FC221471AD0C0068CE2D /* JSDateMath.cpp */; };
 		978801411471AD920041B016 /* JSDateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9788FC231471AD0C0068CE2D /* JSDateMath.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1712B3A11C7B212007A5315 /* RegExpCache.cpp */; };
@@ -871,6 +870,9 @@
 		FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */; };
 		FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4A331E15BD2E07006F54F3 /* VMInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = FED287B115EC9A5700DA8161 /* LLIntOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */; };
+		FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); };};
+		FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -1582,7 +1584,6 @@
 		969A09220ED1E09C00F1F681 /* Completion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Completion.cpp; sourceTree = "<group>"; };
 		9788FC221471AD0C0068CE2D /* JSDateMath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDateMath.cpp; sourceTree = "<group>"; };
 		9788FC231471AD0C0068CE2D /* JSDateMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDateMath.h; sourceTree = "<group>"; };
-		97F6903A1169DF7F00A6BB46 /* Terminator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Terminator.h; sourceTree = "<group>"; };
 		A1712B3A11C7B212007A5315 /* RegExpCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExpCache.cpp; sourceTree = "<group>"; };
 		A1712B3E11C7B228007A5315 /* RegExpCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpCache.h; sourceTree = "<group>"; };
 		A1712B4011C7B235007A5315 /* RegExpKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpKey.h; sourceTree = "<group>"; };
@@ -1813,6 +1814,9 @@
 		FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = "<group>"; };
 		FE4A331E15BD2E07006F54F3 /* VMInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMInspector.h; sourceTree = "<group>"; };
 		FED287B115EC9A5700DA8161 /* LLIntOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntOpcode.h; path = llint/LLIntOpcode.h; sourceTree = "<group>"; };
+		FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchdog.cpp; sourceTree = "<group>"; };
+		FED94F2C171E3E2300BE77A4 /* Watchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchdog.h; sourceTree = "<group>"; };
+		FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WatchdogMac.cpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -2594,11 +2598,13 @@
 				BC9041470EB9250900FE26FA /* StructureTransitionTable.h */,
 				0F919D2715856770004A4E7D /* SymbolTable.cpp */,
 				14A396A60CD2933100B5B4FF /* SymbolTable.h */,
-				97F6903A1169DF7F00A6BB46 /* Terminator.h */,
 				5D53726D0E1C546B0021E549 /* Tracing.d */,
 				5D53726E0E1C54880021E549 /* Tracing.h */,
 				0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */,
 				866739D113BFDE710023D87C /* Uint16WithFraction.h */,
+				FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */,
+				FED94F2C171E3E2300BE77A4 /* Watchdog.h */,
+				FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */,
 				14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
 				1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
 				A7DCB77912E3D90500911940 /* WriteBarrier.h */,
@@ -3094,6 +3100,7 @@
 				0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */,
 				0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */,
 				0F2BDC471522802500CD8910 /* DFGValueRecoveryOverride.h in Headers */,
+				FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */,
 				0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */,
 				0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */,
 				0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */,
@@ -3376,7 +3383,6 @@
 				BC9041480EB9250900FE26FA /* StructureTransitionTable.h in Headers */,
 				BC18C46B0E16F5CD00B34460 /* SymbolTable.h in Headers */,
 				A784A26411D16622005776AC /* SyntaxChecker.h in Headers */,
-				971EDEA61169E0D3005E4262 /* Terminator.h in Headers */,
 				0F572D4F16879FDD00E57FBD /* ThunkGenerator.h in Headers */,
 				A7386556118697B400540279 /* ThunkGenerators.h in Headers */,
 				141448CD13A1783700F5BA1A /* TinyBloomFilter.h in Headers */,
@@ -4023,6 +4029,7 @@
 				0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */,
 				14280841107EC0930013E7B2 /* RegExp.cpp in Sources */,
 				A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */,
+				FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */,
 				8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */,
 				14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */,
 				8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */,
@@ -4060,6 +4067,7 @@
 				0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */,
 				A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
 				FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */,
+				FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */,
 				0FC81516140511B500CFA603 /* VTableSpectrum.cpp in Sources */,
 				0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
 				14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */,
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 300be75..c74bc62 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -324,6 +324,8 @@
     runtime/Structure.cpp \
     runtime/StructureRareData.cpp \
     runtime/SymbolTable.cpp \
+    runtime/Watchdog.cpp \
+    runtime/WatchdogNone.cpp \
     tools/CodeProfile.cpp \
     tools/CodeProfiling.cpp \
     yarr/YarrJIT.cpp \
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index b4a7e9f..206e2c4 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -655,9 +655,7 @@
 
 void BytecodeGenerator::emitLoopHint()
 {
-#if ENABLE(DFG_JIT)
     emitOpcode(op_loop_hint);
-#endif
 }
 
 void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index e955428..2c939b2 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -767,7 +767,7 @@
 
     JSObject* errorObject = asObject(error);
     JSGlobalObject* globalObject = 0;
-    if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error))
+    if (isTerminatedExecutionException(error))
         globalObject = globalData->dynamicGlobalObject;
     else
         globalObject = errorObject->globalObject();
@@ -788,7 +788,7 @@
 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
 {
     CodeBlock* codeBlock = callFrame->codeBlock();
-    bool isInterrupt = false;
+    bool isTermination = false;
 
     ASSERT(!exceptionValue.isEmpty());
     ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
@@ -810,7 +810,7 @@
             addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
         }
 
-        isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception);
+        isTermination = isTerminatedExecutionException(exception);
     } else {
         if (!callFrame->globalData().exceptionStack.size()) {
             Vector<StackFrame> stack;
@@ -827,7 +827,7 @@
 
     // Calculate an exception handler vPC, unwinding call frames as necessary.
     HandlerInfo* handler = 0;
-    while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
+    while (isTermination || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
         if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
             if (LegacyProfiler* profiler = callFrame->globalData().enabledProfiler())
                 profiler->exceptionUnwind(callFrame);
@@ -1030,15 +1030,17 @@
 
     // Execute the code:
     JSValue result;
-    {
+    if (LIKELY(!globalData.watchdog.didFire(newCallFrame))) {
         SamplingTool::CallRecord callRecord(m_sampler.get());
+        Watchdog::Scope watchdogScope(globalData.watchdog);
 
 #if ENABLE(LLINT_C_LOOP)
         result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue);
 #elif ENABLE(JIT)
         result = program->generatedJITCode().execute(&m_stack, newCallFrame, &globalData);
 #endif // ENABLE(JIT)
-    }
+    } else
+        result = throwTerminatedExecutionException(newCallFrame);
 
     if (LegacyProfiler* profiler = globalData.enabledProfiler())
         profiler->didExecute(callFrame, program->sourceURL(), program->lineNo());
@@ -1100,8 +1102,9 @@
         profiler->willExecute(callFrame, function);
 
     JSValue result;
-    {
+    if (LIKELY(!globalData.watchdog.didFire(newCallFrame))) {
         SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall);
+        Watchdog::Scope watchdogScope(globalData.watchdog);
 
         // Execute the code:
         if (isJSCall) {
@@ -1112,7 +1115,8 @@
 #endif // ENABLE(JIT)
         } else
             result = JSValue::decode(callData.native.function(newCallFrame));
-    }
+    } else
+        result = throwTerminatedExecutionException(newCallFrame);
 
     if (LegacyProfiler* profiler = globalData.enabledProfiler())
         profiler->didExecute(callFrame, function);
@@ -1175,8 +1179,9 @@
         profiler->willExecute(callFrame, constructor);
 
     JSValue result;
-    {
+    if (LIKELY(!globalData.watchdog.didFire(newCallFrame))) {
         SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct);
+        Watchdog::Scope watchdogScope(globalData.watchdog);
 
         // Execute the code.
         if (isJSConstruct) {
@@ -1185,10 +1190,10 @@
 #elif ENABLE(JIT)
             result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_stack, newCallFrame, &globalData);
 #endif // ENABLE(JIT)
-        } else {
+        } else
             result = JSValue::decode(constructData.native.function(newCallFrame));
-        }
-    }
+    } else
+        result = throwTerminatedExecutionException(newCallFrame);
 
     if (LegacyProfiler* profiler = globalData.enabledProfiler())
         profiler->didExecute(callFrame, constructor);
@@ -1272,15 +1277,17 @@
 
     // Execute the code:
     JSValue result;
-    {
+    if (LIKELY(!globalData.watchdog.didFire(closure.newCallFrame))) {
         SamplingTool::CallRecord callRecord(m_sampler.get());
-        
+        Watchdog::Scope watchdogScope(globalData.watchdog);
+
 #if ENABLE(LLINT_C_LOOP)
         result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue);
 #elif ENABLE(JIT)
         result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_stack, closure.newCallFrame, &globalData);
 #endif // ENABLE(JIT)
-    }
+    } else
+        result = throwTerminatedExecutionException(closure.newCallFrame);
 
     if (LegacyProfiler* profiler = globalData.enabledProfiler())
         profiler->didExecute(closure.oldCallFrame, closure.function);
@@ -1368,15 +1375,17 @@
 
     // Execute the code:
     JSValue result;
-    {
+    if (LIKELY(!globalData.watchdog.didFire(newCallFrame))) {
         SamplingTool::CallRecord callRecord(m_sampler.get());
-        
+        Watchdog::Scope watchdogScope(globalData.watchdog);
+
 #if ENABLE(LLINT_C_LOOP)
         result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue);
 #elif ENABLE(JIT)
         result = eval->generatedJITCode().execute(&m_stack, newCallFrame, &globalData);
 #endif // ENABLE(JIT)
-    }
+    } else
+        result = throwTerminatedExecutionException(newCallFrame);
 
     if (LegacyProfiler* profiler = globalData.enabledProfiler())
         profiler->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index b83393a..f05eb26 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -118,6 +118,17 @@
 }
 #endif
 
+void JIT::emitWatchdogTimerCheck()
+{
+    if (!m_globalData->watchdog.isEnabled())
+        return;
+
+    Jump skipCheck = branchTest8(Zero, AbsoluteAddress(m_globalData->watchdog.timerDidFireAddress()));
+    JITStubCall stubCall(this, cti_handle_watchdog_timer);
+    stubCall.call();
+    skipCheck.link(this);
+}
+
 #define NEXT_OPCODE(name) \
     m_bytecodeOffset += OPCODE_LENGTH(name); \
     break;
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index d9c4436..e9cd1c8 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -858,7 +858,8 @@
 #else
         void emitOptimizationCheck(OptimizationCheckKind) { }
 #endif
-        
+        void emitWatchdogTimerCheck();
+
 #ifndef NDEBUG
         void printBytecodeOperandTypes(unsigned src1, unsigned src2);
 #endif
@@ -945,6 +946,7 @@
 
     inline void JIT::emit_op_loop_hint(Instruction*)
     {
+        emitWatchdogTimerCheck();
         emitOptimizationCheck(LoopOptimizationCheck);
     }
 
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 1712e5e..c6d48b8 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -1375,6 +1375,18 @@
     return JSValue::encode(result);
 }
 
+DEFINE_STUB_FUNCTION(void, handle_watchdog_timer)
+{
+    STUB_INIT_STACK_FRAME(stackFrame);
+    CallFrame* callFrame = stackFrame.callFrame;
+    JSGlobalData* globalData = stackFrame.globalData;
+    if (UNLIKELY(globalData->watchdog.didFire(callFrame))) {
+        globalData->exception = createTerminatedExecutionException(globalData);
+        VM_THROW_EXCEPTION_AT_END();
+        return;
+    }
+}
+
 DEFINE_STUB_FUNCTION(void*, stack_check)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h
index 5240485..2ea4fe5 100644
--- a/Source/JavaScriptCore/jit/JITStubs.h
+++ b/Source/JavaScriptCore/jit/JITStubs.h
@@ -406,6 +406,7 @@
 int JIT_STUB cti_op_jgreatereq(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 int JIT_STUB cti_op_jtrue(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION) WTF_INTERNAL;
+void JIT_STUB cti_handle_watchdog_timer(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/llint/LLIntExceptions.cpp b/Source/JavaScriptCore/llint/LLIntExceptions.cpp
index 0192070..cc8bd29 100644
--- a/Source/JavaScriptCore/llint/LLIntExceptions.cpp
+++ b/Source/JavaScriptCore/llint/LLIntExceptions.cpp
@@ -65,29 +65,31 @@
     return LLInt::exceptionInstructions();
 }
 
-Instruction* returnToThrow(ExecState* exec, Instruction* pc)
+static void doThrow(ExecState* exec, Instruction* pc)
 {
     JSGlobalData* globalData = &exec->globalData();
     NativeCallFrameTracer tracer(globalData, exec);
-#if LLINT_SLOW_PATH_TRACING
-    dataLog("Throwing exception ", globalData->exception, " (returnToThrow).\n");
-#endif
     fixupPCforExceptionIfNeeded(exec);
     genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin());
-    
+}
+
+Instruction* returnToThrow(ExecState* exec, Instruction* pc)
+{
+#if LLINT_SLOW_PATH_TRACING
+    JSGlobalData* globalData = &exec->globalData();
+    dataLog("Throwing exception ", globalData->exception, " (returnToThrow).\n");
+#endif
+    doThrow(exec, pc);
     return LLInt::exceptionInstructions();
 }
 
 void* callToThrow(ExecState* exec, Instruction* pc)
 {
-    JSGlobalData* globalData = &exec->globalData();
-    NativeCallFrameTracer tracer(globalData, exec);
 #if LLINT_SLOW_PATH_TRACING
+    JSGlobalData* globalData = &exec->globalData();
     dataLog("Throwing exception ", globalData->exception, " (callToThrow).\n");
 #endif
-    fixupPCforExceptionIfNeeded(exec);
-    genericThrow(globalData, exec, globalData->exception, pc - exec->codeBlock()->instructions().begin());
-
+    doThrow(exec, pc);
     return LLInt::getCodePtr(llint_throw_during_call_trampoline);
 }
 
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index eba07a4..efe1792 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -1628,6 +1628,14 @@
         LLINT_THROW(createTypeError(exec, LLINT_OP_C(1).jsValue().toString(exec)->value(exec)));
 }
 
+LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer)
+{
+    LLINT_BEGIN_NO_SET_PC();
+    if (UNLIKELY(globalData.watchdog.didFire(exec)))
+        LLINT_THROW(createTerminatedExecutionException(&globalData));
+    LLINT_RETURN_TWO(0, exec);
+}
+
 LLINT_SLOW_PATH_DECL(slow_path_debug)
 {
     LLINT_BEGIN();
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.h b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
index b373794..b3974f3 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.h
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.h
@@ -204,6 +204,7 @@
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_push_name_scope);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_throw);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_throw_static_error);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_handle_watchdog_timer);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_debug);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_will_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_did_call);
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 4758f12..341b3b6 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -1057,9 +1057,15 @@
 
 _llint_op_loop_hint:
     traceExecution()
+    loadp JITStackFrame::globalData[sp], t1
+    loadb JSGlobalData::watchdog+Watchdog::m_timerDidFire[t1], t0
+    btbnz t0, .handleWatchdogTimer
+.afterWatchdogTimerCheck:
     checkSwitchToJITForLoop()
     dispatch(1)
-
+.handleWatchdogTimer:
+    callWatchdogTimerHandler()
+    jmp .afterWatchdogTimerCheck
 
 _llint_op_switch_string:
     traceExecution()
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 6fe54b3..34fca19 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -185,6 +185,14 @@
     action(t0)
 end
 
+macro callWatchdogTimerHandler()
+    storei PC, ArgumentCount + TagOffset[cfr]
+    cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC)
+    move t1, cfr
+    btpnz t0, _llint_throw_from_slow_path_trampoline
+    loadi ArgumentCount + TagOffset[cfr], PC
+end
+
 macro checkSwitchToJITForLoop()
     checkSwitchToJIT(
         1,
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index d69febf..d3c333f 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -126,6 +126,16 @@
     action(t0)
 end
 
+macro callWatchdogTimerHandler()
+    storei PC, ArgumentCount + TagOffset[cfr]
+    prepareStateForCCall()
+    cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC)
+    move t1, cfr
+    btpnz t0, _llint_throw_from_slow_path_trampoline
+    move t3, PB
+    loadi ArgumentCount + TagOffset[cfr], PC
+end
+
 macro checkSwitchToJITForLoop()
     checkSwitchToJIT(
         1,
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
index 0dd4f07..4e945c0 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -41,33 +41,6 @@
 
 namespace JSC {
 
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(InterruptedExecutionError);
-
-const ClassInfo InterruptedExecutionError::s_info = { "InterruptedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InterruptedExecutionError) };
-
-JSValue InterruptedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint)
-{
-    if (hint == PreferString)
-        return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution exceeded timeout.")));
-    return JSValue(QNaN);
-}
-
-JSObject* createInterruptedExecutionException(JSGlobalData* globalData)
-{
-    return InterruptedExecutionError::create(*globalData);
-}
-
-bool isInterruptedExecutionException(JSObject* object)
-{
-    return object->inherits(&InterruptedExecutionError::s_info);
-}
-
-bool isInterruptedExecutionException(JSValue value)
-{
-    return value.inherits(&InterruptedExecutionError::s_info);
-}
-
-
 ASSERT_HAS_TRIVIAL_DESTRUCTOR(TerminatedExecutionError);
 
 const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) };
@@ -168,4 +141,10 @@
     return throwError(exec, createStackOverflowError(exec));
 }
 
+JSObject* throwTerminatedExecutionException(ExecState* exec)
+{
+    Interpreter::ErrorHandlingMode mode(exec);
+    return throwError(exec, createTerminatedExecutionException(&exec->globalData()));
+}
+
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
index d2daaa0..14aa3b4 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
@@ -33,10 +33,6 @@
 
 namespace JSC {
 
-JS_EXPORT_PRIVATE JSObject* createInterruptedExecutionException(JSGlobalData*);
-bool isInterruptedExecutionException(JSObject*);
-bool isInterruptedExecutionException(JSValue);
-
 JSObject* createTerminatedExecutionException(JSGlobalData*);
 bool isTerminatedExecutionException(JSObject*);
 JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue);
@@ -53,35 +49,9 @@
 
 JSObject* throwOutOfMemoryError(ExecState*);
 JSObject* throwStackOverflowError(ExecState*);
+JSObject* throwTerminatedExecutionException(ExecState*);
 
 
-class InterruptedExecutionError : public JSNonFinalObject {
-private:
-    InterruptedExecutionError(JSGlobalData& globalData)
-        : JSNonFinalObject(globalData, globalData.interruptedExecutionErrorStructure.get())
-    {
-    }
-
-    static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
-
-public:
-    typedef JSNonFinalObject Base;
-
-    static InterruptedExecutionError* create(JSGlobalData& globalData)
-    {
-        InterruptedExecutionError* error = new (NotNull, allocateCell<InterruptedExecutionError>(globalData.heap)) InterruptedExecutionError(globalData);
-        error->finishCreation(globalData);
-        return error;
-    }
-
-    static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
-    {
-        return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
-    }
-
-    static const ClassInfo s_info;
-};
-
 class TerminatedExecutionError : public JSNonFinalObject {
 private:
     TerminatedExecutionError(JSGlobalData& globalData)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index cdc42ab..2e7240b 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -204,7 +204,6 @@
     structureStructure.set(*this, Structure::createStructure(*this));
     structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
     debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
-    interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
     terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
     stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
     notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index efac642..edd067e 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -46,9 +46,9 @@
 #include "PrototypeMap.h"
 #include "SmallStrings.h"
 #include "Strong.h"
-#include "Terminator.h"
 #include "ThunkGenerators.h"
 #include "TypedArrayDescriptor.h"
+#include "Watchdog.h"
 #include "WeakRandom.h"
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/Forward.h>
@@ -211,6 +211,7 @@
         GlobalDataType globalDataType;
         ClientData* clientData;
         ExecState* topCallFrame;
+        Watchdog watchdog;
 
         const HashTable* arrayConstructorTable;
         const HashTable* arrayPrototypeTable;
@@ -233,7 +234,6 @@
         Strong<Structure> structureStructure;
         Strong<Structure> structureRareDataStructure;
         Strong<Structure> debuggerActivationStructure;
-        Strong<Structure> interruptedExecutionErrorStructure;
         Strong<Structure> terminatedExecutionErrorStructure;
         Strong<Structure> stringStructure;
         Strong<Structure> notAnObjectStructure;
@@ -325,8 +325,6 @@
 #endif
         NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor);
 
-        Terminator terminator;
-
         JSValue exception;
         RefCountedArray<StackFrame> exceptionStack;
 
diff --git a/Source/JavaScriptCore/runtime/Terminator.h b/Source/JavaScriptCore/runtime/Terminator.h
deleted file mode 100644
index 6b0f236..0000000
--- a/Source/JavaScriptCore/runtime/Terminator.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Google Inc. ("Google") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Terminator_h
-#define Terminator_h
-
-namespace JSC {
-
-class Terminator {
-public:
-    Terminator() : m_shouldTerminate(false) { }
-
-    void terminateSoon() { m_shouldTerminate = true; }
-    bool shouldTerminate() const { return m_shouldTerminate; }
-
-private:
-    bool m_shouldTerminate;
-};
-
-} // namespace JSC
-
-#endif // Terminator_h
diff --git a/Source/JavaScriptCore/runtime/Watchdog.cpp b/Source/JavaScriptCore/runtime/Watchdog.cpp
new file mode 100644
index 0000000..823904b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Watchdog.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "Watchdog.h"
+
+#include "CallFrame.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+static const double noLimit = std::numeric_limits<double>::infinity();
+
+Watchdog::Watchdog()
+    : m_timerDidFire(false)
+    , m_didFire(false)
+    , m_limit(noLimit)
+    , m_startTime(0)
+    , m_elapsedTime(0)
+    , m_reentryCount(0)
+    , m_isStopped(true)
+    , m_callback(0)
+    , m_callbackData1(0)
+    , m_callbackData2(0)
+{
+    initTimer();
+}
+
+Watchdog::~Watchdog()
+{
+    ASSERT(!isArmed());
+    stopCountdown();
+    destroyTimer();
+}
+
+void Watchdog::setTimeLimit(JSGlobalData& globalData, double limit,
+    ShouldTerminateCallback callback, void* data1, void* data2)
+{
+    bool wasEnabled = isEnabled();
+
+    if (!m_isStopped)
+        stopCountdown();
+
+    m_didFire = false; // Reset the watchdog.
+
+    m_limit = limit;
+    m_callback = callback;
+    m_callbackData1 = data1;
+    m_callbackData2 = data2;
+
+    // If this is the first time that timeout is being enabled, then any
+    // previously JIT compiled code will not have the needed polling checks.
+    // Hence, we need to flush all the pre-existing compiled code.
+    //
+    // However, if the timeout is already enabled, and we're just changing the
+    // timeout value, then any existing JITted code will have the appropriate
+    // polling checks. Hence, there is no need to re-do this flushing.
+    if (!wasEnabled) {
+        // For now, we only support this feature when the DFG JIT is disabled.
+        Options::useDFGJIT() = false;
+
+        // And if we've previously compiled any functions, we need to deopt
+        // them because they don't habe the needed polling checks yet.
+        globalData.releaseExecutableMemory();
+    }
+
+    startCountdownIfNeeded();
+}
+
+bool Watchdog::didFire(ExecState* exec)
+{
+    if (m_didFire)
+        return true;
+
+    if (!m_timerDidFire)
+        return false;
+    m_timerDidFire = false;
+    stopCountdown();
+
+    double currentTime = currentCPUTime();
+    double deltaTime = currentTime - m_startTime;
+    double totalElapsedTime = m_elapsedTime + deltaTime;
+    if (totalElapsedTime > m_limit) {
+        // Case 1: the allowed CPU time has elapsed.
+
+        // If m_callback is not set, then we terminate by default.
+        // Else, we let m_callback decide if we should terminate or not.
+        bool needsTermination = !m_callback
+            || m_callback(exec, m_callbackData1, m_callbackData2);
+        if (needsTermination) {
+            m_didFire = true;
+            return true;
+        }
+
+        // The m_callback may have set a new limit. So, we may need to restart
+        // the countdown.
+        startCountdownIfNeeded();
+
+    } else {
+        // Case 2: the allowed CPU time has NOT elapsed.
+
+        // Tell the timer to alarm us again when it thinks we've reached the
+        // end of the allowed time.
+        double remainingTime = m_limit - totalElapsedTime;
+        m_elapsedTime = totalElapsedTime;
+        m_startTime = currentTime;
+        startCountdown(remainingTime);
+    }
+
+    return false;
+}
+
+bool Watchdog::isEnabled()
+{
+    return (m_limit != noLimit);
+}
+
+void Watchdog::fire()
+{
+    m_didFire = true;
+}
+
+void Watchdog::arm()
+{
+    m_reentryCount++;
+    if (m_reentryCount == 1)
+        startCountdownIfNeeded();
+}
+
+void Watchdog::disarm()
+{
+    ASSERT(m_reentryCount > 0);
+    if (m_reentryCount == 1)
+        stopCountdown();
+    m_reentryCount--;
+}
+
+void Watchdog::startCountdownIfNeeded()
+{
+    if (!m_isStopped)
+        return; // Already started.
+
+    if (!isArmed())
+        return; // Not executing JS script. No need to start.
+
+    if (isEnabled()) {
+        m_elapsedTime = 0;
+        m_startTime = currentCPUTime();
+        startCountdown(m_limit);
+    }
+}
+
+void Watchdog::startCountdown(double limit)
+{
+    ASSERT(m_isStopped);
+    m_isStopped = false;
+    startTimer(limit);
+}
+
+void Watchdog::stopCountdown()
+{
+    if (m_isStopped)
+        return;
+    stopTimer();
+    m_isStopped = true;
+}
+
+Watchdog::Scope::Scope(Watchdog& watchdog)
+    : m_watchdog(watchdog)
+{
+    m_watchdog.arm();
+}
+
+Watchdog::Scope::~Scope()
+{
+    m_watchdog.disarm();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Watchdog.h b/Source/JavaScriptCore/runtime/Watchdog.h
new file mode 100644
index 0000000..4bb18d1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Watchdog.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef Watchdog_h
+#define Watchdog_h
+
+#if PLATFORM(MAC) || PLATFORM(IOS)
+#include <dispatch/dispatch.h>    
+#endif
+
+namespace JSC {
+
+class ExecState;
+class JSGlobalData;
+
+class Watchdog {
+public:
+    class Scope;
+
+    Watchdog();
+    ~Watchdog();
+
+    typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2);
+    void setTimeLimit(JSGlobalData&, double seconds, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0);
+
+    // This version of didFire() will check the elapsed CPU time and call the
+    // callback (if needed) to determine if the watchdog should fire.
+    bool didFire(ExecState*);
+
+    bool isEnabled();
+
+    // This version of didFire() is a more efficient version for when we want
+    // to know if the watchdog has fired in the past, and not whether it should
+    // fire right now.
+    JS_EXPORT_PRIVATE bool didFire() { return m_didFire; }
+    JS_EXPORT_PRIVATE void fire();
+
+    void* timerDidFireAddress() { return &m_timerDidFire; }
+
+private:
+    void arm();
+    void disarm();
+    void startCountdownIfNeeded();
+    void startCountdown(double limit);
+    void stopCountdown();
+    bool isArmed() { return !!m_reentryCount; }
+
+    // Platform specific timer implementation:
+    void initTimer();
+    void destroyTimer();
+    void startTimer(double limit);
+    void stopTimer();
+
+    // m_timerDidFire (above) indicates whether the timer fired. The Watchdog
+    // still needs to check if the allowed CPU time has elapsed. If so, then
+    // the Watchdog fires and m_didFire will be set.
+    // NOTE: m_timerDidFire is only set by the platform specific timer
+    // (probably from another thread) but is only cleared in the script thread.
+    bool m_timerDidFire;
+    bool m_didFire;
+
+    // All time units are in seconds.
+    double m_limit;
+    double m_startTime;
+    double m_elapsedTime;
+
+    int m_reentryCount;
+    bool m_isStopped;
+
+    ShouldTerminateCallback m_callback;
+    void* m_callbackData1;
+    void* m_callbackData2;
+
+#if PLATFORM(MAC) || PLATFORM(IOS)
+    dispatch_queue_t m_queue;
+    dispatch_source_t m_timer;
+#endif
+
+    friend class Watchdog::Scope;
+    friend class LLIntOffsetsExtractor;
+};
+
+class Watchdog::Scope {
+public:
+    Scope(Watchdog&);
+    ~Scope();
+
+private:
+    Watchdog& m_watchdog;
+};
+
+} // namespace JSC
+
+#endif // Watchdog_h
diff --git a/Source/JavaScriptCore/runtime/WatchdogMac.cpp b/Source/JavaScriptCore/runtime/WatchdogMac.cpp
new file mode 100644
index 0000000..ca474df
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WatchdogMac.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "Watchdog.h"
+
+namespace JSC {
+
+void Watchdog::initTimer()
+{
+    m_queue = 0;
+    m_timer = 0;
+}
+
+void Watchdog::destroyTimer()
+{
+    ASSERT(!m_timer);
+    if (m_queue)
+        dispatch_release(m_queue);
+}
+
+void Watchdog::startTimer(double limit)
+{
+    ASSERT(!m_timer);
+    if (!m_queue)
+        m_queue = dispatch_queue_create("jsc.watchdog.queue", 0);
+    m_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_queue);
+
+    dispatch_source_set_timer(m_timer,
+        dispatch_time(DISPATCH_TIME_NOW, limit * NSEC_PER_SEC),
+        DISPATCH_TIME_FOREVER, 0);
+
+    dispatch_source_set_event_handler(m_timer, ^{
+        m_timerDidFire = true;
+    });
+
+    dispatch_resume(m_timer);
+}
+
+void Watchdog::stopTimer()
+{
+    ASSERT(m_queue);
+    dispatch_sync(m_queue, ^{
+        dispatch_source_cancel(m_timer);
+    });
+    dispatch_release(m_timer);
+    m_timer = 0;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/WatchdogNone.cpp b/Source/JavaScriptCore/runtime/WatchdogNone.cpp
new file mode 100644
index 0000000..615314b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WatchdogNone.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "Watchdog.h"
+
+namespace JSC {
+
+// This is a stub for platforms that have not implemented this functionality.
+// In this case, the platform timer here never fires.
+
+void Watchdog::initTimer()
+{
+}
+
+void Watchdog::destroyTimer()
+{
+}
+
+void Watchdog::startTimer(double)
+{
+}
+
+void Watchdog::stopTimer()
+{
+}
+
+} // namespace JSC