Commit dff6b22e authored by mark.lam@apple.com's avatar mark.lam@apple.com

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
parent b982422d
......@@ -79,6 +79,30 @@ void JSContextGroupRelease(JSContextGroupRef group)
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)
......
......@@ -55,6 +55,54 @@ JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
*/
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
......
......@@ -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 @@ static void checkConstnessInJSObjectNames()
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 @@ int main(int argc, char* argv[])
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;
......
......@@ -305,6 +305,8 @@ set(JavaScriptCore_SOURCES
runtime/StructureRareData.cpp
runtime/StructureChain.cpp
runtime/SymbolTable.cpp
runtime/Watchdog.cpp
runtime/WatchdogNone.cpp
tools/CodeProfile.cpp
tools/CodeProfiling.cpp
......
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.
......@@ -782,10 +782,12 @@ javascriptcore_sources += \
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 \
......
......@@ -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
......
......@@ -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" />
......
......@@ -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>
......
......@@ -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 */,
......
......@@ -324,6 +324,8 @@ SOURCES += \
runtime/Structure.cpp \
runtime/StructureRareData.cpp \
runtime/SymbolTable.cpp \
runtime/Watchdog.cpp \
runtime/WatchdogNone.cpp \
tools/CodeProfile.cpp \
tools/CodeProfiling.cpp \
yarr/YarrJIT.cpp \
......
......@@ -655,9 +655,7 @@ UnlinkedValueProfile BytecodeGenerator::emitProfiledOpcode(OpcodeID opcodeID)
void BytecodeGenerator::emitLoopHint()
{
#if ENABLE(DFG_JIT)
emitOpcode(op_loop_hint);
#endif
}
void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
......
......@@ -767,7 +767,7 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSValue error)
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 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSValue error)
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 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
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 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
// 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 @@ failedJSONP:
// 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 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
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 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
#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 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
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 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
#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 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
// 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::