Title: [188329] trunk/Source
Revision
188329
Author
[email protected]
Date
2015-08-11 22:56:20 -0700 (Tue, 11 Aug 2015)

Log Message

Implementation _javascript_ watchdog using WTF::WorkQueue.
https://bugs.webkit.org/show_bug.cgi?id=147107

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

How the Watchdog works?
======================

1. When do we start the Watchdog?
   =============================
   The watchdog should only be started if both the following conditions are true:
   1. A time limit has been set.
   2. We have entered the VM.
 
2. CPU time vs Wall Clock time
   ===========================
   Why do we need 2 time deadlines: m_cpuDeadline and m_wallClockDeadline?

   The watchdog uses WorkQueue dispatchAfter() to queue a timer to measure the watchdog time
   limit. WorkQueue timers measure time in monotonic wall clock time. m_wallClockDeadline
   indicates the wall clock time point when the WorkQueue timer is expected to fire.

   The time limit for which we allow JS code to run should be measured in CPU time, which can
   differ from wall clock time.  m_cpuDeadline indicates the CPU time point when the watchdog
   should fire.

   Note: the timer firing is not the same thing as the watchdog firing.  When the timer fires,
   we need to check if m_cpuDeadline has been reached.

   If m_cpuDeadline has been reached, the watchdog is considered to have fired.

   If not, then we have a remaining amount of CPU time, Tremainder, that we should allow JS
   code to continue to run for.  Hence, we need to start a new timer to fire again after
   Tremainder microseconds.
    
   See Watchdog::didFireSlow().

3. Spurious wake ups
   =================
   Because the WorkQueue timer cannot be cancelled, the watchdog needs to ignore stale timers.
   It does this by checking the m_wallClockDeadline.  A wakeup that occurs right after
   m_wallClockDeadline expires is considered to be the wakeup for the active timer.  All other
   wake ups are considered to be spurious and will be ignored.
 
   See Watchdog::didFireSlow().
 
4. Minimizing Timer creation cost
   ==============================
   Conceptually, we could start a new timer every time we start the watchdog. But we can do better
   than this.
 
   In practice, the time limit of a watchdog tends to be long, and the amount of time a watchdog
   stays active tends to be short for well-behaved JS code. The user also tends to re-use the same
   time limit. Consider the following example:
 
       |---|-----|---|----------------|---------|
       t0  t1    t2  t3            t0 + L    t2 + L 

       |<--- T1 --------------------->|
                 |<--- T2 --------------------->|
       |<-- Td ->|                    |<-- Td ->|

   1. The user initializes the watchdog with time limit L.
   2. At t0, we enter the VM to execute JS code, and starts the watchdog timer, T1.
      The timer is set to expire at t0 + L.
   3. At t1, we exit the VM.
   4. At t2, we enter the VM again, and would like to start a new watchdog timer, T2.
         
      However, we can note that the expiration time for T2 would be after the expiration time
      of T1. Specifically, T2 would have expired at Td after T1 expires.
         
      Hence, we can just wait for T1 to expire, and then start a new timer T2' at time t0 + L
      for a period or Td instead.

   Note that didFireSlow() already compensates for time differences between wall clock and CPU time,
   as well as handle spurious wake ups (see note 2 and 3 above).  As a result, didFireSlow() will
   automatically take care of starting a new timer for the difference Td in the example above.
   Instead of starting the new timer T2 and time t2, we just verify that if the active timer, T1's
   expiration is less than T2s, then we are already covered by T1 and there's no need to start T2.

   The benefit:

   1. we minimize the number of timer instances we have queued in the workqueue at the same time
      (ideally only 1 or 0), and use less peak memory usage.

   2. we minimize the frequency of instantiating timer instances. By waiting for the current
      active timer to expire first, on average, we get to start one timer per time limit
      (which is infrequent because time limits tend to be long) instead of one timer per
      VM entry (which tends to be frequent).

   See Watchdog::startTimer().

* API/JSContextRef.cpp:
(createWatchdogIfNeeded):
(JSContextGroupClearExecutionTimeLimit):
- No need to create the watchdog (if not already created) just to clear it.
  If the watchdog is not created yet, then it is effectively cleared.

* API/tests/ExecutionTimeLimitTest.cpp:
(currentCPUTimeAsJSFunctionCallback):
(testExecutionTimeLimit):
(currentCPUTime): Deleted.
* API/tests/testapi.c:
(main):
* _javascript_Core.vcxproj/testapi/testapi.vcxproj:
* _javascript_Core.vcxproj/testapi/testapi.vcxproj.filters:
- Enable watchdog tests for all platforms.

* CMakeLists.txt:
* _javascript_Core.vcxproj/_javascript_Core.vcxproj:
* _javascript_Core.vcxproj/_javascript_Core.vcxproj.filters:
* _javascript_Core.xcodeproj/project.pbxproj:
- Remove now unneeded WatchdogMac.cpp and WatchdogNone.cpp.

* PlatformEfl.cmake:

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGSpeculativeJIT32_64.cpp:
* dfg/DFGSpeculativeJIT64.cpp:
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_loop_hint):
(JSC::JIT::emitSlow_op_loop_hint):
* jit/JITOperations.cpp:
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntSlowPaths.cpp:
* runtime/VM.cpp:
- #include Watchdog.h in these files directly instead of doing it via VM.h.
  These saves us from having to recompile the world when we change Watchdog.h.

* runtime/VM.h:
- See comment in Watchdog::startTimer() below for why the Watchdog needs to be
  thread-safe ref counted.

* runtime/VMEntryScope.cpp:
(JSC::VMEntryScope::VMEntryScope):
(JSC::VMEntryScope::~VMEntryScope):
- We have done away with the WatchdogScope and arming/disarming of the watchdog.
  Instead, the VMEntryScope will inform the watchdog of when we have entered and
  exited the VM.

* runtime/Watchdog.cpp:
(JSC::currentWallClockTime):
(JSC::Watchdog::Watchdog):
(JSC::Watchdog::hasStartedTimer):
(JSC::Watchdog::setTimeLimit):
(JSC::Watchdog::didFireSlow):
(JSC::Watchdog::hasTimeLimit):
(JSC::Watchdog::fire):
(JSC::Watchdog::enteredVM):
(JSC::Watchdog::exitedVM):

(JSC::Watchdog::startTimer):
- The Watchdog is now thread-safe ref counted because the WorkQueue may access it
  (from a different thread) even after the VM shuts down.  We need to keep it
  alive until the WorkQueue callback completes.

  In Watchdog::startTimer(), we'll ref the Watchdog to keep it alive for each
  WorkQueue callback we dispatch.  The callback will deref the Watchdog after it
  is done with it.  This ensures that the Watchdog is kept alive until all
  WorkQueue callbacks are done.

