Add watchdog timer polling for the DFG.
https://bugs.webkit.org/show_bug.cgi?id=115134.

Reviewed by Geoffrey Garen.

The strategy is to add a speculation check to the DFG generated code to
test if the watchdog timer has fired or not. If the watchdog timer has
fired, the generated code will do an OSR exit to the baseline JIT, and
let it handle servicing the watchdog timer.

If the watchdog is not enabled, this speculation check will not be
emitted.

* API/tests/testapi.c:
(currentCPUTime_callAsFunction):
(extendTerminateCallback):
(main):
- removed try/catch statements so that we can test the watchdog on the DFG.
- added JS bindings to a native currentCPUTime() function so that the timeout
  tests can be more accurate.
- also shortened the time values so that the tests can complete sooner.

* bytecode/ExitKind.h:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/Watchdog.cpp:
(JSC::Watchdog::setTimeLimit):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@149089 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 1352ca2..3c116a0 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1538,6 +1538,10 @@
         m_isValid = false;
         break;
             
+    case CheckWatchdogTimer:
+        node->setCanExit(true);
+        break;
+            
     case Phantom:
     case InlineStart:
     case Nop:
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 5cdf48d..233f0ab 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -3285,9 +3285,13 @@
             if (!m_inlineStackTop->m_caller)
                 m_currentBlock->isOSRTarget = true;
 
-            // Emit a phantom node to ensure that there is a placeholder node for this bytecode
-            // op.
-            addToGraph(Phantom);
+            if (m_vm->watchdog.isEnabled())
+                addToGraph(CheckWatchdogTimer);
+            else {
+                // Emit a phantom node to ensure that there is a placeholder
+                // node for this bytecode op.
+                addToGraph(Phantom);
+            }
             
             NEXT_OPCODE(op_loop_hint);
         }
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 9d33f9f..a0bfca8 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -859,6 +859,7 @@
         case GarbageValue:
         case CountExecution:
         case ForceOSRExit:
+        case CheckWatchdogTimer:
             break;
 #else
         default:
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 0301f64..6ef9542 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -264,7 +264,11 @@
     /* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
     /* this point, but execution does continue in the basic block - just in a */\
     /* different compiler. */\
-    macro(ForceOSRExit, NodeMustGenerate)
+    macro(ForceOSRExit, NodeMustGenerate) \
+    \
+    /* Checks the watchdog timer. If the timer has fired, we OSR exit to the */ \
+    /* baseline JIT to redo the watchdog timer check, and service the timer. */ \
+    macro(CheckWatchdogTimer, NodeMustGenerate) \
 
 // This enum generates a monotonically increasing id for all Node types,
 // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 8c67da9..3377f26 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -526,6 +526,7 @@
         case Phantom:
         case PutGlobalVar:
         case PutGlobalVarCheck:
+        case CheckWatchdogTimer:
             break;
             
         // These gets ignored because it doesn't do anything.
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 358441d..172afee 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4926,6 +4926,14 @@
         break;
     }
 
+    case CheckWatchdogTimer:
+        speculationCheck(
+            WatchdogTimerFired, JSValueRegs(), 0,
+            m_jit.branchTest8(
+                JITCompiler::NonZero,
+                JITCompiler::AbsoluteAddress(m_jit.vm()->watchdog.timerDidFireAddress())));
+        break;
+
     case CountExecution:
         m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node->executionCounter()->address()));
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index e04596c..e7a7791 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4770,6 +4770,14 @@
         break;
     }
 
+    case CheckWatchdogTimer:
+        speculationCheck(
+            WatchdogTimerFired, JSValueRegs(), 0,
+            m_jit.branchTest8(
+                JITCompiler::NonZero,
+                JITCompiler::AbsoluteAddress(m_jit.vm()->watchdog.timerDidFireAddress())));
+        break;
+
     case Phantom:
         DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
         noResult(node);