(JSC::Watchdog::stopTimer):
(JSC::Watchdog::~Watchdog): Deleted.
(JSC::Watchdog::didFire): Deleted.
(JSC::Watchdog::isEnabled): Deleted.
(JSC::Watchdog::arm): Deleted.
(JSC::Watchdog::disarm): Deleted.
(JSC::Watchdog::startCountdownIfNeeded): Deleted.
(JSC::Watchdog::startCountdown): Deleted.
(JSC::Watchdog::stopCountdown): Deleted.
* runtime/Watchdog.h:
(JSC::Watchdog::didFire):
(JSC::Watchdog::timerDidFireAddress):
(JSC::Watchdog::isArmed): Deleted.
(JSC::Watchdog::Scope::Scope): Deleted.
(JSC::Watchdog::Scope::~Scope): Deleted.
* runtime/WatchdogMac.cpp:
(JSC::Watchdog::initTimer): Deleted.
(JSC::Watchdog::destroyTimer): Deleted.
(JSC::Watchdog::startTimer): Deleted.
(JSC::Watchdog::stopTimer): Deleted.
* runtime/WatchdogNone.cpp:
(JSC::Watchdog::initTimer): Deleted.
(JSC::Watchdog::destroyTimer): Deleted.
(JSC::Watchdog::startTimer): Deleted.
(JSC::Watchdog::stopTimer): Deleted.

Source/WebCore:

No new tests because we're not introducing any behavior change to WebCore here.
We're only #include'ing Watchdog.h directly instead of going through VM.h.

* ForwardingHeaders/runtime/Watchdog.h: Added.
* PlatformEfl.cmake:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* bindings/js/JSEventListener.cpp:
* bindings/js/WorkerScriptController.cpp:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSContextRef.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/API/JSContextRef.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/API/JSContextRef.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -37,6 +37,7 @@
 #include "JSCInlines.h"
 #include "SourceProvider.h"
 #include "StackVisitor.h"
+#include "Watchdog.h"
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringHash.h>
 
@@ -94,7 +95,7 @@
 static void createWatchdogIfNeeded(VM& vm)
 {
     if (!vm.watchdog) {
-        vm.watchdog = std::make_unique<Watchdog>();
+        vm.watchdog = adoptRef(new Watchdog());
 
         // The LLINT peeks into the Watchdog object directly. In order to do that,
         // the LLINT assumes that the internal shape of a std::unique_ptr is the
@@ -120,9 +121,8 @@
 {
     VM& vm = *toJS(group);
     JSLockHolder locker(&vm);
-    createWatchdogIfNeeded(vm);
-    Watchdog& watchdog = *vm.watchdog;
-    watchdog.setTimeLimit(vm, std::chrono::microseconds::max());
+    if (vm.watchdog)
+        vm.watchdog->setTimeLimit(vm, Watchdog::noTimeLimit);
 }
 
 // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained.

Modified: trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/API/tests/ExecutionTimeLimitTest.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -26,34 +26,15 @@
 #include "config.h"
 #include "ExecutionTimeLimitTest.h"
 
-#if OS(DARWIN)
-
 #include "JSContextRefPrivate.h"
 #include "_javascript_Core.h"
+#include <chrono>
+#include <wtf/CurrentTime.h>
 
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-#include <stdio.h>
-#include <sys/time.h>
+using namespace std::chrono;
 
 static JSGlobalContextRef context = nullptr;
 
-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;
-}
-
 static JSValueRef currentCPUTimeAsJSFunctionCallback(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
     UNUSED_PARAM(functionObject);
@@ -63,7 +44,7 @@
     UNUSED_PARAM(exception);
     
     ASSERT(JSContextGetGlobalContext(ctx) == context);
-    return JSValueMakeNumber(ctx, currentCPUTime());
+    return JSValueMakeNumber(ctx, currentCPUTime().count() / 1000000.);
 }
 
 bool shouldTerminateCallbackWasCalled = false;
@@ -120,18 +101,16 @@
     {
         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
-        double startTime;
-        double endTime;
         exception = nullptr;
         shouldTerminateCallbackWasCalled = false;
-        startTime = currentCPUTime();
+        auto startTime = currentCPUTime();
         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
-        endTime = currentCPUTime();
+        auto endTime = currentCPUTime();
         
-        if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
+        if (((endTime - startTime) < milliseconds(150)) && shouldTerminateCallbackWasCalled)
             printf("PASS: script timed out as expected.\n");
         else {
-            if (!((endTime - startTime) < .150f))
+            if (!((endTime - startTime) < milliseconds(150)))
                 printf("FAIL: script did not time out as expected.\n");
             if (!shouldTerminateCallbackWasCalled)
                 printf("FAIL: script timeout callback was not called.\n");
@@ -149,16 +128,14 @@
     {
         const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }";
         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
-        double startTime;
-        double endTime;
         exception = nullptr;
         shouldTerminateCallbackWasCalled = false;
-        startTime = currentCPUTime();
+        auto startTime = currentCPUTime();
         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
-        endTime = currentCPUTime();
+        auto endTime = currentCPUTime();
         
-        if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) {
-            if (!((endTime - startTime) < .150f))
+        if (((endTime - startTime) >= milliseconds(150)) || !shouldTerminateCallbackWasCalled) {
+            if (!((endTime - startTime) < milliseconds(150)))
                 printf("FAIL: script did not time out as expected.\n");
             if (!shouldTerminateCallbackWasCalled)
                 printf("FAIL: script timeout callback was not called.\n");
@@ -178,17 +155,15 @@
     {
         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
-        double startTime;
-        double endTime;
         exception = nullptr;
-        startTime = currentCPUTime();
+        auto startTime = currentCPUTime();
         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
-        endTime = currentCPUTime();
+        auto endTime = currentCPUTime();
         
-        if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled)
+        if (((endTime - startTime) < milliseconds(150)) && shouldTerminateCallbackWasCalled)
             printf("PASS: script timed out as expected when no callback is specified.\n");
         else {
-            if (!((endTime - startTime) < .150f))
+            if (!((endTime - startTime) < milliseconds(150)))
                 printf("FAIL: script did not time out as expected when no callback is specified.\n");
             failed = true;
         }
@@ -204,17 +179,15 @@
     {
         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } ";
         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
-        double startTime;
-        double endTime;
         exception = nullptr;
-        startTime = currentCPUTime();
+        auto startTime = currentCPUTime();
         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
-        endTime = currentCPUTime();
+        auto endTime = currentCPUTime();
         
-        if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception)
+        if (((endTime - startTime) >= milliseconds(150)) && cancelTerminateCallbackWasCalled && !exception)
             printf("PASS: script timeout was cancelled as expected.\n");
         else {
-            if (((endTime - startTime) < .150) || exception)
+            if (((endTime - startTime) < milliseconds(150)) || exception)
                 printf("FAIL: script timeout was not cancelled.\n");
             if (!cancelTerminateCallbackWasCalled)
                 printf("FAIL: script timeout callback was not called.\n");
@@ -232,21 +205,18 @@
     {
         const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } ";
         JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript);
-        double startTime;
-        double endTime;
-        double deltaTime;
         exception = nullptr;
-        startTime = currentCPUTime();
+        auto startTime = currentCPUTime();
         v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception);
-        endTime = currentCPUTime();
-        deltaTime = endTime - startTime;
+        auto endTime = currentCPUTime();
+        auto deltaTime = endTime - startTime;
         
-        if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception)
+        if ((deltaTime >= milliseconds(300)) && (deltaTime < milliseconds(500)) && (extendTerminateCallbackCalled == 2) && exception)
             printf("PASS: script timeout was extended as expected.\n");
         else {
-            if (deltaTime < .200f)
+            if (deltaTime < milliseconds(200))
                 printf("FAIL: script timeout was not extended as expected.\n");
-            else if (deltaTime >= .500f)
+            else if (deltaTime >= milliseconds(500))
                 printf("FAIL: script did not timeout.\n");
             
             if (extendTerminateCallbackCalled < 1)
@@ -264,5 +234,3 @@
     JSGlobalContextRelease(context);
     return failed;
 }
-
-#endif // OS(DARWIN)

Modified: trunk/Source/_javascript_Core/API/tests/testapi.c (188328 => 188329)


--- trunk/Source/_javascript_Core/API/tests/testapi.c	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/API/tests/testapi.c	2015-08-12 05:56:20 UTC (rev 188329)
@@ -43,9 +43,7 @@
 #include "CustomGlobalObjectClassTest.h"
 #include "GlobalContextWithFinalizerTest.h"
 
-#if OS(DARWIN)
 #include "ExecutionTimeLimitTest.h"
-#endif
 
 #if JSC_OBJC_API_ENABLED
 void testObjectiveCAPI(void);
@@ -1893,9 +1891,7 @@
         JSGlobalContextRelease(context);
     }
 
-#if OS(DARWIN)
     failed = testExecutionTimeLimit() || failed;
-#endif /* OS(DARWIN) */
     failed = testGlobalContextWithFinalizer() || failed;
 
     // Clear out local variables pointing at JSObjectRefs to allow their values to be collected

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (188328 => 188329)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2015-08-12 05:56:20 UTC (rev 188329)
@@ -617,7 +617,6 @@
     runtime/VMEntryScope.cpp
     runtime/VarOffset.cpp
     runtime/Watchdog.cpp
-    runtime/WatchdogNone.cpp
     runtime/WeakMapConstructor.cpp
     runtime/WeakMapData.cpp
     runtime/WeakMapPrototype.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (188328 => 188329)


--- trunk/Source/_javascript_Core/ChangeLog	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,3 +1,197 @@
+2015-08-11  Mark Lam  <[email protected]>
+
+        Implementation _javascript_ watchdog using WTF::WorkQueue.
+        https://bugs.webkit.org/show_bug.cgi?id=147107
+
+        Reviewed by Geoffrey Garen.
+
+        How the Watchdog works?
+        ======================
+
+        1. When do we start the Watchdog?
+           =============================
+           The watchdog should only be started if both the following conditions are true:
+           1. A time limit has been set.
+           2. We have entered the VM.
+ 
+        2. CPU time vs Wall Clock time
+           ===========================
+           Why do we need 2 time deadlines: m_cpuDeadline and m_wallClockDeadline?
+
+           The watchdog uses WorkQueue dispatchAfter() to queue a timer to measure the watchdog time
+           limit. WorkQueue timers measure time in monotonic wall clock time. m_wallClockDeadline
+           indicates the wall clock time point when the WorkQueue timer is expected to fire.
+
+           The time limit for which we allow JS code to run should be measured in CPU time, which can
+           differ from wall clock time.  m_cpuDeadline indicates the CPU time point when the watchdog
+           should fire.
+
+           Note: the timer firing is not the same thing as the watchdog firing.  When the timer fires,
+           we need to check if m_cpuDeadline has been reached.
+
+           If m_cpuDeadline has been reached, the watchdog is considered to have fired.
+
+           If not, then we have a remaining amount of CPU time, Tremainder, that we should allow JS
+           code to continue to run for.  Hence, we need to start a new timer to fire again after
+           Tremainder microseconds.
+    
+           See Watchdog::didFireSlow().
+
+        3. Spurious wake ups
+           =================
+           Because the WorkQueue timer cannot be cancelled, the watchdog needs to ignore stale timers.
+           It does this by checking the m_wallClockDeadline.  A wakeup that occurs right after
+           m_wallClockDeadline expires is considered to be the wakeup for the active timer.  All other
+           wake ups are considered to be spurious and will be ignored.
+ 
+           See Watchdog::didFireSlow().
+ 
+        4. Minimizing Timer creation cost
+           ==============================
+           Conceptually, we could start a new timer every time we start the watchdog. But we can do better
+           than this.
+ 
+           In practice, the time limit of a watchdog tends to be long, and the amount of time a watchdog
+           stays active tends to be short for well-behaved JS code. The user also tends to re-use the same
+           time limit. Consider the following example:
+ 
+               |---|-----|---|----------------|---------|
+               t0  t1    t2  t3            t0 + L    t2 + L 
+
+               |<--- T1 --------------------->|
+                         |<--- T2 --------------------->|
+               |<-- Td ->|                    |<-- Td ->|
+
+           1. The user initializes the watchdog with time limit L.
+           2. At t0, we enter the VM to execute JS code, and starts the watchdog timer, T1.
+              The timer is set to expire at t0 + L.
+           3. At t1, we exit the VM.
+           4. At t2, we enter the VM again, and would like to start a new watchdog timer, T2.
+         
+              However, we can note that the expiration time for T2 would be after the expiration time
+              of T1. Specifically, T2 would have expired at Td after T1 expires.
+         
+              Hence, we can just wait for T1 to expire, and then start a new timer T2' at time t0 + L
+              for a period or Td instead.
+
+           Note that didFireSlow() already compensates for time differences between wall clock and CPU time,
+           as well as handle spurious wake ups (see note 2 and 3 above).  As a result, didFireSlow() will
+           automatically take care of starting a new timer for the difference Td in the example above.
+           Instead of starting the new timer T2 and time t2, we just verify that if the active timer, T1's
+           expiration is less than T2s, then we are already covered by T1 and there's no need to start T2.
+
+           The benefit:
+
+           1. we minimize the number of timer instances we have queued in the workqueue at the same time
+              (ideally only 1 or 0), and use less peak memory usage.
+
+           2. we minimize the frequency of instantiating timer instances. By waiting for the current
+              active timer to expire first, on average, we get to start one timer per time limit
+              (which is infrequent because time limits tend to be long) instead of one timer per
+              VM entry (which tends to be frequent).
+
+           See Watchdog::startTimer().
+
+        * API/JSContextRef.cpp:
+        (createWatchdogIfNeeded):
+        (JSContextGroupClearExecutionTimeLimit):
+        - No need to create the watchdog (if not already created) just to clear it.
+          If the watchdog is not created yet, then it is effectively cleared.
+
+        * API/tests/ExecutionTimeLimitTest.cpp:
+        (currentCPUTimeAsJSFunctionCallback):
+        (testExecutionTimeLimit):
+        (currentCPUTime): Deleted.
+        * API/tests/testapi.c:
+        (main):
+        * _javascript_Core.vcxproj/testapi/testapi.vcxproj:
+        * _javascript_Core.vcxproj/testapi/testapi.vcxproj.filters:
+        - Enable watchdog tests for all platforms.
+
+        * CMakeLists.txt:
+        * _javascript_Core.vcxproj/_javascript_Core.vcxproj:
+        * _javascript_Core.vcxproj/_javascript_Core.vcxproj.filters:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        - Remove now unneeded WatchdogMac.cpp and WatchdogNone.cpp.
+
+        * PlatformEfl.cmake:
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        * dfg/DFGSpeculativeJIT64.cpp:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::execute):
+        (JSC::Interpreter::executeCall):
+        (JSC::Interpreter::executeConstruct):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_loop_hint):
+        (JSC::JIT::emitSlow_op_loop_hint):
+        * jit/JITOperations.cpp:
+        * llint/LLIntOffsetsExtractor.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        * runtime/VM.cpp:
+        - #include Watchdog.h in these files directly instead of doing it via VM.h.
+          These saves us from having to recompile the world when we change Watchdog.h.
+
+        * runtime/VM.h:
+        - See comment in Watchdog::startTimer() below for why the Watchdog needs to be
+          thread-safe ref counted.
+
+        * runtime/VMEntryScope.cpp:
+        (JSC::VMEntryScope::VMEntryScope):
+        (JSC::VMEntryScope::~VMEntryScope):
+        - We have done away with the WatchdogScope and arming/disarming of the watchdog.
+          Instead, the VMEntryScope will inform the watchdog of when we have entered and
+          exited the VM.
+
+        * runtime/Watchdog.cpp:
+        (JSC::currentWallClockTime):
+        (JSC::Watchdog::Watchdog):
+        (JSC::Watchdog::hasStartedTimer):
+        (JSC::Watchdog::setTimeLimit):
+        (JSC::Watchdog::didFireSlow):
+        (JSC::Watchdog::hasTimeLimit):
+        (JSC::Watchdog::fire):
+        (JSC::Watchdog::enteredVM):
+        (JSC::Watchdog::exitedVM):
+
+        (JSC::Watchdog::startTimer):
+        - The Watchdog is now thread-safe ref counted because the WorkQueue may access it
+          (from a different thread) even after the VM shuts down.  We need to keep it
+          alive until the WorkQueue callback completes.
+
+          In Watchdog::startTimer(), we'll ref the Watchdog to keep it alive for each
+          WorkQueue callback we dispatch.  The callback will deref the Watchdog after it
+          is done with it.  This ensures that the Watchdog is kept alive until all
+          WorkQueue callbacks are done.
+
+        (JSC::Watchdog::stopTimer):
+        (JSC::Watchdog::~Watchdog): Deleted.
+        (JSC::Watchdog::didFire): Deleted.
+        (JSC::Watchdog::isEnabled): Deleted.
+        (JSC::Watchdog::arm): Deleted.
+        (JSC::Watchdog::disarm): Deleted.
+        (JSC::Watchdog::startCountdownIfNeeded): Deleted.
+        (JSC::Watchdog::startCountdown): Deleted.
+        (JSC::Watchdog::stopCountdown): Deleted.
+        * runtime/Watchdog.h:
+        (JSC::Watchdog::didFire):
+        (JSC::Watchdog::timerDidFireAddress):
+        (JSC::Watchdog::isArmed): Deleted.
+        (JSC::Watchdog::Scope::Scope): Deleted.
+        (JSC::Watchdog::Scope::~Scope): Deleted.
+        * runtime/WatchdogMac.cpp:
+        (JSC::Watchdog::initTimer): Deleted.
+        (JSC::Watchdog::destroyTimer): Deleted.
+        (JSC::Watchdog::startTimer): Deleted.
+        (JSC::Watchdog::stopTimer): Deleted.
+        * runtime/WatchdogNone.cpp:
+        (JSC::Watchdog::initTimer): Deleted.
+        (JSC::Watchdog::destroyTimer): Deleted.
+        (JSC::Watchdog::startTimer): Deleted.
+        (JSC::Watchdog::stopTimer): Deleted.
+
 2015-08-11  Filip Pizlo  <[email protected]>
 
         Always use a byte-sized lock implementation

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj (188328 => 188329)


--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj	2015-08-12 05:56:20 UTC (rev 188329)
@@ -870,7 +870,6 @@
     <ClCompile Include="..\runtime\VMEntryScope.cpp" />
     <ClCompile Include="..\runtime\VarOffset.cpp" />
     <ClCompile Include="..\runtime\Watchdog.cpp" />
-    <ClCompile Include="..\runtime\WatchdogNone.cpp" />
     <ClCompile Include="..\runtime\WeakMapConstructor.cpp" />
     <ClCompile Include="..\runtime\WeakMapData.cpp" />
     <ClCompile Include="..\runtime\WeakMapPrototype.cpp" />

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters (188328 => 188329)


--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj.filters	2015-08-12 05:56:20 UTC (rev 188329)
@@ -936,9 +936,6 @@
     <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>

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj (188328 => 188329)


--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj	2015-08-12 05:56:20 UTC (rev 188329)
@@ -297,6 +297,8 @@
     <ClInclude Include="..\..\API\tests\CompareAndSwapTest.h" />
     <ClCompile Include="..\..\API\tests\CustomGlobalObjectClassTest.c" />
     <ClInclude Include="..\..\API\tests\CustomGlobalObjectClassTest.h" />
+    <ClCompile Include="..\..\API\tests\ExecutionTimeLimitTest.cpp" />
+    <ClInclude Include="..\..\API\tests\ExecutionTimeLimitTest.h" />
     <ClCompile Include="..\..\API\tests\GlobalContextWithFinalizerTest.cpp" />
     <ClInclude Include="..\..\API\tests\GlobalContextWithFinalizerTest.h" />
   </ItemGroup>

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj.filters (188328 => 188329)


--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj.filters	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/testapi/testapi.vcxproj.filters	2015-08-12 05:56:20 UTC (rev 188329)
@@ -12,6 +12,8 @@
     <ClInclude Include="..\..\API\tests\CompareAndSwapTest.h" />
     <ClCompile Include="..\..\API\tests\CustomGlobalObjectClassTest.c" />
     <ClInclude Include="..\..\API\tests\CustomGlobalObjectClassTest.h" />
+    <ClCompile Include="..\..\API\tests\ExecutionTimeLimitTest.cpp" />
+    <ClInclude Include="..\..\API\tests\ExecutionTimeLimitTest.h" />
     <ClCompile Include="..\..\API\tests\GlobalContextWithFinalizerTest.cpp" />
     <ClInclude Include="..\..\API\tests\GlobalContextWithFinalizerTest.h" />
   </ItemGroup>

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (188328 => 188329)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1728,7 +1728,6 @@
 		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 */; };
 		FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */; };
 		FEF6835E174343CC00A32E25 /* JITStubsARM.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF6835A174343CC00A32E25 /* JITStubsARM.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		FEF6835F174343CC00A32E25 /* JITStubsARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF6835B174343CC00A32E25 /* JITStubsARMv7.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3587,7 +3586,6 @@
 		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>"; };
 		FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = "<group>"; };
 		FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = "<group>"; };
 		FEF6835A174343CC00A32E25 /* JITStubsARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsARM.h; sourceTree = "<group>"; };
@@ -4920,7 +4918,6 @@
 				FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */,
 				FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */,
 				FED94F2C171E3E2300BE77A4 /* Watchdog.h */,
-				FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */,
 				14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
 				AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */,
 				A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */,
@@ -7833,7 +7830,6 @@
 				E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */,
 				FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */,
 				FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */,
-				FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */,
 				7B98D1361B60CD5F0023B1A4 /* JSWASMModule.cpp in Sources */,
 				0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */,
 				1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/PlatformEfl.cmake (188328 => 188329)


--- trunk/Source/_javascript_Core/PlatformEfl.cmake	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/PlatformEfl.cmake	2015-08-12 05:56:20 UTC (rev 188329)
@@ -2,6 +2,7 @@
     ${ECORE_INCLUDE_DIRS}
     ${EINA_INCLUDE_DIRS}
     ${EO_INCLUDE_DIRS}
+    "${WTF_DIR}/wtf/efl"
 )
 add_definitions(-DSTATICALLY_LINKED_WITH_WTF)
 

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -45,6 +45,7 @@
 #include "PutByIdStatus.h"
 #include "StackAlignment.h"
 #include "StringConstructor.h"
+#include "Watchdog.h"
 #include <wtf/CommaPrinter.h>
 #include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
@@ -4030,7 +4031,7 @@
 
             addToGraph(LoopHint);
             
-            if (m_vm->watchdog && m_vm->watchdog->isEnabled())
+            if (m_vm->watchdog && m_vm->watchdog->hasTimeLimit())
                 addToGraph(CheckWatchdogTimer);
             
             NEXT_OPCODE(op_loop_hint);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -44,6 +44,7 @@
 #include "JSCInlines.h"
 #include "SetupVarargsFrame.h"
 #include "TypeProfilerLog.h"
+#include "Watchdog.h"
 
 namespace JSC { namespace DFG {
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -44,6 +44,7 @@
 #include "SetupVarargsFrame.h"
 #include "SpillRegistersMode.h"
 #include "TypeProfilerLog.h"
+#include "Watchdog.h"
 
 namespace JSC { namespace DFG {
 

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -71,6 +71,7 @@
 #include "Symbol.h"
 #include "VMEntryScope.h"
 #include "VirtualRegister.h"
+#include "Watchdog.h"
 
 #include <limits.h>
 #include <stdio.h>
@@ -880,8 +881,6 @@
     JSValue result;
     {
         SamplingTool::CallRecord callRecord(m_sampler.get());
-        Watchdog::Scope watchdogScope(vm.watchdog.get());
-
         result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
     }
 
@@ -942,7 +941,6 @@
     JSValue result;
     {
         SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall);
-        Watchdog::Scope watchdogScope(vm.watchdog.get());
 
         // Execute the code:
         if (isJSCall)
@@ -1013,7 +1011,6 @@
     JSValue result;
     {
         SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct);
-        Watchdog::Scope watchdogScope(vm.watchdog.get());
 
         // Execute the code.
         if (isJSConstruct)
@@ -1082,8 +1079,6 @@
     JSValue result;
     {
         SamplingTool::CallRecord callRecord(m_sampler.get());
-        Watchdog::Scope watchdogScope(vm.watchdog.get());
-
         result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame);
     }
 
@@ -1173,8 +1168,6 @@
     JSValue result;
     {
         SamplingTool::CallRecord callRecord(m_sampler.get());
-        Watchdog::Scope watchdogScope(vm.watchdog.get());
-
         result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
     }
 

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -45,6 +45,7 @@
 #include "TypeLocation.h"
 #include "TypeProfilerLog.h"
 #include "VirtualRegister.h"
+#include "Watchdog.h"
 
 namespace JSC {
 
@@ -905,7 +906,7 @@
     }
 
     // Emit the watchdog timer check:
-    if (m_vm->watchdog && m_vm->watchdog->isEnabled())
+    if (m_vm->watchdog && m_vm->watchdog->hasTimeLimit())
         addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_vm->watchdog->timerDidFireAddress())));
 }
 
@@ -931,7 +932,7 @@
 #endif
 
     // Emit the slow path of the watchdog timer check:
-    if (m_vm->watchdog && m_vm->watchdog->isEnabled()) {
+    if (m_vm->watchdog && m_vm->watchdog->hasTimeLimit()) {
         linkSlowCase(iter);
         callOperation(operationHandleWatchdogTimer);
 

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -57,6 +57,7 @@
 #include "ScopedArguments.h"
 #include "TestRunnerUtils.h"
 #include "TypeProfilerLog.h"
+#include "Watchdog.h"
 #include <wtf/InlineASM.h>
 
 namespace JSC {

Modified: trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/llint/LLIntOffsetsExtractor.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -55,6 +55,7 @@
 #include "TypeProfilerLog.h"
 #include "VMEntryRecord.h"
 #include "ValueProfile.h"
+#include "Watchdog.h"
 #include <wtf/text/StringImpl.h>
 
 

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -53,6 +53,7 @@
 #include "ObjectConstructor.h"
 #include "ProtoCallFrame.h"
 #include "StructureRareDataInlines.h"
+#include "Watchdog.h"
 #include <wtf/StringPrintStream.h>
 
 namespace JSC { namespace LLInt {

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -85,6 +85,7 @@
 #include "TypeProfiler.h"
 #include "TypeProfilerLog.h"
 #include "UnlinkedCodeBlock.h"
+#include "Watchdog.h"
 #include "WeakGCMapInlines.h"
 #include "WeakMapData.h"
 #include <wtf/CurrentTime.h>

Modified: trunk/Source/_javascript_Core/runtime/VM.h (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/VM.h	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2015-08-12 05:56:20 UTC (rev 188329)
@@ -50,7 +50,6 @@
 #include "ThunkGenerators.h"
 #include "TypedArrayController.h"
 #include "VMEntryRecord.h"
-#include "Watchdog.h"
 #include "Watchpoint.h"
 #include "WeakRandom.h"
 #include <wtf/Bag.h>
@@ -107,6 +106,7 @@
 class UnlinkedProgramCodeBlock;
 class VirtualRegister;
 class VMEntryScope;
+class Watchdog;
 class Watchpoint;
 class WatchpointSet;
 
@@ -259,7 +259,7 @@
     ClientData* clientData;
     VMEntryFrame* topVMEntryFrame;
     ExecState* topCallFrame;
-    std::unique_ptr<Watchdog> watchdog;
+    RefPtr<Watchdog> watchdog;
 
     Strong<Structure> structureStructure;
     Strong<Structure> structureRareDataStructure;

Modified: trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,7 @@
 #include "Debugger.h"
 #include "Options.h"
 #include "VM.h"
+#include "Watchdog.h"
 #include <wtf/StackBounds.h>
 
 namespace JSC {
@@ -48,6 +49,9 @@
         // Reset the date cache between JS invocations to force the VM to
         // observe time xone changes.
         vm.resetDateCache();
+
+        if (vm.watchdog)
+            vm.watchdog->enteredVM();
     }
 
     vm.clearLastException();
@@ -63,6 +67,9 @@
     if (m_vm.entryScope != this)
         return;
 
+    if (m_vm.watchdog)
+        m_vm.watchdog->exitedVM();
+
     m_vm.entryScope = nullptr;
 
     for (auto& listener : m_allEntryScopeDidPopListeners.values())

Modified: trunk/Source/_javascript_Core/runtime/Watchdog.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/Watchdog.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/Watchdog.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,75 +32,136 @@
 
 namespace JSC {
 
-#define NO_LIMIT std::chrono::microseconds::max()
+const std::chrono::microseconds Watchdog::noTimeLimit = std::chrono::microseconds::max();
 
+static std::chrono::microseconds currentWallClockTime()
+{
+    auto steadyTimeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch();
+    return std::chrono::duration_cast<std::chrono::microseconds>(steadyTimeSinceEpoch);
+}
+
 Watchdog::Watchdog()
     : m_timerDidFire(false)
     , m_didFire(false)
-    , m_timeoutPeriod(NO_LIMIT)
-    , m_startCPUTime(0)
-    , m_elapsedCPUTime(0)
-    , m_reentryCount(0)
-    , m_isStopped(true)
+    , m_timeLimit(noTimeLimit)
+    , m_cpuDeadline(noTimeLimit)
+    , m_wallClockDeadline(noTimeLimit)
     , m_callback(0)
     , m_callbackData1(0)
     , m_callbackData2(0)
+    , m_timerQueue(WorkQueue::create("jsc.watchdog.queue", WorkQueue::Type::Serial, WorkQueue::QOS::Utility))
 {
-    initTimer();
+    m_timerHandler = [this] {
+        this->m_timerDidFire = true;
+        this->deref();
+    };
 }
 
-Watchdog::~Watchdog()
+inline bool Watchdog::hasStartedTimer()
 {
-    ASSERT(!isArmed());
-    stopCountdown();
-    destroyTimer();
+    return m_cpuDeadline != noTimeLimit;
 }
 
 void Watchdog::setTimeLimit(VM& vm, std::chrono::microseconds limit,
     ShouldTerminateCallback callback, void* data1, void* data2)
 {
-    bool wasEnabled = isEnabled();
+    bool hadTimeLimit = hasTimeLimit();
 
-    if (!m_isStopped)
-        stopCountdown();
-
     m_didFire = false; // Reset the watchdog.
 
-    m_timeoutPeriod = limit;
+    m_timeLimit = limit;
     m_callback = callback;
     m_callbackData1 = data1;
     m_callbackData2 = data2;
 
-    // If this is the first time that timeout is being enabled, then any
+    // If this is the first time that time limit 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
+    // However, if the time limit is already enabled, and we're just changing the
+    // time limit value, then any existing JITted code will have the appropriate
     // polling checks. Hence, there is no need to re-do this flushing.
-    if (!wasEnabled) {
+    if (!hadTimeLimit) {
         // And if we've previously compiled any functions, we need to revert
         // them because they don't have the needed polling checks yet.
         vm.releaseExecutableMemory();
     }
 
-    startCountdownIfNeeded();
+    if (m_hasEnteredVM && hasTimeLimit())
+        startTimer(m_timeLimit);
 }
 
-bool Watchdog::didFire(ExecState* exec)
+bool Watchdog::didFireSlow(ExecState* exec)
 {
-    if (m_didFire)
-        return true;
-
-    if (!m_timerDidFire)
-        return false;
+    ASSERT(m_timerDidFire);
     m_timerDidFire = false;
-    stopCountdown();
 
-    auto currentTime = currentCPUTime();
-    auto deltaCPUTime = currentTime - m_startCPUTime;
-    auto totalElapsedCPUTime = m_elapsedCPUTime + deltaCPUTime;
-    if (totalElapsedCPUTime > m_timeoutPeriod) {
+    // A legitimate timer is the timer which woke up watchdog and can caused didFireSlow() to be
+    // called after m_wallClockDeadline has expired. All other timers are considered to be stale,
+    // and their wake ups are considered to be spurious and should be ignored.
+    //
+    // didFireSlow() will race against m_timerHandler to clear and set m_timerDidFire respectively.
+    // We need to deal with a variety of scenarios where we can have stale timers and legitimate
+    // timers firing in close proximity to each other.
+    //
+    // Consider the following scenarios:
+    //
+    // 1. A stale timer fires long before m_wallClockDeadline expires.
+    //
+    //    In this case, the m_wallClockDeadline check below will fail and the stale timer will be
+    //    ignored as spurious. We just need to make sure that we clear m_timerDidFire before we
+    //    check m_wallClockDeadline and return below.
+    //
+    // 2. A stale timer fires just before m_wallClockDeadline expires.
+    //    Before the watchdog can gets to the clearing m_timerDidFire above, the legit timer also fires.
+    //
+    //    In this case, m_timerDidFire was set twice by the 2 timers, but we only clear need to clear
+    //    it once. The m_wallClockDeadline below will pass and this invocation of didFireSlow() will
+    //    be treated as the response to the legit timer. The spurious timer is effectively ignored.
+    //
+    // 3. A state timer fires just before m_wallClockDeadline expires.
+    //    Right after the watchdog clears m_timerDidFire above, the legit timer also fires.
+    //
+    //    The fact that the legit timer fails means that the m_wallClockDeadline check will pass.
+    //    As long as we clear m_timerDidFire before we do the check, we are safe. This is the same
+    //    scenario as 2 above.
+    //
+    // 4. A stale timer fires just before m_wallClockDeadline expires.
+    //    Right after we do the m_wallClockDeadline check below, the legit timer fires.
+    //
+    //    The fact that the legit timer fires after the m_wallClockDeadline check means that
+    //    the m_wallClockDeadline check will have failed. This is the same scenario as 1 above.
+    //
+    // 5. A legit timer fires.
+    //    A stale timer also fires before we clear m_timerDidFire above.
+    //
+    //    This is the same scenario as 2 above.
+    //
+    // 6. A legit timer fires.
+    //    A stale timer fires right after we clear m_timerDidFire above.
+    //
+    //    In this case, the m_wallClockDeadline check will pass, and we fire the watchdog
+    //    though m_timerDidFire remains set. This just means that didFireSlow() will be called again due
+    //    to m_timerDidFire being set. The subsequent invocation of didFireSlow() will end up handling
+    //    the stale timer and ignoring it. This is the same scenario as 1 above.
+    //
+    // 7. A legit timer fires.
+    //    A stale timer fires right after we do the m_wallClockDeadline check.
+    //
+    //    This is the same as 6, which means it's the same as 1 above.
+    //
+    // In all these cases, we just need to ensure that we clear m_timerDidFire before we do the
+    // m_wallClockDeadline check below. Hence, a storeLoad fence is needed to ensure that these 2
+    // operations do not get re-ordered.
+
+    WTF::storeLoadFence();
+
+    if (currentWallClockTime() < m_wallClockDeadline)
+        return false; // Just a stale timer firing. Nothing to do.
+
+    m_wallClockDeadline = noTimeLimit;
+
+    if (currentCPUTime() >= m_cpuDeadline) {
         // Case 1: the allowed CPU time has elapsed.
 
         // If m_callback is not set, then we terminate by default.
@@ -112,27 +173,32 @@
             return true;
         }
 
-        // The m_callback may have set a new limit. So, we may need to restart
-        // the countdown.
-        startCountdownIfNeeded();
+        // If we get here, then the callback above did not want to terminate execution. As a
+        // result, the callback may have done one of the following:
+        //   1. cleared the time limit (i.e. watchdog is disabled),
+        //   2. set a new time limit via Watchdog::setTimeLimit(), or
+        //   3. did nothing (i.e. allow another cycle of the current time limit).
+        //
+        // In the case of 1, we don't have to do anything.
+        // In the case of 2, Watchdog::setTimeLimit() would already have started the timer.
+        // In the case of 3, we need to re-start the timer here.
 
+        ASSERT(m_hasEnteredVM);
+        if (hasTimeLimit() && !hasStartedTimer())
+            startTimer(m_timeLimit);
+
     } 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.
-        auto remainingCPUTime = m_timeoutPeriod - totalElapsedCPUTime;
-        m_elapsedCPUTime = totalElapsedCPUTime;
-        m_startCPUTime = currentTime;
-        startCountdown(remainingCPUTime);
+        auto remainingCPUTime = m_cpuDeadline - currentCPUTime();
+        startTimer(remainingCPUTime);
     }
 
     return false;
 }
 
-bool Watchdog::isEnabled()
+bool Watchdog::hasTimeLimit()
 {
-    return (m_timeoutPeriod != NO_LIMIT);
+    return (m_timeLimit != noTimeLimit);
 }
 
 void Watchdog::fire()
@@ -140,49 +206,51 @@
     m_didFire = true;
 }
 
-void Watchdog::arm()
+void Watchdog::enteredVM()
 {
-    m_reentryCount++;
-    if (m_reentryCount == 1)
-        startCountdownIfNeeded();
+    m_hasEnteredVM = true;
+    if (hasTimeLimit())
+        startTimer(m_timeLimit);
 }
 
-void Watchdog::disarm()
+void Watchdog::exitedVM()
 {
-    ASSERT(m_reentryCount > 0);
-    if (m_reentryCount == 1)
-        stopCountdown();
-    m_reentryCount--;
+    ASSERT(m_hasEnteredVM);
+    stopTimer();
+    m_hasEnteredVM = false;
 }
 
-void Watchdog::startCountdownIfNeeded()
+void Watchdog::startTimer(std::chrono::microseconds timeLimit)
 {
-    if (!m_isStopped)
-        return; // Already started.
+    ASSERT(m_hasEnteredVM);
+    ASSERT(hasTimeLimit());
 
-    if (!isArmed())
-        return; // Not executing JS script. No need to start.
+    m_cpuDeadline = currentCPUTime() + timeLimit;
+    auto wallClockTime = currentWallClockTime();
+    auto wallClockDeadline = wallClockTime + timeLimit;
 
-    if (isEnabled()) {
-        m_elapsedCPUTime = std::chrono::microseconds::zero();
-        m_startCPUTime = currentCPUTime();
-        startCountdown(m_timeoutPeriod);
+    if ((wallClockTime < m_wallClockDeadline)
+        && (m_wallClockDeadline <= wallClockDeadline)) {
+        return; // Wait for the current active timer to expire before starting a new one.
     }
-}
 
-void Watchdog::startCountdown(std::chrono::microseconds limit)
-{
-    ASSERT(m_isStopped);
-    m_isStopped = false;
-    startTimer(limit);
+    // Else, the current active timer won't fire soon enough. So, start a new timer.
+    this->ref(); // m_timerHandler will deref to match later.
+    m_wallClockDeadline = wallClockDeadline;
+    m_timerDidFire = false;
+
+    // We clear m_timerDidFire because we're starting a new timer. However, we need to make sure
+    // that the clearing occurs before the timer thread is started. Thereafter, only didFireSlow()
+    // should clear m_timerDidFire (unless we start yet another timer). Hence, we need a storeStore
+    // fence here to ensure these operations do not get re-ordered.
+    WTF::storeStoreFence();
+
+    m_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), m_timerHandler);
 }
 
-void Watchdog::stopCountdown()
+void Watchdog::stopTimer()
 {
-    if (m_isStopped)
-        return;
-    stopTimer();
-    m_isStopped = true;
+    m_cpuDeadline = noTimeLimit;
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/Watchdog.h (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/Watchdog.h	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/Watchdog.h	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,31 +26,40 @@
 #ifndef Watchdog_h
 #define Watchdog_h
 
-#if OS(DARWIN)
-#include <dispatch/dispatch.h>    
-#endif
+#include <mutex>
+#include <wtf/Ref.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/WorkQueue.h>
 
 namespace JSC {
 
 class ExecState;
 class VM;
 
-class Watchdog {
+class Watchdog : public WTF::ThreadSafeRefCounted<Watchdog> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     class Scope;
 
     Watchdog();
-    ~Watchdog();
 
     typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2);
     void setTimeLimit(VM&, std::chrono::microseconds limit, 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 didFire(ExecState* exec)
+    {
+        if (m_didFire)
+            return true;
+        if (!m_timerDidFire)
+            return false;
+        return didFireSlow(exec);
+    }
 
-    bool isEnabled();
+    bool hasTimeLimit();
+    void enteredVM();
+    void exitedVM();
 
     // 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
@@ -60,21 +69,17 @@
 
     void* timerDidFireAddress() { return &m_timerDidFire; }
 
-private:
-    void arm();
-    void disarm();
-    void startCountdownIfNeeded();
-    void startCountdown(std::chrono::microseconds limit);
-    void stopCountdown();
-    bool isArmed() { return !!m_reentryCount; }
+    static const std::chrono::microseconds noTimeLimit;
 
-    // Platform specific timer implementation:
-    void initTimer();
-    void destroyTimer();
-    void startTimer(std::chrono::microseconds limit);
+private:
+    void startTimer(std::chrono::microseconds timeLimit);
     void stopTimer();
 
-    // m_timerDidFire (above) indicates whether the timer fired. The Watchdog
+    inline bool hasStartedTimer();
+
+    bool didFireSlow(ExecState*);
+
+    // m_timerDidFire 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
@@ -82,47 +87,23 @@
     bool m_timerDidFire;
     bool m_didFire;
 
-    std::chrono::microseconds m_timeoutPeriod;
-    std::chrono::microseconds m_startCPUTime;
-    std::chrono::microseconds m_elapsedCPUTime;
+    std::chrono::microseconds m_timeLimit;
 
-    int m_reentryCount;
-    bool m_isStopped;
+    std::chrono::microseconds m_cpuDeadline;
+    std::chrono::microseconds m_wallClockDeadline;
 
+    bool m_hasEnteredVM { false };
+
     ShouldTerminateCallback m_callback;
     void* m_callbackData1;
     void* m_callbackData2;
 
-#if OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK)
-    dispatch_queue_t m_queue;
-    dispatch_source_t m_timer;
-#endif
+    Ref<WorkQueue> m_timerQueue;
+    std::function<void ()> m_timerHandler;
 
-    friend class Watchdog::Scope;
     friend class LLIntOffsetsExtractor;
 };
 
-class Watchdog::Scope {
-public:
-    Scope(Watchdog* watchdog)
-        : m_watchdog(watchdog)
-    {
-        if (!watchdog)
-            return;
-        m_watchdog->arm();
-    }
-    
-    ~Scope()
-    {
-        if (!m_watchdog)
-            return;
-        m_watchdog->disarm();
-    }
-
-private:
-    Watchdog* m_watchdog;
-};
-
 } // namespace JSC
 
 #endif // Watchdog_h

Modified: trunk/Source/_javascript_Core/runtime/WatchdogMac.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/WatchdogMac.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/WatchdogMac.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,72 +0,0 @@
-/*
- * 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(std::chrono::microseconds 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, std::chrono::nanoseconds(limit).count()),
-        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

Modified: trunk/Source/_javascript_Core/runtime/WatchdogNone.cpp (188328 => 188329)


--- trunk/Source/_javascript_Core/runtime/WatchdogNone.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/_javascript_Core/runtime/WatchdogNone.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,50 +0,0 @@
-/*
- * 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(std::chrono::microseconds)
-{
-}
-
-void Watchdog::stopTimer()
-{
-}
-
-} // namespace JSC

Modified: trunk/Source/WebCore/ChangeLog (188328 => 188329)


--- trunk/Source/WebCore/ChangeLog	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/ChangeLog	2015-08-12 05:56:20 UTC (rev 188329)
@@ -1,3 +1,20 @@
+2015-08-11  Mark Lam  <[email protected]>
+
+        Implementation _javascript_ watchdog using WTF::WorkQueue.
+        https://bugs.webkit.org/show_bug.cgi?id=147107
+
+        Reviewed by Geoffrey Garen.
+
+        No new tests because we're not introducing any behavior change to WebCore here.
+        We're only #include'ing Watchdog.h directly instead of going through VM.h.
+
+        * ForwardingHeaders/runtime/Watchdog.h: Added.
+        * PlatformEfl.cmake:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * bindings/js/JSEventListener.cpp:
+        * bindings/js/WorkerScriptController.cpp:
+
 2015-08-11  Simon Fraser  <[email protected]>
 
         [iOS WK2] ASSERT(!m_properties.backingStore || owner()) sometimes on zooming

Added: trunk/Source/WebCore/ForwardingHeaders/runtime/Watchdog.h (0 => 188329)


--- trunk/Source/WebCore/ForwardingHeaders/runtime/Watchdog.h	                        (rev 0)
+++ trunk/Source/WebCore/ForwardingHeaders/runtime/Watchdog.h	2015-08-12 05:56:20 UTC (rev 188329)
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_Watchdog_h
+#define WebCore_FWD_Watchdog_h
+#include <_javascript_Core/Watchdog.h>
+#endif

Modified: trunk/Source/WebCore/PlatformEfl.cmake (188328 => 188329)


--- trunk/Source/WebCore/PlatformEfl.cmake	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/PlatformEfl.cmake	2015-08-12 05:56:20 UTC (rev 188329)
@@ -24,6 +24,7 @@
     "${WEBCORE_DIR}/platform/network/soup"
     "${WEBCORE_DIR}/platform/text/efl"
     "${WEBCORE_DIR}/plugins/efl"
+    "${WTF_DIR}/wtf/efl"
 )
 
 list(APPEND WebCore_SOURCES

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj (188328 => 188329)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2015-08-12 05:56:20 UTC (rev 188329)
@@ -20436,6 +20436,7 @@
     <ClInclude Include="..\ForwardingHeaders\runtime\Structure.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\StructureChain.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\SymbolTable.h" />
+    <ClInclude Include="..\ForwardingHeaders\runtime\Watchdog.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\WeakGCMap.h" />
     <ClInclude Include="..\ForwardingHeaders\runtime\WriteBarrier.h" />
     <ClInclude Include="..\ForwardingHeaders\yarr\YarrJIT.h" />

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters (188328 => 188329)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters	2015-08-12 05:56:20 UTC (rev 188329)
@@ -12198,6 +12198,9 @@
     <ClInclude Include="..\ForwardingHeaders\runtime\SymbolTable.h">
       <Filter>ForwardingHeaders\runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\ForwardingHeaders\runtime\Watchdog.h">
+      <Filter>ForwardingHeaders\runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\ForwardingHeaders\runtime\WeakGCMap.h">
       <Filter>ForwardingHeaders\runtime</Filter>
     </ClInclude>

Modified: trunk/Source/WebCore/bindings/js/JSEventListener.cpp (188328 => 188329)


--- trunk/Source/WebCore/bindings/js/JSEventListener.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/bindings/js/JSEventListener.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -34,6 +34,7 @@
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/JSLock.h>
 #include <runtime/VMEntryScope.h>
+#include <runtime/Watchdog.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCountedLeakCounter.h>
 

Modified: trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp (188328 => 188329)


--- trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp	2015-08-12 05:54:14 UTC (rev 188328)
+++ trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp	2015-08-12 05:56:20 UTC (rev 188329)
@@ -44,6 +44,7 @@
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/Error.h>
 #include <runtime/JSLock.h>
+#include <runtime/Watchdog.h>
 
 using namespace JSC;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to